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