diff options
author | svn2git <svn2git@FreeBSD.org> | 1994-07-01 08:00:00 +0000 |
---|---|---|
committer | svn2git <svn2git@FreeBSD.org> | 1994-07-01 08:00:00 +0000 |
commit | 5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch) | |
tree | e779b5a6edddbb949b7990751b12d6f25304ba86 /usr.sbin | |
parent | a16f65c7d117419bd266c28a1901ef129a337569 (diff) |
Release FreeBSD 1.1.5.1upstream/1.1.5.1_cvsrelease/1.1.5.1_cvsreleng/1
This commit was manufactured to restore the state of the 1.1.5.1-RELEASE image.
Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'usr.sbin')
118 files changed, 17702 insertions, 483 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index c625fea95cad..e189ba5ccfaa 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,10 +1,11 @@ # @(#)Makefile 5.6.1.2 (Berkeley) 5/8/91 -SUBDIR= accton arp chown chroot config cron dbsym dev_mkdb diskpart \ - edquota fdformat flcopy ftinfo gettable htable inetd iostat kgmon \ - kvm_mkdb lpr mtree named portmap pppstats pwd_mkdb quotaon repquota \ - rmt rwhod sendmail sliplogin spkrtest swapinfo syslogd timed \ - traceroute trpt trsp vipw yp +SUBDIR= XNSrouted ac accton arp chown chroot config cron dbsym dev_mkdb \ + diskpart edquota fdcontrol fdformat ftinfo gettable htable \ + inetd iostat kbdcontrol kgmon kvm_mkdb lpr lptcontrol mrouted \ + mtree named portmap pppstats pwd_mkdb quotaon repquota rmt \ + routed rwhod sa sendmail sliplogin slstat spkrtest swapinfo \ + syslogd timed traceroute trpt trsp vidcontrol vipw xten yp .if make(clean) || make(cleandir) SUBDIR+=bad144 diff --git a/usr.sbin/XNSrouted/Makefile b/usr.sbin/XNSrouted/Makefile new file mode 100644 index 000000000000..9f6583f8ee56 --- /dev/null +++ b/usr.sbin/XNSrouted/Makefile @@ -0,0 +1,10 @@ +# From: @(#)Makefile 5.14 (Berkeley) 2/26/91 +# $Id: Makefile,v 1.1 1993/09/07 14:13:06 rgrimes Exp $ + +PROG= XNSrouted +MAN8= XNSrouted.8 +SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c trace.c +DPADD= ${LIBUTIL} +LDADD= -lutil + +.include <bsd.prog.mk> diff --git a/usr.sbin/XNSrouted/XNSrouted.8 b/usr.sbin/XNSrouted/XNSrouted.8 new file mode 100644 index 000000000000..144cb1d40453 --- /dev/null +++ b/usr.sbin/XNSrouted/XNSrouted.8 @@ -0,0 +1,186 @@ +.\" Copyright (c) 1986, 1991 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. +.\" +.\" @(#)XNSrouted.8 6.4 (Berkeley) 3/16/91 +.\" +.Dd March 16, 1991 +.Dt XNSROUTED 8 +.Os BSD 4.3 +.Sh NAME +.Nm XNSrouted +.Nd NS Routing Information Protocol daemon +.Sh SYNOPSIS +.Nm XNSrouted +.Op Fl q +.Op Fl s +.Op Fl t +.Op Ar logfile +.Sh DESCRIPTION +.Nm XNSrouted +is invoked at boot time to manage the Xerox NS routing tables. +The NS routing daemon uses the Xerox NS Routing +Information Protocol in maintaining up to date kernel routing +table entries. +.Pp +Available options: +.Bl -tag -width logfile +.It Fl q +Do not supply routing information (opposite of +.Fl s +option below). +.It Fl s +Forces +.Nm XNSrouted +to supply routing information whether it is acting as an internetwork +router or not. +.It Fl t +All packets sent or received are +printed on the standard output. In addition, +.Nm XNSrouted +will not divorce itself from the controlling terminal +so that interrupts from the keyboard will kill the process. +.It Ar logfile +Name of file in which +.Nm XNSrouted Ns 's +actions should be logged. This log contains information +about any changes to the routing tables and a history of +recent messages sent and received which are related to +the changed route. +.El +.Pp +In normal operation +.Nm XNSrouted +listens +for routing information packets. If the host is connected to +multiple NS networks, it periodically supplies copies +of its routing tables to any directly connected hosts +and networks. +.Pp +When +.Nm XNSrouted +is started, it uses the +.Dv SIOCGIFCONF +.Xr ioctl 2 +to find those +directly connected interfaces configured into the +system and marked +.Dq up +(the software loopback interface +is ignored). If multiple interfaces +are present, it is assumed the host will forward packets +between networks. +.Nm XNSrouted +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 XNSrouted +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 +.Dq hop count +metric (a count of 16, or greater, is +considered +.Dq infinite ) . +The metric associated with each +route returned provides a metric +.Em relative to the sender . +.Pp +.Em Response +packets received by +.Nm XNSrouted +are used to update the routing tables if one of the following +conditions is satisfied: +.Bl -bullet +.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 XNSrouted +records the change in its internal tables and generates a +.Em response +packet to all directly connected hosts and networks. +.Xr Routed 8 +waits a short period +of time (no more than 30 seconds) before modifying the kernel's +routing tables to allow possible unstable situations to settle. +.Pp +In addition to processing incoming packets, +.Nm XNSrouted +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 +to other routers. +.Pp +Hosts acting as internetwork routers gratuitously supply their +routing tables every 30 seconds to all directly connected hosts +and networks. +.Sh SEE ALSO +.Xr idp 4 +.Rs +.%T "Internet Transport Protocols" +.%R "XSIS 028112" +.%Q "Xerox System Integration Standard" +.Re +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.sbin/XNSrouted/af.c b/usr.sbin/XNSrouted/af.c new file mode 100644 index 000000000000..d131e8773992 --- /dev/null +++ b/usr.sbin/XNSrouted/af.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.11 (Berkeley) 2/26/91"; +#endif /* not lint */ + +#include "defs.h" + +/* + * Address family support routines + */ +int null_hash(), null_netmatch(), null_output(), + null_portmatch(), null_portcheck(), + null_checkhost(), null_ishost(), null_canon(); +int xnnet_hash(), xnnet_netmatch(), xnnet_output(), + xnnet_portmatch(), + xnnet_checkhost(), xnnet_ishost(), xnnet_canon(); +#define NIL \ + { null_hash, null_netmatch, null_output, \ + null_portmatch, null_portcheck, null_checkhost, \ + null_ishost, null_canon } +#define XNSNET \ + { xnnet_hash, xnnet_netmatch, xnnet_output, \ + xnnet_portmatch, xnnet_portmatch, xnnet_checkhost, \ + xnnet_ishost, xnnet_canon } + +struct afswitch afswitch[AF_MAX] = + { NIL, NIL, NIL, NIL, NIL, NIL, XNSNET, NIL, NIL, NIL, NIL }; + +struct sockaddr_ns xnnet_default = { sizeof(struct sockaddr_ns), AF_NS }; + +union ns_net ns_anynet; +union ns_net ns_zeronet; + +xnnet_hash(sns, hp) + register struct sockaddr_ns *sns; + struct afhash *hp; +{ + register long hash = 0; + register u_short *s = sns->sns_addr.x_host.s_host; + union ns_net_u net; + + net.net_e = sns->sns_addr.x_net; + hp->afh_nethash = net.long_e; + hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s; + hp->afh_hosthash = hash; +} + +xnnet_netmatch(sxn1, sxn2) + struct sockaddr_ns *sxn1, *sxn2; +{ + return (ns_neteq(sxn1->sns_addr, sxn2->sns_addr)); +} + +/* + * Verify the message is from the right port. + */ +xnnet_portmatch(sns) + register struct sockaddr_ns *sns; +{ + + return (ntohs(sns->sns_addr.x_port) == IDPPORT_RIF ); +} + + +/* + * xns output routine. + */ +#ifdef DEBUG +int do_output = 0; +#endif +xnnet_output(flags, sns, size) + int flags; + struct sockaddr_ns *sns; + int size; +{ + struct sockaddr_ns dst; + + dst = *sns; + sns = &dst; + if (sns->sns_addr.x_port == 0) + sns->sns_addr.x_port = htons(IDPPORT_RIF); +#ifdef DEBUG + if(do_output || ntohs(msg->rip_cmd) == RIPCMD_REQUEST) +#endif + /* + * Kludge to allow us to get routes out to machines that + * don't know their addresses yet; send to that address on + * ALL connected nets + */ + if (ns_neteqnn(sns->sns_addr.x_net, ns_zeronet)) { + extern struct interface *ifnet; + register struct interface *ifp; + + for (ifp = ifnet; ifp; ifp = ifp->int_next) { + sns->sns_addr.x_net = + satons_addr(ifp->int_addr).x_net; + (void) sendto(s, msg, size, flags, + (struct sockaddr *)sns, sizeof (*sns)); + } + return; + } + + (void) sendto(s, msg, size, flags, + (struct sockaddr *)sns, sizeof (*sns)); +} + +/* + * Return 1 if we want this route. + * We use this to disallow route net G entries for one for multiple + * point to point links. + */ +xnnet_checkhost(sns) + struct sockaddr_ns *sns; +{ + register struct interface *ifp = if_ifwithnet(sns); + /* + * We want this route if there is no more than one + * point to point interface with this network. + */ + if (ifp == 0 || (ifp->int_flags & IFF_POINTOPOINT)==0) return (1); + return (ifp->int_sq.n == ifp->int_sq.p); +} + +/* + * Return 1 if the address is + * for a host, 0 for a network. + */ +xnnet_ishost(sns) +struct sockaddr_ns *sns; +{ + register u_short *s = sns->sns_addr.x_host.s_host; + + if ((s[0]==0xffff) && (s[1]==0xffff) && (s[2]==0xffff)) + return (0); + else + return (1); +} + +xnnet_canon(sns) + struct sockaddr_ns *sns; +{ + + sns->sns_addr.x_port = 0; +} + +/*ARGSUSED*/ +null_hash(addr, hp) + struct sockaddr *addr; + struct afhash *hp; +{ + + hp->afh_nethash = hp->afh_hosthash = 0; +} + +/*ARGSUSED*/ +null_netmatch(a1, a2) + struct sockaddr *a1, *a2; +{ + + return (0); +} + +/*ARGSUSED*/ +null_output(s, f, a1, n) + int s, f; + struct sockaddr *a1; + int n; +{ + + ; +} + +/*ARGSUSED*/ +null_portmatch(a1) + struct sockaddr *a1; +{ + + return (0); +} + +/*ARGSUSED*/ +null_portcheck(a1) + struct sockaddr *a1; +{ + + return (0); +} + +/*ARGSUSED*/ +null_ishost(a1) + struct sockaddr *a1; +{ + + return (0); +} + +/*ARGSUSED*/ +null_checkhost(a1) + struct sockaddr *a1; +{ + + return (0); +} + +/*ARGSUSED*/ +null_canon(a1) + struct sockaddr *a1; +{ + + ; +} diff --git a/usr.sbin/XNSrouted/af.h b/usr.sbin/XNSrouted/af.h new file mode 100644 index 000000000000..d2b27c531380 --- /dev/null +++ b/usr.sbin/XNSrouted/af.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983 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 5.1 (Berkeley) 6/4/85 (routed/af.h) + * + * @(#)af.h 5.2 (Berkeley) 6/1/90 + */ + +/* + * 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 for host or net */ + int (*af_ishost)(); /* tells if address is valid */ + int (*af_canon)(); /* canonicalize address for compares */ +}; + +/* + * Structure returned by af_hash routines. + */ +struct afhash { + u_int afh_hosthash; /* host based hash */ + u_int afh_nethash; /* network based hash */ +}; + +struct afswitch afswitch[AF_MAX]; /* table proper */ diff --git a/usr.sbin/XNSrouted/defs.h b/usr.sbin/XNSrouted/defs.h new file mode 100644 index 000000000000..5414d8c08ca3 --- /dev/null +++ b/usr.sbin/XNSrouted/defs.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1983 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 5.9 (Berkeley) 2/26/91 + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <net/route.h> +#include <netns/ns.h> +#include <netns/idp.h> +#if defined(vax) || defined(pdp11) +#define xnnet(x) ((u_long) (x)->rip_dst[1] << 16 | (u_long) (x)->rip_dst[0] ) +#else +#define xnnet(x) ((u_long) (x)->rip_dst[0] << 16 | (u_long) (x)->rip_dst[1] ) +#endif +#define IDPPORT_RIF 1 + +#include <stdio.h> +#include <syslog.h> + +#include "protocol.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 (5*60) + +#define equal(a1, a2) \ + (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) +#define min(a,b) ((a)>(b)?(b):(a)) + +struct sockaddr_ns addr; /* Daemon's Address */ +int s; /* Socket to listen on */ +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 */ +int timeval; /* local idea of time */ +int noteremoterequests; /* squawk on requests from non-local nets */ + +char packet[MAXPACKETSIZE+sizeof(struct idp)+1]; +struct rip *msg; + +char **argv0; + +int sndmsg(); +int supply(); +int cleanup(); diff --git a/usr.sbin/XNSrouted/if.c b/usr.sbin/XNSrouted/if.c new file mode 100644 index 000000000000..0f597a66fac3 --- /dev/null +++ b/usr.sbin/XNSrouted/if.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1983 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. + * + * static char sccsid[] = "@(#)if.c 5.1 (Berkeley) 6/4/85"; (routed/if.c) + */ + +#ifndef lint +static char sccsid[] = "@(#)if.c 5.2 (Berkeley) 6/1/90"; +#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 (maybe == 0 && (*netmatch)(addr, &ifp->int_addr)) + maybe = ifp; + } + if (ifp == 0) + ifp = maybe; + return (ifp); +} diff --git a/usr.sbin/XNSrouted/input.c b/usr.sbin/XNSrouted/input.c new file mode 100644 index 000000000000..7dc64fa5cc9c --- /dev/null +++ b/usr.sbin/XNSrouted/input.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.9 (Berkeley) 6/1/90"; +#endif /* not lint */ + +/* + * XNS Routing Table Management Daemon + */ +#include "defs.h" + +struct sockaddr * +xns_nettosa(net) +union ns_net net; +{ + static struct sockaddr_ns sxn; + extern char ether_broadcast_addr[6]; + + bzero(&sxn, sizeof (struct sockaddr_ns)); + sxn.sns_family = AF_NS; + sxn.sns_len = sizeof (sxn); + sxn.sns_addr.x_net = net; + sxn.sns_addr.x_host = *(union ns_host *)ether_broadcast_addr; + return( (struct sockaddr *)&sxn); + +} + +/* + * Process a newly received packet. + */ +rip_input(from, size) + struct sockaddr *from; + int size; +{ + struct rt_entry *rt; + struct netinfo *n; + struct interface *ifp; + int newsize; + struct afswitch *afp; + + + ifp = 0; + TRACE_INPUT(ifp, from, size); + if (from->sa_family >= AF_MAX) + return; + afp = &afswitch[from->sa_family]; + + size -= sizeof (u_short) /* command */; + n = msg->rip_nets; + + switch (ntohs(msg->rip_cmd)) { + + case RIPCMD_REQUEST: + newsize = 0; + while (size > 0) { + if (size < sizeof (struct netinfo)) + break; + size -= sizeof (struct netinfo); + + /* + * A single entry with rip_dst == DSTNETS_ALL and + * metric ``infinity'' means ``all routes''. + */ + if (ns_neteqnn(n->rip_dst, ns_anynet) && + ntohs(n->rip_metric) == HOPCNT_INFINITY && + size == 0) { + ifp = if_ifwithnet(from); + supply(from, 0, ifp); + return; + } + /* + * request for specific nets + */ + rt = rtlookup(xns_nettosa(n->rip_dst)); + if (ftrace) { + fprintf(ftrace, + "specific request for %s", + xns_nettoa(n->rip_dst)); + fprintf(ftrace, + " yields route %x\n", + rt); + } + n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY : + min(rt->rt_metric+1, HOPCNT_INFINITY)); + n++; + newsize += sizeof (struct netinfo); + } + if (newsize > 0) { + msg->rip_cmd = htons(RIPCMD_RESPONSE); + newsize += sizeof (u_short); + /* should check for if with dstaddr(from) first */ + (*afp->af_output)(0, from, newsize); + ifp = if_ifwithnet(from); + TRACE_OUTPUT(ifp, from, newsize); + if (ftrace) { + fprintf(ftrace, + "request arrived on interface %s\n", + ifp->int_name); + } + } + 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? */ + if (ifp = if_ifwithaddr(from)) { + rt = rtfind(from); + if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) + 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)) { + if(ftrace) fprintf(ftrace, "Got route\n"); + rt->rt_timer = 0; + } else if (ifp = if_ifwithdstaddr(from)) { + if(ftrace) fprintf(ftrace, "Got partner\n"); + addrouteforif(ifp); + } + for (; size > 0; size -= sizeof (struct netinfo), n++) { + struct sockaddr *sa; + if (size < sizeof (struct netinfo)) + break; + if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY) + continue; + rt = rtfind(sa = xns_nettosa(n->rip_dst)); + if (rt == 0) { + rtadd(sa, from, ntohs(n->rip_metric), 0); + continue; + } + + /* + * Update if from gateway and different, + * from anywhere and shorter, or getting stale and equivalent. + */ + if ((equal(from, &rt->rt_router) && + ntohs(n->rip_metric) != rt->rt_metric ) || + (unsigned) ntohs(n->rip_metric) < rt->rt_metric || + (rt->rt_timer > (EXPIRE_TIME/2) && + rt->rt_metric == ntohs(n->rip_metric))) { + rtchange(rt, from, ntohs(n->rip_metric)); + rt->rt_timer = 0; + } + } + return; + } +} diff --git a/usr.sbin/XNSrouted/interface.h b/usr.sbin/XNSrouted/interface.h new file mode 100644 index 000000000000..7cb416699a1b --- /dev/null +++ b/usr.sbin/XNSrouted/interface.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1983 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 5.5 (Berkeley) 6/1/90 + */ + +/* + * 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. + * We list only one address for each interface, the AF_XNS one. + */ +#define NIFADDR 3 +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 */ + 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 */ +/*XNS Specific entry */ + struct sameq { + struct sameq *n; /* q of other pt-to-pt links */ + struct sameq *p; /* with same net # */ + } int_sq; +}; + +/* + * 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_ROUTE 0x8 /* routing entry installed */ +#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */ + +#define IFF_PASSIVE 0x2000 /* can't tell if up/down */ +#define IFF_INTERFACE 0x4000 /* hardware interface */ +#define IFF_REMOTE 0x8000 /* interface isn't on this machine */ + +struct interface *if_ifwithaddr(); +struct interface *if_ifwithdstaddr(); +struct interface *if_ifwithnet(); +struct interface *if_iflookup(); diff --git a/usr.sbin/XNSrouted/main.c b/usr.sbin/XNSrouted/main.c new file mode 100644 index 000000000000..f4ddf285839c --- /dev/null +++ b/usr.sbin/XNSrouted/main.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 +char copyright[] = +"@(#) Copyright (c) 1985 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 5.11 (Berkeley) 2/26/91"; +#endif /* not lint */ + +/* + * XNS Routing Information Protocol Daemon + */ +#include "defs.h" +#include <sys/time.h> + +#include <net/if.h> + +#include <errno.h> +#include <nlist.h> +#include <signal.h> +#include <paths.h> + +int supplier = -1; /* process should supply updates */ +extern int gateway; + +struct rip *msg = (struct rip *) &packet[sizeof (struct idp)]; +void hup(), fkexit(), timer(); + +main(argc, argv) + int argc; + char *argv[]; +{ + int cc; + struct sockaddr from; + u_char retry; + + argv0 = argv; + 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, "-R") == 0) { + noteremoterequests++; + argv++, argc--; + continue; + } + if (strcmp(*argv, "-t") == 0) { + tracepackets++; + argv++, argc--; + ftrace = stderr; + tracing = 1; + continue; + } + if (strcmp(*argv, "-g") == 0) { + gateway = 1; + argv++, argc--; + continue; + } + if (strcmp(*argv, "-l") == 0) { + gateway = -1; + argv++, argc--; + continue; + } + fprintf(stderr, + "usage: xnsrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ]\n"); + exit(1); + } + + +#ifndef DEBUG + if (!tracepackets) + daemon(0, 0); +#endif + openlog("XNSrouted", LOG_PID, LOG_DAEMON); + + ns_anynet.s_net[0] = -1; ns_anynet.s_net[1] = -1; + addr.sns_family = AF_NS; + addr.sns_len = sizeof(addr); + addr.sns_port = htons(IDPPORT_RIF); + s = getsocket(SOCK_DGRAM, 0, &addr); + if (s < 0) + exit(1); + /* + * Any extra argument is considered + * a tracing log file. + */ + if (argc > 0) + traceon(*argv); + /* + * Collect an initial view of the world by + * snooping in the kernel. Then, send a request packet on all + * directly connected networks to find out what + * everyone else thinks. + */ + rtinit(); + ifinit(); + if (supplier < 0) + supplier = 0; + /* request the state of the world */ + msg->rip_cmd = htons(RIPCMD_REQUEST); + msg->rip_nets[0].rip_dst = ns_anynet; + msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY); + toall(sndmsg); + signal(SIGALRM, timer); + signal(SIGHUP, hup); + signal(SIGINT, hup); + signal(SIGEMT, fkexit); + timer(); + + + for (;;) + process(s); + +} + +process(fd) + int fd; +{ + struct sockaddr from; + int fromlen = sizeof (from), cc, omask; + struct idp *idp = (struct idp *)packet; + + cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen); + if (cc <= 0) { + if (cc < 0 && errno != EINTR) + syslog(LOG_ERR, "recvfrom: %m"); + return; + } + if (tracepackets > 1 && ftrace) { + fprintf(ftrace,"rcv %d bytes on %s ", cc, xns_ntoa(&idp->idp_dna)); + fprintf(ftrace," from %s\n", xns_ntoa(&idp->idp_sna)); + } + + if (noteremoterequests && !ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) + && !ns_neteq(idp->idp_sna, idp->idp_dna)) + { + syslog(LOG_ERR, + "net of interface (%s) != net on ether (%s)!\n", + xns_nettoa(idp->idp_dna.x_net), + xns_nettoa(idp->idp_sna.x_net)); + } + + /* We get the IDP header in front of the RIF packet*/ + cc -= sizeof (struct idp); +#define mask(s) (1<<((s)-1)) + omask = sigblock(mask(SIGALRM)); + rip_input(&from, cc); + sigsetmask(omask); +} + +getsocket(type, proto, sns) + int type, proto; + struct sockaddr_ns *sns; +{ + int domain = sns->sns_family; + int retry, s, on = 1; + + retry = 1; + while ((s = socket(domain, type, proto)) < 0 && retry) { + syslog(LOG_ERR, "socket: %m"); + sleep(5 * retry); + retry <<= 1; + } + if (retry == 0) + return (-1); + while (bind(s, (struct sockaddr *)sns, sizeof (*sns)) < 0 && retry) { + syslog(LOG_ERR, "bind: %m"); + sleep(5 * retry); + retry <<= 1; + } + if (retry == 0) + return (-1); + if (domain==AF_NS) { + struct idp idp; + if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) { + syslog(LOG_ERR, "setsockopt SEE HEADERS: %m"); + exit(1); + } + idp.idp_pt = NSPROTO_RI; + if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &idp, sizeof(idp))) { + syslog(LOG_ERR, "setsockopt SET HEADER: %m"); + exit(1); + } + } + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { + syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); + exit(1); + } + return (s); +} + +/* + * Fork and exit on EMT-- for profiling. + */ +void +fkexit() +{ + if (fork() == 0) + exit(0); +} diff --git a/usr.sbin/XNSrouted/output.c b/usr.sbin/XNSrouted/output.c new file mode 100644 index 000000000000..cdea11f2b73f --- /dev/null +++ b/usr.sbin/XNSrouted/output.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.8 (Berkeley) 2/26/91"; +#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) + int (*f)(); +{ + 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) + 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); + } +} + +/* + * Output a preformed packet. + */ +/*ARGSUSED*/ +sndmsg(dst, flags, ifp) + struct sockaddr *dst; + int flags; + struct interface *ifp; +{ + + (*afswitch[dst->sa_family].af_output) + (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) + struct sockaddr *dst; + int flags; + struct interface *ifp; +{ + register struct rt_entry *rt; + register struct rthash *rh; + register struct netinfo *nn; + register struct netinfo *n = msg->rip_nets; + struct rthash *base = hosthash; + struct sockaddr_ns *sns = (struct sockaddr_ns *) dst; + int (*output)() = afswitch[dst->sa_family].af_output; + int doinghost = 1, size, metric; + union ns_net net; + + msg->rip_cmd = ntohs(RIPCMD_RESPONSE); +again: + for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) + for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { + size = (char *)n - (char *)msg; + if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { + (*output)(flags, dst, size); + TRACE_OUTPUT(ifp, dst, size); + n = msg->rip_nets; + } + sns = (struct sockaddr_ns *)&rt->rt_dst; + if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) + sns = (struct sockaddr_ns *)&rt->rt_router; + metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); + net = sns->sns_addr.x_net; + /* + * Make sure that we don't put out a two net entries + * for a pt to pt link (one for the G route, one for the if) + * This is a kludge, and won't work if there are lots of nets. + */ + for (nn = msg->rip_nets; nn < n; nn++) { + if (ns_neteqnn(net, nn->rip_dst)) { + if (metric < ntohs(nn->rip_metric)) + nn->rip_metric = htons(metric); + goto next; + } + } + n->rip_dst = net; + n->rip_metric = htons(metric); + n++; + next:; + } + if (doinghost) { + doinghost = 0; + base = nethash; + goto again; + } + if (n != msg->rip_nets) { + size = (char *)n - (char *)msg; + (*output)(flags, dst, size); + TRACE_OUTPUT(ifp, dst, size); + } +} diff --git a/usr.sbin/XNSrouted/protocol.h b/usr.sbin/XNSrouted/protocol.h new file mode 100644 index 000000000000..9bf422b60625 --- /dev/null +++ b/usr.sbin/XNSrouted/protocol.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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. + * + * @(#)protocol.h 5.6 (Berkeley) 6/1/90 + */ + +/* + * Xerox Routing Information Protocol + * + */ + +struct netinfo { + union ns_net rip_dst; /* destination net */ + u_short rip_metric; /* cost of route */ +}; + +struct rip { + u_short rip_cmd; /* request/response */ + struct netinfo rip_nets[1]; /* variable length */ +}; + +/* + * Packet types. + */ +#define RIPCMD_REQUEST 1 /* want info */ +#define RIPCMD_RESPONSE 2 /* responding to request */ + +#define RIPCMD_MAX 3 +#ifdef RIPCMDS +char *ripcmds[RIPCMD_MAX] = + { "#0", "REQUEST", "RESPONSE" }; +#endif + +#define HOPCNT_INFINITY 16 /* per Xerox NS */ +#define DSTNETS_ALL 0xffffffff /* per Xerox NS */ +#define MAXPACKETSIZE 512 /* max broadcast size */ + +extern union ns_net ns_anynet; +extern union ns_net ns_zeronet; + +/* + * Timer values used in managing the routing table. + * Every update forces an entry's timer to be reset. After + * EXPIRE_TIME without updates, the entry is marked invalid, + * but held onto until GARBAGE_TIME so that others may + * see it "be deleted". + */ +#define TIMER_RATE 30 /* alarm clocks every 30 seconds */ + +#define SUPPLY_INTERVAL 30 /* time to supply tables */ + +#define EXPIRE_TIME 180 /* time to mark entry invalid */ +#define GARBAGE_TIME 240 /* time to garbage collect */ diff --git a/usr.sbin/XNSrouted/startup.c b/usr.sbin/XNSrouted/startup.c new file mode 100644 index 000000000000..8887c1fc474a --- /dev/null +++ b/usr.sbin/XNSrouted/startup.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.11 (Berkeley) 2/26/91"; +#endif /* not lint */ + +/* + * Routing Table Management Daemon + */ +#include "defs.h" +#include <sys/ioctl.h> +#include <net/if.h> +#include <nlist.h> +#include <stdlib.h> + +struct interface *ifnet; +int lookforinterfaces = 1; +int performnlist = 1; +int gateway = 0; +int externalinterfaces = 0; /* # of remote and local interfaces */ +char ether_broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + +/* + * 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; + int s; + struct ifconf ifc; + char buf[BUFSIZ], *cp, *cplim; + struct ifreq ifreq, *ifr; + u_long i; + + if ((s = socket(AF_NS, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket: %m"); + exit(1); + } + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + syslog(LOG_ERR, "ioctl (get interface configuration)"); + close(s); + exit(1); + } + ifr = ifc.ifc_req; + lookforinterfaces = 0; +#ifdef RTM_ADD +#define max(a, b) (a > b ? a : b) +#define size(p) max((p).sa_len, sizeof(p)) +#else +#define size(p) (sizeof (p)) +#endif + cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ + for (cp = buf; cp < cplim; + cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { + ifr = (struct ifreq *)cp; + bzero((char *)&ifs, sizeof(ifs)); + ifs.int_addr = ifr->ifr_addr; + ifreq = *ifr; + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get interface flags)"); + continue; + } + ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; + if ((ifs.int_flags & IFF_UP) == 0 || + ifr->ifr_addr.sa_family == AF_UNSPEC) { + lookforinterfaces = 1; + continue; + } + if (ifs.int_addr.sa_family != AF_NS) + continue; + if (ifs.int_flags & IFF_POINTOPOINT) { + if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get dstaddr): %m"); + continue; + } + ifs.int_dstaddr = ifreq.ifr_dstaddr; + } + if (ifs.int_flags & IFF_BROADCAST) { + if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get broadaddr: %m"); + continue; + } + ifs.int_broadaddr = ifreq.ifr_broadaddr; + } + /* + * already known to us? + * what makes a POINTOPOINT if unique is its dst addr, + * NOT its source address + */ + if ( ((ifs.int_flags & IFF_POINTOPOINT) && + if_ifwithdstaddr(&ifs.int_dstaddr)) || + ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) && + if_ifwithaddr(&ifs.int_addr))) + continue; + /* no one cares about software loopback interfaces */ + if (strncmp(ifr->ifr_name,"lo", 2)==0) + continue; + ifp = (struct interface *)malloc(sizeof (struct interface)); + if (ifp == 0) { + syslog(LOG_ERR,"XNSrouted: out of memory\n"); + 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_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 = malloc(strlen(ifr->ifr_name) + 1); + if (ifp->int_name == 0) { + syslog(LOG_ERR,"XNSrouted: out of memory\n"); + exit(1); + } + strcpy(ifp->int_name, ifr->ifr_name); + ifp->int_metric = 0; + ifp->int_next = ifnet; + ifnet = ifp; + traceinit(ifp); + addrouteforif(ifp); + } + if (externalinterfaces > 1 && supplier < 0) + supplier = 1; + close(s); +} + +addrouteforif(ifp) + struct interface *ifp; +{ + struct sockaddr_ns net; + struct sockaddr *dst; + int state, metric; + struct rt_entry *rt; + + if (ifp->int_flags & IFF_POINTOPOINT) { + int (*match)(); + register struct interface *ifp2 = ifnet; + register struct interface *ifprev = ifnet; + + dst = &ifp->int_dstaddr; + + /* Search for interfaces with the same net */ + ifp->int_sq.n = ifp->int_sq.p = &(ifp->int_sq); + match = afswitch[dst->sa_family].af_netmatch; + if (match) + for (ifp2 = ifnet; ifp2; ifp2 =ifp2->int_next) { + if (ifp->int_flags & IFF_POINTOPOINT == 0) + continue; + if ((*match)(&ifp2->int_dstaddr,&ifp->int_dstaddr)) { + insque(&ifp2->int_sq,&ifp->int_sq); + break; + } + } + } else { + dst = &ifp->int_broadaddr; + } + rt = rtlookup(dst); + if (rt) + rtdelete(rt); + if (tracing) + fprintf(stderr, "Adding route to interface %s\n", ifp->int_name); + if (ifp->int_transitions++ > 0) + syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); + rtadd(dst, &ifp->int_addr, ifp->int_metric, + ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE)); +} + diff --git a/usr.sbin/XNSrouted/table.h b/usr.sbin/XNSrouted/table.h new file mode 100644 index 000000000000..159dc4e64252 --- /dev/null +++ b/usr.sbin/XNSrouted/table.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1983 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 5.1 (Berkeley) 6/4/85 (routed/table.h) + * + * @(#)table.h 5.3 (Berkeley) 6/1/90 + */ + +/* + * 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 { + u_long rtu_hash; + struct sockaddr rtu_dst; + struct sockaddr rtu_router; + short rtu_flags; + short rtu_state; + int rtu_timer; + int rtu_metric; + struct interface *rtu_ifp; + } rtu_entry; + } rt_rtu; +}; + +#define rt_rt rt_rtu.rtu_rt /* 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_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_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 */ + +struct rthash nethash[ROUTEHASHSIZ]; +struct rthash hosthash[ROUTEHASHSIZ]; +struct rt_entry *rtlookup(); +struct rt_entry *rtfind(); diff --git a/usr.sbin/XNSrouted/tables.c b/usr.sbin/XNSrouted/tables.c new file mode 100644 index 000000000000..38ce4386fe25 --- /dev/null +++ b/usr.sbin/XNSrouted/tables.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1985 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 5.9 (Berkeley) 6/1/90"; +#endif /* not lint */ + +/* + * Routing Table Management Daemon + */ +#include "defs.h" +#include <sys/ioctl.h> +#include <errno.h> + +#ifndef DEBUG +#define DEBUG 0 +#endif + +extern char *xns_ntoa(); +#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} + +int install = !DEBUG; /* if 1 call kernel */ +int delete = 1; +/* + * 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); +} + +/* + * 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; + } + 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; + + FIXLEN(dst); + FIXLEN(gate); + if (af >= AF_MAX) + return; + (*afswitch[af].af_hash)(dst, &h); + flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; + 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_metric = metric; + rt->rt_timer = 0; + rt->rt_flags = RTF_UP | flags; + rt->rt_state = state | RTS_CHANGED; + rt->rt_ifp = if_ifwithnet(&rt->rt_router); + if (metric) + rt->rt_flags |= RTF_GATEWAY; + 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 (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { + if (errno != EEXIST) + perror("SIOCADDRT"); + 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 doioctl = 0, metricchanged = 0; + struct rtentry oldroute; + + FIXLEN(gate); + if (!equal(&rt->rt_router, gate)) + doioctl++; + if (metric != rt->rt_metric) + metricchanged++; + if (doioctl || metricchanged) { + TRACE_ACTION(CHANGE FROM, rt); + if (doioctl) { + oldroute = rt->rt_rt; + rt->rt_router = *gate; + } + rt->rt_metric = metric; + if ((rt->rt_state & RTS_INTERFACE) && metric) { + rt->rt_state &= ~RTS_INTERFACE; + syslog(LOG_ERR, + "changing route from interface %s (timed out)", + rt->rt_ifp->int_name); + } + if (metric) + rt->rt_flags |= RTF_GATEWAY; + else + rt->rt_flags &= ~RTF_GATEWAY; + rt->rt_state |= RTS_CHANGED; + TRACE_ACTION(CHANGE TO, rt); + } + if (doioctl && install) { +#ifndef RTM_ADD + if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) + syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", + xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), + xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); + if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) + perror("SIOCDELRT"); +#else + if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) + perror("SIOCDELRT"); + if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) + syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m", + xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), + xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); +#endif + } +} + +rtdelete(rt) + struct rt_entry *rt; +{ + + struct sockaddr *sa = &(rt->rt_rt.rt_gateway); + FIXLEN(sa); +#undef rt_dst + sa = &(rt->rt_rt.rt_dst); + FIXLEN(sa); + if (rt->rt_state & RTS_INTERFACE) { + syslog(LOG_ERR, "deleting route to interface %s (timed out)", + rt->rt_ifp->int_name); + } + TRACE_ACTION(DELETE, rt); + if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) + perror("SIOCDELRT"); + remque(rt); + free((char *)rt); +} + +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; +} diff --git a/usr.sbin/XNSrouted/timer.c b/usr.sbin/XNSrouted/timer.c new file mode 100644 index 000000000000..f420bc074e00 --- /dev/null +++ b/usr.sbin/XNSrouted/timer.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.7 (Berkeley) 2/26/91"; +#endif /* not lint */ + +/* + * Routing Table Management Daemon + */ +#include "defs.h" + +int timeval = -TIMER_RATE; + +/* + * Timer routine. Performs routing information supply + * duties and manages timers on routing table entries. + */ +void +timer() +{ + register struct rthash *rh; + register struct rt_entry *rt; + struct rthash *base = hosthash; + int doinghost = 1, timetobroadcast; + + timeval += TIMER_RATE; + if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0) + ifinit(); + timetobroadcast = supplier && (timeval % 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 that for our only interface. + * The latter is excused because we don't act as + * a routing information supplier and hence would + * time it out. This is fair as if it's down + * we're cut off from the world anyway and it's + * not likely we'll grow any new hardware in + * the mean time. + */ + if (!(rt->rt_state & RTS_PASSIVE) && + (supplier || !(rt->rt_state & RTS_INTERFACE))) + rt->rt_timer += TIMER_RATE; + if (rt->rt_timer >= EXPIRE_TIME) + rt->rt_metric = HOPCNT_INFINITY; + if (rt->rt_timer >= GARBAGE_TIME) { + rt = rt->rt_back; + /* Perhaps we should send a REQUEST for this route? */ + rtdelete(rt->rt_forw); + continue; + } + if (rt->rt_state & RTS_CHANGED) { + rt->rt_state &= ~RTS_CHANGED; + /* don't send extraneous packets */ + if (!supplier || timetobroadcast) + continue; + msg->rip_cmd = htons(RIPCMD_RESPONSE); + msg->rip_nets[0].rip_dst = + (satons_addr(rt->rt_dst)).x_net; + msg->rip_nets[0].rip_metric = + htons(min(rt->rt_metric+1, HOPCNT_INFINITY)); + toall(sndmsg); + } + } + } + if (doinghost) { + doinghost = 0; + base = nethash; + goto again; + } + if (timetobroadcast) + toall(supply); + alarm(TIMER_RATE); +} + +/* + * On hangup, let everyone know we're going away. + */ +void +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); + } + exit(1); +} diff --git a/usr.sbin/XNSrouted/tools/query.c b/usr.sbin/XNSrouted/tools/query.c new file mode 100644 index 000000000000..2e6374d1f63f --- /dev/null +++ b/usr.sbin/XNSrouted/tools/query.c @@ -0,0 +1,232 @@ +/*- + * Copyright (c) 1983, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code includes software contributed to Berkeley by + * Bill Nesheim at Cornell University. + * + * 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 +char copyright[] = +"@(#) Copyright (c) 1983, 1986 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)query.c 5.8 (Berkeley) 4/16/91"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <netns/ns.h> +#include <netns/idp.h> +#include <errno.h> +#include <stdio.h> +#include <netdb.h> +#include "../protocol.h" +#define IDPPORT_RIF 1 + +#define WTIME 5 /* Time to wait for responses */ + +int s; +int timedout, timeout(); +char packet[MAXPACKETSIZE]; +extern int errno; +struct sockaddr_ns myaddr = {sizeof(myaddr), AF_NS}; +char *ns_ntoa(); +struct ns_addr ns_addr(); +main(argc, argv) +int argc; +char *argv[]; +{ + int cc, count, bits; + struct sockaddr from; + int fromlen = sizeof(from); + struct timeval notime; + + if (argc < 2) { + printf("usage: query hosts...\n"); + exit(1); + } + s = getsocket(SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + exit(2); + } + + argv++, argc--; + query(argv,argc); + + /* + * Listen for returning packets; + * may be more than one packet per host. + */ + bits = 1 << s; + bzero(¬ime, sizeof(notime)); + signal(SIGALRM, timeout); + alarm(WTIME); + while (!timedout || + select(20, &bits, 0, 0, ¬ime) > 0) { + struct nspacket { + struct idp hdr; + char data[512]; + } response; + cc = recvfrom(s, &response, sizeof (response), 0, + &from, &fromlen); + if (cc <= 0) { + if (cc < 0) { + if (errno == EINTR) + continue; + perror("recvfrom"); + (void) close(s); + exit(1); + } + continue; + } + rip_input(&from, response.data, cc); + count--; + } +} +static struct sockaddr_ns router = {sizeof(myaddr), AF_NS}; +static struct ns_addr zero_addr; +static short allones[] = {-1, -1, -1}; + +query(argv,argc) +char **argv; +{ + register struct rip *msg = (struct rip *)packet; + char *host = *argv; + int flags = 0; + struct ns_addr specific; + + if (bcmp(*argv, "-r", 3) == 0) { + flags = MSG_DONTROUTE; argv++; argc--; + } + host = *argv; + router.sns_addr = ns_addr(host); + router.sns_addr.x_port = htons(IDPPORT_RIF); + if (ns_hosteq(zero_addr, router.sns_addr)) { + router.sns_addr.x_host = *(union ns_host *) allones; + } + msg->rip_cmd = htons(RIPCMD_REQUEST); + msg->rip_nets[0].rip_dst = *(union ns_net *) allones; + msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY); + if (argc > 0) { + specific = ns_addr(*argv); + msg->rip_nets[0].rip_dst = specific.x_net; + specific.x_host = zero_addr.x_host; + specific.x_port = zero_addr.x_port; + printf("Net asked for was %s\n", ns_ntoa(specific)); + } + if (sendto(s, packet, sizeof (struct rip), flags, + &router, sizeof(router)) < 0) + perror(host); +} + +/* + * Handle an incoming routing packet. + */ +rip_input(from, msg, size) + struct sockaddr_ns *from; + register struct rip *msg; + int size; +{ + struct netinfo *n; + char *name; + int lna, net, subnet; + struct hostent *hp; + struct netent *np; + static struct ns_addr work; + + if (htons(msg->rip_cmd) != RIPCMD_RESPONSE) + return; + printf("from %s\n", ns_ntoa(from->sns_addr)); + size -= sizeof (struct idp); + size -= sizeof (short); + n = msg->rip_nets; + while (size > 0) { + union ns_net_u net; + if (size < sizeof (struct netinfo)) + break; + net.net_e = n->rip_dst; + printf("\t%d, metric %d\n", ntohl(net.long_e), + ntohs(n->rip_metric)); + size -= sizeof (struct netinfo), n++; + } +} + +timeout() +{ + timedout = 1; +} +getsocket(type, proto) + int type, proto; +{ + struct sockaddr_ns *sns = &myaddr; + int domain = sns->sns_family; + int retry, s, on = 1; + + retry = 1; + while ((s = socket(domain, type, proto)) < 0 && retry) { + perror("socket"); + sleep(5 * retry); + retry <<= 1; + } + if (retry == 0) + return (-1); + while (bind(s, sns, sizeof (*sns), 0) < 0 && retry) { + perror("bind"); + sleep(5 * retry); + retry <<= 1; + } + if (retry == 0) + return (-1); + if (domain==AF_NS) { + struct idp idp; + if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) { + perror("setsockopt SEE HEADERS"); + exit(1); + } + idp.idp_pt = NSPROTO_RI; + if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &idp, sizeof(idp))) { + perror("setsockopt SET HEADERS"); + exit(1); + } + } + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { + perror("setsockopt SO_BROADCAST"); + exit(1); + } + return (s); +} diff --git a/usr.sbin/XNSrouted/trace.c b/usr.sbin/XNSrouted/trace.c new file mode 100644 index 000000000000..51728733a387 --- /dev/null +++ b/usr.sbin/XNSrouted/trace.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.11 (Berkeley) 2/26/91"; +#endif /* not lint */ + +/* + * Routing Table Management Daemon + */ +#define RIPCMDS +#include <stdlib.h> +#include "defs.h" + +#define NRECORDS 50 /* size of circular trace buffer */ +#ifdef DEBUG +FILE *ftrace = stdout; +int tracing = 1; +#else DEBUG +FILE *ftrace = NULL; +int tracing = 0; +#endif + +char *xns_ntoa(); + +traceinit(ifp) + register struct interface *ifp; +{ + static int iftraceinit(); + + if (iftraceinit(ifp, &ifp->int_input) && + iftraceinit(ifp, &ifp->int_output)) + return; + tracing = 0; + syslog(LOG_ERR, "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; +{ + + if (ftrace != NULL) + return; + ftrace = fopen(file, "a"); + if (ftrace == NULL) + return; + dup2(fileno(ftrace), 1); + dup2(fileno(ftrace), 2); + tracing = 1; +} + +traceoff() +{ + if (!tracing) + return; + if (ftrace != NULL) + fclose(ftrace); + ftrace = NULL; + tracing = 0; +} + +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_packet) + free(t->ift_packet); + t->ift_packet = 0; + t->ift_stamp = time(0); + t->ift_who = *who; + if (len > 0) { + t->ift_packet = malloc(len); + if (t->ift_packet) + bcopy(p, t->ift_packet, len); + else + len = 0; + } + t->ift_size = len; + t->ift_metric = m; +} + +traceaction(fd, action, rt) + FILE *fd; + char *action; + struct rt_entry *rt; +{ + struct sockaddr_ns *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" }, + { 0 } + }; + register struct bits *p; + register int first; + char *cp; + struct interface *ifp; + + if (fd == NULL) + return; + fprintf(fd, "%s ", action); + dst = (struct sockaddr_ns *)&rt->rt_dst; + gate = (struct sockaddr_ns *)&rt->rt_router; + fprintf(fd, "dst %s, ", xns_ntoa(&dst->sns_addr)); + fprintf(fd, "router %s, metric %d, flags", + xns_ntoa(&gate->sns_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; + } + } + putc('\n', fd); + if (!tracepackets && (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp) + dumpif(fd, rt->rt_ifp); + fflush(fd); +} + +dumpif(fd, ifp) + register struct interface *ifp; + FILE *fd; +{ + if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) { + fprintf(fd, "*** Packet history for interface %s ***\n", + ifp->int_name); + dumptrace(fd, "to", &ifp->int_output); + 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); + 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; + fprintf(fd, "%.24s: metric=%d\n", ctime(&t->ift_stamp), + t->ift_metric); + dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size); + } +} + +dumppacket(fd, dir, who, cp, size) + FILE *fd; + struct sockaddr_ns *who; /* should be sockaddr */ + char *dir, *cp; + register int size; +{ + register struct rip *msg = (struct rip *)cp; + register struct netinfo *n; + char *xns_nettoa(); + + if (msg->rip_cmd && ntohs(msg->rip_cmd) < RIPCMD_MAX) + fprintf(fd, "%s %s %s#%x", ripcmds[ntohs(msg->rip_cmd)], + dir, xns_ntoa(&who->sns_addr), ntohs(who->sns_addr.x_port)); + else { + fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->rip_cmd), + dir, xns_ntoa(&who->sns_addr), ntohs(who->sns_addr.x_port)); + fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet); + return; + } + switch (ntohs(msg->rip_cmd)) { + + case RIPCMD_REQUEST: + case RIPCMD_RESPONSE: + fprintf(fd, ":\n"); + size -= sizeof (u_short); + n = msg->rip_nets; + for (; size > 0; n++, size -= sizeof (struct netinfo)) { + if (size < sizeof (struct netinfo)) + break; + fprintf(fd, "\tnet %s metric %d\n", + xns_nettoa(n->rip_dst), + ntohs(n->rip_metric)); + } + break; + + } +} + +union ns_net_u net; + +char * +xns_nettoa(val) +union ns_net val; +{ + static char buf[100]; + net.net_e = val; + (void)sprintf(buf, "%lx", ntohl(net.long_e)); + return (buf); +} + + +char * +xns_ntoa(addr) +struct ns_addr *addr; +{ + static char buf[100]; + + (void)sprintf(buf, "%s#%x:%x:%x:%x:%x:%x", + xns_nettoa(addr->x_net), + addr->x_host.c_host[0], addr->x_host.c_host[1], + addr->x_host.c_host[2], addr->x_host.c_host[3], + addr->x_host.c_host[4], addr->x_host.c_host[5]); + + return(buf); +} diff --git a/usr.sbin/XNSrouted/trace.h b/usr.sbin/XNSrouted/trace.h new file mode 100644 index 000000000000..be48553d6c13 --- /dev/null +++ b/usr.sbin/XNSrouted/trace.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * This file includes significant work done at Cornell University by + * Bill Nesheim. That work included by permission. + * + * 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 5.6 (Berkeley) 6/1/90 + */ + +/* + * Xerox Routing Information Protocol. + */ + +/* + * Trace record format. + */ +struct iftrace { + time_t 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 */ +}; + +/* + * 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 tracing; /* on/off */ +FILE *ftrace; /* output trace file */ + +#define TRACE_ACTION(action, route) { \ + if (tracing) \ + traceaction(ftrace, "action", route); \ + } +#define TRACE_INPUT(ifp, src, size) { \ + if (tracing) { \ + ifp = if_iflookup(src); \ + if (ifp) \ + trace(&ifp->int_input, src, &packet[sizeof(struct idp)], size, \ + ntohl(ifp->int_metric)); \ + } \ + if (tracepackets && ftrace) \ + dumppacket(ftrace, "from", src, &packet[sizeof(struct idp)], size); \ + } +#define TRACE_OUTPUT(ifp, dst, size) { \ + if (tracing) { \ + ifp = if_iflookup(dst); \ + if (ifp) \ + trace(&ifp->int_output, dst, &packet[sizeof(struct idp)], size, ifp->int_metric); \ + } \ + if (tracepackets && ftrace) \ + dumppacket(ftrace, "to", dst, &packet[sizeof(struct idp)], size); \ + } diff --git a/usr.sbin/ac/Makefile b/usr.sbin/ac/Makefile new file mode 100644 index 000000000000..349e9ce83e78 --- /dev/null +++ b/usr.sbin/ac/Makefile @@ -0,0 +1,18 @@ +# $Id: Makefile,v 1.1.1.1 1994/05/18 08:00:44 csgr Exp $ + +PROG= ac +MAN8= ac.8 + +# If "CONSOLE_TTY" is not defined, this program is compatible with the +# traditional implementation (using SunOS 4.x as the sample traditional +# implementation). This is the default. +# +# If "CONSOLE_TTY" is defined, it must be defined to the appropriate +# console name, e.g. "vga". Additionally, the various commented-out +# sections of the man page should be uncommented. This is not the +# default because of the inability to detect the proper console name +# easily, especially on m68k systems, which can share binaries. +# +#CFLAGS+=-DCONSOLE_TTY=\"vga\" + +.include <bsd.prog.mk> diff --git a/usr.sbin/ac/ac.8 b/usr.sbin/ac/ac.8 new file mode 100644 index 000000000000..86f05bb51279 --- /dev/null +++ b/usr.sbin/ac/ac.8 @@ -0,0 +1,165 @@ +.\" +.\" Copyright (c) 1994 Simon J. Gerraty +.\" Copyright (c) 1994 Christopher G. Demetriou +.\" 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 Christopher G. Demetriou. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +.\" +.\" $Id: ac.8,v 1.1.1.1 1994/05/18 08:00:45 csgr Exp $ +.\" +.Dd March 15, 1994 +.Dt AC 8 +.Os NetBSD 0.9a +.Sh NAME +.Nm ac +.Nd connect time accounting +.Sh SYNOPSIS +.Nm ac +.Op Fl dp +.\".Op Fl c Ar console +.Op Fl t Ar tty +.Op Fl w Ar wtmp +.Op Ar users ... +.Sh DESCRIPTION +If the file +.Pa /var/log/wtmp +exists, a record of individual login and logout +times are written to it by +.Xr login 8 +and +.Xr init 8 , +respectively. +.Nm \&Ac +examines these records and writes the accumulated connect time +for all logins to the standard output. +.Pp +The options are as follows: +.Bl -tag -width indentXXX +.It Fl d +Display the connect times in 24 hour chunks. +.\" .It Fl c Ar console +.\" Use +.\" .Ar console +.\" as the name of the device that local X sessions (ut_host of ":0.0") +.\" originate from. If any login has been recorded on +.\" .Ar console +.\" then these X sessions are ignored unless COMPAT_SUNOS was defined at +.\" compile time. +.It Fl p +Print individual users' totals. +.It Fl t Ar tty +Only do accounting logins on certain ttys. The +.Ar tty +specification can start with '!' to indicate not this +.Ar tty +and end with '*' to indicate all similarly named ttys. +Multiple +.Fl t +flags may be specified. +.It Fl w Ar wtmp +Read connect time data from +.Ar wtmp +instead of the default file, +.Pa /var/log/wtmp . +.It Ar users ... +Display totals for the given individuals only. +.El +.Pp +If no arguments are given, +.Nm ac +displays the total connect time for all +accounts with login sessions recorded in +.Pa wtmp . +.Pp +The default +.Pa wtmp +file will increase without bound unless it is truncated. +It is normally truncated by the daily scripts run +by +.Xr cron 8 , +which rename and rotate the +.Pa wtmp +files, keeping a week's worth of data on +hand. No login or connect time accounting is performed if +.Pa /var/log/wtmp +does not exist. +.Pp +For example, +.Bd -literal -offset +ac -p -t "ttyd*" > modems +ac -p -t "!ttyd*" > other +.Ed +.Pp +allows times recorded in +.Pa modems +to be charged out at a different rate than +.Pa other . +.Pp +The +.Nm ac +utility exits 0 on success, and >0 if a fatal error occurs. +.Sh FILES +.Bl -tag -width /var/log/wtmp.[0-7] -compact +.It Pa /var/log/wtmp +connect time accounting file +.It Pa /var/log/wtmp.[0-7] +rotated files +.El +.Sh SEE ALSO +.Xr init 8 , +.Xr sa 8 , +.Xr login 1 , +.Xr utmp +.Sh HISTORY +An +.Nm ac +command appeard in +.At v6 . +This version of +.Nm ac +was written for +.Nx 0.9a +from the specification provided by various systems' manual pages. +.\" .Sh NOTES +.\" If COMPAT_SUNOS is defined +.\" .Nm ac +.\" ignores the fact that entries with ut_host of ":0.0" are not real +.\" login sessions. Normally such entries are ignored except in the case +.\" of a user being logged in when the +.\" .Pa wtmp +.\" file was rotated, in which case a login with ut_host of ":0.0" may +.\" appear without any preceeding console logins. +.\" If no one is logged in on the console, the user is deemed to have +.\" logged in on at the earliest time stamp found in +.\" .Pa wtmp . +.\" Use of +.\" .Pa console +.\" allows +.\" .Nm ac +.\" to identify and correcty process a logout for the user. The default +.\" value for +.\" .Pa console +.\" is usually correct at compile time. diff --git a/usr.sbin/ac/ac.c b/usr.sbin/ac/ac.c new file mode 100644 index 000000000000..2d6831511217 --- /dev/null +++ b/usr.sbin/ac/ac.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 1994 Christopher G. Demetriou. + * @(#)Copyright (c) 1994, Simon J. Gerraty. + * + * This is free software. It comes with NO WARRANTY. + * Permission to use, modify and distribute this source code + * is granted subject to the following conditions. + * 1/ that the above copyright notice and this notice + * are preserved in all copies and that due credit be given + * to the author. + * 2/ that any changes to this code are clearly commented + * as such so that the author does not get blamed for bugs + * other than his own. + */ + +#ifndef lint +static char rcsid[] = "$Id: ac.c,v 1.1.1.1 1994/05/18 08:00:45 csgr Exp $"; +#endif + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/time.h> +#include <err.h> +#include <errno.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <utmp.h> +#include <unistd.h> + +/* + * this is for our list of currently logged in sessions + */ +struct utmp_list { + struct utmp_list *next; + struct utmp usr; +}; + +/* + * this is for our list of users that are accumulating time. + */ +struct user_list { + struct user_list *next; + char name[UT_NAMESIZE+1]; + time_t secs; +}; + +/* + * this is for chosing whether to ignore a login + */ +struct tty_list { + struct tty_list *next; + char name[UT_LINESIZE+3]; + int len; + int ret; +}; + +/* + * globals - yes yuk + */ +#ifdef CONSOLE_TTY +static char *Console = CONSOLE_TTY; +#endif +static time_t Total = 0; +static time_t FirstTime = 0; +static int Flags = 0; +static struct user_list *Users = NULL; +static struct tty_list *Ttys = NULL; + +#define NEW(type) (type *)malloc(sizeof (type)) + +#define AC_W 1 /* not _PATH_WTMP */ +#define AC_D 2 /* daily totals (ignore -p) */ +#define AC_P 4 /* per-user totals */ +#define AC_U 8 /* specified users only */ +#define AC_T 16 /* specified ttys only */ + +#ifdef DEBUG +static int Debug = 0; +#endif + +int main __P((int, char **)); +int ac __P((FILE *)); +struct tty_list *add_tty __P((char *)); +int do_tty __P((char *)); +FILE *file __P((char *)); +struct utmp_list *log_in __P((struct utmp_list *, struct utmp *)); +struct utmp_list *log_out __P((struct utmp_list *, struct utmp *)); +int on_console __P((struct utmp_list *)); +void show __P((char *, time_t)); +void show_today __P((struct user_list *, struct utmp_list *, + time_t)); +void show_users __P((struct user_list *)); +struct user_list *update_user __P((struct user_list *, char *, time_t)); +void usage __P((void)); + +/* + * open wtmp or die + */ +FILE * +file(name) + char *name; +{ + FILE *fp; + + if ((fp = fopen(name, "r")) == NULL) + err(1, "%s", name); + /* in case we want to discriminate */ + if (strcmp(_PATH_WTMP, name)) + Flags |= AC_W; + return fp; +} + +struct tty_list * +add_tty(name) + char *name; +{ + struct tty_list *tp; + register char *rcp; + + Flags |= AC_T; + + if ((tp = NEW(struct tty_list)) == NULL) + err(1, "malloc"); + tp->len = 0; /* full match */ + tp->ret = 1; /* do if match */ + if (*name == '!') { /* don't do if match */ + tp->ret = 0; + name++; + } + (void)strncpy(tp->name, name, sizeof (tp->name) - 1); + tp->name[sizeof (tp->name) - 1] = '\0'; + if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */ + *rcp = '\0'; + tp->len = strlen(tp->name); /* match len bytes only */ + } + tp->next = Ttys; + Ttys = tp; + return Ttys; +} + +/* + * should we process the named tty? + */ +int +do_tty(name) + char *name; +{ + struct tty_list *tp; + int def_ret = 0; + + for (tp = Ttys; tp != NULL; tp = tp->next) { + if (tp->ret == 0) /* specific don't */ + def_ret = 1; /* default do */ + if (tp->len != 0) { + if (strncmp(name, tp->name, tp->len) == 0) + return tp->ret; + } else { + if (strncmp(name, tp->name, sizeof (tp->name)) == 0) + return tp->ret; + } + } + return def_ret; +} + +#ifdef CONSOLE_TTY +/* + * is someone logged in on Console? + */ +int +on_console(head) + struct utmp_list *head; +{ + struct utmp_list *up; + + for (up = head; up; up = up->next) { + if (strncmp(up->usr.ut_line, Console, + sizeof (up->usr.ut_line)) == 0) + return 1; + } + return 0; +} +#endif + +/* + * update user's login time + */ +struct user_list * +update_user(head, name, secs) + struct user_list *head; + char *name; + time_t secs; +{ + struct user_list *up; + + for (up = head; up != NULL; up = up->next) { + if (strncmp(up->name, name, sizeof (up->name)) == 0) { + up->secs += secs; + Total += secs; + return head; + } + } + /* + * not found so add new user unless specified users only + */ + if (Flags & AC_U) + return head; + + if ((up = NEW(struct user_list)) == NULL) + err(1, "malloc"); + up->next = head; + (void)strncpy(up->name, name, sizeof (up->name) - 1); + up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */ + up->secs = secs; + Total += secs; + return up; +} + +int +main(argc, argv) + int argc; + char **argv; +{ + FILE *fp; + int c; + + fp = NULL; + while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) { + switch (c) { +#ifdef DEBUG + case 'D': + Debug++; + break; +#endif + case 'c': +#ifdef CONSOLE_TTY + Console = optarg; +#else + usage(); /* XXX */ +#endif + break; + case 'd': + Flags |= AC_D; + break; + case 'p': + Flags |= AC_P; + break; + case 't': /* only do specified ttys */ + add_tty(optarg); + break; + case 'w': + fp = file(optarg); + break; + case '?': + default: + usage(); + break; + } + } + if (optind < argc) { + /* + * initialize user list + */ + for (; optind < argc; optind++) { + Users = update_user(Users, argv[optind], 0L); + } + Flags |= AC_U; /* freeze user list */ + } + if (Flags & AC_D) + Flags &= ~AC_P; + if (fp == NULL) { + /* + * if _PATH_WTMP does not exist, exit quietly + */ + if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT) + return 0; + + fp = file(_PATH_WTMP); + } + ac(fp); + + return 0; +} + +/* + * print login time in decimal hours + */ +void +show(name, secs) + char *name; + time_t secs; +{ + (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name, + ((double)secs / 3600)); +} + +void +show_users(list) + struct user_list *list; +{ + struct user_list *lp; + + for (lp = list; lp; lp = lp->next) + show(lp->name, lp->secs); +} + +/* + * print total login time for 24hr period in decimal hours + */ +void +show_today(users, logins, secs) + struct user_list *users; + struct utmp_list *logins; + time_t secs; +{ + struct user_list *up; + struct utmp_list *lp; + char date[64]; + time_t yesterday = secs - 1; + + (void)strftime(date, sizeof (date), "%b %e total", + localtime(&yesterday)); + + /* restore the missing second */ + yesterday++; + + for (lp = logins; lp != NULL; lp = lp->next) { + secs = yesterday - lp->usr.ut_time; + Users = update_user(Users, lp->usr.ut_name, secs); + lp->usr.ut_time = yesterday; /* as if they just logged in */ + } + secs = 0; + for (up = users; up != NULL; up = up->next) { + secs += up->secs; + up->secs = 0; /* for next day */ + } + if (secs) + (void)printf("%s %11.2f\n", date, ((double)secs / 3600)); +} + +/* + * log a user out and update their times. + * if ut_line is "~", we log all users out as the system has + * been shut down. + */ +struct utmp_list * +log_out(head, up) + struct utmp_list *head; + struct utmp *up; +{ + struct utmp_list *lp, *lp2, *tlp; + time_t secs; + + for (lp = head, lp2 = NULL; lp != NULL; ) + if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line, + sizeof (up->ut_line)) == 0) { + secs = up->ut_time - lp->usr.ut_time; + Users = update_user(Users, lp->usr.ut_name, secs); +#ifdef DEBUG + if (Debug) + printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n", + 19, ctime(&up->ut_time), + sizeof (lp->usr.ut_line), lp->usr.ut_line, + sizeof (lp->usr.ut_name), lp->usr.ut_name, + secs / 3600, (secs % 3600) / 60, secs % 60); +#endif + /* + * now lose it + */ + tlp = lp; + lp = lp->next; + if (tlp == head) + head = lp; + else if (lp2 != NULL) + lp2->next = lp; + free(tlp); + } else { + lp2 = lp; + lp = lp->next; + } + return head; +} + + +/* + * if do_tty says ok, login a user + */ +struct utmp_list * +log_in(head, up) + struct utmp_list *head; + struct utmp *up; +{ + struct utmp_list *lp; + + /* + * this could be a login. if we're not dealing with + * the console name, say it is. + * + * If we are, and if ut_host==":0.0" we know that it + * isn't a real login. _But_ if we have not yet recorded + * someone being logged in on Console - due to the wtmp + * file starting after they logged in, we'll pretend they + * logged in, at the start of the wtmp file. + */ + +#ifdef CONSOLE_TTY + if (up->ut_host[0] == ':') { + /* + * SunOS 4.0.2 does not treat ":0.0" as special but we + * do. + */ + if (on_console(head)) + return head; + /* + * ok, no recorded login, so they were here when wtmp + * started! Adjust ut_time! + */ + up->ut_time = FirstTime; + /* + * this allows us to pick the right logout + */ + (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1); + up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */ + } +#endif + /* + * If we are doing specified ttys only, we ignore + * anything else. + */ + if (Flags & AC_T) + if (!do_tty(up->ut_line)) + return head; + + /* + * go ahead and log them in + */ + if ((lp = NEW(struct utmp_list)) == NULL) + err(1, "malloc"); + lp->next = head; + head = lp; + memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp)); +#ifdef DEBUG + if (Debug) { + printf("%-.*s %-.*s: %-.*s logged in", 19, + ctime(&lp->usr.ut_time), sizeof (up->ut_line), + up->ut_line, sizeof (up->ut_name), up->ut_name); + if (*up->ut_host) + printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host); + putchar('\n'); + } +#endif + return head; +} + +int +ac(fp) + FILE *fp; +{ + struct utmp_list *lp, *head = NULL; + struct utmp usr; + struct tm *ltm; + time_t secs; + int day = -1; + + while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) { + if (!FirstTime) + FirstTime = usr.ut_time; + if (Flags & AC_D) { + ltm = localtime(&usr.ut_time); + if (day >= 0 && day != ltm->tm_yday) { + day = ltm->tm_yday; + /* + * print yesterday's total + */ + secs = usr.ut_time; + secs -= ltm->tm_sec; + secs -= 60 * ltm->tm_min; + secs -= 3600 * ltm->tm_hour; + show_today(Users, head, secs); + } else + day = ltm->tm_yday; + } + switch(*usr.ut_line) { + case '|': + secs = usr.ut_time; + break; + case '{': + secs -= usr.ut_time; + /* + * adjust time for those logged in + */ + for (lp = head; lp != NULL; lp = lp->next) + lp->usr.ut_time -= secs; + break; + case '~': /* reboot or shutdown */ + head = log_out(head, &usr); + FirstTime = usr.ut_time; /* shouldn't be needed */ + break; + default: + /* + * if they came in on tty[p-y]*, then it is only + * a login session if the ut_host field is non-empty + */ + if (*usr.ut_name) { + if (strncmp(usr.ut_line, "tty", 3) != 0 || + strchr("pqrstuvwxy", usr.ut_line[3]) == 0 || + *usr.ut_host != '\0') + head = log_in(head, &usr); + } else + head = log_out(head, &usr); + break; + } + } + (void)fclose(fp); + usr.ut_time = time((time_t *)0); + (void)strcpy(usr.ut_line, "~"); + + if (Flags & AC_D) { + ltm = localtime(&usr.ut_time); + if (day >= 0 && day != ltm->tm_yday) { + /* + * print yesterday's total + */ + secs = usr.ut_time; + secs -= ltm->tm_sec; + secs -= 60 * ltm->tm_min; + secs -= 3600 * ltm->tm_hour; + show_today(Users, head, secs); + } + } + /* + * anyone still logged in gets time up to now + */ + head = log_out(head, &usr); + + if (Flags & AC_D) + show_today(Users, head, time((time_t *)0)); + else { + if (Flags & AC_P) + show_users(Users); + show("total", Total); + } + return 0; +} + +void +usage() +{ + (void)fprintf(stderr, +#ifdef CONSOLE_TTY + "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n"); +#else + "ac [-dp] [-t tty] [-w wtmp] [users ...]\n"); +#endif + exit(1); +} diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8 index f5c07b672c49..abf6ced7654d 100644 --- a/usr.sbin/config/config.8 +++ b/usr.sbin/config/config.8 @@ -30,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)config.8 6.5 (Berkeley) 3/16/91 -.\" $Id: config.8,v 1.2 1993/09/26 23:11:06 rgrimes Exp $ +.\" $Id: config.8,v 1.3 1994/06/01 09:50:08 phk Exp $ .\" .Dd March 16, 1991 .Dt CONFIG 8 @@ -133,6 +133,10 @@ the problems in the configuration file should be corrected and should be run again. Attempts to compile a system that had configuration errors are likely to fail. +.Pp +The entire input file is embedded in the new kernel. This means that +.Xr strings 1 +can be used to extract it from a kernel. .Sh FILES .Bl -tag -width /sys/i386/conf/Makefile.i386 -compact .It Pa /sys/conf/files diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c index 2ea5c3d7ec32..93c089b18dde 100644 --- a/usr.sbin/config/main.c +++ b/usr.sbin/config/main.c @@ -146,6 +146,7 @@ usage: fputs("usage: config [-gp] sysname\n", stderr); makefile(); /* build Makefile */ headers(); /* make a lot of .h files */ swapconf(); /* swap config files */ + configfile(); /* add config file into kernel */ printf("Don't forget to run \"make depend\"\n"); exit(0); } @@ -256,3 +257,39 @@ path(file) } return (cp); } + + +configfile() +{ + FILE *fi, *fo; + char *p; + int i; + + fi = fopen(PREFIX,"r"); + if(!fi) { + perror(PREFIX); + exit(2); + } + fo = fopen(p=path("config.c"),"w"); + if(!fo) { + perror(p); + exit(2); + } + fprintf(fo,"static char *config = \"\n"); + fprintf(fo,"START CONFIG FILE %s\n___",PREFIX); + while (EOF != (i=getc(fi))) { + if(i == '\n') { + fprintf(fo,"\n___"); + } else if(i == '\"') { + fprintf(fo,"\\\""); + } else if(i == '\\') { + fprintf(fo,"\\\\"); + } else { + putc(i,fo); + } + } + fprintf(fo,"\nEND CONFIG FILE %s\n",PREFIX); + fprintf(fo,"\";\n"); + fclose(fi); + fclose(fo); +} diff --git a/usr.sbin/config/mkglue.c b/usr.sbin/config/mkglue.c index 8702448d6254..381f7bca0366 100644 --- a/usr.sbin/config/mkglue.c +++ b/usr.sbin/config/mkglue.c @@ -353,7 +353,7 @@ vector() { fprintf(fp, "\ #define BUILD_VECTORS \\\n\ - BUILD_VECTOR(clk, 0,0,0, _highmask, _hardclock,1,1, al);\\\n"); + BUILD_VECTOR(clk, 0,0,0, _high_imask, _timerintr,1,1, al);\\\n"); count=1; for (dp = dtab; dp != 0; dp = dp->d_next) { @@ -388,9 +388,9 @@ build_vector(fp, dp, id, offset) strcmp(dp->d_name, "sio") == 0 ? "FAST_" : "", dp->d_name, dp->d_unit, dp->d_unit, dp->d_irq, offset); if (eq(dp->d_mask, "null")) - fprintf(fp, ", _%s%dmask,", dp->d_name, dp->d_unit); + fprintf(fp, ", _%s%d_imask,", dp->d_name, dp->d_unit); else - fprintf(fp, ", _%smask, ", dp->d_mask); + fprintf(fp, ", _%s_imask, ", dp->d_mask); fprintf(fp, " _%s,%d,1", id->id, 1 + dp->d_irq / 8); if (dp->d_irq < 8) fprintf(fp, ", al"); diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c index 86654bfc104f..e135fc30736a 100644 --- a/usr.sbin/config/mkmakefile.c +++ b/usr.sbin/config/mkmakefile.c @@ -244,6 +244,10 @@ openit: perror(fname); exit(1); } + if(ident == NULL) { + printf("no ident line specified\n"); + exit(1); + } next: /* * filename [ standard | optional ] [ config-dependent ] diff --git a/usr.sbin/cron/cron.8 b/usr.sbin/cron/cron.8 index c89398663e0c..d96755ad0309 100644 --- a/usr.sbin/cron/cron.8 +++ b/usr.sbin/cron/cron.8 @@ -15,7 +15,7 @@ .\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul .\" */ .\" -.\" $Header: /home/cvs/386BSD/src/usr.sbin/cron/cron.8,v 1.1.2.1 1994/05/01 16:09:33 jkh Exp $ +.\" $Header: /home/cvs/386BSD/src/usr.sbin/cron/cron.8,v 1.1 1994/01/22 20:38:58 guido Exp $ .\" .\" From Id: cron.8,v 2.2 1993/12/28 08:34:43 vixie Exp .\" diff --git a/usr.sbin/diskless_cfg/diskless.h b/usr.sbin/diskless_cfg/diskless.h index 96d2a2d043e5..ef037279d5da 100644 --- a/usr.sbin/diskless_cfg/diskless.h +++ b/usr.sbin/diskless_cfg/diskless.h @@ -136,7 +136,7 @@ struct ifaliasreq { */ #define NFS_FHSIZE 32 -typedef struct { u_char f[NFS_FHSIZE] } nfsv2fh_t; +typedef struct { u_char f[NFS_FHSIZE]; } nfsv2fh_t; /* * Arguments to mount NFS */ diff --git a/usr.sbin/diskless_cfg/diskless_cfg.c b/usr.sbin/diskless_cfg/diskless_cfg.c index 3cf21379470f..7678ff54675f 100644 --- a/usr.sbin/diskless_cfg/diskless_cfg.c +++ b/usr.sbin/diskless_cfg/diskless_cfg.c @@ -18,6 +18,11 @@ Based loosely on the 4.4BSD diskless setup code #include <rpc/types.h> #include <sys/errno.h> #include <nfs/nfs.h> +#ifdef __SVR4 +/* Solaris: compile with -lbsm -lnsl -lsocket */ +#define getfh nfs_getfh +#define bcopy(a,b,c) memcpy(b,a,c) +#endif #endif #ifdef i386 /* Native 386bsd system */ @@ -50,6 +55,7 @@ struct nfs_diskless nfs_diskless; #define KW_HOSTNAME 7 #define KW_KERNEL 8 #define KW_GATEWAY 9 +#define KW_SERVER 10 struct { char *name; @@ -63,11 +69,12 @@ struct { { "-wsize", KW_WSIZE }, { "-hostname", KW_HOSTNAME }, { "-gateway", KW_GATEWAY }, + { "-server", KW_SERVER }, { NULL, KW_HELP } }; char *hostname = "386bsd"; -char *gateway = NULL; +char gateway[256]; char cfg[64]; char *rootpath = "/var/386bsd"; char *swappath = "/var/swap/386bsd"; @@ -86,7 +93,7 @@ main(argc, argv) char *p, *q; netmask = 0; - bzero(&nfs_diskless, 0, sizeof(struct nfs_diskless)); + memset(&nfs_diskless, 0, sizeof(struct nfs_diskless)); strcpy(nfs_diskless.myif.ifra_name,"ed0"); nfs_diskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr); nfs_diskless.myif.ifra_addr.sa_family = AF_INET; @@ -107,24 +114,6 @@ main(argc, argv) nfs_diskless.root_saddr.sa_len = sizeof(struct sockaddr); nfs_diskless.root_saddr.sa_family = AF_INET; - if (gethostname(servername, 256) < 0) { - fprintf(stderr,"%s: unable to get host server name\n",argv[0]); - exit(2); - } - if ((hp = gethostbyname(servername)) == NULL) { - fprintf(stderr,"%s: unable to get host address\n",argv[0]); - exit(2); - } - p = servername; - while (*p && (*p != '.')) p++; - *p = 0; - nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0] - = NFS_SOCKET >> 8; - nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1] - = NFS_SOCKET & 0x00FF; - bcopy(*hp->h_addr_list, &nfs_diskless.swap_saddr.sa_data[2], 4); - bcopy(*hp->h_addr_list, &nfs_diskless.root_saddr.sa_data[2], 4); - i = 1; while (i < argc) { cmd = KW_HELP; @@ -174,28 +163,49 @@ main(argc, argv) hostname = argv[i+1]; i += 2; break; + case KW_SERVER: + strcpy(servername,argv[i+1]); + i += 2; + break; case KW_GATEWAY: - gateway = argv[i+1]; + strcpy(gateway,argv[i+1]); i += 2; break; } } - if(gateway) - { - if (gethostname(gateway, 256) < 0) { - fprintf(stderr,"%s: unable to get gateway host name\n",argv[0]); - exit(2); - } - if ((hp = gethostbyname(gateway)) == NULL) { - fprintf(stderr,"%s: unable to get gateway host address\n",argv[0]); - exit(2); - } - nfs_diskless.mygateway.sa_len = sizeof(struct sockaddr); - nfs_diskless.mygateway.sa_family = AF_INET; - nfs_diskless.mygateway.sa_data[0] = NFS_SOCKET >> 8; - nfs_diskless.mygateway.sa_data[1] = NFS_SOCKET & 0x00FF; - bcopy(*hp->h_addr_list, &nfs_diskless.mygateway.sa_data[2], 4); + + if (!*servername && gethostname(servername, sizeof servername) < 0) { + fprintf(stderr,"%s: unable to get host server name\n",argv[0]); + exit(2); + } + if ((hp = gethostbyname(servername)) == NULL) { + fprintf(stderr,"%s: unable to get host address\n",argv[0]); + exit(2); + } + p = servername; + while (*p && (*p != '.')) p++; + *p = 0; + nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0] + = NFS_SOCKET >> 8; + nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1] + = NFS_SOCKET & 0x00FF; + bcopy(*hp->h_addr_list, &nfs_diskless.swap_saddr.sa_data[2], 4); + bcopy(*hp->h_addr_list, &nfs_diskless.root_saddr.sa_data[2], 4); + + if (!*gateway && gethostname(gateway, sizeof gateway) < 0) { + fprintf(stderr,"%s: unable to get gateway host name\n",argv[0]); + exit(2); } + if ((hp = gethostbyname(gateway)) == NULL) { + fprintf(stderr,"%s: unable to get gateway host address\n",argv[0]); + exit(2); + } + nfs_diskless.mygateway.sa_len = sizeof(struct sockaddr); + nfs_diskless.mygateway.sa_family = AF_INET; + nfs_diskless.mygateway.sa_data[0] = NFS_SOCKET >> 8; + nfs_diskless.mygateway.sa_data[1] = NFS_SOCKET & 0x00FF; + bcopy(*hp->h_addr_list, &nfs_diskless.mygateway.sa_data[2], 4); + nfs_diskless.swap_args.rsize = i386order(rsize); nfs_diskless.swap_args.wsize = i386order(wsize); nfs_diskless.root_args.rsize = i386order(rsize); @@ -219,7 +229,7 @@ main(argc, argv) bcopy(&broadcast, &nfs_diskless.myif.ifra_broadaddr.sa_data[2], 4); bcopy(&netmask, &nfs_diskless.myif.ifra_mask.sa_data[2], 4); if (stat(rootpath, &statbuf) < 0) { - fprintf(stderr,"%s: unable to stat '%s'\n", + fprintf(stderr,"%s: unable to stat root '%s'\n", argv[0],rootpath); exit(2); } @@ -238,7 +248,7 @@ main(argc, argv) strcpy(nfs_diskless.root_hostnam,buf); printf("root is on %s\n",nfs_diskless.root_hostnam); if (stat(swappath, &statbuf) < 0) { - fprintf(stderr,"%s: unable to stat '%s'\n", + fprintf(stderr,"%s: unable to stat swap '%s'\n", argv[0],swappath); exit(2); } diff --git a/usr.sbin/fdcontrol/Makefile b/usr.sbin/fdcontrol/Makefile new file mode 100644 index 000000000000..068cadeb782a --- /dev/null +++ b/usr.sbin/fdcontrol/Makefile @@ -0,0 +1,4 @@ +PROG = fdcontrol +MAN8 = fdcontrol.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/fdcontrol/fdcontrol.8 b/usr.sbin/fdcontrol/fdcontrol.8 new file mode 100644 index 000000000000..4c9f2872118c --- /dev/null +++ b/usr.sbin/fdcontrol/fdcontrol.8 @@ -0,0 +1,77 @@ +.\" +.\" Copyright (C) 1994 by Joerg Wunsch, Dresden +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. +.\" +.Dd May 22, 1994 +.Os +.Dt FDCONTROL 8 +.Sh NAME +.Nm fdcontrol +.Nd modify floppy disk parameters +.Sh SYNOPSIS +.Nm fdcontrol +.Ar device +.Sh DESCRIPTION +.Nm Fdcontrol +allows the specification of device parameters for the floppy disk at +.Ar device . +.Ar Device +should be a character device. + +Since the implications of such a specification are considered harmful, +the underlying +.Xr ioctl 2 +command is restricted to the super-user. + +The command asks the user for each individual tunable parameter, +defaulting to the currently used value. + +.Sh DIAGNOSTICS +Error codes for the underlying +.Xr ioctl 2 +commands are printed by the +.Xr perror 3 +facility. + +.Sh BUGS +The +.Nm +command is currently under development. It's user interface is rather +silly and likely to change in future, options should be provided to +allow anything being modified from the command line. + +.Sh SEE ALSO +.Xr fd 4 , +.Xr ioctl 2 , +.Xr perror 3 . +.Sh HISTORY +.Nm Fdcontrol +is currently under development. It's user interface and overall +functionality are subjects to future improvements and changes. +.Sh AUTHOR +The program has been contributed by +.if n Joerg Wunsch, +.if t J\(:org Wunsch, +Dresden. diff --git a/usr.sbin/fdcontrol/fdcontrol.c b/usr.sbin/fdcontrol/fdcontrol.c new file mode 100644 index 000000000000..91011a4a67f6 --- /dev/null +++ b/usr.sbin/fdcontrol/fdcontrol.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 1994 by Joerg Wunsch, Dresden + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <machine/ioctl_fd.h> +#include <sys/file.h> + +int +getnumber(void) +{ + int i; + char b[80]; + + fgets(b, 80, stdin); + if(b[0] == '\n') return -1; + + sscanf(b, " %i", &i); + return i; +} + +void +usage(void) +{ + fprintf(stderr, "usage: fdcontrol device-node\n"); + exit(2); +} + + +#define ask(name, fmt) \ +printf(#name "? [" fmt "]: ", ft.name); fflush(stdout); \ +if((i = getnumber()) != -1) ft.name = i + +int +main(int argc, char **argv) +{ + struct fd_type ft; + int fd, i; + + if(argc != 2) + usage(); + + if((fd = open(argv[1], 0)) < 0) + { + perror("open(floppy)"); + return 1; + } + + if(ioctl(fd, FD_GTYPE, &ft) < 0) + { + perror("ioctl(FD_GTYPE)"); + return 1; + } + + ask(sectrac, "%d"); + ask(secsize, "%d"); + ask(datalen, "0x%x"); + ask(gap, "0x%x"); + ask(tracks, "%d"); + ask(size, "%d"); + ask(steptrac, "%d"); + ask(trans, "%d"); + ask(heads, "%d"); + ask(f_gap, "0x%x"); + ask(f_inter, "%d"); + + if(ioctl(fd, FD_STYPE, &ft) < 0) + { + perror("ioctl(FD_STYPE)"); + return 1; + } + return 0; +} + + + diff --git a/usr.sbin/fdformat/Makefile b/usr.sbin/fdformat/Makefile index 209af72d124d..3ee3b4debeec 100644 --- a/usr.sbin/fdformat/Makefile +++ b/usr.sbin/fdformat/Makefile @@ -1,32 +1,9 @@ -# Copyright (C) 1993 by Joerg Wunsch, Dresden -# 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. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. # PROG = fdformat # the -I's seem to be confusing, but necessery this way # (so the right <unistd.h> will be found in /usr/include, and the # "../i386/isa/ic/nec765.h" included from fdreg.h is accessible, too) -CFLAGS+=-Wall -I/usr/include -I/sys/sys +CFLAGS+= -Wall -I/usr/include -I/sys/sys .include <bsd.prog.mk> diff --git a/usr.sbin/fdformat/fdformat.1 b/usr.sbin/fdformat/fdformat.1 index 78a6b133340c..2b27f7f5ead7 100644 --- a/usr.sbin/fdformat/fdformat.1 +++ b/usr.sbin/fdformat/fdformat.1 @@ -10,20 +10,20 @@ .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. .\" .Dd September 16, 1993 -.Os FreeBSD +.Os .Dt FDFORMAT 1 .Sh NAME .Nm fdformat @@ -57,7 +57,7 @@ or default name in an abbreviated form .Pq e.\ g. Em fd0 . In the latter case, the name is constructed by prepending .Pa /dev/r -and appending an +and appending a .Em .capacity to the .Ar device_name . diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c index b88a8ea7618d..6ab7d94ff96f 100644 --- a/usr.sbin/fdformat/fdformat.c +++ b/usr.sbin/fdformat/fdformat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1992-1993 by Joerg Wunsch, Dresden + * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,17 +11,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. */ /* @@ -90,7 +90,16 @@ verify_track(int fd, int track, int tracksize) { static char *buf = 0; static int bufsz = 0; - + int fdopts = -1, ofdopts, rv = 0; + + if (ioctl(fd, FD_GOPTS, &fdopts) < 0) + perror("warning: ioctl(FD_GOPTS)"); + else { + ofdopts = fdopts; + fdopts |= FDOPT_NORETRY; + (void)ioctl(fd, FD_SOPTS, &fdopts); + } + if (bufsz < tracksize) { if (buf) free (buf); @@ -104,10 +113,14 @@ verify_track(int fd, int track, int tracksize) exit (2); } if (lseek (fd, (long) track*tracksize, 0) < 0) - return (-1); - if (read (fd, buf, tracksize) != tracksize) - return (-1); - return (0); + rv = -1; + /* try twice reading it, without using the normal retrier */ + else if (read (fd, buf, tracksize) != tracksize + && read (fd, buf, tracksize) != tracksize) + rv = -1; + if(fdopts != -1) + (void)ioctl(fd, FD_SOPTS, &ofdopts); + return (rv); } static const char * @@ -127,7 +140,7 @@ makename(const char *arg, const char *suffix) } static void -usage () +usage (void) { printf("Usage:\n\tfdformat [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]\n"); printf("\t\t [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname\n"); @@ -152,7 +165,7 @@ usage () } static int -yes () +yes (void) { char reply [256], *p; @@ -353,3 +366,18 @@ main(int argc, char **argv) return errs; } +/* + * Local Variables: + * c-indent-level: 8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * c-brace-offset: -8 + * c-brace-imaginary-offset: 0 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c++-hanging-braces: 1 + * c++-access-specifier-offset: -8 + * c++-empty-arglist-indent: 8 + * c++-friend-offset: 0 + * End: + */ diff --git a/usr.sbin/flcopy/Makefile b/usr.sbin/flcopy/Makefile deleted file mode 100644 index 2cfc59848c66..000000000000 --- a/usr.sbin/flcopy/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# @(#)Makefile 5.2 (Berkeley) 1/20/91 - -PROG= flcopy -MANSUBDIR=/vax -MAN8= flcopy.8 - -.include <bsd.prog.mk> diff --git a/usr.sbin/flcopy/flcopy.8 b/usr.sbin/flcopy/flcopy.8 deleted file mode 100644 index 1cc14ccd9c80..000000000000 --- a/usr.sbin/flcopy/flcopy.8 +++ /dev/null @@ -1,83 +0,0 @@ -.\" Copyright (c) 1980 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. -.\" -.\" @(#)flcopy.8 5.2 (Berkeley) 4/20/91 -.\" -.TH FLCOPY 8 "April 20, 1991" -.UC 4 -.SH NAME -flcopy \- floppy copy -.SH SYNOPSIS -.nf -.ft B -flcopy [ \-hr ] [ \-f file ] [ \-t ntracks ] -.ft R -.fi -.SH DESCRIPTION -.I Flcopy -copies the console floppy disk (``/dev/floppy'') to a file in the -current directory, named ``floppy''. -The user is then prompted to change the floppy, and enter a carriage -return when done. -When a carriage return is entered, -.I flcopy -copies the file out to the floppy disk. -.PP -The options are as follows: -.TP -\-f -Use -.I file -instead of ``/dev/floppy''. -.TP --h -Cause -.I flcopy -to copy a file named ``floppy'' in the current directory to -the console floppy disk. -.TP -\-r -Cause -.I flcopy -to copy the floppy to the current directory and then quit. -.TP -\-t -Copy only the first -.I ntracks -tracks. -.SH FILES -floppy temporary file name -.br -/dev/floppy default floppy device -.SH SEE ALSO -crl(4), fl(4), rx(4), tu(4), arff(8), rxformat(8) -.SH BUGS -Device errors are handled ungracefully. diff --git a/usr.sbin/flcopy/flcopy.c b/usr.sbin/flcopy/flcopy.c deleted file mode 100644 index d1a2e35ff043..000000000000 --- a/usr.sbin/flcopy/flcopy.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 1989 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 -char copyright[] = -"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)flcopy.c 5.4 (Berkeley) 1/20/91"; -#endif /* not lint */ - -#include <sys/file.h> -#include <stdio.h> -#include "pathnames.h" - -int floppydes; -char *flopname = _PATH_FLOPPY; -long dsize = 77 * 26 * 128; -int hflag; -int rflag; - -main(argc, argv) - register char **argv; -{ - extern char *optarg; - extern int optind; - static char buff[512]; - register long count; - register startad = -26 * 128; - register int n, file; - register char *cp; - int ch; - - while ((ch = getopt(argc, argv, "f:hrt:")) != EOF) - switch(ch) { - case 'f': - flopname = optarg; - break; - case 'h': - hflag = 1; - printf("Halftime!\n"); - if ((file = open("floppy", 0)) < 0) { - printf("can't open \"floppy\"\n"); - exit(1); - } - break; - case 'r': - rflag = 1; - break; - case 't': - dsize = atoi(optarg); - if (dsize <= 0 || dsize > 77) { - (void)fprintf(stderr, - "flcopy: bad number of tracks (0 - 77).\n"); - exit(2); - } - dsize *= 26 * 128; - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (!hflag) { - file = open("floppy", O_RDWR|O_CREAT|O_TRUNC, 0666); - if (file < 0) { - printf("can't open \"floppy\"\n"); - exit(1); - } - for (count = dsize; count > 0 ; count -= 512) { - n = count > 512 ? 512 : count; - lread(startad, n, buff); - write(file, buff, n); - startad += 512; - } - } - if (rflag) - exit(0); - printf("Change Floppy, Hit return when done.\n"); - gets(buff); - lseek(file, 0, 0); - count = dsize; - startad = -26 * 128; - for ( ; count > 0 ; count -= 512) { - n = count > 512 ? 512 : count; - read(file, buff, n); - lwrite(startad, n, buff); - startad += 512; - } - exit(0); -} - -rt_init() -{ - static initized = 0; - int mode = 2; - - if (initized) - return; - if (rflag) - mode = 0; - initized = 1; - if ((floppydes = open(flopname, mode)) < 0) { - printf("Floppy open failed\n"); - exit(1); - } -} - -/* - * Logical to physical adress translation - */ -long -trans(logical) - register int logical; -{ - register int sector, bytes, track; - - logical += 26 * 128; - bytes = (logical & 127); - logical >>= 7; - sector = logical % 26; - if (sector >= 13) - sector = sector*2 +1; - else - sector *= 2; - sector += 26 + ((track = (logical / 26)) - 1) * 6; - sector %= 26; - return ((((track *26) + sector) << 7) + bytes); -} - -lread(startad, count, obuff) - register startad, count; - register char *obuff; -{ - long trans(); - extern floppydes; - - rt_init(); - while ((count -= 128) >= 0) { - lseek(floppydes, trans(startad), 0); - read(floppydes, obuff, 128); - obuff += 128; - startad += 128; - } -} - -lwrite(startad, count, obuff) - register startad, count; - register char *obuff; -{ - long trans(); - extern floppydes; - - rt_init(); - while ((count -= 128) >= 0) { - lseek(floppydes, trans(startad), 0); - write(floppydes, obuff, 128); - obuff += 128; - startad += 128; - } -} - -usage() -{ - (void)fprintf(stderr, "usage: flcopy [-hr] [-f file] [-t ntracks]\n"); - exit(1); -} diff --git a/usr.sbin/kbdcontrol/Makefile b/usr.sbin/kbdcontrol/Makefile new file mode 100644 index 000000000000..da1a23380674 --- /dev/null +++ b/usr.sbin/kbdcontrol/Makefile @@ -0,0 +1,4 @@ +PROG= kbdcontrol +SRCS= kbdcontrol.c lex.l + +.include <bsd.prog.mk> diff --git a/usr.sbin/kbdcontrol/kbdcontrol.1 b/usr.sbin/kbdcontrol/kbdcontrol.1 new file mode 100644 index 000000000000..645103675f4e --- /dev/null +++ b/usr.sbin/kbdcontrol/kbdcontrol.1 @@ -0,0 +1,77 @@ +.\" +.\" kbdcontrol - a utility for manipulating the syscons keyboard driver section +.\" +.\" 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. +.\" +.\" @(#)kbdcontrol.1 +.\" +.TH kbdcontrol 1 "May 22, 1994" "" "FreeBSD" + +.SH NAME +kbdcontrol - a utility for manipulating the syscons keyboard driver section. +.SH SYNOPSIS +.na +.B kbdcontrol +.RB [options] +.SH DESCRIPTION +The +.B kbdcontrol +command is used to set various keyboard related options for the syscons +console driver, such as keymap, keyboard repeat & delay rates, bell +characteristics etc. +.SH OPTIONS +.TP +The following command line options are supported. +.TP +.BI "\-b\ " [ duration.pitch ] +Set the bell duration and pitch values. +.TP +.BI "\-r\ " [ delay.repeat | slow | fast | normal ] +Set keyboard +.I delay +and +.I repeat +rates, or use presets for +.I slow, +.I fast +or +.I normal. +.TP +.BI "\-l\ " mapfile +Install keyboard map file from +.I mapfile +.TP +.BI "\-d\ " +Dump the current keyboard map onto stdout +.TP +.BI "\-f\ " #\ string +Set function key number +.I # +to send +.I string +. +.TP +.BI "\-F\ " +Set function keys back to the standard definitions. +.TP +.B \-v +Turns on verbose output. +.PP +.SH FILES +/usr/share/syscons/keymaps +.SH "BUGS" +Report when found. +.SH "SEE ALSO" +.BR vidcontrol (1) , +.BR keyboard (4) , +.BR screen (4) , +.BR /sys/i386/conf/SYSCONS +.SH AUTHORS +Søren Schmidt (sos@login.dkuug.dk) diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c new file mode 100644 index 000000000000..cda976b203c2 --- /dev/null +++ b/usr.sbin/kbdcontrol/kbdcontrol.c @@ -0,0 +1,566 @@ +/*- + * Copyright (c) 1994 Søren Schmidt + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: kbdcontrol.c,v 1.1 1994/05/20 12:18:05 sos Exp $ + */ + +#include <ctype.h> +#include <stdio.h> +#include <machine/console.h> +#include "path.h" +#include "lex.h" + +char ctrl_names[32][4] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns " + }; + +char fkey_table[60][MAXFK] = { +/* 00-03 */ "\033[M", "\033[N", "\033[O", "\033[P", +/* 04-07 */ "\033[Q", "\033[R", "\033[S", "\033[T", +/* 08-0B */ "\033[U", "\033[V", "\033[W", "\033[X", +/* 0C-0F */ "\033[W", "\033[X", "\033[Y", "\033[Z", +/* 10-13 */ "\033[a", "\033[b", "\033[c", "\033[d", +/* 14-17 */ "\033[e", "\033[f", "\033[g", "\033[h", +/* 18-1B */ "\033[g", "\033[h", "\033[i", "\033[j", +/* 1C-1F */ "\033[k", "\033[l", "\033[m", "\033[n", +/* 20-23 */ "\033[o", "\033[p", "\033[q", "\033[r", +/* 24-27 */ "\033[g", "\033[h", "\033[i", "\033[j", +/* 28-2B */ "\033[k", "\033[l", "\033[m", "\033[n", +/* 2C-2F */ "\033[o", "\033[p", "\033[q", "\033[r", +/* 30-33 */ "\033[H", "\033[A", "\033[I", "-" , +/* 34-37 */ "\033[D", "\177" , "\033[C", "+" , +/* 38-3B */ "\033[F", "\033[B", "\033[G", "\033[L" + }; + +const int delays[] = {250, 500, 750, 1000}; +const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63, + 68, 76, 84, 92, 100, 110, 118, 126, + 136, 152, 168, 184, 200, 220, 236, 252, + 272, 304, 336, 368, 400, 440, 472, 504}; +const int ndelays = (sizeof(delays) / sizeof(int)); +const int nrepeats = (sizeof(repeats) / sizeof(int)); +int hex = 0; +int number, verbose = 0; +char letter; + + +char * +nextarg(int ac, char **av, int *indp, int oc) +{ + if (*indp < ac) + return(av[(*indp)++]); + fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc); + usage(); + exit(1); + return(""); +} + + +char * +mkfullname(const char *s1, const char *s2, const char *s3) +{ +static char *buf = NULL; +static int bufl = 0; +int f; + + + f = strlen(s1) + strlen(s2) + strlen(s3) + 1; + if (f > bufl) + if (buf) + buf = (char *)realloc(buf, f); + else + buf = (char *)malloc(f); + if (!buf) { + bufl = 0; + return(NULL); + } + + bufl = f; + strcpy(buf, s1); + strcat(buf, s2); + strcat(buf, s3); + return(buf); +} + + +int +get_entry() +{ + switch (yylex()) { + case TNOP: + return NOP | 0x100; + case TLSH: + return LSH | 0x100; + case TRSH: + return RSH | 0x100; + case TCLK: + return CLK | 0x100; + case TNLK: + return NLK | 0x100; + case TSLK: + return SLK | 0x100; + case TBTAB: + return BTAB | 0x100; + case TLALT: + return LALT | 0x100; + case TLCTR: + return LCTR | 0x100; + case TNEXT: + return NEXT | 0x100; + case TRCTR: + return RCTR | 0x100; + case TRALT: + return RALT | 0x100; + case TALK: + return ALK | 0x100; + case TASH: + return ASH | 0x100; + case TMETA: + return META | 0x100; + case TRBT: + return RBT | 0x100; + case TDBG: + return DBG | 0x100; + case TFUNC: + if (F(number) > L_FN) + return -1; + return F(number) | 0x100; + case TSCRN: + if (S(number) > L_SCR) + return -1; + return S(number) | 0x100; + case TLET: + return (unsigned char)letter; + case TNUM: + if (number < 0 || number > 255) + return -1; + return number; + default: + return -1; + } +} + + +int +get_key_definition_line(FILE* fd, keymap_t *map) +{ + int i, def, scancode; + + yyin = fd; + + /* get scancode number */ + if (yylex() != TNUM) + return -1; + if (number < 0 || number >= NUM_KEYS) + return -1; + scancode = number; + + /* get key definitions */ + map->key[scancode].spcl = 0; + for (i=0; i<NUM_STATES; i++) { + if ((def = get_entry()) == -1) + return -1; + if (def & 0x100) + map->key[scancode].spcl |= (0x80 >> i); + map->key[scancode].map[i] = def & 0xFF; + } + /* get lock state key def */ + if (yylex() != TFLAG) + return -1; + map->key[scancode].flgs = number; + return scancode; +} + + +int +print_entry(FILE *fp, int value) +{ + int val = value & 0xFF; + + switch (value) { + case NOP | 0x100: + fprintf(fp, " nop "); + break; + case LSH | 0x100: + fprintf(fp, " lshift"); + break; + case RSH | 0x100: + fprintf(fp, " rshift"); + break; + case CLK | 0x100: + fprintf(fp, " clock "); + break; + case NLK | 0x100: + fprintf(fp, " nlock "); + break; + case SLK | 0x100: + fprintf(fp, " slock "); + break; + case BTAB | 0x100: + fprintf(fp, " btab "); + break; + case LALT | 0x100: + fprintf(fp, " lalt "); + break; + case LCTR | 0x100: + fprintf(fp, " lctrl "); + break; + case NEXT | 0x100: + fprintf(fp, " nscr "); + break; + case RCTR | 0x100: + fprintf(fp, " rctrl "); + break; + case RALT | 0x100: + fprintf(fp, " ralt "); + break; + case ALK | 0x100: + fprintf(fp, " alock "); + break; + case ASH | 0x100: + fprintf(fp, " ashift"); + break; + case META | 0x100: + fprintf(fp, " meta "); + break; + case RBT | 0x100: + fprintf(fp, " boot "); + break; + case DBG | 0x100: + fprintf(fp, " debug "); + break; + default: + if (value & 0x100) { + if (val >= F_FN && val <= L_FN) + fprintf(fp, " fkey%02d", val - F_FN + 1); + else if (val >= F_SCR && val <= L_SCR) + fprintf(fp, " scr%02d ", val - F_SCR + 1); + else if (hex) + fprintf(fp, " 0x%02x ", val); + else + fprintf(fp, " %3d ", val); + } + else { + if (val < ' ') + fprintf(fp, " %s ", ctrl_names[val]); + else if (val == 127) + fprintf(fp, " del "); + else if (isprint(val)) + fprintf(fp, " '%c' ", val); + else if (hex) + fprintf(fp, " 0x%02x ", val); + else + fprintf(fp, " %3d ", val); + } + } +} + + +void +print_key_definition_line(FILE *fp, int scancode, struct key_t *key) +{ + int i, value; + + /* print scancode number */ + if (hex) + fprintf(fp, " 0x%02x ", scancode); + else + fprintf(fp, " %03d ", scancode); + + /* print key definitions */ + for (i=0; i<NUM_STATES; i++) { + if (key->spcl & (0x80 >> i)) + print_entry(fp, key->map[i] | 0x100); + else + print_entry(fp, key->map[i]); + } + + /* print lock state key def */ + switch (key->flgs) { + case 0: + fprintf(fp, " O\n"); + break; + case 1: + fprintf(fp, " C\n"); + break; + case 2: + fprintf(fp, " N\n"); + break; + } +} + + +void +load_keymap(char *opt) +{ + keymap_t map; + FILE *fd; + int scancode, i; + char *name; + char *prefix[] = {"", "", KEYMAP_PATH, NULL}; + char *postfix[] = {"", ".kbd", ".kbd"}; + + for (i=0; prefix[i]; i++) { + name = mkfullname(prefix[i], opt, postfix[i]); + if (fd = fopen(name, "r")) + break; + } + if (fd == NULL) { + perror("keymap file not found"); + return; + } + memset(map, 0, sizeof(map)); + while (1) { + if ((scancode = get_key_definition_line(fd, &map)) < 0) + break; + if (scancode > map.n_keys) map.n_keys = scancode; + } + if (ioctl(0, PIO_KEYMAP, &map) < 0) { + perror("setting keymap"); + fclose(fd); + return; + } +} + + +void +print_keymap() +{ + keymap_t map; + int i; + + if (ioctl(0, GIO_KEYMAP, &map) < 0) { + perror("getting keymap"); + exit(1); + } + printf( +"# alt\n" +"# scan cntrl alt alt cntrl lock\n" +"# code base shift cntrl shift alt shift cntrl shift state\n" +"# ------------------------------------------------------------------\n" + ); + for (i=0; i<map.n_keys; i++) + print_key_definition_line(stdout, i, &map.key[i]); +} + + +void +load_default_functionkeys() +{ + fkeyarg_t fkey; + int i; + + for (i=0; i<NUM_FKEYS; i++) { + fkey.keynum = i; + strcpy(fkey.keydef, fkey_table[i]); + fkey.flen = strlen(fkey_table[i]); + if (ioctl(0, SETFKEY, &fkey) < 0) + perror("setting function key"); + } +} + +void +set_functionkey(char *keynumstr, char *string) +{ + fkeyarg_t fkey; + int keynum; + + if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) { + load_default_functionkeys(); + return; + } + fkey.keynum = atoi(keynumstr); + if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) { + fprintf(stderr, + "function key number must be between 1 and %d\n", + NUM_FKEYS); + return; + } + if ((fkey.flen = strlen(string)) > MAXFK) { + fprintf(stderr, "function key string too long (%d > %d)\n", + fkey.flen, MAXFK); + return; + } + strcpy(fkey.keydef, string); + if (verbose) + fprintf(stderr, "setting function key %d to <%s>\n", + fkey.keynum, fkey.keydef); + fkey.keynum -= 1; + if (ioctl(0, SETFKEY, &fkey) < 0) + perror("setting function key"); +} + + +void +set_bell_values(char *opt) +{ + int duration, pitch; + + if (!strcmp(opt, "normal")) + duration = 1, pitch = 15; + else { + int n; + char *v1; + + duration = strtol(opt, &v1, 0); + if ((duration < 0) || (*v1 != '.')) + goto badopt; + opt = ++v1; + pitch = strtol(opt, &v1, 0); + if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) { +badopt: + fprintf(stderr, + "argument to -b must be DURATION.PITCH\n"); + return; + } + } + + if (verbose) + fprintf(stderr, "setting bell values to %d.%d\n", + duration, pitch); + fprintf(stderr, "[=%d;%dB", pitch, duration); +} + + +void +set_keyrates(char *opt) +{ +struct { + int rep:5; + int del:2; + int pad:1; + }rate; + + if (!strcmp(opt, "slow")) + rate.del = 3, rate.rep = 31; + else if (!strcmp(opt, "normal")) + rate.del = 1, rate.rep = 15; + else if (!strcmp(opt, "fast")) + rate.del = rate.rep = 0; + else { + int n; + int delay, repeat; + char *v1; + + delay = strtol(opt, &v1, 0); + if ((delay < 0) || (*v1 != '.')) + goto badopt; + opt = ++v1; + repeat = strtol(opt, &v1, 0); + if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) { +badopt: + fprintf(stderr, + "argument to -r must be delay.repeat\n"); + return; + } + for (n = 0; n < ndelays - 1; n++) + if (delay <= delays[n]) + break; + rate.del = n; + for (n = 0; n < nrepeats - 1; n++) + if (repeat <= repeats[n]) + break; + rate.rep = n; + } + + if (verbose) + fprintf(stderr, "setting keyboard rate to %d.%d\n", + delays[rate.del], repeats[rate.rep]); + if (ioctl(0, KDSETRAD, rate) < 0) + perror("setting keyboard rate"); +} + + +usage() +{ + fprintf(stderr, +"Usage: kbdcontrol -b duration.pitch (set bell duration & pitch)\n" +" -d (dump keyboard map to stdout)\n" +" -l filename (load keyboard map file)\n" +" -f <N> string (set function key N to send <string>)\n" +" -F (set function keys back to default)\n" +" -r delay.repeat (set keyboard delay & repeat rate)\n" +" -r slow (set keyboard delay & repeat to slow)\n" +" -r normal (set keyboard delay & repeat to normal)\n" +" -r fast (set keyboard delay & repeat to fast)\n" +" -v (verbose)\n" + ); +} + + +void +main(int argc, char **argv) +{ + extern char *optarg; + extern int optind; + int opt; + + /* + if (!is_syscons(0)) + exit(1); + */ + while((opt = getopt(argc, argv, "b:df:Fl:r:vx")) != -1) + switch(opt) { + case 'b': + set_bell_values(optarg); + break; + case 'd': + print_keymap(); + break; + case 'l': + load_keymap(optarg); + break; + case 'f': + set_functionkey(optarg, + nextarg(argc, argv, &optind, 'f')); + break; + case 'F': + load_default_functionkeys(); + break; + case 'r': + set_keyrates(optarg); + break; + case 'v': + verbose = 1; + break; + case 'x': + hex = 1; + break; + default: + usage(); + exit(1); + } + if ((optind != argc) || (argc == 1)) { + usage(); + exit(1); + } + exit(0); +} + + diff --git a/usr.sbin/kbdcontrol/lex.h b/usr.sbin/kbdcontrol/lex.h new file mode 100644 index 000000000000..feff74009f95 --- /dev/null +++ b/usr.sbin/kbdcontrol/lex.h @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 1994 Søren Schmidt + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: lex.h,v 1.1 1994/05/20 12:18:06 sos Exp $ + */ + +#define TNOP 256 +#define TLSH 257 +#define TRSH 258 +#define TCLK 259 +#define TNLK 260 +#define TSLK 261 +#define TLALT 262 +#define TLCTR 263 +#define TNEXT 264 +#define TRCTR 265 +#define TRALT 266 +#define TALK 267 +#define TASH 268 +#define TMETA 269 +#define TRBT 270 +#define TDBG 271 +#define TFUNC 272 +#define TSCRN 273 +#define TLET 274 +#define TNUM 275 +#define TFLAG 276 +#define TBTAB 277 + +extern int number; +extern char letter; +extern FILE *yyin; diff --git a/usr.sbin/kbdcontrol/lex.l b/usr.sbin/kbdcontrol/lex.l new file mode 100644 index 000000000000..0729af70f161 --- /dev/null +++ b/usr.sbin/kbdcontrol/lex.l @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 1994 Søren Schmidt + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: lex.l,v 1.1 1994/05/20 12:18:08 sos Exp $ + */ + +%{ + +#include "lex.h" + +%} + +D [0-9] +X [0-9a-fA-F] +A . +L [OCN] + +%% + +nop { return TNOP; } +lshift { return TLSH; } +rshift { return TRSH; } +clock { return TCLK; } +nlock { return TNLK; } +slock { return TSLK; } +lalt|alt { return TLALT; } +btab { return TBTAB; } +lctrl|ctrl { return TLCTR; } +nscr { return TNEXT; } +rctrl { return TRCTR; } +ralt { return TRALT; } +alock { return TALK; } +ashift { return TASH; } +meta { return TMETA; } +boot { return TRBT; } +debug { return TDBG; } + +NUL|nul { number = 0; return TNUM; } +SOH|soh { number = 1; return TNUM; } +STX|stx { number = 2; return TNUM; } +ETX|etx { number = 3; return TNUM; } +EOT|eot { number = 4; return TNUM; } +ENQ|enq { number = 5; return TNUM; } +ACK|ack { number = 6; return TNUM; } +BEL|bel { number = 7; return TNUM; } +BS|bs { number = 8; return TNUM; } +HT|ht { number = 9; return TNUM; } +LF|lf|NL|nl { number = 10; return TNUM; } +VT|vt { number = 11; return TNUM; } +FF|ff|NP|np { number = 12; return TNUM; } +CR|cr { number = 13; return TNUM; } +SO|so { number = 14; return TNUM; } +SI|si { number = 15; return TNUM; } +DLE|dle { number = 16; return TNUM; } +DC1|dc1 { number = 17; return TNUM; } +DC2|dc2 { number = 18; return TNUM; } +DC3|dc3 { number = 19; return TNUM; } +DC4|dc4 { number = 20; return TNUM; } +NAK|nak { number = 21; return TNUM; } +SYN|syn { number = 22; return TNUM; } +ETB|etb { number = 23; return TNUM; } +CAN|can { number = 24; return TNUM; } +EM|em { number = 25; return TNUM; } +SUB|sub { number = 26; return TNUM; } +ESC|esc { number = 27; return TNUM; } +FS|fs { number = 28; return TNUM; } +GS|gs { number = 29; return TNUM; } +RS|rs { number = 30; return TNUM; } +NS|ns { number = 31; return TNUM; } +SP|sp { number = 32; return TNUM; } +DEL|del { number = 127; return TNUM; } + +fkey{D}({D}*) { + sscanf(yytext+4, "%d", &number); + return TFUNC; + } +scr{D}({D}*) { + sscanf(yytext+3, "%d", &number); + return TSCRN; + } +'{A}' { letter = *(yytext+1); return TLET; } +#({A}*) { /* ignore */ } +0x{X}({X}*) { sscanf(yytext, "%x", &number); return TNUM; } +{D}({D}*) { sscanf(yytext, "%d", &number); return TNUM; } +{L} { + if (*yytext == 'O') number = 0; + if (*yytext == 'C') number = 1; + if (*yytext == 'N') number = 2; + return TFLAG; + } +[ \t\n] { /* ignore */ } diff --git a/usr.sbin/kbdcontrol/path.h b/usr.sbin/kbdcontrol/path.h new file mode 100644 index 000000000000..709acbc375dc --- /dev/null +++ b/usr.sbin/kbdcontrol/path.h @@ -0,0 +1,4 @@ +#define KEYMAP_PATH "/usr/share/syscons/keymaps/" +#define FONT_PATH "/usr/share/syscons/fonts/" +#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/" + diff --git a/usr.sbin/kvm_mkdb/nlist.c b/usr.sbin/kvm_mkdb/nlist.c index f2ee8a1999b1..622e0d99edf0 100644 --- a/usr.sbin/kvm_mkdb/nlist.c +++ b/usr.sbin/kvm_mkdb/nlist.c @@ -122,58 +122,6 @@ create_knlist(name, db) if ((db->put)(db, &key, &data, 0)) error("put"); - if (!strncmp((char *)key.data, VRS_SYM, sizeof(VRS_SYM) - 1)) { - off_t cur_off, rel_off, vers_off; - - /* Offset relative to start of text image in VM. */ -#ifdef hp300 - rel_off = nbuf.n_value; -#endif -#ifdef tahoe - /* - * On tahoe, first 0x800 is reserved for communication - * with the console processor. - */ - rel_off = ((nbuf.n_value & ~KERNBASE) - 0x800); -#endif -#ifdef vax - rel_off = nbuf.n_value & ~KERNBASE; -#endif -#ifdef i386 - rel_off = nbuf.n_value - ebuf.a_entry + CLBYTES; -#endif - /* - * When loaded, data is rounded to next page cluster - * after text, but not in file. - */ - rel_off -= CLBYTES - (ebuf.a_text % CLBYTES); - vers_off = N_TXTOFF(ebuf) + rel_off; - - cur_off = ftell(fp); - if (fseek(fp, vers_off, SEEK_SET) == -1) - badfmt("corrupted string table"); - - /* - * Read version string up to, and including newline. - * This code assumes that a newline terminates the - * version line. - */ - if (fgets(buf, sizeof(buf), fp) == NULL) - badfmt("corrupted string table"); - - key.data = (u_char *)VRS_KEY; - key.size = sizeof(VRS_KEY) - 1; - data.data = (u_char *)buf; - data.size = strlen(buf); - if ((db->put)(db, &key, &data, 0)) - error("put"); - - /* Restore to original values. */ - data.data = (u_char *)&nbuf; - data.size = sizeof(NLIST); - if (fseek(fp, cur_off, SEEK_SET) == -1) - badfmt("corrupted string table"); - } } (void)fclose(fp); } diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c index 0fe755dec16f..05339b640e16 100644 --- a/usr.sbin/lpr/common_source/common.c +++ b/usr.sbin/lpr/common_source/common.c @@ -5,7 +5,7 @@ * or UNIX System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * - * $Id: common.c,v 1.1.1.1.2.1 1994/05/04 08:01:55 rgrimes Exp $ + * $Id: common.c,v 1.2 1994/05/04 08:37:15 rgrimes Exp $ */ /* * Copyright (c) 1983 Regents of the University of California. diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c index eca1fb43e2db..9abe1c980bc9 100644 --- a/usr.sbin/lpr/lpr/lpr.c +++ b/usr.sbin/lpr/lpr/lpr.c @@ -5,7 +5,7 @@ * or UNIX System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * - * $Id: lpr.c,v 1.1.1.1.2.2 1994/05/04 08:02:12 rgrimes Exp $ + * $Id: lpr.c,v 1.3 1994/05/04 08:37:28 rgrimes Exp $ */ /* * Copyright (c) 1983 Regents of the University of California. diff --git a/usr.sbin/lptcontrol/Makefile b/usr.sbin/lptcontrol/Makefile new file mode 100644 index 000000000000..e685c02febc4 --- /dev/null +++ b/usr.sbin/lptcontrol/Makefile @@ -0,0 +1,4 @@ +PROG = lptcontrol +CFLAGS += -Wall + +.include <bsd.prog.mk> diff --git a/usr.sbin/lptcontrol/lptcontrol.1 b/usr.sbin/lptcontrol/lptcontrol.1 new file mode 100644 index 000000000000..52c34a68a725 --- /dev/null +++ b/usr.sbin/lptcontrol/lptcontrol.1 @@ -0,0 +1,67 @@ +.\" +.\" lptcontrol - a utility for manipulating the lpt driver +.\" +.\" 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. +.\" +.\" +.\" $Id: lptcontrol.1,v 1.3 1994/05/22 12:31:54 csgr Exp $ +.TH lptcontrol 1 "March 12, 1994" "" "FreeBSD" + +.SH NAME +lptcontrol - a utility for manipulating the lpt printer driver. +.SH SYNOPSIS +.na +.B lptcontrol +.RB [options] +.SH DESCRIPTION +The +.B lptcontrol +command is used to set either the interrupt-driven or polling mode +of individual lpt devices. When a printer is switched between +interrupt-driven and polled mode, this change will only take effect +the next time the device is opened. +.SH OPTIONS +.TP +The following command line options are supported. +.TP +.B \-i +Turns on interrupt-driven mode. +.TP +.B \-p +Turns on polled mode. +.TP +.BI "\-f\ " file +Sets the mode of the printer device specified by +.I file. +The default value for +.I file +is +.I /dev/lpt0 +.TP +One of +.B \-i +or +.B \-p +must be specified. +.PP +.SH FILES +/dev/lpt? +.PP +.SH BUGS +If the port to be controlled does not have a printer connected and +on-line, then lptcontrol will not be able to open the port in question +for performing ioctl's and will fail. +.sp +Sure to be others. +.SH "SEE ALSO" +.BR lpt (4) , +.BR /sys/i386/conf/GENERICAH +.SH AUTHOR +Geoffrey M. Rehmet diff --git a/usr.sbin/lptcontrol/lptcontrol.c b/usr.sbin/lptcontrol/lptcontrol.c new file mode 100644 index 000000000000..bcb3ad303569 --- /dev/null +++ b/usr.sbin/lptcontrol/lptcontrol.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1994 Geoffrey M. Rehmet + * 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 Geoffrey M. Rehmet + * 4. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: lptcontrol.c,v 1.2 1994/04/08 22:23:39 csgr Exp $ + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <machine/lpt.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <sys/errno.h> + + +#define DEFAULT_LPT "/dev/lpt0" +#define IRQ_INVALID -1 +#define DO_POLL 0 +#define USE_IRQ 1 + +static char default_printer[] = DEFAULT_LPT; + +static void usage(const char * progname) +{ + fprintf(stderr, "usage: %s -i | -p [-f <file name>]\n", progname); + exit(1); +} + +static void set_interrupt_status(int irq_status, const char * file) +{ + int fd; + + if((fd = open(file, O_WRONLY, 0660)) < 0) { + perror("open"); + exit(1); + } + if(ioctl(fd, LPT_IRQ, &irq_status) < 0) { + perror("ioctl"); + exit(1); + } + close(fd); +} + + +int main (int argc, char * argv[]) +{ + int opt; + int irq_status = -1; + char * file = default_printer; + + while((opt = getopt(argc, argv, "pif:")) != -1) + switch(opt) { + case 'i': irq_status = USE_IRQ; break; + case 'p': irq_status = DO_POLL; break; + case 'f': file = optarg; break; + default : usage(argv[0]); + } + if(irq_status == IRQ_INVALID) usage(argv[0]); + + set_interrupt_status(irq_status, file); + + exit(0); +} + + diff --git a/usr.sbin/mrouted/LICENSE b/usr.sbin/mrouted/LICENSE new file mode 100644 index 000000000000..ef7da470b117 --- /dev/null +++ b/usr.sbin/mrouted/LICENSE @@ -0,0 +1,48 @@ + +The mrouted program is covered by the following license. Use of the +mrouted program represents acceptance of these terms and conditions. + +1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license +to use, copy and modify the computer software ``mrouted'' (hereinafter +called the ``Program''), upon the terms and conditions hereinafter set +out and until Licensee discontinues use of the Licensed Program. + +2. LICENSEE acknowledges that the Program is a research tool still in +the development state, that it is being supplied ``as is,'' without any +accompanying services from STANFORD, and that this license is entered +into in order to encourage scientific collaboration aimed at further +development and application of the Program. + +3. LICENSEE may copy the Program and may sublicense others to use object +code copies of the Program or any derivative version of the Program. +All copies must contain all copyright and other proprietary notices found +in the Program as provided by STANFORD. Title to copyright to the +Program remains with STANFORD. + +4. LICENSEE may create derivative versions of the Program. LICENSEE +hereby grants STANFORD a royalty-free license to use, copy, modify, +distribute and sublicense any such derivative works. At the time +LICENSEE provides a copy of a derivative version of the Program to a +third party, LICENSEE shall provide STANFORD with one copy of the source +code of the derivative version at no charge to STANFORD. + +5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. +By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION +OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR +THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS, +COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable +for any liability nor for any direct, indirect or consequential damages +with respect to any claim by LICENSEE or any third party on account of or +arising from this Agreement or use of the Program. + +6. This agreement shall be construed, interpreted and applied in +accordance with the State of California and any legal action arising +out of this Agreement or use of the Program shall be filed in a court +in the State of California. + +7. Nothing in this Agreement shall be construed as conferring rights to +use in advertising, publicity or otherwise any trademark or the name +of ``Stanford''. + +The mrouted program is COPYRIGHT 1989 by The Board of Trustees of +Leland Stanford Junior University. diff --git a/usr.sbin/mrouted/Makefile b/usr.sbin/mrouted/Makefile new file mode 100644 index 000000000000..06b9e28be6c4 --- /dev/null +++ b/usr.sbin/mrouted/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for mrouted, a multicast router, and its auxiliary programs, +# map-mbone and mrinfo. +# +# $Id: Makefile,v 1.3 1994/06/15 11:28:38 jkh Exp $ +# +# Modified by: Jim Lowe for FreeBSD 5/17/94 +# + +IGMP_SRCS= igmp.c inet.c kern.c +IGMP_OBJS= igmp.o inet.o kern.o +ROUTER_SRCS= config.c main.c route.c vif.c +ROUTER_OBJS= config.o main.o route.o vif.o +MAPPER_SRCS= mapper.c +MAPPER_OBJS= mapper.o +MRINFO_SRCS= mrinfo.c +MRINFO_OBJS= mrinfo.o +HDRS= defs.h dvmrp.h route.h vif.h +SRCS= ${IGMP_SRCS} ${ROUTER_SRCS} ${MAPPER_SRCS} ${MRINFO_SRCS} +OBJS= ${IGMP_OBJS} ${ROUTER_OBJS} ${MAPPER_OBJS} ${MRINFO_OBJS} +CLEANFILES+=mrouted map-mbone mrinfo + +MAN8= mrouted.8 + +all: mrouted map-mbone mrinfo + +mrouted: ${IGMP_OBJS} ${ROUTER_OBJS} + rm -f $@ + ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${ROUTER_OBJS} + +map-mbone: ${IGMP_OBJS} ${MAPPER_OBJS} + rm -f $@ + ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${MAPPER_OBJS} + +mrinfo: ${IGMP_OBJS} ${MRINFO_OBJS} + rm -f $@ + ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${MRINFO_OBJS} + +install: mrouted mrinfo map-mbone + install -c mrouted ${DESTDIR}${BINDIR} + install -c -o root -m 500 mrinfo ${DESTDIR}${BINDIR} + install -c -o root -m 500 map-mbone ${DESTDIR}${BINDIR} + +.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c new file mode 100644 index 000000000000..089b7098f335 --- /dev/null +++ b/usr.sbin/mrouted/config.c @@ -0,0 +1,528 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: config.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $ + */ + + +#include "defs.h" + + +char *configfilename = "/etc/mrouted.conf"; + + +/* + * Forward declarations. + */ +static char *next_word(); + + +/* + * Query the kernel to find network interfaces that are multicast-capable + * and install them in the uvifs array. + */ +void config_vifs_from_kernel() +{ + struct ifreq ifbuf[32]; + struct ifreq *ifrp, *ifend, *mp; + struct ifconf ifc; + register struct uvif *v; + register vifi_t vifi; + int i, n; + u_long addr, mask, subnet; + u_int flags; + + ifc.ifc_buf = (char *)ifbuf; + ifc.ifc_len = sizeof(ifbuf); + if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) + log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); + + ifrp = (struct ifreq *)ifbuf; + ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len); + /* + * Loop through all of the interfaces. + */ + for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) { + struct ifreq ifr; +#if BSD >= 199006 + n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + n = sizeof(*ifrp); +#else + n = sizeof(*ifrp); +#endif + /* + * Ignore any interface for an address family other than IP. + */ + addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr; + if (ifrp->ifr_addr.sa_family != AF_INET) + continue; + + /* + * Need a template to preserve address info that is + * used below to locate the next entry. (Otherwise, + * SIOCGIFFLAGS stomps over it because the requests + * are returned in a union.) + */ + bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); + + /* + * Ignore loopback interfaces and interfaces that do not support + * multicast. + */ + if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) + log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); + flags = ifr.ifr_flags; + if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue; + + /* + * Ignore any interface whose address and mask do not define a + * valid subnet number, or whose address is of the form {subnet,0} + * or {subnet,-1}. + */ + if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0) + log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name); + mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + subnet = addr & mask; + if (!inet_valid_subnet(subnet, mask) || + addr == subnet || + addr == (subnet | ~mask)) { + log(LOG_WARNING, 0, + "ignoring %s, has invalid address (%s) and/or mask (%08x)", + ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask)); + continue; + } + + /* + * Ignore any interface that is connected to the same subnet as + * one already installed in the uvifs array. + */ + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if ((addr & v->uv_subnetmask) == v->uv_subnet || + (v->uv_subnet & mask) == subnet) { + log(LOG_WARNING, 0, "ignoring %s, same subnet as %s", + ifr.ifr_name, v->uv_name); + break; + } + } + if (vifi != numvifs) continue; + + /* + * If there is room in the uvifs array, install this interface. + */ + if (numvifs == MAXVIFS) { + log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name); + continue; + } + v = &uvifs[numvifs]; + v->uv_flags = 0; + v->uv_metric = DEFAULT_METRIC; + v->uv_threshold = DEFAULT_THRESHOLD; + v->uv_lcl_addr = addr; + v->uv_rmt_addr = 0; + v->uv_subnet = subnet; + v->uv_subnetmask = mask; + v->uv_subnetbcast = subnet | ~mask; + strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ); + v->uv_groups = NULL; + v->uv_neighbors = NULL; + + log(LOG_INFO, 0, "installing %s (%s on subnet %s) as vif #%u", + v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2), + numvifs); + + ++numvifs; + + /* + * If the interface is not yet up, set the vifs_down flag to + * remind us to check again later. + */ + if (!(flags & IFF_UP)) { + v->uv_flags |= VIFF_DOWN; + vifs_down = TRUE; + } + } +} + +static struct ifreq * +ifconfaddr(ifcp, a) + struct ifconf *ifcp; + u_long a; +{ + int n; + struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf; + struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len); + + while (ifrp < ifend) { + if (ifrp->ifr_addr.sa_family == AF_INET && + ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a) + return (ifrp); +#if BSD >= 199006 + n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + ++ifrp; + else + ifrp = (struct ifreq *)((char *)ifrp + n); +#else + ++ifrp; +#endif + } + return (0); +} +/* + * Read the config file to learn about tunnel vifs and + * non-default phyint parameters. + */ +void config_vifs_from_file() +{ + FILE *f; + char linebuf[100]; + char *w, *s, c; + u_long lcl_addr, rmt_addr; + struct ifconf ifc; + struct ifreq *ifr; + struct ifreq ffr; + int i; + u_int n; + struct ifreq ifbuf[32]; + vifi_t vifi; + struct uvif *v; + + f = fopen(configfilename, "r"); + if (f == NULL) { + if (errno != ENOENT) + log(LOG_WARNING, errno, "can't open %s", configfilename); + return; + } + + ifc.ifc_buf = (char *)ifbuf; + ifc.ifc_len = sizeof(ifbuf); + if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) + log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); + + while (fgets(linebuf, sizeof(linebuf), f) != NULL) { + + s = linebuf; + if (EQUAL((w = next_word(&s)), "")) { + /* + * blank or comment line; ignore + */ + } + + else if (EQUAL(w, "phyint")) { + /* + * phyint <local-addr> [disable] [metric <m>] [threshold <t>] + */ + + /* + * Parse the local address. + */ + if (EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing phyint address in %s", + configfilename); + continue; + } + if ((lcl_addr = inet_parse(w)) == 0xffffffff || + !inet_valid_host(lcl_addr)) { + log(LOG_WARNING, 0, + "invalid phyint address '%s' in %s", + w, configfilename); + continue; + } + + /* + * Look up the vif with the specified local address. + */ + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if (!(v->uv_flags & VIFF_TUNNEL) && + lcl_addr == v->uv_lcl_addr) { + break; + } + } + if (vifi == numvifs) { + log(LOG_WARNING, 0, + "phyint %s in %s is not a configured interface", + inet_fmt(lcl_addr, s1), configfilename); + continue; + } + + /* + * Look for "disable", "metric" and "threshold" options. + */ + while (!EQUAL((w = next_word(&s)), "")) { + if (EQUAL(w, "disable")) { + v->uv_flags |= VIFF_DISABLED; + } + else if (EQUAL(w, "metric")) { + if(EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing metric for phyint %s in %s", + inet_fmt(lcl_addr, s1), configfilename); + w = "garbage"; + break; + } + if(sscanf(w, "%u%c", &n, &c) != 1 || + n < 1 || n >= UNREACHABLE ) { + log(LOG_WARNING, 0, + "invalid metric '%s' for phyint %s in %s", + w, inet_fmt(lcl_addr, s1), configfilename); + break; + } + v->uv_metric = n; + } + else if (EQUAL(w, "threshold")) { + if(EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing threshold for phyint %s in %s", + inet_fmt(lcl_addr, s1), configfilename); + w = "garbage"; + break; + } + if(sscanf(w, "%u%c", &n, &c) != 1 || + n < 1 || n > 255 ) { + log(LOG_WARNING, 0, + "invalid threshold '%s' for phyint %s in %s", + w, inet_fmt(lcl_addr, s1), configfilename); + break; + } + v->uv_threshold = n; + } + else break; + } + if (!EQUAL(w, "")) continue; + } + + else if (EQUAL(w, "tunnel")) { + /* + * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>] + */ + + /* + * Parse the local address. + */ + if (EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing tunnel local address in %s", + configfilename); + continue; + } + if ((lcl_addr = inet_parse(w)) == 0xffffffff || + !inet_valid_host(lcl_addr)) { + log(LOG_WARNING, 0, + "invalid tunnel local address '%s' in %s", + w, configfilename); + continue; + } + + /* + * Make sure the local address is one of ours. + */ + ifr = ifconfaddr(&ifc, lcl_addr); + if (ifr == 0) { + log(LOG_WARNING, 0, + "tunnel local address %s in %s is not one of ours", + inet_fmt(lcl_addr, s1), configfilename); + continue; + } + + /* + * Make sure the local address doesn't name a loopback interface.. + */ + strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ); + if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) { + log(LOG_ERR, errno, + "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name); + } + if (ffr.ifr_flags & IFF_LOOPBACK) { + log(LOG_WARNING, 0, + "tunnel local address %s in %s is a loopback interface", + inet_fmt(lcl_addr, s1), configfilename); + continue; + } + + /* + * Parse the remote address. + */ + if (EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing tunnel remote address in %s", + configfilename); + continue; + } + if ((rmt_addr = inet_parse(w)) == 0xffffffff || + !inet_valid_host(rmt_addr)) { + log(LOG_WARNING, 0, + "invalid tunnel remote address %s in %s", + w, configfilename); + continue; + } + + /* + * Make sure the remote address is not one of ours. + */ + if (ifconfaddr(&ifc, rmt_addr) != 0) { + log(LOG_WARNING, 0, + "tunnel remote address %s in %s is one of ours", + inet_fmt(rmt_addr, s1), configfilename); + continue; + } + + /* + * Make sure the remote address has not been used for another + * tunnel and does not belong to a subnet to which we have direct + * access on an enabled phyint. + */ + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if (v->uv_flags & VIFF_TUNNEL) { + if (rmt_addr == v->uv_rmt_addr) { + log(LOG_WARNING, 0, + "duplicate tunnel remote address %s in %s", + inet_fmt(rmt_addr, s1), configfilename); + break; + } + } + else if (!(v->uv_flags & VIFF_DISABLED)) { + if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) { + log(LOG_WARNING, 0, + "unnecessary tunnel remote address %s in %s", + inet_fmt(rmt_addr, s1), configfilename); + break; + } + } + } + if (vifi != numvifs) continue; + + /* + * OK, let's initialize a uvif structure for the tunnel. + */ + if (numvifs == MAXVIFS) { + log(LOG_WARNING, 0, "too many vifs, ignoring tunnel to %s", + inet_fmt(rmt_addr, s1)); + continue; + } + v = &uvifs[numvifs]; + v->uv_flags = VIFF_TUNNEL; + v->uv_metric = DEFAULT_METRIC; + v->uv_threshold = DEFAULT_THRESHOLD; + v->uv_lcl_addr = lcl_addr; + v->uv_rmt_addr = rmt_addr; + v->uv_subnet = 0; + v->uv_subnetmask = 0; + v->uv_subnetbcast = 0; + strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ); + v->uv_groups = NULL; + v->uv_neighbors = NULL; + + /* + * Look for "metric" and "threshold" options. + */ + while (!EQUAL((w = next_word(&s)), "")) { + if (EQUAL(w, "metric")) { + if(EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing metric for tunnel to %s in %s", + inet_fmt(rmt_addr, s1), configfilename); + w = "garbage"; + break; + } + if(sscanf(w, "%u%c", &n, &c) != 1 || + n < 1 || n >= UNREACHABLE ) { + log(LOG_WARNING, 0, + "invalid metric '%s' for tunnel to %s in %s", + w, inet_fmt(rmt_addr, s1), configfilename); + break; + } + v->uv_metric = n; + } + else if (EQUAL(w, "threshold")) { + if(EQUAL((w = next_word(&s)), "")) { + log(LOG_WARNING, 0, + "missing threshold for tunnel to %s in %s", + inet_fmt(rmt_addr, s1), configfilename); + w = "garbage"; + break; + } + if(sscanf(w, "%u%c", &n, &c) != 1 || + n < 1 || n > 255 ) { + log(LOG_WARNING, 0, + "invalid threshold '%s' for tunnel to %s in %s", + w, inet_fmt(rmt_addr, s1), configfilename); + break; + } + v->uv_threshold = n; + } + else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) { + v->uv_flags |= VIFF_SRCRT; + } + else break; + } + if (!EQUAL(w, "")) continue; + + log(LOG_INFO, 0, + "installing %stunnel from %s to %s as vif #%u", + v->uv_flags & VIFF_SRCRT? "srcrt " : "", + inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2), numvifs); + + ++numvifs; + + if (!(ffr.ifr_flags & IFF_UP)) { + v->uv_flags |= VIFF_DOWN; + vifs_down = TRUE; + } + } + + else { + log(LOG_WARNING, 0, + "unknown command '%s' in %s", w, configfilename); + } + } + + close(f); +} + + +/* + * Return a pointer to the next "word" in the string to which '*s' points, + * lower-cased and null terminated, and advance '*s' to point beyond the word. + * Words are separated by blanks and/or tabs, and the input string is + * considered to terminate at a newline, '#' (comment), or null character. + * If no words remain, a pointer to a null string ("") is returned. + * Warning: This function clobbers the input string. + */ +static char *next_word(s) + char **s; +{ + char *w; + + w = *s; + while (*w == ' ' || *w == '\t') + ++w; + + *s = w; + for(;;) { + switch (**s) { + + case ' ' : + case '\t' : **s = '\0'; + ++*s; + return (w); + + case '\n' : + case '#' : **s = '\0'; + return (w); + + case '\0' : return (w); + + default : if (isascii(**s) && isupper(**s)) + **s = tolower(**s); + ++*s; + } + } +} diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h new file mode 100644 index 000000000000..ebaec8e5abff --- /dev/null +++ b/usr.sbin/mrouted/defs.h @@ -0,0 +1,129 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: defs.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + + +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> +#include <signal.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/igmp.h> +#include <netinet/ip_mroute.h> + +#include "dvmrp.h" +#include "vif.h" +#include "route.h" + + +/* + * Miscellaneous constants and macros. + */ +#define FALSE 0 +#define TRUE 1 + +#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) + +#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY + +#define PROTOCOL_VERSION 2 /* increment when packet format/content changes */ + +#define MROUTED_VERSION 0 /* increment on local changes or bug fixes, */ + /* reset to 0 whever PROTOCOL_VERSION increments */ + +#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION ) + /* for IGMP 'group' field of DVMRP messages */ + +/* + * External declarations for global variables and functions. + */ +extern char recv_buf[MAX_IP_PACKET_LEN]; +extern char send_buf[MAX_IP_PACKET_LEN]; +extern int igmp_socket; +extern u_long allhosts_group; +extern u_long dvmrp_group; + +#define DEFAULT_DEBUG 2 /* default if "-d" given without value */ + +extern int debug; + +extern int routes_changed; +extern int delay_change_reports; + +extern struct uvif uvifs[MAXVIFS]; +extern vifi_t numvifs; +extern int vifs_down; +extern int udp_socket; + +extern char s1[]; +extern char s2[]; +extern char s3[]; + +extern int errno; +extern int sys_nerr; +extern char * sys_errlist[]; + +extern void log(); + +extern void init_igmp(); +extern void accept_igmp(); +extern void send_igmp(); + +extern void init_routes(); +extern void start_route_updates(); +extern void update_route(); +extern void age_routes(); +extern void expire_all_routes(); +extern void accept_probe(); +extern void accept_report(); +extern void report(); +extern void report_to_all_neighbors(); +extern void add_vif_to_routes(); +extern void delete_vif_from_routes(); +extern void delete_neighbor_from_routes(); +extern void dump_routes(); + +extern void init_vifs(); +extern void check_vif_state(); +extern vifi_t find_vif(); +extern void age_vifs(); +extern void dump_vifs(); +extern void accept_group_report(); +extern void query_groups(); +extern void probe_for_neighbors(); +extern int update_neighbor(); +extern void accept_neighbor_request(); + +extern void config_vifs_from_kernel(); +extern void config_vifs_from_file(); + +extern int inet_valid_host(); +extern int inet_valid_subnet(); +extern char * inet_fmt(); +extern char * inet_fmts(); +extern u_long inet_parse(); +extern int inet_cksum(); + +extern char * malloc(); +extern char * fgets(); +extern FILE * fopen(); + +#ifndef htonl +extern u_long htonl(); +extern u_long ntohl(); +#endif diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h new file mode 100644 index 000000000000..6928fe82bb9e --- /dev/null +++ b/usr.sbin/mrouted/dvmrp.h @@ -0,0 +1,141 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: dvmrp.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + +/* + * A DVMRP message consists of an IP header + an IGMP header + (for some types) + * zero or more bytes of data. + * + * For REPORT messages, the data is route information; the route information + * consists of one or more lists of the following form: + * + * (mask, (origin, metric), (origin, metric), ...) + * + * where: + * + * "mask" is the subnet mask for all the origins in the list. + * It is always THREE bytes long, containing the low-order + * three bytes of the mask (the high-order byte is always + * 0xff and therefore need not be transmitted). + * + * "origin" is the number of a subnet from which multicast datagrams + * may originate. It is from one to four bytes long, + * depending on the value of "mask": + * if all bytes of the mask are zero + * the subnet number is one byte long + * else if the low-order two bytes of the mask are zero + * the subnet number is two bytes long + * else if the lowest-order byte of the mask is zero + * the subnet number is three bytes long, + * else + * the subnet number is four bytes long. + * + * "metric" is a one-byte value consisting of two subfields: + * - the high-order bit is a flag which, when set, indicates + * the last (origin, metric) pair of a list. + * - the low-order seven bits contain the routing metric for + * the corresponding origin, relative to the sender of the + * DVMRP report. The metric may have the value of UNREACHABLE + * added to it as a "split horizon" indication (so called + * "poisoned reverse"). + * + * Within a list, the origin subnet numbers must be in ascending order, and + * the lists themselves are in order of increasing mask value. A message may + * not exceed 576 bytes, the default maximum IP reassembly size, including + * the IP and IGMP headers; the route information may be split across more + * than one message if necessary, by terminating a list in one message and + * starting a new list in the next message (repeating the same mask value, + * if necessary). + * + * For NEIGHBORS messages, the data is neighboring-router information + * consisting of one or more lists of the following form: + * + * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...) + * + * where: + * + * "local-addr" is the sending router's address as seen by the neighbors + * in this list; it is always four bytes long. + * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding + * packets to any of the neighbors on this list. + * "threshold" is a one-byte unsigned value, a lower bound on the TTL a + * packet must have to be forwarded to any of the neighbors on + * this list. + * "ncount" is the number of neighbors in this list. + * "neighbor" is the address of a neighboring router, four bytes long. + * + * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes, + * including the IP and IGMP headers; split longer messages by terminating the + * list in one and continuing in another, repeating the local-addr, etc., if + * necessary. + * + * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except + * there is a flags byte before the neighbor count: + * + * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...) + */ + +/* + * DVMRP message types (carried in the "code" field of an IGMP header) + */ +#define DVMRP_PROBE 1 /* for finding neighbors */ +#define DVMRP_REPORT 2 /* for reporting some or all routes */ +#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */ + /* of this router's neighbors. */ +#define DVMRP_NEIGHBORS 4 /* response to such a request */ +#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */ +#define DVMRP_NEIGHBORS2 6 + +/* + * 'flags' byte values in DVMRP_NEIGHBORS2 reply. + */ +#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ +#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ +#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ +#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ +#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ + +/* + * Limit on length of route data + */ +#define MAX_IP_PACKET_LEN 576 +#define MIN_IP_HEADER_LEN 20 +#define MAX_IP_HEADER_LEN 60 +#define MAX_DVMRP_DATA_LEN \ + ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN ) + +/* + * Various protocol constants (all times in seconds) + */ + /* address for multicast DVMRP msgs */ +#define INADDR_DVMRP_GROUP (u_long)0xe0000004 /* 224.0.0.4 */ + +#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */ + /* (This is the timer interrupt */ + /* interval; all times must be */ + /* multiples of this value.) */ + +#define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */ +#define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */ +#define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */ +#define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */ + +#define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */ + +#define NEIGHBOR_PROBE_INTERVAL 190 /* periodic neighbor probe interval */ +#define NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */ + +#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */ +#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */ + +#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */ +#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */ +#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */ diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c new file mode 100644 index 000000000000..cfd874e611b9 --- /dev/null +++ b/usr.sbin/mrouted/igmp.c @@ -0,0 +1,217 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: igmp.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + + +#include "defs.h" + + +/* + * Exported variables. + */ +char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */ +char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */ +int igmp_socket; /* socket for all network I/O */ +u_long allhosts_group; /* allhosts addr in net order */ +u_long dvmrp_group; /* DVMRP grp addr in net order */ + + +/* + * Open and initialize the igmp socket, and fill in the non-changing + * IP header fields in the output packet buffer. + */ +void init_igmp() +{ + struct ip *ip; + + if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) + log(LOG_ERR, errno, "IGMP socket"); + + k_hdr_include(TRUE); /* include IP header when sending */ + k_set_rcvbuf(48*1024); /* lots of input buffering */ + k_set_ttl(1); /* restrict multicasts to one hop */ + k_set_loop(FALSE); /* disable multicast loopback */ + + ip = (struct ip *)send_buf; + ip->ip_tos = 0; + ip->ip_off = 0; + ip->ip_p = IPPROTO_IGMP; + ip->ip_ttl = MAXTTL; /* applies to unicasts only */ + + allhosts_group = htonl(INADDR_ALLHOSTS_GROUP); + dvmrp_group = htonl(INADDR_DVMRP_GROUP); +} + +static char *packet_kind(type, code) + u_char type, code; +{ + switch (type) { + case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query "; + case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report "; + case IGMP_DVMRP: + switch (code) { + case DVMRP_PROBE: return "neighbor probe "; + case DVMRP_REPORT: return "route report "; + case DVMRP_ASK_NEIGHBORS: return "neighbor request "; + case DVMRP_NEIGHBORS: return "neighbor list "; + case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2"; + case DVMRP_NEIGHBORS2: return "neighbor list 2 "; + default: return "unknown DVMRP msg "; + } + default: return "unknown IGMP msg "; + } +} + +/* + * Process a newly received IGMP packet that is sitting in the input + * packet buffer. + */ +void accept_igmp(recvlen) + int recvlen; +{ + register vifi_t vifi; + register u_long src, dst, group; + struct ip *ip; + struct igmp *igmp; + int ipdatalen, iphdrlen, igmpdatalen; + + if (recvlen < sizeof(struct ip)) { + log(LOG_WARNING, 0, + "received packet too short (%u bytes) for IP header", recvlen); + return; + } + + ip = (struct ip *)recv_buf; + src = ip->ip_src.s_addr; + dst = ip->ip_dst.s_addr; + iphdrlen = ip->ip_hl << 2; + ipdatalen = ip->ip_len; + if (iphdrlen + ipdatalen != recvlen) { + log(LOG_WARNING, 0, + "received packet shorter (%u bytes) than hdr+data length (%u+%u)", + recvlen, iphdrlen, ipdatalen); + return; + } + + igmp = (struct igmp *)(recv_buf + iphdrlen); + group = igmp->igmp_group.s_addr; + igmpdatalen = ipdatalen - IGMP_MINLEN; + if (igmpdatalen < 0) { + log(LOG_WARNING, 0, + "received IP data field too short (%u bytes) for IGMP, from %s", + ipdatalen, inet_fmt(src, s1)); + return; + } + + log(LOG_DEBUG, 0, "RECV %s from %-15s to %s", + packet_kind(igmp->igmp_type, igmp->igmp_code), + inet_fmt(src, s1), inet_fmt(dst, s2)); + + switch (igmp->igmp_type) { + + case IGMP_HOST_MEMBERSHIP_QUERY: + return; /* Answered automatically by the kernel. */ + + case IGMP_HOST_MEMBERSHIP_REPORT: + accept_group_report(src, dst, group); + return; + + case IGMP_DVMRP: + switch (igmp->igmp_code) { + + case DVMRP_PROBE: + accept_probe(src, dst); + return; + + case DVMRP_REPORT: + accept_report(src, dst, + (char *)(igmp+1), igmpdatalen); + return; + + case DVMRP_ASK_NEIGHBORS: + accept_neighbor_request(src, dst); + return; + + case DVMRP_ASK_NEIGHBORS2: + accept_neighbor_request2(src, dst); + return; + + case DVMRP_NEIGHBORS: + accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen, + group); + return; + + case DVMRP_NEIGHBORS2: + accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen, + group); + return; + + default: + log(LOG_INFO, 0, + "ignoring unknown DVMRP message code %u from %s to %s", + igmp->igmp_code, inet_fmt(src, s1), + inet_fmt(dst, s2)); + return; + } + + default: + log(LOG_INFO, 0, + "ignoring unknown IGMP message type %u from %s to %s", + igmp->igmp_type, inet_fmt(src, s1), + inet_fmt(dst, s2)); + return; + } +} + + +/* + * Construct an IGMP message in the output packet buffer. The caller may + * have already placed data in that buffer, of length 'datalen'. Then send + * the message from the interface with IP address 'src' to destination 'dst'. + */ +void send_igmp(src, dst, type, code, group, datalen) + u_long src, dst; + int type, code; + u_long group; + int datalen; +{ + static struct sockaddr_in sdst = {AF_INET}; + struct ip *ip; + struct igmp *igmp; + + ip = (struct ip *)send_buf; + ip->ip_src.s_addr = src; + ip->ip_dst.s_addr = dst; + ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; + + igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN); + igmp->igmp_type = type; + igmp->igmp_code = code; + igmp->igmp_group.s_addr = group; + igmp->igmp_cksum = 0; + igmp->igmp_cksum = inet_cksum((u_short *)igmp, + IGMP_MINLEN + datalen); + + if (IN_MULTICAST(ntohl(dst))) k_set_if(src); + if (dst == allhosts_group) k_set_loop(TRUE); + + sdst.sin_addr.s_addr = dst; + if (sendto(igmp_socket, send_buf, ip->ip_len, 0, + (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { + if (errno == ENETDOWN) check_vif_state(); + else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1)); + } + + if (dst == allhosts_group) k_set_loop(FALSE); + + log(LOG_DEBUG, 0, "SENT %s from %-15s to %s", + packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2)); +} diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c new file mode 100644 index 000000000000..02b187a85a39 --- /dev/null +++ b/usr.sbin/mrouted/inet.c @@ -0,0 +1,187 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: inet.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + + +#include "defs.h" + + +/* + * Exported variables. + */ +char s1[16]; /* buffers to hold the string representations */ +char s2[16]; /* of IP addresses, to be passed to inet_fmt() */ +char s3[16]; /* or inet_fmts(). */ + + +/* + * Verify that a given IP address is credible as a host address. + * (Without a mask, cannot detect addresses of the form {subnet,0} or + * {subnet,-1}.) + */ +int inet_valid_host(naddr) + u_long naddr; +{ + register u_long addr; + + addr = ntohl(naddr); + + return (!(IN_MULTICAST(addr) || + IN_BADCLASS (addr) || + (addr & 0xff000000) == 0)); +} + + +/* + * Verify that a given subnet number and mask pair are credible. + */ +int inet_valid_subnet(nsubnet, nmask) + u_long nsubnet, nmask; +{ + register u_long subnet, mask; + + subnet = ntohl(nsubnet); + mask = ntohl(nmask); + + if ((subnet & mask) != subnet) return (FALSE); + + if (IN_CLASSA(subnet)) { + if (mask < 0xff000000 || + (subnet & 0xff000000) == 0 || + (subnet & 0xff000000) == 0x7f000000) return (FALSE); + } + else if (IN_CLASSB(subnet)) { + if (mask < 0xffff0000) return (FALSE); + } + else if (IN_CLASSC(subnet)) { + if (mask < 0xffffff00) return (FALSE); + } + else return (FALSE); + + return (TRUE); +} + + +/* + * Convert an IP address in u_long (network) format into a printable string. + */ +char *inet_fmt(addr, s) + u_long addr; + char *s; +{ + register u_char *a; + + a = (u_char *)&addr; + sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); + return (s); +} + + +/* + * Convert an IP subnet number in u_long (network) format into a printable + * string. + */ +char *inet_fmts(addr, mask, s) + u_long addr, mask; + char *s; +{ + register u_char *a, *m; + + a = (u_char *)&addr; + m = (u_char *)&mask; + + if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); + else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]); + else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]); + else sprintf(s, "%u", a[0]); + + return (s); +} + + +/* + * Convert the printable string representation of an IP address into the + * u_long (network) format. Return 0xffffffff on error. (To detect the + * legal address with that value, you must explicitly compare the string + * with "255.255.255.255".) + */ +u_long inet_parse(s) + char *s; +{ + u_long a; + u_int a0, a1, a2, a3; + char c; + + if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 || + a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255) + return (0xffffffff); + + ((u_char *)&a)[0] = a0; + ((u_char *)&a)[1] = a1; + ((u_char *)&a)[2] = a2; + ((u_char *)&a)[3] = a3; + + return (a); +} + + +/* + * inet_cksum extracted from: + * P I N G . C + * + * Author - + * Mike Muuss + * U. S. Army Ballistic Research Laboratory + * December, 1983 + * Modified at Uc Berkeley + * + * (ping.c) Status - + * Public Domain. Distribution Unlimited. + * + * I N _ C K S U M + * + * Checksum routine for Internet Protocol family headers (C Version) + * + */ +int inet_cksum(addr, len) + u_short *addr; + u_int len; +{ + register int nleft = (int)len; + register u_short *w = addr; + u_short answer = 0; + register int sum = 0; + + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), + * we add sequential 16 bit words to it, and at the end, fold + * back all the carry bits from the top 16 bits into the lower + * 16 bits. + */ + while( nleft > 1 ) { + sum += *w++; + nleft -= 2; + } + + /* mop up an odd byte, if necessary */ + if( nleft == 1 ) { + *(u_char *) (&answer) = *(u_char *)w ; + sum += answer; + } + + /* + * add back carry outs from top 16 bits to low 16 bits + */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return (answer); +} diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c new file mode 100644 index 000000000000..08c934982ebb --- /dev/null +++ b/usr.sbin/mrouted/kern.c @@ -0,0 +1,213 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: kern.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + + +#include "defs.h" + + +void k_set_rcvbuf(bufsize) + int bufsize; +{ + if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, + (char *)&bufsize, sizeof(bufsize)) < 0) + log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize); +} + + +void k_hdr_include(bool) + int bool; +{ +#ifdef IP_HDRINCL + if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL, + (char *)&bool, sizeof(bool)) < 0) + log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool); +#endif +} + + +void k_set_ttl(t) + int t; +{ + u_char ttl; + + ttl = t; + if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL, + (char *)&ttl, sizeof(ttl)) < 0) + log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl); +} + + +void k_set_loop(l) + int l; +{ + u_char loop; + + loop = l; + if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, + (char *)&loop, sizeof(loop)) < 0) + log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop); +} + + +void k_set_if(ifa) + u_long ifa; +{ + struct in_addr adr; + + adr.s_addr = ifa; + if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&adr, sizeof(adr)) < 0) + log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s", + inet_fmt(ifa, s1)); +} + + +void k_join(grp, ifa) + u_long grp; + u_long ifa; +{ + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = grp; + mreq.imr_interface.s_addr = ifa; + + if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) < 0) + log(LOG_WARNING, errno, "can't join group %s on interface %s", + inet_fmt(grp, s1), inet_fmt(ifa, s2)); +} + + +void k_leave(grp, ifa) + u_long grp; + u_long ifa; +{ + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = grp; + mreq.imr_interface.s_addr = ifa; + + if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) < 0) + log(LOG_WARNING, errno, "can't leave group %s on interface %s", + inet_fmt(grp, s1), inet_fmt(ifa, s2)); +} + + +void k_init_dvmrp() +{ + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT, + (char *)NULL, 0) < 0) + log(LOG_ERR, errno, "can't enable DVMRP routing in kernel"); +} + + +void k_stop_dvmrp() +{ + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE, + (char *)NULL, 0) < 0) + log(LOG_WARNING, errno, "can't disable DVMRP routing in kernel"); +} + + +void k_add_vif(vifi, v) + vifi_t vifi; + struct uvif *v; +{ + struct vifctl vc; + + vc.vifc_vifi = vifi; + vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS; + vc.vifc_threshold = v->uv_threshold; + vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr; + vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr; + + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_VIF, + (char *)&vc, sizeof(vc)) < 0) + log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF"); +} + + +void k_del_vif(vifi) + vifi_t vifi; +{ + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF, + (char *)&vifi, sizeof(vifi)) < 0) + log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF"); +} + + +void k_add_group(vifi, group) + vifi_t vifi; + u_long group; +{ + struct lgrplctl lc; + + lc.lgc_vifi = vifi; + lc.lgc_gaddr.s_addr = group; + + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_LGRP, + (char *)&lc, sizeof(lc)) < 0) + log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_LGRP"); +} + + +void k_del_group(vifi, group) + vifi_t vifi; + u_long group; +{ + struct lgrplctl lc; + + lc.lgc_vifi = vifi; + lc.lgc_gaddr.s_addr = group; + + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_LGRP, + (char *)&lc, sizeof(lc)) < 0) + log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_LGRP"); +} + + +void k_add_route(r) + struct rtentry *r; +{ + struct mrtctl mc; + + mc.mrtc_origin.s_addr = r->rt_origin; + mc.mrtc_originmask.s_addr = r->rt_originmask; + mc.mrtc_parent = r->rt_parent; + VIFM_COPY(r->rt_children, mc.mrtc_children); + VIFM_COPY(r->rt_leaves, mc.mrtc_leaves); + + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MRT, + (char *)&mc, sizeof(mc)) < 0) + log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MRT"); +} + + +void k_update_route(r) + struct rtentry *r; +{ + k_add_route(r); +} + + +void k_del_route(r) + struct rtentry *r; +{ + struct in_addr orig; + + orig.s_addr = r->rt_origin; + + if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MRT, + (char *)&orig, sizeof(orig)) < 0) + log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MRT"); +} diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c new file mode 100644 index 000000000000..75809dc478e3 --- /dev/null +++ b/usr.sbin/mrouted/main.c @@ -0,0 +1,322 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: main.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + +/* + * Written by Steve Deering, Stanford University, February 1989. + * + * (An earlier version of DVMRP was implemented by David Waitzman of + * BBN STC by extending Berkeley's routed program. Some of Waitzman's + * extensions have been incorporated into mrouted, but none of the + * original routed code has been adopted.) + */ + + +#include "defs.h" + +extern char *configfilename; + +static char pidfilename[] = "/etc/mrouted.pid"; +static char dumpfilename[] = "/usr/tmp/mrouted.dump"; + +static int debug = 0; + + +/* + * Forward declarations. + */ +static void timer(); +static void hup(); +static void dump(); +static void fdump(); + + +main(argc, argv) + int argc; + char *argv[]; +{ + register int recvlen; + register int omask; + int dummy; + FILE *fp; + extern uid_t geteuid(); + + setlinebuf(stderr); + + if (geteuid() != 0) { + fprintf(stderr, "mrouted: must be root\n"); + exit(1); + } + + argv++, argc--; + while (argc > 0 && *argv[0] == '-') { + if (strcmp(*argv, "-d") == 0) { + if (argc > 1 && isdigit(*(argv + 1)[0])) { + argv++, argc--; + debug = atoi(*argv); + } else + debug = DEFAULT_DEBUG; + } else if (strcmp(*argv, "-c") == 0) { + if (argc > 1) { + argv++, argc--; + configfilename = *argv; + } else + goto usage; + } else + goto usage; + argv++, argc--; + } + + if (argc > 0) { +usage: fprintf(stderr, "usage: mrouted [-c configfile] [-d [debug_level]]\n"); + exit(1); + } + + if (debug == 0) { + /* + * Detach from the terminal + */ + int t; + + if (fork()) exit(0); + (void)close(0); + (void)close(1); + (void)close(2); + (void)open("/", 0); + (void)dup2(0, 1); + (void)dup2(0, 2); + t = open("/dev/tty", 2); + if (t >= 0) { + (void)ioctl(t, TIOCNOTTY, (char *)0); + (void)close(t); + } + } + else fprintf(stderr, "debug level %u\n", debug); + +#ifdef LOG_DAEMON + (void)openlog("mrouted", LOG_PID, LOG_DAEMON); + (void)setlogmask(LOG_UPTO(LOG_NOTICE)); +#else + (void)openlog("mrouted", LOG_PID); +#endif + log(LOG_NOTICE, 0, "mrouted version %d.%d", + PROTOCOL_VERSION, MROUTED_VERSION); + + fp = fopen(pidfilename, "w"); + if (fp != NULL) { + fprintf(fp, "%d\n", getpid()); + (void) fclose(fp); + } + + srandom(gethostid()); + + init_igmp(); + k_init_dvmrp(); /* enable DVMRP routing in kernel */ + init_routes(); + init_vifs(); + + if (debug >= 2) dump(); + + (void)signal(SIGALRM, timer); + (void)signal(SIGHUP, hup); + (void)signal(SIGTERM, hup); + (void)signal(SIGINT, hup); + (void)signal(SIGUSR1, fdump); + if (debug != 0) + (void)signal(SIGQUIT, dump); + + (void)alarm(TIMER_INTERVAL); /* schedule first timer interrupt */ + + /* + * Main receive loop. + */ + dummy = 0; + for(;;) { + recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf), + 0, NULL, &dummy); + if (recvlen < 0) { + if (errno != EINTR) log(LOG_ERR, errno, "recvfrom"); + continue; + } + omask = sigblock(sigmask(SIGALRM)); + accept_igmp(recvlen); + (void)sigsetmask(omask); + } +} + + +/* + * The 'virtual_time' variable is initialized to a value that will cause the + * first invocation of timer() to send a probe or route report to all vifs + * and send group membership queries to all subnets for which this router is + * querier. This first invocation occurs approximately TIMER_INTERVAL seconds + * after the router starts up. Note that probes for neighbors and queries + * for group memberships are also sent at start-up time, as part of initial- + * ization. This repetition after a short interval is desirable for quickly + * building up topology and membership information in the presence of possible + * packet loss. + * + * 'virtual_time' advances at a rate that is only a crude approximation of + * real time, because it does not take into account any time spent processing, + * and because the timer intervals are sometimes shrunk by a random amount to + * avoid unwanted synchronization with other routers. + */ + +static u_long virtual_time = 0; + + +/* + * Timer routine. Performs periodic neighbor probing, route reporting, and + * group querying duties, and drives various timers in routing entries and + * virtual interface data structures. + */ +static void timer() +{ + int next_interval; + + age_routes(); /* Advance the timers in the route entries */ + age_vifs(); /* Advance the timers for neighbors and groups */ + + if (virtual_time % GROUP_QUERY_INTERVAL == 0) { + /* + * Time to query the local group memberships on all subnets + * for which this router is the elected querier. + */ + query_groups(); + } + + if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) { + /* + * Time to send a probe on all vifs from which no neighbors have + * been heard. Also, check if any inoperative interfaces have now + * come up. (If they have, they will also be probed as part of + * their initialization.) + */ + probe_for_neighbors(); + + if (vifs_down) + check_vif_state(); + } + + delay_change_reports = FALSE; + next_interval = TIMER_INTERVAL; + + if (virtual_time % ROUTE_REPORT_INTERVAL == 0) { + /* + * Time for the periodic report of all routes to all neighbors. + */ + report_to_all_neighbors(ALL_ROUTES); + + /* + * Schedule the next timer interrupt for a random time between + * 1 and TIMER_INTERVAL seconds from now. This randomization is + * intended to counteract the undesirable synchronizing tendency + * of periodic transmissions from multiple sources. + */ + next_interval = (random() % TIMER_INTERVAL) + 1; + } + else if (routes_changed) { + /* + * Some routes have changed since the last timer interrupt, but + * have not been reported yet. Report the changed routes to all + * neighbors. + */ + report_to_all_neighbors(CHANGED_ROUTES); + } + + /* + * Advance virtual time and schedule the next timer interrupt. + */ + virtual_time += TIMER_INTERVAL; + (void)alarm(next_interval); +} + + +/* + * On hangup signal, let everyone know we're going away. + */ +static void hup() +{ + log(LOG_INFO, 0, "hup"); + expire_all_routes(); + report_to_all_neighbors(ALL_ROUTES); + exit(1); +} + + +/* + * Dump internal data structures to stderr. + */ +static void dump() +{ + dump_vifs(stderr); + dump_routes(stderr); +} + + +/* + * Dump internal data structures to a file. + */ +static void fdump() +{ + FILE *fp; + + fp = fopen(dumpfilename, "w"); + if (fp != NULL) { + dump_vifs(fp); + dump_routes(fp); + (void) fclose(fp); + } +} + + +/* + * Log errors and other messages to the system log daemon and to stderr, + * according to the severity of the message and the current debug level. + * For errors of severity LOG_ERR or worse, terminate the program. + */ +void log(severity, syserr, format, a, b, c, d, e) + int severity, syserr; + char *format; + int a, b, c, d, e; +{ + char fmt[100]; + + switch (debug) { + case 0: break; + case 1: if (severity > LOG_NOTICE) break; + case 2: if (severity > LOG_INFO ) break; + default: + fmt[0] = '\0'; + if (severity == LOG_WARNING) strcat(fmt, "warning - "); + strncat(fmt, format, 80); + fprintf(stderr, fmt, a, b, c, d, e); + if (syserr == 0) + fprintf(stderr, "\n"); + else if(syserr < sys_nerr) + fprintf(stderr, ": %s\n", sys_errlist[syserr]); + else + fprintf(stderr, ": errno %d\n", syserr); + } + + if (severity <= LOG_NOTICE) { + fmt[0] = '\0'; + if (severity == LOG_WARNING) strcat(fmt, "warning - "); + strncat(fmt, format, 80); + if (syserr != 0) { + strcat(fmt, ": %m"); + errno = syserr; + } + syslog(severity, fmt, a, b, c, d, e); + + if (severity <= LOG_ERR) exit(-1); + } +} diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c new file mode 100644 index 000000000000..cdc2e875611b --- /dev/null +++ b/usr.sbin/mrouted/mapper.c @@ -0,0 +1,932 @@ +/* Mapper for connections between MRouteD multicast routers. + * Written by Pavel Curtis <Pavel@PARC.Xerox.Com> + * + * $Id: mapper.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $ + */ + +/* + * Copyright (c) Xerox Corporation 1992. All rights reserved. + * + * License is granted to copy, to use, and to make and to use derivative + * works for research and evaluation purposes, provided that Xerox is + * acknowledged in all documentation pertaining to any such copy or derivative + * work. Xerox grants no other licenses expressed or implied. The Xerox trade + * name should not be used in any advertising without its written permission. + * + * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE + * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE + * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without + * express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this software. + */ + +#include <netdb.h> +#include <sys/time.h> +#include "defs.h" + +#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */ +#define DEFAULT_RETRIES 1 /* How many times to ask each router */ + + +/* All IP addresses are stored in the data structure in NET order. */ + +typedef struct neighbor { + struct neighbor *next; + u_long addr; /* IP address in NET order */ + u_char metric; /* TTL cost of forwarding */ + u_char threshold; /* TTL threshold to forward */ + u_short flags; /* flags on connection */ +#define NF_PRESENT 0x8000 /* True if flags are meaningful */ +} Neighbor; + +typedef struct interface { + struct interface *next; + u_long addr; /* IP address of the interface in NET order */ + Neighbor *neighbors; /* List of neighbors' IP addresses */ +} Interface; + +typedef struct node { + u_long addr; /* IP address of this entry in NET order */ + u_long version; /* which mrouted version is running */ + int tries; /* How many requests sent? -1 for aliases */ + union { + struct node *alias; /* If alias, to what? */ + struct interface *interfaces; /* Else, neighbor data */ + } u; + struct node *left, *right; +} Node; + + +Node *routers = 0; +u_long our_addr, target_addr = 0; /* in NET order */ +int debug = 0; +int retries = DEFAULT_RETRIES; +int timeout = DEFAULT_TIMEOUT; +int show_names = TRUE; + + +Node *find_node(addr, ptr) + u_long addr; + Node **ptr; +{ + Node *n = *ptr; + + if (!n) { + *ptr = n = (Node *) malloc(sizeof(Node)); + n->addr = addr; + n->version = 0; + n->tries = 0; + n->u.interfaces = 0; + n->left = n->right = 0; + return n; + } else if (addr == n->addr) + return n; + else if (addr < n->addr) + return find_node(addr, &(n->left)); + else + return find_node(addr, &(n->right)); +} + + +Interface *find_interface(addr, node) + u_long addr; + Node *node; +{ + Interface *ifc; + + for (ifc = node->u.interfaces; ifc; ifc = ifc->next) + if (ifc->addr == addr) + return ifc; + + ifc = (Interface *) malloc(sizeof(Interface)); + ifc->addr = addr; + ifc->next = node->u.interfaces; + node->u.interfaces = ifc; + ifc->neighbors = 0; + + return ifc; +} + + +Neighbor *find_neighbor(addr, node) + u_long addr; + Node *node; +{ + Interface *ifc; + + for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { + Neighbor *nb; + + for (nb = ifc->neighbors; nb; nb = nb->next) + if (nb->addr == addr) + return nb; + } + + return 0; +} + + +/* + * Log errors and other messages to stderr, according to the severity of the + * message and the current debug level. For errors of severity LOG_ERR or + * worse, terminate the program. + */ +void log(severity, syserr, format, a, b, c, d, e) + int severity, syserr; + char *format; + int a, b, c, d, e; +{ + char fmt[100]; + + switch (debug) { + case 0: if (severity > LOG_WARNING) return; + case 1: if (severity > LOG_NOTICE ) return; + case 2: if (severity > LOG_INFO ) return; + default: + fmt[0] = '\0'; + if (severity == LOG_WARNING) + strcat(fmt, "warning - "); + strncat(fmt, format, 80); + fprintf(stderr, fmt, a, b, c, d, e); + if (syserr == 0) + fprintf(stderr, "\n"); + else if (syserr < sys_nerr) + fprintf(stderr, ": %s\n", sys_errlist[syserr]); + else + fprintf(stderr, ": errno %d\n", syserr); + } + + if (severity <= LOG_ERR) + exit(-1); +} + + +/* + * Send a neighbors-list request. + */ +void ask(dst) + u_long dst; +{ + send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS, + htonl(MROUTED_LEVEL), 0); +} + +void ask2(dst) + u_long dst; +{ + send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, + htonl(MROUTED_LEVEL), 0); +} + + +/* + * Process an incoming group membership report. + */ +void accept_group_report(src, dst, group) + u_long src, dst, group; +{ + log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + + +/* + * Process an incoming neighbor probe message. + */ +void accept_probe(src, dst) + u_long src, dst; +{ + log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + + +/* + * Process an incoming route report message. + */ +void accept_report(src, dst, p, datalen) + u_long src, dst; + char *p; + int datalen; +{ + log(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + + +/* + * Process an incoming neighbor-list request message. + */ +void accept_neighbor_request(src, dst) + u_long src, dst; +{ + if (src != our_addr) + log(LOG_INFO, 0, + "ignoring spurious DVMRP neighbor request from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + +void accept_neighbor_request2(src, dst) + u_long src, dst; +{ + if (src != our_addr) + log(LOG_INFO, 0, + "ignoring spurious DVMRP neighbor request2 from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + + +/* + * Process an incoming neighbor-list message. + */ +void accept_neighbors(src, dst, p, datalen, level) + u_long src, dst, level; + u_char *p; + int datalen; +{ + Node *node = find_node(src, &routers); + + if (node->tries == 0) /* Never heard of 'em; must have hit them at */ + node->tries = 1; /* least once, though...*/ + else if (node->tries == -1) /* follow alias link */ + node = node->u.alias; + +#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\ + a += ((u_long)*p++ << 8), a += *p++) + + /* if node is running a recent mrouted, ask for additional info */ + if (level != 0) { + node->version = ntohl(level); + node->tries = 0; + ask2(src); + return; + } + + if (debug > 3) { + int i; + + fprintf(stderr, " datalen = %d\n", datalen); + for (i = 0; i < datalen; i++) { + if ((i & 0xF) == 0) + fprintf(stderr, " "); + fprintf(stderr, " %02x", p[i]); + if ((i & 0xF) == 0xF) + fprintf(stderr, "\n"); + } + if ((datalen & 0xF) != 0xF) + fprintf(stderr, "\n"); + } + + while (datalen > 0) { /* loop through interfaces */ + u_long ifc_addr; + u_char metric, threshold, ncount; + Node *ifc_node; + Interface *ifc; + Neighbor *old_neighbors; + + if (datalen < 4 + 3) { + log(LOG_WARNING, 0, "received truncated interface record from %s", + inet_fmt(src, s1)); + return; + } + + GET_ADDR(ifc_addr); + ifc_addr = htonl(ifc_addr); + metric = *p++; + threshold = *p++; + ncount = *p++; + datalen -= 4 + 3; + + /* Fix up any alias information */ + ifc_node = find_node(ifc_addr, &routers); + if (ifc_node->tries == 0) { /* new node */ + ifc_node->tries = -1; + ifc_node->u.alias = node; + } else if (ifc_node != node + && (ifc_node->tries > 0 || ifc_node->u.alias != node)) { + /* must merge two hosts' nodes */ + Interface *ifc_i, *next_ifc_i; + + if (ifc_node->tries == -1) { + Node *tmp = ifc_node->u.alias; + + ifc_node->u.alias = node; + ifc_node = tmp; + } + + /* Merge ifc_node (foo_i) into node (foo_n) */ + + if (ifc_node->tries > node->tries) + node->tries = ifc_node->tries; + + for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) { + Neighbor *nb_i, *next_nb_i, *nb_n; + Interface *ifc_n = find_interface(ifc_i->addr, node); + + old_neighbors = ifc_n->neighbors; + for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) { + next_nb_i = nb_i->next; + for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next) + if (nb_i->addr == nb_n->addr) { + if (nb_i->metric != nb_n->metric + || nb_i->threshold != nb_i->threshold) + log(LOG_WARNING, 0, + "inconsistent %s for neighbor %s of %s", + "metric/threshold", + inet_fmt(nb_i->addr, s1), + inet_fmt(node->addr, s2)); + free(nb_i); + break; + } + if (!nb_n) { /* no match for this neighbor yet */ + nb_i->next = ifc_n->neighbors; + ifc_n->neighbors = nb_i; + } + } + + next_ifc_i = ifc_i->next; + free(ifc_i); + } + + ifc_node->tries = -1; + ifc_node->u.alias = node; + } + + ifc = find_interface(ifc_addr, node); + old_neighbors = ifc->neighbors; + + /* Add the neighbors for this interface */ + while (ncount--) { + u_long neighbor; + Neighbor *nb; + Node *n_node; + + if (datalen < 4) { + log(LOG_WARNING, 0, "received truncated neighbor list from %s", + inet_fmt(src, s1)); + return; + } + + GET_ADDR(neighbor); + neighbor = htonl(neighbor); + datalen -= 4; + + for (nb = old_neighbors; nb; nb = nb->next) + if (nb->addr == neighbor) { + if (metric != nb->metric || threshold != nb->threshold) + log(LOG_WARNING, 0, + "inconsistent %s for neighbor %s of %s", + "metric/threshold", + inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2)); + goto next_neighbor; + } + + nb = (Neighbor *) malloc(sizeof(Neighbor)); + nb->next = ifc->neighbors; + ifc->neighbors = nb; + nb->addr = neighbor; + nb->metric = metric; + nb->threshold = threshold; + nb->flags = 0; + + n_node = find_node(neighbor, &routers); + if (n_node->tries == 0 && !target_addr) { /* it's a new router */ + ask(neighbor); + n_node->tries = 1; + } + + next_neighbor: ; + } + } +} + +void accept_neighbors2(src, dst, p, datalen) + u_long src, dst; + u_char *p; + int datalen; +{ + Node *node = find_node(src, &routers); + + if (node->tries == 0) /* Never heard of 'em; must have hit them at */ + node->tries = 1; /* least once, though...*/ + else if (node->tries == -1) /* follow alias link */ + node = node->u.alias; + + while (datalen > 0) { /* loop through interfaces */ + u_long ifc_addr; + u_char metric, threshold, ncount, flags; + Node *ifc_node; + Interface *ifc; + Neighbor *old_neighbors; + + if (datalen < 4 + 4) { + log(LOG_WARNING, 0, "received truncated interface record from %s", + inet_fmt(src, s1)); + return; + } + + ifc_addr = *(u_long*)p; + p += 4; + metric = *p++; + threshold = *p++; + flags = *p++; + ncount = *p++; + datalen -= 4 + 4; + + /* Fix up any alias information */ + ifc_node = find_node(ifc_addr, &routers); + if (ifc_node->tries == 0) { /* new node */ + ifc_node->tries = -1; + ifc_node->u.alias = node; + } else if (ifc_node != node + && (ifc_node->tries > 0 || ifc_node->u.alias != node)) { + /* must merge two hosts' nodes */ + Interface *ifc_i, *next_ifc_i; + + if (ifc_node->tries == -1) { + Node *tmp = ifc_node->u.alias; + + ifc_node->u.alias = node; + ifc_node = tmp; + } + + /* Merge ifc_node (foo_i) into node (foo_n) */ + + if (ifc_node->tries > node->tries) + node->tries = ifc_node->tries; + + for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) { + Neighbor *nb_i, *next_nb_i, *nb_n; + Interface *ifc_n = find_interface(ifc_i->addr, node); + + old_neighbors = ifc_n->neighbors; + for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) { + next_nb_i = nb_i->next; + for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next) + if (nb_i->addr == nb_n->addr) { + if (nb_i->metric != nb_n->metric + || nb_i->threshold != nb_i->threshold) + log(LOG_WARNING, 0, + "inconsistent %s for neighbor %s of %s", + "metric/threshold", + inet_fmt(nb_i->addr, s1), + inet_fmt(node->addr, s2)); + free(nb_i); + break; + } + if (!nb_n) { /* no match for this neighbor yet */ + nb_i->next = ifc_n->neighbors; + ifc_n->neighbors = nb_i; + } + } + + next_ifc_i = ifc_i->next; + free(ifc_i); + } + + ifc_node->tries = -1; + ifc_node->u.alias = node; + } + + ifc = find_interface(ifc_addr, node); + old_neighbors = ifc->neighbors; + + /* Add the neighbors for this interface */ + while (ncount--) { + u_long neighbor; + Neighbor *nb; + Node *n_node; + + if (datalen < 4) { + log(LOG_WARNING, 0, "received truncated neighbor list from %s", + inet_fmt(src, s1)); + return; + } + + neighbor = *(u_long*)p; + p += 4; + datalen -= 4; + if (neighbor == 0) + /* make leaf nets point to themselves */ + neighbor = ifc_addr; + + for (nb = old_neighbors; nb; nb = nb->next) + if (nb->addr == neighbor) { + if (metric != nb->metric || threshold != nb->threshold) + log(LOG_WARNING, 0, + "inconsistent %s for neighbor %s of %s", + "metric/threshold", + inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2)); + goto next_neighbor; + } + + nb = (Neighbor *) malloc(sizeof(Neighbor)); + nb->next = ifc->neighbors; + ifc->neighbors = nb; + nb->addr = neighbor; + nb->metric = metric; + nb->threshold = threshold; + nb->flags = flags | NF_PRESENT; + + n_node = find_node(neighbor, &routers); + if (n_node->tries == 0 && !target_addr) { /* it's a new router */ + ask(neighbor); + n_node->tries = 1; + } + + next_neighbor: ; + } + } +} + + +void check_vif_state() +{ + log(LOG_NOTICE, 0, "network marked down..."); +} + + +int retry_requests(node) + Node *node; +{ + int result; + + if (node) { + result = retry_requests(node->left); + if (node->tries > 0 && node->tries < retries) { + if (node->version) + ask2(node->addr); + else + ask(node->addr); + node->tries++; + result = 1; + } + return retry_requests(node->right) || result; + } else + return 0; +} + + +char *inet_name(addr) + u_long addr; +{ + struct hostent *e; + + e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); + + return e ? e->h_name : 0; +} + + +void print_map(node) + Node *node; +{ + if (node) { + char *name, *addr; + + print_map(node->left); + + addr = inet_fmt(node->addr, s1); + if (!target_addr + || (node->tries >= 0 && node->u.interfaces) + || (node->tries == -1 + && node->u.alias->tries >= 0 + && node->u.alias->u.interfaces)) { + if (show_names && (name = inet_name(node->addr))) + printf("%s (%s):", addr, name); + else + printf("%s:", addr); + if (node->tries < 0) + printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1)); + else if (!node->u.interfaces) + printf(" no response to query\n\n"); + else { + Interface *ifc; + + if (node->version) + printf(" <v%d.%d>", node->version & 0xff, + (node->version >> 8) & 0xff); + printf("\n"); + for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { + Neighbor *nb; + char *ifc_name = inet_fmt(ifc->addr, s1); + int ifc_len = strlen(ifc_name); + int count = 0; + + printf(" %s:", ifc_name); + for (nb = ifc->neighbors; nb; nb = nb->next) { + if (count > 0) + printf("%*s", ifc_len + 5, ""); + printf(" %s", inet_fmt(nb->addr, s1)); + if (show_names && (name = inet_name(nb->addr))) + printf(" (%s)", name); + printf(" [%d/%d", nb->metric, nb->threshold); + if (nb->flags) { + u_short flags = nb->flags; + if (flags & DVMRP_NF_TUNNEL) + printf("/tunnel"); + if (flags & DVMRP_NF_SRCRT) + printf("/srcrt"); + if (flags & DVMRP_NF_QUERIER) + printf("/querier"); + if (flags & DVMRP_NF_DISABLED) + printf("/disabled"); + if (flags & DVMRP_NF_DOWN) + printf("/down"); + } + printf("]\n"); + count++; + } + } + printf("\n"); + } + } + print_map(node->right); + } +} + + +char *graph_name(addr, buf) + u_long addr; + char *buf; +{ + char *name; + + if (show_names && (name = inet_name(addr))) + strcpy(buf, name); + else + inet_fmt(addr, buf); + + return buf; +} + + +void graph_edges(node) + Node *node; +{ + Interface *ifc; + Neighbor *nb; + char name[100]; + + if (node) { + graph_edges(node->left); + if (node->tries >= 0) { + printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n", + (int) node->addr, + node->addr & 0xFF, (node->addr >> 8) & 0xFF, + graph_name(node->addr, name), + node->u.interfaces ? "" : "*"); + for (ifc = node->u.interfaces; ifc; ifc = ifc->next) + for (nb = ifc->neighbors; nb; nb = nb->next) { + Node *nb_node = find_node(nb->addr, &routers); + Neighbor *nb2; + + if (nb_node->tries < 0) + nb_node = nb_node->u.alias; + + if (node != nb_node && + (!(nb2 = find_neighbor(node->addr, nb_node)) + || node->addr < nb_node->addr)) { + printf(" %d \"%d/%d", + nb_node->addr, nb->metric, nb->threshold); + if (nb2 && (nb2->metric != nb->metric + || nb2->threshold != nb->threshold)) + printf(",%d/%d", nb2->metric, nb2->threshold); + if (nb->flags & NF_PRESENT) + printf("%s%s", + nb->flags & DVMRP_NF_SRCRT ? "" : + nb->flags & DVMRP_NF_TUNNEL ? "E" : "P", + nb->flags & DVMRP_NF_DOWN ? "D" : ""); + printf("\"\n"); + } + } + printf(" ;\n"); + } + graph_edges(node->right); + } +} + +void elide_aliases(node) + Node *node; +{ + if (node) { + elide_aliases(node->left); + if (node->tries >= 0) { + Interface *ifc; + + for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { + Neighbor *nb; + + for (nb = ifc->neighbors; nb; nb = nb->next) { + Node *nb_node = find_node(nb->addr, &routers); + + if (nb_node->tries < 0) + nb->addr = nb_node->u.alias->addr; + } + } + } + elide_aliases(node->right); + } +} + +void graph_map() +{ + time_t now = time(0); + char *nowstr = ctime(&now); + + nowstr[24] = '\0'; /* Kill the newline at the end */ + elide_aliases(routers); + printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n", + nowstr); + graph_edges(routers); + printf("END\n"); +} + + +int get_number(var, deflt, pargv, pargc) + int *var, *pargc, deflt; + char ***pargv; +{ + if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */ + if (*pargc > 1 && isdigit((*pargv)[1][0])) { + (*pargv)++, (*pargc)--; + *var = atoi((*pargv)[0]); + return 1; + } else if (deflt >= 0) { + *var = deflt; + return 1; + } else + return 0; + } else { /* Get value from the rest of this argument */ + if (isdigit((*pargv)[0][2])) { + *var = atoi((*pargv)[0] + 2); + return 1; + } else { + return 0; + } + } +} + + +u_long host_addr(name) + char *name; +{ + struct hostent *e = gethostbyname(name); + int addr; + + if (e) + memcpy(&addr, e->h_addr_list[0], e->h_length); + else { + addr = inet_addr(name); + if (addr == -1) + addr = 0; + } + + return addr; +} + + +main(argc, argv) + int argc; + char *argv[]; +{ + int flood = FALSE, graph = FALSE; + +#ifdef SYSV + setvbuf(stderr, NULL, _IOLBF, 0); +#else + setlinebuf(stderr); +#endif + + if (geteuid() != 0) { + fprintf(stderr, "must be root\n"); + exit(1); + } + + argv++, argc--; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 'd': + if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc)) + goto usage; + break; + case 'f': + flood = TRUE; + break; + case 'g': + graph = TRUE; + break; + case 'n': + show_names = FALSE; + break; + case 'r': + if (!get_number(&retries, -1, &argv, &argc)) + goto usage; + break; + case 't': + if (!get_number(&timeout, -1, &argv, &argc)) + goto usage; + break; + default: + goto usage; + } + argv++, argc--; + } + + if (argc > 1) { + usage: + fprintf(stderr, + "Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n", + "[-r retries] [-d [debug-level]] [router]"); + fprintf(stderr, "\t-f Flood the routing graph with queries\n"); + fprintf(stderr, "\t (True by default unless `router' is given)\n"); + fprintf(stderr, "\t-g Generate output in GraphEd format\n"); + fprintf(stderr, "\t-n Don't look up DNS names for routers\n"); + exit(1); + } else if (argc == 1 && !(target_addr = host_addr(argv[0]))) { + fprintf(stderr, "Unknown host: %s\n", argv[0]); + exit(2); + } + + if (debug) + fprintf(stderr, "Debug level %u\n", debug); + + init_igmp(); + + { /* Find a good local address for us. */ + int udp; + struct sockaddr_in addr; + int addrlen = sizeof(addr); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = dvmrp_group; + addr.sin_port = htons(2000); /* any port over 1024 will do... */ + if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 + || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 + || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { + perror("Determining local address"); + exit(-1); + } + close(udp); + our_addr = addr.sin_addr.s_addr; + } + + /* Send initial seed message to all local routers */ + ask(target_addr ? target_addr : allhosts_group); + + if (target_addr) { + Node *n = find_node(target_addr, &routers); + + n->tries = 1; + + if (flood) + target_addr = 0; + } + + /* Main receive loop */ + for(;;) { + fd_set fds; + struct timeval tv; + int count, recvlen, dummy = 0; + + FD_ZERO(&fds); + FD_SET(igmp_socket, &fds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + count = select(igmp_socket + 1, &fds, 0, 0, &tv); + + if (count < 0) { + if (errno != EINTR) + perror("select"); + continue; + } else if (count == 0) { + log(LOG_DEBUG, 0, "Timed out receiving neighbor lists"); + if (retry_requests(routers)) + continue; + else + break; + } + + recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf), + 0, NULL, &dummy); + if (recvlen >= 0) + accept_igmp(recvlen); + else if (errno != EINTR) + perror("recvfrom"); + } + + printf("\n"); + + if (graph) + graph_map(); + else { + if (!target_addr) + printf("Multicast Router Connectivity:\n\n"); + print_map(routers); + } + + exit(0); +} diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c new file mode 100644 index 000000000000..c9451348c09e --- /dev/null +++ b/usr.sbin/mrouted/mrinfo.c @@ -0,0 +1,469 @@ +/* + * This tool requests configuration info from a multicast router + * and prints the reply (if any). Invoke it as: + * + * mrinfo router-name-or-address + * + * Written Wed Mar 24 1993 by Van Jacobson (adapted from the + * multicast mapper written by Pavel Curtis). + * + * The lawyers insist we include the following UC copyright notice. + * The mapper from which this is derived contained a Xerox copyright + * notice which follows the UC one. Try not to get depressed noting + * that the legal gibberish is larger than the program. + * + * Copyright (c) 1993 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 Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory 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. + * --------------------------------- + * Copyright (c) Xerox Corporation 1992. All rights reserved. + * + * License is granted to copy, to use, and to make and to use derivative works + * for research and evaluation purposes, provided that Xerox is acknowledged + * in all documentation pertaining to any such copy or derivative work. Xerox + * grants no other licenses expressed or implied. The Xerox trade name should + * not be used in any advertising without its written permission. + * + * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE + * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR + * ANY PARTICULAR PURPOSE. The software is provided "as is" without express + * or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this software. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Id: mrinfo.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $"; +/* original rcsid: + "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)"; +*/ +#endif + +#include <netdb.h> +#include <sys/time.h> +#include "defs.h" + +#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */ +#define DEFAULT_RETRIES 3 /* How many times to ask each router */ + +u_long our_addr, target_addr = 0; /* in NET order */ +int debug = 0; +int retries = DEFAULT_RETRIES; +int timeout = DEFAULT_TIMEOUT; +int target_level; + +char * +inet_name(addr) + u_long addr; +{ + struct hostent *e; + + if (addr == 0) + return "local"; + + e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); + + return e ? e->h_name : "?"; +} + +/* + * Log errors and other messages to stderr, according to the severity of the + * message and the current debug level. For errors of severity LOG_ERR or + * worse, terminate the program. + */ +void +log(severity, syserr, format, a, b, c, d, e) + int severity, syserr; + char *format; + int a, b, c, d, e; +{ + char fmt[100]; + + switch (debug) { + case 0: + if (severity > LOG_WARNING) + return; + case 1: + if (severity > LOG_NOTICE) + return; + case 2: + if (severity > LOG_INFO) + return; + default: + fmt[0] = '\0'; + if (severity == LOG_WARNING) + strcat(fmt, "warning - "); + strncat(fmt, format, 80); + fprintf(stderr, fmt, a, b, c, d, e); + if (syserr == 0) + fprintf(stderr, "\n"); + else if (syserr < sys_nerr) + fprintf(stderr, ": %s\n", sys_errlist[syserr]); + else + fprintf(stderr, ": errno %d\n", syserr); + } + + if (severity <= LOG_ERR) + exit(-1); +} + +/* + * Send a neighbors-list request. + */ +void +ask(dst) + u_long dst; +{ + send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS, + htonl(MROUTED_LEVEL), 0); +} + +void +ask2(dst) + u_long dst; +{ + send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, + htonl(MROUTED_LEVEL), 0); +} + +/* + * Process an incoming neighbor-list message. + */ +void +accept_neighbors(src, dst, p, datalen) + u_long src, dst; + u_char *p; + int datalen; +{ + u_char *ep = p + datalen; +#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\ + a += ((u_long)*p++ << 8), a += *p++) + + printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src)); + while (p < ep) { + register u_long laddr; + register u_char metric; + register u_char thresh; + register int ncount; + + GET_ADDR(laddr); + laddr = htonl(laddr); + metric = *p++; + thresh = *p++; + ncount = *p++; + while (--ncount >= 0) { + register u_long neighbor; + GET_ADDR(neighbor); + neighbor = htonl(neighbor); + printf(" %s -> ", inet_fmt(laddr, s1)); + printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1), + inet_name(neighbor), metric, thresh); + } + } +} + +void +accept_neighbors2(src, dst, p, datalen) + u_long src, dst; + u_char *p; + int datalen; +{ + u_char *ep = p + datalen; + + printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src), + target_level & 0xff, (target_level >> 8) & 0xff); + while (p < ep) { + register u_char metric; + register u_char thresh; + register u_char flags; + register int ncount; + register u_long laddr = *(u_long*)p; + + p += 4; + metric = *p++; + thresh = *p++; + flags = *p++; + ncount = *p++; + while (--ncount >= 0) { + register u_long neighbor = *(u_long*)p; + p += 4; + printf(" %s -> ", inet_fmt(laddr, s1)); + printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1), + inet_name(neighbor), metric, thresh); + if (flags & DVMRP_NF_TUNNEL) + printf("/tunnel"); + if (flags & DVMRP_NF_SRCRT) + printf("/srcrt"); + if (flags & DVMRP_NF_QUERIER) + printf("/querier"); + if (flags & DVMRP_NF_DISABLED) + printf("/disabled"); + if (flags & DVMRP_NF_DOWN) + printf("/down"); + printf("]\n"); + } + } +} + +int +get_number(var, deflt, pargv, pargc) + int *var, *pargc, deflt; + char ***pargv; +{ + if ((*pargv)[0][2] == '\0') { /* Get the value from the next + * argument */ + if (*pargc > 1 && isdigit((*pargv)[1][0])) { + (*pargv)++, (*pargc)--; + *var = atoi((*pargv)[0]); + return 1; + } else if (deflt >= 0) { + *var = deflt; + return 1; + } else + return 0; + } else { /* Get value from the rest of this argument */ + if (isdigit((*pargv)[0][2])) { + *var = atoi((*pargv)[0] + 2); + return 1; + } else { + return 0; + } + } +} + +u_long +host_addr(name) + char *name; +{ + struct hostent *e = gethostbyname(name); + int addr; + + if (e) + memcpy(&addr, e->h_addr_list[0], e->h_length); + else { + addr = inet_addr(name); + if (addr == -1) + addr = 0; + } + + return addr; +} + +void +usage() +{ + fprintf(stderr, "Usage: mrinfo [-t timeout] [-r retries] router\n"); + exit(1); +} + +main(argc, argv) + int argc; + char *argv[]; +{ + setlinebuf(stderr); + + if (geteuid() != 0) { + fprintf(stderr, "mrinfo: must be root\n"); + exit(1); + } + argv++, argc--; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 'd': + if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc)) + usage(); + break; + case 'r': + if (!get_number(&retries, -1, &argv, &argc)) + usage(); + break; + case 't': + if (!get_number(&timeout, -1, &argv, &argc)) + usage(); + break; + default: + usage(); + } + argv++, argc--; + } + if (argc != 1) + usage(); + + target_addr = host_addr(argv[0]); + if (target_addr == 0) { + fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]); + exit(1); + } + if (debug) + fprintf(stderr, "Debug level %u\n", debug); + + init_igmp(); + + { /* Find a good local address for us. */ + int udp; + struct sockaddr_in addr; + int addrlen = sizeof(addr); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = target_addr; + addr.sin_port = htons(2000); /* any port over 1024 will + * do... */ + if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 + || connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0 + || getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) { + perror("Determining local address"); + exit(-1); + } + close(udp); + our_addr = addr.sin_addr.s_addr; + } + + ask(target_addr); + + /* Main receive loop */ + for (;;) { + fd_set fds; + struct timeval tv; + int count, recvlen, dummy = 0; + register u_long src, dst, group; + struct ip *ip; + struct igmp *igmp; + int ipdatalen, iphdrlen, igmpdatalen; + + FD_ZERO(&fds); + FD_SET(igmp_socket, &fds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + count = select(igmp_socket + 1, &fds, 0, 0, &tv); + + if (count < 0) { + if (errno != EINTR) + perror("select"); + continue; + } else if (count == 0) { + log(LOG_DEBUG, 0, "Timed out receiving neighbor lists"); + if (--retries < 0) + exit(1); + if (target_level == 0) + ask(target_addr); + else + ask2(target_addr); + continue; + } + recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf), + 0, NULL, &dummy); + if (recvlen <= 0) { + if (recvlen && errno != EINTR) + perror("recvfrom"); + continue; + } + + if (recvlen < sizeof(struct ip)) { + log(LOG_WARNING, 0, + "packet too short (%u bytes) for IP header", + recvlen); + continue; + } + ip = (struct ip *) recv_buf; + src = ip->ip_src.s_addr; + if (src != target_addr) { + fprintf(stderr, "mrinfo: got reply from %s", + inet_fmt(src, s1)); + fprintf(stderr, " instead of %s\n", + inet_fmt(target_addr, s1)); + continue; + } + dst = ip->ip_dst.s_addr; + iphdrlen = ip->ip_hl << 2; + ipdatalen = ip->ip_len; + if (iphdrlen + ipdatalen != recvlen) { + log(LOG_WARNING, 0, + "packet shorter (%u bytes) than hdr+data length (%u+%u)", + recvlen, iphdrlen, ipdatalen); + continue; + } + igmp = (struct igmp *) (recv_buf + iphdrlen); + group = igmp->igmp_group.s_addr; + igmpdatalen = ipdatalen - IGMP_MINLEN; + if (igmpdatalen < 0) { + log(LOG_WARNING, 0, + "IP data field too short (%u bytes) for IGMP, from %s", + ipdatalen, inet_fmt(src, s1)); + continue; + } + if (igmp->igmp_type != IGMP_DVMRP) + continue; + + switch (igmp->igmp_code) { + + case DVMRP_NEIGHBORS: + if (group) { + /* knows about DVMRP_NEIGHBORS2 msg */ + if (target_level == 0) { + target_level = ntohl(group); + ask2(target_addr); + } + } else { + accept_neighbors(src, dst, (char *)(igmp + 1), + igmpdatalen); + exit(0); + } + break; + + case DVMRP_NEIGHBORS2: + accept_neighbors2(src, dst, (char *)(igmp + 1), + igmpdatalen); + exit(0); + } + } +} + +/* dummies */ +void accept_probe() +{ +} +void accept_group_report() +{ +} +void accept_neighbor_request2() +{ +} +void accept_report() +{ +} +void accept_neighbor_request() +{ +} +void check_vif_state() +{ +} diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8 new file mode 100644 index 000000000000..5013bc7c9e5b --- /dev/null +++ b/usr.sbin/mrouted/mrouted.8 @@ -0,0 +1,242 @@ +'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University. +.TH MROUTED 8 +.UC 5 +.SH NAME +mrouted \- IP multicast routing daemon +.SH SYNOPSIS +.B /etc/mrouted +[ +.B \-c +.I config_file +] [ +.B \-d +[ +.I debug_level +] ] +.SH DESCRIPTION +.I Mrouted +is an implementation of the Distance-Vector Multicast Routing +Protocol (DVMRP), an earlier version of which is specified in RFC-1075. +It maintains topological knowledge via a distance-vector routing protocol +(like RIP, described in RFC-1058), upon which it implements a multicast +forwarding algorithm called Truncated Reverse Path Broadcasting (TRPB). +.PP +.I Mrouted +forwards a multicast datagram along a shortest (reverse) path tree +rooted at the subnet on which the datagram originates. It is a +.I broadcast +tree, which means it includes +.I all +subnets reachable by a cooperating set of +.I mrouted +routers. However, the datagram will not be forwarded onto +.I leaf +subnets of the tree if those subnets do not have members of the destination +group. Furthermore, the IP time-to-live of a multicast datagram may prevent +it from being forwarded along the entire tree. +.PP +In order to support multicasting among subnets that are separated by (unicast) +routers that do not support IP multicasting, +.I mrouted +includes support for +"tunnels", which are virtual point-to-point links between pairs of +.IR mrouted s +located anywhere in an internet. IP multicast packets are encapsulated for +transmission through tunnels, so that they look like normal unicast datagrams +to intervening routers and subnets. The encapsulation +is inserted on entry to a tunnel, and stripped out +on exit from a tunnel. +By default, the packets are encapsulated using the IP-in-IP protocol +(IP protocol number 4). +Older versions of +.I mrouted +encapsulate using IP source routing, which puts a heavy load on some +types of routers. +This version supports IP source route encapsulation only for backwards +compatibility. +.PP +The tunnel mechanism allows +.I mrouted +to establish a virtual internet, for +the purpose of multicasting only, which is independent of the physical +internet, and which may span multiple Autonomous Systems. This capability +is intended for experimental support of internet multicasting only, pending +widespread support for multicast routing by the regular (unicast) routers. +.I Mrouted +suffers from the well-known scaling problems of any distance-vector +routing protocol, and does not (yet) support hierarchical multicast routing +or inter-operation with other multicast routing protocols. +.PP +.I Mrouted +handles multicast routing only; there may or may not be a unicast +router running on the same host as +.IR mrouted . +With the use of tunnels, it +is not necessary for +.I mrouted +to have access to more than one physical subnet +in order to perform multicast forwarding. +.br +.ne 5 +.SH INVOCATION +.PP +If no "\-d" option is given, or if the debug level is specified as 0, +.I mrouted +detaches from the invoking terminal. Otherwise, it remains attached to the +invoking terminal and responsive to signals from that terminal. If "\-d" is +given with no argument, the debug level defaults to 2. Regardless of the +debug level, +.I mrouted +always writes warning and error messages to the system +log demon. Non-zero debug levels have the following effects: +.IP "level 1" +all syslog'ed messages are also printed to stderr. +.IP "level 2" +all level 1 messages plus notifications of "significant" +events are printed to stderr. +.IP "level 3" +all level 2 messages plus notifications of all packet +arrivals and departures are printed to stderr. +.SH CONFIGURATION +.PP +.I Mrouted +automatically configures itself to forward on all multicast-capable +interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding +the loopback "interface"), and it finds other +.IR mrouted s +directly reachable +via those interfaces. To override the default configuration, or to add +tunnel links to other +.IR mrouted s, +configuration commands may be placed in +/etc/mrouted.conf (or an alternative file, specified by the "\-c" option). +There are two types of configuration command: +.nf + + phyint <local-addr> [disable] [metric <m>] [threshold <t>] + + tunnel <local-addr> <remote-addr> [metric <m>] [threshold <t>] [srcrt] + +.fi +The phyint command can be used to disable multicast routing on the physical +interface identified by local IP address <local-addr>, or to associate a +non-default metric or threshold with the specified physical interface. +Phyint commands must precede tunnel commands. +.PP +The tunnel command can be used to establish a tunnel link between local +IP address <local-addr> and remote IP address <remote-addr>, and to associate +a non-default metric or threshold with that tunnel. The tunnel must be set +up in the mrouted.conf files of both ends before it will be used. +For backwards compatibility with older +.IR mrouted s, +the srcrt keyword specifies +encapsulation using IP source routing. +.PP +The metric is the "cost" associated with sending a datagram on the given +interface or tunnel; it may be used to influence the choice of routes. +The metric defaults to 1. Metrics should be kept as small as possible, +because +.I mrouted +cannot route along paths with a sum of metrics greater +than 31. When in doubt, the following metrics are recommended: +.ne 5 +.IP 1 +LAN, or tunnel across a single LAN +.IP 2 +serial link, or tunnel across a single serial link +.IP 3 +multi-hop tunnel +.LP +The threshold is the minimum IP time-to-live required for a multicast datagram +to be forwarded to the given interface or tunnel. It is used to control the +scope of multicast datagrams. (The TTL of forwarded packets is only compared +to the threshold, it is not decremented by the threshold. Every multicast +router decrements the TTL by 1.) The default threshold is 1. +Suggested thresholds: +.IP 32 +for links that separate sites, +.IP 64 +for links that separate regions, +.IP 128 +for links that separate continents. +.LP +In general, all +.IR mrouted s +connected to a particular subnet or tunnel should +use the same metric and threshold for that subnet or tunnel. +.PP +.I Mrouted +will not initiate execution if it has fewer than two enabled vifs, +where a vif (virtual interface) is either a physical multicast-capable +interface or a tunnel. It will log a warning if all of its vifs are +tunnels; such an +.I mrouted +configuration would be better replaced by more +direct tunnels (i.e., eliminate the middle man). +.SH SIGNALS +.PP +.I Mrouted +responds to the following signals: +.IP HUP +.sp -.5v +.IP TERM +.sp -.5v +.IP INT +terminates execution gracefully (i.e., by sending +good-bye messages to all neighboring routers). +.IP USR1 +dumps the internal routing tables to /usr/tmp/mrouted.dump. +.IP QUIT +dumps the internal routing tables to stderr (only if +.I mrouted +was invoked with a non-zero debug level). +.bp +.SH EXAMPLE +.PP +The routing tables look like this: +.nf + +Virtual Interface Table + Vif Local-Address Metric Thresh Flags + 0 36.2.0.8 subnet: 36.2 1 1 querier + groups: 224.0.2.1 + 224.0.0.4 + 1 36.11.0.1 subnet: 36.11 1 1 querier + groups: 224.0.2.1 + 224.0.1.0 + 224.0.0.4 + 2 36.2.0.8 tunnel: 36.8.0.77 3 1 + peers : 36.8.0.77 + 3 36.2.0.8 tunnel: 36.8.0.110 3 1 + +Multicast Routing Table + Origin-Subnet From-Gateway Metric In-Vif Out-Vifs + 36.2 1 0 1* 2 3* + 36.8 36.8.0.77 4 2 0* 1* 3* + 36.11 1 1 0* 2 3* + +.fi +In this example, there are four vifs connecting to two subnets and two +tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and +vif 1 subnets have some groups present; tunnels never have any groups. This +instance of +.I mrouted +is the one responsible for sending periodic group +membership queries on the vif 0 and vif 1 subnets, as indicated by the +"querier" flags. +.PP +Associated with each subnet from which a multicast datagram can originate +is the address of the previous hop gateway (unless the subnet is directly- +connected), the metric of the path back to the origin, the incoming vif for +multicasts from that origin, and a list of outgoing vifs. "*" means that +the outgoing vif is connected to a leaf of the broadcast tree rooted at the +origin, and a multicast datagram from that origin will be forwarded on that +outgoing vif only if there are members of the destination group on that leaf. +.SH FILES +/etc/mrouted.conf +.SH SEE ALSO +TRPB is described, along with other multicast routing algorithms, in the +paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering, +in the Proceedings of the ACM SIGCOMM '88 Conference. +.SH AUTHOR +Steve Deering diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf new file mode 100644 index 000000000000..6629d4d1a8f8 --- /dev/null +++ b/usr.sbin/mrouted/mrouted.conf @@ -0,0 +1,15 @@ +# $Id: mrouted.conf,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ +# +# This is the configuration file for "mrouted", an IP multicast router. +# mrouted looks for it in "/etc/mrouted.conf". +# +# Command formats: +# +# phyint <local-addr> [disable] [metric <m>] [threshold <t>] +# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>] +# +# any phyint commands MUST precede any tunnel commands +# +# See the Mbone FAQ on ftp.isi.edu for metric, thresholds and connection info. +# +tunnel 129.89.9.63 129.89.9.50 metric 3 threshold 64 # <-- EXAMPLE; REPLACE OR DELETE diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c new file mode 100644 index 000000000000..d31165b1becd --- /dev/null +++ b/usr.sbin/mrouted/route.c @@ -0,0 +1,900 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: route.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + + +#include "defs.h" + + +/* + * Exported variables. + */ +int routes_changed; /* 1=>some routes have changed */ +int delay_change_reports; /* 1=>postpone change reports */ + + +/* + * Private variables. + */ +static struct rtentry *routing_table; /* pointer to list of route entries */ +static struct rtentry *rtp; /* pointer to a route entry */ +static unsigned nroutes; /* current number of route entries */ + + +/* + * Initialize the routing table and associated variables. + */ +void init_routes() +{ + routing_table = NULL; + nroutes = 0; + routes_changed = FALSE; + delay_change_reports = FALSE; +} + + +/* + * Initialize the children and leaf bits for route 'r', along with the + * associated dominant, subordinate, and leaf timing data structures. + * Return TRUE if this changes the value of either the children or + * leaf bitmaps for 'r'. + */ +static int init_children_and_leaves(r, parent) + register struct rtentry *r; + register vifi_t parent; +{ + register vifi_t vifi; + register struct uvif *v; + vifbitmap_t old_children, old_leaves; + + VIFM_COPY(r->rt_children, old_children); + VIFM_COPY(r->rt_leaves, old_leaves ); + + VIFM_CLRALL(r->rt_children); + VIFM_CLRALL(r->rt_leaves); + r->rt_flags &= ~RTF_LEAF_TIMING; + + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + r->rt_dominants [vifi] = 0; + r->rt_subordinates[vifi] = 0; + + if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { + VIFM_SET(vifi, r->rt_children); + if (v->uv_neighbors == NULL) { + VIFM_SET(vifi, r->rt_leaves); + r->rt_leaf_timers[vifi] = 0; + } + else { + r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; + r->rt_flags |= RTF_LEAF_TIMING; + } + } + else { + r->rt_leaf_timers[vifi] = 0; + } + } + + return (!VIFM_SAME(r->rt_children, old_children) || + !VIFM_SAME(r->rt_leaves, old_leaves)); +} + + +/* + * A new vif has come up -- update the children and leaf bitmaps in all route + * entries to take that into account. + */ +void add_vif_to_routes(vifi) + register vifi_t vifi; +{ + register struct rtentry *r; + register struct uvif *v; + + v = &uvifs[vifi]; + for (r = routing_table; r != NULL; r = r->rt_next) { + if (r->rt_metric != UNREACHABLE && + !VIFM_ISSET(vifi, r->rt_children)) { + VIFM_SET(vifi, r->rt_children); + r->rt_dominants [vifi] = 0; + r->rt_subordinates[vifi] = 0; + if (v->uv_neighbors == NULL) { + VIFM_SET(vifi, r->rt_leaves); + r->rt_leaf_timers[vifi] = 0; + } + else { + VIFM_CLR(vifi, r->rt_leaves); + r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; + r->rt_flags |= RTF_LEAF_TIMING; + } + k_update_route(r); + } + } +} + + +/* + * A vif has gone down -- expire all routes that have that vif as parent, + * and update the children bitmaps in all other route entries to take into + * account the failed vif. + */ +void delete_vif_from_routes(vifi) + register vifi_t vifi; +{ + register struct rtentry *r; + + for (r = routing_table; r != NULL; r = r->rt_next) { + if (r->rt_metric != UNREACHABLE) { + if (vifi == r->rt_parent) { + k_del_route(r); + r->rt_timer = ROUTE_EXPIRE_TIME; + r->rt_metric = UNREACHABLE; + r->rt_flags |= RTF_CHANGED; + routes_changed = TRUE; + } + else if (VIFM_ISSET(vifi, r->rt_children)) { + VIFM_CLR(vifi, r->rt_children); + VIFM_CLR(vifi, r->rt_leaves); + r->rt_subordinates[vifi] = 0; + r->rt_leaf_timers [vifi] = 0; + k_update_route(r); + } + else { + r->rt_dominants[vifi] = 0; + } + } + } +} + + +/* + * A neighbor has failed or become unreachable. If that neighbor was + * considered a dominant or subordinate router in any route entries, + * take appropriate action. + */ +void delete_neighbor_from_routes(addr, vifi) + register u_long addr; + register vifi_t vifi; +{ + register struct rtentry *r; + register struct uvif *v; + + v = &uvifs[vifi]; + for (r = routing_table; r != NULL; r = r->rt_next) { + if (r->rt_metric != UNREACHABLE) { + if (r->rt_dominants[vifi] == addr) { + VIFM_SET(vifi, r->rt_children); + r->rt_dominants [vifi] = 0; + r->rt_subordinates[vifi] = 0; + if (v->uv_neighbors == NULL) { + VIFM_SET(vifi, r->rt_leaves); + r->rt_leaf_timers[vifi] = 0; + } + else { + VIFM_CLR(vifi, r->rt_leaves); + r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; + r->rt_flags |= RTF_LEAF_TIMING; + } + k_update_route(r); + } + else if (r->rt_subordinates[vifi] == addr) { + r->rt_subordinates[vifi] = 0; + if (v->uv_neighbors == NULL) { + VIFM_SET(vifi, r->rt_leaves); + k_update_route(r); + } + else { + r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; + r->rt_flags |= RTF_LEAF_TIMING; + } + } + else if (v->uv_neighbors == NULL && + r->rt_leaf_timers[vifi] != 0) { + VIFM_SET(vifi, r->rt_leaves); + r->rt_leaf_timers[vifi] = 0; + k_update_route(r); + } + } + } +} + + +/* + * Prepare for a sequence of ordered route updates by initializing a pointer + * to the start of the routing table. The pointer is used to remember our + * position in the routing table in order to avoid searching from the + * beginning for each update; this relies on having the route reports in + * a single message be in the same order as the route entries in the routing + * table. + */ +void start_route_updates() +{ + rtp = (struct rtentry *)&routing_table; +} + + +/* + * Starting at the route entry following the one to which 'rtp' points, + * look for a route entry matching the specified origin and mask. If a + * match is found, return TRUE and leave 'rtp' pointing at the found entry. + * If no match is found, return FALSE and leave 'rtp' pointing to the route + * entry preceding the point at which the new origin should be inserted. + * This code is optimized for the normal case in which the first entry to + * be examined is the matching entry. + */ +static int find_route(origin, mask) + register u_long origin, mask; +{ + register struct rtentry *r; + + r = rtp->rt_next; + while (r != NULL) { + if (origin == r->rt_origin && mask == r->rt_originmask) { + rtp = r; + return (TRUE); + } + if (ntohl(mask) > ntohl(r->rt_originmask) || + (mask == r->rt_originmask && + ntohl(origin) > ntohl(r->rt_origin))) { + rtp = r; + r = r->rt_next; + } + else break; + } + return (FALSE); +} + + +/* + * Search the entire routing table, looking for an entry which conflicts + * with the given origin and mask, for example, an entry which has the same + * origin under a different mask. If a conflicting entry is found, return + * a pointer to the entry preceding it (to facilitate deletion); if no + * conflict is found, return NULL. + */ +static struct rtentry *find_conflicting_route(origin, mask) + register u_long origin, mask; +{ + register struct rtentry *r, *prev_r; + + for (prev_r = (struct rtentry *)&routing_table, r = routing_table; + r != NULL; + prev_r = r, r = r->rt_next ) { + if ((origin & r->rt_originmask) == r->rt_origin || + (r->rt_origin & mask) == origin) { + return (prev_r); + } + } + return (NULL); +} + + +/* + * Create a new routing table entry for the specified origin and link it into + * the routing table. The shared variable 'rtp' is assumed to point to the + * routing entry after which the new one should be inserted. It is left + * pointing to the new entry. + * + * Only the origin, originmask, originwidth and flags fields are initialized + * in the new route entry; the caller is responsible for filling in the the + * rest. + */ +static void create_route(origin, mask) + u_long origin, mask; +{ + register struct rtentry *r; + + if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) + + (3 * numvifs * sizeof(u_long)))) == NULL) { + log(LOG_ERR, 0, "ran out of memory"); /* fatal */ + } + r->rt_origin = origin; + r->rt_originmask = mask; + if (((char *)&mask)[3] != 0) r->rt_originwidth = 4; + else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3; + else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2; + else r->rt_originwidth = 1; + r->rt_flags = 0; + r->rt_dominants = (u_long *)(r + 1); + r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs); + r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs); + + r->rt_next = rtp->rt_next; + rtp->rt_next = r; + rtp = r; + ++nroutes; +} + + +/* + * Discard the routing table entry following the one to which 'prev_r' points. + */ +static void discard_route(prev_r) + register struct rtentry *prev_r; +{ + register struct rtentry *r; + + r = prev_r->rt_next; + prev_r->rt_next = r->rt_next; + free((char *)r); + --nroutes; +} + + +/* + * Process a route report for a single origin, creating or updating the + * corresponding routing table entry if necessary. 'src' is either the + * address of a neighboring router from which the report arrived, or zero + * to indicate a change of status of one of our own interfaces. + */ +void update_route(origin, mask, metric, src, vifi) + u_long origin, mask; + int metric; + u_long src; + vifi_t vifi; +{ + register struct rtentry *r; + struct rtentry *prev_r; + int adj_metric; + + /* + * Compute an adjusted metric, taking into account the cost of the + * subnet or tunnel over which the report arrived, and normalizing + * all unreachable/poisoned metrics into a single value. + */ + if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) { + log(LOG_WARNING, 0, + "%s reports out-of-range metric %u for origin %s", + inet_fmt(src, s1), metric, inet_fmts(origin, mask, s2)); + return; + } + adj_metric = metric + uvifs[vifi].uv_metric; + if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE; + + /* + * Look up the reported origin in the routing table. + */ + if (!find_route(origin, mask)) { + /* + * Not found. + * Don't create a new entry if the report says it's unreachable, + * or if the reported origin and mask are invalid. + */ + if (adj_metric == UNREACHABLE) { + return; + } + if (src != 0 && !inet_valid_subnet(origin, mask)) { + log(LOG_WARNING, 0, + "%s reports an invalid origin (%s) and/or mask (%08x)", + inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask)); + return; + } + + /* + * If the new origin and mask are inconsistent with an entry + * already in the routing table, either ignore this update + * (if it came from another router), or delete the conflicting + * entry (if the update is for a directly-connected subnet). + */ + if ((prev_r = find_conflicting_route(origin, mask)) != NULL ) { + if (src != 0) { + log(LOG_WARNING, 0, + "%s reports a conflicting origin (%s) and mask (%08x)", + inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask)); + return; + } + else { + r = prev_r->rt_next; + log(LOG_WARNING, 0, + "deleting route with conflicting origin (%s), mask (%08x)", + inet_fmt(r->rt_origin, s1), ntohl(r->rt_originmask)); + + if (r->rt_metric != UNREACHABLE) { + k_del_route(r); + } + discard_route(prev_r); + if (rtp == r) rtp = prev_r; + } + } + + /* + * OK, create the new routing entry. 'rtp' will be left pointing + * to the new entry. + */ + create_route(origin, mask); + + rtp->rt_metric = UNREACHABLE; /* temporary; updated below */ + } + + /* + * We now have a routing entry for the reported origin. Update it? + */ + r = rtp; + if (r->rt_metric == UNREACHABLE) { + /* + * The routing entry is for a formerly-unreachable or new origin. + * If the report claims reachability, update the entry to use + * the reported route. + */ + if (adj_metric == UNREACHABLE) + return; + + r->rt_parent = vifi; + init_children_and_leaves(r, vifi); + k_add_route(r); + r->rt_gateway = src; + r->rt_timer = 0; + r->rt_metric = adj_metric; + r->rt_flags |= RTF_CHANGED; + routes_changed = TRUE; + } + else if (src == r->rt_gateway) { + /* + * The report has come either from the interface directly-connected + * to the origin subnet (src and r->rt_gateway both equal zero) or + * from the gateway we have chosen as the best first-hop gateway back + * towards the origin (src and r->rt_gateway not equal zero). Reset + * the route timer and, if the reported metric has changed, update + * our entry accordingly. + */ + r->rt_timer = 0; + if (adj_metric == r->rt_metric) + return; + + if (adj_metric == UNREACHABLE) { + k_del_route(r); + r->rt_timer = ROUTE_EXPIRE_TIME; + } + else if (adj_metric < r->rt_metric) { + if (init_children_and_leaves(r, vifi)) { + k_update_route(r); + } + } + r->rt_metric = adj_metric; + r->rt_flags |= RTF_CHANGED; + routes_changed = TRUE; + } + else if (src == 0 || + (r->rt_gateway != 0 && + (adj_metric < r->rt_metric || + (adj_metric == r->rt_metric && + r->rt_timer >= ROUTE_SWITCH_TIME)))) { + /* + * The report is for an origin we consider reachable; the report + * comes either from one of our own interfaces or from a gateway + * other than the one we have chosen as the best first-hop gateway + * back towards the origin. If the source of the update is one of + * our own interfaces, or if the origin is not a directly-connected + * subnet and the reported metric for that origin is better than + * what our routing entry says, update the entry to use the new + * gateway and metric. We also switch gateways if the reported + * metric is the same as the one in the route entry and the gateway + * associated with the route entry has not been heard from recently. + * Did you get all that? + */ + if (r->rt_parent != vifi || adj_metric < r->rt_metric) { + r->rt_parent = vifi; + if (init_children_and_leaves(r, vifi)) { + k_update_route(r); + } + } + r->rt_gateway = src; + r->rt_timer = 0; + r->rt_metric = adj_metric; + r->rt_flags |= RTF_CHANGED; + routes_changed = TRUE; + } + else if (vifi != r->rt_parent) { + /* + * The report came from a vif other than the route's parent vif. + * Update the children and leaf info, if necessary. + */ + if (VIFM_ISSET(vifi, r->rt_children)) { + /* + * Vif is a child vif for this route. + */ + if (metric < r->rt_metric || + (metric == r->rt_metric && + ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) { + /* + * Neighbor has lower metric to origin (or has same metric + * and lower IP address) -- it becomes the dominant router, + * and vif is no longer a child for me. + */ + VIFM_CLR(vifi, r->rt_children); + VIFM_CLR(vifi, r->rt_leaves); + r->rt_dominants [vifi] = src; + r->rt_subordinates[vifi] = 0; + r->rt_leaf_timers [vifi] = 0; + k_update_route(r); + } + else if (metric > UNREACHABLE) { /* "poisoned reverse" */ + /* + * Neighbor considers this vif to be on path to route's + * origin; if no subordinate recorded, record this neighbor + * as subordinate and clear the leaf flag. + */ + if (r->rt_subordinates[vifi] == 0) { + VIFM_CLR(vifi, r->rt_leaves); + r->rt_subordinates[vifi] = src; + r->rt_leaf_timers [vifi] = 0; + k_update_route(r); + } + } + else if (src == r->rt_subordinates[vifi]) { + /* + * Current subordinate no longer considers this vif to be on + * path to route's origin; it is no longer a subordinate + * router, and we set the leaf confirmation timer to give + * us time to hear from other subordinates. + */ + r->rt_subordinates[vifi] = 0; + if (uvifs[vifi].uv_neighbors == NULL || + uvifs[vifi].uv_neighbors->al_next == NULL) { + VIFM_SET(vifi, r->rt_leaves); + k_update_route(r); + } + else { + r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME; + r->rt_flags |= RTF_LEAF_TIMING; + } + } + + } + else if (src == r->rt_dominants[vifi] && + (metric > r->rt_metric || + (metric == r->rt_metric && + ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) { + /* + * Current dominant no longer has a lower metric to origin + * (or same metric and lower IP address); we adopt the vif + * as our own child. + */ + VIFM_SET(vifi, r->rt_children); + r->rt_dominants [vifi] = 0; + if (metric > UNREACHABLE) { + r->rt_subordinates[vifi] = src; + } + else if (uvifs[vifi].uv_neighbors == NULL || + uvifs[vifi].uv_neighbors->al_next == NULL) { + VIFM_SET(vifi, r->rt_leaves); + } + else { + r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; + r->rt_flags |= RTF_LEAF_TIMING; + } + k_update_route(r); + } + } +} + + +/* + * On every timer interrupt, advance the timer in each routing entry. + */ +void age_routes() +{ + register struct rtentry *r; + register struct rtentry *prev_r; + register vifi_t vifi; + + for (prev_r = (struct rtentry *)&routing_table, r = routing_table; + r != NULL; + prev_r = r, r = r->rt_next) { + + if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) { + /* + * Route is still good; see if any leaf timers need to be + * advanced. + */ + if (r->rt_flags & RTF_LEAF_TIMING) { + r->rt_flags &= ~RTF_LEAF_TIMING; + for (vifi = 0; vifi < numvifs; ++vifi) { + if (r->rt_leaf_timers[vifi] != 0) { + /* + * Unlike other timers, leaf timers decrement. + */ + if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){ + VIFM_SET(vifi, r->rt_leaves); + k_update_route(r); + } + else { + r->rt_flags |= RTF_LEAF_TIMING; + } + } + } + } + } + else if (r->rt_timer >= ROUTE_DISCARD_TIME) { + /* + * Time to garbage-collect the route entry. + */ + discard_route(prev_r); + r = prev_r; + } + else if (r->rt_metric != UNREACHABLE) { + /* + * Time to expire the route entry. If the gateway is zero, + * i.e., it is a route to a directly-connected subnet, just + * set the timer back to zero; such routes expire only when + * the interface to the subnet goes down. + */ + if (r->rt_gateway == 0) { + r->rt_timer = 0; + } + else { + k_del_route(r); + r->rt_metric = UNREACHABLE; + r->rt_flags |= RTF_CHANGED; + routes_changed = TRUE; + } + } + } +} + + +/* + * Mark all routes as unreachable. This function is called only from + * hup() in preparation for informing all neighbors that we are going + * off the air. For consistency, we ought also to delete all reachable + * route entries from the kernel, but since we are about to exit we rely + * on the kernel to do its own cleanup -- no point in making all those + * expensive kernel calls now. + */ +void expire_all_routes() +{ + register struct rtentry *r; + + for (r = routing_table; r != NULL; r = r->rt_next) { + r->rt_metric = UNREACHABLE; + r->rt_flags |= RTF_CHANGED; + routes_changed = TRUE; + } +} + + +/* + * Process an incoming neighbor probe message. + */ +void accept_probe(src, dst) + u_long src, dst; +{ + vifi_t vifi; + + if ((vifi = find_vif(src, dst)) == NO_VIF) { + log(LOG_INFO, 0, + "ignoring probe from non-neighbor %s", inet_fmt(src, s1)); + return; + } + + if (!update_neighbor(vifi, src, DVMRP_PROBE)) + return; + + report(ALL_ROUTES, vifi, src); +} + + +/* + * Process an incoming route report message. + */ +void accept_report(src, dst, p, datalen) + u_long src, dst; + register char *p; + register int datalen; +{ + vifi_t vifi; + register int width, i; + int metric; + u_long mask; + u_long origin; + + if ((vifi = find_vif(src, dst)) == NO_VIF) { + log(LOG_INFO, 0, + "ignoring route report from non-neighbor %s", inet_fmt(src, s1)); + return; + } + + if (!update_neighbor(vifi, src, DVMRP_REPORT)) + return; + + start_route_updates(); + + while (datalen > 0) { /* Loop through per-mask lists. */ + + if (datalen < 3) { + log(LOG_WARNING, 0, + "received truncated route report from %s", inet_fmt(src, s1)); + return; + } + ((char *)&mask)[0] = 0xff; width = 1; + if ((((char *)&mask)[1] = *p++) != 0) width = 2; + if ((((char *)&mask)[2] = *p++) != 0) width = 3; + if ((((char *)&mask)[3] = *p++) != 0) width = 4; + datalen -= 3; + + do { /* Loop through (origin, metric) pairs */ + + if (datalen < width + 1) { + log(LOG_WARNING, 0, + "received truncated route report from %s", inet_fmt(src, s1)); + return; + } + origin = 0; + for (i = 0; i < width; ++i) + ((char *)&origin)[i] = *p++; + metric = *p++; + datalen -= width + 1; + + update_route(origin, mask, (metric & 0x7f), src, vifi); + + } while (!(metric & 0x80)); + } + + if (routes_changed && !delay_change_reports) + report_to_all_neighbors(CHANGED_ROUTES); +} + + +/* + * Send a route report message to destination 'dst', via virtual interface + * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. + */ +void report(which_routes, vifi, dst) + int which_routes; + vifi_t vifi; + u_long dst; +{ + register struct rtentry *r; + register char *p; + register int i; + int datalen; + int width; + u_long mask; + u_long src; + + src = uvifs[vifi].uv_lcl_addr; + + p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; + datalen = 0; + mask = 0; + + for (r = routing_table; r != NULL; r = r->rt_next) { + + if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) + continue; + + /* + * If there is no room for this route in the current message, + * send the message and start a new one. + */ + if (datalen + ((r->rt_originmask == mask) ? + (width + 1) : + (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) { + *(p-1) |= 0x80; + send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, + htonl(MROUTED_LEVEL), datalen); + + p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; + datalen = 0; + mask = 0; + } + + if(r->rt_originmask != mask) { + mask = r->rt_originmask; + width = r->rt_originwidth; + if (datalen != 0) *(p-1) |= 0x80; + *p++ = ((char *)&mask)[1]; + *p++ = ((char *)&mask)[2]; + *p++ = ((char *)&mask)[3]; + datalen += 3; + } + + for (i = 0; i < width; ++i) + *p++ = ((char *)&(r->rt_origin))[i]; + + *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ? + (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */ + (char)(r->rt_metric); + + datalen += width + 1; + } + + if (datalen != 0) { + *(p-1) |= 0x80; + send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, + htonl(MROUTED_LEVEL), datalen); + } +} + + +/* + * Send a route report message to all neighboring routers. + * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. + */ +void report_to_all_neighbors(which_routes) + int which_routes; +{ + register vifi_t vifi; + register struct uvif *v; + register struct rtentry *r; + int routes_changed_before; + + /* + * Remember the state of the global routes_changed flag before + * generating the reports, and clear the flag. + */ + routes_changed_before = routes_changed; + routes_changed = FALSE; + + + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if (v->uv_neighbors != NULL) { + report(which_routes, vifi, + (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr + : dvmrp_group); + } + } + + /* + * If there were changed routes before we sent the reports AND + * if no new changes occurred while sending the reports, clear + * the change flags in the individual route entries. If changes + * did occur while sending the reports, new reports will be + * generated at the next timer interrupt. + */ + if (routes_changed_before && !routes_changed) { + for (r = routing_table; r != NULL; r = r->rt_next) { + r->rt_flags &= ~RTF_CHANGED; + } + } + + /* + * Set a flag to inhibit further reports of changed routes until the + * next timer interrupt. This is to alleviate update storms. + */ + delay_change_reports = TRUE; +} + + +/* + * Print the contents of the routing table on file 'fp'. + */ +void dump_routes(fp) + FILE *fp; +{ + register struct rtentry *r; + register int i; + + fprintf(fp, + "Multicast Routing Table (%u %s)\n%s", + nroutes, (nroutes == 1) ? "entry" : "entries", + " Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n"); + + for (r = routing_table; r != NULL; r = r->rt_next) { + + fprintf(fp, " %-15s %-15s ", + inet_fmts(r->rt_origin, r->rt_originmask, s1), + (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2)); + + fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ", + r->rt_metric); + + fprintf(fp, "%7u ", + r->rt_parent); + + for (i = 0; i < numvifs; ++i) { + if (VIFM_ISSET(i, r->rt_children)) { + fprintf(fp, " %u%c", + i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' '); + } + } + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); +} diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h new file mode 100644 index 000000000000..03ee8c656cfe --- /dev/null +++ b/usr.sbin/mrouted/route.h @@ -0,0 +1,50 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: route.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + +/* + * Routing Table Entry, one per subnet from which a multicast could originate. + * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.) + * + * The Routing Table is stored as a singly-linked list of these structures, + * ordered by increasing value of rt_originmask and, secondarily, by + * increasing value of rt_origin within each rt_originmask value. + * This data structure is efficient for generating route reports, whether + * full or partial, for processing received full reports, for clearing the + * CHANGED flags, and for periodically advancing the timers in all routes. + * It is not so efficient for updating a small number of routes in response + * to a partial report. In a stable topology, the latter are rare; if they + * turn out to be costing a lot, we can add an auxiliary hash table for + * faster access to arbitrary route entries. + */ +struct rtentry { + struct rtentry *rt_next; /* link to next entry MUST BE FIRST */ + u_long rt_origin; /* subnet origin of multicasts */ + u_long rt_originmask; /* subnet mask for origin */ + short rt_originwidth; /* # bytes of origin subnet number */ + u_char rt_metric; /* cost of route back to origin */ + u_char rt_flags; /* RTF_ flags defined below */ + u_long rt_gateway; /* first-hop gateway back to origin */ + vifi_t rt_parent; /* incoming vif (ie towards origin) */ + vifbitmap_t rt_children; /* outgoing children vifs */ + vifbitmap_t rt_leaves; /* subset of outgoing children vifs */ + u_long *rt_dominants; /* per vif dominant gateways */ + u_long *rt_subordinates; /* per vif subordinate gateways */ + u_long *rt_leaf_timers; /* per vif leaf confirmation timers */ + u_long rt_timer; /* for timing out the route entry */ +}; + +#define RTF_CHANGED 0x01 /* route changed but not reported */ +#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */ + + +#define ALL_ROUTES 0 /* possible arguments to report() */ +#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */ diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c new file mode 100644 index 000000000000..5a55dd41654b --- /dev/null +++ b/usr.sbin/mrouted/vif.c @@ -0,0 +1,782 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: vif.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $ + */ + + +#include "defs.h" + + +/* + * Exported variables. + */ +struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */ +vifi_t numvifs; /* number of vifs in use */ +int vifs_down; /* 1=>some interfaces are down */ +int udp_socket; /* Since the honkin' kernel doesn't support */ + /* ioctls on raw IP sockets, we need a UDP */ + /* socket as well as our IGMP (raw) socket. */ + /* How dumb. */ + +/* + * Forward declarations. + */ +static void start_vif(); +static void stop_vif(); + + +/* + * Initialize the virtual interfaces. + */ +void init_vifs() +{ + vifi_t vifi; + struct uvif *v; + int enabled_vifs, enabled_phyints; + + numvifs = 0; + vifs_down = FALSE; + + /* + * Configure the vifs based on the interface configuration of the + * the kernel and the contents of the configuration file. + * (Open a UDP socket for ioctl use in the config procedures.) + */ + if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + log(LOG_ERR, errno, "UDP socket"); + config_vifs_from_kernel(); + config_vifs_from_file(); + + /* + * Quit if there are fewer than two enabled vifs. + */ + enabled_vifs = 0; + enabled_phyints = 0; + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if (!(v->uv_flags & VIFF_DISABLED)) { + ++enabled_vifs; + if (!(v->uv_flags & VIFF_TUNNEL)) + ++enabled_phyints; + } + } + if (enabled_vifs < 2) + log(LOG_ERR, 0, "can't forward: %s", + enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif"); + + if (enabled_phyints == 0) + log(LOG_WARNING, 0, + "no enabled interfaces, forwarding via tunnels only"); + + /* + * Start routing on all virtual interfaces that are not down or + * administratively disabled. + */ + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if (!(v->uv_flags & VIFF_DISABLED)) { + if (!(v->uv_flags & VIFF_DOWN)) + start_vif(vifi); + else log(LOG_INFO, 0, + "%s is not yet up; vif #%u not in service", + v->uv_name, vifi); + } + } +} + + +/* + * See if any interfaces have changed from up state to down, or vice versa, + * including any non-multicast-capable interfaces that are in use as local + * tunnel end-points. Ignore interfaces that have been administratively + * disabled. + */ +void check_vif_state() +{ + register vifi_t vifi; + register struct uvif *v; + struct ifreq ifr; + + vifs_down = FALSE; + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + + if (v->uv_flags & VIFF_DISABLED) continue; + + strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ); + if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) + log(LOG_ERR, errno, + "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); + + if (v->uv_flags & VIFF_DOWN) { + if (ifr.ifr_flags & IFF_UP) { + v->uv_flags &= ~VIFF_DOWN; + start_vif(vifi); + log(LOG_INFO, 0, + "%s has come up; vif #%u now in service", + v->uv_name, vifi); + } + else vifs_down = TRUE; + } + else { + if (!(ifr.ifr_flags & IFF_UP)) { + stop_vif(vifi); + v->uv_flags |= VIFF_DOWN; + log(LOG_INFO, 0, + "%s has gone down; vif #%u taken out of service", + v->uv_name, vifi); + vifs_down = TRUE; + } + } + } +} + + +/* + * Start routing on the specified virtual interface. + */ +static void start_vif(vifi) + vifi_t vifi; +{ + struct uvif *v; + u_long src, dst; + + v = &uvifs[vifi]; + src = v->uv_lcl_addr; + dst = (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr : dvmrp_group; + + /* + * Install the interface in the kernel's vif structure. + */ + k_add_vif(vifi, &uvifs[vifi]); + + /* + * Update the existing route entries to take into account the new vif. + */ + add_vif_to_routes(vifi); + + if (!(v->uv_flags & VIFF_TUNNEL)) { + /* + * Join the DVMRP multicast group on the interface. + * (This is not strictly necessary, since the kernel promiscuously + * receives IGMP packets addressed to ANY IP multicast group while + * multicast routing is enabled. However, joining the group allows + * this host to receive non-IGMP packets as well, such as 'pings'.) + */ + k_join(dvmrp_group, src); + + /* + * Install an entry in the routing table for the subnet to which + * the interface is connected. + */ + start_route_updates(); + update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi); + + /* + * Until neighbors are discovered, assume responsibility for sending + * periodic group membership queries to the subnet. Send the first + * query. + */ + v->uv_flags |= VIFF_QUERIER; + send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY, 0, 0, 0); + } + + /* + * Send a probe via the new vif to look for neighbors. + */ + send_igmp(src, dst, IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), 0); +} + + +/* + * Stop routing on the specified virtual interface. + */ +static void stop_vif(vifi) + vifi_t vifi; +{ + struct uvif *v; + struct listaddr *a; + + v = &uvifs[vifi]; + + if (!(v->uv_flags & VIFF_TUNNEL)) { + /* + * Depart from the DVMRP multicast group on the interface. + */ + k_leave(dvmrp_group, v->uv_lcl_addr); + + /* + * Update the entry in the routing table for the subnet to which + * the interface is connected, to take into account the interface + * failure. + */ + start_route_updates(); + update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi); + + /* + * Discard all group addresses. (No need to tell kernel; + * the k_del_vif() call, below, will clean up kernel state.) + */ + while (v->uv_groups != NULL) { + a = v->uv_groups; + v->uv_groups = a->al_next; + free((char *)a); + } + + v->uv_flags &= ~VIFF_QUERIER; + } + + /* + * Update the existing route entries to take into account the vif failure. + */ + delete_vif_from_routes(vifi); + + /* + * Delete the interface from the kernel's vif structure. + */ + k_del_vif(vifi); + + /* + * Discard all neighbor addresses. + */ + while (v->uv_neighbors != NULL) { + a = v->uv_neighbors; + v->uv_neighbors = a->al_next; + free((char *)a); + } +} + + +/* + * Find the virtual interface from which an incoming packet arrived, + * based on the packet's source and destination IP addresses. + */ +vifi_t find_vif(src, dst) + register u_long src; + register u_long dst; +{ + register vifi_t vifi; + register struct uvif *v; + + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { + if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { + if (v->uv_flags & VIFF_TUNNEL) { + if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr) + return(vifi); + } + else { + if ((src & v->uv_subnetmask) == v->uv_subnet && + src != v->uv_subnetbcast) + return(vifi); + } + } + } + return (NO_VIF); +} + + +/* + * Send group membership queries to all subnets for which I am querier. + */ +void query_groups() +{ + register vifi_t vifi; + register struct uvif *v; + + for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { + if (v->uv_flags & VIFF_QUERIER) { + send_igmp(v->uv_lcl_addr, allhosts_group, + IGMP_HOST_MEMBERSHIP_QUERY, 0, 0, 0); + } + } +} + + +/* + * Process an incoming group membership report. + */ +void accept_group_report(src, dst, group) + u_long src, dst, group; +{ + register vifi_t vifi; + register struct uvif *v; + register struct listaddr *g; + + if ((vifi = find_vif(src, dst)) == NO_VIF || + (uvifs[vifi].uv_flags & VIFF_TUNNEL)) { + log(LOG_INFO, 0, + "ignoring group membership report from non-adjacent host %s", + inet_fmt(src, s1)); + return; + } + + v = &uvifs[vifi]; + + /* + * Look for the group in our group list; if found, reset its timer. + */ + for (g = v->uv_groups; g != NULL; g = g->al_next) { + if (group == g->al_addr) { + g->al_timer = 0; + break; + } + } + + /* + * If not found, add it to the list and tell the kernel. + */ + if (g == NULL) { + g = (struct listaddr *)malloc(sizeof(struct listaddr)); + if (g == NULL) + log(LOG_ERR, 0, "ran out of memory"); /* fatal */ + + g->al_addr = group; + g->al_timer = 0; + g->al_next = v->uv_groups; + v->uv_groups = g; + + k_add_group(vifi, group); + } +} + + +/* + * Send a probe on all vifs from which no neighbors have been heard recently. + */ +void probe_for_neighbors() +{ + register vifi_t vifi; + register struct uvif *v; + + for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { + if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED)) && + v->uv_neighbors == NULL) { + send_igmp(v->uv_lcl_addr, + (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr + : dvmrp_group, + IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), 0); + } + } +} + + +/* + * Send a list of all of our neighbors to the requestor, `src'. + */ +void accept_neighbor_request(src, dst) + u_long src, dst; +{ + vifi_t vifi; + struct uvif *v; + u_char *p, *ncount; + struct listaddr *la; + int datalen; + u_long temp_addr, us, them = src; + + /* Determine which of our addresses to use as the source of our response + * to this query. + */ + if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ + int udp; /* find best interface to reply on */ + struct sockaddr_in addr; + int addrlen = sizeof(addr); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = dst; + addr.sin_port = htons(2000); /* any port over 1024 will do... */ + if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 + || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 + || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { + log(LOG_WARNING, errno, "Determining local address"); + close(udp); + return; + } + close(udp); + us = addr.sin_addr.s_addr; + } else /* query sent to us alone */ + us = dst; + +#define PUT_ADDR(a) temp_addr = ntohl(a); \ + *p++ = temp_addr >> 24; \ + *p++ = (temp_addr >> 16) & 0xFF; \ + *p++ = (temp_addr >> 8) & 0xFF; \ + *p++ = temp_addr & 0xFF; + + p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); + datalen = 0; + + for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { + if (v->uv_flags & VIFF_DISABLED) + continue; + + ncount = 0; + + for (la = v->uv_neighbors; la; la = la->al_next) { + + /* Make sure that there's room for this neighbor... */ + if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) { + send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, + htonl(MROUTED_LEVEL), datalen); + p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); + datalen = 0; + ncount = 0; + } + + /* Put out the header for this neighbor list... */ + if (ncount == 0) { + PUT_ADDR(v->uv_lcl_addr); + *p++ = v->uv_metric; + *p++ = v->uv_threshold; + ncount = p; + *p++ = 0; + datalen += 4 + 3; + } + + PUT_ADDR(la->al_addr); + datalen += 4; + (*ncount)++; + } + } + + if (datalen != 0) + send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL), + datalen); +} + +/* + * Send a list of all of our neighbors to the requestor, `src'. + */ +void accept_neighbor_request2(src, dst) + u_long src, dst; +{ + vifi_t vifi; + struct uvif *v; + u_char *p, *ncount; + struct listaddr *la; + int datalen; + u_long temp_addr, us, them = src; + + /* Determine which of our addresses to use as the source of our response + * to this query. + */ + if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ + int udp; /* find best interface to reply on */ + struct sockaddr_in addr; + int addrlen = sizeof(addr); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = dst; + addr.sin_port = htons(2000); /* any port over 1024 will do... */ + if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 + || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 + || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { + log(LOG_WARNING, errno, "Determining local address"); + close(udp); + return; + } + close(udp); + us = addr.sin_addr.s_addr; + } else /* query sent to us alone */ + us = dst; + + p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); + datalen = 0; + + for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { + register u_short vflags = v->uv_flags; + register u_char rflags = 0; + if (vflags & VIFF_TUNNEL) + rflags |= DVMRP_NF_TUNNEL; + if (vflags & VIFF_SRCRT) + rflags |= DVMRP_NF_SRCRT; + if (vflags & VIFF_DOWN) + rflags |= DVMRP_NF_DOWN; + if (vflags & VIFF_DISABLED) + rflags |= DVMRP_NF_DISABLED; + if (vflags & VIFF_QUERIER) + rflags |= DVMRP_NF_QUERIER; + ncount = 0; + la = v->uv_neighbors; + if (la == NULL) { + /* + * include down & disabled interfaces and interfaces on + * leaf nets. + */ + if (rflags & DVMRP_NF_TUNNEL) + rflags |= DVMRP_NF_DOWN; + if (datalen > MAX_DVMRP_DATA_LEN - 12) { + send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, + htonl(MROUTED_LEVEL), datalen); + p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); + datalen = 0; + } + *(u_int*)p = v->uv_lcl_addr; + p += 4; + *p++ = v->uv_metric; + *p++ = v->uv_threshold; + *p++ = rflags; + *p++ = 1; + *(u_int*)p = v->uv_rmt_addr; + p += 4; + datalen += 12; + } else { + for ( ; la; la = la->al_next) { + /* Make sure that there's room for this neighbor... */ + if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) { + send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, + htonl(MROUTED_LEVEL), datalen); + p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); + datalen = 0; + ncount = 0; + } + /* Put out the header for this neighbor list... */ + if (ncount == 0) { + *(u_int*)p = v->uv_lcl_addr; + p += 4; + *p++ = v->uv_metric; + *p++ = v->uv_threshold; + *p++ = rflags; + ncount = p; + *p++ = 0; + datalen += 4 + 4; + } + *(u_int*)p = la->al_addr; + p += 4; + datalen += 4; + (*ncount)++; + } + } + } + if (datalen != 0) + send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL), + datalen); +} + + +/* + * Process an incoming neighbor-list message. + */ +void accept_neighbors(src, dst, p, datalen, level) + u_long src, dst, level; + char *p; + int datalen; +{ + log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + +/* + * Process an incoming neighbor-list message. + */ +void accept_neighbors2(src, dst, p, datalen, level) + u_long src, dst, level; + char *p; + int datalen; +{ + log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", + inet_fmt(src, s1), inet_fmt(dst, s2)); +} + + +/* + * Update the neighbor entry for neighbor 'addr' on vif 'vifi'. + * 'msgtype' is the type of DVMRP message received from the neighbor. + * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise. + */ +int update_neighbor(vifi, addr, msgtype) + vifi_t vifi; + u_long addr; + int msgtype; +{ + register struct uvif *v; + register struct listaddr *n; + + v = &uvifs[vifi]; + + /* + * Confirm that 'addr' is a valid neighbor address on vif 'vifi'. + * IT IS ASSUMED that this was preceded by a call to find_vif(), which + * checks that 'addr' is either a valid remote tunnel endpoint or a + * non-broadcast address belonging to a directly-connected subnet. + * Therefore, here we check only that 'addr' is not our own address + * (due to an impostor or erroneous loopback) or an address of the form + * {subnet,0} ("the unknown host"). These checks are not performed in + * find_vif() because those types of address are acceptable for some + * types of IGMP message (such as group membership reports). + */ + if (!(v->uv_flags & VIFF_TUNNEL) && + (addr == v->uv_lcl_addr || + addr == v->uv_subnet )) { + log(LOG_WARNING, 0, + "received DVMRP message from 'the unknown host' or self: %s", + inet_fmt(addr, s1)); + return (FALSE); + } + + /* + * If we have received a route report from a neighbor, and we believed + * that we had no neighbors on this vif, send a full route report to + * all neighbors on the vif. + */ + + if (msgtype == DVMRP_REPORT && v->uv_neighbors == NULL) + report(ALL_ROUTES, vifi, + (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group); + + /* + * Look for addr in list of neighbors; if found, reset its timer. + */ + for (n = v->uv_neighbors; n != NULL; n = n->al_next) { + if (addr == n->al_addr) { + n->al_timer = 0; + break; + } + } + + /* + * If not found, add it to the list. If the neighbor has a lower + * IP address than me, yield querier duties to it. + */ + if (n == NULL) { + n = (struct listaddr *)malloc(sizeof(struct listaddr)); + if (n == NULL) + log(LOG_ERR, 0, "ran out of memory"); /* fatal */ + + n->al_addr = addr; + n->al_timer = 0; + n->al_next = v->uv_neighbors; + v->uv_neighbors = n; + + if (!(v->uv_flags & VIFF_TUNNEL) && + ntohl(addr) < ntohl(v->uv_lcl_addr)) + v->uv_flags &= ~VIFF_QUERIER; + } + + return (TRUE); +} + + +/* + * On every timer interrupt, advance the timer in each neighbor and + * group entry on every vif. + */ +void age_vifs() +{ + register vifi_t vifi; + register struct uvif *v; + register struct listaddr *a, *prev_a, *n; + register u_long addr; + + for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { + + for (prev_a = (struct listaddr *)&(v->uv_neighbors), + a = v->uv_neighbors; + a != NULL; + prev_a = a, a = a->al_next) { + + if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME) + continue; + + /* + * Neighbor has expired; delete it from the neighbor list, + * delete it from the 'dominants' and 'subordinates arrays of + * any route entries and assume querier duties unless there is + * another neighbor with a lower IP address than mine. + */ + addr = a->al_addr; + prev_a->al_next = a->al_next; + free((char *)a); + a = prev_a; + + delete_neighbor_from_routes(addr, vifi); + + if (!(v->uv_flags & VIFF_TUNNEL)) { + v->uv_flags |= VIFF_QUERIER; + for (n = v->uv_neighbors; n != NULL; n = n->al_next) { + if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) { + v->uv_flags &= ~VIFF_QUERIER; + break; + } + } + } + } + + for (prev_a = (struct listaddr *)&(v->uv_groups), + a = v->uv_groups; + a != NULL; + prev_a = a, a = a->al_next) { + + if ((a->al_timer += TIMER_INTERVAL) < GROUP_EXPIRE_TIME) + continue; + + /* + * Group has expired; tell kernel and delete from group list. + */ + k_del_group(vifi, a->al_addr); + + prev_a->al_next = a->al_next; + free((char *)a); + a = prev_a; + } + } +} + + +/* + * Print the contents of the uvifs array on file 'fp'. + */ +void dump_vifs(fp) + FILE *fp; +{ + register vifi_t vifi; + register struct uvif *v; + register struct listaddr *a; + + fprintf(fp, + "\nVirtual Interface Table\n%s", + " Vif Local-Address Metric Thresh Flags\n"); + + for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { + + fprintf(fp, " %2u %-15s %6s: %-15s %4u %7u ", + vifi, + inet_fmt(v->uv_lcl_addr, s1), + (v->uv_flags & VIFF_TUNNEL) ? + "tunnel": + "subnet", + (v->uv_flags & VIFF_TUNNEL) ? + inet_fmt(v->uv_rmt_addr, s2) : + inet_fmts(v->uv_subnet, v->uv_subnetmask, s3), + v->uv_metric, + v->uv_threshold); + + if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down"); + if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled"); + if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier"); + if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt"); + fprintf(fp, "\n"); + + if (v->uv_neighbors != NULL) { + fprintf(fp, " peers : %-15s\n", + inet_fmt(v->uv_neighbors->al_addr, s1)); + for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) { + fprintf(fp, " %-15s\n", + inet_fmt(a->al_addr, s1)); + } + } + + if (v->uv_groups != NULL) { + fprintf(fp, " groups: %-15s\n", + inet_fmt(v->uv_groups->al_addr, s1)); + for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) { + fprintf(fp, " %-15s\n", + inet_fmt(a->al_addr, s1)); + } + } + } + fprintf(fp, "\n"); +} diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h new file mode 100644 index 000000000000..4af87c5ae805 --- /dev/null +++ b/usr.sbin/mrouted/vif.h @@ -0,0 +1,47 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: vif.h,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $ + */ + +/* + * User level Virtual Interface structure + * + * A "virtual interface" is either a physical, multicast-capable interface + * (called a "phyint") or a virtual point-to-point link (called a "tunnel"). + * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.) + */ +struct uvif { + u_short uv_flags; /* VIFF_ flags defined below */ + u_char uv_metric; /* cost of this vif */ + u_char uv_threshold; /* min ttl required to forward on vif */ + u_long uv_lcl_addr; /* local address of this vif */ + u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */ + u_long uv_subnet; /* subnet number (phyints only) */ + u_long uv_subnetmask; /* subnet mask (phyints only) */ + u_long uv_subnetbcast;/* subnet broadcast addr (phyints only) */ + char uv_name[IFNAMSIZ]; /* interface name */ + struct listaddr *uv_groups; /* list of local groups (phyints only) */ + struct listaddr *uv_neighbors; /* list of neighboring routers */ +}; + +#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT) +#define VIFF_DOWN 0x0100 /* kernel state of interface */ +#define VIFF_DISABLED 0x0200 /* administratively disabled */ +#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */ + + +struct listaddr { + struct listaddr *al_next; /* link to next addr, MUST BE FIRST */ + u_long al_addr; /* local group or neighbor address */ + u_long al_timer; /* for timing out group or neighbor */ +}; + + +#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */ diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/mtree/verify.c index d09312622265..c50611de4a4a 100644 --- a/usr.sbin/mtree/verify.c +++ b/usr.sbin/mtree/verify.c @@ -172,10 +172,11 @@ miss(p, tail) (void)printf(" (not created: group not specified)"); else if (!(p->flags & F_MODE)) (void)printf(" (not created: mode not specified)"); - else if (mkdir(path, S_IRWXU)) + else if (mkdir(path, S_IRWXU)) { + create = 1; (void)printf(" (not created: %s)", strerror(errno)); - else { + } else { create = 1; (void)printf(" (created)"); } diff --git a/usr.sbin/named/named.restart b/usr.sbin/named/named.restart index 6159a605cebe..19a2590e1b96 100644 --- a/usr.sbin/named/named.restart +++ b/usr.sbin/named/named.restart @@ -5,5 +5,5 @@ PATH=/bin:/sbin:/usr/sbin:/usr/bin -kill -9 `cat /var/run/named.pid` +kill -TERM `cat /var/run/named.pid` named diff --git a/usr.sbin/pwd_mkdb/Makefile b/usr.sbin/pwd_mkdb/Makefile index 645728b3505c..616f10514dae 100644 --- a/usr.sbin/pwd_mkdb/Makefile +++ b/usr.sbin/pwd_mkdb/Makefile @@ -3,5 +3,8 @@ PROG= pwd_mkdb SRCS= pw_scan.c pwd_mkdb.c MAN8= pwd_mkdb.8 +.if defined (PW_COMPACT) +CFLAGS+=-DPW_COMPACT +.endif .include <bsd.prog.mk> diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8 index 2ab2cee6ca5f..845662dc233c 100644 --- a/usr.sbin/pwd_mkdb/pwd_mkdb.8 +++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8 @@ -99,6 +99,20 @@ The front-ends to and .IR vipw (8), handle the locking necessary to avoid this problem. +.PP +Standard database make routines are slow especially for big passwd +files. Moreover, *pwd.db bases are too big and waste root space. +You can have much faster routines with small *pwd.db, +but loose binary compatibility +with previous versions and with other BSD-like systems. +If you want to setup much faster routines, define +.B PW_COMPACT +envirnoment variable (f.e. 'setenv PW_COMPACT' in csh) and use +.I bootstrappwd +target into /usr/src/Makefile. +If you will want to return this changes back, use the same target +without defining +.BR PW_COMPACT . .SH COMPATIBILITY Previous versions of the system had a program similar to .I pwd_mkdb, diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c index b90daee24884..ffad7ed3158e 100644 --- a/usr.sbin/pwd_mkdb/pwd_mkdb.c +++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c @@ -53,11 +53,42 @@ static char sccsid[] = "@(#)pwd_mkdb.c 5.5 (Berkeley) 5/6/91"; #include <string.h> #include <stdlib.h> +/* #define PW_COMPACT */ +/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */ +#ifdef PW_COMPACT +# define HI_BSIZE 1024 +# define HI_CACHE (512 * 1024) +# define HI_SCACHE (128 * 1024) +#else +# define HI_BSIZE 4096 +# define HI_CACHE (2048 * 1024) +#endif + #define INSECURE 1 #define SECURE 2 #define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) #define PERM_SECURE (S_IRUSR|S_IWUSR) +HASHINFO openinfo = { + HI_BSIZE, /* bsize */ + 32, /* ffactor */ + 256, /* nelem */ + HI_CACHE, /* cachesize */ + NULL, /* hash() */ + 0 /* lorder */ +}; + +#ifdef PW_COMPACT +HASHINFO sopeninfo = { + HI_BSIZE, /* bsize */ + 32, /* ffactor */ + 256, /* nelem */ + HI_SCACHE, /* cachesize */ + NULL, /* hash() */ + 0 /* lorder */ +}; +#endif + char *progname = "pwd_mkdb"; static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; @@ -76,10 +107,14 @@ main(argc, argv) DB *dp, *edp; sigset_t set; DBT data, key; +#ifdef PW_COMPACT + DBT pdata, sdata; +#endif int ch, cnt, tfd; char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; char buf2[MAXPATHLEN]; + umask(022); strcpy(prefix, _PATH_PWD); makeold = 0; while ((ch = getopt(argc, argv, "d:pv")) != EOF) @@ -121,17 +156,21 @@ main(argc, argv) /* Open the temporary insecure password database. */ (void)sprintf(buf, "%s/%s.tmp", prefix, _MP_DB); - dp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, NULL); + dp = dbopen(buf, + O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); if (!dp) error(buf); clean = FILE_INSECURE; +#ifdef PW_COMPACT /* Open the temporary encrypted password database. */ (void)sprintf(buf, "%s/%s.tmp", prefix, _SMP_DB); - edp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, NULL); + edp = dbopen(buf, + O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &sopeninfo); if (!edp) error(buf); clean = FILE_SECURE; +#endif /* * Open file for old password file. Minor trickiness -- don't want to @@ -163,11 +202,19 @@ main(argc, argv) data.data = (u_char *)buf; key.data = (u_char *)tbuf; for (cnt = 1; scan(fp, &pwd); ++cnt) { +#ifdef PW_COMPACT + pdata.data = (u_char *)&cnt; + pdata.size = sizeof(int); + sdata.data = (u_char *)pwd.pw_passwd; + sdata.size = strlen(pwd.pw_passwd) + 1; +#endif #define COMPACT(e) t = e; while (*p++ = *t++); /* Create insecure data. */ p = buf; COMPACT(pwd.pw_name); +#ifndef PW_COMPACT COMPACT("*"); +#endif bcopy((char *)&pwd.pw_uid, p, sizeof(int)); p += sizeof(int); bcopy((char *)&pwd.pw_gid, p, sizeof(int)); @@ -187,7 +234,22 @@ main(argc, argv) len = strlen(pwd.pw_name); bcopy(pwd.pw_name, tbuf + 1, len); key.size = len + 1; +#ifdef PW_COMPACT + if ((dp->put)(dp, &key, &pdata, R_NOOVERWRITE) == -1) +#else + if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) +#endif + error("put"); + + /* Store insecure by uid. */ + tbuf[0] = _PW_KEYBYUID; + bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid)); + key.size = sizeof(pwd.pw_uid) + 1; +#ifdef PW_COMPACT + if ((dp->put)(dp, &key, &pdata, R_NOOVERWRITE) == -1) +#else if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) +#endif error("put"); /* Store insecure by number. */ @@ -197,12 +259,41 @@ main(argc, argv) if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) error("put"); - /* Store insecure by uid. */ - tbuf[0] = _PW_KEYBYUID; - bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid)); - key.size = sizeof(pwd.pw_uid) + 1; - if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) +#ifdef PW_COMPACT + /* Store secure. */ + if ((edp->put)(edp, &key, &sdata, R_NOOVERWRITE) == -1) error("put"); +#endif + + /* Create original format password file entry */ + if (makeold) + (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", + pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, + pwd.pw_dir, pwd.pw_shell); + + } + (void)(dp->close)(dp); +#ifdef PW_COMPACT + (void)(edp->close)(edp); +#endif + + if (makeold) { + (void)fflush(oldfp); + (void)fsync(fileno(oldfp)); + (void)fclose(oldfp); + } + +#ifndef PW_COMPACT + /* Open the temporary encrypted password database. */ + (void)sprintf(buf, "%s/%s.tmp", prefix, _SMP_DB); + edp = dbopen(buf, + O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); + if (!edp) + error(buf); + clean = FILE_SECURE; + + rewind(fp); + for (cnt = 1; scan(fp, &pwd); ++cnt) { /* Create secure data. */ p = buf; @@ -227,35 +318,27 @@ main(argc, argv) len = strlen(pwd.pw_name); bcopy(pwd.pw_name, tbuf + 1, len); key.size = len + 1; - if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) + if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) error("put"); /* Store secure by number. */ tbuf[0] = _PW_KEYBYNUM; bcopy((char *)&cnt, tbuf + 1, sizeof(cnt)); key.size = sizeof(cnt) + 1; - if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) + if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) error("put"); /* Store secure by uid. */ tbuf[0] = _PW_KEYBYUID; bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid)); key.size = sizeof(pwd.pw_uid) + 1; - if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) + if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) error("put"); - /* Create original format password file entry */ - if (makeold) - (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", - pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, - pwd.pw_dir, pwd.pw_shell); } - (void)(dp->close)(dp); + (void)(edp->close)(edp); - if (makeold) { - (void)fsync(oldfp); - (void)fclose(oldfp); - } +#endif /* Set master.passwd permissions, in case caller forgot. */ (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); @@ -284,6 +367,7 @@ main(argc, argv) exit(0); } +int scan(fp, pw) FILE *fp; struct passwd *pw; @@ -310,8 +394,8 @@ scan(fp, pw) (void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt); fmt: errno = EFTYPE; error(pname); - exit(1); } + return(1); } mv(from, to) diff --git a/usr.sbin/routed/Makefile b/usr.sbin/routed/Makefile new file mode 100644 index 000000000000..0fc8bc839cbf --- /dev/null +++ b/usr.sbin/routed/Makefile @@ -0,0 +1,22 @@ +# @(#)Makefile 5.16 (Berkeley) 4/26/91 + +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.8 +SUBDIR= query trace +DPADD= ${LIBUTIL} ${LIBCOMPAT} +LDADD= -lutil + +.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..19807b71db41 --- /dev/null +++ b/usr.sbin/routed/af.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1983 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 5.11 (Berkeley) 2/28/91"; +#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..2d1bf293d365 --- /dev/null +++ b/usr.sbin/routed/af.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1983 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 5.7 (Berkeley) 6/1/90 + */ + +/* + * 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 */ +}; + +struct afswitch afswitch[]; /* table proper */ +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..f4fdf7a68f29 --- /dev/null +++ b/usr.sbin/routed/defs.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1983, 1988 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 5.10 (Berkeley) 2/28/91 + */ + +/* + * 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 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 sndmsg(); +int supply(); +int cleanup(); diff --git a/usr.sbin/routed/if.c b/usr.sbin/routed/if.c new file mode 100644 index 000000000000..4871c9df32aa --- /dev/null +++ b/usr.sbin/routed/if.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1983 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 5.6 (Berkeley) 6/1/90"; +#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..a465ac7637c9 --- /dev/null +++ b/usr.sbin/routed/inet.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 1983 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 5.8 (Berkeley) 6/1/90"; +#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 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..ec8c9d76239b --- /dev/null +++ b/usr.sbin/routed/input.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 1983, 1988 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 5.22 (Berkeley) 6/1/90"; +#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..c67f203e3f8c --- /dev/null +++ b/usr.sbin/routed/interface.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1983 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 5.6 (Berkeley) 6/1/90 + */ + +/* + * 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_KERNELPUN 0x1f /* mask for above */ + +#define IFF_SUBNET 0x1000 /* interface on subnetted network */ +#define IFF_PASSIVE 0x2000 /* can't tell if up/down */ +#define IFF_INTERFACE 0x4000 /* hardware interface */ +#define IFF_REMOTE 0x8000 /* interface isn't on this machine */ + +struct interface *if_ifwithaddr(); +struct interface *if_ifwithdstaddr(); +struct interface *if_ifwithnet(); +struct interface *if_iflookup(); diff --git a/usr.sbin/routed/main.c b/usr.sbin/routed/main.c new file mode 100644 index 000000000000..75ed82f58e56 --- /dev/null +++ b/usr.sbin/routed/main.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 1983, 1988 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 +char copyright[] = +"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 5.23 (Berkeley) 7/1/91"; +#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; + 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) + 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..10c81b1a0ca0 --- /dev/null +++ b/usr.sbin/routed/output.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1983, 1988 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 5.15 (Berkeley) 2/28/91"; +#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/flcopy/pathnames.h b/usr.sbin/routed/pathnames.h index 60b2df28a6b4..54bac2751e52 100644 --- a/usr.sbin/flcopy/pathnames.h +++ b/usr.sbin/routed/pathnames.h @@ -1,5 +1,5 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. +/* + * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +30,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)pathnames.h 5.1 (Berkeley) 4/28/90 + * @(#)pathnames.h 5.3 (Berkeley) 6/1/90 */ -#define _PATH_FLOPPY "/dev/floppy" +#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..03746d30652d --- /dev/null +++ b/usr.sbin/routed/query/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 5.6 (Berkeley) 5/11/90 + +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..32c10c1e1a8b --- /dev/null +++ b/usr.sbin/routed/query/query.c @@ -0,0 +1,289 @@ +/*- + * Copyright (c) 1982, 1986 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 +char copyright[] = +"@(#) Copyright (c) 1982, 1986 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)query.c 5.13 (Berkeley) 4/16/91"; +#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; + int fromlen = sizeof(from), size = 32*1024; + struct timeval shorttime; + + while ((ch = getopt(argc, argv, "n")) != EOF) + switch((char)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; + signal(SIGALRM, timeout); + 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..1d428a7b39b3 --- /dev/null +++ b/usr.sbin/routed/routed.8 @@ -0,0 +1,360 @@ +.\" Copyright (c) 1983, 1991 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 6.6 (Berkeley) 3/16/91 +.\" +.Dd March 16, 1991 +.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 the 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. +Sites needing assistance with such configurations +should contact the Computer Systems Research Group at Berkeley. +.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..de4d58da2f45 --- /dev/null +++ b/usr.sbin/routed/startup.c @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1983, 1988 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 5.19 (Berkeley) 2/28/91"; +#endif /* not lint */ + +/* + * Routing Table Management Daemon + */ +#include "defs.h" +#include <sys/ioctl.h> +#include <net/if.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 */ + +/* + * 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; + int s; + char buf[BUFSIZ], *cp, *cplim; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + struct sockaddr_in *sin; + u_long i; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket: %m"); + close(s); + return; + } + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + syslog(LOG_ERR, "ioctl (get interface configuration)"); + close(s); + return; + } + ifr = ifc.ifc_req; + lookforinterfaces = 0; +#ifdef RTM_ADD +#define max(a, b) (a > b ? a : b) +#define size(p) max((p).sa_len, sizeof(p)) +#else +#define size(p) (sizeof (p)) +#endif + cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ + for (cp = buf; cp < cplim; + cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { + ifr = (struct ifreq *)cp; + bzero((char *)&ifs, sizeof(ifs)); + ifs.int_addr = ifr->ifr_addr; + ifreq = *ifr; + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get interface flags)", + ifr->ifr_name); + continue; + } + ifs.int_flags = (ifreq.ifr_flags & IFF_KERNELPUN) | IFF_INTERFACE; + if ((ifs.int_flags & IFF_UP) == 0 || + ifr->ifr_addr.sa_family == AF_UNSPEC) { + lookforinterfaces = 1; + continue; + } + /* argh, this'll have to change sometime */ + if (ifs.int_addr.sa_family != AF_INET) + continue; + if (ifs.int_flags & IFF_POINTOPOINT) { + if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get dstaddr)", + ifr->ifr_name); + continue; + } + if (ifr->ifr_addr.sa_family == AF_UNSPEC) { + lookforinterfaces = 1; + continue; + } + ifs.int_dstaddr = ifreq.ifr_dstaddr; + } + /* + * 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 (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get broadaddr)", + ifr->ifr_name); + continue; + } +#ifndef sun + ifs.int_broadaddr = ifreq.ifr_broadaddr; +#else + ifs.int_broadaddr = ifreq.ifr_addr; +#endif + } +#ifdef SIOCGIFMETRIC + if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get metric)", + ifr->ifr_name); + ifs.int_metric = 0; + } else + ifs.int_metric = ifreq.ifr_metric; +#else + ifs.int_metric = 0; +#endif + /* + * Use a minimum metric of one; + * treat the interface metric (default 0) + * as an increment to the hop count of one. + */ + ifs.int_metric++; + if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get netmask)", + ifr->ifr_name); + continue; + } + sin = (struct sockaddr_in *)&ifreq.ifr_addr; + 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(sizeof (struct interface)); + if (ifp == 0) { + printf("routed: out of memory\n"); + 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 = malloc(strlen(ifr->ifr_name) + 1); + if (ifp->int_name == 0) { + fprintf(stderr, "routed: ifinit: out of memory\n"); + syslog(LOG_ERR, "routed: ifinit: out of memory\n"); + close(s); + return; + } + strcpy(ifp->int_name, ifr->ifr_name); + *ifnext = ifp; + ifnext = &ifp->int_next; + traceinit(ifp); + addrouteforif(ifp); + } + if (externalinterfaces > 1 && supplier < 0) + supplier = 1; + close(s); +} + +/* + * 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) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); + continue; + } + if (strcmp(qual, "external") == 0) { + /* + * Entries marked external are handled + * by other means, e.g. EGP, + * and are placed in our tables only + * to prevent overriding them + * with something else. + */ + rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); + 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..124e098eb295 --- /dev/null +++ b/usr.sbin/routed/table.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1983 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 5.8 (Berkeley) 6/1/90 + */ + +/* + * 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 { + u_long rtu_hash; + struct sockaddr rtu_dst; + struct sockaddr rtu_router; + short rtu_flags; + short 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_rt /* 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 0x8000 /* 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..17a4fb7b966e --- /dev/null +++ b/usr.sbin/routed/tables.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 1983, 1988 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 5.17 (Berkeley) 6/1/90"; +#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); + /* + * seems like we can't figure out the interface for the + * IP address of the local side of a point to point + * connection, we just don't add that entry in the + * table. (it seems to already be there anyway) + */ + if (rt->rt_ifp == 0) { + syslog(LOG_DEBUG, + "rtadd: can't get interface for %s", + (*afswitch[dst->sa_family].af_format)(dst)); + return; + } + } + 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 (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && + ioctl(s, SIOCADDRT, (char *)&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("SIOCADDRT"); + 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 rtentry 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->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); + /* + * seems like we can't figure out the interface for the + * IP address of the local side of a point to point + * connection, we just don't add that entry in the + * table. (it seems to already be there anyway) + */ + if (rt->rt_ifp == 0) { + struct sockaddr *dst = &(rt->rt_dst); + syslog(LOG_DEBUG, + "rtchange: can't get interface for %s", + (*afswitch[dst->sa_family].af_format)(dst)); + return; + } + } + } + rt->rt_metric = metric; + rt->rt_state |= RTS_CHANGED; + if (newgateway) + TRACE_ACTION("CHANGE TO ", rt); +#ifndef RTM_ADD + if (add && install) + if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) + perror("SIOCADDRT"); + if (delete && install) + if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) + perror("SIOCDELRT"); +#else + if (delete && install) + if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) + perror("SIOCDELRT"); + if (add && install) { + if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) + perror("SIOCADDRT"); + } +#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 (install && + (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && + ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) + perror("SIOCDELRT"); + } + 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 && + ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) + perror("SIOCDELRT"); + } + } + 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; +} + + +/* ffrom /sys/i386/i386/machdep.c */ +/* + * insert an element into a queue + */ +insque(element, head) + register struct rthash *element, *head; +{ + element->rt_forw = head->rt_forw; + head->rt_forw = (struct rt_entry *)element; + element->rt_back = (struct rt_entry *)head; + ((struct rthash *)(element->rt_forw))->rt_back=(struct rt_entry *)element; +} + +/* + * remove an element from a queue + */ +remque(element) + register struct rthash *element; +{ + ((struct rthash *)(element->rt_forw))->rt_back = element->rt_back; + ((struct rthash *)(element->rt_back))->rt_forw = element->rt_forw; + element->rt_back = (struct rt_entry *)0; +} diff --git a/usr.sbin/routed/timer.c b/usr.sbin/routed/timer.c new file mode 100644 index 000000000000..fd0851d20ad9 --- /dev/null +++ b/usr.sbin/routed/timer.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1983, 1988 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 5.10 (Berkeley) 2/28/91"; +#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..6e0b478bc55d --- /dev/null +++ b/usr.sbin/routed/trace.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 1983, 1988 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 5.11 (Berkeley) 2/28/91"; +#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..741de720ce20 --- /dev/null +++ b/usr.sbin/routed/trace.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1983, 1988 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 5.8 (Berkeley) 6/1/90 + */ + +/* + * 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..85e405af1d50 --- /dev/null +++ b/usr.sbin/routed/trace/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 5.1 (Berkeley) 5/11/90 + +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..64d928db8f20 --- /dev/null +++ b/usr.sbin/routed/trace/trace.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 1983, 1988 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 +char copyright[] = +"@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)trace.c 5.9 (Berkeley) 4/16/91"; +#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--; + } +} diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile new file mode 100644 index 000000000000..c0a7a2dc767b --- /dev/null +++ b/usr.sbin/sa/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile,v 1.2 1994/05/18 12:21:31 csgr Exp $ + +PROG= sa +MAN8= sa.8 +SRCS= main.c pdb.c usrdb.c +LDADD= -lutil + +.include <bsd.prog.mk> diff --git a/usr.sbin/sa/extern.h b/usr.sbin/sa/extern.h new file mode 100644 index 000000000000..609752d2d0d2 --- /dev/null +++ b/usr.sbin/sa/extern.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1994 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: extern.h,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $ + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <db.h> + +/* structures */ + +struct cmdinfo { + char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */ + u_long ci_uid; /* user id */ + u_quad_t ci_calls; /* number of calls */ + u_quad_t ci_etime; /* elapsed time */ + u_quad_t ci_utime; /* user time */ + u_quad_t ci_stime; /* system time */ + u_quad_t ci_mem; /* memory use */ + u_quad_t ci_io; /* number of disk i/o ops */ + u_int ci_flags; /* flags; see below */ +}; +#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */ + +struct userinfo { + u_long ui_uid; /* user id; for consistency */ + u_quad_t ui_calls; /* number of invocations */ + u_quad_t ui_utime; /* user time */ + u_quad_t ui_stime; /* system time */ + u_quad_t ui_mem; /* memory use */ + u_quad_t ui_io; /* number of disk i/o ops */ +}; + +/* typedefs */ + +typedef int (*cmpf_t) __P((const DBT *, const DBT *)); + +/* external functions in sa.c */ +int main __P((int, char **)); + +/* external functions in pdb.c */ +int pacct_init __P((void)); +void pacct_destroy __P((void)); +int pacct_add __P((const struct cmdinfo *)); +int pacct_update __P((void)); +void pacct_print __P((void)); + +/* external functions in usrdb.c */ +int usracct_init __P((void)); +void usracct_destroy __P((void)); +int usracct_add __P((const struct cmdinfo *)); +int usracct_update __P((void)); +void usracct_print __P((void)); + +/* variables */ + +extern int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag; +extern int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag; +extern int cutoff; +extern cmpf_t sa_cmp; + +/* some #defines to help with db's stupidity */ + +#define DB_CLOSE(db) \ + ((*(db)->close)(db)) +#define DB_GET(db, key, data, flags) \ + ((*(db)->get)((db), (key), (data), (flags))) +#define DB_PUT(db, key, data, flags) \ + ((*(db)->put)((db), (key), (data), (flags))) +#define DB_SYNC(db, flags) \ + ((*(db)->sync)((db), (flags))) +#define DB_SEQ(db, key, data, flags) \ + ((*(db)->seq)((db), (key), (data), (flags))) diff --git a/usr.sbin/sa/main.c b/usr.sbin/sa/main.c new file mode 100644 index 000000000000..65a0216e928a --- /dev/null +++ b/usr.sbin/sa/main.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 1994 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 copright[] = +"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\ + All rights reserved.\n"; + +static char rcsid[] = "$Id: main.c,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $"; +#endif + +/* + * sa: system accounting + */ + +#include <sys/types.h> +#include <sys/acct.h> +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "extern.h" +#include "pathnames.h" + +static int acct_load __P((char *, int)); +static u_quad_t decode_comp_t __P((comp_t)); +static int cmp_comm __P((const char *, const char *)); +static int cmp_usrsys __P((const DBT *, const DBT *)); +static int cmp_avgusrsys __P((const DBT *, const DBT *)); +static int cmp_dkio __P((const DBT *, const DBT *)); +static int cmp_avgdkio __P((const DBT *, const DBT *)); +static int cmp_cpumem __P((const DBT *, const DBT *)); +static int cmp_avgcpumem __P((const DBT *, const DBT *)); +static int cmp_calls __P((const DBT *, const DBT *)); + +int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag; +int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag; +int cutoff = 1; + +static char *dfltargv[] = { _PATH_ACCT }; +static int dfltargc = (sizeof dfltargv/sizeof(char *)); + +/* default to comparing by sum of user + system time */ +cmpf_t sa_cmp = cmp_usrsys; + +int +main(argc, argv) + int argc; + char **argv; +{ + char ch; + int error; + + while ((ch = getopt(argc, argv, "abcdDfijkKlmnqrstuv:")) != -1) + switch (ch) { + case 'a': + /* print all commands */ + aflag = 1; + break; + case 'b': + /* sort by per-call user/system time average */ + bflag = 1; + sa_cmp = cmp_avgusrsys; + break; + case 'c': + /* print percentage total time */ + cflag = 1; + break; + case 'd': + /* sort by averge number of disk I/O ops */ + dflag = 1; + sa_cmp = cmp_avgdkio; + break; + case 'D': + /* print and sort by total disk I/O ops */ + Dflag = 1; + sa_cmp = cmp_dkio; + break; + case 'f': + /* force no interactive threshold comprison */ + fflag = 1; + break; + case 'i': + /* do not read in summary file */ + iflag = 1; + break; + case 'j': + /* instead of total minutes, give sec/call */ + jflag = 1; + break; + case 'k': + /* sort by cpu-time average memory usage */ + kflag = 1; + sa_cmp = cmp_avgcpumem; + break; + case 'K': + /* print and sort by cpu-storage integral */ + sa_cmp = cmp_cpumem; + Kflag = 1; + break; + case 'l': + /* seperate system and user time */ + lflag = 1; + break; + case 'm': + /* print procs and time per-user */ + mflag = 1; + break; + case 'n': + /* sort by number of calls */ + sa_cmp = cmp_calls; + break; + case 'q': + /* quiet; error messages only */ + qflag = 1; + break; + case 'r': + /* reverse order of sort */ + rflag = 1; + break; + case 's': + /* merge accounting file into summaries */ + sflag = 1; + break; + case 't': + /* report ratio of user and system times */ + tflag = 1; + break; + case 'u': + /* first, print uid and command name */ + uflag = 1; + break; + case 'v': + /* cull junk */ + vflag = 1; + cutoff = atoi(optarg); + break; + case '?': + default: + (void)fprintf(stderr, + "usage: sa [-abcdDfijkKlmnqrstu] [-v cutoff] [file ...]\n"); + exit(1); + } + + argc -= optind; + argv += optind; + + /* various argument checking */ + if (fflag && !vflag) + errx(1, "only one of -f requires -v"); + if (fflag && aflag) + errx(1, "only one of -a and -v may be specified"); + /* XXX need more argument checking */ + + if (!uflag) { + /* initialize tables */ + if ((sflag || (!mflag && !qflag)) && pacct_init() != 0) + errx(1, "process accounting initialization failed"); + if ((sflag || (mflag && !qflag)) && usracct_init() != 0) + errx(1, "user accounting initialization failed"); + } + + if (argc == 0) { + argc = dfltargc; + argv = dfltargv; + } + + /* for each file specified */ + for (; argc > 0; argc--, argv++) { + int fd; + + /* + * load the accounting data from the file. + * if it fails, go on to the next file. + */ + fd = acct_load(argv[0], sflag); + if (fd < 0) + continue; + + if (!uflag && sflag) { +#ifndef DEBUG + sigset_t nmask, omask; + int unmask = 1; + + /* + * block most signals so we aren't interrupted during + * the update. + */ + if (sigfillset(&nmask) == -1) { + warn("sigfillset"); + unmask = 0; + error = 1; + } + if (unmask && + (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) { + warn("couldn't set signal mask "); + unmask = 0; + error = 1; + } +#endif /* DEBUG */ + + /* + * truncate the accounting data file ASAP, to avoid + * losing data. don't worry about errors in updating + * the saved stats; better to underbill than overbill, + * but we want every accounting record intact. + */ + if (ftruncate(fd, 0) == -1) { + warn("couldn't truncate %s", argv); + error = 1; + } + + /* + * update saved user and process accounting data. + * note errors for later. + */ + if (pacct_update() != 0 || usracct_update() != 0) + error = 1; + +#ifndef DEBUG + /* + * restore signals + */ + if (unmask && + (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) { + warn("couldn't restore signal mask"); + error = 1; + } +#endif /* DEBUG */ + } + + /* + * close the opened accounting file + */ + if (close(fd) == -1) { + warn("close %s", argv); + error = 1; + } + } + + if (!uflag && !qflag) { + /* print any results we may have obtained. */ + if (!mflag) + pacct_print(); + else + usracct_print(); + } + + if (!uflag) { + /* finally, deallocate databases */ + if (sflag || (!mflag && !qflag)) + pacct_destroy(); + if (sflag || (mflag && !qflag)) + usracct_destroy(); + } + + exit(error); +} + +static int +acct_load(pn, wr) + char *pn; + int wr; +{ + struct acct ac; + struct cmdinfo ci; + ssize_t rv; + int fd, i; + + /* + * open the file + */ + fd = open(pn, wr ? O_RDWR : O_RDONLY, 0); + if (fd == -1) { + warn("open %s %s", pn, wr ? "for read/write" : "read-only"); + return (-1); + } + + /* + * read all we can; don't stat and open because more processes + * could exit, and we'd miss them + */ + while (1) { + /* get one accounting entry and punt if there's an error */ + rv = read(fd, &ac, sizeof(struct acct)); + if (rv == -1) + warn("error reading %s", pn); + else if (rv > 0 && rv < sizeof(struct acct)) + warnx("short read of accounting data in %s", pn); + if (rv != sizeof(struct acct)) + break; + + /* decode it */ + ci.ci_calls = 1; + for (i = 0; i < sizeof ac.ac_comm && ac.ac_comm[i] != '\0'; + i++) { + char c = ac.ac_comm[i]; + + if (!isascii(c) || iscntrl(c)) { + ci.ci_comm[i] = '?'; + ci.ci_flags |= CI_UNPRINTABLE; + } else + ci.ci_comm[i] = c; + } + if (ac.ac_flag & AFORK) + ci.ci_comm[i++] = '*'; + ci.ci_comm[i++] = '\0'; + ci.ci_etime = decode_comp_t(ac.ac_etime); + ci.ci_utime = decode_comp_t(ac.ac_utime); + ci.ci_stime = decode_comp_t(ac.ac_stime); + ci.ci_uid = ac.ac_uid; + ci.ci_mem = ac.ac_mem; + ci.ci_io = decode_comp_t(ac.ac_io) / AHZ; + + if (!uflag) { + /* and enter it into the usracct and pacct databases */ + if (sflag || (!mflag && !qflag)) + pacct_add(&ci); + if (sflag || (mflag && !qflag)) + usracct_add(&ci); + } else if (!qflag) + printf("%6u %12.2lf cpu %12quk mem %12qu io %s\n", + ci.ci_uid, + (ci.ci_utime + ci.ci_stime) / (double) AHZ, + ci.ci_mem, ci.ci_io, ci.ci_comm); + } + + /* finally, return the file descriptor for possible truncation */ + return (fd); +} + +static u_quad_t +decode_comp_t(comp) + comp_t comp; +{ + u_quad_t rv; + + /* + * for more info on the comp_t format, see: + * /usr/src/sys/kern/kern_acct.c + * /usr/src/sys/sys/acct.h + * /usr/src/usr.bin/lastcomm/lastcomm.c + */ + rv = comp & 0x1fff; /* 13 bit fraction */ + comp >>= 13; /* 3 bit base-8 exponent */ + while (comp--) + rv <<= 3; + + return (rv); +} + +/* sort commands, doing the right thing in terms of reversals */ +static int +cmp_comm(s1, s2) + const char *s1, *s2; +{ + int rv; + + rv = strcmp(s1, s2); + if (rv == 0) + rv = -1; + return (rflag ? rv : -rv); +} + +/* sort by total user and system time */ +static int +cmp_usrsys(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + u_quad_t t1, t2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + t1 = c1->ci_utime + c1->ci_stime; + t2 = c2->ci_utime + c2->ci_stime; + + if (t1 < t2) + return -1; + else if (t1 == t2) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} + +/* sort by average user and system time */ +static int +cmp_avgusrsys(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + double t1, t2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + t1 = c1->ci_utime + c1->ci_stime; + t1 /= (double) (c1->ci_calls ? c1->ci_calls : 1); + + t2 = c2->ci_utime + c2->ci_stime; + t2 /= (double) (c2->ci_calls ? c2->ci_calls : 1); + + if (t1 < t2) + return -1; + else if (t1 == t2) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} + +/* sort by total number of disk I/O operations */ +static int +cmp_dkio(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + if (c1->ci_io < c2->ci_io) + return -1; + else if (c1->ci_io == c2->ci_io) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} + +/* sort by average number of disk I/O operations */ +static int +cmp_avgdkio(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + double n1, n2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + n1 = (double) c1->ci_io / (double) (c1->ci_calls ? c1->ci_calls : 1); + n2 = (double) c2->ci_io / (double) (c2->ci_calls ? c2->ci_calls : 1); + + if (n1 < n2) + return -1; + else if (n1 == n2) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} + +/* sort by the cpu-storage integral */ +static int +cmp_cpumem(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + if (c1->ci_mem < c2->ci_mem) + return -1; + else if (c1->ci_mem == c2->ci_mem) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} + +/* sort by the cpu-time average memory usage */ +static int +cmp_avgcpumem(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + u_quad_t t1, t2; + double n1, n2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + t1 = c1->ci_utime + c1->ci_stime; + t2 = c2->ci_utime + c2->ci_stime; + + n1 = (double) c1->ci_mem / (double) (t1 ? t1 : 1); + n2 = (double) c2->ci_mem / (double) (t2 ? t2 : 1); + + if (n1 < n2) + return -1; + else if (n1 == n2) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} + +/* sort by the number of invocations */ +static int +cmp_calls(d1, d2) + const DBT *d1, *d2; +{ + struct cmdinfo *c1, *c2; + + c1 = (struct cmdinfo *) d1->data; + c2 = (struct cmdinfo *) d2->data; + + if (c1->ci_calls < c2->ci_calls) + return -1; + else if (c1->ci_calls == c2->ci_calls) + return (cmp_comm(c1->ci_comm, c2->ci_comm)); + else + return 1; +} diff --git a/usr.sbin/sa/pathnames.h b/usr.sbin/sa/pathnames.h new file mode 100644 index 000000000000..3ed865785492 --- /dev/null +++ b/usr.sbin/sa/pathnames.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1994 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: pathnames.h,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $ + */ + +#define _PATH_ACCT "/var/account/acct" +#define _PATH_SAVACCT "/var/account/savacct" +#define _PATH_USRACCT "/var/account/usracct" diff --git a/usr.sbin/sa/pdb.c b/usr.sbin/sa/pdb.c new file mode 100644 index 000000000000..25b0168ffa28 --- /dev/null +++ b/usr.sbin/sa/pdb.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1994 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 rcsid[] = "$Id: pdb.c,v 1.1.1.1 1994/05/18 08:04:11 csgr Exp $"; +#endif + +#include <sys/types.h> +#include <sys/acct.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include "extern.h" +#include "pathnames.h" + +static int check_junk __P((struct cmdinfo *)); +static void add_ci __P((const struct cmdinfo *, struct cmdinfo *)); +static void print_ci __P((const struct cmdinfo *, const struct cmdinfo *)); + +static DB *pacct_db; + +int +pacct_init() +{ + DB *saved_pacct_db; + int error; + + pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL); + if (pacct_db == NULL) + return (-1); + + error = 0; + if (!iflag) { + DBT key, data; + int serr, nerr; + + saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE, + NULL); + if (saved_pacct_db == NULL) { + error = errno == ENOENT ? 0 : -1; + if (error) + warn("retrieving process accounting summary"); + goto out; + } + + serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST); + if (serr < 0) { + warn("retrieving process accounting summary"); + error = -1; + goto closeout; + } + while (serr == 0) { + nerr = DB_PUT(pacct_db, &key, &data, 0); + if (nerr < 0) { + warn("initializing process accounting stats"); + error = -1; + break; + } + + serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT); + if (serr < 0) { + warn("retrieving process accounting summary"); + error = -1; + break; + } + } + +closeout: if (DB_CLOSE(saved_pacct_db) < 0) { + warn("closing process accounting summary"); + error = -1; + } + } + +out: if (error != 0) + pacct_destroy(); + return (error); +} + +void +pacct_destroy() +{ + if (DB_CLOSE(pacct_db) < 0) + warn("destroying process accounting stats"); +} + +int +pacct_add(ci) + const struct cmdinfo *ci; +{ + DBT key, data; + struct cmdinfo newci; + char keydata[sizeof ci->ci_comm]; + int rv; + + bcopy(ci->ci_comm, &keydata, sizeof keydata); + key.data = &keydata; + key.size = strlen(keydata); + + rv = DB_GET(pacct_db, &key, &data, 0); + if (rv < 0) { + warn("get key %s from process accounting stats", ci->ci_comm); + return (-1); + } else if (rv == 0) { /* it's there; copy whole thing */ + /* XXX compare size if paranoid */ + /* add the old data to the new data */ + bcopy(data.data, &newci, data.size); + } else { /* it's not there; zero it and copy the key */ + bzero(&newci, sizeof newci); + bcopy(key.data, newci.ci_comm, key.size); + } + + add_ci(ci, &newci); + + data.data = &newci; + data.size = sizeof newci; + rv = DB_PUT(pacct_db, &key, &data, 0); + if (rv < 0) { + warn("add key %s to process accounting stats", ci->ci_comm); + return (-1); + } else if (rv == 1) { + warnx("duplicate key %s in process accounting stats", + ci->ci_comm); + return (-1); + } + + return (0); +} + +int +pacct_update() +{ + DB *saved_pacct_db; + DBT key, data; + int error, serr, nerr; + + saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, + DB_BTREE, NULL); + if (saved_pacct_db == NULL) { + warn("creating process accounting summary"); + return (-1); + } + + error = 0; + + serr = DB_SEQ(pacct_db, &key, &data, R_FIRST); + if (serr < 0) { + warn("retrieving process accounting stats"); + error = -1; + } + while (serr == 0) { + nerr = DB_PUT(saved_pacct_db, &key, &data, 0); + if (nerr < 0) { + warn("saving process accounting summary"); + error = -1; + break; + } + + serr = DB_SEQ(pacct_db, &key, &data, R_NEXT); + if (serr < 0) { + warn("retrieving process accounting stats"); + error = -1; + break; + } + } + + if (DB_SYNC(saved_pacct_db, 0) < 0) { + warn("syncing process accounting summary"); + error = -1; + } + if (DB_CLOSE(saved_pacct_db) < 0) { + warn("closing process accounting summary"); + error = -1; + } + return error; +} + +void +pacct_print() +{ + BTREEINFO bti; + DBT key, data, ndata; + DB *output_pacct_db; + struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk; + int rv; + + bzero(&ci_total, sizeof ci_total); + strcpy(ci_total.ci_comm, ""); + bzero(&ci_other, sizeof ci_other); + strcpy(ci_other.ci_comm, "***other"); + bzero(&ci_junk, sizeof ci_junk); + strcpy(ci_junk.ci_comm, "**junk**"); + + /* + * Retrieve them into new DB, sorted by appropriate key. + * At the same time, cull 'other' and 'junk' + */ + bzero(&bti, sizeof bti); + bti.compare = sa_cmp; + output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); + if (output_pacct_db == NULL) { + warn("couldn't sort process accounting stats"); + return; + } + + ndata.data = NULL; + ndata.size = 0; + rv = DB_SEQ(pacct_db, &key, &data, R_FIRST); + if (rv < 0) + warn("retrieving process accounting stats"); + while (rv == 0) { + cip = (struct cmdinfo *) data.data; + bcopy(cip, &ci, sizeof ci); + + /* add to total */ + add_ci(&ci, &ci_total); + + if (vflag && ci.ci_calls <= cutoff && + (fflag || check_junk(&ci))) { + /* put it into **junk** */ + add_ci(&ci, &ci_junk); + goto next; + } + if (!aflag && + ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) { + /* put into ***other */ + add_ci(&ci, &ci_other); + goto next; + } + rv = DB_PUT(output_pacct_db, &data, &ndata, 0); + if (rv < 0) + warn("sorting process accounting stats"); + +next: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT); + if (rv < 0) + warn("retrieving process accounting stats"); + } + + /* insert **junk** and ***other */ + if (ci_junk.ci_calls != 0) { + data.data = &ci_junk; + data.size = sizeof ci_junk; + rv = DB_PUT(output_pacct_db, &data, &ndata, 0); + if (rv < 0) + warn("sorting process accounting stats"); + } + if (ci_other.ci_calls != 0) { + data.data = &ci_other; + data.size = sizeof ci_other; + rv = DB_PUT(output_pacct_db, &data, &ndata, 0); + if (rv < 0) + warn("sorting process accounting stats"); + } + + /* print out the total */ + print_ci(&ci_total, &ci_total); + + /* print out; if reversed, print first (smallest) first */ + rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST); + if (rv < 0) + warn("retrieving process accounting report"); + while (rv == 0) { + cip = (struct cmdinfo *) data.data; + bcopy(cip, &ci, sizeof ci); + + print_ci(&ci, &ci_total); + + rv = DB_SEQ(output_pacct_db, &data, &ndata, + rflag ? R_NEXT : R_PREV); + if (rv < 0) + warn("retrieving process accounting report"); + } + DB_CLOSE(output_pacct_db); +} + +static int +check_junk(cip) + struct cmdinfo *cip; +{ + char *cp; + size_t len; + + fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls); + cp = fgetln(stdin, &len); + + return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0; +} + +static void +add_ci(fromcip, tocip) + const struct cmdinfo *fromcip; + struct cmdinfo *tocip; +{ + tocip->ci_calls += fromcip->ci_calls; + tocip->ci_etime += fromcip->ci_etime; + tocip->ci_utime += fromcip->ci_utime; + tocip->ci_stime += fromcip->ci_stime; + tocip->ci_mem += fromcip->ci_mem; + tocip->ci_io += fromcip->ci_io; +} + +static void +print_ci(cip, totalcip) + const struct cmdinfo *cip, *totalcip; +{ + double t, c; + int uflow; + + c = cip->ci_calls ? cip->ci_calls : 1; + t = (cip->ci_utime + cip->ci_stime) / (double) AHZ; + if (t < 0.01) { + t = 0.01; + uflow = 1; + } else + uflow = 0; + + printf("%8qu ", cip->ci_calls); + if (cflag) { + if (cip != totalcip) + printf(" %4.2f%% ", + cip->ci_calls / (double) totalcip->ci_calls); + else + printf(" %4s ", ""); + } + + if (jflag) + printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c)); + else + printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ)); + if (cflag) { + if (cip != totalcip) + printf(" %4.2f%% ", + cip->ci_etime / (double) totalcip->ci_etime); + else + printf(" %4s ", ""); + } + + if (!lflag) { + if (jflag) + printf("%11.2fcp ", t / (double) cip->ci_calls); + else + printf("%11.2fcp ", t / 60.0); + if (cflag) { + if (cip != totalcip) + printf(" %4.2f%% ", + (cip->ci_utime + cip->ci_stime) / (double) + (totalcip->ci_utime + totalcip->ci_stime)); + else + printf(" %4s ", ""); + } + } else { + if (jflag) + printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c)); + else + printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ)); + if (cflag) { + if (cip != totalcip) + printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime); + else + printf(" %4s ", ""); + } + if (jflag) + printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c)); + else + printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ)); + if (cflag) { + if (cip != totalcip) + printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime); + else + printf(" %4s ", ""); + } + } + + if (tflag) + if (!uflow) + printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime)); + else + printf("%8 ", "*ignore*"); + + if (Dflag) + printf("%10qutio ", cip->ci_io); + else + printf("%8.0favio ", cip->ci_io / c); + + if (Kflag) + printf("%10quk*sec ", cip->ci_mem); + else + printf("%8.0fk ", cip->ci_mem / t); + + printf(" %s\n", cip->ci_comm); +} diff --git a/usr.sbin/sa/sa.8 b/usr.sbin/sa/sa.8 new file mode 100644 index 000000000000..339ab55d29e1 --- /dev/null +++ b/usr.sbin/sa/sa.8 @@ -0,0 +1,246 @@ +.\" +.\" Copyright (c) 1994 Christopher G. Demetriou +.\" 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 Christopher G. Demetriou. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +.\" +.\" $Id: sa.8,v 1.1.1.1 1994/05/18 08:04:11 csgr Exp $ +.\" +.Dd February 25, 1994 +.Dt SA 8 +.Os NetBSD 0.9a +.Sh NAME +.Nm sa +.Nd print system accounting statistics +.Sh SYNOPSIS +.Nm sa +.Op Fl abcdDfijkKlmnqrstu +.Op Fl v Ar cutoff +.Op Ar +.Sh DESCRIPTION +The +.Nm sa +utility reports on, cleans up, +and generally maintains system +accounting files. +.Pp +.Nm Sa +is able to condense the the information in +.Pa /var/account/acct +into the summary files +.Pa /var/account/savacct +and +.Pa /var/account/usracct , +which contain system statistics according +to command name and login id, respectively. +This condensation is desirable because on a +large system, +.Pa /var/account/acct +can grow by hundreds of blocks per day. +The summary files are normally read before +the accounting file, so that reports include +all available information. +.Pp +If file names are supplied, they are read instead of +.Pa /var/account/account . +After each file is read, if the summary +files are being updated, an updated summary will +be saved to disk. Only one report is printed, +after the last file is processed. +.Pp +The labels used in the output indicate the following, except +where otherwise specified by individual options: +.Bl -tag -width k*sec +.It Dv avio +Average number of I/O operations per execution +.It Dv cp +Sum of user and system time, in minutes +.It Dv cpu +Same as +.Dv cp +.It Dv k +CPU-time averaged core usage, in 1k units +.It Dv k*sec +CPU storage integral, in 1k-core seconds +.It Dv re +Real time, in minutes +.It Dv s +System time, in minutes +.It Dv tio +Total number of I/O operations +.It Dv u +User time, in minutes +.El +.Pp +The options to +.Nm sa +are: +.Bl -tag -width Ds +.It Fl a +List all command names, including those containing unprintable +characters and those used only once. By default, +.Nm sa +places all names containing unprintable characters and +those used only once under the name ``***other''. +.It Fl b +If printing command statistics, sort output by the sum of user and system +time divided by number of calls. +.It Fl c +In addition to the number of calls and the user, system and real times +for each command, print their percentage of the total over all commands. +.It Fl d +If printing command statistics, sort by the average number of disk +I/O operations. If printing user statistics, print the average number of +disk I/O operations per user. +.It Fl D +If printing command statistics, sort and print by the total number +of disk I/O operations. +.It Fl f +Force no interactive threshold comparison with the +.Fl v +option. +.It Fl i +Do not read in the summary files. +.It Fl j +Instead of the total minutes per category, give seconds per call. +.It Fl k +If printing command statistics, sort by the cpu-time average memory +usage. If printing user statistics, print the cpu-time average +memory usage. +.It Fl K +If printing command statistics, print and sort by the cpu-storage integral. +.It Fl l +Separate system and user time; normally they are combined. +.It Fl m +Print per-user statistics rather than per-command statistics. +.It Fl n +Sort by number of calls. +.It Fl q +Create no output other than error messages. +.It Fl r +Reverse order of sort. +.It Fl s +Truncate the accounting files when done and merge their data +into the summary files. +.It Fl t +For each command, report the ratio of real time to the sum +of user and system cpu times. +If the cpu time is too small to report, ``*ignore*'' appears in +this field. +.It Fl u +Superseding all other flags, for each entry +in the accounting file, print the user ID, total seconds of cpu usage, +total memory usage, number of I/O operations performed, and +command name. +.It Fl v Ar cutoff +For each command used +.Ar cutoff +times or fewer, print the command name and await a reply +from the terminal. If the reply begins with ``y'', add +the command to the category ``**junk**''. This flag is +used to strip garbage from the report. +.El +.Pp +By default, per-command statistics will be printed. The number of +calls, the total elapsed time in minutes, total cpu and user time +in minutes, average number of I/O operations, and CPU-time +averaged core usage will be printed. If the +.Fl m +option is specified, per-user statistics will be printed, including +the user name, the number of commands invoked, total cpu time used +(in minutes), total number of I/O operations, and CPU storage integral +for each user. If the +.Fl u +option is specified, the uid, user and system time (in seconds), +CPU storage integral, I/O usage, and command name will be printed +for each entry in the accounting data file. +.Pp +If the +.Fl u +flag is specified, all flags other than +.Fl q +are ignored. If the +.Fl m +flag is specified, only the +.Fl b , +.Fl d , +.Fl i , +.Fl k , +.Fl q , +and +.Fl s +flags are honored. +.Pp +The +.Nm sa +utility exits 0 on success, and >0 if an error occurs. +.Sh FILES +.Bl -tag -width /var/account/usracct -compact +.It Pa /var/account/acct +raw accounting data file +.It Pa /var/account/savacct +per-command accounting summary database +.It Pa /var/account/usracct +per-user accounting summary database +.El +.Sh SEE ALSO +.Xr ac 8 , +.Xr acct 5 , +.Xr accton 8 , +.Xr lastcomm 1 +.Sh BUGS +The number of options to this program is absurd, especially considering +that there's not much logic behind their lettering. +.Pp +The field labels should be more consistent. +.Pp +NetBSD's VM system does not record the CPU storage integral. +.Sh CAVEATS +While the behavior of the options in this version of +.Nm sa +was modeled after the original version, there are some intentional +differences and undoubtedly some unintentional ones as well. In +particular, the +.Fl q +option has been added, and the +.Fl m +option now understands more options than it used to. +.Pp +The formats of the summary files created by this version of +.Nm sa +are very different than the those used by the original version. +This is not considered a problem, however, because the accounting record +format has changed as well (since user ids are now 32 bits). +.Sh HISTORY +.Nm Sa +was written for +.Nx 0.9a +from the specification provided by various systems' manual pages. +Its date of origin is unknown to the author. +.Sh AUTHOR +.Bl -tag +Chris G. Demetriou, cgd@postgres.berkeley.edu +.El diff --git a/usr.sbin/sa/usrdb.c b/usr.sbin/sa/usrdb.c new file mode 100644 index 000000000000..2e004731c1fe --- /dev/null +++ b/usr.sbin/sa/usrdb.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1994 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 rcsid[] = "$Id: usrdb.c,v 1.2 1994/05/18 12:21:33 csgr Exp $"; +#endif + +#include <sys/types.h> +#include <sys/acct.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include "extern.h" +#include "pathnames.h" + +static int uid_compare __P((const DBT *, const DBT *)); + +static DB *usracct_db; + +int +usracct_init() +{ + DB *saved_usracct_db; + BTREEINFO bti; + int error; + + bzero(&bti, sizeof bti); + bti.compare = uid_compare; + + usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); + if (usracct_db == NULL) + return (-1); + + error = 0; + if (!iflag) { + DBT key, data; + int serr, nerr; + + saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, + &bti); + if (saved_usracct_db == NULL) { + error = (errno == ENOENT) ? 0 : -1; + if (error) + warn("retrieving user accounting summary"); + goto out; + } + + serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); + if (serr < 0) { + warn("retrieving user accounting summary"); + error = -1; + goto closeout; + } + while (serr == 0) { + nerr = DB_PUT(usracct_db, &key, &data, 0); + if (nerr < 0) { + warn("initializing user accounting stats"); + error = -1; + break; + } + + serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); + if (serr < 0) { + warn("retrieving user accounting summary"); + error = -1; + break; + } + } + +closeout: + if (DB_CLOSE(saved_usracct_db) < 0) { + warn("closing user accounting summary"); + error = -1; + } + } + +out: + if (error != 0) + usracct_destroy(); + return (error); +} + +void +usracct_destroy() +{ + if (DB_CLOSE(usracct_db) < 0) + warn("destroying user accounting stats"); +} + +int +usracct_add(ci) + const struct cmdinfo *ci; +{ + DBT key, data; + struct userinfo newui; + u_long uid; + int rv; + + uid = ci->ci_uid; + key.data = &uid; + key.size = sizeof uid; + + rv = DB_GET(usracct_db, &key, &data, 0); + if (rv < 0) { + warn("get key %d from user accounting stats", uid); + return (-1); + } else if (rv == 0) { /* it's there; copy whole thing */ + /* add the old data to the new data */ + bcopy(data.data, &newui, data.size); + if (newui.ui_uid != uid) { + warnx("key %d != expected record number %d", + newui.ui_uid, uid); + warnx("inconsistent user accounting stats"); + return (-1); + } + } else { /* it's not there; zero it and copy the key */ + bzero(&newui, sizeof newui); + newui.ui_uid = ci->ci_uid; + } + + newui.ui_calls += ci->ci_calls; + newui.ui_utime += ci->ci_utime; + newui.ui_stime += ci->ci_stime; + newui.ui_mem += ci->ci_mem; + newui.ui_io += ci->ci_io; + + data.data = &newui; + data.size = sizeof newui; + rv = DB_PUT(usracct_db, &key, &data, 0); + if (rv < 0) { + warn("add key %d to user accounting stats", uid); + return (-1); + } else if (rv != 0) { + warnx("DB_PUT returned 1"); + return (-1); + } + + return (0); +} + +int +usracct_update() +{ + DB *saved_usracct_db; + DBT key, data; + BTREEINFO bti; + u_long uid; + int error, serr, nerr; + + bzero(&bti, sizeof bti); + bti.compare = uid_compare; + + saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, + DB_BTREE, &bti); + if (saved_usracct_db == NULL) { + warn("creating user accounting summary"); + return (-1); + } + + error = 0; + + serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); + if (serr < 0) { + warn("retrieving user accounting stats"); + error = -1; + } + while (serr == 0) { + nerr = DB_PUT(saved_usracct_db, &key, &data, 0); + if (nerr < 0) { + warn("saving user accounting summary"); + error = -1; + break; + } + + serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); + if (serr < 0) { + warn("retrieving user accounting stats"); + error = -1; + break; + } + } + + if (DB_SYNC(saved_usracct_db, 0) < 0) { + warn("syncing process accounting summary"); + error = -1; + } +out: + if (DB_CLOSE(saved_usracct_db) < 0) { + warn("closing process accounting summary"); + error = -1; + } + return error; +} + +void +usracct_print() +{ + DBT key, data; + struct userinfo *ui; + double t; + int rv; + + rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); + if (rv < 0) + warn("retrieving user accounting stats"); + + while (rv == 0) { + ui = (struct userinfo *) data.data; + + printf("%-8s %9qu ", + user_from_uid(ui->ui_uid, 0), ui->ui_calls); + + t = (double) (ui->ui_utime + ui->ui_stime) / + (double) AHZ; + if (t < 0.0001) /* kill divide by zero */ + t = 0.0001; + + printf("%12.2lf%s ", t / 60.0, "cpu"); + + /* ui->ui_calls is always != 0 */ + if (dflag) + printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio"); + else + printf("%12qu%s", ui->ui_io, "tio"); + + /* t is always >= 0.0001; see above */ + if (kflag) + printf("%12qu%s", ui->ui_mem / t, "k"); + else + printf("%12qu%s", ui->ui_mem, "k*sec"); + + printf("\n"); + + rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); + if (rv < 0) + warn("retrieving user accounting stats"); + } +} + +static int +uid_compare(k1, k2) + const DBT *k1, *k2; +{ + u_long d1, d2; + + bcopy(k1->data, &d1, sizeof d1); + bcopy(k2->data, &d2, sizeof d2); + + if (d1 < d2) + return -1; + else if (d1 == d2) + return 0; + else + return 1; +} diff --git a/usr.sbin/sendmail/cf/README b/usr.sbin/sendmail/cf/README index 53bc084bb88e..c026b141f242 100644 --- a/usr.sbin/sendmail/cf/README +++ b/usr.sbin/sendmail/cf/README @@ -813,7 +813,7 @@ Sam Leffler's FlexFAX software is still in beta test -- but he expects a public version out "later this week" [as of 3/1/93]. The following blurb is direct from Sam: - $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/cf/README,v 1.7.2.1 1994/04/18 03:51:03 rgrimes Exp $ + $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/cf/README,v 1.8 1994/03/19 07:35:36 alm Exp $ How To Obtain This Software (in case all you get is this file) -------------------------------------------------------------- diff --git a/usr.sbin/sendmail/contrib/expn.pl b/usr.sbin/sendmail/contrib/expn.pl index 15d287b5c650..b202fd738482 100644 --- a/usr.sbin/sendmail/contrib/expn.pl +++ b/usr.sbin/sendmail/contrib/expn.pl @@ -14,7 +14,7 @@ $sockaddr = 'S n a4 x8'; # system requirements: # must have 'nslookup' and 'hostname' programs. -# $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/contrib/expn.pl,v 1.1.2.1 1994/04/18 03:52:18 rgrimes Exp $ +# $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/contrib/expn.pl,v 1.2 1994/03/19 07:36:03 alm Exp $ # TODO: # less magic should apply to command-line addresses diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c index 1a9646365b88..8fef644fc7a9 100644 --- a/usr.sbin/sendmail/src/conf.c +++ b/usr.sbin/sendmail/src/conf.c @@ -913,7 +913,7 @@ getla() /* Non Apollo stuff removed by Don Lewis 11/15/93 */ #ifndef lint -static char rcsid[] = "@(#)$Id: conf.c,v 1.5.2.1 1994/04/18 03:53:45 rgrimes Exp $"; +static char rcsid[] = "@(#)$Id: conf.c,v 1.6 1994/03/19 07:36:47 alm Exp $"; #endif /* !lint */ #ifdef apollo diff --git a/usr.sbin/sliplogin/slip.hosts b/usr.sbin/sliplogin/slip.hosts index 00c01e6e58da..16d22fbd43e0 100644 --- a/usr.sbin/sliplogin/slip.hosts +++ b/usr.sbin/sliplogin/slip.hosts @@ -1,6 +1,6 @@ # # login local-addr remote-addr mask opt1 opt2 -# (normal,compress,noicmp) +# (normal,compressautocomp,noicmp) # Shavoc okeeffe havoc 0xffffff00 normal Soxford okeeffe oxford-gw 0xffffff00 compress diff --git a/usr.sbin/sliplogin/sliplogin.c b/usr.sbin/sliplogin/sliplogin.c index a4cf21491733..3ca006cd847e 100644 --- a/usr.sbin/sliplogin/sliplogin.c +++ b/usr.sbin/sliplogin/sliplogin.c @@ -280,7 +280,7 @@ main(argc, argv) #ifdef POSIX if (fork() > 0) exit(0); - if (setsid() != 0) + if (setsid() == -1) perror("setsid"); #else if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { @@ -318,6 +318,11 @@ main(argc, argv) } findid(name); } + if (!isatty(0)) { + (void) fprintf(stderr, "access denied - stdin is not a tty\n"); + syslog(LOG_ERR, "access denied - stdin is not a tty\n"); + exit(1); + } (void) fchmod(0, 0600); (void) fprintf(stderr, "starting slip login for %s\n", loginname); #ifdef POSIX diff --git a/usr.sbin/slstat/Makefile b/usr.sbin/slstat/Makefile new file mode 100644 index 000000000000..21309a612b45 --- /dev/null +++ b/usr.sbin/slstat/Makefile @@ -0,0 +1,11 @@ +# from: @(#)Makefile 5.6 (Berkeley) 4/23/91 +# $Id: Makefile,v 1.1.1.1 1994/06/17 06:42:36 rich Exp $ + +PROG= slstat +MAN8= slstat.8 +DPADD= ${LIBUTIL} +LDADD= -lutil +BINGRP= kmem +BINMODE=2555 + +.include <bsd.prog.mk> diff --git a/usr.sbin/slstat/slstat.8 b/usr.sbin/slstat/slstat.8 new file mode 100644 index 000000000000..0194cbf80e95 --- /dev/null +++ b/usr.sbin/slstat/slstat.8 @@ -0,0 +1,141 @@ +.\" Copyright (c) 1986 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. +.\" +.\" @(#)slstat.8 6.8 (Berkeley) 6/20/91 +.\" +.TH SLSTAT 1 "June 20, 1991" +.UC 4 +.SH NAME +slstat \- report serial line IP statistics +.SH SYNOPSIS +.nf +.ft B +slstat [ \-i interval ] [ \-v ] [ \-r ] [ unit ] [ system ] [ core ] +.ft R +.fi +.SH DESCRIPTION +.I Slstat +reports certain kernel statistics kept about serial line internet +protocol traffic. +.PP +The options are as follows: +.TP +\-i +Repeat the display indefinitely every +.I interval +seconds. +If no +.I interval +is specified, the default is 5 seconds. +.TP +\-v +Verbose display of extra fields of information. +.TP +\-r +Display all values in rate per second that ammount per interval. +.TP +unit +is a single digit specifying the slip interface. The default unit is +.I 0 +for interface +.I sl0. +.TP +system +Extract the name list from the specified system instead of the default, /386bsd. +.TP +core +Extract values associated with the name list from the specified +core instead of the default, /dev/kmem. +.PP +By default, +.I vmstat +displays the following information: +.PP +.TP +in +bytes received +.TP +out +bytes sent +.TP +pack +packets received or sent +.TP +comp +compressed packets received or sent +.TP +uncomp +uncompressed packets received or sent +.TP +unknwn +inbound packets of unknown type +.TP +toss +inbound packets tossed because of error +.TP +other +all other inbound or outbound ip packets +.TP +err +input or output errors +.TP +search +searches for connection state +.TP +miss +times we could not find a connectoin state +.TP +coll +collisions with end of clists. +If you get many collisions (more than one or two +a day) you probably do not have enough clists +and you should increase "nclist" in param.c. +.SH EXAMPLES +The command ``slstat -i 5'' will print what the system is doing every five +seconds. +.SH FILES +.ta \w'/dev/kmem 'u +/386bsd default kernel namelist +.br +/dev/kmem default memory file +.SH SEE ALSO +.IR fstat (1), +.IR netstat (1), +.IR nfsstat (1), +.IR ps (1), +.IR systat (1), +.IR iostat (8), +.IR pstat (8) +.sp +The sections starting with ``Interpreting system activity'' in +.IR "Installing and Operating 4.3BSD" . +.SH BUGS + diff --git a/usr.sbin/slstat/slstat.c b/usr.sbin/slstat/slstat.c new file mode 100644 index 000000000000..ddcee8b10f3e --- /dev/null +++ b/usr.sbin/slstat/slstat.c @@ -0,0 +1,287 @@ +/* + * print serial line IP statistics: + * slstat [-i interval] [-v] [interface] [system] [core] + * + * Copyright (c) 1989, 1990, 1991, 1992 Regents of the University of + * California. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#ifndef lint +static char rcsid[] = "$Id: slstat.c,v 1.1.1.1 1994/06/17 06:42:39 rich Exp $"; +#endif + +#include <stdio.h> +#include <paths.h> +#include <nlist.h> +#include <kvm.h> + +#define INET + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <errno.h> +#include <signal.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +#include <net/slcompress.h> +#include <net/if_slvar.h> + +struct nlist nl[] = { +#define N_SOFTC 0 + { "_sl_softc" }, + "", +}; + +char *system = _PATH_UNIX; +char *kmemf = NULL; + +int kflag; +int rflag; +int vflag; +unsigned interval = 5; +int unit; + +extern char *malloc(); +extern off_t lseek(); + +main(argc, argv) + int argc; + char *argv[]; +{ + int c; + --argc; ++argv; + while (argc > 0) { + if (strcmp(argv[0], "-v") == 0) { + ++vflag; + ++argv, --argc; + continue; + } + if (strcmp(argv[0], "-r") == 0) { + ++rflag; + ++argv, --argc; + continue; + } + if (strcmp(argv[0], "-i") == 0 && argv[1] && + isdigit(argv[1][0])) { + interval = atoi(argv[1]); + if (interval <= 0) + usage(); + ++argv, --argc; + ++argv, --argc; + continue; + } + if (isdigit(argv[0][0])) { + unit = atoi(argv[0]); + if (unit < 0) + usage(); + ++argv, --argc; + continue; + } + if (kflag) + usage(); + + system = *argv; + ++argv, --argc; + if (argc > 0) { + kmemf = *argv++; + --argc; + kflag++; + } + } + if (kvm_openfiles(system, kmemf, NULL) < 0) { + (void)fprintf(stderr, + "slstat: kvm_openfiles(%s,%s,0): %s\n", + system, kmemf, kvm_geterr()); + exit(1); + } + if ((c = kvm_nlist(nl)) != 0) { + if (c > 0) { + (void)fprintf(stderr, + "slstat: undefined symbols in %s:", system); + for (c = 0; c < sizeof(nl)/sizeof(nl[0]); c++) + if (nl[c].n_type == 0) + fprintf(stderr, " %s", nl[c].n_name); + (void)fputc('\n', stderr); + } else + (void)fprintf(stderr, "slstat: kvm_nlist: %s\n", + kvm_geterr()); + exit(1); + } + intpr(); + exit(0); +} + +#define V(offset) ((line % 20)? ((sc->offset - osc->offset) / (rflag ? interval : 1)) : sc->offset) +#define AMT (sizeof(*sc) - 2 * sizeof(sc->sc_comp.tstate)) + +usage() +{ + static char umsg[] = + "usage: slstat [-i interval] [-v] [unit] [system] [core]\n"; + + fprintf(stderr, umsg); + exit(1); +} + +u_char signalled; /* set if alarm goes off "early" */ + +/* + * Print a running summary of interface statistics. + * Repeat display every interval seconds, showing statistics + * collected over that interval. Assumes that interval is non-zero. + * First line printed at top of screen is always cumulative. + */ +intpr() +{ + register int line = 0; + int oldmask; + void catchalarm(); + struct sl_softc *sc, *osc; + off_t addr; + + addr = nl[N_SOFTC].n_value + unit * sizeof(struct sl_softc); + sc = (struct sl_softc *)malloc(AMT); + osc = (struct sl_softc *)malloc(AMT); + bzero((char *)osc, AMT); + + while (1) { + if (kread(addr, (char *)sc, AMT) < 0) + perror("kmem read"); + (void)signal(SIGALRM, catchalarm); + signalled = 0; + (void)alarm(interval); + + if ((line % 20) == 0) { + printf("%8.8s %6.6s %6.6s %6.6s %6.6s", + "in", "pack", "comp", "uncomp", "unknwn"); + if (vflag) + printf(" %6.6s %6.6s %6.6s", + "toss", "other", "err"); + printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s", + "out", "pack", "comp", "uncomp", "other"); + if (vflag) + printf(" %6.6s %6.6s %6.6s %6.6s", + "search", "miss", "err", "coll"); + putchar('\n'); + } + printf("%8u %6d %6u %6u %6u", + V(sc_bytesrcvd), + V(sc_if.if_ipackets), + V(sc_comp.sls_compressedin), + V(sc_comp.sls_uncompressedin), + V(sc_comp.sls_errorin)); + if (vflag) + printf(" %6u %6u %6u", + V(sc_comp.sls_tossed), + V(sc_if.if_ipackets) - + V(sc_comp.sls_compressedin) - + V(sc_comp.sls_uncompressedin) - + V(sc_comp.sls_errorin), + V(sc_if.if_ierrors)); + printf(" | %8u %6d %6u %6u %6u", + V(sc_bytessent) / (rflag ? interval : 1), + V(sc_if.if_opackets), + V(sc_comp.sls_compressed), + V(sc_comp.sls_packets) - V(sc_comp.sls_compressed), + V(sc_if.if_opackets) - V(sc_comp.sls_packets)); + if (vflag) + printf(" %6u %6u %6u %6u", + V(sc_comp.sls_searches), + V(sc_comp.sls_misses), + V(sc_if.if_oerrors), + V(sc_if.if_collisions)); + putchar('\n'); + fflush(stdout); + line++; + oldmask = sigblock(sigmask(SIGALRM)); + if (! signalled) { + sigpause(0); + } + sigsetmask(oldmask); + signalled = 0; + (void)alarm(interval); + bcopy((char *)sc, (char *)osc, AMT); + } +} + +/* + * Called if an interval expires before sidewaysintpr has completed a loop. + * Sets a flag to not wait for the alarm. + */ +void +catchalarm() +{ + signalled = 1; +} + +#include <kvm.h> +#include <fcntl.h> + +int kd; + +kopen(system, kmemf, errstr) + char *system; + char *kmemf; + char *errstr; +{ + if (strcmp(system, _PATH_UNIX) == 0 && + strcmp(kmemf, _PATH_KMEM) == 0) { + system = 0; + kmemf = 0; + } + kd = kvm_openfiles(system, kmemf, (void *)0); + if (kd == 0) + return -1; + + return 0; +} + +int +knlist(system, nl, errstr) + char *system; + struct nlist *nl; + char *errstr; +{ + if (kd == 0) + /* kopen() must be called first */ + abort(); + + if (kvm_nlist(nl) < 0 || nl[0].n_type == 0) { + fprintf(stderr, "%s: %s: no namelist\n", errstr, system); + return -1; + } + return 0; +} + +int +kread(addr, buf, size) + off_t addr; + char *buf; + int size; +{ + if (kvm_read((char *)addr, buf, size) != size) + return -1; + return 0; +} diff --git a/usr.sbin/vidcontrol/Makefile b/usr.sbin/vidcontrol/Makefile new file mode 100644 index 000000000000..11636b96dba2 --- /dev/null +++ b/usr.sbin/vidcontrol/Makefile @@ -0,0 +1,4 @@ +PROG= vidcontrol +SRCS= vidcontrol.c decode.c + +.include <bsd.prog.mk> diff --git a/usr.sbin/vidcontrol/decode.c b/usr.sbin/vidcontrol/decode.c new file mode 100644 index 000000000000..88861db6e8f2 --- /dev/null +++ b/usr.sbin/vidcontrol/decode.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 1994 Søren Schmidt + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: decode.c,v 1.1 1994/05/20 12:20:37 sos Exp $ + */ + +#include <stdio.h> + +int decode(FILE *fd, char *buffer) +{ + int n, pos = 0; + char *p; + char temp[128]; + +#define DEC(c) (((c) - ' ') & 0x3f) + + do { + if (!fgets(temp, sizeof(temp), fd)) + return(0); + } while (strncmp(temp, "begin ", 6)); + sscanf(temp, "begin %o %s", &n, temp); + for (;;) { + if (!fgets(p = temp, sizeof(temp), fd)) + return(0); + if ((n = DEC(*p)) <= 0) + break; + for (++p; n > 0; p += 4, n -= 3) + if (n >= 3) { + buffer[pos++] = DEC(p[0])<<2 | DEC(p[1])>>4; + buffer[pos++] = DEC(p[1])<<4 | DEC(p[2])>>2; + buffer[pos++] = DEC(p[2])<<6 | DEC(p[3]); + } + else { + if (n >= 1) { + buffer[pos++] = + DEC(p[0])<<2 | DEC(p[1])>>4; + } + if (n >= 2) { + buffer[pos++] = + DEC(p[1])<<4 | DEC(p[2])>>2; + } + if (n >= 3) { + buffer[pos++] = + DEC(p[2])<<6 | DEC(p[3]); + } + } + } + if (!fgets(temp, sizeof(temp), fd) || strcmp(temp, "end\n")) + return(0); + return(pos); +} diff --git a/usr.sbin/vidcontrol/path.h b/usr.sbin/vidcontrol/path.h new file mode 100644 index 000000000000..709acbc375dc --- /dev/null +++ b/usr.sbin/vidcontrol/path.h @@ -0,0 +1,4 @@ +#define KEYMAP_PATH "/usr/share/syscons/keymaps/" +#define FONT_PATH "/usr/share/syscons/fonts/" +#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/" + diff --git a/usr.sbin/vidcontrol/vidcontrol.1 b/usr.sbin/vidcontrol/vidcontrol.1 new file mode 100644 index 000000000000..5bc0af0372fe --- /dev/null +++ b/usr.sbin/vidcontrol/vidcontrol.1 @@ -0,0 +1,112 @@ +.\" +.\" vidcontrol - a utility for manipulating the syscons video driver +.\" +.\" 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. +.\" +.\" @(#)vidcontrol.1 +.\" +.TH vidcontrol 1 "May 22, 1994" "" "FreeBSD" + +.SH NAME +vidcontrol - a utility for manipulating the syscons video driver. +.SH SYNOPSIS +.na +.B vidcontrol +.RB [options] +.SH DESCRIPTION +The +.B vidcontrol +command is used to set various options for the syscons video driver, +such as video mode, colors, cursor, scrnmaps, font, +screensaver type and timeout. + +A new video mode is selected by specifying its name as an argument to +.B vidcontrol +eg. " +.B vidcontrol 80x25 +". + +The modes currently supported: 80x25 and 80x50 text. + +The colors used when displaying text can be changed by specifying the +foreground color (eg. " +.B vidcontrol white +"), or both a foreground & background +color (eg. " +.B vidcontrol yellow blue +"). + +To see the supported colors on a given platform use " +.B vidcontrol show +". + +.SH OPTIONS +.TP +The following command line options are supported. +.TP +.BI "\-r\ " foreground\ background +Change reverse mode colors to +.B foreground +and +.B background +. +.TP +.BI "\-b\ " color +Set border color to +.B color +(only supported on VGA hardware): +.TP +.BI "\-c\ " start.end +Change the cursor apperance. The cursor is changed to a shape that starts +on scanline +.B start +and ends on scanline +.B end +. +.TP +.BI "\-l\ " scrmap +Install screen output map file from +.I scrmap +.TP +.BI "\-L\ " +Install default screen output map. +.TP +.BI "\-f\ " size\ file +Load font +.I file +for +.I size +(currently, only 8x8, 8x14 or 8x16). +The fontfile can be either uuencoded or in raw binary format. +.TP +.BI "\-t\ " N|off +Sets the screensaver timeout to +.I N +seconds, or turns it +.I off +.TP +.BI "\-s\ " NAME|help +Sets the screensaver appearance to +.I NAME . +Use \-s help to print a list of the available screen savers. +.PP +.SH FILES +/usr/share/syscons/fonts +/usr/share/syscons/scrnmaps +.SH BUGS +Report when found. +.SH "SEE ALSO" +.BR kbdcontrol(1) , +.BR keyboard (4) , +.BR screen (4) , +.BR /sys/i386/conf/SYSCONS +.SH AUTHORS +Søren Schmidt (sos@login.dkuug.dk) + diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c new file mode 100644 index 000000000000..3278f921092a --- /dev/null +++ b/usr.sbin/vidcontrol/vidcontrol.c @@ -0,0 +1,472 @@ +/*- + * Copyright (c) 1994 Søren Schmidt + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $Id: vidcontrol.c,v 1.4 1994/05/26 04:13:59 jkh Exp $ + */ + +#include <ctype.h> +#include <stdio.h> +#include <machine/console.h> +#include <sys/errno.h> +#include "path.h" + + +char legal_colors[16][16] = { + "black", "blue", "green", "cyan", + "red", "magenta", "brown", "white", + "grey", "lightblue", "lightgreen", "lightcyan", + "lightred", "lightmagenta", "yellow", "lightwhite" + }; +int hex = 0; +int number, verbose = 0; +char letter; +struct vid_info info; + + +char * +nextarg(int ac, char **av, int *indp, int oc) +{ + if (*indp < ac) + return(av[(*indp)++]); + fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc); + usage(); + exit(1); + return(""); +} + + +char * +mkfullname(const char *s1, const char *s2, const char *s3) +{ +static char *buf = NULL; +static int bufl = 0; +int f; + + + f = strlen(s1) + strlen(s2) + strlen(s3) + 1; + if (f > bufl) + if (buf) + buf = (char *)realloc(buf, f); + else + buf = (char *)malloc(f); + if (!buf) { + bufl = 0; + return(NULL); + } + + bufl = f; + strcpy(buf, s1); + strcat(buf, s2); + strcat(buf, s3); + return(buf); +} + + +void +load_scrnmap(char *filename) +{ + FILE *fd; + int i, size; + char *name; + scrmap_t scrnmap; + char *prefix[] = {"", "", SCRNMAP_PATH, SCRNMAP_PATH, NULL}; + char *postfix[] = {"", ".scm", "", ".scm"}; + + for (i=0; prefix[i]; i++) { + name = mkfullname(prefix[i], filename, postfix[i]); + if (fd = fopen(name, "r")) + break; + } + if (fd == NULL) { + perror("screenmap file not found"); + return; + } + size = sizeof(scrnmap); + if (decode(fd, &scrnmap) != size) { + rewind(fd); + if (fread(&scrnmap, 1, size, fd) != size) { + fprintf(stderr, "bad scrnmap file\n"); + close(fd); + return; + } + } + if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0) + perror("can't load screenmap"); + close(fd); +} + + +void +load_default_scrnmap() +{ + int i; + scrmap_t scrnmap; + + for (i=0; i<256; i++) + *((char*)&scrnmap + i) = i; + if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0) + perror("can't load default screenmap"); +} + + +void +print_scrnmap() +{ + unsigned char map[256]; + int i; + + if (ioctl(0, GIO_SCRNMAP, &map) < 0) { + perror("getting scrnmap"); + return; + } + for (i=0; i<sizeof(map); i++) { + if (i > 0 && i % 16 == 0) + fprintf(stdout, "\n"); + if (hex) + fprintf(stdout, " %02x", map[i]); + else + fprintf(stdout, " %03d", map[i]); + } + fprintf(stdout, "\n"); + +} + + +void +load_font(char *type, char *filename) +{ + FILE *fd; + int i, io, size; + char *name, *fontmap; + char *prefix[] = {"", "", FONT_PATH, FONT_PATH, NULL}; + char *postfix[] = {"", ".fnt", "", ".fnt"}; + + for (i=0; prefix[i]; i++) { + name = mkfullname(prefix[i], filename, postfix[i]); + if (fd = fopen(name, "r")) + break; + } + if (fd == NULL) { + perror("font file not found"); + return; + } + if (!strcmp(type, "8x8")) { + size = 8*256; + io = PIO_FONT8x8; + } + else if (!strcmp(type, "8x14")) { + size = 14*256; + io = PIO_FONT8x14; + } + else if (!strcmp(type, "8x16")) { + size = 16*256; + io = PIO_FONT8x16; + } + else { + perror("bad font size specification"); + close(fd); + return; + } + fontmap = (char*) malloc(size); + if (decode(fd, fontmap) != size) { + rewind(fd); + if (fread(fontmap, 1, size, fd) != size) { + fprintf(stderr, "bad font file\n"); + close(fd); + free(fontmap); + return; + } + } + if (ioctl(0, io, fontmap) < 0) + perror("can't load font"); + close(fd); + free(fontmap); +} + + +void +set_screensaver_timeout(char *arg) +{ + int nsec; + + if (!strcmp(arg, "off")) + nsec = 0; + else { + nsec = atoi(arg); + if ((*arg == '\0') || (nsec < 1)) { + fprintf(stderr, "argument must be a positive number\n"); + return; + } + } + if (ioctl(0, CONS_BLANKTIME, &nsec) == -1) + perror("setting screensaver period"); +} + + +void +set_screensaver_type(char *type) +{ + ssaver_t saver; + int i, e; + + if (!strcmp(type, "help")) { + i = 0; + printf("available screen saver types:\n"); + do { + saver.num = i; + e = ioctl(0, CONS_GSAVER, &saver); + i ++; + if (e == 0) + printf("\t%s\n", saver.name); + } while (e == 0); + if (e == -1 && errno != EIO) + perror("getting screensaver info"); + } else { + i = 0; + do { + saver.num = i; + e = ioctl(0, CONS_GSAVER, &saver); + i ++; + if (e == 0 && !strcmp(type, saver.name)) { + if (ioctl(0, CONS_SSAVER, &saver) == -1) + perror("setting screensaver type"); + return; + } + } while (e == 0); + if (e == -1 && errno != EIO) + perror("getting screensaver info"); + else + fprintf(stderr, "%s: No such screensaver\n", type); + } +} + +void +set_cursor_values(char *size) +{ + int start, end; + int n; + char *v1; + + start = strtol(size, &v1, 0); + if ((start < 0) || (*v1 != '.')) + goto badopt; + size = ++v1; + end = strtol(size, &v1, 0); + if ((end < 0) || (*size == '\0') || (*v1 != '\0')) { +badopt: + fprintf(stderr, + "argument to -c must be start.end\n"); + return; + } + if (verbose) + fprintf(stderr, "setting cursor to %d.%d\n", start, end); + fprintf(stdout, "[=%d;%dC", start, end); +} + + +int +video_mode(int argc, char **argv, int *index) +{ + int mode; + + if (*index < argc) { + if (!strcmp(argv[*index], "80x25")) + mode = CONS_80x25TEXT; + else if (!strcmp(argv[*index], "80x50")) + mode = CONS_80x50TEXT; + else + return; + if (ioctl(0, mode, NULL) < 0) + perror("Cannot set videomode"); + (*index)++; + } + return; +} + + +int +get_color_number(char *color) +{ + int i; + + for (i=0; i<16; i++) + if (!strcmp(color, legal_colors[i])) + return i; + return -1; +} + + +int +set_normal_colors(int argc, char **argv, int *index) +{ + int color; + + if (*index < argc && (color = get_color_number(argv[*index])) != -1) { + (*index)++; + fprintf(stderr, "[=%dF", color); + if (*index < argc + && (color = get_color_number(argv[*index])) != -1 + && color < 8) { + (*index)++; + fprintf(stderr, "[=%dG", color); + } + } +} + + +set_reverse_colors(int argc, char **argv, int *index) +{ + int color; + + if ((color = get_color_number(argv[*(index)-1])) != -1) { + fprintf(stderr, "[=%dH", color); + if (*index < argc + && (color = get_color_number(argv[*index])) != -1 + && color < 8) { + (*index)++; + fprintf(stderr, "[=%dI", color); + } + } +} + + +set_border_color(char *arg) +{ + int color; + + if ((color = get_color_number(arg)) != -1) { + fprintf(stderr, "[=%dA", color); + } + else + usage(); +} + + +test_frame() +{ + int i; + + fprintf(stdout, "[=0G\n\n"); + for (i=0; i<8; i++) { + fprintf(stdout, "[=15F[=0G %2d [=%dF%-16s" + "[=15F[=0G %2d [=%dF%-16s " + "[=15F %2d [=%dGBACKGROUND[=0G\n", + i, i, legal_colors[i], i+8, i+8, + legal_colors[i+8], i, i); + } + fprintf(stdout, "[=%dF[=%dG[=%dH[=%dI\n", + info.mv_norm.fore, info.mv_norm.back, + info.mv_rev.fore, info.mv_rev.back); +} + + +usage() +{ + fprintf(stderr, +"Usage: vidcontrol mode (available modes: 80x25, 80x50)\n" +" show (show available colors)\n" +" fgcol bgcol (set fore- & background colors)\n" +" -r fgcol bgcol (set reverse fore- & background colors)\n" +" -b color (set border color)\n" +" -c n.m (set cursor start line n & end line m)\n" +#if 0 +" -d (dump screenmap to stdout)\n" +#endif +" -l filename (load srceenmap file filename)\n" +" -L (load default screenmap)\n" +" -f DxL filename (load font, D dots wide & L lines high)\n" +" -s saver | help (set screensaver type or help for a list)\n" +" -t N (set screensaver timeout in seconds)\n" + ); +} + + +void +main(int argc, char **argv) +{ + extern char *optarg; + extern int optind; + int opt; + + + info.size = sizeof(info); + if (ioctl(0, CONS_GETINFO, &info) < 0) { + perror("Must be on a vty"); + exit(1); + } + while((opt = getopt(argc, argv, "b:c:df:l:Lr:s:t:vx")) != -1) + switch(opt) { + case 'c': + set_cursor_values(optarg); + break; + case 'b': + set_border_color(optarg); + break; + case 'd': + print_scrnmap(); + break; + case 'f': + load_font(optarg, + nextarg(argc, argv, &optind, 'f')); + break; + case 'l': + load_scrnmap(optarg); + break; + case 'L': + load_default_scrnmap(); + break; + case 'r': + set_reverse_colors(argc, argv, &optind); + break; + case 's': + set_screensaver_type(optarg); + break; + case 't': + set_screensaver_timeout(optarg); + break; + case 'v': + verbose = 1; + break; + case 'x': + hex = 1; + break; + default: + usage(); + exit(1); + } + if (video_mode(argc, argv, &optind)) ; + if (set_normal_colors(argc, argv, &optind)) ; + if (optind < argc && !strcmp(argv[optind], "show")) { + test_frame(); + optind++; + } + if ((optind != argc) || (argc == 1)) { + usage(); + exit(1); + } + exit(0); +} + diff --git a/usr.sbin/xten/Install.notes b/usr.sbin/xten/Install.notes new file mode 100644 index 000000000000..9725ba402b58 --- /dev/null +++ b/usr.sbin/xten/Install.notes @@ -0,0 +1,222 @@ +Installation Notes for X-10 software +Eugene W. Stark (stark@cs.sunysb.edu) +October 30, 1993 + +The TW523 is a carrier-current modem for home control/automation purposes. +It is made by: + + X-10 Inc. + 185A LeGrand Ave. + Northvale, NJ 07647 + USA + (201) 784-9700 or 1-800-526-0027 + + X-10 Home Controls Inc. + 1200 Aerowood Drive, Unit 20 + Mississauga, Ontario + (416) 624-4446 or 1-800-387-3346 + +The TW523 is designed for communications using the X-10 protocol, +which is compatible with a number of home control systems, including +Radio Shack "Plug 'n Power(tm)" and Stanley "Lightmaker(tm)." +I bought my TW523 from: + + Home Control Concepts + 9353-C Activity Road + San Diego, CA 92126 + (619) 693-8887 + +They supplied me with the TW523 (which has an RJ-11 four-wire modular +telephone connector), a modular cable, an RJ-11 to DB-25 connector with +internal wiring, documentation from X-10 on the TW523 (very good), +an instruction manual by Home Control Concepts (not very informative), +and a floppy disk containing binary object code of some demonstration/test +programs and of a C function library suitable for controlling the TW523 +by an IBM PC under MS-DOS (not useful to me other than to verify that +the unit worked). I suggest saving money and buying the bare TW523 +rather than the TW523 development kit (what I bought), because if you +are running 386BSD you don't really care about the DOS binaries. +For details on the X-10 protocol itself, refer to the documentation from +X-10 Inc. + +The interface to the TW-523 consists of four wires on the RJ-11 connector, +which are jumpered to somewhat more wires on the DB-25 connector, which +in turn is intended to plug into the PC parallel printer port. I dismantled +the DB-25 connector to find out what they had done: + + Signal RJ-11 pin DB-25 pin(s) Parallel Port + Transmit TX 4 (Y) 2, 4, 6, 8 Data out + Receive RX 3 (G) 10, 14 -ACK, -AutoFeed + Common 2 (R) 25 Common + Zero crossing 1 (B) 17 -Select Input + +I use the TW-523 and this software in the USA with 120V/60Hz power. +Phil Sampson (vk2jnt@gw.vk2jnt.ampr.org OR sampson@gidday.enet.dec.com) +in Australia has reported success in using a TW-7223 (a local version +of the TW-523) and Tandy modules with this software under 240V/50Hz power. +For reasons explained in the comments in the driver, it will probably not +work if you have three-phase power, but this is usually not the case for +normal residences and offices. + + +1. Installing the TW523 Device Driver + +I assume that you are running FreeBSD. If you are running some other +system, you are more or less on your own, though I can try to help if you +have problems. + +Check the configuration parameters at the beginning of the file + + /sys/i386/isa/tw.c + +Probably the only thing you might need to change is to change the +definition of HALFCYCLE from 8333 to 10000 if you are using 50Hz power. +The driver assumes that the TW523 device is connected to a parallel port. +See the comments near the beginning of the file to find out where to +get a TW523 if you don't have one, and how to make a cable for it to +connect to your parallel port. + +Add a line like the following + + device tw0 at isa? port 0x278 tty irq 5 vector twintr + +to /sys/i386/conf/YOURSYSTEM, but make sure to change the I/O port and +interrupt to match your hardware configuration. + +Cd to /sys/i386/conf and do "config YOURSYSTEM". +Cd to /sys/compile/YOURSYSTEM and do "make depend", then "make". +(If you have any troubles, I suggest starting fresh by doing a full +"make clean; make depend; make".) Assuming the make works correctly, do + + mv /386bsd /386bsd.old + mv 386bsd /386bsd + +(If you are not a trusting person, or you don't have any spare fixit +floppies with working kernels lying around, don't do this without testing +the kernel first by copying it to a fixit floppy and booting from that.) + +Reboot the system. You should see a line indicating that the TW523 has +been configured as the system comes up. If you see this line, then probably +everything is going to work OK, because the TW523 will only get configured +if the driver is able to sync to the power line. If the TW523 is not plugged +in, or the driver is not getting sync for some reason, then you won't see +any message on bootup. + +NOTE: I have received a report that some multi IDE/SIO/PARALLEL cards +"cheat" and use TTL outputs rather than pullup open collector outputs, +and this can mess up the scheme by which sync gets to the driver. +If you are having trouble getting the driver to work, you might want to +look into this possibility. + +In directory /dev, execute the command + + MAKEDEV tw0 + + +2. Installing the X-10 Daemon + +Go to the xten source directory (probably /usr/src/contrib/xten). +Check over the file "paths.h", if desired, to make sure that the entries +are reasonable for your system. On my system, I have a special UID "xten" +for the daemon. If you want to do this, too, you will have to add this UID +to your /etc/master.passwd in the usual way. Otherwise, use "root" or +"daemon" or something. You should change the ownership of /dev/tw0 to +match this UID, so that the daemon will be able to access the TW-523. +Edit the file Makefile.inc in the source directory to specify this UID: + + xtenuser= xten + +Then run "make". If everything is OK, run + + make install + +This should install the daemon "xtend" and the command "xten". + +Make sure the directory /var/spool/xten exists and is owned by the UID +you selected above. This directory is used by the daemon for its log and +device status files. When it is run, the daemon will also create a socket +/var/run/tw523 and it will put its pid in /var/run/xtend.pid so that it can +be signalled from shell scripts. + +Add the following lines to your /etc/rc.local file: + + if [ -x /usr/libexec/xtend ]; then + echo -n ' xtend'; /usr/libexec/xtend + fi + +This will cause the X-10 daemon to be invoked automatically when you boot +the system. To test the installation, you can either reboot now, or +you can just run "xtend" by hand. The daemon should start up, and it should +create files in /var/spool/xten. Check the file /var/spool/xten/Log to +make sure that the daemon started up without any errors. + +Now you are ready to start trying X-10 commands. Try doing + + xten A 1 Off + xten A 1 On 1 Dim:10 + +etc. The "xten" program expects a house code as its first argument, then +a series of key codes, which are either unit names ("1" through "16") or +else are command names. You can find the list of command names by looking +at the table in the file "xten.c". Each key code can optionally be followed +by a colon : then a number specifying the number of times that command is +to be transmitted without gaps between packets. The default is 2, and this +is the normal case, but some commands like Bright and Dim are designed to +be transmitted with counts other than 2. See the X-10 documentation for +more detail. + +The "xten" program works by connecting to "xtend" through a socket, and +asking that the X-10 codes be transmitted over the TW523. All activity +on the TW523 is logged by the daemon in /var/spool/xten/Log. The daemon +also attempts to track the state of all devices. (Of course, most X-10 +devices do not transmit when they are operated manually, so if somebody +operates a device manually there is no way the X-10 daemon will know +about it.) + +3. Low-level Programming of the TW523 Driver + +Normally, you would never operate the TW523 directly, rather you would +use the shell command "xten" or you would connect to "xtend" through its +socket. However, if you don't want to run "xtend", you can manipulate +the TW523 directly through the device /dev/tw0. Have a look at the +xtend code for a programming example. + +The driver supports read(), write(), and select() system calls. +The driver allows multiple processes to read and write simultaneously, +but there is probably not much sense in having more than one reader or more +than one writer at a time, and in fact there may currently be a race +condition in the driver if two processes try to transmit simultaneously +(due to unsynchronized access to the sc_pkt structure in tw_sc). + +Transmission is done by calling write() to send three byte packets of data. +The first byte contains a four bit house code (0=A to 15=P). The second byte +contains five bit unit/key code (0=unit 1 to 15=unit 16, 16=All Units Off +to 31 = Status Request). The third byte specifies the number of times the +packet is to be transmitted without any gaps between successive transmissions. +Normally this is 2, as per the X-10 documentation, but sometimes (e.g. for +bright and dim codes) it can be another value. Each call to write can specify +an arbitrary number of data bytes, but at most one packet will actually be +processed in any call. Any incomplete packet is buffered until a subsequent +call to write() provides data to complete it. Successive calls to write() +leave a three-cycle gap between transmissions, per the X-10 documentation. +The driver transmits each bit only once per half cycle, not three times as +the X-10 documentation states, because the TW523 only provides sync on +each power line zero crossing. So, the driver will probably not work +properly if you have three-phase service. Most residences use a two-wire +system, for which the driver does work. + +Reception is done using read(). The driver produces a series of three +character packets. In each packet, the first character consists of flags, +the second character is a four bit house code (0-15), and the third character +is a five bit key/function code (0-31). The flags are the following: + +#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */ +#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */ + +The select() system call can be used in the usual way to determine if there +is data ready for reading. + + + Happy Controlling! + Gene Stark + stark@cs.sunysb.edu diff --git a/usr.sbin/xten/Makefile b/usr.sbin/xten/Makefile new file mode 100644 index 000000000000..6300ec9effed --- /dev/null +++ b/usr.sbin/xten/Makefile @@ -0,0 +1,10 @@ +# Makefile for xten (Stark) 10/30/93 + +PROG= xten +SRCS= xten.c +CFLAGS+=-I. -I/usr/src/libexec/xtend + +MAN1= xten.1 + +.include <bsd.prog.mk> + diff --git a/usr.sbin/xten/xten.1 b/usr.sbin/xten/xten.1 new file mode 100644 index 000000000000..1c7d51de7963 --- /dev/null +++ b/usr.sbin/xten/xten.1 @@ -0,0 +1,110 @@ +.\" Copyright (c) 1992, 1993 Eugene W. Stark +.\" 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 Eugene W. Stark. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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. +.\" +.Th XTEN 8 "30 Oct 1993" +.Dd Oct 30, 1993 +.Dt XTEN 1 +.Os BSD FreeBSD +.Sh NAME +xten \- transmit X-10 commands +.Sh SYNOPSIS +.Nm xten +[ - ] house key[:cnt] [ [ house ] key[:cnt] .\|.\|. ] +.Sh DESCRIPTION +.Nm Xten +is a command-line interface to the X-10 daemon. +When invoked with a one-letter house code (A-P) and a series of key/unit +codes as arguments, it requests the X-10 daemon to transmit a corresponding +series of X-10 packets. The X-10 daemon makes its best effort to ensure +that the packets are all transmitted correctly, though in general it is +not possible to tell whether the commands were actually received and +executed by the remote X-10 devices. +.Pp +When invoked with the single argument \-, +.Nm xten +enters an interactive mode in which a line is repeatedly read from the +standard input, sent to the X-10 daemon, and the one-line response from +the daemon printed on the standard output. +.Sh OPTIONS +The +.I +house +argument is a one-letter house code in the range A-P. +All the X-10 requests generated will refer to this house code. +Each +.I +key +is either a numeric unit code in the range 1-16, or else +is a string that specifies an X-10 function. The possible +function code strings are: +.Bl -diag +.It AllUnitsOff +.It AllLightsOn +.It On +.It Off +.It Dim +.It Bright +.It AllLightsOff +.It ExtendedCode +.It HailRequest +.It HailAcknowledge +.It PreSetDim0 +.It PreSetDim1 +.It ExtendedData +.It StatusOn +.It StatusOff +.It StatusRequest +.El +.Pp +Each +.I +key +may be followed by an optional numeric +.I +cnt, +which specifies the number of packets that are to be sent with that +key code without gaps. If this argument is omitted, two packets +are transmitted. The ability to specify numbers of packets other than +two is used by the X-10 +.I +Dim +and +.I +Bright +commands. +.Sh SEE ALSO +.Xr xtend 8 +.Xr tw 4 +.Sh FILES +.Bl -tag -width /var/spool/xten/Status -compact +.It Pa /dev/tw0 +the TW523 special file +.El +.Sh AUTHOR +Eugene W. Stark (stark@cs.sunysb.edu) diff --git a/usr.sbin/xten/xten.c b/usr.sbin/xten/xten.c new file mode 100644 index 000000000000..dc8555675d4a --- /dev/null +++ b/usr.sbin/xten/xten.c @@ -0,0 +1,164 @@ +/*- + * Copyright (c) 1992, 1993 Eugene W. Stark + * 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 Eugene W. Stark. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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. + */ + +/* + * Xten - user command interface to X-10 daemon + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "xtend.h" +#include "xten.h" +#include "paths.h" + +#define RETRIES 10 +#define CMDLEN 512 + +char *X10housenames[] = { + "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", + NULL +}; + +char *X10cmdnames[] = { + "1", "2", "3", "4", "5", "6", "7", "8", + "9", "10", "11", "12", "13", "14", "15", "16", + "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff", + "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1", + "ExtendedData", "StatusOn", "StatusOff", "StatusRequest", + NULL +}; + +main(argc, argv) +int argc; +char *argv[]; +{ + int c, tmp, h, k, sock, error; + FILE *daemon; + struct sockaddr_un sa; + char *sockpath = SOCKPATH; + char reply[CMDLEN], cmd[CMDLEN], *cp; + int interactive = 0; + + if(argc == 2 && !strcmp(argv[1], "-")) interactive++; + else if(argc < 3) { + fprintf(stderr, "Usage: %s house key[:cnt] [ [house] key[:cnt] ... ]\n", argv[0]); + exit(1); + } + if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "%s: Can't create socket\n", argv[0]); + exit(1); + } + strcpy(sa.sun_path, sockpath); + sa.sun_family = AF_UNIX; + if(connect(sock, (struct sockaddr *)(&sa), strlen(sa.sun_path) + 2) < 0) { + fprintf(stderr, "%s: Can't connect to X-10 daemon\n", argv[0]); + exit(1); + } + if((daemon = fdopen(sock, "w+")) == NULL) { + fprintf(stderr, "%s: Can't attach stream to socket\n", argv[0]); + exit(1); + } + /* + * If interactive, copy standard input to daemon and report results + * on standard output. + */ + if(interactive) { + while(!feof(stdin)) { + if(fgets(cmd, CMDLEN, stdin) != NULL) { + fprintf(daemon, "%s", cmd); + fflush(daemon); + if(fgets(reply, CMDLEN, daemon) != NULL) { + fprintf(stdout, "%s", reply); + fflush(stdout); + } + } + } + exit(0); + } + /* + * Otherwise, interpret arguments and issue commands to daemon, + * handling retries in case of errors. + */ + if((h = find(argv[1], X10housenames)) < 0) { + fprintf(stderr, "Invalid house code: %s\n", argv[1]); + exit(1); + } + argv++; + argv++; + while(argc >= 3) { + cp = argv[0]; + if((tmp = find(cp, X10housenames)) >= 0) { + h = tmp; + argv++; + argc--; + continue; + } + while(*cp != '\0' && *cp != ':') cp++; + if(*cp == ':') c = atoi(cp+1); + else c = 2; + *cp = '\0'; + if((k = find(argv[0], X10cmdnames)) < 0) { + fprintf(stderr, "Invalid key/unit code: %s\n", argv[0]); + error++; + } + error = 0; + while(error < RETRIES) { + fprintf(daemon, "send %s %s %d\n", X10housenames[h], X10cmdnames[k], c); + fflush(daemon); + fgets(reply, CMDLEN, daemon); + if(strncmp(reply, "ERROR", 5)) break; + error++; + usleep(200000); + } + if(error == RETRIES) { + fprintf(stderr, "Command failed: send %s %s %d\n", + X10housenames[h], X10cmdnames[k], c); + } + argc--; + argv++; + } + exit(0); +} + +find(s, tab) +char *s; +char *tab[]; +{ + int i; + + for(i = 0; tab[i] != NULL; i++) { + if(strcmp(s, tab[i]) == 0) return(i); + } + return(-1); +} |