124323Ssklower /* 224323Ssklower * Copyright (c) 1985 Regents of the University of California. 324323Ssklower * All rights reserved. The Berkeley software License Agreement 424323Ssklower * specifies the terms and conditions for redistribution. 524323Ssklower * 624323Ssklower */ 724323Ssklower 824323Ssklower 924313Ssklower #ifndef lint 10*30350Skarels static char sccsid[] = "@(#)tables.c 5.6 (Berkeley) 12/30/86"; 1124323Ssklower #endif not lint 1224313Ssklower 1324313Ssklower /* 1424313Ssklower * Routing Table Management Daemon 1524313Ssklower */ 1624313Ssklower #include "defs.h" 1724313Ssklower #include <sys/ioctl.h> 1824313Ssklower #include <errno.h> 1924313Ssklower 2024313Ssklower #ifndef DEBUG 2124313Ssklower #define DEBUG 0 2224313Ssklower #endif 2324313Ssklower 24*30350Skarels extern char *xns_ntoa(); 25*30350Skarels 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 11524313Ssklower if (af >= AF_MAX) 11624313Ssklower return; 11724313Ssklower (*afswitch[af].af_hash)(dst, &h); 11824313Ssklower flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 11924313Ssklower if (flags & RTF_HOST) { 12024313Ssklower hash = h.afh_hosthash; 12124313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 12224313Ssklower } else { 12324313Ssklower hash = h.afh_nethash; 12424313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 12524313Ssklower } 12624313Ssklower rt = (struct rt_entry *)malloc(sizeof (*rt)); 12724313Ssklower if (rt == 0) 12824313Ssklower return; 12924313Ssklower rt->rt_hash = hash; 13024313Ssklower rt->rt_dst = *dst; 13124313Ssklower rt->rt_router = *gate; 13224313Ssklower rt->rt_metric = metric; 13324313Ssklower rt->rt_timer = 0; 13424313Ssklower rt->rt_flags = RTF_UP | flags; 13524313Ssklower rt->rt_state = state | RTS_CHANGED; 13624313Ssklower rt->rt_ifp = if_ifwithnet(&rt->rt_router); 13724313Ssklower if (metric) 13824313Ssklower rt->rt_flags |= RTF_GATEWAY; 13924313Ssklower insque(rt, rh); 14024313Ssklower TRACE_ACTION(ADD, rt); 14124313Ssklower /* 14224313Ssklower * If the ioctl fails because the gateway is unreachable 14324313Ssklower * from this host, discard the entry. This should only 14424313Ssklower * occur because of an incorrect entry in /etc/gateways. 14524313Ssklower */ 14624313Ssklower if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 147*30350Skarels if (errno != EEXIST) 148*30350Skarels perror("SIOCADDRT"); 14924313Ssklower if (errno == ENETUNREACH) { 15024313Ssklower TRACE_ACTION(DELETE, rt); 15124313Ssklower remque(rt); 15224313Ssklower free((char *)rt); 15324313Ssklower } 15424313Ssklower } 15524313Ssklower } 15624313Ssklower 15724313Ssklower rtchange(rt, gate, metric) 15824313Ssklower struct rt_entry *rt; 15924313Ssklower struct sockaddr *gate; 16024313Ssklower short metric; 16124313Ssklower { 16224313Ssklower int doioctl = 0, metricchanged = 0; 16324313Ssklower struct rtentry oldroute; 16424313Ssklower 16524313Ssklower if (!equal(&rt->rt_router, gate)) 16624313Ssklower doioctl++; 16724313Ssklower if (metric != rt->rt_metric) 16824313Ssklower metricchanged++; 16924313Ssklower if (doioctl || metricchanged) { 17024313Ssklower TRACE_ACTION(CHANGE FROM, rt); 17124313Ssklower if (doioctl) { 17224313Ssklower oldroute = rt->rt_rt; 17324313Ssklower rt->rt_router = *gate; 17424313Ssklower } 17524313Ssklower rt->rt_metric = metric; 17626171Ssklower if ((rt->rt_state & RTS_INTERFACE) && metric) { 17726171Ssklower rt->rt_state &= ~RTS_INTERFACE; 17826171Ssklower syslog(LOG_ERR, 17926171Ssklower "changing route from interface %s (timed out)", 18026171Ssklower rt->rt_ifp->int_name); 18126171Ssklower } 18224313Ssklower if (metric) 18326171Ssklower rt->rt_flags |= RTF_GATEWAY; 18426171Ssklower else 18526171Ssklower rt->rt_flags &= ~RTF_GATEWAY; 18624313Ssklower rt->rt_state |= RTS_CHANGED; 18724313Ssklower TRACE_ACTION(CHANGE TO, rt); 18824313Ssklower } 18924313Ssklower if (doioctl && install) { 19024313Ssklower if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 191*30350Skarels syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", 192*30350Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 193*30350Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 194*30350Skarels if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 195*30350Skarels perror("SIOCDELRT"); 19624313Ssklower } 19724313Ssklower } 19824313Ssklower 19924313Ssklower rtdelete(rt) 20024313Ssklower struct rt_entry *rt; 20124313Ssklower { 20224313Ssklower 20326171Ssklower if (rt->rt_state & RTS_INTERFACE) { 20426171Ssklower syslog(LOG_ERR, "deleting route to interface %s (timed out)", 20526171Ssklower rt->rt_ifp->int_name); 20626171Ssklower } 20724313Ssklower TRACE_ACTION(DELETE, rt); 20826171Ssklower if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 20926171Ssklower perror("SIOCDELRT"); 21024313Ssklower remque(rt); 21124313Ssklower free((char *)rt); 21224313Ssklower } 21324313Ssklower 21424313Ssklower rtinit() 21524313Ssklower { 21624313Ssklower register struct rthash *rh; 21724313Ssklower 21824313Ssklower for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 21924313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 22024313Ssklower for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 22124313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 22224313Ssklower } 223