111820Sjulian/* 211820Sjulian * Copyright (c) 1985, 1993 311820Sjulian * The Regents of the University of California. All rights reserved. 411820Sjulian * 511820Sjulian * Copyright (c) 1995 John Hay. All rights reserved. 611820Sjulian * 711820Sjulian * Redistribution and use in source and binary forms, with or without 811820Sjulian * modification, are permitted provided that the following conditions 911820Sjulian * are met: 1011820Sjulian * 1. Redistributions of source code must retain the above copyright 1111820Sjulian * notice, this list of conditions and the following disclaimer. 1211820Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1311820Sjulian * notice, this list of conditions and the following disclaimer in the 1411820Sjulian * documentation and/or other materials provided with the distribution. 1511820Sjulian * 3. All advertising materials mentioning features or use of this software 1611820Sjulian * must display the following acknowledgement: 1711820Sjulian * This product includes software developed by the University of 1811820Sjulian * California, Berkeley and its contributors. 1911820Sjulian * 4. Neither the name of the University nor the names of its contributors 2011820Sjulian * may be used to endorse or promote products derived from this software 2111820Sjulian * without specific prior written permission. 2211820Sjulian * 2311820Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2411820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2511820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2611820Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2711820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2811820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2911820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3011820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3111820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3211820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3311820Sjulian * SUCH DAMAGE. 3411820Sjulian * 3550479Speter * $FreeBSD$ 3611820Sjulian */ 3711820Sjulian 3811820Sjulian#ifndef lint 39122760Strhodesstatic const char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; 4011820Sjulian#endif /* not lint */ 4111820Sjulian 4211820Sjulian/* 4311820Sjulian * Routing Table Management Daemon 4411820Sjulian */ 4511820Sjulian#include "defs.h" 4611820Sjulian#include <sys/ioctl.h> 4711820Sjulian#include <errno.h> 48122760Strhodes#include <search.h> 4911820Sjulian#include <stdlib.h> 5011820Sjulian#include <unistd.h> 5111820Sjulian 5211820Sjulian#ifndef DEBUG 5311820Sjulian#define DEBUG 0 5411820Sjulian#endif 5511820Sjulian 5611820Sjulian#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} 5711820Sjulian 5811820Sjulianint install = !DEBUG; /* if 1 call kernel */ 5911820Sjulianint delete = 1; 6015248Sjhay 6115248Sjhaystruct rthash nethash[ROUTEHASHSIZ]; 6215248Sjhay 6311820Sjulian/* 6411820Sjulian * Lookup dst in the tables for an exact match. 6511820Sjulian */ 6611820Sjulianstruct rt_entry * 67189369Sedrtlookup(struct sockaddr *dst) 6811820Sjulian{ 6911820Sjulian register struct rt_entry *rt; 7011820Sjulian register struct rthash *rh; 7111820Sjulian register u_int hash; 7211820Sjulian struct afhash h; 7311820Sjulian 7411820Sjulian if (dst->sa_family >= AF_MAX) 7511820Sjulian return (0); 7611820Sjulian (*afswitch[dst->sa_family].af_hash)(dst, &h); 7727244Sjhay hash = h.afh_nethash; 7827244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 7911820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 8011820Sjulian if (rt->rt_hash != hash) 8111820Sjulian continue; 8211820Sjulian if (equal(&rt->rt_dst, dst)) 8311820Sjulian return (rt); 8411820Sjulian } 8511820Sjulian return (0); 8611820Sjulian} 8711820Sjulian 8811820Sjulian/* 8911820Sjulian * Find a route to dst as the kernel would. 9011820Sjulian */ 9111820Sjulianstruct rt_entry * 92189369Sedrtfind(struct sockaddr *dst) 9311820Sjulian{ 9411820Sjulian register struct rt_entry *rt; 9511820Sjulian register struct rthash *rh; 9611820Sjulian register u_int hash; 9711820Sjulian struct afhash h; 9811820Sjulian int af = dst->sa_family; 9927244Sjhay int (*match)() = 0; 10011820Sjulian 10111820Sjulian if (af >= AF_MAX) 10211820Sjulian return (0); 10311820Sjulian (*afswitch[af].af_hash)(dst, &h); 10411820Sjulian 10527244Sjhay hash = h.afh_nethash; 10627244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 10727244Sjhay match = afswitch[af].af_netmatch; 10811820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 10911820Sjulian if (rt->rt_hash != hash) 11011820Sjulian continue; 11127244Sjhay if (rt->rt_dst.sa_family == af && 11227244Sjhay (*match)(&rt->rt_dst, dst)) 11327244Sjhay return (rt); 11411820Sjulian } 11511820Sjulian return (0); 11611820Sjulian} 11711820Sjulian 11811820Sjulianvoid 119189369Sedrtadd(struct sockaddr *dst, struct sockaddr *gate, short metric, 120189369Sed short ticks, int state) 12111820Sjulian{ 12211820Sjulian struct afhash h; 12311820Sjulian register struct rt_entry *rt; 12411820Sjulian struct rthash *rh; 12511820Sjulian int af = dst->sa_family, flags; 12611820Sjulian u_int hash; 12711820Sjulian 12811820Sjulian FIXLEN(dst); 12911820Sjulian FIXLEN(gate); 13011820Sjulian if (af >= AF_MAX) 13111820Sjulian return; 13211820Sjulian (*afswitch[af].af_hash)(dst, &h); 13311820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 13427244Sjhay hash = h.afh_nethash; 13527244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 13611820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 13711820Sjulian if (rt == 0) 13811820Sjulian return; 13911820Sjulian rt->rt_hash = hash; 14011820Sjulian rt->rt_dst = *dst; 14111820Sjulian rt->rt_router = *gate; 14211820Sjulian rt->rt_metric = metric; 14311820Sjulian rt->rt_ticks = ticks; 14411820Sjulian rt->rt_timer = 0; 14511820Sjulian rt->rt_flags = RTF_UP | flags; 14611820Sjulian rt->rt_state = state | RTS_CHANGED; 14711820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 14811820Sjulian rt->rt_clone = NULL; 14911820Sjulian if (metric) 15011820Sjulian rt->rt_flags |= RTF_GATEWAY; 15111820Sjulian insque(rt, rh); 15227244Sjhay TRACE_ACTION("ADD", rt); 15311820Sjulian /* 15411820Sjulian * If the ioctl fails because the gateway is unreachable 15511820Sjulian * from this host, discard the entry. This should only 15611820Sjulian * occur because of an incorrect entry in /etc/gateways. 15711820Sjulian */ 15811820Sjulian if (install && rtioctl(ADD, &rt->rt_rt) < 0) { 15911820Sjulian if (errno != EEXIST) 16011820Sjulian perror("SIOCADDRT"); 16111820Sjulian if (errno == ENETUNREACH) { 16227244Sjhay TRACE_ACTION("DELETE", rt); 16311820Sjulian remque(rt); 16411820Sjulian free((char *)rt); 16511820Sjulian } 16611820Sjulian } 16711820Sjulian} 16811820Sjulian 16911820Sjulianvoid 170189369Sedrtadd_clone(struct rt_entry *ort, struct sockaddr *dst, 171189369Sed struct sockaddr *gate, short metric, short ticks, int state) 17211820Sjulian{ 17311820Sjulian struct afhash h; 17411820Sjulian register struct rt_entry *rt; 17511820Sjulian int af = dst->sa_family, flags; 17611820Sjulian u_int hash; 17711820Sjulian 17811820Sjulian FIXLEN(dst); 17911820Sjulian FIXLEN(gate); 18011820Sjulian if (af >= AF_MAX) 18111820Sjulian return; 18211820Sjulian (*afswitch[af].af_hash)(dst, &h); 18311820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 18427244Sjhay hash = h.afh_nethash; 18511820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 18611820Sjulian if (rt == 0) 18711820Sjulian return; 18811820Sjulian rt->rt_hash = hash; 18911820Sjulian rt->rt_dst = *dst; 19011820Sjulian rt->rt_router = *gate; 19111820Sjulian rt->rt_metric = metric; 19211820Sjulian rt->rt_ticks = ticks; 19311820Sjulian rt->rt_timer = 0; 19411820Sjulian rt->rt_flags = RTF_UP | flags; 19511820Sjulian rt->rt_state = state | RTS_CHANGED; 19611820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 19711820Sjulian rt->rt_clone = NULL; 19811820Sjulian rt->rt_forw = NULL; 19911820Sjulian rt->rt_back = NULL; 20011820Sjulian if (metric) 20111820Sjulian rt->rt_flags |= RTF_GATEWAY; 20211820Sjulian 20311820Sjulian while(ort->rt_clone != NULL) 20411820Sjulian ort = ort->rt_clone; 20511820Sjulian ort->rt_clone = rt; 20627244Sjhay TRACE_ACTION("ADD_CLONE", rt); 20711820Sjulian} 20811820Sjulian 20911820Sjulianvoid 210189369Sedrtchange(struct rt_entry *rt, struct sockaddr *gate, short metric, 211189369Sed short ticks) 21211820Sjulian{ 21311820Sjulian int doioctl = 0, metricchanged = 0; 21411820Sjulian 21511820Sjulian FIXLEN(gate); 21611820Sjulian /* 21711820Sjulian * Handling of clones. 21811820Sjulian * When the route changed and it had clones, handle it special. 21911820Sjulian * 1. If the new route is cheaper than the clone(s), free the clones. 22011820Sjulian * 2. If the new route is the same cost, it may be one of the clones, 22111820Sjulian * search for it and free it. 22211820Sjulian * 3. If the new route is more expensive than the clone(s), use the 22311820Sjulian * values of the clone(s). 22411820Sjulian */ 22511820Sjulian if (rt->rt_clone) { 22611820Sjulian if ((ticks < rt->rt_clone->rt_ticks) || 22711820Sjulian ((ticks == rt->rt_clone->rt_ticks) && 22811820Sjulian (metric < rt->rt_clone->rt_metric))) { 22911820Sjulian /* 23011820Sjulian * Free all clones. 23111820Sjulian */ 23211820Sjulian struct rt_entry *trt, *nrt; 23311820Sjulian 23411820Sjulian trt = rt->rt_clone; 23511820Sjulian rt->rt_clone = NULL; 23611820Sjulian while(trt) { 23711820Sjulian nrt = trt->rt_clone; 23811820Sjulian free((char *)trt); 23911820Sjulian trt = nrt; 24011820Sjulian } 24111820Sjulian } else if ((ticks == rt->rt_clone->rt_ticks) && 24211820Sjulian (metric == rt->rt_clone->rt_metric)) { 24311820Sjulian struct rt_entry *prt, *trt; 24411820Sjulian 24511820Sjulian prt = rt; 24611820Sjulian trt = rt->rt_clone; 24711820Sjulian 24811820Sjulian while(trt) { 24911820Sjulian if (equal(&trt->rt_router, gate)) { 25011820Sjulian prt->rt_clone = trt->rt_clone; 25111820Sjulian free(trt); 25211820Sjulian trt = prt->rt_clone; 25311820Sjulian } else { 25411820Sjulian prt = trt; 25511820Sjulian trt = trt->rt_clone; 25611820Sjulian } 25711820Sjulian } 25811820Sjulian } else { 25911820Sjulian /* 26011820Sjulian * Use the values of the first clone. 26111820Sjulian * Delete the corresponding clone. 26211820Sjulian */ 26311820Sjulian struct rt_entry *trt; 26411820Sjulian 26511820Sjulian trt = rt->rt_clone; 26611820Sjulian rt->rt_clone = rt->rt_clone->rt_clone; 26711820Sjulian metric = trt->rt_metric; 26811820Sjulian ticks = trt->rt_ticks; 26911820Sjulian *gate = trt->rt_router; 27011820Sjulian free((char *)trt); 27111820Sjulian } 27211820Sjulian } 27311820Sjulian 27411820Sjulian if (!equal(&rt->rt_router, gate)) 27511820Sjulian doioctl++; 27611820Sjulian if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks)) 27711820Sjulian metricchanged++; 27811820Sjulian if (doioctl || metricchanged) { 27927244Sjhay TRACE_ACTION("CHANGE FROM", rt); 28011820Sjulian if (doioctl) { 28111820Sjulian rt->rt_router = *gate; 28211820Sjulian } 28311820Sjulian rt->rt_metric = metric; 28411820Sjulian rt->rt_ticks = ticks; 28511820Sjulian if ((rt->rt_state & RTS_INTERFACE) && metric) { 28611820Sjulian rt->rt_state &= ~RTS_INTERFACE; 28711820Sjulian if(rt->rt_ifp) 28811820Sjulian syslog(LOG_ERR, 28911820Sjulian "changing route from interface %s (timed out)", 29011820Sjulian rt->rt_ifp->int_name); 29111820Sjulian else 29211820Sjulian syslog(LOG_ERR, 29311820Sjulian "changing route from interface ??? (timed out)"); 29411820Sjulian } 29511820Sjulian if (metric) 29611820Sjulian rt->rt_flags |= RTF_GATEWAY; 29711820Sjulian else 29811820Sjulian rt->rt_flags &= ~RTF_GATEWAY; 29927244Sjhay rt->rt_ifp = if_ifwithnet(&rt->rt_router); 30011820Sjulian rt->rt_state |= RTS_CHANGED; 30127244Sjhay TRACE_ACTION("CHANGE TO", rt); 30211820Sjulian } 30311820Sjulian if (doioctl && install) { 30411820Sjulian#ifndef RTM_ADD 30511820Sjulian if (rtioctl(ADD, &rt->rt_rt) < 0) 30611820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 30727244Sjhay ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 30827244Sjhay ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 30911820Sjulian if (delete && rtioctl(DELETE, &oldroute) < 0) 31011820Sjulian perror("rtioctl DELETE"); 31111820Sjulian#else 31211820Sjulian if (delete == 0) { 31311820Sjulian if (rtioctl(ADD, &rt->rt_rt) >= 0) 31411820Sjulian return; 31511820Sjulian } else { 31611820Sjulian if (rtioctl(CHANGE, &rt->rt_rt) >= 0) 31711820Sjulian return; 31811820Sjulian } 31911820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 32011820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 32111820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 32211820Sjulian#endif 32311820Sjulian } 32411820Sjulian} 32511820Sjulian 32611820Sjulianvoid 327189369Sedrtdelete(struct rt_entry *rt) 32811820Sjulian{ 32911820Sjulian 33011820Sjulian struct sockaddr *sa = &(rt->rt_router); 33111820Sjulian FIXLEN(sa); 33211820Sjulian sa = &(rt->rt_dst); 33311820Sjulian FIXLEN(sa); 33411820Sjulian if (rt->rt_clone) { 33511820Sjulian /* 33611820Sjulian * If there is a clone we just do a rt_change to it. 33711820Sjulian */ 33811820Sjulian struct rt_entry *trt = rt->rt_clone; 33911820Sjulian rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks); 34011820Sjulian return; 34111820Sjulian } 34211820Sjulian if (rt->rt_state & RTS_INTERFACE) { 34311820Sjulian if (rt->rt_ifp) 34411820Sjulian syslog(LOG_ERR, 34511820Sjulian "deleting route to interface %s (timed out)", 34611820Sjulian rt->rt_ifp->int_name); 34711820Sjulian else 34811820Sjulian syslog(LOG_ERR, 34911820Sjulian "deleting route to interface ??? (timed out)"); 35011820Sjulian } 35127244Sjhay TRACE_ACTION("DELETE", rt); 35211820Sjulian if (install && rtioctl(DELETE, &rt->rt_rt) < 0) 35311820Sjulian perror("rtioctl DELETE"); 35411820Sjulian remque(rt); 35511820Sjulian free((char *)rt); 35611820Sjulian} 35711820Sjulian 35811820Sjulianvoid 35911820Sjulianrtinit(void) 36011820Sjulian{ 36111820Sjulian register struct rthash *rh; 36211820Sjulian 36311820Sjulian for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 36411820Sjulian rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 36511820Sjulian} 36611820Sjulianint seqno; 36711820Sjulian 36811820Sjulianint 369189369Sedrtioctl(int action, struct rtuentry *ort) 37011820Sjulian{ 37111820Sjulian#ifndef RTM_ADD 37211820Sjulian if (install == 0) 37311820Sjulian return (errno = 0); 37411820Sjulian 37511820Sjulian ort->rtu_rtflags = ort->rtu_flags; 37611820Sjulian 37711820Sjulian switch (action) { 37811820Sjulian 37911820Sjulian case ADD: 38011820Sjulian return (ioctl(s, SIOCADDRT, (char *)ort)); 38111820Sjulian 38211820Sjulian case DELETE: 38311820Sjulian return (ioctl(s, SIOCDELRT, (char *)ort)); 38411820Sjulian 38511820Sjulian default: 38611820Sjulian return (-1); 38711820Sjulian } 38811820Sjulian#else /* RTM_ADD */ 38911820Sjulian struct { 39011820Sjulian struct rt_msghdr w_rtm; 39111820Sjulian struct sockaddr w_dst; 39211820Sjulian struct sockaddr w_gate; 39311820Sjulian struct sockaddr_ipx w_netmask; 39411820Sjulian } w; 39511820Sjulian#define rtm w.w_rtm 39611820Sjulian 39711820Sjulian bzero((char *)&w, sizeof(w)); 39811820Sjulian rtm.rtm_msglen = sizeof(w); 39911820Sjulian rtm.rtm_version = RTM_VERSION; 40011820Sjulian rtm.rtm_type = (action == ADD ? RTM_ADD : 40111820Sjulian (action == DELETE ? RTM_DELETE : RTM_CHANGE)); 40211820Sjulian rtm.rtm_flags = ort->rtu_flags; 40311820Sjulian rtm.rtm_seq = ++seqno; 40411820Sjulian rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 40511820Sjulian bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst)); 40611820Sjulian bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate)); 40711820Sjulian w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX; 40811820Sjulian w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); 40911820Sjulian if (rtm.rtm_flags & RTF_HOST) { 41011820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask); 41111820Sjulian } else { 41211820Sjulian rtm.rtm_addrs |= RTA_NETMASK; 41311820Sjulian w.w_netmask = ipx_netmask; 41411820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len; 41511820Sjulian } 41611820Sjulian errno = 0; 41711820Sjulian return write(r, (char *)&w, rtm.rtm_msglen); 41811820Sjulian#endif /* RTM_ADD */ 41911820Sjulian} 420