provide correct exit values
[unix-history] / usr / src / sbin / routed / input.c
index 0d4034f..013fd15 100644 (file)
@@ -1,11 +1,29 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)input.c    4.3 %G%";
-#endif
+static char sccsid[] = "@(#)input.c    5.18 (Berkeley) %G%";
+#endif /* not lint */
 
 /*
  * Routing Table Management Daemon
  */
 #include "defs.h"
 
 /*
  * Routing Table Management Daemon
  */
 #include "defs.h"
+#include <sys/syslog.h>
 
 /*
  * Process a newly received packet.
 
 /*
  * Process a newly received packet.
@@ -14,17 +32,23 @@ rip_input(from, size)
        struct sockaddr *from;
        int size;
 {
        struct sockaddr *from;
        int size;
 {
-       struct rt_entry *rt;
-       struct netinfo *n;
-       struct interface *ifp;
+       register struct rt_entry *rt;
+       register struct netinfo *n;
+       register struct interface *ifp;
+       struct interface *if_ifwithdstaddr();
        int newsize;
        int newsize;
-       struct afswitch *afp;
+       register struct afswitch *afp;
+       static struct sockaddr badfrom, badfrom2;
 
        ifp = 0;
        TRACE_INPUT(ifp, from, size);
 
        ifp = 0;
        TRACE_INPUT(ifp, from, size);
-       if (from->sa_family >= AF_MAX)
+       if (from->sa_family >= af_max ||
+           (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) {
+               syslog(LOG_INFO,
+        "\"from\" address in unsupported address family (%d), cmd %d\n",
+                   from->sa_family, msg->rip_cmd);
                return;
                return;
-       afp = &afswitch[from->sa_family];
+       }
        switch (msg->rip_cmd) {
 
        case RIPCMD_REQUEST:
        switch (msg->rip_cmd) {
 
        case RIPCMD_REQUEST:
@@ -36,18 +60,36 @@ rip_input(from, size)
                                break;
                        size -= sizeof (struct netinfo);
 
                                break;
                        size -= sizeof (struct netinfo);
 
+                       if (msg->rip_vers > 0) {
+                               n->rip_dst.sa_family =
+                                       ntohs(n->rip_dst.sa_family);
+                               n->rip_metric = ntohl(n->rip_metric);
+                       }
                        /* 
                         * A single entry with sa_family == AF_UNSPEC and
                         * metric ``infinity'' means ``all routes''.
                        /* 
                         * A single entry with sa_family == AF_UNSPEC and
                         * metric ``infinity'' means ``all routes''.
+                        * We respond to routers only if we are acting
+                        * as a supplier, or to anyone other than a router
+                        * (eg, query).
                         */
                        if (n->rip_dst.sa_family == AF_UNSPEC &&
                            n->rip_metric == HOPCNT_INFINITY && size == 0) {
                         */
                        if (n->rip_dst.sa_family == AF_UNSPEC &&
                            n->rip_metric == HOPCNT_INFINITY && size == 0) {
-                               supply(from, 0, ifp);
+                               if (supplier || (*afp->af_portmatch)(from) == 0)
+                                       supply(from, 0, 0);
                                return;
                        }
                                return;
                        }
-                       rt = rtlookup(&n->rip_dst);
+                       if (n->rip_dst.sa_family < af_max &&
+                           afswitch[n->rip_dst.sa_family].af_hash)
+                               rt = rtlookup(&n->rip_dst);
+                       else
+                               rt = 0;
                        n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
                        n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
