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