124323Ssklower /* 2*35593Sbostic * Copyright (c) 1985 The Regents of the University of California. 3*35593Sbostic * All rights reserved. 424323Ssklower * 5*35593Sbostic * Redistribution and use in source and binary forms are permitted 6*35593Sbostic * provided that the above copyright notice and this paragraph are 7*35593Sbostic * duplicated in all such forms and that any documentation, 8*35593Sbostic * advertising materials, and other materials related to such 9*35593Sbostic * distribution and use acknowledge that the software was developed 10*35593Sbostic * by the University of California, Berkeley. The name of the 11*35593Sbostic * University may not be used to endorse or promote products derived 12*35593Sbostic * from this software without specific prior written permission. 13*35593Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35593Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35593Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1624323Ssklower */ 1724323Ssklower 1824313Ssklower #ifndef lint 19*35593Sbostic static char sccsid[] = "@(#)tables.c 5.7 (Berkeley) 09/20/88"; 20*35593Sbostic #endif /* not lint */ 2124313Ssklower 2224313Ssklower /* 2324313Ssklower * Routing Table Management Daemon 2424313Ssklower */ 2524313Ssklower #include "defs.h" 2624313Ssklower #include <sys/ioctl.h> 2724313Ssklower #include <errno.h> 2824313Ssklower 2924313Ssklower #ifndef DEBUG 3024313Ssklower #define DEBUG 0 3124313Ssklower #endif 3224313Ssklower 3330350Skarels extern char *xns_ntoa(); 3430350Skarels 3524313Ssklower int install = !DEBUG; /* if 1 call kernel */ 3624318Ssklower int delete = 1; 3724313Ssklower /* 3824313Ssklower * Lookup dst in the tables for an exact match. 3924313Ssklower */ 4024313Ssklower struct rt_entry * 4124313Ssklower rtlookup(dst) 4224313Ssklower struct sockaddr *dst; 4324313Ssklower { 4424313Ssklower register struct rt_entry *rt; 4524313Ssklower register struct rthash *rh; 4624313Ssklower register u_int hash; 4724313Ssklower struct afhash h; 4824313Ssklower int doinghost = 1; 4924313Ssklower 5024313Ssklower if (dst->sa_family >= AF_MAX) 5124313Ssklower return (0); 5224313Ssklower (*afswitch[dst->sa_family].af_hash)(dst, &h); 5324313Ssklower hash = h.afh_hosthash; 5424313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 5524313Ssklower again: 5624313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 5724313Ssklower if (rt->rt_hash != hash) 5824313Ssklower continue; 5924313Ssklower if (equal(&rt->rt_dst, dst)) 6024313Ssklower return (rt); 6124313Ssklower } 6224313Ssklower if (doinghost) { 6324313Ssklower doinghost = 0; 6424313Ssklower hash = h.afh_nethash; 6524313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 6624313Ssklower goto again; 6724313Ssklower } 6824313Ssklower return (0); 6924313Ssklower } 7024313Ssklower 7124313Ssklower /* 7224313Ssklower * Find a route to dst as the kernel would. 7324313Ssklower */ 7424313Ssklower struct rt_entry * 7524313Ssklower rtfind(dst) 7624313Ssklower struct sockaddr *dst; 7724313Ssklower { 7824313Ssklower register struct rt_entry *rt; 7924313Ssklower register struct rthash *rh; 8024313Ssklower register u_int hash; 8124313Ssklower struct afhash h; 8224313Ssklower int af = dst->sa_family; 8324313Ssklower int doinghost = 1, (*match)(); 8424313Ssklower 8524313Ssklower if (af >= AF_MAX) 8624313Ssklower return (0); 8724313Ssklower (*afswitch[af].af_hash)(dst, &h); 8824313Ssklower hash = h.afh_hosthash; 8924313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 9024313Ssklower 9124313Ssklower again: 9224313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 9324313Ssklower if (rt->rt_hash != hash) 9424313Ssklower continue; 9524313Ssklower if (doinghost) { 9624313Ssklower if (equal(&rt->rt_dst, dst)) 9724313Ssklower return (rt); 9824323Ssklower } else { 9924323Ssklower if (rt->rt_dst.sa_family == af && 10024323Ssklower (*match)(&rt->rt_dst, dst)) 10124323Ssklower return (rt); 10224313Ssklower } 10324313Ssklower } 10424313Ssklower if (doinghost) { 10524313Ssklower doinghost = 0; 10624313Ssklower hash = h.afh_nethash; 10724313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 10824313Ssklower match = afswitch[af].af_netmatch; 10924313Ssklower goto again; 11024313Ssklower } 11124313Ssklower return (0); 11224313Ssklower } 11324313Ssklower 11424313Ssklower rtadd(dst, gate, metric, state) 11524313Ssklower struct sockaddr *dst, *gate; 11624313Ssklower int metric, state; 11724313Ssklower { 11824313Ssklower struct afhash h; 11924313Ssklower register struct rt_entry *rt; 12024313Ssklower struct rthash *rh; 12124313Ssklower int af = dst->sa_family, flags; 12224313Ssklower u_int hash; 12324313Ssklower 12424313Ssklower if (af >= AF_MAX) 12524313Ssklower return; 12624313Ssklower (*afswitch[af].af_hash)(dst, &h); 12724313Ssklower flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 12824313Ssklower if (flags & RTF_HOST) { 12924313Ssklower hash = h.afh_hosthash; 13024313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 13124313Ssklower } else { 13224313Ssklower hash = h.afh_nethash; 13324313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 13424313Ssklower } 13524313Ssklower rt = (struct rt_entry *)malloc(sizeof (*rt)); 13624313Ssklower if (rt == 0) 13724313Ssklower return; 13824313Ssklower rt->rt_hash = hash; 13924313Ssklower rt->rt_dst = *dst; 14024313Ssklower rt->rt_router = *gate; 14124313Ssklower rt->rt_metric = metric; 14224313Ssklower rt->rt_timer = 0; 14324313Ssklower rt->rt_flags = RTF_UP | flags; 14424313Ssklower rt->rt_state = state | RTS_CHANGED; 14524313Ssklower rt->rt_ifp = if_ifwithnet(&rt->rt_router); 14624313Ssklower if (metric) 14724313Ssklower rt->rt_flags |= RTF_GATEWAY; 14824313Ssklower insque(rt, rh); 14924313Ssklower TRACE_ACTION(ADD, rt); 15024313Ssklower /* 15124313Ssklower * If the ioctl fails because the gateway is unreachable 15224313Ssklower * from this host, discard the entry. This should only 15324313Ssklower * occur because of an incorrect entry in /etc/gateways. 15424313Ssklower */ 15524313Ssklower if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 15630350Skarels if (errno != EEXIST) 15730350Skarels perror("SIOCADDRT"); 15824313Ssklower if (errno == ENETUNREACH) { 15924313Ssklower TRACE_ACTION(DELETE, rt); 16024313Ssklower remque(rt); 16124313Ssklower free((char *)rt); 16224313Ssklower } 16324313Ssklower } 16424313Ssklower } 16524313Ssklower 16624313Ssklower rtchange(rt, gate, metric) 16724313Ssklower struct rt_entry *rt; 16824313Ssklower struct sockaddr *gate; 16924313Ssklower short metric; 17024313Ssklower { 17124313Ssklower int doioctl = 0, metricchanged = 0; 17224313Ssklower struct rtentry oldroute; 17324313Ssklower 17424313Ssklower if (!equal(&rt->rt_router, gate)) 17524313Ssklower doioctl++; 17624313Ssklower if (metric != rt->rt_metric) 17724313Ssklower metricchanged++; 17824313Ssklower if (doioctl || metricchanged) { 17924313Ssklower TRACE_ACTION(CHANGE FROM, rt); 18024313Ssklower if (doioctl) { 18124313Ssklower oldroute = rt->rt_rt; 18224313Ssklower rt->rt_router = *gate; 18324313Ssklower } 18424313Ssklower rt->rt_metric = metric; 18526171Ssklower if ((rt->rt_state & RTS_INTERFACE) && metric) { 18626171Ssklower rt->rt_state &= ~RTS_INTERFACE; 18726171Ssklower syslog(LOG_ERR, 18826171Ssklower "changing route from interface %s (timed out)", 18926171Ssklower rt->rt_ifp->int_name); 19026171Ssklower } 19124313Ssklower if (metric) 19226171Ssklower rt->rt_flags |= RTF_GATEWAY; 19326171Ssklower else 19426171Ssklower rt->rt_flags &= ~RTF_GATEWAY; 19524313Ssklower rt->rt_state |= RTS_CHANGED; 19624313Ssklower TRACE_ACTION(CHANGE TO, rt); 19724313Ssklower } 19824313Ssklower if (doioctl && install) { 19924313Ssklower if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 20030350Skarels syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", 20130350Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 20230350Skarels xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 20330350Skarels if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 20430350Skarels perror("SIOCDELRT"); 20524313Ssklower } 20624313Ssklower } 20724313Ssklower 20824313Ssklower rtdelete(rt) 20924313Ssklower struct rt_entry *rt; 21024313Ssklower { 21124313Ssklower 21226171Ssklower if (rt->rt_state & RTS_INTERFACE) { 21326171Ssklower syslog(LOG_ERR, "deleting route to interface %s (timed out)", 21426171Ssklower rt->rt_ifp->int_name); 21526171Ssklower } 21624313Ssklower TRACE_ACTION(DELETE, rt); 21726171Ssklower if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 21826171Ssklower perror("SIOCDELRT"); 21924313Ssklower remque(rt); 22024313Ssklower free((char *)rt); 22124313Ssklower } 22224313Ssklower 22324313Ssklower rtinit() 22424313Ssklower { 22524313Ssklower register struct rthash *rh; 22624313Ssklower 22724313Ssklower for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 22824313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 22924313Ssklower for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 23024313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 23124313Ssklower } 232