1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)ip_icmp.c 7.12 (Berkeley) 04/22/89 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "malloc.h" 23 #include "mbuf.h" 24 #include "protosw.h" 25 #include "socket.h" 26 #include "time.h" 27 #include "kernel.h" 28 29 #include "../net/route.h" 30 #include "../net/if.h" 31 32 #include "in.h" 33 #include "in_systm.h" 34 #include "in_var.h" 35 #include "ip.h" 36 #include "ip_icmp.h" 37 #include "icmp_var.h" 38 39 /* 40 * ICMP routines: error generation, receive packet processing, and 41 * routines to turnaround packets back to the originator, and 42 * host table maintenance routines. 43 */ 44 #ifdef ICMPPRINTFS 45 int icmpprintfs = 0; 46 #endif 47 48 /* 49 * Generate an error packet of type error 50 * in response to bad packet ip. 51 */ 52 /*VARARGS3*/ 53 icmp_error(n, type, code, dest) 54 struct mbuf *n; 55 int type, code; 56 struct in_addr dest; 57 { 58 register struct ip *oip = mtod(n, struct ip *), *nip; 59 register unsigned oiplen = oip->ip_hl << 2; 60 register struct icmp *icp; 61 register struct mbuf *m; 62 unsigned icmplen; 63 64 #ifdef ICMPPRINTFS 65 if (icmpprintfs) 66 printf("icmp_error(%x, %d, %d)\n", oip, type, code); 67 #endif 68 if (type != ICMP_REDIRECT) 69 icmpstat.icps_error++; 70 /* 71 * Don't send error if not the first fragment of message. 72 * Don't error if the old packet protocol was ICMP 73 * error message, only known informational types. 74 */ 75 if (oip->ip_off &~ (IP_MF|IP_DF)) 76 goto freeit; 77 if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 78 n->m_len >= oiplen + ICMP_MINLEN && 79 !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 80 icmpstat.icps_oldicmp++; 81 goto freeit; 82 } 83 84 /* 85 * First, formulate icmp message 86 */ 87 m = m_gethdr(M_DONTWAIT, MT_HEADER); 88 if (m == NULL) 89 goto freeit; 90 icmplen = oiplen + min(8, oip->ip_len); 91 m->m_len = icmplen + ICMP_MINLEN; 92 MH_ALIGN(m, m->m_len); 93 icp = mtod(m, struct icmp *); 94 if ((u_int)type > ICMP_MAXTYPE) 95 panic("icmp_error"); 96 icmpstat.icps_outhist[type]++; 97 icp->icmp_type = type; 98 if (type == ICMP_REDIRECT) 99 icp->icmp_gwaddr = dest; 100 else 101 icp->icmp_void = 0; 102 if (type == ICMP_PARAMPROB) { 103 icp->icmp_pptr = code; 104 code = 0; 105 } 106 icp->icmp_code = code; 107 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 108 nip = &icp->icmp_ip; 109 nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); 110 111 /* 112 * Now, copy old ip header (without options) 113 * in front of icmp message. 114 */ 115 if (m->m_data - sizeof(struct ip) < m->m_pktdat) 116 panic("icmp len"); 117 m->m_data -= sizeof(struct ip); 118 m->m_len += sizeof(struct ip); 119 m->m_pkthdr.len = m->m_len; 120 m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 121 nip = mtod(m, struct ip *); 122 bcopy((caddr_t)oip, (caddr_t)nip, oiplen); 123 nip->ip_len = m->m_len; 124 nip->ip_hl = sizeof(struct ip) >> 2; 125 nip->ip_p = IPPROTO_ICMP; 126 icmp_reflect(m); 127 128 freeit: 129 m_freem(n); 130 } 131 132 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 133 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 134 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 135 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 136 struct sockaddr_in icmpmask = { 8, 0 }; 137 struct in_ifaddr *ifptoia(); 138 139 /* 140 * Process a received ICMP message. 141 */ 142 icmp_input(m, hlen) 143 register struct mbuf *m; 144 int hlen; 145 { 146 register struct icmp *icp; 147 register struct ip *ip = mtod(m, struct ip *); 148 int icmplen = ip->ip_len; 149 register int i; 150 struct in_ifaddr *ia; 151 int (*ctlfunc)(), code; 152 extern u_char ip_protox[]; 153 extern struct in_addr in_makeaddr(); 154 155 /* 156 * Locate icmp structure in mbuf, and check 157 * that not corrupted and of at least minimum length. 158 */ 159 #ifdef ICMPPRINTFS 160 if (icmpprintfs) 161 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 162 #endif 163 if (icmplen < ICMP_MINLEN) { 164 icmpstat.icps_tooshort++; 165 goto freeit; 166 } 167 i = hlen + MIN(icmplen, ICMP_ADVLENMIN); 168 if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 169 icmpstat.icps_tooshort++; 170 return; 171 } 172 ip = mtod(m, struct ip *); 173 m->m_len -= hlen; 174 m->m_data += hlen; 175 icp = mtod(m, struct icmp *); 176 if (in_cksum(m, icmplen)) { 177 icmpstat.icps_checksum++; 178 goto freeit; 179 } 180 m->m_len += hlen; 181 m->m_data -= hlen; 182 183 #ifdef ICMPPRINTFS 184 /* 185 * Message type specific processing. 186 */ 187 if (icmpprintfs) 188 printf("icmp_input, type %d code %d\n", icp->icmp_type, 189 icp->icmp_code); 190 #endif 191 if (icp->icmp_type > ICMP_MAXTYPE) 192 goto raw; 193 icmpstat.icps_inhist[icp->icmp_type]++; 194 code = icp->icmp_code; 195 switch (icp->icmp_type) { 196 197 case ICMP_UNREACH: 198 if (code > 5) 199 goto badcode; 200 code += PRC_UNREACH_NET; 201 goto deliver; 202 203 case ICMP_TIMXCEED: 204 if (code > 1) 205 goto badcode; 206 code += PRC_TIMXCEED_INTRANS; 207 goto deliver; 208 209 case ICMP_PARAMPROB: 210 if (code) 211 goto badcode; 212 code = PRC_PARAMPROB; 213 goto deliver; 214 215 case ICMP_SOURCEQUENCH: 216 if (code) 217 goto badcode; 218 code = PRC_QUENCH; 219 deliver: 220 /* 221 * Problem with datagram; advise higher level routines. 222 */ 223 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); 224 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 225 icmpstat.icps_badlen++; 226 goto freeit; 227 } 228 #ifdef ICMPPRINTFS 229 if (icmpprintfs) 230 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 231 #endif 232 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 233 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 234 (*ctlfunc)(code, (struct sockaddr *)&icmpsrc); 235 break; 236 237 badcode: 238 icmpstat.icps_badcode++; 239 break; 240 241 case ICMP_ECHO: 242 icp->icmp_type = ICMP_ECHOREPLY; 243 goto reflect; 244 245 case ICMP_TSTAMP: 246 if (icmplen < ICMP_TSLEN) { 247 icmpstat.icps_badlen++; 248 break; 249 } 250 icp->icmp_type = ICMP_TSTAMPREPLY; 251 icp->icmp_rtime = iptime(); 252 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 253 goto reflect; 254 255 case ICMP_IREQ: 256 #define satosin(sa) ((struct sockaddr_in *)(sa)) 257 if (in_netof(ip->ip_src) == 0 && 258 (ia = ifptoia(m->m_pkthdr.rcvif))) 259 ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr), 260 in_lnaof(ip->ip_src)); 261 icp->icmp_type = ICMP_IREQREPLY; 262 goto reflect; 263 264 case ICMP_MASKREQ: 265 if (icmplen < ICMP_MASKLEN || 266 (ia = ifptoia(m->m_pkthdr.rcvif)) == 0) 267 break; 268 icp->icmp_type = ICMP_MASKREPLY; 269 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 270 if (ip->ip_src.s_addr == 0) { 271 if (ia->ia_ifp->if_flags & IFF_BROADCAST) 272 ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 273 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 274 ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 275 } 276 reflect: 277 ip->ip_len += hlen; /* since ip_input deducts this */ 278 icmpstat.icps_reflect++; 279 icmpstat.icps_outhist[icp->icmp_type]++; 280 icmp_reflect(m); 281 return; 282 283 case ICMP_REDIRECT: 284 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 285 icmpstat.icps_badlen++; 286 break; 287 } 288 /* 289 * Short circuit routing redirects to force 290 * immediate change in the kernel's routing 291 * tables. The message is also handed to anyone 292 * listening on a raw socket (e.g. the routing 293 * daemon for use in updating its tables). 294 */ 295 icmpgw.sin_addr = ip->ip_src; 296 icmpdst.sin_addr = icp->icmp_gwaddr; 297 #ifdef ICMPPRINTFS 298 if (icmpprintfs) 299 printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 300 icp->icmp_gwaddr); 301 #endif 302 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { 303 u_long in_netof(); 304 icmpsrc.sin_addr = 305 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); 306 in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask); 307 rtredirect((struct sockaddr *)&icmpsrc, 308 (struct sockaddr *)&icmpdst, 309 (struct sockaddr *)&icmpmask, RTF_GATEWAY, 310 (struct sockaddr *)&icmpgw, (struct rtentry **)0); 311 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 312 pfctlinput(PRC_REDIRECT_NET, 313 (struct sockaddr *)&icmpsrc); 314 } else { 315 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 316 rtredirect((struct sockaddr *)&icmpsrc, 317 (struct sockaddr *)&icmpdst, 318 (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 319 (struct sockaddr *)&icmpgw, (struct rtentry **)0); 320 pfctlinput(PRC_REDIRECT_HOST, 321 (struct sockaddr *)&icmpsrc); 322 } 323 break; 324 325 /* 326 * No kernel processing for the following; 327 * just fall through to send to raw listener. 328 */ 329 case ICMP_ECHOREPLY: 330 case ICMP_TSTAMPREPLY: 331 case ICMP_IREQREPLY: 332 case ICMP_MASKREPLY: 333 default: 334 break; 335 } 336 337 raw: 338 icmpsrc.sin_addr = ip->ip_src; 339 icmpdst.sin_addr = ip->ip_dst; 340 raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc, 341 (struct sockaddr *)&icmpdst); 342 return; 343 344 freeit: 345 m_freem(m); 346 } 347 348 /* 349 * Reflect the ip packet back to the source 350 */ 351 icmp_reflect(m) 352 struct mbuf *m; 353 { 354 register struct ip *ip = mtod(m, struct ip *); 355 register struct in_ifaddr *ia; 356 struct in_addr t; 357 struct mbuf *opts = 0, *ip_srcroute(); 358 int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 359 360 t = ip->ip_dst; 361 ip->ip_dst = ip->ip_src; 362 /* 363 * If the incoming packet was addressed directly to us, 364 * use dst as the src for the reply. Otherwise (broadcast 365 * or anonymous), use the address which corresponds 366 * to the incoming interface. 367 */ 368 for (ia = in_ifaddr; ia; ia = ia->ia_next) { 369 if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 370 break; 371 if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 372 t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 373 break; 374 } 375 if (ia == (struct in_ifaddr *)0) 376 ia = ifptoia(m->m_pkthdr.rcvif); 377 if (ia == (struct in_ifaddr *)0) 378 ia = in_ifaddr; 379 t = IA_SIN(ia)->sin_addr; 380 ip->ip_src = t; 381 ip->ip_ttl = MAXTTL; 382 383 if (optlen > 0) { 384 register u_char *cp; 385 int opt, cnt; 386 u_int len; 387 388 /* 389 * Retrieve any source routing from the incoming packet; 390 * add on any record-route or timestamp options. 391 */ 392 cp = (u_char *) (ip + 1); 393 if ((opts = ip_srcroute()) == 0 && 394 (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 395 opts->m_len = sizeof(struct in_addr); 396 mtod(opts, struct in_addr *)->s_addr = 0; 397 } 398 if (opts) { 399 #ifdef ICMPPRINTFS 400 if (icmpprintfs) 401 printf("icmp_reflect optlen %d rt %d => ", 402 optlen, opts->m_len); 403 #endif 404 for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 405 opt = cp[IPOPT_OPTVAL]; 406 if (opt == IPOPT_EOL) 407 break; 408 if (opt == IPOPT_NOP) 409 len = 1; 410 else { 411 len = cp[IPOPT_OLEN]; 412 if (len <= 0 || len > cnt) 413 break; 414 } 415 /* 416 * should check for overflow, but it "can't happen" 417 */ 418 if (opt == IPOPT_RR || opt == IPOPT_TS) { 419 bcopy((caddr_t)cp, 420 mtod(opts, caddr_t) + opts->m_len, len); 421 opts->m_len += len; 422 } 423 } 424 if (opts->m_len % 4 != 0) { 425 *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL; 426 opts->m_len++; 427 } 428 #ifdef ICMPPRINTFS 429 if (icmpprintfs) 430 printf("%d\n", opts->m_len); 431 #endif 432 } 433 /* 434 * Now strip out original options by copying rest of first 435 * mbuf's data back, and adjust the IP length. 436 */ 437 ip->ip_len -= optlen; 438 ip->ip_hl = sizeof(struct ip) >> 2; 439 m->m_len -= optlen; 440 if (m->m_flags & M_PKTHDR) 441 m->m_pkthdr.len -= optlen; 442 optlen += sizeof(struct ip); 443 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 444 (unsigned)(m->m_len - sizeof(struct ip))); 445 } 446 icmp_send(m, opts); 447 if (opts) 448 (void)m_free(opts); 449 } 450 451 struct in_ifaddr * 452 ifptoia(ifp) 453 struct ifnet *ifp; 454 { 455 register struct in_ifaddr *ia; 456 457 for (ia = in_ifaddr; ia; ia = ia->ia_next) 458 if (ia->ia_ifp == ifp) 459 return (ia); 460 return ((struct in_ifaddr *)0); 461 } 462 463 /* 464 * Send an icmp packet back to the ip level, 465 * after supplying a checksum. 466 */ 467 icmp_send(m, opts) 468 register struct mbuf *m; 469 struct mbuf *opts; 470 { 471 register struct ip *ip = mtod(m, struct ip *); 472 register int hlen; 473 register struct icmp *icp; 474 475 hlen = ip->ip_hl << 2; 476 m->m_data += hlen; 477 m->m_len -= hlen; 478 icp = mtod(m, struct icmp *); 479 icp->icmp_cksum = 0; 480 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 481 m->m_data -= hlen; 482 m->m_len += hlen; 483 #ifdef ICMPPRINTFS 484 if (icmpprintfs) 485 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 486 #endif 487 (void) ip_output(m, opts, (struct route *)0, 0); 488 } 489 490 n_time 491 iptime() 492 { 493 struct timeval atv; 494 u_long t; 495 496 microtime(&atv); 497 t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 498 return (htonl(t)); 499 } 500