changes to allow subnets to remain local, propogate net route
authorMike Karels <karels@ucbvax.Berkeley.EDU>
Mon, 21 Apr 1986 14:34:38 +0000 (06:34 -0800)
committerMike Karels <karels@ucbvax.Berkeley.EDU>
Mon, 21 Apr 1986 14:34:38 +0000 (06:34 -0800)
where subnets don't go, and allow external routes from /etc/gateways
to block routed from installing routes from elsewhere

SCCS-vsn: sbin/routed/af.c 5.4
SCCS-vsn: sbin/routed/af.h 5.3
SCCS-vsn: sbin/routed/if.c 5.3
SCCS-vsn: sbin/routed/inet.c 5.2
SCCS-vsn: sbin/routed/input.c 5.4
SCCS-vsn: sbin/routed/interface.h 5.3
SCCS-vsn: sbin/routed/main.c 5.7
SCCS-vsn: sbin/routed/output.c 5.2
SCCS-vsn: sbin/routed/startup.c 5.4
SCCS-vsn: sbin/routed/table.h 5.2
SCCS-vsn: sbin/routed/tables.c 5.3

usr/src/sbin/routed/af.c
usr/src/sbin/routed/af.h
usr/src/sbin/routed/if.c
usr/src/sbin/routed/inet.c
usr/src/sbin/routed/input.c
usr/src/sbin/routed/interface.h
usr/src/sbin/routed/main.c
usr/src/sbin/routed/output.c
usr/src/sbin/routed/startup.c
usr/src/sbin/routed/table.h
usr/src/sbin/routed/tables.c

index a6e0257..67d273e 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)af.c       5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)af.c       5.4 (Berkeley) %G%";
 #endif not lint
 
 #include "defs.h"
 #endif not lint
 
 #include "defs.h"
@@ -15,16 +15,22 @@ static char sccsid[] = "@(#)af.c    5.3 (Berkeley) %G%";
  */
 int    inet_hash(), inet_netmatch(), inet_output(),
        inet_portmatch(), inet_portcheck(),
  */
 int    inet_hash(), inet_netmatch(), inet_output(),
        inet_portmatch(), inet_portcheck(),
-       inet_checkhost(), inet_ishost(), inet_canon();
+       inet_checkhost(), inet_rtflags(), inet_sendsubnet(), inet_canon();
 char   *inet_format();
 char   *inet_format();
+
 #define NIL    { 0 }
 #define        INET \
        { inet_hash,            inet_netmatch,          inet_output, \
          inet_portmatch,       inet_portcheck,         inet_checkhost, \
 #define NIL    { 0 }
 #define        INET \
        { inet_hash,            inet_netmatch,          inet_output, \
          inet_portmatch,       inet_portcheck,         inet_checkhost, \
-         inet_ishost,          inet_canon,             inet_format }
+         inet_rtflags,         inet_sendsubnet,        inet_canon, \
+         inet_format \
+       }
 
 
-struct afswitch afswitch[AF_MAX] =
-       { NIL, NIL, INET, };
+struct afswitch afswitch[AF_MAX] = {
+       NIL,            /* 0- unused */
+       NIL,            /* 1- Unix domain, unused */
+       INET,           /* Internet */
+};
 
 int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
 
 
 int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
 
@@ -111,17 +117,6 @@ inet_checkhost(sin)
        return (1);
 }
 
        return (1);
 }
 
-/*
- * Return 1 if the address is
- * for an Internet host, 0 for a network.
- */
-inet_ishost(sin)
-       struct sockaddr_in *sin;
-{
-
-       return (inet_lnaof(sin->sin_addr) != 0);
-}
-
 inet_canon(sin)
        struct sockaddr_in *sin;
 {
 inet_canon(sin)
        struct sockaddr_in *sin;
 {
index ac8ceff..b9b825f 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)af.h        5.2 (Berkeley) %G%
+ *     @(#)af.h        5.3 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -19,8 +19,9 @@ struct afswitch {
        int     (*af_output)();         /* interprets address for sending */
        int     (*af_portmatch)();      /* packet from some other router? */
        int     (*af_portcheck)();      /* packet from privileged peer? */
        int     (*af_output)();         /* interprets address for sending */
        int     (*af_portmatch)();      /* packet from some other router? */
        int     (*af_portcheck)();      /* packet from privileged peer? */
-       int     (*af_checkhost)();      /* tells if address for host or net */
-       int     (*af_ishost)();         /* tells if address is valid */
+       int     (*af_checkhost)();      /* tells if address is valid */
+       int     (*af_rtflags)();        /* get flags for route (host or net) */
+       int     (*af_sendsubnet)();     /* check bounds of subnet broadcast */
        int     (*af_canon)();          /* canonicalize address for compares */
        char    *(*af_format)();        /* convert address to string */
 };
        int     (*af_canon)();          /* canonicalize address for compares */
        char    *(*af_format)();        /* convert address to string */
 };
