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