|
|
1.1 root 1: /*
2: * Copyright (c) 1983, 1988 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 this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)tables.c 5.13 (Berkeley) 6/6/88";
15: #endif /* not lint */
16:
17: /*
18: * Routing Table Management Daemon
19: */
20: #include "defs.h"
21: #include <sys/ioctl.h>
22: #include <errno.h>
23: #include <sys/syslog.h>
24:
25: #ifndef DEBUG
26: #define DEBUG 0
27: #endif
28:
29: int install = !DEBUG; /* if 1 call kernel */
30:
31: /*
32: * Lookup dst in the tables for an exact match.
33: */
34: struct rt_entry *
35: rtlookup(dst)
36: struct sockaddr *dst;
37: {
38: register struct rt_entry *rt;
39: register struct rthash *rh;
40: register u_int hash;
41: struct afhash h;
42: int doinghost = 1;
43:
44: if (dst->sa_family >= af_max)
45: return (0);
46: (*afswitch[dst->sa_family].af_hash)(dst, &h);
47: hash = h.afh_hosthash;
48: rh = &hosthash[hash & ROUTEHASHMASK];
49: again:
50: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
51: if (rt->rt_hash != hash)
52: continue;
53: if (equal(&rt->rt_dst, dst))
54: return (rt);
55: }
56: if (doinghost) {
57: doinghost = 0;
58: hash = h.afh_nethash;
59: rh = &nethash[hash & ROUTEHASHMASK];
60: goto again;
61: }
62: return (0);
63: }
64:
65: struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
66:
67: /*
68: * Find a route to dst as the kernel would.
69: */
70: struct rt_entry *
71: rtfind(dst)
72: struct sockaddr *dst;
73: {
74: register struct rt_entry *rt;
75: register struct rthash *rh;
76: register u_int hash;
77: struct afhash h;
78: int af = dst->sa_family;
79: int doinghost = 1, (*match)();
80:
81: if (af >= af_max)
82: return (0);
83: (*afswitch[af].af_hash)(dst, &h);
84: hash = h.afh_hosthash;
85: rh = &hosthash[hash & ROUTEHASHMASK];
86:
87: again:
88: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
89: if (rt->rt_hash != hash)
90: continue;
91: if (doinghost) {
92: if (equal(&rt->rt_dst, dst))
93: return (rt);
94: } else {
95: if (rt->rt_dst.sa_family == af &&
96: (*match)(&rt->rt_dst, dst))
97: return (rt);
98: }
99: }
100: if (doinghost) {
101: doinghost = 0;
102: hash = h.afh_nethash;
103: rh = &nethash[hash & ROUTEHASHMASK];
104: match = afswitch[af].af_netmatch;
105: goto again;
106: }
107: #ifdef notyet
108: /*
109: * Check for wildcard gateway, by convention network 0.
110: */
111: if (dst != &wildcard) {
112: dst = &wildcard, hash = 0;
113: goto again;
114: }
115: #endif
116: return (0);
117: }
118:
119: rtadd(dst, gate, metric, state)
120: struct sockaddr *dst, *gate;
121: int metric, state;
122: {
123: struct afhash h;
124: register struct rt_entry *rt;
125: struct rthash *rh;
126: int af = dst->sa_family, flags;
127: u_int hash;
128:
129: if (af >= af_max)
130: return;
131: (*afswitch[af].af_hash)(dst, &h);
132: flags = (*afswitch[af].af_rtflags)(dst);
133: /*
134: * Subnet flag isn't visible to kernel, move to state. XXX
135: */
136: if (flags & RTF_SUBNET) {
137: state |= RTS_SUBNET;
138: flags &= ~RTF_SUBNET;
139: }
140: if (flags & RTF_HOST) {
141: hash = h.afh_hosthash;
142: rh = &hosthash[hash & ROUTEHASHMASK];
143: } else {
144: hash = h.afh_nethash;
145: rh = &nethash[hash & ROUTEHASHMASK];
146: }
147: rt = (struct rt_entry *)malloc(sizeof (*rt));
148: if (rt == 0)
149: return;
150: rt->rt_hash = hash;
151: rt->rt_dst = *dst;
152: rt->rt_router = *gate;
153: rt->rt_timer = 0;
154: rt->rt_flags = RTF_UP | flags;
155: rt->rt_state = state | RTS_CHANGED;
156: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
157: if (rt->rt_ifp == 0)
158: rt->rt_ifp = if_ifwithnet(&rt->rt_router);
159: if ((state & RTS_INTERFACE) == 0)
160: rt->rt_flags |= RTF_GATEWAY;
161: rt->rt_metric = metric;
162: insque(rt, rh);
163: TRACE_ACTION("ADD", rt);
164: /*
165: * If the ioctl fails because the gateway is unreachable
166: * from this host, discard the entry. This should only
167: * occur because of an incorrect entry in /etc/gateways.
168: */
169: if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
170: ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
171: if (errno != EEXIST && gate->sa_family < af_max)
172: syslog(LOG_ERR,
173: "adding route to net/host %s through gateway %s: %m\n",
174: (*afswitch[dst->sa_family].af_format)(dst),
175: (*afswitch[gate->sa_family].af_format)(gate));
176: perror("SIOCADDRT");
177: if (errno == ENETUNREACH) {
178: TRACE_ACTION("DELETE", rt);
179: remque(rt);
180: free((char *)rt);
181: }
182: }
183: }
184:
185: rtchange(rt, gate, metric)
186: struct rt_entry *rt;
187: struct sockaddr *gate;
188: short metric;
189: {
190: int add = 0, delete = 0;
191: struct rtentry oldroute;
192:
193: if ((rt->rt_state & RTS_INTERNAL) == 0) {
194: /*
195: * If changing to different router, we need to add
196: * new route and delete old one if in the kernel.
197: * If the router is the same, we need to delete
198: * the route if has become unreachable, or re-add
199: * it if it had been unreachable.
200: */
201: if (!equal(&rt->rt_router, gate)) {
202: add++;
203: if (rt->rt_metric != HOPCNT_INFINITY)
204: delete++;
205: } else if (metric == HOPCNT_INFINITY)
206: delete++;
207: else if (rt->rt_metric == HOPCNT_INFINITY)
208: add++;
209: }
210: if (!equal(&rt->rt_router, gate)) {
211: TRACE_ACTION("CHANGE FROM ", rt);
212: } else if (metric != rt->rt_metric)
213: TRACE_NEWMETRIC(rt, metric);
214: if (delete)
215: oldroute = rt->rt_rt;
216: if ((rt->rt_state & RTS_INTERFACE) && delete) {
217: rt->rt_state &= ~RTS_INTERFACE;
218: rt->rt_flags |= RTF_GATEWAY;
219: if (metric > rt->rt_metric && delete)
220: syslog(LOG_ERR, "%s route to interface %s (timed out)",
221: add? "changing" : "deleting",
222: rt->rt_ifp->int_name);
223: }
224: if (add) {
225: rt->rt_router = *gate;
226: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
227: if (rt->rt_ifp == 0)
228: rt->rt_ifp = if_ifwithnet(&rt->rt_router);
229: }
230: rt->rt_metric = metric;
231: rt->rt_state |= RTS_CHANGED;
232: if (add)
233: TRACE_ACTION("CHANGE TO ", rt);
234: if (add && install)
235: if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
236: perror("SIOCADDRT");
237: if (delete && install)
238: if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
239: perror("SIOCDELRT");
240: }
241:
242: rtdelete(rt)
243: struct rt_entry *rt;
244: {
245:
246: TRACE_ACTION("DELETE", rt);
247: if (rt->rt_metric < HOPCNT_INFINITY) {
248: if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
249: syslog(LOG_ERR,
250: "deleting route to interface %s? (timed out?)",
251: rt->rt_ifp->int_name);
252: if (install &&
253: (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
254: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
255: perror("SIOCDELRT");
256: }
257: remque(rt);
258: free((char *)rt);
259: }
260:
261: rtdeleteall(s)
262: int s;
263: {
264: register struct rthash *rh;
265: register struct rt_entry *rt;
266: struct rthash *base = hosthash;
267: int doinghost = 1;
268:
269: again:
270: for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
271: rt = rh->rt_forw;
272: for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
273: if (rt->rt_state & RTS_INTERFACE ||
274: rt->rt_metric >= HOPCNT_INFINITY)
275: continue;
276: TRACE_ACTION("DELETE", rt);
277: if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
278: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
279: perror("SIOCDELRT");
280: }
281: }
282: if (doinghost) {
283: doinghost = 0;
284: base = nethash;
285: goto again;
286: }
287: exit(s);
288: }
289:
290: /*
291: * If we have an interface to the wide, wide world,
292: * add an entry for an Internet default route (wildcard) to the internal
293: * tables and advertise it. This route is not added to the kernel routes,
294: * but this entry prevents us from listening to other people's defaults
295: * and installing them in the kernel here.
296: */
297: rtdefault()
298: {
299: extern struct sockaddr inet_default;
300:
301: rtadd(&inet_default, &inet_default, 1,
302: RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
303: }
304:
305: rtinit()
306: {
307: register struct rthash *rh;
308:
309: for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
310: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
311: for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
312: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
313: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.