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