]> git.saurik.com Git - apple/network_cmds.git/blame - routed.tproj/tables.c
network_cmds-307.1.1.tar.gz
[apple/network_cmds.git] / routed.tproj / tables.c
CommitLineData
b7080c8e
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
a2c93a76
A
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
b7080c8e
A
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
a2c93a76
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
b7080c8e
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright (c) 1983, 1988, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgment:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 *
56 * @(#)defs.h 8.1 (Berkeley) 6/5/93
57 */
58
59
60/*
61 * Routing Table Management Daemon
62 */
63#include "defs.h"
64#include <sys/ioctl.h>
65#include <errno.h>
b8dff150 66#include <search.h>
b7080c8e
A
67#include <sys/syslog.h>
68
69#ifndef DEBUG
70#define DEBUG 0
71#endif
72
73#ifdef RTM_ADD
74#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
75#else
76#define FIXLEN(s) { }
77#endif
78
79int install = !DEBUG; /* if 1 call kernel */
80
81/*
82 * Lookup dst in the tables for an exact match.
83 */
84struct rt_entry *
85rtlookup(dst)
86 struct sockaddr *dst;
87{
88 register struct rt_entry *rt;
89 register struct rthash *rh;
90 register u_int hash;
91 struct afhash h;
92 int doinghost = 1;
93
94 if (dst->sa_family >= af_max)
95 return (0);
96 (*afswitch[dst->sa_family].af_hash)(dst, &h);
97 hash = h.afh_hosthash;
98 rh = &hosthash[hash & ROUTEHASHMASK];
99again:
100 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
101 if (rt->rt_hash != hash)
102 continue;
103 if (equal(&rt->rt_dst, dst))
104 return (rt);
105 }
106 if (doinghost) {
107 doinghost = 0;
108 hash = h.afh_nethash;
109 rh = &nethash[hash & ROUTEHASHMASK];
110 goto again;
111 }
112 return (0);
113}
114
115struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
116
117/*
118 * Find a route to dst as the kernel would.
119 */
120struct rt_entry *
121rtfind(dst)
122 struct sockaddr *dst;
123{
124 register struct rt_entry *rt;
125 register struct rthash *rh;
126 register u_int hash;
127 struct afhash h;
128 int af = dst->sa_family;
b8dff150 129 int doinghost = 1, (*match)() = NULL;
b7080c8e
A
130
131 if (af >= af_max)
132 return (0);
133 (*afswitch[af].af_hash)(dst, &h);
134 hash = h.afh_hosthash;
135 rh = &hosthash[hash & ROUTEHASHMASK];
136
137again:
138 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
139 if (rt->rt_hash != hash)
140 continue;
141 if (doinghost) {
142 if (equal(&rt->rt_dst, dst))
143 return (rt);
144 } else {
145 if (rt->rt_dst.sa_family == af &&
146 (*match)(&rt->rt_dst, dst))
147 return (rt);
148 }
149 }
150 if (doinghost) {
151 doinghost = 0;
152 hash = h.afh_nethash;
153 rh = &nethash[hash & ROUTEHASHMASK];
154 match = afswitch[af].af_netmatch;
155 goto again;
156 }
157#ifdef notyet
158 /*
159 * Check for wildcard gateway, by convention network 0.
160 */
161 if (dst != &wildcard) {
162 dst = &wildcard, hash = 0;
163 goto again;
164 }
165#endif
166 return (0);
167}
168
b8dff150 169void
b7080c8e
A
170rtadd(dst, gate, metric, state)
171 struct sockaddr *dst, *gate;
172 int metric, state;
173{
174 struct afhash h;
175 register struct rt_entry *rt;
176 struct rthash *rh;
177 int af = dst->sa_family, flags;
178 u_int hash;
179
180 if (af >= af_max)
181 return;
182 (*afswitch[af].af_hash)(dst, &h);
183 flags = (*afswitch[af].af_rtflags)(dst);
184 /*
185 * Subnet flag isn't visible to kernel, move to state. XXX
186 */
187 FIXLEN(dst);
188 FIXLEN(gate);
189 if (flags & RTF_SUBNET) {
190 state |= RTS_SUBNET;
191 flags &= ~RTF_SUBNET;
192 }
193 if (flags & RTF_HOST) {
194 hash = h.afh_hosthash;
195 rh = &hosthash[hash & ROUTEHASHMASK];
196 } else {
197 hash = h.afh_nethash;
198 rh = &nethash[hash & ROUTEHASHMASK];
199 }
200 rt = (struct rt_entry *)malloc(sizeof (*rt));
201 if (rt == 0)
202 return;
203 rt->rt_hash = hash;
204 rt->rt_dst = *dst;
205 rt->rt_router = *gate;
206 rt->rt_timer = 0;
207 rt->rt_flags = RTF_UP | flags;
208 rt->rt_state = state | RTS_CHANGED;
209 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
210 if (rt->rt_ifp == 0)
211 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
212 if ((state & RTS_INTERFACE) == 0)
213 rt->rt_flags |= RTF_GATEWAY;
214 rt->rt_metric = metric;
215 insque(rt, rh);
216 TRACE_ACTION("ADD", rt);
217 /*
218 * If the ioctl fails because the gateway is unreachable
219 * from this host, discard the entry. This should only
220 * occur because of an incorrect entry in /etc/gateways.
221 */
222 if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
223 rtioctl(ADD, &rt->rt_rt) < 0) {
224 if (errno != EEXIST && gate->sa_family < af_max)
225 syslog(LOG_ERR,
226 "adding route to net/host %s through gateway %s: %m\n",
227 (*afswitch[dst->sa_family].af_format)(dst),
228 (*afswitch[gate->sa_family].af_format)(gate));
229 perror("ADD ROUTE");
230 if (errno == ENETUNREACH) {
231 TRACE_ACTION("DELETE", rt);
232 remque(rt);
233 free((char *)rt);
234 }
235 }
236}
237
b8dff150 238void
b7080c8e
A
239rtchange(rt, gate, metric)
240 struct rt_entry *rt;
241 struct sockaddr *gate;
242 short metric;
243{
244 int add = 0, delete = 0, newgateway = 0;
245 struct rtuentry oldroute;
246
247 FIXLEN(gate);
248 FIXLEN(&(rt->rt_router));
249 FIXLEN(&(rt->rt_dst));
250 if (!equal(&rt->rt_router, gate)) {
251 newgateway++;
252 TRACE_ACTION("CHANGE FROM ", rt);
253 } else if (metric != rt->rt_metric)
254 TRACE_NEWMETRIC(rt, metric);
255 if ((rt->rt_state & RTS_INTERNAL) == 0) {
256 /*
257 * If changing to different router, we need to add
258 * new route and delete old one if in the kernel.
259 * If the router is the same, we need to delete
260 * the route if has become unreachable, or re-add
261 * it if it had been unreachable.
262 */
263 if (newgateway) {
264 add++;
265 if (rt->rt_metric != HOPCNT_INFINITY)
266 delete++;
267 } else if (metric == HOPCNT_INFINITY)
268 delete++;
269 else if (rt->rt_metric == HOPCNT_INFINITY)
270 add++;
271 }
272 if (delete)
273 oldroute = rt->rt_rt;
274 if ((rt->rt_state & RTS_INTERFACE) && delete) {
275 rt->rt_state &= ~RTS_INTERFACE;
276 rt->rt_flags |= RTF_GATEWAY;
277 if (metric > rt->rt_metric && delete)
278 syslog(LOG_ERR, "%s route to interface %s (timed out)",
279 add? "changing" : "deleting",
280 rt->rt_ifp ? rt->rt_ifp->int_name : "?");
281 }
282 if (add) {
283 rt->rt_router = *gate;
284 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
285 if (rt->rt_ifp == 0)
286 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
287 }
288 rt->rt_metric = metric;
289 rt->rt_state |= RTS_CHANGED;
290 if (newgateway)
291 TRACE_ACTION("CHANGE TO ", rt);
292#ifndef RTM_ADD
293 if (add && rtioctl(ADD, &rt->rt_rt) < 0)
294 perror("ADD ROUTE");
295 if (delete && rtioctl(DELETE, &oldroute) < 0)
296 perror("DELETE ROUTE");
297#else
298 if (delete && !add) {
299 if (rtioctl(DELETE, &oldroute) < 0)
300 perror("DELETE ROUTE");
301 } else if (!delete && add) {
302 if (rtioctl(ADD, &rt->rt_rt) < 0)
303 perror("ADD ROUTE");
304 } else if (delete && add) {
305 if (rtioctl(CHANGE, &rt->rt_rt) < 0)
306 perror("CHANGE ROUTE");
307 }
308#endif
309}
310
b8dff150 311void
b7080c8e
A
312rtdelete(rt)
313 struct rt_entry *rt;
314{
315
316 TRACE_ACTION("DELETE", rt);
317 FIXLEN(&(rt->rt_router));
318 FIXLEN(&(rt->rt_dst));
319 if (rt->rt_metric < HOPCNT_INFINITY) {
320 if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
321 syslog(LOG_ERR,
322 "deleting route to interface %s? (timed out?)",
323 rt->rt_ifp->int_name);
324 if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
325 rtioctl(DELETE, &rt->rt_rt) < 0)
326 perror("rtdelete");
327 }
328 remque(rt);
329 free((char *)rt);
330}
331
b8dff150 332void
b7080c8e
A
333rtdeleteall(sig)
334 int sig;
335{
336 register struct rthash *rh;
337 register struct rt_entry *rt;
338 struct rthash *base = hosthash;
339 int doinghost = 1;
340
341again:
342 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
343 rt = rh->rt_forw;
344 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
345 if (rt->rt_state & RTS_INTERFACE ||
346 rt->rt_metric >= HOPCNT_INFINITY)
347 continue;
348 TRACE_ACTION("DELETE", rt);
349 if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
350 rtioctl(DELETE, &rt->rt_rt) < 0)
351 perror("rtdeleteall");
352 }
353 }
354 if (doinghost) {
355 doinghost = 0;
356 base = nethash;
357 goto again;
358 }
359 exit(sig);
360}
361
362/*
363 * If we have an interface to the wide, wide world,
364 * add an entry for an Internet default route (wildcard) to the internal
365 * tables and advertise it. This route is not added to the kernel routes,
366 * but this entry prevents us from listening to other people's defaults
367 * and installing them in the kernel here.
368 */
b8dff150 369void
b7080c8e
A
370rtdefault()
371{
372 extern struct sockaddr inet_default;
373
374 rtadd(&inet_default, &inet_default, 1,
375 RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
376}
377
b8dff150 378void
b7080c8e
A
379rtinit()
380{
381 register struct rthash *rh;
382
383 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
384 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
385 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
386 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
387}
388
b8dff150 389int
b7080c8e
A
390rtioctl(action, ort)
391 int action;
392 struct rtuentry *ort;
393{
394#ifndef RTM_ADD
395 if (install == 0)
396 return (errno = 0);
397 ort->rtu_rtflags = ort->rtu_flags;
398 switch (action) {
399
400 case ADD:
401 return (ioctl(s, SIOCADDRT, (char *)ort));
402
403 case DELETE:
404 return (ioctl(s, SIOCDELRT, (char *)ort));
405
406 default:
407 return (-1);
408 }
409#else /* RTM_ADD */
410 struct {
411 struct rt_msghdr w_rtm;
412 struct sockaddr_in w_dst;
413 struct sockaddr w_gate;
414 struct sockaddr_in w_netmask;
415 } w;
416#define rtm w.w_rtm
417
418 memset(&w, 0, sizeof(w));
419 rtm.rtm_msglen = sizeof(w);
420 rtm.rtm_version = RTM_VERSION;
421 rtm.rtm_type = (action == ADD ? RTM_ADD :
422 (action == DELETE ? RTM_DELETE : RTM_CHANGE));
423#undef rt_dst
424 rtm.rtm_flags = ort->rtu_flags;
425 rtm.rtm_seq = ++seqno;
426 rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
427 memmove(&w.w_dst, &ort->rtu_dst, sizeof(w.w_dst));
428 memmove(&w.w_gate, &ort->rtu_router, sizeof(w.w_gate));
429 w.w_dst.sin_family = AF_INET;
430 w.w_dst.sin_len = sizeof(w.w_dst);
431 w.w_gate.sa_family = AF_INET;
432 w.w_gate.sa_len = sizeof(w.w_gate);
433 if (rtm.rtm_flags & RTF_HOST) {
434 rtm.rtm_msglen -= sizeof(w.w_netmask);
435 } else {
436 register char *cp;
437 int len;
438
439 rtm.rtm_addrs |= RTA_NETMASK;
440 w.w_netmask.sin_addr.s_addr =
441 inet_maskof(w.w_dst.sin_addr.s_addr);
442 for (cp = (char *)(1 + &w.w_netmask.sin_addr);
443 --cp > (char *) &w.w_netmask; )
444 if (*cp)
445 break;
446 len = cp - (char *)&w.w_netmask;
447 if (len) {
448 len++;
449 w.w_netmask.sin_len = len;
450 len = 1 + ((len - 1) | (sizeof(long) - 1));
451 } else
452 len = sizeof(long);
453 rtm.rtm_msglen -= (sizeof(w.w_netmask) - len);
454 }
455 errno = 0;
456 return (install ? write(r, (char *)&w, rtm.rtm_msglen) : (errno = 0));
457#endif /* RTM_ADD */
458}