index dc2fd5c..6f49efb 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)if.c       5.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)if.c       5.3 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -109,6 +109,9 @@ if_iflookup(addr)
                if ((ifp->int_flags & IFF_BROADCAST) &&
                    same(&ifp->int_broadaddr, addr))
                        break;
                if ((ifp->int_flags & IFF_BROADCAST) &&
                    same(&ifp->int_broadaddr, addr))
                        break;
+               if ((ifp->int_flags & IFF_POINTOPOINT) &&
+                   same(&ifp->int_dstaddr, addr))
+                       break;
                if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
                        maybe = ifp;
        }
                if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
                        maybe = ifp;
        }
index 4514725..3e688cb 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)inet.c     5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)inet.c     5.2 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -100,3 +100,68 @@ inet_lnaof(in)
                        return (host &~ ifp->int_subnetmask);
        return (host);
 }
                        return (host &~ ifp->int_subnetmask);
        return (host);
 }
+
+/*
+ * Return RTF_HOST if the address is
+ * for an Internet host, RTF_SUBNET for a subnet,
+ * 0 for a network.
+ */
+inet_rtflags(sin)
+       struct sockaddr_in *sin;
+{
+       register u_long i = ntohl(sin->sin_addr.s_addr);
+       register u_long net, host;
+       register struct interface *ifp;
+
+       if (IN_CLASSA(i)) {
+               net = i & IN_CLASSA_NET;
+               host = i & IN_CLASSA_HOST;
+       } else if (IN_CLASSB(i)) {
+               net = i & IN_CLASSB_NET;
+               host = i & IN_CLASSB_HOST;
+       } else {
+               net = i & IN_CLASSC_NET;
+               host = i & IN_CLASSC_HOST;
+       }
+
+       if (host == 0)
+               return (0);     /* network */
+       /*
+        * Check whether this network is subnetted;
+        * if so, check whether this is a subnet or a host.
+        */
+       for (ifp = ifnet; ifp; ifp = ifp->int_next)
+               if (net == ifp->int_net) {
+                       if ((host &~ ifp->int_subnetmask) == 0)
+                               return (RTF_SUBNET);
+                       else
+                               return (RTF_HOST);
+               }
+       return (RTF_HOST);
+}
+
+/*
+ * Return true if a route to subnet rtsin should be sent to dst.
+ * Send it only if dst is on the same logical network,
+ * or the route turns out to be for the net (aka subnet 0).
+ */
+inet_sendsubnet(rtsin, dst)
+       struct sockaddr_in *rtsin, *dst;
+{
+       register u_long rt = ntohl(rtsin->sin_addr.s_addr);
+       register u_long d = ntohl(dst->sin_addr.s_addr);
+
+       if (IN_CLASSA(rt)) {
+               if ((rt & IN_CLASSA_HOST) == 0)
+                       return (1);
+               return ((rt & IN_CLASSA_NET) == (d & IN_CLASSA_NET));
+       } else if (IN_CLASSB(rt)) {
+               if ((rt & IN_CLASSB_HOST) == 0)
+                       return (1);
+               return ((rt & IN_CLASSB_NET) == (d & IN_CLASSB_NET));
+       } else {
+               if ((rt & IN_CLASSC_HOST) == 0)
+                       return (1);
+               return ((rt & IN_CLASSC_NET) == (d & IN_CLASSC_NET));
+       }
+}
index 035ecf6..42da57c 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)input.c    5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)input.c    5.4 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -63,7 +63,7 @@ rip_input(from, size)
                        if (n->rip_dst.sa_family == AF_UNSPEC &&
                            n->rip_metric == HOPCNT_INFINITY && size == 0) {
                                if (supplier || (*afp->af_portmatch)(from) == 0)
                        if (n->rip_dst.sa_family == AF_UNSPEC &&
                            n->rip_metric == HOPCNT_INFINITY && size == 0) {
                                if (supplier || (*afp->af_portmatch)(from) == 0)
-                                       supply(from, 0, ifp);
+                                       supply(from, 0, 0);
                                return;
                        }
                        if (n->rip_dst.sa_family < af_max &&
                                return;
                        }
                        if (n->rip_dst.sa_family < af_max &&
index 2c3e5ac..857728a 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)interface.h 5.2 (Berkeley) %G%
+ *     @(#)interface.h 5.3 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -52,10 +52,12 @@ struct interface {
 #define        IFF_LOOPBACK    0x8             /* software loopback net */
 #define        IFF_POINTOPOINT 0x10            /* interface is point-to-point link */
 
 #define        IFF_LOOPBACK    0x8             /* software loopback net */
 #define        IFF_POINTOPOINT 0x10            /* interface is point-to-point link */
 
+#define        IFF_SUBNET      0x1000          /* interface on subnetted network */
 #define        IFF_PASSIVE     0x2000          /* can't tell if up/down */
 #define        IFF_INTERFACE   0x4000          /* hardware interface */
 #define        IFF_REMOTE      0x8000          /* interface isn't on this machine */
 
 struct interface *if_ifwithaddr();
 #define        IFF_PASSIVE     0x2000          /* can't tell if up/down */
 #define        IFF_INTERFACE   0x4000          /* hardware interface */
 #define        IFF_REMOTE      0x8000          /* interface isn't on this machine */
 
 struct interface *if_ifwithaddr();
+struct interface *if_ifwithdstaddr();
 struct interface *if_ifwithnet();
 struct interface *if_iflookup();
 struct interface *if_ifwithnet();
 struct interface *if_iflookup();
index 9c766eb..a4608bc 100644 (file)
@@ -11,7 +11,7 @@ char copyright[] =
 #endif not lint
 
 #ifndef lint
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.6 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     5.7 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -24,7 +24,6 @@ static char sccsid[] = "@(#)main.c    5.6 (Berkeley) %G%";
 #include <net/if.h>
 
 #include <errno.h>
 #include <net/if.h>
 
 #include <errno.h>
-#include <nlist.h>
 #include <signal.h>
 #include <syslog.h>
 
 #include <signal.h>
 #include <syslog.h>
 
index 530235b..09ec259 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)output.c   5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)output.c   5.2 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -68,12 +68,33 @@ supply(dst, flags, ifp)
        struct rthash *base = hosthash;
        int doinghost = 1, size;
        int (*output)() = afswitch[dst->sa_family].af_output;
        struct rthash *base = hosthash;
        int doinghost = 1, size;
        int (*output)() = afswitch[dst->sa_family].af_output;
