1 /* 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 06/05/93"; 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 && rtioctl(ADD, &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 (rtioctl(ADD, &rt->rt_rt) < 0) 195 syslog(LOG_ERR, "rtioctl ADD 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 && rtioctl(DELETE, &oldroute) < 0) 199 perror("rtioctl DELETE"); 200 #else 201 if (delete == 0) { 202 if (rtioctl(ADD, &rt->rt_rt) >= 0) 203 return; 204 } else { 205 if (rtioctl(CHANGE, &rt->rt_rt) >= 0) 206 return; 207 } 208 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 209 xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 210 xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 211 #endif 212 } 213 } 214 215 rtdelete(rt) 216 struct rt_entry *rt; 217 { 218 219 struct sockaddr *sa = &(rt->rt_rt.rt_gateway); 220 FIXLEN(sa); 221 #undef rt_dst 222 sa = &(rt->rt_rt.rt_dst); 223 FIXLEN(sa); 224 if (rt->rt_state & RTS_INTERFACE) { 225 syslog(LOG_ERR, "deleting route to interface %s (timed out)", 226 rt->rt_ifp->int_name); 227 } 228 TRACE_ACTION(DELETE, rt); 229 if (install && rtioctl(DELETE, &rt->rt_rt) < 0) 230 perror("rtioctl DELETE"); 231 remque(rt); 232 free((char *)rt); 233 } 234 235 rtinit() 236 { 237 register struct rthash *rh; 238 239 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 240 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 241 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 242 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 243 } 244 int seqno; 245 246 rtioctl(action, ort) 247 int action; 248 struct ortentry *ort; 249 { 250 #ifndef RTM_ADD 251 switch (action) { 252 253 case ADD: 254 return (ioctl(s, SIOCADDRT, (char *)ort)); 255 256 case DELETE: 257 return (ioctl(s, SIOCDELRT, (char *)ort)); 258 259 default: 260 return (-1); 261 } 262 #else /* RTM_ADD */ 263 struct { 264 struct rt_msghdr w_rtm; 265 struct sockaddr w_dst; 266 struct sockaddr w_gate; 267 struct sockaddr_ns w_netmask; 268 } w; 269 #define rtm w.w_rtm 270 271 bzero((char *)&w, sizeof(w)); 272 rtm.rtm_msglen = sizeof(w); 273 rtm.rtm_version = RTM_VERSION; 274 rtm.rtm_type = (action == ADD ? RTM_ADD : 275 (action == DELETE ? RTM_DELETE : RTM_CHANGE)); 276 #undef rt_flags 277 rtm.rtm_flags = ort->rt_flags; 278 rtm.rtm_seq = ++seqno; 279 rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 280 bcopy((char *)&ort->rt_dst, (char *)&w.w_dst, sizeof(w.w_dst)); 281 bcopy((char *)&ort->rt_gateway, (char *)&w.w_gate, sizeof(w.w_gate)); 282 w.w_gate.sa_family = w.w_dst.sa_family = AF_NS; 283 w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); 284 if (rtm.rtm_flags & RTF_HOST) { 285 rtm.rtm_msglen -= sizeof(w.w_netmask); 286 } else { 287 w.w_netmask = ns_netmask; 288 rtm.rtm_msglen -= 8; 289 } 290 errno = 0; 291 return write(r, (char *)&w, rtm.rtm_msglen); 292 #endif /* RTM_ADD */ 293 } 294