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