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