+       int (*sendsubnet)() = afswitch[dst->sa_family].af_sendsubnet;
 
        msg->rip_cmd = RIPCMD_RESPONSE;
        msg->rip_vers = RIPVERSION;
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
 
        msg->rip_cmd = RIPCMD_RESPONSE;
        msg->rip_vers = RIPVERSION;
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+               /*
+                * Don't resend the information
+                * on the network from which it was received.
+                */
+               if (ifp && rt->rt_ifp == ifp)
+                       continue;
+               if (rt->rt_state & RTS_EXTERNAL)
+                       continue;
+               /*
+                * Limit the spread of subnet information
+                * to those who are interested.
+                */
+               if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
+                       if (ifp && (ifp->int_flags & IFF_SUBNET) == 0)
+                               continue;
+                       if (rt->rt_dst.sa_family != dst->sa_family)
+                               continue;
+                       if ((*sendsubnet)(&rt->rt_dst, dst) == 0)
+                               continue;
+               }
                size = (char *)n - packet;
                if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
                        (*output)(s, flags, dst, size);
                size = (char *)n - packet;
                if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
                        (*output)(s, flags, dst, size);
index 6438276..5f4d244 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)startup.c  5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)startup.c  5.4 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -14,12 +14,10 @@ static char sccsid[] = "@(#)startup.c       5.3 (Berkeley) %G%";
 #include "defs.h"
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include "defs.h"
 #include <sys/ioctl.h>
 #include <net/if.h>
-#include <nlist.h>
 #include <syslog.h>
 
 struct interface *ifnet;
 int    lookforinterfaces = 1;
 #include <syslog.h>
 
 struct interface *ifnet;
 int    lookforinterfaces = 1;
