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