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*26171Ssklower static char sccsid[] = "@(#)tables.c 5.5 (Berkeley) 02/14/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 2424313Ssklower int install = !DEBUG; /* if 1 call kernel */ 2524318Ssklower int delete = 1; 2624313Ssklower /* 2724313Ssklower * Lookup dst in the tables for an exact match. 2824313Ssklower */ 2924313Ssklower struct rt_entry * 3024313Ssklower rtlookup(dst) 3124313Ssklower struct sockaddr *dst; 3224313Ssklower { 3324313Ssklower register struct rt_entry *rt; 3424313Ssklower register struct rthash *rh; 3524313Ssklower register u_int hash; 3624313Ssklower struct afhash h; 3724313Ssklower int doinghost = 1; 3824313Ssklower 3924313Ssklower if (dst->sa_family >= AF_MAX) 4024313Ssklower return (0); 4124313Ssklower (*afswitch[dst->sa_family].af_hash)(dst, &h); 4224313Ssklower hash = h.afh_hosthash; 4324313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 4424313Ssklower again: 4524313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4624313Ssklower if (rt->rt_hash != hash) 4724313Ssklower continue; 4824313Ssklower if (equal(&rt->rt_dst, dst)) 4924313Ssklower return (rt); 5024313Ssklower } 5124313Ssklower if (doinghost) { 5224313Ssklower doinghost = 0; 5324313Ssklower hash = h.afh_nethash; 5424313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 5524313Ssklower goto again; 5624313Ssklower } 5724313Ssklower return (0); 5824313Ssklower } 5924313Ssklower 6024313Ssklower /* 6124313Ssklower * Find a route to dst as the kernel would. 6224313Ssklower */ 6324313Ssklower struct rt_entry * 6424313Ssklower rtfind(dst) 6524313Ssklower struct sockaddr *dst; 6624313Ssklower { 6724313Ssklower register struct rt_entry *rt; 6824313Ssklower register struct rthash *rh; 6924313Ssklower register u_int hash; 7024313Ssklower struct afhash h; 7124313Ssklower int af = dst->sa_family; 7224313Ssklower int doinghost = 1, (*match)(); 7324313Ssklower 7424313Ssklower if (af >= AF_MAX) 7524313Ssklower return (0); 7624313Ssklower (*afswitch[af].af_hash)(dst, &h); 7724313Ssklower hash = h.afh_hosthash; 7824313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 7924313Ssklower 8024313Ssklower again: 8124313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 8224313Ssklower if (rt->rt_hash != hash) 8324313Ssklower continue; 8424313Ssklower if (doinghost) { 8524313Ssklower if (equal(&rt->rt_dst, dst)) 8624313Ssklower return (rt); 8724323Ssklower } else { 8824323Ssklower if (rt->rt_dst.sa_family == af && 8924323Ssklower (*match)(&rt->rt_dst, dst)) 9024323Ssklower return (rt); 9124313Ssklower } 9224313Ssklower } 9324313Ssklower if (doinghost) { 9424313Ssklower doinghost = 0; 9524313Ssklower hash = h.afh_nethash; 9624313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 9724313Ssklower match = afswitch[af].af_netmatch; 9824313Ssklower goto again; 9924313Ssklower } 10024313Ssklower return (0); 10124313Ssklower } 10224313Ssklower 10324313Ssklower rtadd(dst, gate, metric, state) 10424313Ssklower struct sockaddr *dst, *gate; 10524313Ssklower int metric, state; 10624313Ssklower { 10724313Ssklower struct afhash h; 10824313Ssklower register struct rt_entry *rt; 10924313Ssklower struct rthash *rh; 11024313Ssklower int af = dst->sa_family, flags; 11124313Ssklower u_int hash; 11224313Ssklower 11324313Ssklower if (af >= AF_MAX) 11424313Ssklower return; 11524313Ssklower (*afswitch[af].af_hash)(dst, &h); 11624313Ssklower flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 11724313Ssklower if (flags & RTF_HOST) { 11824313Ssklower hash = h.afh_hosthash; 11924313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 12024313Ssklower } else { 12124313Ssklower hash = h.afh_nethash; 12224313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 12324313Ssklower } 12424313Ssklower rt = (struct rt_entry *)malloc(sizeof (*rt)); 12524313Ssklower if (rt == 0) 12624313Ssklower return; 12724313Ssklower rt->rt_hash = hash; 12824313Ssklower rt->rt_dst = *dst; 12924313Ssklower rt->rt_router = *gate; 13024313Ssklower rt->rt_metric = metric; 13124313Ssklower rt->rt_timer = 0; 13224313Ssklower rt->rt_flags = RTF_UP | flags; 13324313Ssklower rt->rt_state = state | RTS_CHANGED; 13424313Ssklower rt->rt_ifp = if_ifwithnet(&rt->rt_router); 13524313Ssklower if (metric) 13624313Ssklower rt->rt_flags |= RTF_GATEWAY; 13724313Ssklower insque(rt, rh); 13824313Ssklower TRACE_ACTION(ADD, rt); 13924313Ssklower /* 14024313Ssklower * If the ioctl fails because the gateway is unreachable 14124313Ssklower * from this host, discard the entry. This should only 14224313Ssklower * occur because of an incorrect entry in /etc/gateways. 14324313Ssklower */ 14424313Ssklower if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 14524875Ssklower syslog(LOG_ERR,"SIOCADDRT: %m"); 14624313Ssklower if (errno == ENETUNREACH) { 14724313Ssklower TRACE_ACTION(DELETE, rt); 14824313Ssklower remque(rt); 14924313Ssklower free((char *)rt); 15024313Ssklower } 15124313Ssklower } 15224313Ssklower } 15324313Ssklower 15424313Ssklower rtchange(rt, gate, metric) 15524313Ssklower struct rt_entry *rt; 15624313Ssklower struct sockaddr *gate; 15724313Ssklower short metric; 15824313Ssklower { 15924313Ssklower int doioctl = 0, metricchanged = 0; 16024313Ssklower struct rtentry oldroute; 16124313Ssklower 16224313Ssklower if (!equal(&rt->rt_router, gate)) 16324313Ssklower doioctl++; 16424313Ssklower if (metric != rt->rt_metric) 16524313Ssklower metricchanged++; 16624313Ssklower if (doioctl || metricchanged) { 16724313Ssklower TRACE_ACTION(CHANGE FROM, rt); 16824313Ssklower if (doioctl) { 16924313Ssklower oldroute = rt->rt_rt; 17024313Ssklower rt->rt_router = *gate; 17124313Ssklower } 17224313Ssklower rt->rt_metric = metric; 173*26171Ssklower if ((rt->rt_state & RTS_INTERFACE) && metric) { 174*26171Ssklower rt->rt_state &= ~RTS_INTERFACE; 175*26171Ssklower syslog(LOG_ERR, 176*26171Ssklower "changing route from interface %s (timed out)", 177*26171Ssklower rt->rt_ifp->int_name); 178*26171Ssklower } 17924313Ssklower if (metric) 180*26171Ssklower rt->rt_flags |= RTF_GATEWAY; 181*26171Ssklower else 182*26171Ssklower rt->rt_flags &= ~RTF_GATEWAY; 18324313Ssklower rt->rt_state |= RTS_CHANGED; 18424313Ssklower TRACE_ACTION(CHANGE TO, rt); 18524313Ssklower } 18624313Ssklower if (doioctl && install) { 18724313Ssklower if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 18824875Ssklower syslog(LOG_ERR,"SIOCADDRT %m"); 18924318Ssklower if (delete) 19024313Ssklower if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 19124875Ssklower syslog(LOG_ERR,"SIOCDELRT %m"); 19224313Ssklower } 19324313Ssklower } 19424313Ssklower 19524313Ssklower rtdelete(rt) 19624313Ssklower struct rt_entry *rt; 19724313Ssklower { 19824313Ssklower 199*26171Ssklower if (rt->rt_state & RTS_INTERFACE) { 200*26171Ssklower syslog(LOG_ERR, "deleting route to interface %s (timed out)", 201*26171Ssklower rt->rt_ifp->int_name); 202*26171Ssklower } 20324313Ssklower TRACE_ACTION(DELETE, rt); 204*26171Ssklower if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 205*26171Ssklower perror("SIOCDELRT"); 20624313Ssklower remque(rt); 20724313Ssklower free((char *)rt); 20824313Ssklower } 20924313Ssklower 21024313Ssklower rtinit() 21124313Ssklower { 21224313Ssklower register struct rthash *rh; 21324313Ssklower 21424313Ssklower for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 21524313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 21624313Ssklower for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 21724313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 21824313Ssklower } 219