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.1 (Berkeley) 06/04/85"; 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_ishost)(dst) ? RTF_HOST : 0; 116 if (flags & RTF_HOST) { 117 hash = h.afh_hosthash; 118 rh = &hosthash[hash & ROUTEHASHMASK]; 119 } else { 120 hash = h.afh_nethash; 121 rh = &nethash[hash & ROUTEHASHMASK]; 122 } 123 rt = (struct rt_entry *)malloc(sizeof (*rt)); 124 if (rt == 0) 125 return; 126 rt->rt_hash = hash; 127 rt->rt_dst = *dst; 128 rt->rt_router = *gate; 129 rt->rt_metric = metric; 130 rt->rt_timer = 0; 131 rt->rt_flags = RTF_UP | flags; 132 rt->rt_state = state | RTS_CHANGED; 133 rt->rt_ifp = if_ifwithnet(&rt->rt_router); 134 if (metric) 135 rt->rt_flags |= RTF_GATEWAY; 136 insque(rt, rh); 137 TRACE_ACTION(ADD, rt); 138 /* 139 * If the ioctl fails because the gateway is unreachable 140 * from this host, discard the entry. This should only 141 * occur because of an incorrect entry in /etc/gateways. 142 */ 143 if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 144 perror("SIOCADDRT"); 145 if (errno == ENETUNREACH) { 146 TRACE_ACTION(DELETE, rt); 147 remque(rt); 148 free((char *)rt); 149 } 150 } 151 } 152 153 rtchange(rt, gate, metric) 154 struct rt_entry *rt; 155 struct sockaddr *gate; 156 short metric; 157 { 158 int doioctl = 0, metricchanged = 0; 159 struct rtentry oldroute; 160 161 if (!equal(&rt->rt_router, gate)) 162 doioctl++; 163 if (metric != rt->rt_metric) 164 metricchanged++; 165 if (doioctl || metricchanged) { 166 TRACE_ACTION(CHANGE FROM, rt); 167 if (doioctl) { 168 oldroute = rt->rt_rt; 169 rt->rt_router = *gate; 170 } 171 rt->rt_metric = metric; 172 if ((rt->rt_state & RTS_INTERFACE) && metric) { 173 rt->rt_state &= ~RTS_INTERFACE; 174 syslog(LOG_ERR, 175 "changing route from interface %s (timed out)", 176 rt->rt_ifp->int_name); 177 } 178 if (metric) 179 rt->rt_flags |= RTF_GATEWAY; 180 else 181 rt->rt_flags &= ~RTF_GATEWAY; 182 rt->rt_state |= RTS_CHANGED; 183 TRACE_ACTION(CHANGE TO, rt); 184 } 185 if (doioctl && install) { 186 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 187 perror("SIOCADDRT"); 188 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 189 perror("SIOCDELRT"); 190 } 191 } 192 193 rtdelete(rt) 194 struct rt_entry *rt; 195 { 196 197 if (rt->rt_state & RTS_INTERFACE) 198 syslog(LOG_ERR, "deleting route to interface %s (timed out)", 199 rt->rt_ifp->int_name); 200 TRACE_ACTION(DELETE, rt); 201 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 202 perror("SIOCDELRT"); 203 remque(rt); 204 free((char *)rt); 205 } 206 207 /* 208 * If we have an interface to the wide, wide world, 209 * add an entry for an Internet default route (wildcard) to the internal 210 * tables and advertise it. This route is not added to the kernel routes, 211 * but this entry prevents us from listening to other people's defaults 212 * and installing them in the kernel here. 213 */ 214 rtdefault() 215 { 216 struct afhash h; 217 register struct rt_entry *rt; 218 struct rthash *rh; 219 extern struct sockaddr inet_default; 220 221 rt = (struct rt_entry *)malloc(sizeof (*rt)); 222 if (rt == 0) 223 return; 224 rt->rt_dst = inet_default; 225 rt->rt_router = rt->rt_dst; 226 (*afswitch[AF_INET].af_hash)(&rt->rt_dst, &h); 227 rh = &nethash[h.afh_nethash & ROUTEHASHMASK]; 228 rt->rt_hash = h.afh_nethash; 229 rt->rt_metric = 0; 230 rt->rt_timer = 0; 231 rt->rt_flags = RTF_UP | RTF_GATEWAY; 232 rt->rt_state = RTS_CHANGED | RTS_PASSIVE; 233 rt->rt_ifp = 0; 234 insque(rt, rh); 235 TRACE_ACTION(ADD, rt); 236 } 237 238 rtinit() 239 { 240 register struct rthash *rh; 241 242 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 243 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 244 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 245 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 246 } 247