1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)tables.c 5.15 (Berkeley) 02/18/89"; 20 #endif /* not lint */ 21 22 /* 23 * Routing Table Management Daemon 24 */ 25 #include "defs.h" 26 #include <sys/ioctl.h> 27 #include <errno.h> 28 #include <sys/syslog.h> 29 30 #ifndef DEBUG 31 #define DEBUG 0 32 #endif 33 34 int install = !DEBUG; /* if 1 call kernel */ 35 36 /* 37 * Lookup dst in the tables for an exact match. 38 */ 39 struct rt_entry * 40 rtlookup(dst) 41 struct sockaddr *dst; 42 { 43 register struct rt_entry *rt; 44 register struct rthash *rh; 45 register u_int hash; 46 struct afhash h; 47 int doinghost = 1; 48 49 if (dst->sa_family >= af_max) 50 return (0); 51 (*afswitch[dst->sa_family].af_hash)(dst, &h); 52 hash = h.afh_hosthash; 53 rh = &hosthash[hash & ROUTEHASHMASK]; 54 again: 55 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 56 if (rt->rt_hash != hash) 57 continue; 58 if (equal(&rt->rt_dst, dst)) 59 return (rt); 60 } 61 if (doinghost) { 62 doinghost = 0; 63 hash = h.afh_nethash; 64 rh = &nethash[hash & ROUTEHASHMASK]; 65 goto again; 66 } 67 return (0); 68 } 69 70 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 71 72 /* 73 * Find a route to dst as the kernel would. 74 */ 75 struct rt_entry * 76 rtfind(dst) 77 struct sockaddr *dst; 78 { 79 register struct rt_entry *rt; 80 register struct rthash *rh; 81 register u_int hash; 82 struct afhash h; 83 int af = dst->sa_family; 84 int doinghost = 1, (*match)(); 85 86 if (af >= af_max) 87 return (0); 88 (*afswitch[af].af_hash)(dst, &h); 89 hash = h.afh_hosthash; 90 rh = &hosthash[hash & ROUTEHASHMASK]; 91 92 again: 93 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 94 if (rt->rt_hash != hash) 95 continue; 96 if (doinghost) { 97 if (equal(&rt->rt_dst, dst)) 98 return (rt); 99 } else { 100 if (rt->rt_dst.sa_family == af && 101 (*match)(&rt->rt_dst, dst)) 102 return (rt); 103 } 104 } 105 if (doinghost) { 106 doinghost = 0; 107 hash = h.afh_nethash; 108 rh = &nethash[hash & ROUTEHASHMASK]; 109 match = afswitch[af].af_netmatch; 110 goto again; 111 } 112 #ifdef notyet 113 /* 114 * Check for wildcard gateway, by convention network 0. 115 */ 116 if (dst != &wildcard) { 117 dst = &wildcard, hash = 0; 118 goto again; 119 } 120 #endif 121 return (0); 122 } 123 124 rtadd(dst, gate, metric, state) 125 struct sockaddr *dst, *gate; 126 int metric, state; 127 { 128 struct afhash h; 129 register struct rt_entry *rt; 130 struct rthash *rh; 131 int af = dst->sa_family, flags; 132 u_int hash; 133 134 if (af >= af_max) 135 return; 136 (*afswitch[af].af_hash)(dst, &h); 137 flags = (*afswitch[af].af_rtflags)(dst); 138 /* 139 * Subnet flag isn't visible to kernel, move to state. XXX 140 */ 141 if (flags & RTF_SUBNET) { 142 state |= RTS_SUBNET; 143 flags &= ~RTF_SUBNET; 144 } 145 if (flags & RTF_HOST) { 146 hash = h.afh_hosthash; 147 rh = &hosthash[hash & ROUTEHASHMASK]; 148 } else { 149 hash = h.afh_nethash; 150 rh = &nethash[hash & ROUTEHASHMASK]; 151 } 152 rt = (struct rt_entry *)malloc(sizeof (*rt)); 153 if (rt == 0) 154 return; 155 rt->rt_hash = hash; 156 rt->rt_dst = *dst; 157 rt->rt_router = *gate; 158 rt->rt_timer = 0; 159 rt->rt_flags = RTF_UP | flags; 160 rt->rt_state = state | RTS_CHANGED; 161 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); 162 if (rt->rt_ifp == 0) 163 rt->rt_ifp = if_ifwithnet(&rt->rt_router); 164 if ((state & RTS_INTERFACE) == 0) 165 rt->rt_flags |= RTF_GATEWAY; 166 rt->rt_metric = metric; 167 insque(rt, rh); 168 TRACE_ACTION("ADD", rt); 169 /* 170 * If the ioctl fails because the gateway is unreachable 171 * from this host, discard the entry. This should only 172 * occur because of an incorrect entry in /etc/gateways. 173 */ 174 if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && 175 ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 176 if (errno != EEXIST && gate->sa_family < af_max) 177 syslog(LOG_ERR, 178 "adding route to net/host %s through gateway %s: %m\n", 179 (*afswitch[dst->sa_family].af_format)(dst), 180 (*afswitch[gate->sa_family].af_format)(gate)); 181 perror("SIOCADDRT"); 182 if (errno == ENETUNREACH) { 183 TRACE_ACTION("DELETE", rt); 184 remque(rt); 185 free((char *)rt); 186 } 187 } 188 } 189 190 rtchange(rt, gate, metric) 191 struct rt_entry *rt; 192 struct sockaddr *gate; 193 short metric; 194 { 195 int add = 0, delete = 0, newgateway = 0; 196 struct rtentry oldroute; 197 198 if (!equal(&rt->rt_router, gate)) { 199 newgateway++; 200 TRACE_ACTION("CHANGE FROM ", rt); 201 } else if (metric != rt->rt_metric) 202 TRACE_NEWMETRIC(rt, metric); 203 if ((rt->rt_state & RTS_INTERNAL) == 0) { 204 /* 205 * If changing to different router, we need to add 206 * new route and delete old one if in the kernel. 207 * If the router is the same, we need to delete 208 * the route if has become unreachable, or re-add 209 * it if it had been unreachable. 210 */ 211 if (newgateway) { 212 add++; 213 if (rt->rt_metric != HOPCNT_INFINITY) 214 delete++; 215 } else if (metric == HOPCNT_INFINITY) 216 delete++; 217 else if (rt->rt_metric == HOPCNT_INFINITY) 218 add++; 219 } 220 if (delete) 221 oldroute = rt->rt_rt; 222 if ((rt->rt_state & RTS_INTERFACE) && delete) { 223 rt->rt_state &= ~RTS_INTERFACE; 224 rt->rt_flags |= RTF_GATEWAY; 225 if (metric > rt->rt_metric && delete) 226 syslog(LOG_ERR, "%s route to interface %s (timed out)", 227 add? "changing" : "deleting", 228 rt->rt_ifp->int_name); 229 } 230 if (add) { 231 rt->rt_router = *gate; 232 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); 233 if (rt->rt_ifp == 0) 234 rt->rt_ifp = if_ifwithnet(&rt->rt_router); 235 } 236 rt->rt_metric = metric; 237 rt->rt_state |= RTS_CHANGED; 238 if (newgateway) 239 TRACE_ACTION("CHANGE TO ", rt); 240 if (add && install) 241 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 242 perror("SIOCADDRT"); 243 if (delete && install) 244 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 245 perror("SIOCDELRT"); 246 } 247 248 rtdelete(rt) 249 struct rt_entry *rt; 250 { 251 252 TRACE_ACTION("DELETE", rt); 253 if (rt->rt_metric < HOPCNT_INFINITY) { 254 if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE) 255 syslog(LOG_ERR, 256 "deleting route to interface %s? (timed out?)", 257 rt->rt_ifp->int_name); 258 if (install && 259 (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && 260 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 261 perror("SIOCDELRT"); 262 } 263 remque(rt); 264 free((char *)rt); 265 } 266 267 rtdeleteall(sig) 268 int sig; 269 { 270 register struct rthash *rh; 271 register struct rt_entry *rt; 272 struct rthash *base = hosthash; 273 int doinghost = 1; 274 275 again: 276 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 277 rt = rh->rt_forw; 278 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 279 if (rt->rt_state & RTS_INTERFACE || 280 rt->rt_metric >= HOPCNT_INFINITY) 281 continue; 282 TRACE_ACTION("DELETE", rt); 283 if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 && 284 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 285 perror("SIOCDELRT"); 286 } 287 } 288 if (doinghost) { 289 doinghost = 0; 290 base = nethash; 291 goto again; 292 } 293 exit(sig); 294 } 295 296 /* 297 * If we have an interface to the wide, wide world, 298 * add an entry for an Internet default route (wildcard) to the internal 299 * tables and advertise it. This route is not added to the kernel routes, 300 * but this entry prevents us from listening to other people's defaults 301 * and installing them in the kernel here. 302 */ 303 rtdefault() 304 { 305 extern struct sockaddr inet_default; 306 307 rtadd(&inet_default, &inet_default, 1, 308 RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL); 309 } 310 311 rtinit() 312 { 313 register struct rthash *rh; 314 315 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 316 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 317 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 318 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 319 } 320