From: Mike Karels Date: Mon, 21 Apr 1986 14:34:38 +0000 (-0800) Subject: changes to allow subnets to remain local, propogate net route X-Git-Tag: BSD-4_3-Snapshot-Development~2691 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/4fad5a6eeb6297fea5e2a7c10ee0fe5db9cd1192 changes to allow subnets to remain local, propogate net route 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 --- diff --git a/usr/src/sbin/routed/af.c b/usr/src/sbin/routed/af.c index a6e02577f9..67d273e69e 100644 --- a/usr/src/sbin/routed/af.c +++ b/usr/src/sbin/routed/af.c @@ -5,7 +5,7 @@ */ #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" @@ -15,16 +15,22 @@ static char sccsid[] = "@(#)af.c 5.3 (Berkeley) %G%"; */ 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(); + #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]); @@ -111,17 +117,6 @@ inet_checkhost(sin) 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; { diff --git a/usr/src/sbin/routed/af.h b/usr/src/sbin/routed/af.h index ac8ceff595..b9b825f1ea 100644 --- a/usr/src/sbin/routed/af.h +++ b/usr/src/sbin/routed/af.h @@ -3,7 +3,7 @@ * 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_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 */ }; diff --git a/usr/src/sbin/routed/if.c b/usr/src/sbin/routed/if.c index dc2fd5ce4f..6f49efbeb2 100644 --- a/usr/src/sbin/routed/if.c +++ b/usr/src/sbin/routed/if.c @@ -5,7 +5,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)if.c 5.2 (Berkeley) %G%"; +static char sccsid[] = "@(#)if.c 5.3 (Berkeley) %G%"; #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_POINTOPOINT) && + same(&ifp->int_dstaddr, addr)) + break; if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr)) maybe = ifp; } diff --git a/usr/src/sbin/routed/inet.c b/usr/src/sbin/routed/inet.c index 4514725608..3e688cbbf4 100644 --- a/usr/src/sbin/routed/inet.c +++ b/usr/src/sbin/routed/inet.c @@ -5,7 +5,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)inet.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)inet.c 5.2 (Berkeley) %G%"; #endif not lint /* @@ -100,3 +100,68 @@ inet_lnaof(in) 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)); + } +} diff --git a/usr/src/sbin/routed/input.c b/usr/src/sbin/routed/input.c index 035ecf6aec..42da57cb9a 100644 --- a/usr/src/sbin/routed/input.c +++ b/usr/src/sbin/routed/input.c @@ -5,7 +5,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)input.c 5.3 (Berkeley) %G%"; +static char sccsid[] = "@(#)input.c 5.4 (Berkeley) %G%"; #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) - supply(from, 0, ifp); + supply(from, 0, 0); return; } if (n->rip_dst.sa_family < af_max && diff --git a/usr/src/sbin/routed/interface.h b/usr/src/sbin/routed/interface.h index 2c3e5ac6d6..857728a0a1 100644 --- a/usr/src/sbin/routed/interface.h +++ b/usr/src/sbin/routed/interface.h @@ -3,7 +3,7 @@ * 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_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(); +struct interface *if_ifwithdstaddr(); struct interface *if_ifwithnet(); struct interface *if_iflookup(); diff --git a/usr/src/sbin/routed/main.c b/usr/src/sbin/routed/main.c index 9c766eb391..a4608bcb27 100644 --- a/usr/src/sbin/routed/main.c +++ b/usr/src/sbin/routed/main.c @@ -11,7 +11,7 @@ char copyright[] = #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 /* @@ -24,7 +24,6 @@ static char sccsid[] = "@(#)main.c 5.6 (Berkeley) %G%"; #include #include -#include #include #include diff --git a/usr/src/sbin/routed/output.c b/usr/src/sbin/routed/output.c index 530235b3e4..09ec259ca6 100644 --- a/usr/src/sbin/routed/output.c +++ b/usr/src/sbin/routed/output.c @@ -5,7 +5,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)output.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)output.c 5.2 (Berkeley) %G%"; #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; + 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) { + /* + * 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); diff --git a/usr/src/sbin/routed/startup.c b/usr/src/sbin/routed/startup.c index 6438276a29..5f4d24424f 100644 --- a/usr/src/sbin/routed/startup.c +++ b/usr/src/sbin/routed/startup.c @@ -5,7 +5,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)startup.c 5.3 (Berkeley) %G%"; +static char sccsid[] = "@(#)startup.c 5.4 (Berkeley) %G%"; #endif not lint /* @@ -14,12 +14,10 @@ static char sccsid[] = "@(#)startup.c 5.3 (Berkeley) %G%"; #include "defs.h" #include #include -#include #include struct interface *ifnet; int lookforinterfaces = 1; -int performnlist = 1; 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; + 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"); @@ -153,6 +153,12 @@ bad: _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; { @@ -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, - 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; } + 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)); diff --git a/usr/src/sbin/routed/table.h b/usr/src/sbin/routed/table.h index e2379ded03..0664e9e329 100644 --- a/usr/src/sbin/routed/table.h +++ b/usr/src/sbin/routed/table.h @@ -3,7 +3,7 @@ * 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 */ +#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_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]; diff --git a/usr/src/sbin/routed/tables.c b/usr/src/sbin/routed/tables.c index 364f5fbe06..60a7b7f627 100644 --- a/usr/src/sbin/routed/tables.c +++ b/usr/src/sbin/routed/tables.c @@ -5,7 +5,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)tables.c 5.2 (Berkeley) %G%"; +static char sccsid[] = "@(#)tables.c 5.3 (Berkeley) %G%"; #endif not lint /* @@ -112,7 +112,14 @@ rtadd(dst, gate, metric, state) 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]; @@ -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_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); @@ -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. */ - 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); @@ -158,7 +168,7 @@ rtchange(rt, gate, metric) 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++; @@ -167,6 +177,9 @@ rtchange(rt, gate, metric) 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) { @@ -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); - 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); @@ -213,26 +227,10 @@ rtdelete(rt) */ rtdefault() { - struct afhash h; - register struct rt_entry *rt; - struct rthash *rh; 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()