home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / routed / tables.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-16  |  9.4 KB  |  359 lines

  1. /*
  2.  * Copyright (c) 1983, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)tables.c    5.17 (Berkeley) 6/1/90";
  36. #endif /* not lint */
  37.  
  38. /*
  39.  * Routing Table Management Daemon
  40.  */
  41. #include "defs.h"
  42. #include <sys/ioctl.h>
  43. #include <errno.h>
  44. #include <sys/syslog.h>
  45.  
  46. #ifndef DEBUG
  47. #define    DEBUG    0
  48. #endif
  49.  
  50. #ifdef RTM_ADD
  51. #define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
  52. #else
  53. #define FIXLEN(s) { }
  54. #endif
  55.  
  56. int    install = !DEBUG;        /* if 1 call kernel */
  57.  
  58. /*
  59.  * Lookup dst in the tables for an exact match.
  60.  */
  61. struct rt_entry *
  62. rtlookup(dst)
  63.     struct sockaddr *dst;
  64. {
  65.     register struct rt_entry *rt;
  66.     register struct rthash *rh;
  67.     register u_int hash;
  68.     struct afhash h;
  69.     int doinghost = 1;
  70.  
  71.     if (dst->sa_family >= af_max)
  72.         return (0);
  73.     (*afswitch[dst->sa_family].af_hash)(dst, &h);
  74.     hash = h.afh_hosthash;
  75.     rh = &hosthash[hash & ROUTEHASHMASK];
  76. again:
  77.     for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
  78.         if (rt->rt_hash != hash)
  79.             continue;
  80.         if (equal(&rt->rt_dst, dst))
  81.             return (rt);
  82.     }
  83.     if (doinghost) {
  84.         doinghost = 0;
  85.         hash = h.afh_nethash;
  86.         rh = &nethash[hash & ROUTEHASHMASK];
  87.         goto again;
  88.     }
  89.     return (0);
  90. }
  91.  
  92. struct sockaddr wildcard;    /* zero valued cookie for wildcard searches */
  93.  
  94. /*
  95.  * Find a route to dst as the kernel would.
  96.  */
  97. struct rt_entry *
  98. rtfind(dst)
  99.     struct sockaddr *dst;
  100. {
  101.     register struct rt_entry *rt;
  102.     register struct rthash *rh;
  103.     register u_int hash;
  104.     struct afhash h;
  105.     int af = dst->sa_family;
  106.     int doinghost = 1, (*match)();
  107.  
  108.     if (af >= af_max)
  109.         return (0);
  110.     (*afswitch[af].af_hash)(dst, &h);
  111.     hash = h.afh_hosthash;
  112.     rh = &hosthash[hash & ROUTEHASHMASK];
  113.  
  114. again:
  115.     for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
  116.         if (rt->rt_hash != hash)
  117.             continue;
  118.         if (doinghost) {
  119.             if (equal(&rt->rt_dst, dst))
  120.                 return (rt);
  121.         } else {
  122.             if (rt->rt_dst.sa_family == af &&
  123.                 (*match)(&rt->rt_dst, dst))
  124.                 return (rt);
  125.         }
  126.     }
  127.     if (doinghost) {
  128.         doinghost = 0;
  129.         hash = h.afh_nethash;
  130.         rh = &nethash[hash & ROUTEHASHMASK];
  131.         match = afswitch[af].af_netmatch;
  132.         goto again;
  133.     }
  134. #ifdef notyet
  135.     /*
  136.      * Check for wildcard gateway, by convention network 0.
  137.      */
  138.     if (dst != &wildcard) {
  139.         dst = &wildcard, hash = 0;
  140.         goto again;
  141.     }
  142. #endif
  143.     return (0);
  144. }
  145.  
  146. rtadd(dst, gate, metric, state)
  147.     struct sockaddr *dst, *gate;
  148.     int metric, state;
  149. {
  150.     struct afhash h;
  151.     register struct rt_entry *rt;
  152.     struct rthash *rh;
  153.     int af = dst->sa_family, flags;
  154.     u_int hash;
  155.  
  156.     if (af >= af_max)
  157.         return;
  158.     (*afswitch[af].af_hash)(dst, &h);
  159.     flags = (*afswitch[af].af_rtflags)(dst);
  160.     /*
  161.      * Subnet flag isn't visible to kernel, move to state.    XXX
  162.      */
  163.     FIXLEN(dst);
  164.     FIXLEN(gate);
  165.     if (flags & RTF_SUBNET) {
  166.         state |= RTS_SUBNET;
  167.         flags &= ~RTF_SUBNET;
  168.     }
  169.     if (flags & RTF_HOST) {
  170.         hash = h.afh_hosthash;
  171.         rh = &hosthash[hash & ROUTEHASHMASK];
  172.     } else {
  173.         hash = h.afh_nethash;
  174.         rh = &nethash[hash & ROUTEHASHMASK];
  175.     }
  176.     rt = (struct rt_entry *)malloc(sizeof (*rt));
  177.     if (rt == 0)
  178.         return;
  179.     rt->rt_hash = hash;
  180.     rt->rt_dst = *dst;
  181.     rt->rt_router = *gate;
  182.     rt->rt_timer = 0;
  183.     rt->rt_flags = RTF_UP | flags;
  184.     rt->rt_state = state | RTS_CHANGED;
  185.     rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
  186.     if (rt->rt_ifp == 0)
  187.         rt->rt_ifp = if_ifwithnet(&rt->rt_router);
  188.     if ((state & RTS_INTERFACE) == 0)
  189.         rt->rt_flags |= RTF_GATEWAY;
  190.     rt->rt_metric = metric;
  191.     insque(rt, rh);
  192.     TRACE_ACTION("ADD", rt);
  193.     /*
  194.      * If the ioctl fails because the gateway is unreachable
  195.      * from this host, discard the entry.  This should only
  196.      * occur because of an incorrect entry in /etc/gateways.
  197.      */
  198.     if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
  199.         ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
  200.         if (errno != EEXIST && gate->sa_family < af_max)
  201.             syslog(LOG_ERR,
  202.             "adding route to net/host %s through gateway %s: %m\n",
  203.                (*afswitch[dst->sa_family].af_format)(dst),
  204.                (*afswitch[gate->sa_family].af_format)(gate));
  205.         perror("SIOCADDRT");
  206.         if (errno == ENETUNREACH) {
  207.             TRACE_ACTION("DELETE", rt);
  208.             remque(rt);
  209.             free((char *)rt);
  210.         }
  211.     }
  212. }
  213.  
  214. rtchange(rt, gate, metric)
  215.     struct rt_entry *rt;
  216.     struct sockaddr *gate;
  217.     short metric;
  218. {
  219.     int add = 0, delete = 0, newgateway = 0;
  220.     struct rtentry oldroute;
  221.  
  222.     FIXLEN(gate);
  223.     FIXLEN(&(rt->rt_router));
  224.     FIXLEN(&(rt->rt_dst));
  225.     if (!equal(&rt->rt_router, gate)) {
  226.         newgateway++;
  227.         TRACE_ACTION("CHANGE FROM ", rt);
  228.     } else if (metric != rt->rt_metric)
  229.         TRACE_NEWMETRIC(rt, metric);
  230.     if ((rt->rt_state & RTS_INTERNAL) == 0) {
  231.         /*
  232.          * If changing to different router, we need to add
  233.          * new route and delete old one if in the kernel.
  234.          * If the router is the same, we need to delete
  235.          * the route if has become unreachable, or re-add
  236.          * it if it had been unreachable.
  237.          */
  238.         if (newgateway) {
  239.             add++;
  240.             if (rt->rt_metric != HOPCNT_INFINITY)
  241.                 delete++;
  242.         } else if (metric == HOPCNT_INFINITY)
  243.             delete++;
  244.         else if (rt->rt_metric == HOPCNT_INFINITY)
  245.             add++;
  246.     }
  247.     if (delete)
  248.         oldroute = rt->rt_rt;
  249.     if ((rt->rt_state & RTS_INTERFACE) && delete) {
  250.         rt->rt_state &= ~RTS_INTERFACE;
  251.         rt->rt_flags |= RTF_GATEWAY;
  252.         if (metric > rt->rt_metric && delete)
  253.             syslog(LOG_ERR, "%s route to interface %s (timed out)",
  254.                 add? "changing" : "deleting",
  255.                 rt->rt_ifp->int_name);
  256.     }
  257.     if (add) {
  258.         rt->rt_router = *gate;
  259.         rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
  260.         if (rt->rt_ifp == 0)
  261.             rt->rt_ifp = if_ifwithnet(&rt->rt_router);
  262.     }
  263.     rt->rt_metric = metric;
  264.     rt->rt_state |= RTS_CHANGED;
  265.     if (newgateway)
  266.         TRACE_ACTION("CHANGE TO   ", rt);
  267. #ifndef RTM_ADD
  268.     if (add && install)
  269.         if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
  270.             perror("SIOCADDRT");
  271.     if (delete && install)
  272.         if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
  273.             perror("SIOCDELRT");
  274. #else
  275.     if (delete && install)
  276.         if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
  277.             perror("SIOCDELRT");
  278.     if (add && install) {
  279.         if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
  280.             perror("SIOCADDRT");
  281.     }
  282. #endif
  283. }
  284.  
  285. rtdelete(rt)
  286.     struct rt_entry *rt;
  287. {
  288.  
  289.     TRACE_ACTION("DELETE", rt);
  290.     FIXLEN(&(rt->rt_router));
  291.     FIXLEN(&(rt->rt_dst));
  292.     if (rt->rt_metric < HOPCNT_INFINITY) {
  293.         if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
  294.         syslog(LOG_ERR,
  295.             "deleting route to interface %s? (timed out?)",
  296.             rt->rt_ifp->int_name);
  297.         if (install &&
  298.         (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
  299.         ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
  300.             perror("SIOCDELRT");
  301.     }
  302.     remque(rt);
  303.     free((char *)rt);
  304. }
  305.  
  306. rtdeleteall(sig)
  307.     int sig;
  308. {
  309.     register struct rthash *rh;
  310.     register struct rt_entry *rt;
  311.     struct rthash *base = hosthash;
  312.     int doinghost = 1;
  313.  
  314. again:
  315.     for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
  316.         rt = rh->rt_forw;
  317.         for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
  318.             if (rt->rt_state & RTS_INTERFACE ||
  319.                 rt->rt_metric >= HOPCNT_INFINITY)
  320.                 continue;
  321.             TRACE_ACTION("DELETE", rt);
  322.             if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
  323.                 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
  324.                 perror("SIOCDELRT");
  325.         }
  326.     }
  327.     if (doinghost) {
  328.         doinghost = 0;
  329.         base = nethash;
  330.         goto again;
  331.     }
  332.     exit(sig);
  333. }
  334.  
  335. /*
  336.  * If we have an interface to the wide, wide world,
  337.  * add an entry for an Internet default route (wildcard) to the internal
  338.  * tables and advertise it.  This route is not added to the kernel routes,
  339.  * but this entry prevents us from listening to other people's defaults
  340.  * and installing them in the kernel here.
  341.  */
  342. rtdefault()
  343. {
  344.     extern struct sockaddr inet_default;
  345.  
  346.     rtadd(&inet_default, &inet_default, 1,
  347.         RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
  348. }
  349.  
  350. rtinit()
  351. {
  352.     register struct rthash *rh;
  353.  
  354.     for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
  355.         rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
  356.     for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
  357.         rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
  358. }
  359.