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