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