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