1*25202Skarels #ifdef RCSIDENT 2*25202Skarels static char rcsident[] = "$Header: icmp.c,v 1.17 85/06/18 14:53:43 walsh Exp $"; 3*25202Skarels #endif 4*25202Skarels 5*25202Skarels #include "../h/param.h" 6*25202Skarels #include "../h/systm.h" 7*25202Skarels #include "../h/mbuf.h" 8*25202Skarels #include "../h/socket.h" 9*25202Skarels #include "../h/socketvar.h" 10*25202Skarels #include "../h/protosw.h" 11*25202Skarels #include "../h/syslog.h" 12*25202Skarels 13*25202Skarels #include "../net/route.h" 14*25202Skarels #include "../net/if.h" 15*25202Skarels 16*25202Skarels #include "../bbnnet/in.h" 17*25202Skarels #include "../bbnnet/net.h" 18*25202Skarels #include "../bbnnet/in_pcb.h" 19*25202Skarels #include "../bbnnet/in_var.h" 20*25202Skarels 21*25202Skarels #include "../bbnnet/ip.h" 22*25202Skarels #include "../bbnnet/icmp.h" 23*25202Skarels #include "../bbnnet/nopcb.h" 24*25202Skarels #ifdef HMPTRAPS 25*25202Skarels #include "../bbnnet/hmp_traps.h" 26*25202Skarels #endif 27*25202Skarels 28*25202Skarels #include "../h/errno.h" 29*25202Skarels #include "../h/time.h" 30*25202Skarels #include "../h/kernel.h" 31*25202Skarels 32*25202Skarels #ifdef RCSIDENT 33*25202Skarels static char rcsicmphdr[] = RCSICMPHDR; 34*25202Skarels #endif 35*25202Skarels 36*25202Skarels extern int nosum; 37*25202Skarels 38*25202Skarels #define NICTYPE 17 39*25202Skarels 40*25202Skarels /* ICMP message formats */ 41*25202Skarels #define ICBAD 0 /* unimplemented */ 42*25202Skarels #define ICERR 1 /* error format (use header) */ 43*25202Skarels #define ICDAT 2 /* data format (use id) */ 44*25202Skarels #define ICINT 3 /* data format (handle internally) */ 45*25202Skarels 46*25202Skarels char icaction[NICTYPE] = 47*25202Skarels { 48*25202Skarels ICDAT, ICBAD, ICBAD, ICERR, ICERR, ICERR, ICBAD, 49*25202Skarels ICBAD, ICINT, ICBAD, ICBAD, ICERR, ICERR, ICINT, 50*25202Skarels ICDAT, ICINT, ICDAT 51*25202Skarels } ; 52*25202Skarels 53*25202Skarels #define ICLEN1 (sizeof(struct ip) + ICMPSIZE + sizeof(struct ip) + ICMP_ERRLEN) 54*25202Skarels #define ICLEN2 (sizeof(struct ip) + ICMPSIZE + 3 * sizeof(long)) 55*25202Skarels 56*25202Skarels int icpullup[NICTYPE] = 57*25202Skarels { 58*25202Skarels 0, /* echo reply */ 59*25202Skarels 0, 60*25202Skarels 0, 61*25202Skarels ICLEN1, /* unreachable */ 62*25202Skarels ICLEN1, /* source quench */ 63*25202Skarels ICLEN1, /* redirect */ 64*25202Skarels 0, 65*25202Skarels 0, 66*25202Skarels 0, /* echo request */ 67*25202Skarels 0, 68*25202Skarels 0, 69*25202Skarels ICLEN1, /* time exceeded */ 70*25202Skarels ICLEN1, /* parameter problem */ 71*25202Skarels ICLEN2, /* timestamp */ 72*25202Skarels ICLEN2, /* timestamp reply */ 73*25202Skarels 0, /* information request */ 74*25202Skarels 0 /* information reply */ 75*25202Skarels } ; 76*25202Skarels 77*25202Skarels char icunrch[ICMP_UNRCH_NUM] = 78*25202Skarels { 79*25202Skarels PRC_UNREACH_NET, PRC_UNREACH_HOST, PRC_UNREACH_PROTOCOL, 80*25202Skarels PRC_UNREACH_PORT, PRC_MSGSIZE, PRC_UNREACH_HOST 81*25202Skarels } ; 82*25202Skarels 83*25202Skarels struct icmp_stat icmpstat; 84*25202Skarels 85*25202Skarels 86*25202Skarels u_long iptime() 87*25202Skarels { 88*25202Skarels int s = spl7(); /* berkeley had spl6() */ 89*25202Skarels u_long t; 90*25202Skarels 91*25202Skarels t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 92*25202Skarels splx(s); 93*25202Skarels return (htonl(t)); 94*25202Skarels } 95*25202Skarels 96*25202Skarels know_gateway2 (gaddr, list) 97*25202Skarels u_long gaddr; 98*25202Skarels struct mbuf *list; 99*25202Skarels { 100*25202Skarels register struct rtentry *rt; 101*25202Skarels 102*25202Skarels while (list) 103*25202Skarels { 104*25202Skarels rt = mtod(list, struct rtentry *); 105*25202Skarels if ((rt->rt_flags & RTF_GATEWAY) && 106*25202Skarels (rt->rt_dst.sa_family == AF_INET) && 107*25202Skarels (((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr == gaddr)) 108*25202Skarels return (TRUE); 109*25202Skarels list = list->m_next; 110*25202Skarels } 111*25202Skarels return (FALSE); 112*25202Skarels } 113*25202Skarels 114*25202Skarels know_gateway (gaddr) 115*25202Skarels u_long gaddr; 116*25202Skarels { 117*25202Skarels register int i; 118*25202Skarels 119*25202Skarels for (i=0 ; i<RTHASHSIZ ; i++) 120*25202Skarels { 121*25202Skarels if (know_gateway2 (gaddr, rthost[i]) || 122*25202Skarels know_gateway2 (gaddr, rtnet[i])) 123*25202Skarels return (TRUE); 124*25202Skarels } 125*25202Skarels return (FALSE); 126*25202Skarels } 127*25202Skarels 128*25202Skarels #ifdef BBNPING 129*25202Skarels /* 130*25202Skarels * Note that pinging is done on a per-route basis. 131*25202Skarels * 132*25202Skarels * 1. If a gateway is used by more than one route, then for routes 133*25202Skarels * with no active (measured by new data xfer) tcp connections, 134*25202Skarels * the gateway will be pinged. 135*25202Skarels * It is possible that every PINGTIME/2 seconds a gateway would 136*25202Skarels * be sent multiple icmp ECHO REQUESTS, but that is unlikely (uncommon) 137*25202Skarels * and we can worry about that if it actually proves to be a problem. 138*25202Skarels * 139*25202Skarels * 2. Since the ping count is incremented on a per-route basis, but 140*25202Skarels * ECHO REPLIES are dealt with on a per-address basis, a gateway is 141*25202Skarels * not prematurely pinged out if it is used by more than one active 142*25202Skarels * routing entry. 143*25202Skarels */ 144*25202Skarels 145*25202Skarels static check_ping(list) 146*25202Skarels register struct mbuf *list; 147*25202Skarels { 148*25202Skarels register struct rtentry *rt; 149*25202Skarels register struct sockaddr_in *sin; 150*25202Skarels register struct mbuf *next; 151*25202Skarels 152*25202Skarels while (list) 153*25202Skarels { 154*25202Skarels rt = mtod(list, struct rtentry *); 155*25202Skarels next = list->m_next; /* in case remove it from list */ 156*25202Skarels 157*25202Skarels if ((rt->rt_flags & RTF_GATEWAY) && 158*25202Skarels (rt->rt_dst.sa_family == AF_INET)) 159*25202Skarels { 160*25202Skarels sin = (struct sockaddr_in *) &rt->rt_gateway; 161*25202Skarels if ((rt->rt_refcnt > 0) && (rt->rt_flags & RTF_UP)) 162*25202Skarels { 163*25202Skarels if (rt->irt_pings >= MAXPING) 164*25202Skarels { 165*25202Skarels /* 166*25202Skarels * Too many unanswered pings. re-route 167*25202Skarels * connections using this gateway. Usually, 168*25202Skarels * this happens because the gateway is flooded 169*25202Skarels * with traffic. 170*25202Skarels */ 171*25202Skarels union { u_long ul; u_char c[4]; } a; 172*25202Skarels 173*25202Skarels a.ul = sin->sin_addr.s_addr; 174*25202Skarels log(KERN_RECOV, "gw %d.%d.%d.%d pinged out\n", 175*25202Skarels a.c[0], a.c[1], a.c[2], a.c[3]); 176*25202Skarels 177*25202Skarels rt->irt_pings = 0; 178*25202Skarels ip_gdown(sin->sin_addr.s_addr); 179*25202Skarels } 180*25202Skarels else 181*25202Skarels { 182*25202Skarels /* 183*25202Skarels * Ping him again. 184*25202Skarels * See rcv_ack() for comparison with zero here. 185*25202Skarels */ 186*25202Skarels rt->irt_pings ++; 187*25202Skarels if (rt->irt_pings > 0) 188*25202Skarels { 189*25202Skarels /* 190*25202Skarels * count ping even if doesn't get to 191*25202Skarels * interface (ENOBUFS) or other error 192*25202Skarels * (EHOSTDOWN if no gateway at that 193*25202Skarels * address on an IMP network). 194*25202Skarels */ 195*25202Skarels 196*25202Skarels ping (sin->sin_addr); 197*25202Skarels icmpstat.ic_pings ++; 198*25202Skarels } 199*25202Skarels else 200*25202Skarels icmpstat.ic_svpings ++; 201*25202Skarels } 202*25202Skarels } 203*25202Skarels else 204*25202Skarels { 205*25202Skarels if (rt->rt_flags & RTF_REINSTATE) 206*25202Skarels { 207*25202Skarels /* 208*25202Skarels * The gateway pinged out or died at some point. 209*25202Skarels * Let's see if it's back up or if our 210*25202Skarels * re-routing of current connections in ip_gdown 211*25202Skarels * has let it breathe again. Wait a while 212*25202Skarels * before try to use it again. 213*25202Skarels */ 214*25202Skarels rt->irt_gdown --; 215*25202Skarels if (rt->irt_gdown <= 0) 216*25202Skarels { 217*25202Skarels rt->irt_gdown = 0; 218*25202Skarels /* 219*25202Skarels * Wait until we know it's alive 220*25202Skarels * for certain. Ping it. 221*25202Skarels */ 222*25202Skarels ping (sin->sin_addr); 223*25202Skarels } 224*25202Skarels } 225*25202Skarels } 226*25202Skarels } 227*25202Skarels 228*25202Skarels list = next; 229*25202Skarels } 230*25202Skarels } 231*25202Skarels 232*25202Skarels static reset_ping(list, addr) 233*25202Skarels register struct mbuf *list; 234*25202Skarels register u_long addr; 235*25202Skarels { 236*25202Skarels register struct rtentry *rt; 237*25202Skarels 238*25202Skarels while (list) 239*25202Skarels { 240*25202Skarels rt = mtod(list, struct rtentry *); 241*25202Skarels if ((rt->rt_flags & RTF_GATEWAY) && 242*25202Skarels (rt->rt_dst.sa_family == AF_INET)) 243*25202Skarels { 244*25202Skarels if (((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr == addr) 245*25202Skarels { 246*25202Skarels if (rt->rt_flags & RTF_REINSTATE) 247*25202Skarels { 248*25202Skarels if (rt->irt_gdown == 0) 249*25202Skarels { 250*25202Skarels /* 251*25202Skarels * Was not a slow echo reply. If was dead, 252*25202Skarels * use it again. If was flooded, new connections 253*25202Skarels * can now use it (old shifted away). 254*25202Skarels */ 255*25202Skarels rt->rt_flags |= RTF_UP; 256*25202Skarels rt->rt_flags &= ~RTF_REINSTATE; 257*25202Skarels rt->rt_refcnt --; /* see ip_gdown() */ 258*25202Skarels } 259*25202Skarels } 260*25202Skarels else 261*25202Skarels rt->irt_pings = 0; 262*25202Skarels } 263*25202Skarels } 264*25202Skarels list = list->m_next; 265*25202Skarels } 266*25202Skarels } 267*25202Skarels 268*25202Skarels /* 269*25202Skarels * Would be nice if we could use HOSTHASH/NETHASH/0, but the hashing is done 270*25202Skarels * on the destination, not the intermediary gateway. 271*25202Skarels */ 272*25202Skarels got_ping(addr) 273*25202Skarels register u_long addr; 274*25202Skarels { 275*25202Skarels register int i; 276*25202Skarels 277*25202Skarels for (i=0 ; i<RTHASHSIZ ; i++) 278*25202Skarels { 279*25202Skarels reset_ping(rthost[i], addr); 280*25202Skarels reset_ping(rtnet[i], addr); 281*25202Skarels } 282*25202Skarels } 283*25202Skarels #endif 284*25202Skarels 285*25202Skarels /* 286*25202Skarels * Process ICMP messages. Called directly from ip_input processor. 287*25202Skarels */ 288*25202Skarels icmp(mp) 289*25202Skarels register struct mbuf *mp; 290*25202Skarels { 291*25202Skarels register struct ip *ip; 292*25202Skarels register struct icmp *icp; 293*25202Skarels struct in_ifaddr *ia; 294*25202Skarels int ilen; 295*25202Skarels int prccode; 296*25202Skarels 297*25202Skarels icmpstat.ic_total ++; 298*25202Skarels 299*25202Skarels /* 300*25202Skarels * see ip_input() 301*25202Skarels */ 302*25202Skarels if ((mp->m_off > MMAXOFF) || 303*25202Skarels (mp->m_len < sizeof(struct ip) + ICMPSIZE)) 304*25202Skarels { 305*25202Skarels if ((mp = m_pullup(mp, sizeof(struct ip) + ICMPSIZE)) == NULL) 306*25202Skarels { 307*25202Skarels icmpstat.ic_tooshort ++; 308*25202Skarels return; 309*25202Skarels } 310*25202Skarels } 311*25202Skarels ip = mtod(mp, struct ip *); 312*25202Skarels icp = (struct icmp *) (ip+1); 313*25202Skarels 314*25202Skarels /* 315*25202Skarels * watch for fools sending out broadcast ICMP packets 316*25202Skarels * Don't check against inetifp, since is up to ip_input whether to receive 317*25202Skarels * on some interface rather than send to self for input on dst interface. 318*25202Skarels */ 319*25202Skarels ia = in_iawithaddr(ip->ip_dst, FALSE); 320*25202Skarels if (ia == NULL) 321*25202Skarels { 322*25202Skarels /* drop it */ 323*25202Skarels m_freem(mp); 324*25202Skarels return; 325*25202Skarels } 326*25202Skarels 327*25202Skarels /* filter out message types */ 328*25202Skarels 329*25202Skarels if (icp->ic_type >= NICTYPE || icaction[icp->ic_type] == ICBAD) 330*25202Skarels { 331*25202Skarels icmpstat.ic_drops++; 332*25202Skarels goto badret; 333*25202Skarels } 334*25202Skarels 335*25202Skarels if (mp->m_len < icpullup[icp->ic_type]) 336*25202Skarels { 337*25202Skarels if ((mp = m_pullup(mp, icpullup[icp->ic_type])) == NULL) 338*25202Skarels { 339*25202Skarels icmpstat.ic_tooshort ++; 340*25202Skarels return; 341*25202Skarels } 342*25202Skarels ip = mtod(mp, struct ip *); 343*25202Skarels icp = (struct icmp *) (ip+1); 344*25202Skarels } 345*25202Skarels mp->m_off += sizeof(struct ip); 346*25202Skarels mp->m_len -= sizeof(struct ip); 347*25202Skarels 348*25202Skarels ilen = ip->ip_len; 349*25202Skarels 350*25202Skarels { 351*25202Skarels register u_short his_sum, our_sum; 352*25202Skarels 353*25202Skarels his_sum = (u_short)icp->ic_sum; 354*25202Skarels icp->ic_sum = 0; 355*25202Skarels if (his_sum != (our_sum = (u_short)in_cksum(mp, ilen))) 356*25202Skarels { 357*25202Skarels icmpstat.ic_badsum++; 358*25202Skarels if (! nosum) 359*25202Skarels { 360*25202Skarels /* note that the icmp header doesn't overlap IP */ 361*25202Skarels #ifdef HMPTRAPS 362*25202Skarels /* hmp_trap(T_ICMP_CKSUM, (caddr_t),0); */ 363*25202Skarels #endif 364*25202Skarels inet_cksum_err ("icmp", ip, (u_long) his_sum, (u_long) our_sum); 365*25202Skarels netlog(mp); 366*25202Skarels return; 367*25202Skarels } 368*25202Skarels } 369*25202Skarels } 370*25202Skarels 371*25202Skarels /* 372*25202Skarels * Now do any processing. Some messages are handled here, 373*25202Skarels * others are passed up ctlinput path for further processing. 374*25202Skarels */ 375*25202Skarels 376*25202Skarels switch (icp->ic_type) 377*25202Skarels { 378*25202Skarels 379*25202Skarels case ICMP_UNRCH: /* destination unreachable */ 380*25202Skarels 381*25202Skarels if (icp->ic_code < ICMP_UNRCH_NUM) 382*25202Skarels { 383*25202Skarels register int (*ctlfunc)(); 384*25202Skarels 385*25202Skarels prccode = icunrch[icp->ic_code]; 386*25202Skarels passup: 387*25202Skarels ctlfunc = ipsw[icp->ic_iphdr.ip_p].ipsw_user->pr_ctlinput; 388*25202Skarels (*ctlfunc) (prccode, (caddr_t) icp); 389*25202Skarels } 390*25202Skarels break; 391*25202Skarels 392*25202Skarels case ICMP_SRCQ: /* source quench */ 393*25202Skarels 394*25202Skarels /* 395*25202Skarels * At the IP level, we could try to reroute the connection and see if we 396*25202Skarels * come up with a less loaded gateway. Problem with this is that we know 397*25202Skarels * total number of packets sent over a route, not the recent traffic load. 398*25202Skarels */ 399*25202Skarels icmpstat.ic_quenches++; 400*25202Skarels prccode = PRC_QUENCH; 401*25202Skarels #ifdef HMPTRAPS 402*25202Skarels /* hmp_trap(T_ICMP_SRCQ, (caddr_t)0, 0); */ 403*25202Skarels #endif 404*25202Skarels goto passup; 405*25202Skarels 406*25202Skarels case ICMP_REDIR: /* redirect */ 407*25202Skarels 408*25202Skarels icmpstat.ic_redirects ++; 409*25202Skarels 410*25202Skarels /* 411*25202Skarels * Sorry, we only trust the connected set of gateways 412*25202Skarels * that includes gateways installed by the system 413*25202Skarels * manager. 414*25202Skarels */ 415*25202Skarels if (know_gateway(ip->ip_src.s_addr)) 416*25202Skarels { 417*25202Skarels register struct mbuf **table; 418*25202Skarels 419*25202Skarels if (icp->ic_code == ICMP_REDIR_NET) 420*25202Skarels { 421*25202Skarels prccode = PRC_REDIRECT_NET; 422*25202Skarels table = rtnet; 423*25202Skarels } 424*25202Skarels else 425*25202Skarels { 426*25202Skarels prccode = PRC_REDIRECT_HOST; 427*25202Skarels table = rthost; 428*25202Skarels } 429*25202Skarels if (icmp_redirect_route (icp, table)) 430*25202Skarels goto passup; 431*25202Skarels } 432*25202Skarels else 433*25202Skarels { 434*25202Skarels /* 435*25202Skarels * Who are you? Why are you talking to us? 436*25202Skarels * And how do we know the ip source isn't a lie? 437*25202Skarels * (Eg., Catches Symbolics redirection of subnet broadcast.) 438*25202Skarels */ 439*25202Skarels union { u_long ul; u_char c[4]; } a; 440*25202Skarels 441*25202Skarels a.ul = ip->ip_src.s_addr; 442*25202Skarels log(KERN_RECOV, "Ignoring redirect from %d.%d.%d.%d\n", 443*25202Skarels a.c[0], a.c[1], a.c[2], a.c[3]); 444*25202Skarels } 445*25202Skarels #ifdef HMPTRAPS 446*25202Skarels /* hmp_trap(T_ICMP_REDIR, (caddr_t)0,0); */ 447*25202Skarels #endif 448*25202Skarels break; 449*25202Skarels 450*25202Skarels case ICMP_ECHO: /* echo */ 451*25202Skarels 452*25202Skarels icp->ic_type = ICMP_ECHOR; 453*25202Skarels icmpstat.ic_echoes++; 454*25202Skarels goto loopback; 455*25202Skarels 456*25202Skarels case ICMP_ECHOR: /* echo reply */ 457*25202Skarels 458*25202Skarels /* check for gateway ping packets, look for 459*25202Skarels * corresponding gateway entry and set echo count 460*25202Skarels * to zero. 461*25202Skarels */ 462*25202Skarels #ifdef BBNPING 463*25202Skarels if (icp->ic_id == MY_ECHO_ID) 464*25202Skarels got_ping(ip->ip_src.s_addr); 465*25202Skarels #endif 466*25202Skarels break; 467*25202Skarels 468*25202Skarels case ICMP_TIMEX: /* time exceeded */ 469*25202Skarels /* 470*25202Skarels * IP time to live field should be associated with the route so 471*25202Skarels * that it can be dynamically adjusted for time exceeded in transit. 472*25202Skarels * If did, would only need to "pass time exceeded in reassembly" 473*25202Skarels * up to protocol (TCP) so that it can better try to avoid IP 474*25202Skarels * fragmentation. 475*25202Skarels */ 476*25202Skarels icmpstat.ic_timex++; 477*25202Skarels prccode = (icp->ic_code == ICMP_TIMEX_XMT) 478*25202Skarels ? PRC_TIMXCEED_INTRANS 479*25202Skarels : PRC_TIMXCEED_REASS; 480*25202Skarels #ifdef HMPTRAPS 481*25202Skarels /* hmp_trap(T_ICMP_TIMEX, (caddr_t)0,0); */ 482*25202Skarels #endif 483*25202Skarels goto passup; 484*25202Skarels 485*25202Skarels case ICMP_TIMES: /* timestamp */ 486*25202Skarels 487*25202Skarels if (icp->ic_code == 0) 488*25202Skarels { 489*25202Skarels icp->ic_type = ICMP_TIMESR; 490*25202Skarels /* 491*25202Skarels * Can now do timestamps in UT 492*25202Skarels * 493*25202Skarels icp->ic_trcv = (long)time.tv_sec | 0x80; 494*25202Skarels icp->ic_txmt = (long)time.tv_sec | 0x80; 495*25202Skarels */ 496*25202Skarels icp->ic_txmt = icp->ic_trcv = iptime(); 497*25202Skarels goto loopback; 498*25202Skarels } 499*25202Skarels break; 500*25202Skarels 501*25202Skarels case ICMP_INFO: /* info request */ 502*25202Skarels /* 503*25202Skarels * He knows his host number, but not his network #, 504*25202Skarels * fill in src & dst as he would have, had he known. 505*25202Skarels */ 506*25202Skarels { 507*25202Skarels register struct in_ifaddr *inaddress; 508*25202Skarels extern struct ifnet *inetifp; 509*25202Skarels 510*25202Skarels icp->ic_type = ICMP_INFOR; 511*25202Skarels inaddress = in_iafromif(inetifp); 512*25202Skarels ip->ip_src.s_addr |= inaddress->ia_subnet; 513*25202Skarels ip->ip_dst = redir_addr(ip); 514*25202Skarels } 515*25202Skarels goto loopback; 516*25202Skarels 517*25202Skarels case ICMP_PARM: /* parameter problem */ 518*25202Skarels icmpstat.ic_parm++; 519*25202Skarels prccode = PRC_PARAMPROB; 520*25202Skarels #ifdef HMPTRAPS 521*25202Skarels /* hmp_trap(T_ICMP_PARM, (caddr_t)0,0); */ 522*25202Skarels #endif 523*25202Skarels goto passup; 524*25202Skarels } 525*25202Skarels 526*25202Skarels badret : 527*25202Skarels m_freem(mp); 528*25202Skarels return; 529*25202Skarels 530*25202Skarels loopback : 531*25202Skarels { 532*25202Skarels struct in_addr temp; 533*25202Skarels register int error; 534*25202Skarels 535*25202Skarels temp = ip->ip_src; 536*25202Skarels ip->ip_src = ip->ip_dst; 537*25202Skarels ip->ip_dst = temp; 538*25202Skarels /* ip->ip_p = IPPROTO_ICMP; still is from input */ 539*25202Skarels /* ip->ip_tos = 0; use same tos for reply */ 540*25202Skarels 541*25202Skarels icp->ic_sum = in_cksum(mp, ilen); 542*25202Skarels mp->m_off -= sizeof(struct ip); 543*25202Skarels mp->m_len += sizeof(struct ip); 544*25202Skarels NOPCB_IPSEND (mp, (int)ip->ip_len, FALSE, error); 545*25202Skarels 546*25202Skarels #ifdef lint 547*25202Skarels error = error; 548*25202Skarels #endif 549*25202Skarels 550*25202Skarels } 551*25202Skarels } 552*25202Skarels 553*25202Skarels 554*25202Skarels /* 555*25202Skarels * Ping gateways in use to see if they are still alive. 556*25202Skarels */ 557*25202Skarels ic_timeo() 558*25202Skarels { 559*25202Skarels #ifdef BBNPING 560*25202Skarels register int i; 561*25202Skarels register int level; 562*25202Skarels static int ictimer; 563*25202Skarels 564*25202Skarels if (--ictimer > 0) 565*25202Skarels return; 566*25202Skarels ictimer = PINGTIME; 567*25202Skarels 568*25202Skarels level = splnet(); 569*25202Skarels for (i=0 ; i<RTHASHSIZ ; i++) 570*25202Skarels { 571*25202Skarels check_ping(rthost[i]); 572*25202Skarels check_ping(rtnet[i]); 573*25202Skarels } 574*25202Skarels splx(level); 575*25202Skarels #endif 576*25202Skarels } 577*25202Skarels 578*25202Skarels static struct rtentry *rtfind (dst, via, table) 579*25202Skarels struct in_addr dst; 580*25202Skarels struct in_addr via; 581*25202Skarels struct mbuf *table[]; 582*25202Skarels { 583*25202Skarels register struct mbuf *m; 584*25202Skarels 585*25202Skarels struct rtentry *rt; 586*25202Skarels 587*25202Skarels if (table == rthost) 588*25202Skarels m = rthost[HOSTHASH(dst.s_addr) % RTHASHSIZ]; 589*25202Skarels else 590*25202Skarels { 591*25202Skarels if (dst.s_addr) 592*25202Skarels { 593*25202Skarels m = rtnet[NETHASH(dst) % RTHASHSIZ]; 594*25202Skarels dst.s_addr = iptonet(dst); 595*25202Skarels } 596*25202Skarels else 597*25202Skarels m = rtnet[0]; 598*25202Skarels } 599*25202Skarels 600*25202Skarels while (m) 601*25202Skarels { 602*25202Skarels struct in_addr d, g; 603*25202Skarels 604*25202Skarels rt = mtod(m, struct rtentry *); 605*25202Skarels d = satoipa(&rt->rt_dst); 606*25202Skarels g = satoipa(&rt->rt_gateway); 607*25202Skarels if ((d.s_addr == dst.s_addr) && 608*25202Skarels (g.s_addr == via.s_addr) && 609*25202Skarels (rt->rt_dst.sa_family == AF_INET)) 610*25202Skarels { 611*25202Skarels /* then, hash values must be same. */ 612*25202Skarels return (rt); 613*25202Skarels } 614*25202Skarels 615*25202Skarels m = m->m_next; 616*25202Skarels } 617*25202Skarels 618*25202Skarels return (NULL); 619*25202Skarels } 620*25202Skarels 621*25202Skarels 622*25202Skarels icmp_redirect_route (ic, table) 623*25202Skarels struct icmp *ic; 624*25202Skarels struct mbuf *table[]; 625*25202Skarels { 626*25202Skarels struct ip *ip; 627*25202Skarels int flags; 628*25202Skarels static struct sockaddr_in red_dst = { AF_INET } ; 629*25202Skarels static struct sockaddr_in red_gtw = { AF_INET } ; 630*25202Skarels 631*25202Skarels ip = (struct ip *) ic->ic_data; 632*25202Skarels /* 633*25202Skarels * 1. Make new routing entry so that new connections will use better 634*25202Skarels * route. But only make entry if have not already done so. 635*25202Skarels */ 636*25202Skarels if (!rtfind(ip->ip_dst, ic->ic_gaddr, table)) 637*25202Skarels { 638*25202Skarels char *err; 639*25202Skarels 640*25202Skarels /* check reasonableness of redirect */ 641*25202Skarels 642*25202Skarels if (in_iawithnet(ic->ic_gaddr) == NULL) 643*25202Skarels { 644*25202Skarels /* 645*25202Skarels * Sorry, can't get there from here. 646*25202Skarels */ 647*25202Skarels union { u_long ul; u_char c[4]; } g, f, t, v; 648*25202Skarels 649*25202Skarels err = "No interface for first hop"; 650*25202Skarels perr : 651*25202Skarels 652*25202Skarels g.ul = (((struct ip *) (((char *) ic) - sizeof(struct ip)))->ip_src.s_addr); 653*25202Skarels f.ul = ip->ip_src.s_addr; 654*25202Skarels t.ul = ip->ip_dst.s_addr; 655*25202Skarels v.ul = ic->ic_gaddr.s_addr; 656*25202Skarels log(KERN_RECOV, 657*25202Skarels "Ignoring ICMP redirect from gw %d.%d.%d.%d? to go from %d.%d.%d.%d to %d.%d.%d.%d via %d.%d.%d.%d : %s\n", 658*25202Skarels g.c[0], g.c[1], g.c[2], g.c[3], 659*25202Skarels f.c[0], f.c[1], f.c[2], f.c[3], 660*25202Skarels t.c[0], t.c[1], t.c[2], t.c[3], 661*25202Skarels v.c[0], v.c[1], v.c[2], v.c[3], 662*25202Skarels err); 663*25202Skarels 664*25202Skarels return (FALSE); 665*25202Skarels } 666*25202Skarels 667*25202Skarels if (in_iawithaddr(ic->ic_gaddr, TRUE)) 668*25202Skarels { 669*25202Skarels /* 670*25202Skarels * redirect to self is stupid, as is redirect to 671*25202Skarels * broadcast address (which if_iawithaddr will match 672*25202Skarels * for interfaces with IFF_BROADCAST set.) 673*25202Skarels */ 674*25202Skarels err = "redirected to self"; 675*25202Skarels goto perr; 676*25202Skarels } 677*25202Skarels 678*25202Skarels if (iptonet(ic->ic_gaddr) != iptonet(ip->ip_src)) 679*25202Skarels { 680*25202Skarels /* 681*25202Skarels * Why is this gateway redirecting us? It is not 682*25202Skarels * giving us a first hop gateway that is on the 683*25202Skarels * local net that we advertise. 684*25202Skarels */ 685*25202Skarels err = "new first hop net <> src net"; 686*25202Skarels goto perr; 687*25202Skarels } 688*25202Skarels 689*25202Skarels #ifdef done_in_icmp_c 690*25202Skarels if (! know_gateway(icmp source)) 691*25202Skarels /* 692*25202Skarels * Sorry, we only trust the connected set of gateways 693*25202Skarels * that includes gateways installed by the system 694*25202Skarels * manager. Who are you? Why are you talking to us? 695*25202Skarels */ 696*25202Skarels return; 697*25202Skarels #endif 698*25202Skarels 699*25202Skarels /* o.k., I'll believe it */ 700*25202Skarels flags = RTF_UP; 701*25202Skarels if (table == rthost) 702*25202Skarels { 703*25202Skarels flags |= RTF_HOST; 704*25202Skarels red_dst.sin_addr.s_addr = ip->ip_dst.s_addr; 705*25202Skarels } 706*25202Skarels else 707*25202Skarels { 708*25202Skarels flags |= RTF_GATEWAY; 709*25202Skarels red_dst.sin_addr.s_addr = iptonet(ip->ip_dst); 710*25202Skarels } 711*25202Skarels red_gtw.sin_addr.s_addr = ic->ic_gaddr.s_addr; 712*25202Skarels rtinit ((struct sockaddr *) &red_dst, 713*25202Skarels (struct sockaddr *) &red_gtw, 714*25202Skarels flags); 715*25202Skarels } 716*25202Skarels return (TRUE); 717*25202Skarels } 718*25202Skarels 719*25202Skarels icmp_redirect_inp(inp, ic, table) 720*25202Skarels struct inpcb *inp; 721*25202Skarels struct icmp *ic; 722*25202Skarels struct mbuf **table; 723*25202Skarels { 724*25202Skarels struct rtentry *rt; 725*25202Skarels 726*25202Skarels /* 727*25202Skarels * 2. Redirect current connection. 728*25202Skarels */ 729*25202Skarels 730*25202Skarels #ifdef neverdef 731*25202Skarels /* 732*25202Skarels * This would try to balance load across gateways, but 733*25202Skarels * that's something best done by the gateway before it 734*25202Skarels * sends a redirect. Also, consider 3 gateways of which 735*25202Skarels * two are bad, and possibility of bouncing between the 736*25202Skarels * two bad ones until their use counts got high enough. 737*25202Skarels * 738*25202Skarels * Currently, gateways only take into account # hops, not 739*25202Skarels * load. 740*25202Skarels */ 741*25202Skarels if (rt = inp->inp_route.ro_rt) 742*25202Skarels { 743*25202Skarels short oflags; 744*25202Skarels 745*25202Skarels /* try to force a different path */ 746*25202Skarels oflags = rt->rt_flags; 747*25202Skarels rt->rt_flags &= ~RTF_UP; 748*25202Skarels /* but don't lose current route */ 749*25202Skarels rt->rt_refcnt ++; 750*25202Skarels (void) ip_reroute (inp); 751*25202Skarels rt->rt_refcnt --; 752*25202Skarels rt->rt_flags = oflags; 753*25202Skarels } 754*25202Skarels #endif 755*25202Skarels if (rt = rtfind (ic->ic_iphdr.ip_dst, ic->ic_gaddr, table)) 756*25202Skarels { 757*25202Skarels if (rt->rt_flags & RTF_UP) 758*25202Skarels { 759*25202Skarels /* 760*25202Skarels * packets go out an interface with our local 761*25202Skarels * IP address. Know true from checks after 762*25202Skarels * first call to rtfind above. 763*25202Skarels * 764*25202Skarels * Interface has to be at least as up as 765*25202Skarels * for previous route, so don't bother to 766*25202Skarels * check. 767*25202Skarels */ 768*25202Skarels if (inp->inp_route.ro_rt) 769*25202Skarels rtfree (inp->inp_route.ro_rt); 770*25202Skarels inp->inp_route.ro_rt = rt; 771*25202Skarels rt->rt_refcnt ++; 772*25202Skarels } 773*25202Skarels else 774*25202Skarels log(KERN_RECOV, "ICMP Redirect to down route\n"); 775*25202Skarels } 776*25202Skarels else 777*25202Skarels log(KERN_RECOV, "ICMP Redirect route not installed?\n"); 778*25202Skarels } 779