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