1 /* $NetBSD: ip_icmp.c,v 1.23 1997/06/24 01:26:19 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/mbuf.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/time.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 48 #include <vm/vm.h> 49 #include <sys/sysctl.h> 50 51 #include <net/if.h> 52 #include <net/route.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/in_var.h> 57 #include <netinet/ip.h> 58 #include <netinet/ip_icmp.h> 59 #include <netinet/ip_var.h> 60 #include <netinet/icmp_var.h> 61 62 #include <machine/stdarg.h> 63 64 /* 65 * ICMP routines: error generation, receive packet processing, and 66 * routines to turnaround packets back to the originator, and 67 * host table maintenance routines. 68 */ 69 70 int icmpmaskrepl = 0; 71 #ifdef ICMPPRINTFS 72 int icmpprintfs = 0; 73 #endif 74 75 extern struct protosw inetsw[]; 76 77 /* 78 * Generate an error packet of type error 79 * in response to bad packet ip. 80 */ 81 void 82 icmp_error(n, type, code, dest, destifp) 83 struct mbuf *n; 84 int type, code; 85 n_long dest; 86 struct ifnet *destifp; 87 { 88 register struct ip *oip = mtod(n, struct ip *), *nip; 89 register unsigned oiplen = oip->ip_hl << 2; 90 register struct icmp *icp; 91 register struct mbuf *m; 92 unsigned icmplen; 93 94 #ifdef ICMPPRINTFS 95 if (icmpprintfs) 96 printf("icmp_error(%x, %d, %d)\n", oip, type, code); 97 #endif 98 if (type != ICMP_REDIRECT) 99 icmpstat.icps_error++; 100 /* 101 * Don't send error if not the first fragment of message. 102 * Don't error if the old packet protocol was ICMP 103 * error message, only known informational types. 104 */ 105 if (oip->ip_off &~ (IP_MF|IP_DF)) 106 goto freeit; 107 if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 108 n->m_len >= oiplen + ICMP_MINLEN && 109 !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 110 icmpstat.icps_oldicmp++; 111 goto freeit; 112 } 113 /* Don't send error in response to a multicast or broadcast packet */ 114 if (n->m_flags & (M_BCAST|M_MCAST)) 115 goto freeit; 116 /* 117 * First, formulate icmp message 118 */ 119 m = m_gethdr(M_DONTWAIT, MT_HEADER); 120 if (m == NULL) 121 goto freeit; 122 icmplen = oiplen + min(8, oip->ip_len); 123 m->m_len = icmplen + ICMP_MINLEN; 124 MH_ALIGN(m, m->m_len); 125 icp = mtod(m, struct icmp *); 126 if ((u_int)type > ICMP_MAXTYPE) 127 panic("icmp_error"); 128 icmpstat.icps_outhist[type]++; 129 icp->icmp_type = type; 130 if (type == ICMP_REDIRECT) 131 icp->icmp_gwaddr.s_addr = dest; 132 else { 133 icp->icmp_void = 0; 134 /* 135 * The following assignments assume an overlay with the 136 * zeroed icmp_void field. 137 */ 138 if (type == ICMP_PARAMPROB) { 139 icp->icmp_pptr = code; 140 code = 0; 141 } else if (type == ICMP_UNREACH && 142 code == ICMP_UNREACH_NEEDFRAG && destifp) 143 icp->icmp_nextmtu = htons(destifp->if_mtu); 144 } 145 146 icp->icmp_code = code; 147 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 148 nip = &icp->icmp_ip; 149 nip->ip_len = htons((u_int16_t)(nip->ip_len + oiplen)); 150 151 /* 152 * Now, copy old ip header (without options) 153 * in front of icmp message. 154 */ 155 if (m->m_data - sizeof(struct ip) < m->m_pktdat) 156 panic("icmp len"); 157 m->m_data -= sizeof(struct ip); 158 m->m_len += sizeof(struct ip); 159 m->m_pkthdr.len = m->m_len; 160 m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 161 nip = mtod(m, struct ip *); 162 bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 163 nip->ip_len = m->m_len; 164 nip->ip_hl = sizeof(struct ip) >> 2; 165 nip->ip_p = IPPROTO_ICMP; 166 nip->ip_tos = 0; 167 icmp_reflect(m); 168 169 freeit: 170 m_freem(n); 171 } 172 173 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 174 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 175 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 176 struct sockaddr_in icmpmask = { 8, 0 }; 177 178 /* 179 * Process a received ICMP message. 180 */ 181 void 182 #if __STDC__ 183 icmp_input(struct mbuf *m, ...) 184 #else 185 icmp_input(m, va_alist) 186 struct mbuf *m; 187 va_dcl 188 #endif 189 { 190 register struct icmp *icp; 191 register struct ip *ip = mtod(m, struct ip *); 192 int icmplen = ip->ip_len; 193 register int i; 194 struct in_ifaddr *ia; 195 void *(*ctlfunc) __P((int, struct sockaddr *, void *)); 196 int code; 197 extern u_char ip_protox[]; 198 int hlen; 199 va_list ap; 200 201 va_start(ap, m); 202 hlen = va_arg(ap, int); 203 va_end(ap); 204 205 /* 206 * Locate icmp structure in mbuf, and check 207 * that not corrupted and of at least minimum length. 208 */ 209 #ifdef ICMPPRINTFS 210 if (icmpprintfs) 211 printf("icmp_input from %x to %x, len %d\n", 212 ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), 213 icmplen); 214 #endif 215 if (icmplen < ICMP_MINLEN) { 216 icmpstat.icps_tooshort++; 217 goto freeit; 218 } 219 i = hlen + min(icmplen, ICMP_ADVLENMIN); 220 if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 221 icmpstat.icps_tooshort++; 222 return; 223 } 224 ip = mtod(m, struct ip *); 225 m->m_len -= hlen; 226 m->m_data += hlen; 227 icp = mtod(m, struct icmp *); 228 if (in_cksum(m, icmplen)) { 229 icmpstat.icps_checksum++; 230 goto freeit; 231 } 232 m->m_len += hlen; 233 m->m_data -= hlen; 234 235 #ifdef ICMPPRINTFS 236 /* 237 * Message type specific processing. 238 */ 239 if (icmpprintfs) 240 printf("icmp_input, type %d code %d\n", icp->icmp_type, 241 icp->icmp_code); 242 #endif 243 if (icp->icmp_type > ICMP_MAXTYPE) 244 goto raw; 245 icmpstat.icps_inhist[icp->icmp_type]++; 246 code = icp->icmp_code; 247 switch (icp->icmp_type) { 248 249 case ICMP_UNREACH: 250 switch (code) { 251 case ICMP_UNREACH_NET: 252 case ICMP_UNREACH_HOST: 253 case ICMP_UNREACH_PROTOCOL: 254 case ICMP_UNREACH_PORT: 255 case ICMP_UNREACH_SRCFAIL: 256 code += PRC_UNREACH_NET; 257 break; 258 259 case ICMP_UNREACH_NEEDFRAG: 260 code = PRC_MSGSIZE; 261 break; 262 263 case ICMP_UNREACH_NET_UNKNOWN: 264 case ICMP_UNREACH_NET_PROHIB: 265 case ICMP_UNREACH_TOSNET: 266 code = PRC_UNREACH_NET; 267 break; 268 269 case ICMP_UNREACH_HOST_UNKNOWN: 270 case ICMP_UNREACH_ISOLATED: 271 case ICMP_UNREACH_HOST_PROHIB: 272 case ICMP_UNREACH_TOSHOST: 273 code = PRC_UNREACH_HOST; 274 break; 275 276 default: 277 goto badcode; 278 } 279 goto deliver; 280 281 case ICMP_TIMXCEED: 282 if (code > 1) 283 goto badcode; 284 code += PRC_TIMXCEED_INTRANS; 285 goto deliver; 286 287 case ICMP_PARAMPROB: 288 if (code > 1) 289 goto badcode; 290 code = PRC_PARAMPROB; 291 goto deliver; 292 293 case ICMP_SOURCEQUENCH: 294 if (code) 295 goto badcode; 296 code = PRC_QUENCH; 297 goto deliver; 298 299 deliver: 300 /* 301 * Problem with datagram; advise higher level routines. 302 */ 303 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 304 icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 305 icmpstat.icps_badlen++; 306 goto freeit; 307 } 308 if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr)) 309 goto badcode; 310 NTOHS(icp->icmp_ip.ip_len); 311 #ifdef ICMPPRINTFS 312 if (icmpprintfs) 313 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 314 #endif 315 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 316 ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 317 if (ctlfunc) 318 (*ctlfunc)(code, sintosa(&icmpsrc), &icp->icmp_ip); 319 break; 320 321 badcode: 322 icmpstat.icps_badcode++; 323 break; 324 325 case ICMP_ECHO: 326 icp->icmp_type = ICMP_ECHOREPLY; 327 goto reflect; 328 329 case ICMP_TSTAMP: 330 if (icmplen < ICMP_TSLEN) { 331 icmpstat.icps_badlen++; 332 break; 333 } 334 icp->icmp_type = ICMP_TSTAMPREPLY; 335 icp->icmp_rtime = iptime(); 336 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 337 goto reflect; 338 339 case ICMP_MASKREQ: 340 if (icmpmaskrepl == 0) 341 break; 342 /* 343 * We are not able to respond with all ones broadcast 344 * unless we receive it over a point-to-point interface. 345 */ 346 if (icmplen < ICMP_MASKLEN) { 347 icmpstat.icps_badlen++; 348 break; 349 } 350 if (ip->ip_dst.s_addr == INADDR_BROADCAST || 351 in_nullhost(ip->ip_dst)) 352 icmpdst.sin_addr = ip->ip_src; 353 else 354 icmpdst.sin_addr = ip->ip_dst; 355 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), 356 m->m_pkthdr.rcvif)); 357 if (ia == 0) 358 break; 359 icp->icmp_type = ICMP_MASKREPLY; 360 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 361 if (in_nullhost(ip->ip_src)) { 362 if (ia->ia_ifp->if_flags & IFF_BROADCAST) 363 ip->ip_src = ia->ia_broadaddr.sin_addr; 364 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 365 ip->ip_src = ia->ia_dstaddr.sin_addr; 366 } 367 reflect: 368 ip->ip_len += hlen; /* since ip_input deducts this */ 369 icmpstat.icps_reflect++; 370 icmpstat.icps_outhist[icp->icmp_type]++; 371 icmp_reflect(m); 372 return; 373 374 case ICMP_REDIRECT: 375 if (code > 3) 376 goto badcode; 377 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 378 icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 379 icmpstat.icps_badlen++; 380 break; 381 } 382 /* 383 * Short circuit routing redirects to force 384 * immediate change in the kernel's routing 385 * tables. The message is also handed to anyone 386 * listening on a raw socket (e.g. the routing 387 * daemon for use in updating its tables). 388 */ 389 icmpgw.sin_addr = ip->ip_src; 390 icmpdst.sin_addr = icp->icmp_gwaddr; 391 #ifdef ICMPPRINTFS 392 if (icmpprintfs) 393 printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 394 icp->icmp_gwaddr); 395 #endif 396 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 397 rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst), 398 (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 399 sintosa(&icmpgw), (struct rtentry **)0); 400 pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc)); 401 break; 402 403 /* 404 * No kernel processing for the following; 405 * just fall through to send to raw listener. 406 */ 407 case ICMP_ECHOREPLY: 408 case ICMP_ROUTERADVERT: 409 case ICMP_ROUTERSOLICIT: 410 case ICMP_TSTAMPREPLY: 411 case ICMP_IREQREPLY: 412 case ICMP_MASKREPLY: 413 default: 414 break; 415 } 416 417 raw: 418 rip_input(m); 419 return; 420 421 freeit: 422 m_freem(m); 423 } 424 425 /* 426 * Reflect the ip packet back to the source 427 */ 428 void 429 icmp_reflect(m) 430 struct mbuf *m; 431 { 432 register struct ip *ip = mtod(m, struct ip *); 433 register struct in_ifaddr *ia; 434 struct in_addr t; 435 struct mbuf *opts = 0; 436 int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 437 438 if (!in_canforward(ip->ip_src) && 439 ((ip->ip_src.s_addr & IN_CLASSA_NET) != 440 htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 441 m_freem(m); /* Bad return address */ 442 goto done; /* ip_output() will check for broadcast */ 443 } 444 t = ip->ip_dst; 445 ip->ip_dst = ip->ip_src; 446 /* 447 * If the incoming packet was addressed directly to us, 448 * use dst as the src for the reply. Otherwise (broadcast 449 * or anonymous), use the address which corresponds 450 * to the incoming interface. 451 */ 452 for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) { 453 if (in_hosteq(t, ia->ia_addr.sin_addr)) 454 break; 455 if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 456 in_hosteq(t, ia->ia_broadaddr.sin_addr)) 457 break; 458 } 459 icmpdst.sin_addr = t; 460 if (ia == (struct in_ifaddr *)0) 461 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), 462 m->m_pkthdr.rcvif)); 463 /* 464 * The following happens if the packet was not addressed to us, 465 * and was received on an interface with no IP address. 466 */ 467 if (ia == (struct in_ifaddr *)0) 468 ia = in_ifaddr.tqh_first; 469 t = ia->ia_addr.sin_addr; 470 ip->ip_src = t; 471 ip->ip_ttl = MAXTTL; 472 473 if (optlen > 0) { 474 register u_char *cp; 475 int opt, cnt; 476 u_int len; 477 478 /* 479 * Retrieve any source routing from the incoming packet; 480 * add on any record-route or timestamp options. 481 */ 482 cp = (u_char *) (ip + 1); 483 if ((opts = ip_srcroute()) == 0 && 484 (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 485 opts->m_len = sizeof(struct in_addr); 486 *mtod(opts, struct in_addr *) = zeroin_addr; 487 } 488 if (opts) { 489 #ifdef ICMPPRINTFS 490 if (icmpprintfs) 491 printf("icmp_reflect optlen %d rt %d => ", 492 optlen, opts->m_len); 493 #endif 494 for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 495 opt = cp[IPOPT_OPTVAL]; 496 if (opt == IPOPT_EOL) 497 break; 498 if (opt == IPOPT_NOP) 499 len = 1; 500 else { 501 len = cp[IPOPT_OLEN]; 502 if (len <= 0 || len > cnt) 503 break; 504 } 505 /* 506 * Should check for overflow, but it "can't happen" 507 */ 508 if (opt == IPOPT_RR || opt == IPOPT_TS || 509 opt == IPOPT_SECURITY) { 510 bcopy((caddr_t)cp, 511 mtod(opts, caddr_t) + opts->m_len, len); 512 opts->m_len += len; 513 } 514 } 515 /* Terminate & pad, if necessary */ 516 if ((cnt = opts->m_len % 4) != 0) { 517 for (; cnt < 4; cnt++) { 518 *(mtod(opts, caddr_t) + opts->m_len) = 519 IPOPT_EOL; 520 opts->m_len++; 521 } 522 } 523 #ifdef ICMPPRINTFS 524 if (icmpprintfs) 525 printf("%d\n", opts->m_len); 526 #endif 527 } 528 /* 529 * Now strip out original options by copying rest of first 530 * mbuf's data back, and adjust the IP length. 531 */ 532 ip->ip_len -= optlen; 533 ip->ip_hl = sizeof(struct ip) >> 2; 534 m->m_len -= optlen; 535 if (m->m_flags & M_PKTHDR) 536 m->m_pkthdr.len -= optlen; 537 optlen += sizeof(struct ip); 538 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 539 (unsigned)(m->m_len - sizeof(struct ip))); 540 } 541 m->m_flags &= ~(M_BCAST|M_MCAST); 542 icmp_send(m, opts); 543 done: 544 if (opts) 545 (void)m_free(opts); 546 } 547 548 /* 549 * Send an icmp packet back to the ip level, 550 * after supplying a checksum. 551 */ 552 void 553 icmp_send(m, opts) 554 register struct mbuf *m; 555 struct mbuf *opts; 556 { 557 register struct ip *ip = mtod(m, struct ip *); 558 register int hlen; 559 register struct icmp *icp; 560 561 hlen = ip->ip_hl << 2; 562 m->m_data += hlen; 563 m->m_len -= hlen; 564 icp = mtod(m, struct icmp *); 565 icp->icmp_cksum = 0; 566 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 567 m->m_data -= hlen; 568 m->m_len += hlen; 569 #ifdef ICMPPRINTFS 570 if (icmpprintfs) 571 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 572 #endif 573 (void) ip_output(m, opts, NULL, 0, NULL); 574 } 575 576 n_time 577 iptime() 578 { 579 struct timeval atv; 580 u_long t; 581 582 microtime(&atv); 583 t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 584 return (htonl(t)); 585 } 586 587 int 588 icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 589 int *name; 590 u_int namelen; 591 void *oldp; 592 size_t *oldlenp; 593 void *newp; 594 size_t newlen; 595 { 596 597 /* All sysctl names at this level are terminal. */ 598 if (namelen != 1) 599 return (ENOTDIR); 600 601 switch (name[0]) { 602 case ICMPCTL_MASKREPL: 603 return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl)); 604 default: 605 return (ENOPROTOOPT); 606 } 607 /* NOTREACHED */ 608 } 609