1 /* 2 * Copyright (c) 1985 The 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.8 (Berkeley) 08/21/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 29 #ifndef DEBUG 30 #define DEBUG 0 31 #endif 32 33 extern char *xns_ntoa(); 34 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} 35 36 int install = !DEBUG; /* if 1 call kernel */ 37 int delete = 1; 38 /* 39 * Lookup dst in the tables for an exact match. 40 */ 41 struct rt_entry * 42 rtlookup(dst) 43 struct sockaddr *dst; 44 { 45 register struct rt_entry *rt; 46 register struct rthash *rh; 47 register u_int hash; 48 struct afhash h; 49 int doinghost = 1; 50 51 if (dst->sa_family >= AF_MAX) 52 return (0); 53 (*afswitch[dst->sa_family].af_hash)(dst, &h); 54 hash = h.afh_hosthash; 55 rh = &hosthash[hash & ROUTEHASHMASK]; 56 again: 57 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 58 if (rt->rt_hash != hash) 59 continue; 60 if (equal(&rt->rt_dst, dst)) 61 return (rt); 62 } 63 if (doinghost) { 64 doinghost = 0; 65 hash = h.afh_nethash; 66 rh = &nethash[hash & ROUTEHASHMASK]; 67 goto again; 68 } 69 return (0); 70 } 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 return (0); 113 } 114 115 rtadd(dst, gate, metric, state) 116 struct sockaddr *dst, *gate; 117 int metric, state; 118 { 119 struct afhash h; 120 register struct rt_entry *rt; 121 struct rthash *rh; 122 int af = dst->sa_family, flags; 123 u_int hash; 124 125 FIXLEN(dst); 126 FIXLEN(gate); 127 if (af >= AF_MAX) 128 return; 129 (*afswitch[af].af_hash)(dst, &h); 130 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 131 if (flags & RTF_HOST) { 132 hash = h.afh_hosthash; 133 rh = &hosthash[hash & ROUTEHASHMASK]; 134 } else { 135 hash = h.afh_nethash; 136 rh = &nethash[hash & ROUTEHASHMASK]; 137 } 138 rt = (struct rt_entry *)malloc(sizeof (*rt)); 139 if (rt == 0) 140 return; 141 rt->rt_hash = hash; 142 rt->rt_dst = *dst; 143 rt->rt_router = *gate; 144 rt->rt_metric = metric; 145 rt->rt_timer = 0; 146 rt->rt_flags = RTF_UP | flags; 147 rt->rt_state = state | RTS_CHANGED; 148 rt->rt_ifp = if_ifwithnet(&rt->rt_router); 149 if (metric) 150 rt->rt_flags |= RTF_GATEWAY; 151 insque(rt, rh); 152 TRACE_ACTION(ADD, rt); 153 /* 154 * If the ioctl fails because the gateway is unreachable 155 * from this host, discard the entry. This should only 156 * occur because of an incorrect entry in /etc/gateways. 157 */ 158 if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 159 if (errno != EEXIST) 160 perror("SIOCADDRT"); 161 if (errno == ENETUNREACH) { 162 TRACE_ACTION(DELETE, rt); 163 remque(rt); 164 free((char *)rt); 165 } 166 } 167 } 168 169 rtchange(rt, gate, metric) 170 struct rt_entry *rt; 171 struct sockaddr *gate; 172 short metric; 173 { 174 int doioctl = 0, metricchanged = 0; 175 struct rtentry oldroute; 176 177 FIXLEN(gate); 178 if (!equal(&rt->rt_router, gate)) 179 doioctl++; 180 if (metric != rt->rt_metric) 181 metricchanged++; 182 if (doioctl || metricchanged) { 183 TRACE_ACTION(CHANGE FROM, rt); 184 if (doioctl) { 185 oldroute = rt->rt_rt; 186 rt->rt_router = *gate; 187 } 188 rt->rt_metric = metric; 189 if ((rt->rt_state & RTS_INTERFACE) && metric) { 190 rt->rt_state &= ~RTS_INTERFACE; 191 syslog(LOG_ERR, 192 "changing route from interface %s (timed out)", 193 rt->rt_ifp->int_name); 194 } 195 if (metric) 196 rt->rt_flags |= RTF_GATEWAY; 197 else 198 rt->rt_flags &= ~RTF_GATEWAY; 199 rt->rt_state |= RTS_CHANGED; 200 TRACE_ACTION(CHANGE TO, rt); 201 } 202 if (doioctl && install) { 203 #ifndef RTM_ADD 204 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 205 syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", 206 xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 207 xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 208 if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 209 perror("SIOCDELRT"); 210 #else 211 if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 212 perror("SIOCDELRT"); 213 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 214 syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", 215 xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 216 xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 217 #endif 218 } 219 } 220 221 rtdelete(rt) 222 struct rt_entry *rt; 223 { 224 225 struct sockaddr *sa = &(rt->rt_rt.rt_gateway); 226 FIXLEN(sa); 227 #undef rt_dst 228 sa = &(rt->rt_rt.rt_dst); 229 FIXLEN(sa); 230 if (rt->rt_state & RTS_INTERFACE) { 231 syslog(LOG_ERR, "deleting route to interface %s (timed out)", 232 rt->rt_ifp->int_name); 233 } 234 TRACE_ACTION(DELETE, rt); 235 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 236 perror("SIOCDELRT"); 237 remque(rt); 238 free((char *)rt); 239 } 240 241 rtinit() 242 { 243 register struct rthash *rh; 244 245 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 246 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 247 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 248 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 249 } 250