Commit | Line | Data |
---|---|---|
5ff67f98 DF |
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 | ||
b9b7b06a | 7 | #ifndef lint |
17fe297f | 8 | static char sccsid[] = "@(#)tables.c 5.2 (Berkeley) %G%"; |
5ff67f98 | 9 | #endif not lint |
b9b7b06a SL |
10 | |
11 | /* | |
12 | * Routing Table Management Daemon | |
13 | */ | |
7fe7fe74 | 14 | #include "defs.h" |
b9b7b06a SL |
15 | #include <sys/ioctl.h> |
16 | #include <errno.h> | |
69b7ef61 | 17 | #include <syslog.h> |
b9b7b06a SL |
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; | |
d5568f13 | 34 | register u_int hash; |
b9b7b06a SL |
35 | struct afhash h; |
36 | int doinghost = 1; | |
37 | ||
17fe297f | 38 | if (dst->sa_family >= af_max) |
b9b7b06a SL |
39 | return (0); |
40 | (*afswitch[dst->sa_family].af_hash)(dst, &h); | |
41 | hash = h.afh_hosthash; | |
49139b80 | 42 | rh = &hosthash[hash & ROUTEHASHMASK]; |
b9b7b06a SL |
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; | |
49139b80 | 53 | rh = &nethash[hash & ROUTEHASHMASK]; |
b9b7b06a SL |
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; | |
d5568f13 | 68 | register u_int hash; |
b9b7b06a SL |
69 | struct afhash h; |
70 | int af = dst->sa_family; | |
71 | int doinghost = 1, (*match)(); | |
72 | ||
17fe297f | 73 | if (af >= af_max) |
b9b7b06a SL |
74 | return (0); |
75 | (*afswitch[af].af_hash)(dst, &h); | |
76 | hash = h.afh_hosthash; | |
49139b80 | 77 | rh = &hosthash[hash & ROUTEHASHMASK]; |
b9b7b06a SL |
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; | |
49139b80 | 95 | rh = &nethash[hash & ROUTEHASHMASK]; |
b9b7b06a SL |
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; | |
d5568f13 MK |
109 | int af = dst->sa_family, flags; |
110 | u_int hash; | |
b9b7b06a | 111 | |
17fe297f | 112 | if (af >= af_max) |
b9b7b06a SL |
113 | return; |
114 | (*afswitch[af].af_hash)(dst, &h); | |
d5568f13 | 115 | flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; |
b9b7b06a SL |
116 | if (flags & RTF_HOST) { |
117 | hash = h.afh_hosthash; | |
49139b80 | 118 | rh = &hosthash[hash & ROUTEHASHMASK]; |
b9b7b06a SL |
119 | } else { |
120 | hash = h.afh_nethash; | |
49139b80 | 121 | rh = &nethash[hash & ROUTEHASHMASK]; |
b9b7b06a SL |
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); | |
a8d9e287 SL |
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) { | |
b9b7b06a | 144 | perror("SIOCADDRT"); |
a8d9e287 SL |
145 | if (errno == ENETUNREACH) { |
146 | TRACE_ACTION(DELETE, rt); | |
147 | remque(rt); | |
148 | free((char *)rt); | |
149 | } | |
150 | } | |
b9b7b06a SL |
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++; | |
b7e4f8be | 163 | if (metric != rt->rt_metric) |
b9b7b06a | 164 | metricchanged++; |
b9b7b06a | 165 | if (doioctl || metricchanged) { |
b7e4f8be MK |
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; | |
69b7ef61 MK |
172 | if ((rt->rt_state & RTS_INTERFACE) && metric) { |
173 | rt->rt_state &= ~RTS_INTERFACE; | |
174 | syslog(LOG_ERR, | |
78c998d3 | 175 | "changing route from interface %s (timed out)", |
69b7ef61 MK |
176 | rt->rt_ifp->int_name); |
177 | } | |
b7e4f8be | 178 | if (metric) |
78c998d3 MK |
179 | rt->rt_flags |= RTF_GATEWAY; |
180 | else | |
181 | rt->rt_flags &= ~RTF_GATEWAY; | |
b9b7b06a | 182 | rt->rt_state |= RTS_CHANGED; |
b7e4f8be | 183 | TRACE_ACTION(CHANGE TO, rt); |
b9b7b06a | 184 | } |
b7e4f8be MK |
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"); | |
b9b7b06a SL |
190 | } |
191 | } | |
192 | ||
193 | rtdelete(rt) | |
194 | struct rt_entry *rt; | |
195 | { | |
a8d9e287 | 196 | |
69b7ef61 MK |
197 | if (rt->rt_state & RTS_INTERFACE) |
198 | syslog(LOG_ERR, "deleting route to interface %s (timed out)", | |
199 | rt->rt_ifp->int_name); | |
b9b7b06a SL |
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 | ||
ad34083f MK |
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; | |
ad34083f MK |
224 | rt->rt_dst = inet_default; |
225 | rt->rt_router = rt->rt_dst; | |
226 | (*afswitch[AF_INET].af_hash)(&rt->rt_dst, &h); | |
49139b80 | 227 | rh = &nethash[h.afh_nethash & ROUTEHASHMASK]; |
8aa8bd6a | 228 | rt->rt_hash = h.afh_nethash; |
ad34083f MK |
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 | ||
b9b7b06a SL |
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 | } |