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