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: }