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