aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/routed
diff options
context:
space:
mode:
authorRodney W. Grimes <rgrimes@FreeBSD.org>1994-05-26 06:39:07 +0000
committerRodney W. Grimes <rgrimes@FreeBSD.org>1994-05-26 06:39:07 +0000
commit3219c922a9b5bb60c7773ad93345d871bce72a68 (patch)
tree8dcfc04937aae7801351ea404d5b58eda94c65b1 /usr.sbin/routed
parent8fae3551ec46402adf7ab034cf9e02bcbc7ca8ee (diff)
downloadsrc-3219c922a9b5bb60c7773ad93345d871bce72a68.tar.gz
src-3219c922a9b5bb60c7773ad93345d871bce72a68.zip
BSD 4.4 Lite sbin -> usr.sbin Sources
Note: The sources for XNSrouted and routed are being imported to usr.sbin instead of sbin.
Notes
Notes: svn path=/vendor/CSRG/dist/; revision=1560
Diffstat (limited to 'usr.sbin/routed')
-rw-r--r--usr.sbin/routed/Makefile22
-rw-r--r--usr.sbin/routed/af.c171
-rw-r--r--usr.sbin/routed/af.h65
-rw-r--r--usr.sbin/routed/defs.h103
-rw-r--r--usr.sbin/routed/if.c148
-rw-r--r--usr.sbin/routed/inet.c243
-rw-r--r--usr.sbin/routed/input.c362
-rw-r--r--usr.sbin/routed/interface.h90
-rw-r--r--usr.sbin/routed/main.c351
-rw-r--r--usr.sbin/routed/output.c172
-rw-r--r--usr.sbin/routed/pathnames.h38
-rw-r--r--usr.sbin/routed/query/Makefile7
-rw-r--r--usr.sbin/routed/query/query.c294
-rw-r--r--usr.sbin/routed/routed.8358
-rw-r--r--usr.sbin/routed/startup.c515
-rw-r--r--usr.sbin/routed/table.h108
-rw-r--r--usr.sbin/routed/tables.c428
-rw-r--r--usr.sbin/routed/timer.c127
-rw-r--r--usr.sbin/routed/trace.c426
-rw-r--r--usr.sbin/routed/trace.h96
-rw-r--r--usr.sbin/routed/trace/Makefile7
-rw-r--r--usr.sbin/routed/trace/trace.c125
22 files changed, 4256 insertions, 0 deletions
diff --git a/usr.sbin/routed/Makefile b/usr.sbin/routed/Makefile
new file mode 100644
index 000000000000..d9dd7f8f7ada
--- /dev/null
+++ b/usr.sbin/routed/Makefile
@@ -0,0 +1,22 @@
+# @(#)Makefile 8.1 (Berkeley) 6/19/93
+
+PROG= routed
+SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c \
+ trace.c inet.c
+MAN8= routed.0
+#SUBDIR= query trace
+DPADD= ${LIBCOMPAT}
+LDADD= -lcompat
+
+.include <bsd.prog.mk>
+
+.if (${MACHINE} == "vax")
+# The following can be deleted where not appropriate to use the kernel's
+# inline code expansions.
+INLINE= /sys/vax/inline/obj/inline
+C2= /usr/libexec/c2
+.c.o:
+ ${CC} -S ${CFLAGS} ${.CURDIR}/${.PREFIX}.c
+ @${C2} ${.PREFIX}.s | ${INLINE} | ${AS} -o ${.PREFIX}.o
+ @rm -f ${.PREFIX}.s
+.endif
diff --git a/usr.sbin/routed/af.c b/usr.sbin/routed/af.c
new file mode 100644
index 000000000000..05bf8fab805e
--- /dev/null
+++ b/usr.sbin/routed/af.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)af.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include "defs.h"
+
+/*
+ * Address family support routines
+ */
+int inet_hash(), inet_netmatch(), inet_output(),
+ inet_portmatch(), inet_portcheck(),
+ inet_checkhost(), inet_rtflags(), inet_sendroute(), inet_canon();
+char *inet_format();
+
+#define NIL { 0 }
+#define INET \
+ { inet_hash, inet_netmatch, inet_output, \
+ inet_portmatch, inet_portcheck, inet_checkhost, \
+ inet_rtflags, inet_sendroute, inet_canon, \
+ inet_format \
+ }
+
+struct afswitch afswitch[AF_MAX] = {
+ NIL, /* 0- unused */
+ NIL, /* 1- Unix domain, unused */
+ INET, /* Internet */
+};
+
+int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
+
+struct sockaddr_in inet_default = {
+#ifdef RTM_ADD
+ sizeof (inet_default),
+#endif
+ AF_INET, INADDR_ANY };
+
+inet_hash(sin, hp)
+ register struct sockaddr_in *sin;
+ struct afhash *hp;
+{
+ register u_long n;
+
+ n = inet_netof(sin->sin_addr);
+ if (n)
+ while ((n & 0xff) == 0)
+ n >>= 8;
+ hp->afh_nethash = n;
+ hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
+ hp->afh_hosthash &= 0x7fffffff;
+}
+
+inet_netmatch(sin1, sin2)
+ struct sockaddr_in *sin1, *sin2;
+{
+
+ return (inet_netof(sin1->sin_addr) == inet_netof(sin2->sin_addr));
+}
+
+/*
+ * Verify the message is from the right port.
+ */
+inet_portmatch(sin)
+ register struct sockaddr_in *sin;
+{
+
+ return (sin->sin_port == sp->s_port);
+}
+
+/*
+ * Verify the message is from a "trusted" port.
+ */
+inet_portcheck(sin)
+ struct sockaddr_in *sin;
+{
+
+ return (ntohs(sin->sin_port) <= IPPORT_RESERVED);
+}
+
+/*
+ * Internet output routine.
+ */
+inet_output(s, flags, sin, size)
+ int s, flags;
+ struct sockaddr_in *sin;
+ int size;
+{
+ struct sockaddr_in dst;
+
+ dst = *sin;
+ sin = &dst;
+ if (sin->sin_port == 0)
+ sin->sin_port = sp->s_port;
+ if (sin->sin_len == 0)
+ sin->sin_len = sizeof (*sin);
+ if (sendto(s, packet, size, flags,
+ (struct sockaddr *)sin, sizeof (*sin)) < 0)
+ perror("sendto");
+}
+
+/*
+ * Return 1 if the address is believed
+ * for an Internet host -- THIS IS A KLUDGE.
+ */
+inet_checkhost(sin)
+ struct sockaddr_in *sin;
+{
+ u_long i = ntohl(sin->sin_addr.s_addr);
+
+#ifndef IN_EXPERIMENTAL
+#define IN_EXPERIMENTAL(i) (((long) (i) & 0xe0000000) == 0xe0000000)
+#endif
+
+ if (IN_EXPERIMENTAL(i) || sin->sin_port != 0)
+ return (0);
+ if (i != 0 && (i & 0xff000000) == 0)
+ return (0);
+ for (i = 0; i < sizeof(sin->sin_zero)/sizeof(sin->sin_zero[0]); i++)
+ if (sin->sin_zero[i])
+ return (0);
+ return (1);
+}
+
+inet_canon(sin)
+ struct sockaddr_in *sin;
+{
+
+ sin->sin_port = 0;
+ sin->sin_len = sizeof(*sin);
+}
+
+char *
+inet_format(sin)
+ struct sockaddr_in *sin;
+{
+ char *inet_ntoa();
+
+ return (inet_ntoa(sin->sin_addr));
+}
diff --git a/usr.sbin/routed/af.h b/usr.sbin/routed/af.h
new file mode 100644
index 000000000000..2fff298bbcb0
--- /dev/null
+++ b/usr.sbin/routed/af.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)af.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Per address family routines.
+ */
+struct afswitch {
+ int (*af_hash)(); /* returns keys based on address */
+ int (*af_netmatch)(); /* verifies net # matching */
+ 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 is valid */
+ int (*af_rtflags)(); /* get flags for route (host or net) */
+ int (*af_sendroute)(); /* check bounds of subnet broadcast */
+ int (*af_canon)(); /* canonicalize address for compares */
+ char *(*af_format)(); /* convert address to string */
+};
+
+/*
+ * Structure returned by af_hash routines.
+ */
+struct afhash {
+ u_int afh_hosthash; /* host based hash */
+ u_int afh_nethash; /* network based hash */
+};
+
+extern struct afswitch afswitch[]; /* table proper */
+extern int af_max; /* number of entries in table */
diff --git a/usr.sbin/routed/defs.h b/usr.sbin/routed/defs.h
new file mode 100644
index 000000000000..5b5ccacbf2f9
--- /dev/null
+++ b/usr.sbin/routed/defs.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Internal data structure definitions for
+ * user routing process. Based on Xerox NS
+ * protocol specs with mods relevant to more
+ * general addressing scheme.
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+
+#include <stdio.h>
+#include <netdb.h>
+
+#include "trace.h"
+#include "interface.h"
+#include "table.h"
+#include "af.h"
+
+/*
+ * When we find any interfaces marked down we rescan the
+ * kernel every CHECK_INTERVAL seconds to see if they've
+ * come up.
+ */
+#define CHECK_INTERVAL (1*60)
+
+#define equal(a1, a2) \
+ (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
+
+struct sockaddr_in addr; /* address of daemon's socket */
+
+int s; /* source and sink of all data */
+int r; /* routing socket */
+pid_t pid; /* process id for identifying messages */
+uid_t uid; /* user id for identifying messages */
+int seqno; /* sequence number for identifying messages */
+int kmem;
+int supplier; /* process should supply updates */
+int install; /* if 1 call kernel */
+int lookforinterfaces; /* if 1 probe kernel for new up interfaces */
+int performnlist; /* if 1 check if /vmunix has changed */
+int externalinterfaces; /* # of remote and local interfaces */
+struct timeval now; /* current idea of time */
+struct timeval lastbcast; /* last time all/changes broadcast */
+struct timeval lastfullupdate; /* last time full table broadcast */
+struct timeval nextbcast; /* time to wait before changes broadcast */
+int needupdate; /* true if we need update at nextbcast */
+
+char packet[MAXPACKETSIZE+1];
+struct rip *msg;
+
+char **argv0;
+struct servent *sp;
+
+struct in_addr inet_makeaddr();
+int inet_addr();
+int inet_maskof();
+int sndmsg();
+int supply();
+int cleanup();
+
+int rtioctl();
+#define ADD 1
+#define DELETE 2
+#define CHANGE 3
diff --git a/usr.sbin/routed/if.c b/usr.sbin/routed/if.c
new file mode 100644
index 000000000000..54e8705c7699
--- /dev/null
+++ b/usr.sbin/routed/if.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Find the interface with address addr.
+ */
+struct interface *
+if_ifwithaddr(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp;
+
+#define same(a1, a2) \
+ (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_REMOTE)
+ continue;
+ if (ifp->int_addr.sa_family != addr->sa_family)
+ continue;
+ if (same(&ifp->int_addr, addr))
+ break;
+ if ((ifp->int_flags & IFF_BROADCAST) &&
+ same(&ifp->int_broadaddr, addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find the point-to-point interface with destination address addr.
+ */
+struct interface *
+if_ifwithdstaddr(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if ((ifp->int_flags & IFF_POINTOPOINT) == 0)
+ continue;
+ if (same(&ifp->int_dstaddr, addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find the interface on the network
+ * of the specified address.
+ */
+struct interface *
+if_ifwithnet(addr)
+ register struct sockaddr *addr;
+{
+ register struct interface *ifp;
+ register int af = addr->sa_family;
+ register int (*netmatch)();
+
+ if (af >= af_max)
+ return (0);
+ netmatch = afswitch[af].af_netmatch;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_REMOTE)
+ continue;
+ if (af != ifp->int_addr.sa_family)
+ continue;
+ if ((*netmatch)(addr, &ifp->int_addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find an interface from which the specified address
+ * should have come from. Used for figuring out which
+ * interface a packet came in on -- for tracing.
+ */
+struct interface *
+if_iflookup(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp, *maybe;
+ register int af = addr->sa_family;
+ register int (*netmatch)();
+
+ if (af >= af_max)
+ return (0);
+ maybe = 0;
+ netmatch = afswitch[af].af_netmatch;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_addr.sa_family != af)
+ continue;
+ if (same(&ifp->int_addr, 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 (ifp == 0)
+ ifp = maybe;
+ return (ifp);
+}
diff --git a/usr.sbin/routed/inet.c b/usr.sbin/routed/inet.c
new file mode 100644
index 000000000000..925472c287b4
--- /dev/null
+++ b/usr.sbin/routed/inet.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)inet.c 8.2 (Berkeley) 8/14/93";
+#endif /* not lint */
+
+/*
+ * Temporarily, copy these routines from the kernel,
+ * as we need to know about subnets.
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Formulate an Internet address from network + host.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+ u_long net, host;
+{
+ register struct interface *ifp;
+ register u_long mask;
+ u_long addr;
+
+ if (IN_CLASSA(net))
+ mask = IN_CLASSA_HOST;
+ else if (IN_CLASSB(net))
+ mask = IN_CLASSB_HOST;
+ else
+ mask = IN_CLASSC_HOST;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & net) == ifp->int_net) {
+ mask = ~ifp->int_subnetmask;
+ break;
+ }
+ addr = net | (host & mask);
+ addr = htonl(addr);
+ return (*(struct in_addr *)&addr);
+}
+
+/*
+ * Return the network number from an internet address.
+ */
+inet_netof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+ register u_long net;
+ register struct interface *ifp;
+
+ if (IN_CLASSA(i))
+ net = i & IN_CLASSA_NET;
+ else if (IN_CLASSB(i))
+ net = i & IN_CLASSB_NET;
+ else
+ net = i & IN_CLASSC_NET;
+
+ /*
+ * Check whether network is a subnet;
+ * if so, return subnet number.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & net) == ifp->int_net)
+ return (i & ifp->int_subnetmask);
+ return (net);
+}
+
+/*
+ * Return the host portion of an internet address.
+ */
+inet_lnaof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.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;
+ }
+
+ /*
+ * Check whether network is a subnet;
+ * if so, use the modified interpretation of `host'.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & net) == ifp->int_net)
+ return (host &~ ifp->int_subnetmask);
+ return (host);
+}
+
+/*
+ * Return the netmask pertaining to an internet address.
+ */
+inet_maskof(inaddr)
+ u_long inaddr;
+{
+ register u_long i = ntohl(inaddr);
+ register u_long mask;
+ register struct interface *ifp;
+
+ if (i == 0) {
+ mask = 0;
+ } else if (IN_CLASSA(i)) {
+ mask = IN_CLASSA_NET;
+ } else if (IN_CLASSB(i)) {
+ mask = i & IN_CLASSB_NET;
+ } else
+ mask = i & IN_CLASSC_NET;
+
+ /*
+ * Check whether network is a subnet;
+ * if so, use the modified interpretation of `host'.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & i) == ifp->int_net)
+ mask = ifp->int_subnetmask;
+ return (htonl(mask));
+}
+
+/*
+ * 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;
+ }
+
+ /*
+ * 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)
+ return (RTF_HOST);
+ else if (ifp->int_subnetmask != ifp->int_netmask)
+ return (RTF_SUBNET);
+ else
+ return (0); /* network */
+ }
+ if (host == 0)
+ return (0); /* network */
+ else
+ return (RTF_HOST);
+}
+
+/*
+ * Return true if a route to subnet/host of route rt should be sent to dst.
+ * Send it only if dst is on the same logical network if not "internal",
+ * otherwise only if the route is the "internal" route for the logical net.
+ */
+inet_sendroute(rt, dst)
+ struct rt_entry *rt;
+ struct sockaddr_in *dst;
+{
+ register u_long r =
+ ntohl(((struct sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr);
+ register u_long d = ntohl(dst->sin_addr.s_addr);
+
+ if (IN_CLASSA(r)) {
+ if ((r & IN_CLASSA_NET) == (d & IN_CLASSA_NET)) {
+ if ((r & IN_CLASSA_HOST) == 0)
+ return ((rt->rt_state & RTS_INTERNAL) == 0);
+ return (1);
+ }
+ if (r & IN_CLASSA_HOST)
+ return (0);
+ return ((rt->rt_state & RTS_INTERNAL) != 0);
+ } else if (IN_CLASSB(r)) {
+ if ((r & IN_CLASSB_NET) == (d & IN_CLASSB_NET)) {
+ if ((r & IN_CLASSB_HOST) == 0)
+ return ((rt->rt_state & RTS_INTERNAL) == 0);
+ return (1);
+ }
+ if (r & IN_CLASSB_HOST)
+ return (0);
+ return ((rt->rt_state & RTS_INTERNAL) != 0);
+ } else {
+ if ((r & IN_CLASSC_NET) == (d & IN_CLASSC_NET)) {
+ if ((r & IN_CLASSC_HOST) == 0)
+ return ((rt->rt_state & RTS_INTERNAL) == 0);
+ return (1);
+ }
+ if (r & IN_CLASSC_HOST)
+ return (0);
+ return ((rt->rt_state & RTS_INTERNAL) != 0);
+ }
+}
diff --git a/usr.sbin/routed/input.c b/usr.sbin/routed/input.c
new file mode 100644
index 000000000000..fb0ee798bebd
--- /dev/null
+++ b/usr.sbin/routed/input.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/syslog.h>
+
+/*
+ * Process a newly received packet.
+ */
+rip_input(from, rip, size)
+ struct sockaddr *from;
+ register struct rip *rip;
+ int size;
+{
+ register struct rt_entry *rt;
+ register struct netinfo *n;
+ register struct interface *ifp;
+ struct interface *if_ifwithdstaddr();
+ int count, changes = 0;
+ register struct afswitch *afp;
+ static struct sockaddr badfrom, badfrom2;
+
+ ifp = 0;
+ TRACE_INPUT(ifp, from, (char *)rip, size);
+ 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, rip->rip_cmd);
+ return;
+ }
+ if (rip->rip_vers == 0) {
+ syslog(LOG_ERR,
+ "RIP version 0 packet received from %s! (cmd %d)",
+ (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd);
+ return;
+ }
+ switch (rip->rip_cmd) {
+
+ case RIPCMD_REQUEST:
+ n = rip->rip_nets;
+ count = size - ((char *)n - (char *)rip);
+ if (count < sizeof (struct netinfo))
+ return;
+ for (; count > 0; n++) {
+ if (count < sizeof (struct netinfo))
+ break;
+ count -= sizeof (struct netinfo);
+
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+#else
+#define osa(x) ((struct osockaddr *)(&(x)))
+ n->rip_dst.sa_family =
+ ntohs(osa(n->rip_dst)->sa_family);
+ n->rip_dst.sa_len = sizeof(n->rip_dst);
+#endif
+ n->rip_metric = ntohl(n->rip_metric);
+ /*
+ * 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 && count == 0) {
+ if (supplier || (*afp->af_portmatch)(from) == 0)
+ supply(from, 0, 0, 0);
+ return;
+ }
+ if (n->rip_dst.sa_family < af_max &&
+ afswitch[n->rip_dst.sa_family].af_hash)
+ rt = rtlookup(&n->rip_dst);
+ else
+ rt = 0;
+#define min(a, b) (a < b ? a : b)
+ n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
+ min(rt->rt_metric + 1, HOPCNT_INFINITY);
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
+#else
+ osa(n->rip_dst)->sa_family =
+ htons(n->rip_dst.sa_family);
+#endif
+ n->rip_metric = htonl(n->rip_metric);
+ }
+ rip->rip_cmd = RIPCMD_RESPONSE;
+ bcopy((char *)rip, packet, size);
+ (*afp->af_output)(s, 0, from, size);
+ return;
+
+ case RIPCMD_TRACEON:
+ case RIPCMD_TRACEOFF:
+ /* verify message came from a privileged port */
+ 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;
+ }
+ ((char *)rip)[size] = '\0';
+ if (rip->rip_cmd == RIPCMD_TRACEON)
+ traceon(rip->rip_tracefile);
+ else
+ traceoff();
+ return;
+
+ case RIPCMD_RESPONSE:
+ /* verify message came from a router */
+ if ((*afp->af_portmatch)(from) == 0)
+ return;
+ (*afp->af_canon)(from);
+ /* 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);
+ if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) &&
+ rt->rt_metric >= ifp->int_metric)
+ 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 = rip->rip_nets;
+ for (; size > 0; size -= sizeof (struct netinfo), n++) {
+ if (size < sizeof (struct netinfo))
+ break;
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family =
+ ntohs(n->rip_dst.sa_family);
+#else
+ n->rip_dst.sa_family =
+ ntohs(osa(n->rip_dst)->sa_family);
+ n->rip_dst.sa_len = sizeof(n->rip_dst);
+#endif
+ 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;
+ }
+ 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);
+ 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);
+ changes++;
+ }
+ continue;
+ }
+
+ /*
+ * Update if from gateway and different,
+ * shorter, or equivalent but old route
+ * is getting stale.
+ */
+ if (equal(from, &rt->rt_router)) {
+ if (n->rip_metric != rt->rt_metric) {
+ rtchange(rt, from, n->rip_metric);
+ changes++;
+ 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);
+ changes++;
+ rt->rt_timer = 0;
+ }
+ }
+ break;
+ }
+
+ /*
+ * If changes have occurred, and if we have not sent a broadcast
+ * recently, send a dynamic update. This update is sent only
+ * on interfaces other than the one on which we received notice
+ * of the change. If we are within MIN_WAITTIME of a full update,
+ * don't bother sending; if we just sent a dynamic update
+ * and set a timer (nextbcast), delay until that time.
+ * If we just sent a full update, delay the dynamic update.
+ * Set a timer for a randomized value to suppress additional
+ * dynamic updates until it expires; if we delayed sending
+ * the current changes, set needupdate.
+ */
+ if (changes && supplier &&
+ now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
+ u_long delay;
+ extern long random();
+
+ if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
+ timercmp(&nextbcast, &now, <)) {
+ if (traceactions)
+ fprintf(ftrace, "send dynamic update\n");
+ toall(supply, RTS_CHANGED, ifp);
+ lastbcast = now;
+ needupdate = 0;
+ nextbcast.tv_sec = 0;
+ } else {
+ needupdate++;
+ if (traceactions)
+ fprintf(ftrace, "delay dynamic update\n");
+ }
+#define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \
+ (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
+
+ if (nextbcast.tv_sec == 0) {
+ delay = RANDOMDELAY();
+ if (traceactions)
+ fprintf(ftrace,
+ "inhibit dynamic update for %d usec\n",
+ delay);
+ nextbcast.tv_sec = delay / 1000000;
+ nextbcast.tv_usec = delay % 1000000;
+ timevaladd(&nextbcast, &now);
+ /*
+ * If the next possibly dynamic update
+ * is within MIN_WAITTIME of the next full update,
+ * force the delay past the full update,
+ * or we might send a dynamic update just before
+ * the full update.
+ */
+ if (nextbcast.tv_sec > lastfullupdate.tv_sec +
+ SUPPLY_INTERVAL - MIN_WAITTIME)
+ nextbcast.tv_sec = lastfullupdate.tv_sec +
+ SUPPLY_INTERVAL + 1;
+ }
+ }
+}
diff --git a/usr.sbin/routed/interface.h b/usr.sbin/routed/interface.h
new file mode 100644
index 000000000000..fc576d428288
--- /dev/null
+++ b/usr.sbin/routed/interface.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)interface.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * An ``interface'' is similar to an ifnet structure,
+ * except it doesn't contain q'ing info, and it also
+ * handles ``logical'' interfaces (remote gateways
+ * that we want to keep polling even if they go down).
+ * The list of interfaces which we maintain is used
+ * in supplying the gratuitous routing table updates.
+ */
+struct interface {
+ struct interface *int_next;
+ struct sockaddr int_addr; /* address on this host */
+ union {
+ struct sockaddr intu_broadaddr;
+ struct sockaddr intu_dstaddr;
+ } int_intu;
+#define int_broadaddr int_intu.intu_broadaddr /* broadcast address */
+#define int_dstaddr int_intu.intu_dstaddr /* other end of p-to-p link */
+ int int_metric; /* init's routing entry */
+ int int_flags; /* see below */
+ /* START INTERNET SPECIFIC */
+ u_long int_net; /* network # */
+ u_long int_netmask; /* net mask for addr */
+ u_long int_subnet; /* subnet # */
+ u_long int_subnetmask; /* subnet mask for addr */
+ /* END INTERNET SPECIFIC */
+ struct ifdebug int_input, int_output; /* packet tracing stuff */
+ int int_ipackets; /* input packets received */
+ int int_opackets; /* output packets sent */
+ char *int_name; /* from kernel if structure */
+ u_short int_transitions; /* times gone up-down */
+};
+
+/*
+ * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
+ * the others agree with the RTS_ flags defined elsewhere.
+ */
+#define IFF_UP 0x1 /* interface is up */
+#define IFF_BROADCAST 0x2 /* broadcast address valid */
+#define IFF_DEBUG 0x4 /* turn on debugging */
+#define IFF_LOOPBACK 0x8 /* software loopback net */
+#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
+
+#define IFF_SUBNET 0x100000 /* interface on subnetted network */
+#define IFF_PASSIVE 0x200000 /* can't tell if up/down */
+#define IFF_INTERFACE 0x400000 /* hardware interface */
+#define IFF_REMOTE 0x800000 /* 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.sbin/routed/main.c b/usr.sbin/routed/main.c
new file mode 100644
index 000000000000..187aca115544
--- /dev/null
+++ b/usr.sbin/routed/main.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <net/if.h>
+
+#include <sys/errno.h>
+#include <sys/signal.h>
+#include <sys/syslog.h>
+#include "pathnames.h"
+
+int supplier = -1; /* process should supply updates */
+int gateway = 0; /* 1 if we are a gateway to parts beyond */
+int debug = 0;
+int bufspace = 127*1024; /* max. input buffer size to request */
+
+struct rip *msg = (struct rip *)packet;
+void hup(), rtdeleteall(), sigtrace(), timer();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int n, cc, nfd, omask, tflags = 0;
+ struct sockaddr from;
+ struct timeval *tvp, waittime;
+ struct itimerval itval;
+ register struct rip *query = msg;
+ fd_set ibits;
+ u_char retry;
+
+ argv0 = argv;
+#if BSD >= 43
+ openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ setlogmask(LOG_UPTO(LOG_WARNING));
+#else
+ openlog("routed", LOG_PID);
+#define LOG_UPTO(x) (x)
+#define setlogmask(x) (x)
+#endif
+ sp = getservbyname("router", "udp");
+ if (sp == NULL) {
+ fprintf(stderr, "routed: router/udp: unknown service\n");
+ exit(1);
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = sp->s_port;
+ r = socket(AF_ROUTE, SOCK_RAW, 0);
+ /* later, get smart about lookingforinterfaces */
+ if (r)
+ shutdown(r, 0); /* for now, don't want reponses */
+ else {
+ fprintf(stderr, "routed: no routing socket\n");
+ exit(1);
+ }
+ s = getsocket(AF_INET, SOCK_DGRAM, &addr);
+ if (s < 0)
+ exit(1);
+ argv++, argc--;
+ while (argc > 0 && **argv == '-') {
+ if (strcmp(*argv, "-s") == 0) {
+ supplier = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-q") == 0) {
+ supplier = 0;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-t") == 0) {
+ tflags++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-d") == 0) {
+ debug++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ gateway = 1;
+ argv++, argc--;
+ continue;
+ }
+ fprintf(stderr,
+ "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n");
+ exit(1);
+ }
+
+ if (debug == 0 && tflags == 0)
+ daemon(0, 0);
+ /*
+ * Any extra argument is considered
+ * a tracing log file.
+ */
+ if (argc > 0)
+ traceon(*argv);
+ while (tflags-- > 0)
+ bumploglevel();
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ /*
+ * Collect an initial view of the world by
+ * checking the interface configuration and the gateway kludge
+ * file. Then, send a request packet on all
+ * directly connected networks to find out what
+ * everyone else thinks.
+ */
+ rtinit();
+ ifinit();
+ gwkludge();
+ if (gateway > 0)
+ rtdefault();
+ if (supplier < 0)
+ supplier = 0;
+ query->rip_cmd = RIPCMD_REQUEST;
+ query->rip_vers = RIPVERSION;
+ if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */
+ query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC);
+ else
+ query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
+ query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
+ toall(sndmsg);
+ signal(SIGALRM, timer);
+ signal(SIGHUP, hup);
+ signal(SIGTERM, hup);
+ signal(SIGINT, rtdeleteall);
+ signal(SIGUSR1, sigtrace);
+ signal(SIGUSR2, sigtrace);
+ itval.it_interval.tv_sec = TIMER_RATE;
+ itval.it_value.tv_sec = TIMER_RATE;
+ itval.it_interval.tv_usec = 0;
+ itval.it_value.tv_usec = 0;
+ srandom(getpid());
+ if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
+ syslog(LOG_ERR, "setitimer: %m\n");
+
+ FD_ZERO(&ibits);
+ nfd = s + 1; /* 1 + max(fd's) */
+ for (;;) {
+ FD_SET(s, &ibits);
+ /*
+ * If we need a dynamic update that was held off,
+ * needupdate will be set, and nextbcast is the time
+ * by which we want select to return. Compute time
+ * until dynamic update should be sent, and select only
+ * until then. If we have already passed nextbcast,
+ * just poll.
+ */
+ if (needupdate) {
+ waittime = nextbcast;
+ timevalsub(&waittime, &now);
+ if (waittime.tv_sec < 0) {
+ waittime.tv_sec = 0;
+ waittime.tv_usec = 0;
+ }
+ if (traceactions)
+ fprintf(ftrace,
+ "select until dynamic update %d/%d sec/usec\n",
+ waittime.tv_sec, waittime.tv_usec);
+ tvp = &waittime;
+ } else
+ tvp = (struct timeval *)NULL;
+ n = select(nfd, &ibits, 0, 0, tvp);
+ if (n <= 0) {
+ /*
+ * Need delayed dynamic update if select returned
+ * nothing and we timed out. Otherwise, ignore
+ * errors (e.g. EINTR).
+ */
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ if (n == 0 && needupdate) {
+ if (traceactions)
+ fprintf(ftrace,
+ "send delayed dynamic update\n");
+ (void) gettimeofday(&now,
+ (struct timezone *)NULL);
+ toall(supply, RTS_CHANGED,
+ (struct interface *)NULL);
+ lastbcast = now;
+ needupdate = 0;
+ nextbcast.tv_sec = 0;
+ }
+ sigsetmask(omask);
+ continue;
+ }
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ omask = sigblock(sigmask(SIGALRM));
+#ifdef doesntwork
+/*
+printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n",
+ s,
+ ibits.fds_bits[0],
+ (s)/(sizeof(fd_mask) * 8),
+ ((s) % (sizeof(fd_mask) * 8)),
+ (1 << ((s) % (sizeof(fd_mask) * 8))),
+ ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))),
+ &ibits
+ );
+*/
+ if (FD_ISSET(s, &ibits))
+#else
+ if (ibits.fds_bits[s/32] & (1 << s))
+#endif
+ process(s);
+ /* handle ICMP redirects */
+ sigsetmask(omask);
+ }
+}
+
+timevaladd(t1, t2)
+ struct timeval *t1, *t2;
+{
+
+ t1->tv_sec += t2->tv_sec;
+ if ((t1->tv_usec += t2->tv_usec) > 1000000) {
+ t1->tv_sec++;
+ t1->tv_usec -= 1000000;
+ }
+}
+
+timevalsub(t1, t2)
+ struct timeval *t1, *t2;
+{
+
+ t1->tv_sec -= t2->tv_sec;
+ if ((t1->tv_usec -= t2->tv_usec) < 0) {
+ t1->tv_sec--;
+ t1->tv_usec += 1000000;
+ }
+}
+
+process(fd)
+ int fd;
+{
+ struct sockaddr from;
+ int fromlen, cc;
+ union {
+ char buf[MAXPACKETSIZE+1];
+ struct rip rip;
+ } inbuf;
+
+ for (;;) {
+ fromlen = sizeof (from);
+ cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EWOULDBLOCK)
+ perror("recvfrom");
+ break;
+ }
+ if (fromlen != sizeof (struct sockaddr_in))
+ break;
+ rip_input(&from, &inbuf.rip, cc);
+ }
+}
+
+getsocket(domain, type, sin)
+ int domain, type;
+ struct sockaddr_in *sin;
+{
+ int sock, on = 1;
+
+ if ((sock = socket(domain, type, 0)) < 0) {
+ perror("socket");
+ syslog(LOG_ERR, "socket: %m");
+ return (-1);
+ }
+#ifdef SO_BROADCAST
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ close(sock);
+ return (-1);
+ }
+#endif
+#ifdef SO_RCVBUF
+ for (on = bufspace; ; on -= 1024) {
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ &on, sizeof (on)) == 0)
+ break;
+ if (on <= 8*1024) {
+ syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
+ break;
+ }
+ }
+ if (traceactions)
+ fprintf(ftrace, "recv buf %d\n", on);
+#endif
+ if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) {
+ perror("bind");
+ syslog(LOG_ERR, "bind: %m");
+ close(sock);
+ return (-1);
+ }
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
+ syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
+ return (sock);
+}
diff --git a/usr.sbin/routed/output.c b/usr.sbin/routed/output.c
new file mode 100644
index 000000000000..528f7fc038e4
--- /dev/null
+++ b/usr.sbin/routed/output.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+/*
+ * Apply the function "f" to all non-passive
+ * interfaces. If the interface supports the
+ * use of broadcasting use it, otherwise address
+ * the output to the known router.
+ */
+toall(f, rtstate, skipif)
+ int (*f)();
+ int rtstate;
+ struct interface *skipif;
+{
+ register struct interface *ifp;
+ register struct sockaddr *dst;
+ register int flags;
+ extern struct interface *ifnet;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_PASSIVE || ifp == skipif)
+ continue;
+ dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
+ ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
+ &ifp->int_addr;
+ flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
+ (*f)(dst, flags, ifp, rtstate);
+ }
+}
+
+/*
+ * Output a preformed packet.
+ */
+/*ARGSUSED*/
+sndmsg(dst, flags, ifp, rtstate)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+ int rtstate;
+{
+
+ (*afswitch[dst->sa_family].af_output)(s, flags,
+ dst, sizeof (struct rip));
+ TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
+}
+
+/*
+ * Supply dst with the contents of the routing tables.
+ * If this won't fit in one packet, chop it up into several.
+ */
+supply(dst, flags, ifp, rtstate)
+ struct sockaddr *dst;
+ int flags;
+ register struct interface *ifp;
+ int rtstate;
+{
+ register struct rt_entry *rt;
+ register struct netinfo *n = msg->rip_nets;
+ register struct rthash *rh;
+ struct rthash *base = hosthash;
+ int doinghost = 1, size;
+ int (*output)() = afswitch[dst->sa_family].af_output;
+ int (*sendroute)() = afswitch[dst->sa_family].af_sendroute;
+ int npackets = 0;
+
+ msg->rip_cmd = RIPCMD_RESPONSE;
+ msg->rip_vers = RIPVERSION;
+ bzero(msg->rip_res1, sizeof(msg->rip_res1));
+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 (unless sending
+ * in response to a query).
+ */
+ if (ifp && rt->rt_ifp == ifp &&
+ (rt->rt_state & RTS_INTERFACE) == 0)
+ continue;
+ if (rt->rt_state & RTS_EXTERNAL)
+ continue;
+ /*
+ * For dynamic updates, limit update to routes
+ * with the specified state.
+ */
+ if (rtstate && (rt->rt_state & rtstate) == 0)
+ continue;
+ /*
+ * Limit the spread of subnet information
+ * to those who are interested.
+ */
+ if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
+ if (rt->rt_dst.sa_family != dst->sa_family)
+ continue;
+ if ((*sendroute)(rt, dst) == 0)
+ continue;
+ }
+ size = (char *)n - packet;
+ if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
+ TRACE_OUTPUT(ifp, dst, size);
+ (*output)(s, flags, dst, size);
+ /*
+ * If only sending to ourselves,
+ * one packet is enough to monitor interface.
+ */
+ if (ifp && (ifp->int_flags &
+ (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0)
+ return;
+ n = msg->rip_nets;
+ npackets++;
+ }
+ n->rip_dst = rt->rt_dst;
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
+#else
+#define osa(x) ((struct osockaddr *)(&(x)))
+ osa(n->rip_dst)->sa_family = htons(n->rip_dst.sa_family);
+#endif
+ n->rip_metric = htonl(rt->rt_metric);
+ n++;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (n != msg->rip_nets || (npackets == 0 && rtstate == 0)) {
+ size = (char *)n - packet;
+ TRACE_OUTPUT(ifp, dst, size);
+ (*output)(s, flags, dst, size);
+ }
+}
diff --git a/usr.sbin/routed/pathnames.h b/usr.sbin/routed/pathnames.h
new file mode 100644
index 000000000000..461d82bfac4d
--- /dev/null
+++ b/usr.sbin/routed/pathnames.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/5/93
+ */
+
+#include <paths.h>
+
+#define _PATH_GATEWAYS "/etc/gateways"
diff --git a/usr.sbin/routed/query/Makefile b/usr.sbin/routed/query/Makefile
new file mode 100644
index 000000000000..0e7d1cdcc436
--- /dev/null
+++ b/usr.sbin/routed/query/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= query
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/routed/query/query.c b/usr.sbin/routed/query/query.c
new file mode 100644
index 000000000000..a80038815544
--- /dev/null
+++ b/usr.sbin/routed/query/query.c
@@ -0,0 +1,294 @@
+/*-
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1982, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WTIME 5 /* Time to wait for all responses */
+#define STIME 500000 /* usec to wait for another response */
+
+int s;
+int timedout;
+void timeout();
+char packet[MAXPACKETSIZE];
+int nflag;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, cc, count, bits;
+ struct sockaddr from;
+ struct sigaction sigact;
+ int fromlen = sizeof(from), size = 32*1024;
+ struct timeval shorttime;
+
+ while ((ch = getopt(argc, argv, "n")) != EOF)
+ switch (ch) {
+ case 'n':
+ nflag++;
+ break;
+ case '?':
+ default:
+ goto usage;
+ }
+ argv += optind;
+
+ if (!*argv) {
+usage: printf("usage: query [-n] hosts...\n");
+ exit(1);
+ }
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0)
+ perror("setsockopt SO_RCVBUF");
+
+ while (*argv) {
+ query(*argv++);
+ count++;
+ }
+
+ /*
+ * Listen for returning packets;
+ * may be more than one packet per host.
+ */
+ bits = 1 << s;
+ bzero(&shorttime, sizeof(shorttime));
+ shorttime.tv_usec = STIME;
+ bzero(&sigact, sizeof(sigact));
+ sigact.sa_handler = timeout;
+ /*sigact.sa_flags = 0; /* no restart */
+ if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) == -1)
+ perror("sigaction");
+ alarm(WTIME);
+ while ((count > 0 && !timedout) ||
+ select(20, (fd_set *)&bits, NULL, NULL, &shorttime) > 0) {
+ cc = recvfrom(s, packet, sizeof (packet), 0,
+ &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("recvfrom");
+ (void) close(s);
+ exit(1);
+ }
+ continue;
+ }
+ rip_input(&from, cc);
+ count--;
+ }
+ exit (count > 0 ? count : 0);
+}
+
+query(host)
+ char *host;
+{
+ struct sockaddr_in router;
+ register struct rip *msg = (struct rip *)packet;
+ struct hostent *hp;
+ struct servent *sp;
+
+ bzero((char *)&router, sizeof (router));
+ router.sin_family = AF_INET;
+ router.sin_addr.s_addr = inet_addr(host);
+ if (router.sin_addr.s_addr == -1) {
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "query: %s: ", host);
+ herror((char *)NULL);
+ exit(1);
+ }
+ bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
+ }
+ sp = getservbyname("router", "udp");
+ if (sp == 0) {
+ printf("udp/router: service unknown\n");
+ exit(1);
+ }
+ router.sin_port = sp->s_port;
+ msg->rip_cmd = RIPCMD_REQUEST;
+ msg->rip_vers = RIPVERSION;
+ msg->rip_nets[0].rip_dst.sa_family = htons(AF_UNSPEC);
+ msg->rip_nets[0].rip_metric = htonl(HOPCNT_INFINITY);
+ if (sendto(s, packet, sizeof (struct rip), 0,
+ (struct sockaddr *)&router, sizeof(router)) < 0)
+ perror(host);
+}
+
+/*
+ * Handle an incoming routing packet.
+ */
+rip_input(from, size)
+ struct sockaddr_in *from;
+ int size;
+{
+ register struct rip *msg = (struct rip *)packet;
+ register struct netinfo *n;
+ char *name;
+ int lna, net, subnet;
+ struct hostent *hp;
+ struct netent *np;
+
+ if (msg->rip_cmd != RIPCMD_RESPONSE)
+ return;
+ printf("%d bytes from ", size);
+ if (nflag)
+ printf("%s:\n", inet_ntoa(from->sin_addr));
+ else {
+ hp = gethostbyaddr((char *)&from->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ name = hp == 0 ? "???" : hp->h_name;
+ printf("%s(%s):\n", name, inet_ntoa(from->sin_addr));
+ }
+ size -= sizeof (int);
+ n = msg->rip_nets;
+ while (size > 0) {
+ if (size < sizeof (struct netinfo))
+ break;
+ if (msg->rip_vers > 0) {
+ n->rip_dst.sa_family =
+ ntohs(n->rip_dst.sa_family);
+ n->rip_metric = ntohl(n->rip_metric);
+ }
+ switch (n->rip_dst.sa_family) {
+
+ case AF_INET:
+ { register struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)&n->rip_dst;
+ net = inet_netof(sin->sin_addr);
+ subnet = inet_subnetof(sin->sin_addr);
+ lna = inet_lnaof(sin->sin_addr);
+ name = "???";
+ if (!nflag) {
+ if (sin->sin_addr.s_addr == 0)
+ name = "default";
+ else if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ name = np->n_name;
+ else if (net == 0)
+ name = "default";
+ } else if ((lna & 0xff) == 0 &&
+ (np = getnetbyaddr(subnet, AF_INET))) {
+ struct in_addr subnaddr, inet_makeaddr();
+
+ subnaddr = inet_makeaddr(subnet, INADDR_ANY);
+ if (bcmp(&sin->sin_addr, &subnaddr,
+ sizeof(subnaddr)) == 0)
+ name = np->n_name;
+ else
+ goto host;
+ } else {
+ host:
+ hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ if (hp)
+ name = hp->h_name;
+ }
+ printf("\t%-17s metric %2d name %s\n",
+ inet_ntoa(sin->sin_addr), n->rip_metric, name);
+ } else
+ printf("\t%-17s metric %2d\n",
+ inet_ntoa(sin->sin_addr), n->rip_metric);
+ break;
+ }
+
+ default:
+ { u_short *p = (u_short *)n->rip_dst.sa_data;
+
+ printf("\t(af %d) %x %x %x %x %x %x %x, metric %d\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6],
+ n->rip_dst.sa_family,
+ n->rip_metric);
+ break;
+ }
+
+ }
+ size -= sizeof (struct netinfo), n++;
+ }
+}
+
+void
+timeout()
+{
+ timedout = 1;
+}
+
+/*
+ * Return the possible subnetwork number from an internet address.
+ * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING
+ * INSIDE OF THE HOST PART. We can only believe this if we have other
+ * information (e.g., we can find a name for this number).
+ */
+inet_subnetof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else if (IN_CLASSB(i))
+ return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+ else
+ return ((i & 0xffffffc0) >> 28);
+}
diff --git a/usr.sbin/routed/routed.8 b/usr.sbin/routed/routed.8
new file mode 100644
index 000000000000..8d9ea20e00b2
--- /dev/null
+++ b/usr.sbin/routed/routed.8
@@ -0,0 +1,358 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt ROUTED 8
+.Os BSD 4.2
+.Sh NAME
+.Nm routed
+.Nd network routing daemon
+.Sh SYNOPSIS
+.Nm routed
+.Op Fl d
+.Op Fl g
+.Op Fl q
+.Op Fl s
+.Op Fl t
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm Routed
+is invoked at boot time to manage the network routing tables.
+The routing daemon uses a variant of the Xerox NS Routing
+Information Protocol in maintaining up to date kernel routing
+table entries.
+It used a generalized protocol capable of use with multiple
+address types, but is currently used only for Internet routing
+within a cluster of networks.
+.Pp
+In normal operation
+.Nm routed
+listens on the
+.Xr udp 4
+socket for the
+.Xr route 8
+service (see
+.Xr services 5 )
+for routing information packets. If the host is an
+internetwork router, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm routed
+is started, it uses the
+.Dv SIOCGIFCONF
+.Xr ioctl 2
+to find those
+directly connected interfaces configured into the
+system and marked ``up'' (the software loopback interface
+is ignored). If multiple interfaces
+are present, it is assumed that the host will forward packets
+between networks.
+.Nm Routed
+then transmits a
+.Em request
+packet on each interface (using a broadcast packet if
+the interface supports it) and enters a loop, listening
+for
+.Em request
+and
+.Em response
+packets from other hosts.
+.Pp
+When a
+.Em request
+packet is received,
+.Nm routed
+formulates a reply based on the information maintained in its
+internal tables. The
+.Em response
+packet generated contains a list of known routes, each marked
+with a ``hop count'' metric (a count of 16, or greater, is
+considered ``infinite''). The metric associated with each
+route returned provides a metric
+.Em relative to the sender .
+.Pp
+.Em Response
+packets received by
+.Nm routed
+are used to update the routing tables if one of the following
+conditions is satisfied:
+.Bl -enum
+.It
+No routing table entry exists for the destination network
+or host, and the metric indicates the destination is ``reachable''
+(i.e. the hop count is not infinite).
+.It
+The source host of the packet is the same as the router in the
+existing routing table entry. That is, updated information is
+being received from the very internetwork router through which
+packets for the destination are being routed.
+.It
+The existing entry in the routing table has not been updated for
+some time (defined to be 90 seconds) and the route is at least
+as cost effective as the current route.
+.It
+The new route describes a shorter route to the destination than
+the one currently stored in the routing tables; the metric of
+the new route is compared against the one stored in the table
+to decide this.
+.El
+.Pp
+When an update is applied,
+.Nm routed
+records the change in its internal tables and updates the kernel
+routing table.
+The change is reflected in the next
+.Em response
+packet sent.
+.Pp
+In addition to processing incoming packets,
+.Nm routed
+also periodically checks the routing table entries.
+If an entry has not been updated for 3 minutes, the entry's metric
+is set to infinity and marked for deletion. Deletions are delayed
+an additional 60 seconds to insure the invalidation is propagated
+throughout the local internet.
+.Pp
+Hosts acting as internetwork routers gratuitously supply their
+routing tables every 30 seconds to all directly connected hosts
+and networks.
+The response is sent to the broadcast address on nets capable of that function,
+to the destination address on point-to-point links, and to the router's
+own address on other networks.
+The normal routing tables are bypassed when sending gratuitous responses.
+The reception of responses on each network is used to determine that the
+network and interface are functioning correctly.
+If no response is received on an interface, another route may be chosen
+to route around the interface, or the route may be dropped if no alternative
+is available.
+.Pp
+Options supported by
+.Nm routed :
+.Bl -tag -width Ds
+.It Fl d
+Enable additional debugging information to be logged,
+such as bad packets received.
+.It Fl g
+This flag is used on internetwork routers to offer a route
+to the ``default'' destination.
+This is typically used on a gateway to the Internet,
+or on a gateway that uses another routing protocol whose routes
+are not reported to other local routers.
+.It Fl s
+Supplying this
+option forces
+.Nm routed
+to supply routing information whether it is acting as an internetwork
+router or not.
+This is the default if multiple network interfaces are present,
+or if a point-to-point link is in use.
+.It Fl q
+This
+is the opposite of the
+.Fl s
+option.
+.It Fl t
+If the
+.Fl t
+option is specified, all packets sent or received are
+printed on the standard output. In addition,
+.Nm routed
+will not divorce itself from the controlling terminal
+so that interrupts from the keyboard will kill the process.
+.El
+.Pp
+Any other argument supplied is interpreted as the name
+of file in which
+.Nm routed Ns \'s
+actions should be logged. This log contains information
+about any changes to the routing tables and, if not tracing all packets,
+a history of recent messages sent and received which are related to
+the changed route.
+.Pp
+In addition to the facilities described above,
+.Nm routed
+supports the notion of ``distant''
+.Em passive
+and
+.Em active
+gateways. When
+.Nm routed
+is started up, it reads the file
+.Pa /etc/gateways
+to find gateways which may not be located using
+only information from the
+.Dv SIOGIFCONF
+.Xr ioctl 2 .
+Gateways specified in this manner should be marked passive
+if they are not expected to exchange routing information,
+while gateways marked active
+should be willing to exchange routing information (i.e.
+they should have a
+.Nm routed
+process running on the machine).
+Routes through passive gateways are installed in the
+kernel's routing tables once upon startup.
+Such routes are not included in
+any routing information transmitted.
+Active gateways are treated equally to network
+interfaces. Routing information is distributed
+to the gateway and if no routing information is
+received for a period of time, the associated
+route is deleted.
+Gateways marked
+.Em external
+are also passive, but are not placed in the kernel
+routing table nor are they included in routing updates.
+The function of external entries is to inform
+.Nm routed
+that another routing process
+will install such a route, and that alternate routes to that destination
+should not be installed.
+Such entries are only required when both routers may learn of routes
+to the same destination.
+.Pp
+The
+.Pa /etc/gateways
+is comprised of a series of lines, each in
+the following format:
+.Bd -ragged
+.Pf < Cm net No \&|
+.Cm host Ns >
+.Ar name1
+.Cm gateway
+.Ar name2
+.Cm metric
+.Ar value
+.Pf < Cm passive No \&|
+.Cm active No \&|
+.Cm external Ns >
+.Ed
+.Pp
+The
+.Cm net
+or
+.Cm host
+keyword indicates if the route is to a network or specific host.
+.Pp
+.Ar Name1
+is the name of the destination network or host. This may be a
+symbolic name located in
+.Pa /etc/networks
+or
+.Pa /etc/hosts
+(or, if started after
+.Xr named 8 ,
+known to the name server),
+or an Internet address specified in ``dot'' notation; see
+.Xr inet 3 .
+.Pp
+.Ar Name2
+is the name or address of the gateway to which messages should
+be forwarded.
+.Pp
+.Ar Value
+is a metric indicating the hop count to the destination host
+or network.
+.Pp
+One of the keywords
+.Cm passive ,
+.Cm active
+or
+.Cm external
+indicates if the gateway should be treated as
+.Em passive
+or
+.Em active
+(as described above),
+or whether the gateway is
+.Em external
+to the scope of the
+.Nm routed
+protocol.
+.Pp
+Internetwork routers that are directly attached to the Arpanet or Milnet
+should use the Exterior Gateway Protocol
+.Pq Tn EGP
+to gather routing information
+rather then using a static routing table of passive gateways.
+.Tn EGP
+is required in order to provide routes for local networks to the rest
+of the Internet system.
+.Sh FILES
+.Bl -tag -width /etc/gateways -compact
+.It Pa /etc/gateways
+for distant gateways
+.El
+.Sh SEE ALSO
+.Xr udp 4 ,
+.Xr icmp 4 ,
+.Xr XNSrouted 8 ,
+.Xr htable 8
+.Rs
+.%T Internet Transport Protocols
+.%R XSIS 028112
+.%Q Xerox System Integration Standard
+.Re
+.Sh BUGS
+The kernel's routing tables may not correspond to those of
+.Nm routed
+when redirects change or add routes.
+.Nm Routed
+should note any redirects received by reading
+the
+.Tn ICMP
+packets received via a raw socket.
+.Pp
+.Nm Routed
+should incorporate other routing protocols,
+such as Xerox
+.Tn \&NS
+.Pq Xr XNSrouted 8
+and
+.Tn EGP .
+Using separate processes for each requires configuration options
+to avoid redundant or competing routes.
+.Pp
+.Nm Routed
+should listen to intelligent interfaces, such as an
+.Tn IMP ,
+to gather more information.
+It does not always detect unidirectional failures in network interfaces
+(e.g., when the output side fails).
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/routed/startup.c b/usr.sbin/routed/startup.c
new file mode 100644
index 000000000000..e87d9e9b71c7
--- /dev/null
+++ b/usr.sbin/routed/startup.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)startup.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+struct interface *ifnet;
+struct interface **ifnext = &ifnet;
+int lookforinterfaces = 1;
+int externalinterfaces = 0; /* # of remote and local interfaces */
+int foundloopback; /* valid flag for loopaddr */
+struct sockaddr loopaddr; /* our address on loopback */
+
+
+void
+quit(s)
+ char *s;
+{
+ extern int errno;
+ int sverrno = errno;
+
+ (void) fprintf(stderr, "route: ");
+ if (s)
+ (void) fprintf(stderr, "%s: ", s);
+ (void) fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(1);
+ /* NOTREACHED */
+}
+
+struct rt_addrinfo info;
+/* Sleazy use of local variables throughout file, warning!!!! */
+#define netmask info.rti_info[RTAX_NETMASK]
+#define ifaaddr info.rti_info[RTAX_IFA]
+#define brdaddr info.rti_info[RTAX_BRD]
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+void
+rt_xaddrs(cp, cplim, rtinfo)
+ register caddr_t cp, cplim;
+ register struct rt_addrinfo *rtinfo;
+{
+ register struct sockaddr *sa;
+ register int i;
+
+ bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ ADVANCE(cp, sa);
+ }
+}
+
+/*
+ * Find the network interfaces which have configured themselves.
+ * If the interface is present but not yet up (for example an
+ * ARPANET IMP), set the lookforinterfaces flag so we'll
+ * come back later and look again.
+ */
+ifinit()
+{
+ struct interface ifs, *ifp;
+ size_t needed;
+ int mib[6], no_ipaddr = 0, flags = 0;
+ char *buf, *cplim, *cp;
+ register struct if_msghdr *ifm;
+ register struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ struct sockaddr_in *sin;
+ u_long i;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ quit("route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ quit("malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ quit("actual retrieval of interface table");
+ lookforinterfaces = 0;
+ cplim = buf + needed;
+ for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)cp;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ bzero(&ifs, sizeof(ifs));
+ ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE;
+ if ((flags & IFF_UP) == 0 || no_ipaddr)
+ lookforinterfaces = 1;
+ sdl = (struct sockaddr_dl *) (ifm + 1);
+ sdl->sdl_data[sdl->sdl_nlen] = 0;
+ no_ipaddr = 1;
+ continue;
+ }
+ if (ifm->ifm_type != RTM_NEWADDR)
+ quit("ifinit: out of sync");
+ if ((flags & IFF_UP) == 0)
+ continue;
+ ifam = (struct ifa_msghdr *)ifm;
+ info.rti_addrs = ifam->ifam_addrs;
+ rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
+ if (ifaaddr == 0) {
+ syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
+ continue;
+ }
+ ifs.int_addr = *ifaaddr;
+ if (ifs.int_addr.sa_family != AF_INET)
+ continue;
+ no_ipaddr = 0;
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get dstaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ if (brdaddr->sa_family == AF_UNSPEC) {
+ lookforinterfaces = 1;
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ /*
+ * already known to us?
+ * This allows multiple point-to-point links
+ * to share a source address (possibly with one
+ * other link), but assumes that there will not be
+ * multiple links with the same destination address.
+ */
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (if_ifwithdstaddr(&ifs.int_dstaddr))
+ continue;
+ } else if (if_ifwithaddr(&ifs.int_addr))
+ continue;
+ if (ifs.int_flags & IFF_LOOPBACK) {
+ ifs.int_flags |= IFF_PASSIVE;
+ foundloopback = 1;
+ loopaddr = ifs.int_addr;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if (ifp->int_flags & IFF_POINTOPOINT)
+ add_ptopt_localrt(ifp);
+ }
+ if (ifs.int_flags & IFF_BROADCAST) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get broadaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ /*
+ * Use a minimum metric of one;
+ * treat the interface metric (default 0)
+ * as an increment to the hop count of one.
+ */
+ ifs.int_metric = ifam->ifam_metric + 1;
+ if (netmask == 0) {
+ syslog(LOG_ERR, "%s: (get netmask)",
+ sdl->sdl_data);
+ continue;
+ }
+ sin = (struct sockaddr_in *)netmask;
+ ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
+ sin = (struct sockaddr_in *)&ifs.int_addr;
+ i = ntohl(sin->sin_addr.s_addr);
+ if (IN_CLASSA(i))
+ ifs.int_netmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(i))
+ ifs.int_netmask = IN_CLASSB_NET;
+ else
+ 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(sdl->sdl_nlen + 1 + sizeof(ifs));
+ if (ifp == 0) {
+ printf("routed: out of memory\n");
+ lookforinterfaces = 1;
+ break;
+ }
+ *ifp = ifs;
+ /*
+ * Count the # of directly connected networks
+ * and point to point links which aren't looped
+ * back to ourself. This is used below to
+ * decide if we should be a routing ``supplier''.
+ */
+ if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
+ ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
+ if_ifwithaddr(&ifs.int_dstaddr) == 0))
+ externalinterfaces++;
+ /*
+ * If we have a point-to-point link, we want to act
+ * as a supplier even if it's our only interface,
+ * as that's the only way our peer on the other end
+ * can tell that the link is up.
+ */
+ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
+ supplier = 1;
+ ifp->int_name = (char *)(ifp + 1);
+ strcpy(ifp->int_name, sdl->sdl_data);
+ *ifnext = ifp;
+ ifnext = &ifp->int_next;
+ traceinit(ifp);
+ addrouteforif(ifp);
+ }
+ if (externalinterfaces > 1 && supplier < 0)
+ supplier = 1;
+ free(buf);
+}
+
+/*
+ * 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)
+ register struct interface *ifp;
+{
+ struct sockaddr_in net;
+ struct sockaddr *dst;
+ int state;
+ register struct rt_entry *rt;
+
+ if (ifp->int_flags & IFF_POINTOPOINT)
+ dst = &ifp->int_dstaddr;
+ else {
+ bzero((char *)&net, sizeof (net));
+ net.sin_family = AF_INET;
+ net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
+ dst = (struct sockaddr *)&net;
+ }
+ rt = rtfind(dst);
+ if (rt &&
+ (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
+ return;
+ if (rt)
+ rtdelete(rt);
+ /*
+ * 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) {
+ struct in_addr subnet;
+
+ subnet = net.sin_addr;
+ net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+ rt = rtfind(dst);
+ if (rt == 0)
+ rtadd(dst, &ifp->int_addr, ifp->int_metric,
+ ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
+ RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
+ else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) ==
+ (RTS_INTERNAL|RTS_SUBNET) &&
+ ifp->int_metric < rt->rt_metric)
+ rtchange(rt, &rt->rt_router, ifp->int_metric);
+ net.sin_addr = subnet;
+ }
+ if (ifp->int_transitions++ > 0)
+ syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+ state = ifp->int_flags &
+ (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
+ if (ifp->int_flags & IFF_POINTOPOINT &&
+ (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
+ ifp->int_netmask) != ifp->int_net)
+ state &= ~RTS_SUBNET;
+ if (ifp->int_flags & IFF_LOOPBACK)
+ state |= RTS_EXTERNAL;
+ rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
+ if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
+ add_ptopt_localrt(ifp);
+}
+
+/*
+ * Add route to local end of point-to-point using loopback.
+ * If a route to this network is being sent to neighbors on other nets,
+ * mark this route as subnet so we don't have to propagate it too.
+ */
+add_ptopt_localrt(ifp)
+ register struct interface *ifp;
+{
+ struct rt_entry *rt;
+ struct sockaddr *dst;
+ struct sockaddr_in net;
+ int state;
+
+ state = RTS_INTERFACE | RTS_PASSIVE;
+
+ /* look for route to logical network */
+ bzero((char *)&net, sizeof (net));
+ net.sin_family = AF_INET;
+ net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+ dst = (struct sockaddr *)&net;
+ rt = rtfind(dst);
+ if (rt && rt->rt_state & RTS_INTERNAL)
+ state |= RTS_SUBNET;
+
+ dst = &ifp->int_addr;
+ if (rt = rtfind(dst)) {
+ if (rt && rt->rt_state & RTS_INTERFACE)
+ return;
+ rtdelete(rt);
+ }
+ rtadd(dst, &loopaddr, 1, state);
+}
+
+/*
+ * As a concession to the ARPANET we read a list of gateways
+ * from /etc/gateways and add them to our tables. This file
+ * exists at each ARPANET gateway and indicates a set of ``remote''
+ * gateways (i.e. a gateway which we can't immediately determine
+ * if it's present or not as we can do for those directly connected
+ * at the hardware level). If a gateway is marked ``passive''
+ * in the file, then we assume it doesn't have a routing process
+ * of our design and simply assume it's always present. Those
+ * not marked passive are treated as if they were directly
+ * connected -- they're added into the interface list so we'll
+ * send them routing updates.
+ *
+ * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
+ */
+gwkludge()
+{
+ struct sockaddr_in dst, gate;
+ FILE *fp;
+ char *type, *dname, *gname, *qual, buf[BUFSIZ];
+ struct interface *ifp;
+ int metric, n;
+ struct rt_entry route;
+
+ fp = fopen(_PATH_GATEWAYS, "r");
+ if (fp == NULL)
+ return;
+ qual = buf;
+ dname = buf + 64;
+ gname = buf + ((BUFSIZ - 64) / 3);
+ type = buf + (((BUFSIZ - 64) * 2) / 3);
+ bzero((char *)&dst, sizeof (dst));
+ bzero((char *)&gate, sizeof (gate));
+ bzero((char *)&route, sizeof(route));
+/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
+#define readentry(fp) \
+ fscanf((fp), "%s %s gateway %s metric %d %s\n", \
+ type, dname, gname, &metric, qual)
+ for (;;) {
+ if ((n = readentry(fp)) == EOF)
+ break;
+ if (!getnetorhostname(type, dname, &dst))
+ continue;
+ if (!gethostnameornumber(gname, &gate))
+ continue;
+ if (metric == 0) /* XXX */
+ metric = 1;
+ if (strcmp(qual, "passive") == 0) {
+ /*
+ * Passive entries aren't placed in our tables,
+ * only the kernel's, so we don't copy all of the
+ * external routing information within a net.
+ * Internal machines should use the default
+ * route to a suitable gateway (like us).
+ */
+ route.rt_dst = *(struct sockaddr *) &dst;
+ route.rt_router = *(struct sockaddr *) &gate;
+ route.rt_flags = RTF_UP;
+ if (strcmp(type, "host") == 0)
+ route.rt_flags |= RTF_HOST;
+ if (metric)
+ route.rt_flags |= RTF_GATEWAY;
+ (void) rtioctl(ADD, &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);
+ continue;
+ }
+ /* assume no duplicate entries */
+ externalinterfaces++;
+ ifp = (struct interface *)malloc(sizeof (*ifp));
+ bzero((char *)ifp, sizeof (*ifp));
+ ifp->int_flags = IFF_REMOTE;
+ /* can't identify broadcast capability */
+ ifp->int_net = inet_netof(dst.sin_addr);
+ if (strcmp(type, "host") == 0) {
+ ifp->int_flags |= IFF_POINTOPOINT;
+ ifp->int_dstaddr = *((struct sockaddr *)&dst);
+ }
+ ifp->int_addr = *((struct sockaddr *)&gate);
+ ifp->int_metric = metric;
+ ifp->int_next = ifnet;
+ ifnet = ifp;
+ addrouteforif(ifp);
+ }
+ fclose(fp);
+}
+
+getnetorhostname(type, name, sin)
+ char *type, *name;
+ struct sockaddr_in *sin;
+{
+
+ if (strcmp(type, "net") == 0) {
+ struct netent *np = getnetbyname(name);
+ int n;
+
+ if (np == 0)
+ n = inet_network(name);
+ else {
+ if (np->n_addrtype != AF_INET)
+ return (0);
+ n = np->n_net;
+ /*
+ * getnetbyname returns right-adjusted value.
+ */
+ if (n < 128)
+ n <<= IN_CLASSA_NSHIFT;
+ else if (n < 65536)
+ n <<= IN_CLASSB_NSHIFT;
+ else
+ n <<= IN_CLASSC_NSHIFT;
+ }
+ sin->sin_family = AF_INET;
+ sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
+ return (1);
+ }
+ if (strcmp(type, "host") == 0) {
+ struct hostent *hp = gethostbyname(name);
+
+ if (hp == 0)
+ sin->sin_addr.s_addr = inet_addr(name);
+ else {
+ if (hp->h_addrtype != AF_INET)
+ return (0);
+ bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+ }
+ sin->sin_family = AF_INET;
+ return (1);
+ }
+ return (0);
+}
+
+gethostnameornumber(name, sin)
+ char *name;
+ struct sockaddr_in *sin;
+{
+ struct hostent *hp;
+
+ hp = gethostbyname(name);
+ if (hp) {
+ bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+ sin->sin_family = hp->h_addrtype;
+ return (1);
+ }
+ sin->sin_addr.s_addr = inet_addr(name);
+ sin->sin_family = AF_INET;
+ return (sin->sin_addr.s_addr != -1);
+}
diff --git a/usr.sbin/routed/table.h b/usr.sbin/routed/table.h
new file mode 100644
index 000000000000..01336f0681af
--- /dev/null
+++ b/usr.sbin/routed/table.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)table.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Routing table structure; differs a bit from kernel tables.
+ *
+ * Note: the union below must agree in the first 4 members
+ * so the ioctl's will work.
+ */
+struct rthash {
+ struct rt_entry *rt_forw;
+ struct rt_entry *rt_back;
+};
+#ifdef RTM_ADD
+#define rtentry ortentry
+#endif
+
+struct rt_entry {
+ struct rt_entry *rt_forw;
+ struct rt_entry *rt_back;
+ union {
+ struct rtentry rtu_rt;
+ struct rtuentry {
+ u_long rtu_hash;
+ struct sockaddr rtu_dst;
+ struct sockaddr rtu_router;
+ short rtu_rtflags; /* used by rtioctl */
+ short rtu_wasted[5];
+ int rtu_flags;
+ int rtu_state;
+ int rtu_timer;
+ int rtu_metric;
+ int rtu_ifmetric;
+ struct interface *rtu_ifp;
+ } rtu_entry;
+ } rt_rtu;
+};
+
+#define rt_rt rt_rtu.rtu_entry /* pass to ioctl */
+#define rt_hash rt_rtu.rtu_entry.rtu_hash /* for net or host */
+#define rt_dst rt_rtu.rtu_entry.rtu_dst /* match value */
+#define rt_router rt_rtu.rtu_entry.rtu_router /* who to forward to */
+#define rt_flags rt_rtu.rtu_entry.rtu_flags /* kernel flags */
+#define rt_timer rt_rtu.rtu_entry.rtu_timer /* for invalidation */
+#define rt_state rt_rtu.rtu_entry.rtu_state /* see below */
+#define rt_metric rt_rtu.rtu_entry.rtu_metric /* cost of route */
+#define rt_ifmetric rt_rtu.rtu_entry.rtu_ifmetric /* cost of route if */
+#define rt_ifp rt_rtu.rtu_entry.rtu_ifp /* interface to take */
+
+#define ROUTEHASHSIZ 32 /* must be a power of 2 */
+#define ROUTEHASHMASK (ROUTEHASHSIZ - 1)
+
+/*
+ * "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 0x80000 /* pseudo: route to subnet */
+
+struct rthash nethash[ROUTEHASHSIZ];
+struct rthash hosthash[ROUTEHASHSIZ];
+struct rt_entry *rtlookup();
+struct rt_entry *rtfind();
diff --git a/usr.sbin/routed/tables.c b/usr.sbin/routed/tables.c
new file mode 100644
index 000000000000..ac837f80dffb
--- /dev/null
+++ b/usr.sbin/routed/tables.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/syslog.h>
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#ifdef RTM_ADD
+#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
+#else
+#define FIXLEN(s) { }
+#endif
+
+int install = !DEBUG; /* if 1 call kernel */
+
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *
+rtlookup(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int doinghost = 1;
+
+ if (dst->sa_family >= af_max)
+ return (0);
+ (*afswitch[dst->sa_family].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ goto again;
+ }
+ return (0);
+}
+
+struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
+
+/*
+ * Find a route to dst as the kernel would.
+ */
+struct rt_entry *
+rtfind(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int af = dst->sa_family;
+ int doinghost = 1, (*match)();
+
+ if (af >= af_max)
+ return (0);
+ (*afswitch[af].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (doinghost) {
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ } else {
+ if (rt->rt_dst.sa_family == af &&
+ (*match)(&rt->rt_dst, dst))
+ return (rt);
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ match = afswitch[af].af_netmatch;
+ goto again;
+ }
+#ifdef notyet
+ /*
+ * Check for wildcard gateway, by convention network 0.
+ */
+ if (dst != &wildcard) {
+ dst = &wildcard, hash = 0;
+ goto again;
+ }
+#endif
+ return (0);
+}
+
+rtadd(dst, gate, metric, state)
+ struct sockaddr *dst, *gate;
+ int metric, state;
+{
+ struct afhash h;
+ register struct rt_entry *rt;
+ struct rthash *rh;
+ int af = dst->sa_family, flags;
+ u_int hash;
+
+ if (af >= af_max)
+ return;
+ (*afswitch[af].af_hash)(dst, &h);
+ flags = (*afswitch[af].af_rtflags)(dst);
+ /*
+ * Subnet flag isn't visible to kernel, move to state. XXX
+ */
+ FIXLEN(dst);
+ FIXLEN(gate);
+ if (flags & RTF_SUBNET) {
+ state |= RTS_SUBNET;
+ flags &= ~RTF_SUBNET;
+ }
+ if (flags & RTF_HOST) {
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+ } else {
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ }
+ rt = (struct rt_entry *)malloc(sizeof (*rt));
+ if (rt == 0)
+ return;
+ rt->rt_hash = hash;
+ rt->rt_dst = *dst;
+ rt->rt_router = *gate;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
+ if (rt->rt_ifp == 0)
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ if ((state & RTS_INTERFACE) == 0)
+ rt->rt_flags |= RTF_GATEWAY;
+ rt->rt_metric = metric;
+ insque(rt, rh);
+ TRACE_ACTION("ADD", rt);
+ /*
+ * If the ioctl fails because the gateway is unreachable
+ * from this host, discard the entry. This should only
+ * occur because of an incorrect entry in /etc/gateways.
+ */
+ if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+ rtioctl(ADD, &rt->rt_rt) < 0) {
+ if (errno != EEXIST && gate->sa_family < af_max)
+ syslog(LOG_ERR,
+ "adding route to net/host %s through gateway %s: %m\n",
+ (*afswitch[dst->sa_family].af_format)(dst),
+ (*afswitch[gate->sa_family].af_format)(gate));
+ perror("ADD ROUTE");
+ if (errno == ENETUNREACH) {
+ TRACE_ACTION("DELETE", rt);
+ remque(rt);
+ free((char *)rt);
+ }
+ }
+}
+
+rtchange(rt, gate, metric)
+ struct rt_entry *rt;
+ struct sockaddr *gate;
+ short metric;
+{
+ int add = 0, delete = 0, newgateway = 0;
+ struct rtuentry oldroute;
+
+ FIXLEN(gate);
+ FIXLEN(&(rt->rt_router));
+ FIXLEN(&(rt->rt_dst));
+ if (!equal(&rt->rt_router, gate)) {
+ newgateway++;
+ TRACE_ACTION("CHANGE FROM ", rt);
+ } else if (metric != rt->rt_metric)
+ TRACE_NEWMETRIC(rt, metric);
+ if ((rt->rt_state & RTS_INTERNAL) == 0) {
+ /*
+ * If changing to different router, we need to add
+ * new route and delete old one if in the kernel.
+ * If the router is the same, we need to delete
+ * the route if has become unreachable, or re-add
+ * it if it had been unreachable.
+ */
+ if (newgateway) {
+ add++;
+ if (rt->rt_metric != HOPCNT_INFINITY)
+ delete++;
+ } else if (metric == HOPCNT_INFINITY)
+ delete++;
+ else if (rt->rt_metric == HOPCNT_INFINITY)
+ add++;
+ }
+ if (delete)
+ oldroute = rt->rt_rt;
+ if ((rt->rt_state & RTS_INTERFACE) && delete) {
+ rt->rt_state &= ~RTS_INTERFACE;
+ rt->rt_flags |= RTF_GATEWAY;
+ if (metric > rt->rt_metric && delete)
+ syslog(LOG_ERR, "%s route to interface %s (timed out)",
+ add? "changing" : "deleting",
+ rt->rt_ifp ? rt->rt_ifp->int_name : "?");
+ }
+ if (add) {
+ 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;
+ rt->rt_state |= RTS_CHANGED;
+ if (newgateway)
+ TRACE_ACTION("CHANGE TO ", rt);
+#ifndef RTM_ADD
+ if (add && rtioctl(ADD, &rt->rt_rt) < 0)
+ perror("ADD ROUTE");
+ if (delete && rtioctl(DELETE, &oldroute) < 0)
+ perror("DELETE ROUTE");
+#else
+ if (delete && !add) {
+ if (rtioctl(DELETE, &oldroute) < 0)
+ perror("DELETE ROUTE");
+ } else if (!delete && add) {
+ if (rtioctl(ADD, &rt->rt_rt) < 0)
+ perror("ADD ROUTE");
+ } else if (delete && add) {
+ if (rtioctl(CHANGE, &rt->rt_rt) < 0)
+ perror("CHANGE ROUTE");
+ }
+#endif
+}
+
+rtdelete(rt)
+ struct rt_entry *rt;
+{
+
+ TRACE_ACTION("DELETE", rt);
+ FIXLEN(&(rt->rt_router));
+ FIXLEN(&(rt->rt_dst));
+ if (rt->rt_metric < HOPCNT_INFINITY) {
+ if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
+ syslog(LOG_ERR,
+ "deleting route to interface %s? (timed out?)",
+ rt->rt_ifp->int_name);
+ if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+ rtioctl(DELETE, &rt->rt_rt) < 0)
+ perror("rtdelete");
+ }
+ remque(rt);
+ free((char *)rt);
+}
+
+rtdeleteall(sig)
+ int sig;
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1;
+
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_state & RTS_INTERFACE ||
+ rt->rt_metric >= HOPCNT_INFINITY)
+ continue;
+ TRACE_ACTION("DELETE", rt);
+ if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
+ rtioctl(DELETE, &rt->rt_rt) < 0)
+ perror("rtdeleteall");
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ exit(sig);
+}
+
+/*
+ * If we have an interface to the wide, wide world,
+ * add an entry for an Internet default route (wildcard) to the internal
+ * tables and advertise it. This route is not added to the kernel routes,
+ * but this entry prevents us from listening to other people's defaults
+ * and installing them in the kernel here.
+ */
+rtdefault()
+{
+ extern struct sockaddr inet_default;
+
+ rtadd(&inet_default, &inet_default, 1,
+ RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
+}
+
+rtinit()
+{
+ register struct rthash *rh;
+
+ for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+ for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+}
+
+rtioctl(action, ort)
+ int action;
+ struct rtuentry *ort;
+{
+#ifndef RTM_ADD
+ if (install == 0)
+ return (errno = 0);
+ ort->rtu_rtflags = ort->rtu_flags;
+ switch (action) {
+
+ case ADD:
+ return (ioctl(s, SIOCADDRT, (char *)ort));
+
+ case DELETE:
+ return (ioctl(s, SIOCDELRT, (char *)ort));
+
+ default:
+ return (-1);
+ }
+#else /* RTM_ADD */
+ struct {
+ struct rt_msghdr w_rtm;
+ struct sockaddr_in w_dst;
+ struct sockaddr w_gate;
+ struct sockaddr_in w_netmask;
+ } w;
+#define rtm w.w_rtm
+
+ bzero((char *)&w, sizeof(w));
+ rtm.rtm_msglen = sizeof(w);
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = (action == ADD ? RTM_ADD :
+ (action == DELETE ? RTM_DELETE : RTM_CHANGE));
+#undef rt_dst
+ rtm.rtm_flags = ort->rtu_flags;
+ rtm.rtm_seq = ++seqno;
+ rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+ bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
+ bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
+ w.w_dst.sin_family = AF_INET;
+ w.w_dst.sin_len = sizeof(w.w_dst);
+ w.w_gate.sa_family = AF_INET;
+ w.w_gate.sa_len = sizeof(w.w_gate);
+ if (rtm.rtm_flags & RTF_HOST) {
+ rtm.rtm_msglen -= sizeof(w.w_netmask);
+ } else {
+ register char *cp;
+ int len;
+
+ rtm.rtm_addrs |= RTA_NETMASK;
+ w.w_netmask.sin_addr.s_addr =
+ inet_maskof(w.w_dst.sin_addr.s_addr);
+ for (cp = (char *)(1 + &w.w_netmask.sin_addr);
+ --cp > (char *) &w.w_netmask; )
+ if (*cp)
+ break;
+ len = cp - (char *)&w.w_netmask;
+ if (len) {
+ len++;
+ w.w_netmask.sin_len = len;
+ len = 1 + ((len - 1) | (sizeof(long) - 1));
+ } else
+ len = sizeof(long);
+ rtm.rtm_msglen -= (sizeof(w.w_netmask) - len);
+ }
+ errno = 0;
+ return (install ? write(r, (char *)&w, rtm.rtm_msglen) : (errno = 0));
+#endif /* RTM_ADD */
+}
diff --git a/usr.sbin/routed/timer.c b/usr.sbin/routed/timer.c
new file mode 100644
index 000000000000..643e2f5ef55f
--- /dev/null
+++ b/usr.sbin/routed/timer.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)timer.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+int faketime;
+
+/*
+ * Timer routine. Performs routing information supply
+ * duties and manages timers on routing table entries.
+ * Management of the RTS_CHANGED bit assumes that we broadcast
+ * each time called.
+ */
+void
+timer()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1, timetobroadcast;
+ extern int externalinterfaces;
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ faketime += TIMER_RATE;
+ if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
+ ifinit();
+ timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ /*
+ * We don't advance time on a routing entry for
+ * a passive gateway, or any interface if we're
+ * not acting as supplier.
+ */
+ if (!(rt->rt_state & RTS_PASSIVE) &&
+ (supplier || !(rt->rt_state & RTS_INTERFACE)))
+ rt->rt_timer += TIMER_RATE;
+ if (rt->rt_timer >= GARBAGE_TIME) {
+ rt = rt->rt_back;
+ rtdelete(rt->rt_forw);
+ continue;
+ }
+ if (rt->rt_timer >= EXPIRE_TIME &&
+ rt->rt_metric < HOPCNT_INFINITY)
+ rtchange(rt, &rt->rt_router, HOPCNT_INFINITY);
+ rt->rt_state &= ~RTS_CHANGED;
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (timetobroadcast) {
+ toall(supply, 0, (struct interface *)NULL);
+ lastbcast = now;
+ lastfullupdate = now;
+ needupdate = 0; /* cancel any pending dynamic update */
+ nextbcast.tv_sec = 0;
+ }
+}
+
+/*
+ * On hangup, let everyone know we're going away.
+ */
+hup()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1;
+
+ if (supplier) {
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
+ rt->rt_metric = HOPCNT_INFINITY;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ toall(supply, 0, (struct interface *)NULL);
+ }
+ exit(1);
+}
diff --git a/usr.sbin/routed/trace.c b/usr.sbin/routed/trace.c
new file mode 100644
index 000000000000..f630001cbf35
--- /dev/null
+++ b/usr.sbin/routed/trace.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#define RIPCMDS
+#include "defs.h"
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+#define NRECORDS 50 /* size of circular trace buffer */
+#ifdef DEBUG
+FILE *ftrace = stdout;
+int traceactions = 0;
+#endif
+static struct timeval lastlog;
+static char *savetracename;
+
+traceinit(ifp)
+ register struct interface *ifp;
+{
+ static int iftraceinit();
+
+ if (iftraceinit(ifp, &ifp->int_input) &&
+ iftraceinit(ifp, &ifp->int_output))
+ return;
+ tracehistory = 0;
+ fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
+}
+
+static
+iftraceinit(ifp, ifd)
+ struct interface *ifp;
+ register struct ifdebug *ifd;
+{
+ register struct iftrace *t;
+
+ ifd->ifd_records =
+ (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
+ if (ifd->ifd_records == 0)
+ return (0);
+ ifd->ifd_front = ifd->ifd_records;
+ ifd->ifd_count = 0;
+ for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
+ t->ift_size = 0;
+ t->ift_packet = 0;
+ }
+ ifd->ifd_if = ifp;
+ return (1);
+}
+
+traceon(file)
+ char *file;
+{
+ struct stat stbuf;
+
+ if (ftrace != NULL)
+ return;
+ if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
+ return;
+ savetracename = file;
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ ftrace = fopen(file, "a");
+ if (ftrace == NULL)
+ return;
+ dup2(fileno(ftrace), 1);
+ dup2(fileno(ftrace), 2);
+ traceactions = 1;
+ fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
+}
+
+traceoff()
+{
+ if (!traceactions)
+ return;
+ if (ftrace != NULL) {
+ int fd = open(_PATH_DEVNULL, O_RDWR);
+
+ fprintf(ftrace, "Tracing disabled %s\n",
+ ctime((time_t *)&now.tv_sec));
+ fflush(ftrace);
+ (void) dup2(fd, 1);
+ (void) dup2(fd, 2);
+ (void) close(fd);
+ fclose(ftrace);
+ ftrace = NULL;
+ }
+ traceactions = 0;
+ tracehistory = 0;
+ tracepackets = 0;
+ tracecontents = 0;
+}
+
+void
+sigtrace(s)
+ int s;
+{
+
+ if (s == SIGUSR2)
+ traceoff();
+ else if (ftrace == NULL && savetracename)
+ traceon(savetracename);
+ else
+ bumploglevel();
+}
+
+/*
+ * Move to next higher level of tracing when -t option processed or
+ * SIGUSR1 is received. Successive levels are:
+ * traceactions
+ * traceactions + tracepackets
+ * traceactions + tracehistory (packets and contents after change)
+ * traceactions + tracepackets + tracecontents
+ */
+bumploglevel()
+{
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ if (traceactions == 0) {
+ traceactions++;
+ if (ftrace)
+ fprintf(ftrace, "Tracing actions started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ } else if (tracepackets == 0) {
+ tracepackets++;
+ tracehistory = 0;
+ tracecontents = 0;
+ if (ftrace)
+ fprintf(ftrace, "Tracing packets started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ } else if (tracehistory == 0) {
+ tracehistory++;
+ if (ftrace)
+ fprintf(ftrace, "Tracing history started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ } else {
+ tracepackets++;
+ tracecontents++;
+ tracehistory = 0;
+ if (ftrace)
+ fprintf(ftrace, "Tracing packet contents started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ }
+ if (ftrace)
+ fflush(ftrace);
+}
+
+trace(ifd, who, p, len, m)
+ register struct ifdebug *ifd;
+ struct sockaddr *who;
+ char *p;
+ int len, m;
+{
+ register struct iftrace *t;
+
+ if (ifd->ifd_records == 0)
+ return;
+ t = ifd->ifd_front++;
+ if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
+ ifd->ifd_front = ifd->ifd_records;
+ if (ifd->ifd_count < NRECORDS)
+ ifd->ifd_count++;
+ if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
+ free(t->ift_packet);
+ t->ift_packet = 0;
+ }
+ t->ift_stamp = now;
+ t->ift_who = *who;
+ if (len > 0 && t->ift_packet == 0) {
+ t->ift_packet = malloc(len);
+ if (t->ift_packet == 0)
+ len = 0;
+ }
+ if (len > 0)
+ bcopy(p, t->ift_packet, len);
+ t->ift_size = len;
+ t->ift_metric = m;
+}
+
+traceaction(fd, action, rt)
+ FILE *fd;
+ char *action;
+ struct rt_entry *rt;
+{
+ struct sockaddr_in *dst, *gate;
+ static struct bits {
+ int t_bits;
+ char *t_name;
+ } flagbits[] = {
+ { RTF_UP, "UP" },
+ { RTF_GATEWAY, "GATEWAY" },
+ { RTF_HOST, "HOST" },
+ { 0 }
+ }, statebits[] = {
+ { RTS_PASSIVE, "PASSIVE" },
+ { RTS_REMOTE, "REMOTE" },
+ { RTS_INTERFACE,"INTERFACE" },
+ { RTS_CHANGED, "CHANGED" },
+ { RTS_INTERNAL, "INTERNAL" },
+ { RTS_EXTERNAL, "EXTERNAL" },
+ { RTS_SUBNET, "SUBNET" },
+ { 0 }
+ };
+ register struct bits *p;
+ register int first;
+ char *cp;
+ struct interface *ifp;
+
+ if (fd == NULL)
+ return;
+ if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+ fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
+ lastlog = now;
+ }
+ fprintf(fd, "%s ", action);
+ dst = (struct sockaddr_in *)&rt->rt_dst;
+ gate = (struct sockaddr_in *)&rt->rt_router;
+ fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
+ fprintf(fd, "router %s, metric %d, flags",
+ inet_ntoa(gate->sin_addr), rt->rt_metric);
+ cp = " %s";
+ for (first = 1, p = flagbits; p->t_bits > 0; p++) {
+ if ((rt->rt_flags & p->t_bits) == 0)
+ continue;
+ fprintf(fd, cp, p->t_name);
+ if (first) {
+ cp = "|%s";
+ first = 0;
+ }
+ }
+ fprintf(fd, " state");
+ cp = " %s";
+ for (first = 1, p = statebits; p->t_bits > 0; p++) {
+ if ((rt->rt_state & p->t_bits) == 0)
+ continue;
+ fprintf(fd, cp, p->t_name);
+ if (first) {
+ cp = "|%s";
+ first = 0;
+ }
+ }
+ fprintf(fd, " timer %d\n", rt->rt_timer);
+ if (tracehistory && !tracepackets &&
+ (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
+ dumpif(fd, rt->rt_ifp);
+ fflush(fd);
+ if (ferror(fd))
+ traceoff();
+}
+
+tracenewmetric(fd, rt, newmetric)
+ FILE *fd;
+ struct rt_entry *rt;
+ int newmetric;
+{
+ struct sockaddr_in *dst, *gate;
+
+ if (fd == NULL)
+ return;
+ if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+ fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
+ lastlog = now;
+ }
+ dst = (struct sockaddr_in *)&rt->rt_dst;
+ gate = (struct sockaddr_in *)&rt->rt_router;
+ fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
+ fprintf(fd, "router %s, from %d to %d\n",
+ inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
+ fflush(fd);
+ if (ferror(fd))
+ traceoff();
+}
+
+dumpif(fd, ifp)
+ FILE *fd;
+ register struct interface *ifp;
+{
+ if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
+ fprintf(fd, "*** Packet history for interface %s ***\n",
+ ifp->int_name);
+#ifdef notneeded
+ dumptrace(fd, "to", &ifp->int_output);
+#endif
+ dumptrace(fd, "from", &ifp->int_input);
+ fprintf(fd, "*** end packet history ***\n");
+ }
+}
+
+dumptrace(fd, dir, ifd)
+ FILE *fd;
+ char *dir;
+ register struct ifdebug *ifd;
+{
+ register struct iftrace *t;
+ char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+
+ if (ifd->ifd_front == ifd->ifd_records &&
+ ifd->ifd_front->ift_size == 0) {
+ fprintf(fd, "%s: no packets.\n", cp);
+ fflush(fd);
+ return;
+ }
+ fprintf(fd, "%s trace:\n", cp);
+ t = ifd->ifd_front - ifd->ifd_count;
+ if (t < ifd->ifd_records)
+ t += NRECORDS;
+ for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
+ if (t >= ifd->ifd_records + NRECORDS)
+ t = ifd->ifd_records;
+ if (t->ift_size == 0)
+ continue;
+ dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
+ &t->ift_stamp);
+ }
+}
+
+dumppacket(fd, dir, who, cp, size, stamp)
+ FILE *fd;
+ struct sockaddr_in *who; /* should be sockaddr */
+ char *dir, *cp;
+ register int size;
+ struct timeval *stamp;
+{
+ register struct rip *msg = (struct rip *)cp;
+ register struct netinfo *n;
+
+ if (fd == NULL)
+ return;
+ if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
+ fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
+ dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
+ ctime((time_t *)&stamp->tv_sec));
+ else {
+ fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd,
+ dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
+ fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet,
+ ctime((time_t *)&stamp->tv_sec));
+ fflush(fd);
+ return;
+ }
+ if (tracepackets && tracecontents == 0) {
+ fflush(fd);
+ return;
+ }
+ switch (msg->rip_cmd) {
+
+ case RIPCMD_REQUEST:
+ case RIPCMD_RESPONSE:
+ size -= 4 * sizeof (char);
+ n = msg->rip_nets;
+ for (; size > 0; n++, size -= sizeof (struct netinfo)) {
+ if (size < sizeof (struct netinfo)) {
+ fprintf(fd, "(truncated record, len %d)\n",
+ size);
+ break;
+ }
+ if (sizeof(n->rip_dst.sa_family) > 1)
+ n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+
+ switch ((int)n->rip_dst.sa_family) {
+
+ case AF_INET:
+ fprintf(fd, "\tdst %s metric %d\n",
+#define satosin(sa) ((struct sockaddr_in *)&sa)
+ inet_ntoa(satosin(n->rip_dst)->sin_addr),
+ ntohl(n->rip_metric));
+ break;
+
+ default:
+ fprintf(fd, "\taf %d? metric %d\n",
+ n->rip_dst.sa_family,
+ ntohl(n->rip_metric));
+ break;
+ }
+ }
+ break;
+
+ case RIPCMD_TRACEON:
+ fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
+ break;
+
+ case RIPCMD_TRACEOFF:
+ break;
+ }
+ fflush(fd);
+ if (ferror(fd))
+ traceoff();
+}
diff --git a/usr.sbin/routed/trace.h b/usr.sbin/routed/trace.h
new file mode 100644
index 000000000000..42521fc95dc1
--- /dev/null
+++ b/usr.sbin/routed/trace.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trace.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Trace record format.
+ */
+struct iftrace {
+ struct timeval ift_stamp; /* time stamp */
+ struct sockaddr ift_who; /* from/to */
+ char *ift_packet; /* pointer to packet */
+ short ift_size; /* size of packet */
+ short ift_metric; /* metric on associated metric */
+};
+
+/*
+ * Per interface packet tracing buffers. An incoming and
+ * outgoing circular buffer of packets is maintained, per
+ * interface, for debugging. Buffers are dumped whenever
+ * an interface is marked down.
+ */
+struct ifdebug {
+ struct iftrace *ifd_records; /* array of trace records */
+ struct iftrace *ifd_front; /* next empty trace record */
+ int ifd_count; /* number of unprinted records */
+ struct interface *ifd_if; /* for locating stuff */
+};
+
+/*
+ * Packet tracing stuff.
+ */
+int tracepackets; /* watch packets as they go by */
+int tracecontents; /* watch packet contents as they go by */
+int traceactions; /* on/off */
+int tracehistory; /* on/off */
+FILE *ftrace; /* output trace file */
+
+#define TRACE_ACTION(action, route) { \
+ if (traceactions) \
+ traceaction(ftrace, action, route); \
+ }
+#define TRACE_NEWMETRIC(route, newmetric) { \
+ if (traceactions) \
+ tracenewmetric(ftrace, route, newmetric); \
+ }
+#define TRACE_INPUT(ifp, src, pack, size) { \
+ if (tracehistory) { \
+ ifp = if_iflookup(src); \
+ if (ifp) \
+ trace(&ifp->int_input, src, pack, size, \
+ ntohl(ifp->int_metric)); \
+ } \
+ if (tracepackets) \
+ dumppacket(ftrace, "from", src, pack, size, &now); \
+ }
+#define TRACE_OUTPUT(ifp, dst, size) { \
+ if (tracehistory && ifp) \
+ trace(&ifp->int_output, dst, packet, size, ifp->int_metric); \
+ if (tracepackets) \
+ dumppacket(ftrace, "to", dst, packet, size, &now); \
+ }
diff --git a/usr.sbin/routed/trace/Makefile b/usr.sbin/routed/trace/Makefile
new file mode 100644
index 000000000000..01b16b3436be
--- /dev/null
+++ b/usr.sbin/routed/trace/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= trace
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/routed/trace/trace.c b/usr.sbin/routed/trace/trace.c
new file mode 100644
index 000000000000..38c630cfe953
--- /dev/null
+++ b/usr.sbin/routed/trace/trace.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sockaddr_in myaddr;
+char packet[MAXPACKETSIZE];
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int size, s;
+ struct sockaddr from;
+ struct sockaddr_in router;
+ register struct rip *msg = (struct rip *)packet;
+ struct hostent *hp;
+ struct servent *sp;
+
+ if (argc < 3) {
+usage:
+ printf("usage: trace cmd machines,\n");
+ printf("cmd either \"on filename\", or \"off\"\n");
+ exit(1);
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_port = htons(IPPORT_RESERVED-1);
+ if (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
+ perror("bind");
+ exit(2);
+ }
+
+ argv++, argc--;
+ msg->rip_cmd = strcmp(*argv, "on") == 0 ?
+ RIPCMD_TRACEON : RIPCMD_TRACEOFF;
+ msg->rip_vers = RIPVERSION;
+ argv++, argc--;
+ size = sizeof (int);
+ if (msg->rip_cmd == RIPCMD_TRACEON) {
+ strcpy(msg->rip_tracefile, *argv);
+ size += strlen(*argv);
+ argv++, argc--;
+ }
+ if (argc == 0)
+ goto usage;
+ bzero((char *)&router, sizeof (router));
+ router.sin_family = AF_INET;
+ sp = getservbyname("router", "udp");
+ if (sp == 0) {
+ printf("udp/router: service unknown\n");
+ exit(1);
+ }
+ router.sin_port = sp->s_port;
+ while (argc > 0) {
+ router.sin_family = AF_INET;
+ router.sin_addr.s_addr = inet_addr(*argv);
+ if (router.sin_addr.s_addr == -1) {
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "trace: %s: ", *argv);
+ herror((char *)NULL);
+ continue;
+ }
+ bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
+ }
+ if (sendto(s, packet, size, 0,
+ (struct sockaddr *)&router, sizeof(router)) < 0)
+ perror(*argv);
+ argv++, argc--;
+ }
+}