124323Ssklower /* 235593Sbostic * Copyright (c) 1985 The Regents of the University of California. 335593Sbostic * All rights reserved. 424323Ssklower * 5*42698Sbostic * %sccs.include.redist.c% 624323Ssklower */ 724323Ssklower 824313Ssklower #ifndef lint 9*42698Sbostic static char sccsid[] = "@(#)tables.c 5.9 (Berkeley) 06/01/90"; 1035593Sbostic #endif /* not lint */ 1124313Ssklower 1224313Ssklower /* 1324313Ssklower * Routing Table Management Daemon 1424313Ssklower */ 1524313Ssklower #include "defs.h" 1624313Ssklower #include <sys/ioctl.h> 1724313Ssklower #include <errno.h> 1824313Ssklower 1924313Ssklower #ifndef DEBUG 2024313Ssklower #define DEBUG 0 2124313Ssklower #endif 2224313Ssklower 2330350Skarels extern char *xns_ntoa(); 2438688Skarels #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} 2530350Skarels 2624313Ssklower int install = !DEBUG; /* if 1 call kernel */ 2724318Ssklower int delete = 1; 2824313Ssklower /* 2924313Ssklower * Lookup dst in the tables for an exact match. 3024313Ssklower */ 3124313Ssklower struct rt_entry * 3224313Ssklower rtlookup(dst) 3324313Ssklower struct sockaddr *dst; 3424313Ssklower { 3524313Ssklower register struct rt_entry *rt; 3624313Ssklower register struct rthash *rh; 3724313Ssklower register u_int hash; 3824313Ssklower struct afhash h; 3924313Ssklower int doinghost = 1; 4024313Ssklower 4124313Ssklower if (dst->sa_family >= AF_MAX) 4224313Ssklower return (0); 4324313Ssklower (*afswitch[dst->sa_family].af_hash)(dst, &h); 4424313Ssklower hash = h.afh_hosthash; 4524313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 4624313Ssklower again: 4724313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4824313Ssklower if (rt->rt_hash != hash) 4924313Ssklower continue; 5024313Ssklower if (equal(&rt->rt_dst, dst)) 5124313Ssklower return (rt); 5224313Ssklower } 5324313Ssklower if (doinghost) { 5424313Ssklower doinghost = 0; 5524313Ssklower hash = h.afh_nethash; 5624313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 5724313Ssklower goto again; 5824313Ssklower } 5924313Ssklower return (0); 6024313Ssklower } 6124313Ssklower 6224313Ssklower /* 6324313Ssklower * Find a route to dst as the kernel would. 6424313Ssklower */ 6524313Ssklower struct rt_entry * 6624313Ssklower rtfind(dst) 6724313Ssklower struct sockaddr *dst; 6824313Ssklower { 6924313Ssklower register struct rt_entry *rt; 7024313Ssklower register struct rthash *rh; 7124313Ssklower register u_int hash; 7224313Ssklower struct afhash h; 7324313Ssklower int af = dst->sa_family; 7424313Ssklower int doinghost = 1, (*match)(); 7524313Ssklower 7624313Ssklower if (af >= AF_MAX) 7724313Ssklower return (0); 7824313Ssklower (*afswitch[af].af_hash)(dst, &h); 7924313Ssklower hash = h.afh_hosthash; 8024313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 8124313Ssklower 8224313Ssklower again: 8324313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 8424313Ssklower if (rt->rt_hash != hash) 8524313Ssklower continue; 8624313Ssklower if (doinghost) { 8724313Ssklower if (equal(&rt->rt_dst, dst)) 8824313Ssklower return (rt); 8924323Ssklower } else { 9024323Ssklower if (rt->rt_dst.sa_family == af && 9124323Ssklower (*match)(&rt->rt_dst, dst)) 9224323Ssklower return (rt); 9324313Ssklower } 9424313Ssklower } 9524313Ssklower if (doinghost) { 9624313Ssklower doinghost = 0; 9724313Ssklower hash = h.afh_nethash; 9824313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 9924313Ssklower match = afswitch[af].af_netmatch; 10024313Ssklower goto again; 10124313Ssklower } 10224313Ssklower return (0); 10324313Ssklower } 10424313Ssklower 10524313Ssklower rtadd(dst, gate, metric, state) 10624313Ssklower struct sockaddr *dst, *gate; 10724313Ssklower int metric, state; 10824313Ssklower { 10924313Ssklower struct afhash h; 11024313Ssklower register struct rt_entry *rt; 11124313Ssklower struct rthash *rh; 11224313Ssklower int af = dst->sa_family, flags; 11324313Ssklower u_int hash; 11424313Ssklower 11538688Skarels FIXLEN(dst); 11638688Skarels FIXLEN(gate); 11724313Ssklower if (af >= AF_MAX) 11824313Ssklower return; 11924313Ssklower (*afswitch[af].af_hash)(dst, &h); 12024313Ssklower flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 12124313Ssklower if (flags & RTF_HOST) { 12224313Ssklower hash = h.afh_hosthash; 12324313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 12424313Ssklower } else { 12524313Ssklower hash = h.afh_nethash; 12624313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 12724313Ssklower } 12824313Ssklower rt = (struct rt_entry *)malloc(sizeof (*rt)); 12924313Ssklower if (rt == 0) 13024313Ssklower return; 13124313Ssklower rt->rt_hash = hash; 13224313Ssklower rt->rt_dst = *dst; 13324313Ssklower rt->rt_router = *gate; 13424313Ssklower rt->rt_metric = metric; 13524313Ssklower rt->rt_timer = 0; 13624313Ssklower rt->rt_flags = RTF_UP | flags; 13724313Ssklower rt->rt_state = state | RTS_CHANGED; 13824313Ssklower rt->rt_ifp = if_ifwithnet(&rt->rt_router); 13924313Ssklower if (metric) 14024313Ssklower rt->rt_flags |= RTF_GATEWAY; 14124313Ssklower insque(rt, rh); 14224313Ssklower TRACE_ACTION(ADD, rt); 14324313Ssklower /* 14424313Ssklower * If the ioctl fails because the gateway is unreachable 14524313Ssklower * from this host, discard the entry. This should only 14624313Ssklower * occur because of an incorrect entry in /etc/gateways. 14724313Ssklower */ 14824313Ssklower if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 14930350Skarels if (errno != EEXIST) 15030350Skarels perror("SIOCADDRT"); 15124313Ssklower if (errno == ENETUNREACH) { 15224313Ssklower TRACE_ACTION(DELETE, rt); 15324313Ssklower remque(rt); 15424313Ssklower free((char *)rt); 15524313Ssklower } 15624313Ssklower } 15724313Ssklower } 15824313Ssklower 15924313Ssklower rtchange(rt, gate, metric) 16024313Ssklower struct rt_entry *rt; 16124313Ssklower struct sockaddr *gate; 16224313Ssklower short metric; 16324313Ssklower { 16424313Ssklower int doioctl = 0, metricchanged = 0; 16524313Ssklower struct rtentry oldroute; 16624313Ssklower 16738688Skarels FIXLEN(gate); 16824313Ssklower if (!equal(&rt->rt_router, gate)) 16924313Ssklower doioctl++; 17024313Ssklower if (metric != rt->rt_metric) 17124313Ssklower metricchanged++; 17224313Ssklower if (doioctl || metricchanged) { 17324313Ssklower TRACE_ACTION(CHANGE FROM, rt); 17424313Ssklower if (doioctl) { 17524313Ssklower oldroute = rt->rt_rt; 17624313Ssklower rt->rt_router = *gate; 17724313Ssklower } 17824313Ssklower rt->rt_metric = metric; 17926171Ssklower if ((rt->rt_state & RTS_INTERFACE) && metric) { 18026171Ssklower rt->rt_state &= ~RTS_INTERFACE; 18126171Ssklower syslog(LOG_ERR, 18226171Ssklower "changing route from interface %s (timed out)", 18326171Ssklower rt->rt_ifp->int_name); 18426171Ssklower } 18524313Ssklower if (metric) 18626171Ssklower rt->rt_flags |= RTF_GATEWAY; 18726171Ssklower else 18826171Ssklower rt->rt_flags &= ~RTF_GATEWAY; 18924313Ssklower rt->rt_state |= RTS_CHANGED; 19024313Ssklower TRACE_ACTION(CHANGE TO, rt); 19124313Ssklower } 19224313Ssklower if (doioctl && install) { 19338688Skarels #ifndef RTM_ADD 19424313Ssklower if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 19530350Skarels syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", 19630350Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 19730350Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 19830350Skarels if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 19930350Skarels perror("SIOCDELRT"); 20038688Skarels #else 20138688Skarels if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 20238688Skarels perror("SIOCDELRT"); 20338688Skarels if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 20438688Skarels syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", 20538688Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 20638688Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 20738688Skarels #endif 20824313Ssklower } 20924313Ssklower } 21024313Ssklower 21124313Ssklower rtdelete(rt) 21224313Ssklower struct rt_entry *rt; 21324313Ssklower { 21424313Ssklower 21538688Skarels struct sockaddr *sa = &(rt->rt_rt.rt_gateway); 21638688Skarels FIXLEN(sa); 21738688Skarels #undef rt_dst 21838688Skarels sa = &(rt->rt_rt.rt_dst); 21938688Skarels FIXLEN(sa); 22026171Ssklower if (rt->rt_state & RTS_INTERFACE) { 22126171Ssklower syslog(LOG_ERR, "deleting route to interface %s (timed out)", 22226171Ssklower rt->rt_ifp->int_name); 22326171Ssklower } 22424313Ssklower TRACE_ACTION(DELETE, rt); 22526171Ssklower if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 22626171Ssklower perror("SIOCDELRT"); 22724313Ssklower remque(rt); 22824313Ssklower free((char *)rt); 22924313Ssklower } 23024313Ssklower 23124313Ssklower rtinit() 23224313Ssklower { 23324313Ssklower register struct rthash *rh; 23424313Ssklower 23524313Ssklower for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 23624313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 23724313Ssklower for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 23824313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 23924313Ssklower } 240