|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1988, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 ! 59: */ ! 60: ! 61: #import <sys/param.h> ! 62: #import <sys/systm.h> ! 63: #import <sys/malloc.h> ! 64: #import <sys/mbuf.h> ! 65: #import <sys/protosw.h> ! 66: #import <sys/socket.h> ! 67: #import <sys/time.h> ! 68: #import <sys/kernel.h> ! 69: ! 70: #import <net/if.h> ! 71: #import <net/route.h> ! 72: ! 73: #import <netinet/in.h> ! 74: #import <netinet/in_systm.h> ! 75: #import <netinet/in_var.h> ! 76: #import <netinet/ip.h> ! 77: #import <netinet/ip_var.h> ! 78: #import <netinet/ip_icmp.h> ! 79: #import <netinet/icmp_var.h> ! 80: ! 81: /* ! 82: * ICMP routines: error generation, receive packet processing, and ! 83: * routines to turnaround packets back to the originator, and ! 84: * host table maintenance routines. ! 85: */ ! 86: ! 87: int icmpmaskrepl = 0; ! 88: int icmpbmcastecho = 0; ! 89: #ifdef ICMPPRINTFS ! 90: int icmpprintfs = 0; ! 91: #endif ! 92: ! 93: extern struct protosw inetsw[]; ! 94: ! 95: #if NeXT ! 96: static struct in_ifaddr * ! 97: ifptoia(ifp) ! 98: struct ifnet *ifp; ! 99: { ! 100: register struct in_ifaddr *ia; ! 101: ! 102: for (ia = in_ifaddr; ia; ia = ia->ia_next) ! 103: if (ia->ia_ifp == ifp) ! 104: return (ia); ! 105: return ((struct in_ifaddr *)0); ! 106: } ! 107: #endif NeXT ! 108: ! 109: /* ! 110: * Generate an error packet of type error ! 111: * in response to bad packet ip. ! 112: */ ! 113: void ! 114: icmp_error(n, type, code, dest, destifp) ! 115: struct mbuf *n; ! 116: int type, code; ! 117: n_long dest; ! 118: struct ifnet *destifp; ! 119: { ! 120: register struct ip *oip = mtod(n, struct ip *), *nip; ! 121: register unsigned oiplen = oip->ip_hl << 2; ! 122: register struct icmp *icp; ! 123: register struct mbuf *m; ! 124: unsigned icmplen; ! 125: ! 126: #ifdef ICMPPRINTFS ! 127: if (icmpprintfs) ! 128: printf("icmp_error(%x, %d, %d)\n", oip, type, code); ! 129: #endif ! 130: if (type != ICMP_REDIRECT) ! 131: icmpstat.icps_error++; ! 132: /* ! 133: * Don't send error if not the first fragment of message. ! 134: * Don't error if the old packet protocol was ICMP ! 135: * error message, only known informational types. ! 136: */ ! 137: if (oip->ip_off &~ (IP_MF|IP_DF)) ! 138: goto freeit; ! 139: if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && ! 140: n->m_len >= oiplen + ICMP_MINLEN && ! 141: !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { ! 142: icmpstat.icps_oldicmp++; ! 143: goto freeit; ! 144: } ! 145: /* Don't send error in response to a multicast or broadcast packet */ ! 146: if (n->m_flags & (M_BCAST|M_MCAST)) ! 147: goto freeit; ! 148: /* ! 149: * First, formulate icmp message ! 150: */ ! 151: m = m_gethdr(M_DONTWAIT, MT_HEADER); ! 152: if (m == NULL) ! 153: goto freeit; ! 154: icmplen = oiplen + min(8, oip->ip_len); ! 155: m->m_len = icmplen + ICMP_MINLEN; ! 156: MH_ALIGN(m, m->m_len); ! 157: icp = mtod(m, struct icmp *); ! 158: if ((u_int)type > ICMP_MAXTYPE) ! 159: panic("icmp_error"); ! 160: icmpstat.icps_outhist[type]++; ! 161: icp->icmp_type = type; ! 162: if (type == ICMP_REDIRECT) ! 163: icp->icmp_gwaddr.s_addr = dest; ! 164: else { ! 165: icp->icmp_void = 0; ! 166: /* ! 167: * The following assignments assume an overlay with the ! 168: * zeroed icmp_void field. ! 169: */ ! 170: if (type == ICMP_PARAMPROB) { ! 171: icp->icmp_pptr = code; ! 172: code = 0; ! 173: } else if (type == ICMP_UNREACH && ! 174: code == ICMP_UNREACH_NEEDFRAG && destifp) { ! 175: icp->icmp_nextmtu = htons(destifp->if_mtu); ! 176: } ! 177: } ! 178: ! 179: icp->icmp_code = code; ! 180: bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); ! 181: nip = &icp->icmp_ip; ! 182: nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); ! 183: ! 184: /* ! 185: * Now, copy old ip header (without options) ! 186: * in front of icmp message. ! 187: */ ! 188: if (m->m_data - sizeof(struct ip) < m->m_pktdat) ! 189: panic("icmp len"); ! 190: m->m_data -= sizeof(struct ip); ! 191: m->m_len += sizeof(struct ip); ! 192: m->m_pkthdr.len = m->m_len; ! 193: m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; ! 194: nip = mtod(m, struct ip *); ! 195: bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); ! 196: nip->ip_len = m->m_len; ! 197: nip->ip_hl = sizeof(struct ip) >> 2; ! 198: nip->ip_p = IPPROTO_ICMP; ! 199: nip->ip_tos = 0; ! 200: icmp_reflect(m); ! 201: ! 202: freeit: ! 203: m_freem(n); ! 204: } ! 205: ! 206: static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; ! 207: static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; ! 208: static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; ! 209: struct sockaddr_in icmpmask = { 8, 0 }; ! 210: ! 211: /* ! 212: * Process a received ICMP message. ! 213: */ ! 214: void ! 215: icmp_input(m, hlen) ! 216: register struct mbuf *m; ! 217: int hlen; ! 218: { ! 219: register struct icmp *icp; ! 220: register struct ip *ip = mtod(m, struct ip *); ! 221: unsigned int icmplen = (unsigned short)ip->ip_len; ! 222: register int i; ! 223: struct in_ifaddr *ia; ! 224: void (*ctlfunc) __P((int, struct sockaddr *, struct ip *)); ! 225: int code; ! 226: extern u_char ip_protox[]; ! 227: ! 228: /* ! 229: * Locate icmp structure in mbuf, and check ! 230: * that not corrupted and of at least minimum length. ! 231: */ ! 232: #ifdef ICMPPRINTFS ! 233: if (icmpprintfs) ! 234: printf("icmp_input from %x to %x, len %d\n", ! 235: ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ! 236: icmplen); ! 237: #endif ! 238: if (icmplen < ICMP_MINLEN) { ! 239: icmpstat.icps_tooshort++; ! 240: goto freeit; ! 241: } ! 242: i = hlen + min(icmplen, ICMP_ADVLENMIN); ! 243: if (m->m_len < i && (m = m_pullup(m, i)) == 0) { ! 244: icmpstat.icps_tooshort++; ! 245: return; ! 246: } ! 247: ip = mtod(m, struct ip *); ! 248: m->m_len -= hlen; ! 249: m->m_data += hlen; ! 250: icp = mtod(m, struct icmp *); ! 251: if (in_cksum(m, icmplen)) { ! 252: icmpstat.icps_checksum++; ! 253: goto freeit; ! 254: } ! 255: m->m_len += hlen; ! 256: m->m_data -= hlen; ! 257: ! 258: #ifdef ICMPPRINTFS ! 259: /* ! 260: * Message type specific processing. ! 261: */ ! 262: if (icmpprintfs) ! 263: printf("icmp_input, type %d code %d\n", icp->icmp_type, ! 264: icp->icmp_code); ! 265: #endif ! 266: if (icp->icmp_type > ICMP_MAXTYPE) ! 267: goto raw; ! 268: icmpstat.icps_inhist[icp->icmp_type]++; ! 269: code = icp->icmp_code; ! 270: switch (icp->icmp_type) { ! 271: ! 272: case ICMP_UNREACH: ! 273: switch (code) { ! 274: case ICMP_UNREACH_NET: ! 275: case ICMP_UNREACH_HOST: ! 276: case ICMP_UNREACH_PROTOCOL: ! 277: case ICMP_UNREACH_PORT: ! 278: case ICMP_UNREACH_SRCFAIL: ! 279: code += PRC_UNREACH_NET; ! 280: break; ! 281: ! 282: case ICMP_UNREACH_NEEDFRAG: ! 283: code = PRC_MSGSIZE; ! 284: break; ! 285: ! 286: case ICMP_UNREACH_NET_UNKNOWN: ! 287: case ICMP_UNREACH_NET_PROHIB: ! 288: case ICMP_UNREACH_TOSNET: ! 289: code = PRC_UNREACH_NET; ! 290: break; ! 291: ! 292: case ICMP_UNREACH_HOST_UNKNOWN: ! 293: case ICMP_UNREACH_ISOLATED: ! 294: case ICMP_UNREACH_HOST_PROHIB: ! 295: case ICMP_UNREACH_TOSHOST: ! 296: code = PRC_UNREACH_HOST; ! 297: break; ! 298: ! 299: default: ! 300: goto badcode; ! 301: } ! 302: goto deliver; ! 303: ! 304: case ICMP_TIMXCEED: ! 305: if (code > 1) ! 306: goto badcode; ! 307: code += PRC_TIMXCEED_INTRANS; ! 308: goto deliver; ! 309: ! 310: case ICMP_PARAMPROB: ! 311: if (code > 1) ! 312: goto badcode; ! 313: code = PRC_PARAMPROB; ! 314: goto deliver; ! 315: ! 316: case ICMP_SOURCEQUENCH: ! 317: if (code) ! 318: goto badcode; ! 319: code = PRC_QUENCH; ! 320: deliver: ! 321: /* ! 322: * Problem with datagram; advise higher level routines. ! 323: */ ! 324: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || ! 325: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { ! 326: icmpstat.icps_badlen++; ! 327: goto freeit; ! 328: } ! 329: NTOHS(icp->icmp_ip.ip_len); ! 330: #ifdef ICMPPRINTFS ! 331: if (icmpprintfs) ! 332: printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); ! 333: #endif ! 334: icmpsrc.sin_addr = icp->icmp_ip.ip_dst; ! 335: if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) ! 336: (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, ! 337: &icp->icmp_ip); ! 338: break; ! 339: ! 340: badcode: ! 341: icmpstat.icps_badcode++; ! 342: break; ! 343: ! 344: case ICMP_ECHO: ! 345: if (!icmpbmcastecho ! 346: && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { ! 347: break; ! 348: } ! 349: icp->icmp_type = ICMP_ECHOREPLY; ! 350: goto reflect; ! 351: ! 352: case ICMP_TSTAMP: ! 353: if (!icmpbmcastecho ! 354: && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { ! 355: break; ! 356: } ! 357: if (icmplen < ICMP_TSLEN) { ! 358: icmpstat.icps_badlen++; ! 359: break; ! 360: } ! 361: icp->icmp_type = ICMP_TSTAMPREPLY; ! 362: icp->icmp_rtime = iptime(); ! 363: icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ ! 364: goto reflect; ! 365: ! 366: case ICMP_MASKREQ: ! 367: #define satosin(sa) ((struct sockaddr_in *)(sa)) ! 368: if (icmpmaskrepl == 0) ! 369: break; ! 370: /* ! 371: * We are not able to respond with all ones broadcast ! 372: * unless we receive it over a point-to-point interface. ! 373: */ ! 374: if (icmplen < ICMP_MASKLEN) ! 375: break; ! 376: switch (ip->ip_dst.s_addr) { ! 377: ! 378: case INADDR_BROADCAST: ! 379: case INADDR_ANY: ! 380: icmpdst.sin_addr = ip->ip_src; ! 381: break; ! 382: ! 383: default: ! 384: icmpdst.sin_addr = ip->ip_dst; ! 385: } ! 386: ia = (struct in_ifaddr *)ifaof_ifpforaddr( ! 387: (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); ! 388: if (ia == 0) ! 389: break; ! 390: icp->icmp_type = ICMP_MASKREPLY; ! 391: icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; ! 392: if (ip->ip_src.s_addr == 0) { ! 393: if (ia->ia_ifp->if_flags & IFF_BROADCAST) ! 394: ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; ! 395: else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) ! 396: ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; ! 397: } ! 398: reflect: ! 399: ip->ip_len += hlen; /* since ip_input deducts this */ ! 400: icmpstat.icps_reflect++; ! 401: icmpstat.icps_outhist[icp->icmp_type]++; ! 402: icmp_reflect(m); ! 403: return; ! 404: ! 405: case ICMP_REDIRECT: ! 406: if (code > 3) ! 407: goto badcode; ! 408: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || ! 409: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { ! 410: icmpstat.icps_badlen++; ! 411: break; ! 412: } ! 413: /* ! 414: * Short circuit routing redirects to force ! 415: * immediate change in the kernel's routing ! 416: * tables. The message is also handed to anyone ! 417: * listening on a raw socket (e.g. the routing ! 418: * daemon for use in updating its tables). ! 419: */ ! 420: icmpgw.sin_addr = ip->ip_src; ! 421: icmpdst.sin_addr = icp->icmp_gwaddr; ! 422: #ifdef ICMPPRINTFS ! 423: if (icmpprintfs) ! 424: printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, ! 425: icp->icmp_gwaddr); ! 426: #endif ! 427: icmpsrc.sin_addr = icp->icmp_ip.ip_dst; ! 428: rtredirect((struct sockaddr *)&icmpsrc, ! 429: (struct sockaddr *)&icmpdst, ! 430: (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, ! 431: (struct sockaddr *)&icmpgw, (struct rtentry **)0); ! 432: pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); ! 433: break; ! 434: #if NeXT ! 435: case ICMP_MASKREPLY: ! 436: { ! 437: struct ifnet *ifp = m->m_pkthdr.rcvif; ! 438: u_long mask; ! 439: ! 440: /* ! 441: * Conditions for accepting a new netmask have changed for NEXTSTEP 3.2 ! 442: * to meet RFC1122 requirements. Now we accept only one NETMASK_REPLY ! 443: * packet, accept either directed or broadcast packets, and check for ! 444: * reasonable netmask values in the packet. We maintain the previous ! 445: * condition that we reconfigure the ! 446: * netmask and broadcast address only if the provided subnetmask is ! 447: * larger than the current one. ! 448: */ ! 449: if ((ia = ifptoia(ifp)) && (ifp->if_eflags & IFEF_AWAITING_NETMASK)) { ! 450: /* Check for reasonable mask */ ! 451: /* i.e. highest-order byte = 0xff and not all ones */ ! 452: mask = ntohl(icp->icmp_mask); ! 453: if ((mask == 0xffffffff) || ( (mask & 0xff000000) != 0xff000000)) ! 454: break; ! 455: ! 456: ifp->if_eflags &= ~(IFEF_AWAITING_NETMASK); ! 457: if (!(ifp->if_flags & IFF_LOOPBACK) ! 458: && ((ia->ia_subnetmask|mask) != ia->ia_subnetmask)) { ! 459: int err; ! 460: ia->ia_subnetmask |= mask; ! 461: ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); ! 462: if (err = in_ifinit(ifp, ia, (struct sockaddr_in *) ! 463: &ia->ia_addr, 1)) { ! 464: printf("icmp_input: in_ifinit failed, error = %d\n", ! 465: err); ! 466: } ! 467: else { ! 468: printf("%s%d: setting netmask to %x, received from %s\n", ! 469: ifp->if_name, ifp->if_unit, ! 470: mask, inet_ntoa(&ip->ip_src.s_addr)); ! 471: wakeup(&ia->ia_subnetmask); ! 472: } ! 473: } ! 474: } ! 475: } ! 476: /* Fall through */ ! 477: #endif NeXT ! 478: ! 479: ! 480: /* ! 481: * No kernel processing for the following; ! 482: * just fall through to send to raw listener. ! 483: */ ! 484: case ICMP_ECHOREPLY: ! 485: case ICMP_ROUTERADVERT: ! 486: case ICMP_ROUTERSOLICIT: ! 487: case ICMP_TSTAMPREPLY: ! 488: case ICMP_IREQREPLY: ! 489: default: ! 490: break; ! 491: } ! 492: ! 493: raw: ! 494: rip_input(m); ! 495: return; ! 496: ! 497: freeit: ! 498: m_freem(m); ! 499: } ! 500: ! 501: /* ! 502: * Reflect the ip packet back to the source ! 503: */ ! 504: void ! 505: icmp_reflect(m) ! 506: struct mbuf *m; ! 507: { ! 508: register struct ip *ip = mtod(m, struct ip *); ! 509: register struct in_ifaddr *ia; ! 510: struct in_addr t; ! 511: struct mbuf *opts = 0, *ip_srcroute(); ! 512: int optlen = (ip->ip_hl << 2) - sizeof(struct ip); ! 513: ! 514: if (!in_canforward(ip->ip_src) && ! 515: ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != ! 516: (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { ! 517: m_freem(m); /* Bad return address */ ! 518: goto done; /* Ip_output() will check for broadcast */ ! 519: } ! 520: t = ip->ip_dst; ! 521: ip->ip_dst = ip->ip_src; ! 522: /* ! 523: * If the incoming packet was addressed directly to us, ! 524: * use dst as the src for the reply. Otherwise (broadcast ! 525: * or anonymous), use the address which corresponds ! 526: * to the incoming interface. ! 527: */ ! 528: for (ia = in_ifaddr; ia; ia = ia->ia_next) { ! 529: if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) ! 530: break; ! 531: if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && ! 532: t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) ! 533: break; ! 534: } ! 535: icmpdst.sin_addr = t; ! 536: if (ia == (struct in_ifaddr *)0) ! 537: ia = (struct in_ifaddr *)ifaof_ifpforaddr( ! 538: (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); ! 539: /* ! 540: * The following happens if the packet was not addressed to us, ! 541: * and was received on an interface with no IP address. ! 542: */ ! 543: if (ia == (struct in_ifaddr *)0) ! 544: ia = in_ifaddr; ! 545: t = IA_SIN(ia)->sin_addr; ! 546: ip->ip_src = t; ! 547: ip->ip_ttl = MAXTTL; ! 548: ! 549: if (optlen > 0) { ! 550: register u_char *cp; ! 551: int opt, cnt; ! 552: u_int len; ! 553: ! 554: /* ! 555: * Retrieve any source routing from the incoming packet; ! 556: * add on any record-route or timestamp options. ! 557: */ ! 558: cp = (u_char *) (ip + 1); ! 559: if ((opts = ip_srcroute()) == 0 && ! 560: (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { ! 561: opts->m_len = sizeof(struct in_addr); ! 562: mtod(opts, struct in_addr *)->s_addr = 0; ! 563: } ! 564: if (opts) { ! 565: #ifdef ICMPPRINTFS ! 566: if (icmpprintfs) ! 567: printf("icmp_reflect optlen %d rt %d => ", ! 568: optlen, opts->m_len); ! 569: #endif ! 570: for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { ! 571: opt = cp[IPOPT_OPTVAL]; ! 572: if (opt == IPOPT_EOL) ! 573: break; ! 574: if (opt == IPOPT_NOP) ! 575: len = 1; ! 576: else { ! 577: len = cp[IPOPT_OLEN]; ! 578: if (len <= 0 || len > cnt) ! 579: break; ! 580: } ! 581: /* ! 582: * Should check for overflow, but it "can't happen" ! 583: */ ! 584: if (opt == IPOPT_RR || opt == IPOPT_TS || ! 585: opt == IPOPT_SECURITY) { ! 586: bcopy((caddr_t)cp, ! 587: mtod(opts, caddr_t) + opts->m_len, len); ! 588: opts->m_len += len; ! 589: } ! 590: } ! 591: /* Terminate & pad, if necessary */ ! 592: if (cnt = opts->m_len % 4) { ! 593: for (; cnt < 4; cnt++) { ! 594: *(mtod(opts, caddr_t) + opts->m_len) = ! 595: IPOPT_EOL; ! 596: opts->m_len++; ! 597: } ! 598: } ! 599: #ifdef ICMPPRINTFS ! 600: if (icmpprintfs) ! 601: printf("%d\n", opts->m_len); ! 602: #endif ! 603: } ! 604: /* ! 605: * Now strip out original options by copying rest of first ! 606: * mbuf's data back, and adjust the IP length. ! 607: */ ! 608: ip->ip_len -= optlen; ! 609: ip->ip_hl = sizeof(struct ip) >> 2; ! 610: m->m_len -= optlen; ! 611: if (m->m_flags & M_PKTHDR) ! 612: m->m_pkthdr.len -= optlen; ! 613: optlen += sizeof(struct ip); ! 614: bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), ! 615: (unsigned)(m->m_len - sizeof(struct ip))); ! 616: } ! 617: m->m_flags &= ~(M_BCAST|M_MCAST); ! 618: icmp_send(m, opts); ! 619: done: ! 620: if (opts) ! 621: (void)m_free(opts); ! 622: } ! 623: ! 624: /* ! 625: * Send an icmp packet back to the ip level, ! 626: * after supplying a checksum. ! 627: */ ! 628: void ! 629: icmp_send(m, opts) ! 630: register struct mbuf *m; ! 631: struct mbuf *opts; ! 632: { ! 633: register struct ip *ip = mtod(m, struct ip *); ! 634: register unsigned int hlen; ! 635: register struct icmp *icp; ! 636: unsigned int ulen; ! 637: ! 638: hlen = (unsigned short)ip->ip_hl << 2; ! 639: m->m_data += hlen; ! 640: m->m_len -= hlen; ! 641: icp = mtod(m, struct icmp *); ! 642: icp->icmp_cksum = 0; ! 643: ulen = (unsigned short)ip->ip_len - hlen; ! 644: icp->icmp_cksum = in_cksum(m, ulen); ! 645: m->m_data -= hlen; ! 646: m->m_len += hlen; ! 647: #ifdef ICMPPRINTFS ! 648: if (icmpprintfs) ! 649: printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); ! 650: #endif ! 651: (void) ip_output(m, opts, NULL, 0, NULL); ! 652: } ! 653: ! 654: n_time ! 655: iptime() ! 656: { ! 657: struct timeval atv; ! 658: u_long t; ! 659: ! 660: microtime(&atv); ! 661: t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; ! 662: return (htonl(t)); ! 663: } ! 664: ! 665: int ! 666: icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) ! 667: int *name; ! 668: u_int namelen; ! 669: void *oldp; ! 670: size_t *oldlenp; ! 671: void *newp; ! 672: size_t newlen; ! 673: { ! 674: ! 675: /* All sysctl names at this level are terminal. */ ! 676: if (namelen != 1) ! 677: return (ENOTDIR); ! 678: ! 679: switch (name[0]) { ! 680: case ICMPCTL_MASKREPL: ! 681: return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl)); ! 682: default: ! 683: return (ENOPROTOOPT); ! 684: } ! 685: /* NOTREACHED */ ! 686: } ! 687: ! 688: #if NeXT ! 689: /* ! 690: * Routine: icmp_sendMaskPacket ! 691: * Function: ! 692: * ! 693: * Former routine icmp_maskrequest() has been renamed to icmp_sendMaskPacket() ! 694: * and modified to send either an ICMP_MASKREQ packet (as before) or a broadcast ! 695: * ICMP_MASKREPLY packet, as required by RFC1122 when an interface comes up. ! 696: * ! 697: * The only valid values for parameter icmp_msg_type are ICMP_MASKREQ and ICMP_MASKREPLY. ! 698: */ ! 699: icmp_sendMaskPacket(ifp, icmp_msg_type, retry_delay) ! 700: struct ifnet *ifp; ! 701: u_char icmp_msg_type; ! 702: int retry_delay; /* Seconds to delay before transmitting */ ! 703: { ! 704: struct mbuf *m = NULL; ! 705: struct sockaddr_in *sin; ! 706: struct sockaddr_in lsin; ! 707: struct ip *ip; ! 708: struct icmp *icp; ! 709: struct in_ifaddr *ifa; ! 710: register int error; ! 711: extern int wakeup(); ! 712: caddr_t m_offset; ! 713: ! 714: if ((ifp->if_flags & IFF_UP) != IFF_UP) { ! 715: return(0); ! 716: } ! 717: ! 718: /* Don't do this on our loopback interface */ ! 719: if (ifp->if_flags & IFF_LOOPBACK) { ! 720: return(0); ! 721: } ! 722: ! 723: if ((ifa = ifptoia(ifp)) == NULL) { ! 724: error = ENETUNREACH; ! 725: goto errout; ! 726: } ! 727: ! 728: /* Build a packet */ ! 729: MGETHDR(m, M_WAIT, MT_DATA); ! 730: if (m == NULL) { ! 731: error = ENOBUFS; ! 732: goto errout; ! 733: } ! 734: m->m_pkthdr.rcvif = ifp; ! 735: m->m_pkthdr.len = 12 + sizeof(struct ip);/* Size of packet we're sending */ ! 736: m->m_len = m->m_pkthdr.len; ! 737: m->m_flags |= M_BCAST; ! 738: bzero(mtod(m, caddr_t), m->m_len); ! 739: m->m_len -= sizeof(struct ip); ! 740: m->m_data += sizeof(struct ip); ! 741: icp = mtod(m, struct icmp *); ! 742: if (icmp_msg_type == ICMP_MASKREPLY) { ! 743: icp->icmp_type = ICMP_MASKREPLY; ! 744: if ((icp->icmp_mask = htonl(ifa->ia_subnetmask)) == 0) { ! 745: error = EINVAL; ! 746: goto errout; ! 747: } ! 748: } ! 749: else { ! 750: icp->icmp_type = ICMP_MASKREQ; ! 751: } ! 752: icp->icmp_code = 0; ! 753: icp->icmp_cksum = 0; ! 754: icp->icmp_void = 0; ! 755: icp->icmp_cksum = in_cksum(m, 12); ! 756: ! 757: m->m_data -= sizeof(struct ip); ! 758: m->m_len += sizeof(struct ip); ! 759: ip = mtod(m, struct ip *); ! 760: ! 761: ip->ip_v = IPVERSION; ! 762: ip->ip_hl = sizeof(struct ip) >> 2; ! 763: ip->ip_id = htons(ip_id++); ! 764: ip->ip_ttl = MAXTTL; ! 765: ip->ip_p = IPPROTO_ICMP; ! 766: ! 767: sin = (struct sockaddr_in *)(&ifa->ia_addr); ! 768: ip->ip_src.s_addr = sin->sin_addr.s_addr; ! 769: ip->ip_dst.s_addr = INADDR_BROADCAST; ! 770: ip->ip_len = htons(sizeof (struct ip) + 12); ! 771: ip->ip_sum=0; ! 772: ip->ip_sum = in_cksum(m, sizeof(struct ip)); ! 773: ! 774: lsin.sin_family = AF_INET; ! 775: lsin.sin_port = 0; ! 776: lsin.sin_addr.s_addr = INADDR_BROADCAST; ! 777: ! 778: /* Send the packet */ ! 779: if (retry_delay > 0) { ! 780: timeout(wakeup, (caddr_t)&ifa->ia_subnetmask, retry_delay * hz); ! 781: sleep((caddr_t)&ifa->ia_subnetmask, PZERO); ! 782: } ! 783: error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&lsin, (struct rtentry *)0); ! 784: m = NULL; ! 785: ! 786: if (icmp_msg_type == ICMP_MASKREQ) { ! 787: /* Now wait at least one second for any responses */ ! 788: timeout(wakeup, (caddr_t)&ifa->ia_subnetmask, 1 * hz); ! 789: sleep((caddr_t)&ifa->ia_subnetmask, PZERO); ! 790: } ! 791: errout: ! 792: if (m) { ! 793: m_freem(m); ! 794: } ! 795: return(error); ! 796: } ! 797: #endif NeXT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.