-int    performnlist = 1;
 int    externalinterfaces = 0;         /* # of remote and local interfaces */
 
 /*
 int    externalinterfaces = 0;         /* # of remote and local interfaces */
 
 /*
@@ -108,6 +106,8 @@ ifinit()
                        ifs.int_netmask = IN_CLASSC_NET;
                ifs.int_net = i & ifs.int_netmask;
                ifs.int_subnet = i & ifs.int_subnetmask;
                        ifs.int_netmask = IN_CLASSC_NET;
                ifs.int_net = i & ifs.int_netmask;
                ifs.int_subnet = i & ifs.int_subnetmask;
+               if (ifs.int_subnetmask != ifs.int_netmask)
+                       ifs.int_flags |= IFF_SUBNET;
                ifp = (struct interface *)malloc(sizeof (struct interface));
                if (ifp == 0) {
                        printf("routed: out of memory\n");
                ifp = (struct interface *)malloc(sizeof (struct interface));
                if (ifp == 0) {
                        printf("routed: out of memory\n");
@@ -153,6 +153,12 @@ bad:
        _exit(0177);
 }
 
        _exit(0177);
 }
 
+/*
+ * Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ * INTERNET SPECIFIC.
+ */
 addrouteforif(ifp)
        struct interface *ifp;
 {
 addrouteforif(ifp)
        struct interface *ifp;
 {
@@ -177,7 +183,22 @@ addrouteforif(ifp)
        if (ifp->int_transitions++ > 0)
                syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
        rtadd(dst, &ifp->int_addr, ifp->int_metric,
        if (ifp->int_transitions++ > 0)
                syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
        rtadd(dst, &ifp->int_addr, ifp->int_metric,
-               ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
+           ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE|IFF_SUBNET));
+
+       /*
+        * If interface on subnetted network,
+        * install route to network as well.
+        * This is meant for external viewers.
+        */
+       if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
+               net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+               rt = rtfind(dst);
+               if (rt && (rt->rt_state & RTS_INTERFACE))
+                       return;
+               rtadd(dst, &ifp->int_addr, ifp->int_metric,
+                   (ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE) |
+                       RTS_INTERNAL));
+       }
 }
 
 /*
 }
 
 /*
@@ -241,6 +262,16 @@ gwkludge()
                        (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
                        continue;
                }
                        (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
                        continue;
                }
+               if (strcmp(qual, "external") == 0) {
+                       /*
+                        * Entries marked external are handled
+                        * by other means, e.g. EGP,
+                        * and are placed in our tables only
+                        * to prevent overriding them
+                        * with something else.
+                        */
+                       rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
+               }
                /* assume no duplicate entries */
                externalinterfaces++;
                ifp = (struct interface *)malloc(sizeof (*ifp));
                /* assume no duplicate entries */
                externalinterfaces++;
                ifp = (struct interface *)malloc(sizeof (*ifp));
index e2379de..0664e9e 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)table.h     5.1 (Berkeley) %G%
+ *     @(#)table.h     5.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -56,9 +56,17 @@ struct rt_entry {
  * "State" of routing table entry.
  */
 #define        RTS_CHANGED     0x1             /* route has been altered recently */
  * "State" of routing table entry.
  */
 #define        RTS_CHANGED     0x1             /* route has been altered recently */
+#define        RTS_EXTERNAL    0x2             /* extern info, not installed or sent */
+#define        RTS_INTERNAL    0x4             /* internal route, not installed */
 #define        RTS_PASSIVE     IFF_PASSIVE     /* don't time out route */
 #define        RTS_INTERFACE   IFF_INTERFACE   /* route is for network interface */
 #define        RTS_REMOTE      IFF_REMOTE      /* route is for ``remote'' entity */
 #define        RTS_PASSIVE     IFF_PASSIVE     /* don't time out route */
 #define        RTS_INTERFACE   IFF_INTERFACE   /* route is for network interface */
 #define        RTS_REMOTE      IFF_REMOTE      /* route is for ``remote'' entity */
+#define        RTS_SUBNET      IFF_SUBNET      /* route is for network subnet */
+
+/*
+ * Flags are same as kernel, with this addition for af_rtflags:
+ */
+#define        RTF_SUBNET      0x8000          /* pseudo: route to subnet */
 
 struct rthash nethash[ROUTEHASHSIZ];
 struct rthash hosthash[ROUTEHASHSIZ];
 
 struct rthash nethash[ROUTEHASHSIZ];
 struct rthash hosthash[ROUTEHASHSIZ];
index 364f5fb..60a7b7f 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)tables.c   5.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)tables.c   5.3 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -112,7 +112,14 @@ rtadd(dst, gate, metric, state)
        if (af >= af_max)
                return;
        (*afswitch[af].af_hash)(dst, &h);
        if (af >= af_max)
                return;
        (*afswitch[af].af_hash)(dst, &h);
