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