|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 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: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)tables.c 5.5 (Berkeley) 5/28/86"; ! 9: #endif not lint ! 10: ! 11: /* ! 12: * Routing Table Management Daemon ! 13: */ ! 14: #include "defs.h" ! 15: #include <sys/ioctl.h> ! 16: #include <errno.h> ! 17: #include <syslog.h> ! 18: ! 19: #ifndef DEBUG ! 20: #define DEBUG 0 ! 21: #endif ! 22: ! 23: int install = !DEBUG; /* if 1 call kernel */ ! 24: ! 25: /* ! 26: * Lookup dst in the tables for an exact match. ! 27: */ ! 28: struct rt_entry * ! 29: rtlookup(dst) ! 30: struct sockaddr *dst; ! 31: { ! 32: register struct rt_entry *rt; ! 33: register struct rthash *rh; ! 34: register u_int hash; ! 35: struct afhash h; ! 36: int doinghost = 1; ! 37: ! 38: if (dst->sa_family >= af_max) ! 39: return (0); ! 40: (*afswitch[dst->sa_family].af_hash)(dst, &h); ! 41: hash = h.afh_hosthash; ! 42: rh = &hosthash[hash & ROUTEHASHMASK]; ! 43: again: ! 44: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 45: if (rt->rt_hash != hash) ! 46: continue; ! 47: if (equal(&rt->rt_dst, dst)) ! 48: return (rt); ! 49: } ! 50: if (doinghost) { ! 51: doinghost = 0; ! 52: hash = h.afh_nethash; ! 53: rh = &nethash[hash & ROUTEHASHMASK]; ! 54: goto again; ! 55: } ! 56: return (0); ! 57: } ! 58: ! 59: /* ! 60: * Find a route to dst as the kernel would. ! 61: */ ! 62: struct rt_entry * ! 63: rtfind(dst) ! 64: struct sockaddr *dst; ! 65: { ! 66: register struct rt_entry *rt; ! 67: register struct rthash *rh; ! 68: register u_int hash; ! 69: struct afhash h; ! 70: int af = dst->sa_family; ! 71: int doinghost = 1, (*match)(); ! 72: ! 73: if (af >= af_max) ! 74: return (0); ! 75: (*afswitch[af].af_hash)(dst, &h); ! 76: hash = h.afh_hosthash; ! 77: rh = &hosthash[hash & ROUTEHASHMASK]; ! 78: ! 79: again: ! 80: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 81: if (rt->rt_hash != hash) ! 82: continue; ! 83: if (doinghost) { ! 84: if (equal(&rt->rt_dst, dst)) ! 85: return (rt); ! 86: } else { ! 87: if (rt->rt_dst.sa_family == af && ! 88: (*match)(&rt->rt_dst, dst)) ! 89: return (rt); ! 90: } ! 91: } ! 92: if (doinghost) { ! 93: doinghost = 0; ! 94: hash = h.afh_nethash; ! 95: rh = &nethash[hash & ROUTEHASHMASK]; ! 96: match = afswitch[af].af_netmatch; ! 97: goto again; ! 98: } ! 99: return (0); ! 100: } ! 101: ! 102: rtadd(dst, gate, metric, state) ! 103: struct sockaddr *dst, *gate; ! 104: int metric, state; ! 105: { ! 106: struct afhash h; ! 107: register struct rt_entry *rt; ! 108: struct rthash *rh; ! 109: int af = dst->sa_family, flags; ! 110: u_int hash; ! 111: ! 112: if (af >= af_max) ! 113: return; ! 114: (*afswitch[af].af_hash)(dst, &h); ! 115: flags = (*afswitch[af].af_rtflags)(dst); ! 116: /* ! 117: * Subnet flag isn't visible to kernel, move to state. XXX ! 118: */ ! 119: if (flags & RTF_SUBNET) { ! 120: state |= RTS_SUBNET; ! 121: flags &= ~RTF_SUBNET; ! 122: } ! 123: if (flags & RTF_HOST) { ! 124: hash = h.afh_hosthash; ! 125: rh = &hosthash[hash & ROUTEHASHMASK]; ! 126: } else { ! 127: hash = h.afh_nethash; ! 128: rh = &nethash[hash & ROUTEHASHMASK]; ! 129: } ! 130: rt = (struct rt_entry *)malloc(sizeof (*rt)); ! 131: if (rt == 0) ! 132: return; ! 133: rt->rt_hash = hash; ! 134: rt->rt_dst = *dst; ! 135: rt->rt_router = *gate; ! 136: rt->rt_metric = metric; ! 137: rt->rt_timer = 0; ! 138: rt->rt_flags = RTF_UP | flags; ! 139: rt->rt_state = state | RTS_CHANGED; ! 140: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); ! 141: if (rt->rt_ifp == 0) ! 142: rt->rt_ifp = if_ifwithnet(&rt->rt_router); ! 143: if (metric) ! 144: rt->rt_flags |= RTF_GATEWAY; ! 145: insque(rt, rh); ! 146: TRACE_ACTION(ADD, rt); ! 147: /* ! 148: * If the ioctl fails because the gateway is unreachable ! 149: * from this host, discard the entry. This should only ! 150: * occur because of an incorrect entry in /etc/gateways. ! 151: */ ! 152: if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && ! 153: ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { ! 154: perror("SIOCADDRT"); ! 155: if (errno == ENETUNREACH) { ! 156: TRACE_ACTION(DELETE, rt); ! 157: remque(rt); ! 158: free((char *)rt); ! 159: } ! 160: } ! 161: } ! 162: ! 163: rtchange(rt, gate, metric) ! 164: struct rt_entry *rt; ! 165: struct sockaddr *gate; ! 166: short metric; ! 167: { ! 168: int doioctl = 0, metricchanged = 0; ! 169: struct rtentry oldroute; ! 170: ! 171: if (!equal(&rt->rt_router, gate) && (rt->rt_state & RTS_INTERNAL) == 0) ! 172: doioctl++; ! 173: if (metric != rt->rt_metric) ! 174: metricchanged++; ! 175: if (doioctl || metricchanged) { ! 176: TRACE_ACTION(CHANGE FROM, rt); ! 177: if ((rt->rt_state & RTS_INTERFACE) && metric) { ! 178: rt->rt_state &= ~RTS_INTERFACE; ! 179: syslog(LOG_ERR, ! 180: "changing route from interface %s (timed out)", ! 181: rt->rt_ifp->int_name); ! 182: } ! 183: if (doioctl) { ! 184: oldroute = rt->rt_rt; ! 185: rt->rt_router = *gate; ! 186: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); ! 187: if (rt->rt_ifp == 0) ! 188: rt->rt_ifp = if_ifwithnet(&rt->rt_router); ! 189: } ! 190: rt->rt_metric = metric; ! 191: if (metric) ! 192: rt->rt_flags |= RTF_GATEWAY; ! 193: else ! 194: rt->rt_flags &= ~RTF_GATEWAY; ! 195: rt->rt_state |= RTS_CHANGED; ! 196: TRACE_ACTION(CHANGE TO, rt); ! 197: } ! 198: if (doioctl && install) { ! 199: if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) ! 200: perror("SIOCADDRT"); ! 201: if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) ! 202: perror("SIOCDELRT"); ! 203: } ! 204: } ! 205: ! 206: rtdelete(rt) ! 207: struct rt_entry *rt; ! 208: { ! 209: ! 210: if (rt->rt_state & RTS_INTERFACE) ! 211: syslog(LOG_ERR, "deleting route to interface %s (timed out)", ! 212: rt->rt_ifp->int_name); ! 213: TRACE_ACTION(DELETE, rt); ! 214: if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && ! 215: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) ! 216: perror("SIOCDELRT"); ! 217: remque(rt); ! 218: free((char *)rt); ! 219: } ! 220: ! 221: /* ! 222: * If we have an interface to the wide, wide world, ! 223: * add an entry for an Internet default route (wildcard) to the internal ! 224: * tables and advertise it. This route is not added to the kernel routes, ! 225: * but this entry prevents us from listening to other people's defaults ! 226: * and installing them in the kernel here. ! 227: */ ! 228: rtdefault() ! 229: { ! 230: extern struct sockaddr inet_default; ! 231: ! 232: rtadd(&inet_default, &inet_default, 0, ! 233: RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL); ! 234: } ! 235: ! 236: rtinit() ! 237: { ! 238: register struct rthash *rh; ! 239: ! 240: for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) ! 241: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; ! 242: for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) ! 243: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; ! 244: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.