1 /* $NetBSD: ip_icmp.c,v 1.22 1996/10/13 02:03:04 christos 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 break; 348 if (ip->ip_dst.s_addr == INADDR_BROADCAST || 349 in_nullhost(ip->ip_dst)) 350 icmpdst.sin_addr = ip->ip_src; 351 else 352 icmpdst.sin_addr = ip->ip_dst; 353 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), 354 m->m_pkthdr.rcvif)); 355 if (ia == 0) 356 break; 357 icp->icmp_type = ICMP_MASKREPLY; 358 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 359 if (in_nullhost(ip->ip_src)) { 360 if (ia->ia_ifp->if_flags & IFF_BROADCAST) 361 ip->ip_src = ia->ia_broadaddr.sin_addr; 362 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 363 ip->ip_src = ia->ia_dstaddr.sin_addr; 364 } 365 reflect: 366 ip->ip_len += hlen; /* since ip_input deducts this */ 367 icmpstat.icps_reflect++; 368 icmpstat.icps_outhist[icp->icmp_type]++; 369 icmp_reflect(m); 370 return; 371 372 case ICMP_REDIRECT: 373 if (code > 3) 374 goto badcode; 375 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 376 icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 377 icmpstat.icps_badlen++; 378 break; 379 } 380 /* 381 * Short circuit routing redirects to force 382 * immediate change in the kernel's routing 383 * tables. The message is also handed to anyone 384 * listening on a raw socket (e.g. the routing 385 * daemon for use in updating its tables). 386 */ 387 icmpgw.sin_addr = ip->ip_src; 388 icmpdst.sin_addr = icp->icmp_gwaddr; 389 #ifdef ICMPPRINTFS 390 if (icmpprintfs) 391 printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 392 icp->icmp_gwaddr); 393 #endif 394 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 395 rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst), 396 (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 397 sintosa(&icmpgw), (struct rtentry **)0); 398 pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc)); 399 break; 400 401 /* 402 * No kernel processing for the following; 403 * just fall through to send to raw listener. 404 */ 405 case ICMP_ECHOREPLY: 406 case ICMP_ROUTERADVERT: 407 case ICMP_ROUTERSOLICIT: 408 case ICMP_TSTAMPREPLY: 409 case ICMP_IREQREPLY: 410 case ICMP_MASKREPLY: 411 default: 412 break; 413 } 414 415 raw: 416 rip_input(m); 417 return; 418 419 freeit: 420 m_freem(m); 421 } 422 423 /* 424 * Reflect the ip packet back to the source 425 */ 426 void 427 icmp_reflect(m) 428 struct mbuf *m; 429 { 430 register struct ip *ip = mtod(m, struct ip *); 431 register struct in_ifaddr *ia; 432 struct in_addr t; 433 struct mbuf *opts = 0; 434 int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 435 436 if (!in_canforward(ip->ip_src) && 437 ((ip->ip_src.s_addr & IN_CLASSA_NET) != 438 htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 439 m_freem(m); /* Bad return address */ 440 goto done; /* ip_output() will check for broadcast */ 441 } 442 t = ip->ip_dst; 443 ip->ip_dst = ip->ip_src; 444 /* 445 * If the incoming packet was addressed directly to us, 446 * use dst as the src for the reply. Otherwise (broadcast 447 * or anonymous), use the address which corresponds 448 * to the incoming interface. 449 */ 450 for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) { 451 if (in_hosteq(t, ia->ia_addr.sin_addr)) 452 break; 453 if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 454 in_hosteq(t, ia->ia_broadaddr.sin_addr)) 455 break; 456 } 457 icmpdst.sin_addr = t; 458 if (ia == (struct in_ifaddr *)0) 459 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), 460 m->m_pkthdr.rcvif)); 461 /* 462 * The following happens if the packet was not addressed to us, 463 * and was received on an interface with no IP address. 464 */ 465 if (ia == (struct in_ifaddr *)0) 466 ia = in_ifaddr.tqh_first; 467 t = ia->ia_addr.sin_addr; 468 ip->ip_src = t; 469 ip->ip_ttl = MAXTTL; 470 471 if (optlen > 0) { 472 register u_char *cp; 473 int opt, cnt; 474 u_int len; 475 476 /* 477 * Retrieve any source routing from the incoming packet; 478 * add on any record-route or timestamp options. 479 */ 480 cp = (u_char *) (ip + 1); 481 if ((opts = ip_srcroute()) == 0 && 482 (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 483 opts->m_len = sizeof(struct in_addr); 484 *mtod(opts, struct in_addr *) = zeroin_addr; 485 } 486 if (opts) { 487 #ifdef ICMPPRINTFS 488 if (icmpprintfs) 489 printf("icmp_reflect optlen %d rt %d => ", 490 optlen, opts->m_len); 491 #endif 492 for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 493 opt = cp[IPOPT_OPTVAL]; 494 if (opt == IPOPT_EOL) 495 break; 496 if (opt == IPOPT_NOP) 497 len = 1; 498 else { 499 len = cp[IPOPT_OLEN]; 500 if (len <= 0 || len > cnt) 501 break; 502 } 503 /* 504 * Should check for overflow, but it "can't happen" 505 */ 506 if (opt == IPOPT_RR || opt == IPOPT_TS || 507 opt == IPOPT_SECURITY) { 508 bcopy((caddr_t)cp, 509 mtod(opts, caddr_t) + opts->m_len, len); 510 opts->m_len += len; 511 } 512 } 513 /* Terminate & pad, if necessary */ 514 if ((cnt = opts->m_len % 4) != 0) { 515 for (; cnt < 4; cnt++) { 516 *(mtod(opts, caddr_t) + opts->m_len) = 517 IPOPT_EOL; 518 opts->m_len++; 519 } 520 } 521 #ifdef ICMPPRINTFS 522 if (icmpprintfs) 523 printf("%d\n", opts->m_len); 524 #endif 525 } 526 /* 527 * Now strip out original options by copying rest of first 528 * mbuf's data back, and adjust the IP length. 529 */ 530 ip->ip_len -= optlen; 531 ip->ip_hl = sizeof(struct ip) >> 2; 532 m->m_len -= optlen; 533 if (m->m_flags & M_PKTHDR) 534 m->m_pkthdr.len -= optlen; 535 optlen += sizeof(struct ip); 536 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 537 (unsigned)(m->m_len - sizeof(struct ip))); 538 } 539 m->m_flags &= ~(M_BCAST|M_MCAST); 540 icmp_send(m, opts); 541 done: 542 if (opts) 543 (void)m_free(opts); 544 } 545 546 /* 547 * Send an icmp packet back to the ip level, 548 * after supplying a checksum. 549 */ 550 void 551 icmp_send(m, opts) 552 register struct mbuf *m; 553 struct mbuf *opts; 554 { 555 register struct ip *ip = mtod(m, struct ip *); 556 register int hlen; 557 register struct icmp *icp; 558 559 hlen = ip->ip_hl << 2; 560 m->m_data += hlen; 561 m->m_len -= hlen; 562 icp = mtod(m, struct icmp *); 563 icp->icmp_cksum = 0; 564 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 565 m->m_data -= hlen; 566 m->m_len += hlen; 567 #ifdef ICMPPRINTFS 568 if (icmpprintfs) 569 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 570 #endif 571 (void) ip_output(m, opts, NULL, 0, NULL); 572 } 573 574 n_time 575 iptime() 576 { 577 struct timeval atv; 578 u_long t; 579 580 microtime(&atv); 581 t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 582 return (htonl(t)); 583 } 584 585 int 586 icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 587 int *name; 588 u_int namelen; 589 void *oldp; 590 size_t *oldlenp; 591 void *newp; 592 size_t newlen; 593 { 594 595 /* All sysctl names at this level are terminal. */ 596 if (namelen != 1) 597 return (ENOTDIR); 598 599 switch (name[0]) { 600 case ICMPCTL_MASKREPL: 601 return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl)); 602 default: 603 return (ENOPROTOOPT); 604 } 605 /* NOTREACHED */ 606 } 607