-       flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
+       flags = (*afswitch[af].af_rtflags)(dst);
+       /*
+        * Subnet flag isn't visible to kernel, move to state.  XXX
+        */
+       if (flags & RTF_SUBNET) {
+               state |= RTS_SUBNET;
+               flags &= ~RTF_SUBNET;
+       }
        if (flags & RTF_HOST) {
                hash = h.afh_hosthash;
                rh = &hosthash[hash & ROUTEHASHMASK];
        if (flags & RTF_HOST) {
                hash = h.afh_hosthash;
                rh = &hosthash[hash & ROUTEHASHMASK];
@@ -130,7 +137,9 @@ rtadd(dst, gate, metric, state)
        rt->rt_timer = 0;
        rt->rt_flags = RTF_UP | flags;
        rt->rt_state = state | RTS_CHANGED;
        rt->rt_timer = 0;
        rt->rt_flags = RTF_UP | flags;
        rt->rt_state = state | RTS_CHANGED;
-       rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+       rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+       if (rt->rt_ifp == 0)
+               rt->rt_ifp = if_ifwithnet(&rt->rt_router);
        if (metric)
                rt->rt_flags |= RTF_GATEWAY;
        insque(rt, rh);
        if (metric)
                rt->rt_flags |= RTF_GATEWAY;
        insque(rt, rh);
@@ -140,7 +149,8 @@ rtadd(dst, gate, metric, state)
         * from this host, discard the entry.  This should only
         * occur because of an incorrect entry in /etc/gateways.
         */
         * from this host, discard the entry.  This should only
         * occur because of an incorrect entry in /etc/gateways.
         */
-       if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
+       if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+           ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
                perror("SIOCADDRT");
                if (errno == ENETUNREACH) {
                        TRACE_ACTION(DELETE, rt);
                perror("SIOCADDRT");
                if (errno == ENETUNREACH) {
                        TRACE_ACTION(DELETE, rt);
@@ -158,7 +168,7 @@ rtchange(rt, gate, metric)
        int doioctl = 0, metricchanged = 0;
        struct rtentry oldroute;
 
        int doioctl = 0, metricchanged = 0;
        struct rtentry oldroute;
 
-       if (!equal(&rt->rt_router, gate))
+       if (!equal(&rt->rt_router, gate) && (rt->rt_state & RTS_INTERNAL) == 0)
                doioctl++;
        if (metric != rt->rt_metric)
                metricchanged++;
                doioctl++;
        if (metric != rt->rt_metric)
                metricchanged++;
@@ -167,6 +177,9 @@ rtchange(rt, gate, metric)
                if (doioctl) {
                        oldroute = rt->rt_rt;
                        rt->rt_router = *gate;
                if (doioctl) {
                        oldroute = rt->rt_rt;
                        rt->rt_router = *gate;
+                       rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+                       if (rt->rt_ifp == 0)
+                               rt->rt_ifp = if_ifwithnet(&rt->rt_router);
                }
                rt->rt_metric = metric;
                if ((rt->rt_state & RTS_INTERFACE) && metric) {
                }
                rt->rt_metric = metric;
                if ((rt->rt_state & RTS_INTERFACE) && metric) {
@@ -198,7 +211,8 @@ rtdelete(rt)
                syslog(LOG_ERR, "deleting route to interface %s (timed out)",
                        rt->rt_ifp->int_name);
        TRACE_ACTION(DELETE, rt);
                syslog(LOG_ERR, "deleting route to interface %s (timed out)",
                        rt->rt_ifp->int_name);
        TRACE_ACTION(DELETE, rt);
-       if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+       if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL) == 0) &&
+           ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
                perror("SIOCDELRT");
        remque(rt);
        free((char *)rt);
                perror("SIOCDELRT");
        remque(rt);
        free((char *)rt);
@@ -213,26 +227,10 @@ rtdelete(rt)
  */
 rtdefault()
 {
  */
 rtdefault()
 {
-       struct afhash h;
-       register struct rt_entry *rt;
-       struct rthash *rh;
        extern struct sockaddr inet_default;
 
        extern struct sockaddr inet_default;
 
-       rt = (struct rt_entry *)malloc(sizeof (*rt));
-       if (rt == 0)
-               return;
-       rt->rt_dst = inet_default;
-       rt->rt_router = rt->rt_dst;
-       (*afswitch[AF_INET].af_hash)(&rt->rt_dst, &h);
-       rh = &nethash[h.afh_nethash & ROUTEHASHMASK];
-       rt->rt_hash = h.afh_nethash;
-       rt->rt_metric = 0;
-       rt->rt_timer = 0;
-       rt->rt_flags = RTF_UP | RTF_GATEWAY;
-       rt->rt_state = RTS_CHANGED | RTS_PASSIVE;
-       rt->rt_ifp = 0;
-       insque(rt, rh);
-       TRACE_ACTION(ADD, rt);
+       rtadd(&inet_default, &inet_default, 0,
+               RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
 }
 
 rtinit()
 }
 
 rtinit()