-                               min(rt->rt_metric+1, HOPCNT_INFINITY);
+                               min(rt->rt_metric + 1, HOPCNT_INFINITY);
+                       if (msg->rip_vers > 0) {
+                               n->rip_dst.sa_family =
+                                       htons(n->rip_dst.sa_family);
+                               n->rip_metric = htonl(n->rip_metric);
+                       }
                        n++, newsize += sizeof (struct netinfo);
                }
                if (newsize > 0) {
                        n++, newsize += sizeof (struct netinfo);
                }
                if (newsize > 0) {
@@ -59,9 +101,16 @@ rip_input(from, size)
 
        case RIPCMD_TRACEON:
        case RIPCMD_TRACEOFF:
 
        case RIPCMD_TRACEON:
        case RIPCMD_TRACEOFF:
-               /* verify message came from a priviledged port */
+               /* verify message came from a privileged port */
                if ((*afp->af_portcheck)(from) == 0)
                        return;
                if ((*afp->af_portcheck)(from) == 0)
                        return;
+               if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
+                   (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
+                   ifp->int_flags & IFF_PASSIVE) {
+                       syslog(LOG_ERR, "trace command from unknown router, %s",
+                           (*afswitch[from->sa_family].af_format)(from));
+                       return;
+               }
                packet[size] = '\0';
                if (msg->rip_cmd == RIPCMD_TRACEON)
                        traceon(msg->rip_tracefile);
                packet[size] = '\0';
                if (msg->rip_cmd == RIPCMD_TRACEON)
                        traceon(msg->rip_tracefile);
@@ -77,34 +126,139 @@ rip_input(from, size)
                /* are we talking to ourselves? */
                ifp = if_ifwithaddr(from);
                if (ifp) {
                /* are we talking to ourselves? */
                ifp = if_ifwithaddr(from);
                if (ifp) {
+                       if (ifp->int_flags & IFF_PASSIVE) {
+                               syslog(LOG_ERR,
+                                 "bogus input (from passive interface, %s)",
+                                 (*afswitch[from->sa_family].af_format)(from));
+                               return;
+                       }
                        rt = rtfind(from);
                        rt = rtfind(from);
-                       if (rt == 0)
+                       if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) &&
+                           rt->rt_metric >= ifp->int_metric) 
                                addrouteforif(ifp);
                        else
                                rt->rt_timer = 0;
                        return;
                }
                                addrouteforif(ifp);
                        else
                                rt->rt_timer = 0;
                        return;
                }
