1 /* 2 * Copyright (c) 1982 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 6.13 (Berkeley) 09/16/85 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 /*VARARGS3*/ 41 icmp_error(oip, type, code, dest) 42 struct ip *oip; 43 int type, code; 44 struct in_addr dest; 45 { 46 register unsigned oiplen = oip->ip_hl << 2; 47 register struct icmp *icp; 48 struct mbuf *m; 49 struct ip *nip; 50 int icmplen; 51 52 #ifdef ICMPPRINTFS 53 if (icmpprintfs) 54 printf("icmp_error(%x, %d, %d)\n", oip, type, code); 55 #endif 56 icmpstat.icps_error++; 57 /* 58 * Don't send error if not the first fragment of message. 59 * Don't EVER error if the old packet protocol was ICMP. 60 * (Could do ECHO, etc, but not error indications.) 61 */ 62 if (oip->ip_off &~ (IP_MF|IP_DF)) 63 goto free; 64 if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT) { 65 icmpstat.icps_oldicmp++; 66 goto free; 67 } 68 69 /* 70 * First, formulate icmp message 71 */ 72 m = m_get(M_DONTWAIT, MT_HEADER); 73 if (m == NULL) 74 goto free; 75 icmplen = oiplen + MIN(8, oip->ip_len); 76 m->m_len = icmplen + ICMP_MINLEN; 77 m->m_off = MMAXOFF - m->m_len; 78 icp = mtod(m, struct icmp *); 79 if ((u_int)type > ICMP_MAXTYPE) 80 panic("icmp_error"); 81 icmpstat.icps_outhist[type]++; 82 icp->icmp_type = type; 83 if (type == ICMP_REDIRECT) 84 icp->icmp_gwaddr = dest; 85 else 86 icp->icmp_void = 0; 87 if (type == ICMP_PARAMPROB) { 88 icp->icmp_pptr = code; 89 code = 0; 90 } 91 icp->icmp_code = code; 92 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 93 nip = &icp->icmp_ip; 94 nip->ip_len += oiplen; 95 nip->ip_len = htons((u_short)nip->ip_len); 96 97 /* 98 * Now, copy old ip header in front of icmp 99 * message. This allows us to reuse any source 100 * routing info present. 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 nip = mtod(m, struct ip *); 108 bcopy((caddr_t)oip, (caddr_t)nip, oiplen); 109 nip->ip_len = m->m_len + oiplen; 110 nip->ip_p = IPPROTO_ICMP; 111 /* icmp_send adds ip header to m_off and m_len, so we deduct here */ 112 m->m_off += oiplen; 113 icmp_reflect(nip, in_ifaddr->ia_ifp); 114 115 free: 116 m_freem(dtom(oip)); 117 } 118 119 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 120 static struct sockaddr_in icmpsrc = { AF_INET }; 121 static struct sockaddr_in icmpdst = { AF_INET }; 122 static struct sockaddr_in icmpgw = { AF_INET }; 123 struct in_ifaddr *ifptoia(); 124 125 /* 126 * Process a received ICMP message. 127 */ 128 icmp_input(m, ifp) 129 struct mbuf *m; 130 struct ifnet *ifp; 131 { 132 register struct icmp *icp; 133 register struct ip *ip = mtod(m, struct ip *); 134 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2; 135 register int i; 136 struct in_ifaddr *ia; 137 int (*ctlfunc)(), code; 138 extern u_char ip_protox[]; 139 extern struct in_addr in_makeaddr(); 140 141 /* 142 * Locate icmp structure in mbuf, and check 143 * that not corrupted and of at least minimum length. 144 */ 145 #ifdef ICMPPRINTFS 146 if (icmpprintfs) 147 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 148 #endif 149 if (icmplen < ICMP_MINLEN) { 150 icmpstat.icps_tooshort++; 151 goto free; 152 } 153 i = hlen + MIN(icmplen, ICMP_ADVLENMIN); 154 if ((m->m_off > MMAXOFF || m->m_len < i) && 155 (m = m_pullup(m, i)) == 0) { 156 icmpstat.icps_tooshort++; 157 return; 158 } 159 ip = mtod(m, struct ip *); 160 m->m_len -= hlen; 161 m->m_off += hlen; 162 icp = mtod(m, struct icmp *); 163 if (in_cksum(m, icmplen)) { 164 icmpstat.icps_checksum++; 165 goto free; 166 } 167 168 #ifdef ICMPPRINTFS 169 /* 170 * Message type specific processing. 171 */ 172 if (icmpprintfs) 173 printf("icmp_input, type %d code %d\n", icp->icmp_type, 174 icp->icmp_code); 175 #endif 176 if (icp->icmp_type > ICMP_MAXTYPE) 177 goto free; 178 icmpstat.icps_inhist[icp->icmp_type]++; 179 code = icp->icmp_code; 180 switch (icp->icmp_type) { 181 182 case ICMP_UNREACH: 183 if (code > 5) 184 goto badcode; 185 code += PRC_UNREACH_NET; 186 goto deliver; 187 188 case ICMP_TIMXCEED: 189 if (code > 1) 190 goto badcode; 191 code += PRC_TIMXCEED_INTRANS; 192 goto deliver; 193 194 case ICMP_PARAMPROB: 195 if (code) 196 goto badcode; 197 code = PRC_PARAMPROB; 198 goto deliver; 199 200 case ICMP_SOURCEQUENCH: 201 if (code) 202 goto badcode; 203 code = PRC_QUENCH; 204 deliver: 205 /* 206 * Problem with datagram; advise higher level routines. 207 */ 208 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); 209 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 210 icmpstat.icps_badlen++; 211 goto free; 212 } 213 #ifdef ICMPPRINTFS 214 if (icmpprintfs) 215 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 216 #endif 217 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 218 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 219 (*ctlfunc)(code, (struct sockaddr *)&icmpsrc); 220 goto free; 221 222 badcode: 223 icmpstat.icps_badcode++; 224 goto free; 225 226 case ICMP_ECHO: 227 icp->icmp_type = ICMP_ECHOREPLY; 228 goto reflect; 229 230 case ICMP_TSTAMP: 231 if (icmplen < ICMP_TSLEN) { 232 icmpstat.icps_badlen++; 233 goto free; 234 } 235 icp->icmp_type = ICMP_TSTAMPREPLY; 236 icp->icmp_rtime = iptime(); 237 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 238 goto reflect; 239 240 case ICMP_IREQ: 241 #define satosin(sa) ((struct sockaddr_in *)(sa)) 242 if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp))) 243 ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr), 244 in_lnaof(ip->ip_src)); 245 icp->icmp_type = ICMP_IREQREPLY; 246 goto reflect; 247 248 case ICMP_MASKREQ: 249 if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0) 250 goto free; 251 icp->icmp_type = ICMP_IREQREPLY; 252 icp->icmp_mask = ia->ia_netmask; 253 if (ip->ip_src.s_addr == 0) { 254 if (ia->ia_ifp->if_flags & IFF_BROADCAST) 255 ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 256 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 257 ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 258 } 259 goto reflect; 260 261 case ICMP_REDIRECT: 262 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 263 icmpstat.icps_badlen++; 264 goto free; 265 } 266 /* 267 * Short circuit routing redirects to force 268 * immediate change in the kernel's routing 269 * tables. The message is also handed to anyone 270 * listening on a raw socket (e.g. the routing 271 * daemon for use in updating its tables). 272 */ 273 icmpgw.sin_addr = ip->ip_src; 274 icmpdst.sin_addr = icp->icmp_gwaddr; 275 #ifdef ICMPPRINTFS 276 if (icmpprintfs) 277 printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 278 icp->icmp_gwaddr); 279 #endif 280 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { 281 icmpsrc.sin_addr = 282 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); 283 rtredirect((struct sockaddr *)&icmpsrc, 284 (struct sockaddr *)&icmpdst, RTF_GATEWAY, 285 (struct sockaddr *)&icmpgw); 286 pfctlinput(PRC_REDIRECT_NET, 287 (struct sockaddr *)&icmpsrc); 288 } else { 289 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 290 rtredirect((struct sockaddr *)&icmpsrc, 291 (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST, 292 (struct sockaddr *)&icmpgw); 293 pfctlinput(PRC_REDIRECT_HOST, 294 (struct sockaddr *)&icmpsrc); 295 } 296 /* FALL THROUGH */ 297 298 case ICMP_ECHOREPLY: 299 case ICMP_TSTAMPREPLY: 300 case ICMP_IREQREPLY: 301 case ICMP_MASKREPLY: 302 icmpsrc.sin_addr = ip->ip_src; 303 icmpdst.sin_addr = ip->ip_dst; 304 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, 305 (struct sockaddr *)&icmpdst); 306 return; 307 308 default: 309 goto free; 310 } 311 reflect: 312 ip->ip_len += hlen; /* since ip_input deducts this */ 313 icmpstat.icps_reflect++; 314 icmpstat.icps_outhist[icp->icmp_type]++; 315 icmp_reflect(ip, ifp); 316 return; 317 free: 318 m_freem(dtom(ip)); 319 } 320 321 /* 322 * Reflect the ip packet back to the source 323 */ 324 icmp_reflect(ip, ifp) 325 struct ip *ip; 326 struct ifnet *ifp; 327 { 328 register struct in_ifaddr *ia; 329 register u_char *cp; 330 int opt, optlen, cnt; 331 struct in_addr t; 332 struct in_addr *p, *q; 333 334 t = ip->ip_dst; 335 ip->ip_dst = ip->ip_src; 336 /* 337 * If the incoming packet was addressed directly to us, 338 * use dst as the src for the reply. Otherwise (broadcast 339 * or anonymous), use the address which corresponds 340 * to the incoming interface. 341 */ 342 for (ia = in_ifaddr; ia; ia = ia->ia_next) { 343 if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 344 break; 345 if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 346 t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 347 break; 348 } 349 if (ia == (struct in_ifaddr *)0) 350 ia = ifptoia(ifp); 351 if (ia) 352 t = IA_SIN(ia)->sin_addr; 353 ip->ip_src = t; 354 355 /* 356 * If the incoming packet was source-routed, 357 * we need to reverse the route and set the next-hop destination. 358 * We can dispense with the error checking 359 * as ip_dooptions has been through here before. 360 */ 361 if ((ip->ip_hl << 2) > sizeof(struct ip)) { 362 cp = (u_char *)(ip + 1); 363 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 364 for (; cnt > 0; cnt -= optlen, cp += optlen) { 365 opt = cp[IPOPT_OPTVAL]; 366 if (opt == IPOPT_EOL) 367 break; 368 if (opt == IPOPT_NOP) 369 optlen = 1; 370 else 371 optlen = cp[IPOPT_OLEN]; 372 if (opt == IPOPT_LSRR || opt == IPOPT_SSRR) { 373 p = (struct in_addr *) 374 (cp + cp[IPOPT_OFFSET] - 1) - 1; 375 q = (struct in_addr *)(cp + IPOPT_MINOFF - 1); 376 /* 377 * First switch the last route entry 378 * (first hop for return) with ip_dst 379 * (final hop on return). 380 */ 381 bcopy((caddr_t)p, (caddr_t)&t, sizeof(t)); 382 bcopy((caddr_t)&ip->ip_dst, (caddr_t)p, 383 sizeof(struct in_addr)); 384 ip->ip_dst = t; 385 p--; 386 /* 387 * Then reverse remaining route entries. 388 */ 389 while (p > q) { 390 bcopy((caddr_t)p, (caddr_t)&t, 391 sizeof(struct in_addr)); 392 bcopy((caddr_t)q, (caddr_t)p, 393 sizeof(struct in_addr)); 394 bcopy((caddr_t)&t, (caddr_t)q, 395 sizeof(struct in_addr)); 396 p--; 397 q++; 398 } 399 cp[IPOPT_OFFSET] = IPOPT_MINOFF; 400 break; 401 } 402 } 403 } 404 icmp_send(ip); 405 } 406 407 struct in_ifaddr * 408 ifptoia(ifp) 409 struct ifnet *ifp; 410 { 411 register struct in_ifaddr *ia; 412 413 for (ia = in_ifaddr; ia; ia = ia->ia_next) 414 if (ia->ia_ifp == ifp) 415 return (ia); 416 return ((struct in_ifaddr *)0); 417 } 418 419 /* 420 * Send an icmp packet back to the ip level, 421 * after supplying a checksum. 422 */ 423 icmp_send(ip) 424 struct ip *ip; 425 { 426 register int hlen; 427 register struct icmp *icp; 428 register struct mbuf *m; 429 430 m = dtom(ip); 431 hlen = ip->ip_hl << 2; 432 icp = mtod(m, struct icmp *); 433 icp->icmp_cksum = 0; 434 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 435 m->m_off -= hlen; 436 m->m_len += hlen; 437 #ifdef ICMPPRINTFS 438 if (icmpprintfs) 439 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 440 #endif 441 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0); 442 } 443 444 n_time 445 iptime() 446 { 447 int s = spl6(); 448 u_long t; 449 450 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 451 splx(s); 452 return (htonl(t)); 453 } 454