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