|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983, 1988 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 this notice is preserved and that due credit is given ! 7: * to the University of California at Berkeley. The name of the University ! 8: * may not be used to endorse or promote products derived from this ! 9: * software without specific prior written permission. This software ! 10: * is provided ``as is'' without express or implied warranty. ! 11: */ ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)tables.c 5.13 (Berkeley) 6/6/88"; ! 15: #endif /* not lint */ ! 16: ! 17: /* ! 18: * Routing Table Management Daemon ! 19: */ ! 20: #include "defs.h" ! 21: #include <sys/ioctl.h> ! 22: #include <errno.h> ! 23: #include <sys/syslog.h> ! 24: ! 25: #ifndef DEBUG ! 26: #define DEBUG 0 ! 27: #endif ! 28: ! 29: int install = !DEBUG; /* if 1 call kernel */ ! 30: ! 31: /* ! 32: * Lookup dst in the tables for an exact match. ! 33: */ ! 34: struct rt_entry * ! 35: rtlookup(dst) ! 36: struct sockaddr *dst; ! 37: { ! 38: register struct rt_entry *rt; ! 39: register struct rthash *rh; ! 40: register u_int hash; ! 41: struct afhash h; ! 42: int doinghost = 1; ! 43: ! 44: if (dst->sa_family >= af_max) ! 45: return (0); ! 46: (*afswitch[dst->sa_family].af_hash)(dst, &h); ! 47: hash = h.afh_hosthash; ! 48: rh = &hosthash[hash & ROUTEHASHMASK]; ! 49: again: ! 50: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 51: if (rt->rt_hash != hash) ! 52: continue; ! 53: if (equal(&rt->rt_dst, dst)) ! 54: return (rt); ! 55: } ! 56: if (doinghost) { ! 57: doinghost = 0; ! 58: hash = h.afh_nethash; ! 59: rh = &nethash[hash & ROUTEHASHMASK]; ! 60: goto again; ! 61: } ! 62: return (0); ! 63: } ! 64: ! 65: struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ ! 66: ! 67: /* ! 68: * Find a route to dst as the kernel would. ! 69: */ ! 70: struct rt_entry * ! 71: rtfind(dst) ! 72: struct sockaddr *dst; ! 73: { ! 74: register struct rt_entry *rt; ! 75: register struct rthash *rh; ! 76: register u_int hash; ! 77: struct afhash h; ! 78: int af = dst->sa_family; ! 79: int doinghost = 1, (*match)(); ! 80: ! 81: if (af >= af_max) ! 82: return (0); ! 83: (*afswitch[af].af_hash)(dst, &h); ! 84: hash = h.afh_hosthash; ! 85: rh = &hosthash[hash & ROUTEHASHMASK]; ! 86: ! 87: again: ! 88: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 89: if (rt->rt_hash != hash) ! 90: continue; ! 91: if (doinghost) { ! 92: if (equal(&rt->rt_dst, dst)) ! 93: return (rt); ! 94: } else { ! 95: if (rt->rt_dst.sa_family == af && ! 96: (*match)(&rt->rt_dst, dst)) ! 97: return (rt); ! 98: } ! 99: } ! 100: if (doinghost) { ! 101: doinghost = 0; ! 102: hash = h.afh_nethash; ! 103: rh = &nethash[hash & ROUTEHASHMASK]; ! 104: match = afswitch[af].af_netmatch; ! 105: goto again; ! 106: } ! 107: #ifdef notyet ! 108: /* ! 109: * Check for wildcard gateway, by convention network 0. ! 110: */ ! 111: if (dst != &wildcard) { ! 112: dst = &wildcard, hash = 0; ! 113: goto again; ! 114: } ! 115: #endif ! 116: return (0); ! 117: } ! 118: ! 119: rtadd(dst, gate, metric, state) ! 120: struct sockaddr *dst, *gate; ! 121: int metric, state; ! 122: { ! 123: struct afhash h; ! 124: register struct rt_entry *rt; ! 125: struct rthash *rh; ! 126: int af = dst->sa_family, flags; ! 127: u_int hash; ! 128: ! 129: if (af >= af_max) ! 130: return; ! 131: (*afswitch[af].af_hash)(dst, &h); ! 132: flags = (*afswitch[af].af_rtflags)(dst); ! 133: /* ! 134: * Subnet flag isn't visible to kernel, move to state. XXX ! 135: */ ! 136: if (flags & RTF_SUBNET) { ! 137: state |= RTS_SUBNET; ! 138: flags &= ~RTF_SUBNET; ! 139: } ! 140: if (flags & RTF_HOST) { ! 141: hash = h.afh_hosthash; ! 142: rh = &hosthash[hash & ROUTEHASHMASK]; ! 143: } else { ! 144: hash = h.afh_nethash; ! 145: rh = &nethash[hash & ROUTEHASHMASK]; ! 146: } ! 147: rt = (struct rt_entry *)malloc(sizeof (*rt)); ! 148: if (rt == 0) ! 149: return; ! 150: rt->rt_hash = hash; ! 151: rt->rt_dst = *dst; ! 152: rt->rt_router = *gate; ! 153: rt->rt_timer = 0; ! 154: rt->rt_flags = RTF_UP | flags; ! 155: rt->rt_state = state | RTS_CHANGED; ! 156: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); ! 157: if (rt->rt_ifp == 0) ! 158: rt->rt_ifp = if_ifwithnet(&rt->rt_router); ! 159: if ((state & RTS_INTERFACE) == 0) ! 160: rt->rt_flags |= RTF_GATEWAY; ! 161: rt->rt_metric = metric; ! 162: insque(rt, rh); ! 163: TRACE_ACTION("ADD", rt); ! 164: /* ! 165: * If the ioctl fails because the gateway is unreachable ! 166: * from this host, discard the entry. This should only ! 167: * occur because of an incorrect entry in /etc/gateways. ! 168: */ ! 169: if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && ! 170: ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { ! 171: if (errno != EEXIST && gate->sa_family < af_max) ! 172: syslog(LOG_ERR, ! 173: "adding route to net/host %s through gateway %s: %m\n", ! 174: (*afswitch[dst->sa_family].af_format)(dst), ! 175: (*afswitch[gate->sa_family].af_format)(gate)); ! 176: perror("SIOCADDRT"); ! 177: if (errno == ENETUNREACH) { ! 178: TRACE_ACTION("DELETE", rt); ! 179: remque(rt); ! 180: free((char *)rt); ! 181: } ! 182: } ! 183: } ! 184: ! 185: rtchange(rt, gate, metric) ! 186: struct rt_entry *rt; ! 187: struct sockaddr *gate; ! 188: short metric; ! 189: { ! 190: int add = 0, delete = 0; ! 191: struct rtentry oldroute; ! 192: ! 193: if ((rt->rt_state & RTS_INTERNAL) == 0) { ! 194: /* ! 195: * If changing to different router, we need to add ! 196: * new route and delete old one if in the kernel. ! 197: * If the router is the same, we need to delete ! 198: * the route if has become unreachable, or re-add ! 199: * it if it had been unreachable. ! 200: */ ! 201: if (!equal(&rt->rt_router, gate)) { ! 202: add++; ! 203: if (rt->rt_metric != HOPCNT_INFINITY) ! 204: delete++; ! 205: } else if (metric == HOPCNT_INFINITY) ! 206: delete++; ! 207: else if (rt->rt_metric == HOPCNT_INFINITY) ! 208: add++; ! 209: } ! 210: if (!equal(&rt->rt_router, gate)) { ! 211: TRACE_ACTION("CHANGE FROM ", rt); ! 212: } else if (metric != rt->rt_metric) ! 213: TRACE_NEWMETRIC(rt, metric); ! 214: if (delete) ! 215: oldroute = rt->rt_rt; ! 216: if ((rt->rt_state & RTS_INTERFACE) && delete) { ! 217: rt->rt_state &= ~RTS_INTERFACE; ! 218: rt->rt_flags |= RTF_GATEWAY; ! 219: if (metric > rt->rt_metric && delete) ! 220: syslog(LOG_ERR, "%s route to interface %s (timed out)", ! 221: add? "changing" : "deleting", ! 222: rt->rt_ifp->int_name); ! 223: } ! 224: if (add) { ! 225: rt->rt_router = *gate; ! 226: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); ! 227: if (rt->rt_ifp == 0) ! 228: rt->rt_ifp = if_ifwithnet(&rt->rt_router); ! 229: } ! 230: rt->rt_metric = metric; ! 231: rt->rt_state |= RTS_CHANGED; ! 232: if (add) ! 233: TRACE_ACTION("CHANGE TO ", rt); ! 234: if (add && install) ! 235: if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) ! 236: perror("SIOCADDRT"); ! 237: if (delete && install) ! 238: if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) ! 239: perror("SIOCDELRT"); ! 240: } ! 241: ! 242: rtdelete(rt) ! 243: struct rt_entry *rt; ! 244: { ! 245: ! 246: TRACE_ACTION("DELETE", rt); ! 247: if (rt->rt_metric < HOPCNT_INFINITY) { ! 248: if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE) ! 249: syslog(LOG_ERR, ! 250: "deleting route to interface %s? (timed out?)", ! 251: rt->rt_ifp->int_name); ! 252: if (install && ! 253: (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && ! 254: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) ! 255: perror("SIOCDELRT"); ! 256: } ! 257: remque(rt); ! 258: free((char *)rt); ! 259: } ! 260: ! 261: rtdeleteall(s) ! 262: int s; ! 263: { ! 264: register struct rthash *rh; ! 265: register struct rt_entry *rt; ! 266: struct rthash *base = hosthash; ! 267: int doinghost = 1; ! 268: ! 269: again: ! 270: for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { ! 271: rt = rh->rt_forw; ! 272: for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 273: if (rt->rt_state & RTS_INTERFACE || ! 274: rt->rt_metric >= HOPCNT_INFINITY) ! 275: continue; ! 276: TRACE_ACTION("DELETE", rt); ! 277: if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 && ! 278: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) ! 279: perror("SIOCDELRT"); ! 280: } ! 281: } ! 282: if (doinghost) { ! 283: doinghost = 0; ! 284: base = nethash; ! 285: goto again; ! 286: } ! 287: exit(s); ! 288: } ! 289: ! 290: /* ! 291: * If we have an interface to the wide, wide world, ! 292: * add an entry for an Internet default route (wildcard) to the internal ! 293: * tables and advertise it. This route is not added to the kernel routes, ! 294: * but this entry prevents us from listening to other people's defaults ! 295: * and installing them in the kernel here. ! 296: */ ! 297: rtdefault() ! 298: { ! 299: extern struct sockaddr inet_default; ! 300: ! 301: rtadd(&inet_default, &inet_default, 1, ! 302: RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL); ! 303: } ! 304: ! 305: rtinit() ! 306: { ! 307: register struct rthash *rh; ! 308: ! 309: for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) ! 310: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; ! 311: for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) ! 312: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; ! 313: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.