+               /*
+                * Update timer for interface on which the packet arrived.
+                * If from other end of a point-to-point link that isn't
+                * in the routing tables, (re-)add the route.
+                */
+               if ((rt = rtfind(from)) &&
+                   (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
+                       rt->rt_timer = 0;
+               else if ((ifp = if_ifwithdstaddr(from)) &&
+                   (rt == 0 || rt->rt_metric >= ifp->int_metric))
+                       addrouteforif(ifp);
+               /*
+                * "Authenticate" router from which message originated.
+                * We accept routing packets from routers directly connected
+                * via broadcast or point-to-point networks,
+                * and from those listed in /etc/gateways.
+                */
+               if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
+                   (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
+                   ifp->int_flags & IFF_PASSIVE) {
+                       if (bcmp((char *)from, (char *)&badfrom,
+                           sizeof(badfrom)) != 0) {
+                               syslog(LOG_ERR,
+                                 "packet from unknown router, %s",
+                                 (*afswitch[from->sa_family].af_format)(from));
+                               badfrom = *from;
+                       }
+                       return;
+               }
                size -= 4 * sizeof (char);
                n = msg->rip_nets;
                for (; size > 0; size -= sizeof (struct netinfo), n++) {
                        if (size < sizeof (struct netinfo))
                                break;
                size -= 4 * sizeof (char);
                n = msg->rip_nets;
                for (; size > 0; size -= sizeof (struct netinfo), n++) {
                        if (size < sizeof (struct netinfo))
                                break;
-                       if (n->rip_metric >= HOPCNT_INFINITY)
+                       if (msg->rip_vers > 0) {
+                               n->rip_dst.sa_family =
+                                       ntohs(n->rip_dst.sa_family);
+                               n->rip_metric = ntohl(n->rip_metric);
+                       }
+                       if (n->rip_dst.sa_family >= af_max ||
+                           (afp = &afswitch[n->rip_dst.sa_family])->af_hash ==
+                           (int (*)())0) {
+                               syslog(LOG_INFO,
+               "route in unsupported address family (%d), from %s (af %d)\n",
+                                  n->rip_dst.sa_family,
+                                  (*afswitch[from->sa_family].af_format)(from),
+                                  from->sa_family);
+                               continue;
+                       }
+                       if (((*afp->af_checkhost)(&n->rip_dst)) == 0) {
+                               syslog(LOG_DEBUG,
+                                   "bad host in route from %s (af %d)\n",
+                                  (*afswitch[from->sa_family].af_format)(from),
+                                  from->sa_family);
                                continue;
                                continue;
+                       }
+                       if (n->rip_metric == 0 ||
+                           (unsigned) n->rip_metric > HOPCNT_INFINITY) {
+                               if (bcmp((char *)from, (char *)&badfrom2,
+                                   sizeof(badfrom2)) != 0) {
+                                       syslog(LOG_ERR,
+                                           "bad metric (%d) from %s\n",
+                                           n->rip_metric,
+                                 (*afswitch[from->sa_family].af_format)(from));
+                                       badfrom2 = *from;
+                               }
+                               continue;
+                       }
+                       /*
+                        * Adjust metric according to incoming interface.
+                        */
+                       if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
+                               n->rip_metric += ifp->int_metric;
+                       if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
+                               n->rip_metric = HOPCNT_INFINITY;
                        rt = rtlookup(&n->rip_dst);
                        rt = rtlookup(&n->rip_dst);
-                       if (rt == 0) {
-                               rtadd(&n->rip_dst, from, n->rip_metric, 0);
+                       if (rt == 0 ||
+                           (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
+                           (RTS_INTERNAL|RTS_INTERFACE)) {
+                               /*
+                                * If we're hearing a logical network route
+                                * back from a peer to which we sent it,
+                                * ignore it.
+                                */
+                               if (rt && rt->rt_state & RTS_SUBNET &&
+                                   (*afp->af_sendroute)(rt, from))
+                                       continue;
+                               if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
+                                   /*
+                                    * Look for an equivalent route that
+                                    * includes this one before adding
+                                    * this route.
+                                    */
+                                   rt = rtfind(&n->rip_dst);
+                                   if (rt && equal(from, &rt->rt_router))
+                                           continue;
+                                   rtadd(&n->rip_dst, from, n->rip_metric, 0);
+                               }
                                continue;
                        }
 
                        /*
                                continue;
                        }
 
                        /*
-                        * Update if from gateway, shorter, or getting
-                        * stale and equivalent.
+                        * Update if from gateway and different,
+                        * shorter, or equivalent but old route
+                        * is getting stale.
                         */
                         */
-                       if (equal(from, &rt->rt_router) ||
-                           n->rip_metric < rt->rt_metric ||
-                           (rt->rt_timer > (EXPIRE_TIME/2) &&
-                           rt->rt_metric == n->rip_metric)) {
+                       if (equal(from, &rt->rt_router)) {
+                               if (n->rip_metric != rt->rt_metric) {
+                                       rtchange(rt, from, n->rip_metric);
+                                       rt->rt_timer = 0;
+                                       if (rt->rt_metric >= HOPCNT_INFINITY)
+                                               rt->rt_timer =
+                                                   GARBAGE_TIME - EXPIRE_TIME;
+                               } else if (rt->rt_metric < HOPCNT_INFINITY)
+                                       rt->rt_timer = 0;
+                       } else if ((unsigned) n->rip_metric < rt->rt_metric ||
+                           (rt->rt_metric == n->rip_metric &&
+                           rt->rt_timer > (EXPIRE_TIME/2) &&
+                           (unsigned) n->rip_metric < HOPCNT_INFINITY)) {
                                rtchange(rt, from, n->rip_metric);
                                rt->rt_timer = 0;
                        }
                                rtchange(rt, from, n->rip_metric);
                                rt->rt_timer = 0;
                        }