Delete old routed(8).

This commit is contained in:
Garrett Wollman 1996-09-16 16:56:00 +00:00
parent 322bab890f
commit 1c7ee7bf52
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=18321
18 changed files with 0 additions and 10763 deletions

View File

@ -1,10 +0,0 @@
# From: @(#)Makefile 8.1 (Berkeley) 6/19/93
# $Id$
PROG= routed
SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
MAN8= routed.8
SUBDIR= rtquery
#COPTS= -g -DDEBUG -Wall
.include <bsd.prog.mk>

View File

@ -1 +0,0 @@
.include "../../Makefile.inc"

View File

@ -1,561 +0,0 @@
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)defs.h 8.1 (Berkeley) 6/5/93
* $Id: defs.h,v 1.4 1996/07/22 21:12:14 wollman Exp $
*/
#ifndef __NetBSD__
#ident "$Revision: 1.1.3.3 $"
#endif
/* Definitions for RIPv2 routing process.
*
* This code is based on the 4.4BSD `routed` daemon, with extensions to
* support:
* RIPv2, including variable length subnet masks.
* Router Discovery
* aggregate routes in the kernel tables.
* aggregate advertised routes.
* maintain spare routes for faster selection of another gateway
* when the current gateway dies.
* timers on routes with second granularity so that selection
* of a new route does not wait 30-60 seconds.
* tolerance of static routes.
* tell the kernel hop counts
* do not advertise if ipforwarding=0
*
* The vestigual support for other protocols has been removed. There
* is no likelihood that IETF RIPv1 or RIPv2 will ever be used with
* other protocols. The result is far smaller, faster, cleaner, and
* perhaps understandable.
*
* The accumulation of special flags and kludges added over the many
* years have been simplified and integrated.
*/
#include <stdio.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#ifdef sgi
#include <strings.h>
#include <bstring.h>
#endif
#include <stdarg.h>
#include <syslog.h>
#include <time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#ifdef sgi
#include <net/radix.h>
#else
#include "radix.h"
#endif
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define RIPVERSION RIPv2
#include <protocols/routed.h>
/* Type of an IP address.
* Some systems do not like to pass structures, so do not use in_addr.
* Some systems think a long has 64 bits, which would be a gross waste.
* So define it here so it can be changed for the target system.
* It should be defined somewhere netinet/in.h, but it is not.
*/
#ifdef sgi
#define naddr __uint32_t
#else
#ifdef __NetBSD__
#define naddr u_int32_t
#else
#define naddr u_long
#endif
#define _HAVE_SA_LEN
#define _HAVE_SIN_LEN
#endif
/* Turn on if IP_DROP_MEMBERSHIP and IP_ADD_MEMBERSHIP do not look at
* the dstaddr of point-to-point interfaces.
*/
/* #define MCAST_PPP_BUG */
#define NEVER (24*60*60) /* a long time */
#define EPOCH NEVER /* bias time by this to avoid <0 */
/* Scan the kernel regularly to see if any interfaces have appeared or been
* turned off. These must be less than STALE_TIME.
*/
#define CHECK_BAD_INTERVAL 5 /* when an interface is known bad */
#define CHECK_ACT_INTERVAL 30 /* when advertising */
#define CHECK_QUIET_INTERVAL 300 /* when not */
#define LIM_SEC(s,l) ((s).tv_sec = MIN((s).tv_sec, (l)))
/* Router Discovery parameters */
#ifndef sgi
#define INADDR_ALLROUTERS_GROUP 0xe0000002 /* 224.0.0.2 */
#endif
#define MaxMaxAdvertiseInterval 1800
#define MinMaxAdvertiseInterval 4
#define DefMaxAdvertiseInterval 600
#define DEF_PreferenceLevel 0
#define MIN_PreferenceLevel 0x80000000
#define MAX_INITIAL_ADVERT_INTERVAL 16
#define MAX_INITIAL_ADVERTS 3
#define MAX_RESPONSE_DELAY 2
#define MAX_SOLICITATION_DELAY 1
#define SOLICITATION_INTERVAL 3
#define MAX_SOLICITATIONS 3
/* typical packet buffers */
union pkt_buf {
char packet[MAXPACKETSIZE+1];
struct rip rip;
};
/* no more routes than this, to protect ourself in case something goes
* whacko and starts broadcast zillions of bogus routes.
*/
#define MAX_ROUTES (128*1024)
extern int total_routes;
/* Main, daemon routing table structure
*/
struct rt_entry {
struct radix_node rt_nodes[2]; /* radix tree glue */
u_int rt_state;
# define RS_IF 0x001 /* for network interface */
# define RS_NET_INT 0x002 /* authority route */
# define RS_NET_SYN 0x004 /* fake net route for subnet */
# define RS_NO_NET_SYN (RS_LOCAL | RS_LOCAL | RS_IF)
# define RS_SUBNET 0x008 /* subnet route from any source */
# define RS_LOCAL 0x010 /* loopback for pt-to-pt */
# define RS_MHOME 0x020 /* from -m */
# define RS_STATIC 0x040 /* from the kernel */
# define RS_RDISC 0x080 /* from router discovery */
# define RS_PERMANENT (RS_MHOME | RS_STATIC | RS_NET_SYN | RS_RDISC)
struct sockaddr_in rt_dst_sock;
naddr rt_mask;
struct rt_spare {
struct interface *rts_ifp;
naddr rts_gate; /* forward packets here */
naddr rts_router; /* on the authority of this router */
char rts_metric;
u_short rts_tag;
time_t rts_time; /* timer to junk stale routes */
#define NUM_SPARES 4
} rt_spares[NUM_SPARES];
u_int rt_seqno; /* when last changed */
char rt_poison_metric; /* to notice maximum recently */
time_t rt_poison_time; /* advertised metric */
};
#define rt_dst rt_dst_sock.sin_addr.s_addr
#define rt_ifp rt_spares[0].rts_ifp
#define rt_gate rt_spares[0].rts_gate
#define rt_router rt_spares[0].rts_router
#define rt_metric rt_spares[0].rts_metric
#define rt_tag rt_spares[0].rts_tag
#define rt_time rt_spares[0].rts_time
#define HOST_MASK 0xffffffff
#define RT_ISHOST(rt) ((rt)->rt_mask == HOST_MASK)
/* age all routes that
* are not from -g, -m, or static routes from the kernel
* not unbroken interface routes
* but not broken interfaces
* nor non-passive, remote interfaces that are not aliases
* (i.e. remote & metric=0)
*/
#define AGE_RT(rt,ifp) (0 == ((rt)->rt_state & RS_PERMANENT) \
&& (!((rt)->rt_state & RS_IF) \
|| (ifp) == 0 \
|| (((ifp)->int_state & IS_REMOTE) \
&& !((ifp)->int_state & IS_PASSIVE))))
/* true if A is better than B
* Better if
* - A is not a poisoned route
* - and A is not stale
* - and A has a shorter path
* - or is the router speaking for itself
* - or the current route is equal but stale
* - or it is a host route advertised by a system for itself
*/
#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \
&& now_stale <= (A)->rts_time \
&& ((A)->rts_metric < (B)->rts_metric \
|| ((A)->rts_gate == (A)->rts_router \
&& (B)->rts_gate != (B)->rts_router) \
|| ((A)->rts_metric == (B)->rts_metric \
&& now_stale > (B)->rts_time) \
|| (RT_ISHOST(rt) \
&& (rt)->rt_dst == (A)->rts_router \
&& (A)->rts_metric == (B)->rts_metric)))
/* An "interface" is similar to a kernel ifnet structure, except it also
* handles "logical" or "IS_REMOTE" interfaces (remote gateways).
*/
struct interface {
struct interface *int_next, *int_prev;
char int_name[IFNAMSIZ+15+1]; /* big enough for IS_REMOTE */
u_short int_index;
naddr int_addr; /* address on this host (net order) */
naddr int_brdaddr; /* broadcast address (n) */
naddr int_dstaddr; /* other end of pt-to-pt link (n) */
naddr int_net; /* working network # (host order)*/
naddr int_mask; /* working net mask (host order) */
naddr int_ripv1_mask; /* for inferring a mask (n) */
naddr int_std_addr; /* class A/B/C address (n) */
naddr int_std_net; /* class A/B/C network (h) */
naddr int_std_mask; /* class A/B/C netmask (h) */
int int_rip_sock; /* for queries */
int int_if_flags; /* copied from kernel */
u_int int_state;
time_t int_act_time; /* last thought healthy */
u_short int_transitions; /* times gone up-down */
char int_metric;
char int_d_metric; /* for faked default route */
struct int_data {
u_int ipackets; /* previous network stats */
u_int ierrors;
u_int opackets;
u_int oerrors;
#ifdef sgi
u_int odrops;
#endif
time_t ts; /* timestamp on network stats */
} int_data;
char int_passwd[RIP_AUTH_PW_LEN]; /* RIPv2 password */
int int_rdisc_pref; /* advertised rdisc preference */
int int_rdisc_int; /* MaxAdvertiseInterval */
int int_rdisc_cnt;
struct timeval int_rdisc_timer;
};
#define IS_ALIAS 0x0000001 /* interface alias */
#define IS_SUBNET 0x0000002 /* interface on subnetted network */
#define IS_REMOTE 0x0000004 /* interface is not on this machine */
#define IS_PASSIVE 0x0000008 /* remote and does not do RIP */
#define IS_EXTERNAL 0x0000010 /* handled by EGP or something */
#define IS_CHECKED 0x0000020 /* still exists */
#define IS_ALL_HOSTS 0x0000040 /* in INADDR_ALLHOSTS_GROUP */
#define IS_ALL_ROUTERS 0x0000080 /* in INADDR_ALLROUTERS_GROUP */
#define IS_RIP_QUERIED 0x0000100 /* query broadcast */
#define IS_BROKE 0x0000200 /* seems to be broken */
#define IS_SICK 0x0000400 /* seems to be broken */
#define IS_DUP 0x0000800 /* has a duplicate address */
#define IS_ACTIVE 0x0001000 /* heard from it at least once */
#define IS_NEED_NET_SYN 0x0002000 /* need RS_NET_SYN route */
#define IS_NO_AG 0x0004000 /* do not aggregate subnets */
#define IS_NO_SUPER_AG 0x0008000 /* do not aggregate networks */
#define IS_NO_RIPV1_IN 0x0010000 /* no RIPv1 input at all */
#define IS_NO_RIPV2_IN 0x0020000 /* no RIPv2 input at all */
#define IS_NO_RIP_IN (IS_NO_RIPV1_IN | IS_NO_RIPV2_IN)
#define IS_RIP_IN_OFF(s) (((s) & IS_NO_RIP_IN) == IS_NO_RIP_IN)
#define IS_NO_RIPV1_OUT 0x0040000 /* no RIPv1 output at all */
#define IS_NO_RIPV2_OUT 0x0080000 /* no RIPv2 output at all */
#define IS_NO_RIP_OUT (IS_NO_RIPV1_OUT | IS_NO_RIPV2_OUT)
#define IS_NO_RIP (IS_NO_RIP_OUT | IS_NO_RIP_IN)
#define IS_RIP_OUT_OFF(s) (((s) & IS_NO_RIP_OUT) == IS_NO_RIP_OUT)
#define IS_RIP_OFF(s) (((s) & IS_NO_RIP) == IS_NO_RIP)
#define IS_NO_ADV_IN 0x0100000
#define IS_NO_SOL_OUT 0x0200000 /* no solicitations */
#define IS_SOL_OUT 0x0400000 /* send solicitations */
#define GROUP_IS_SOL (IS_NO_ADV_IN|IS_NO_SOL_OUT)
#define IS_NO_ADV_OUT 0x0800000 /* do not advertise rdisc */
#define IS_ADV_OUT 0x1000000 /* advertise rdisc */
#define GROUP_IS_ADV (IS_NO_ADV_OUT|IS_ADV_OUT)
#define IS_BCAST_RDISC 0x2000000 /* broadcast instead of multicast */
#define IS_NO_RDISC (IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT)
#define IS_PM_RDISC 0x4000000 /* poor-man's router discovery */
#ifdef sgi
#define IFF_UP_RUNNING (IFF_RUNNING|IFF_UP)
#else
#define IFF_UP_RUNNING IFF_UP
#endif
#define iff_alive(f) (((f) & IFF_UP_RUNNING) == IFF_UP_RUNNING)
/* Information for aggregating routes */
#define NUM_AG_SLOTS 32
struct ag_info {
struct ag_info *ag_fine; /* slot with finer netmask */
struct ag_info *ag_cors; /* more coarse netmask */
naddr ag_dst_h; /* destination in host byte order */
naddr ag_mask;
naddr ag_gate;
naddr ag_nhop;
char ag_metric; /* metric to be advertised */
char ag_pref; /* aggregate based on this */
u_int ag_seqno;
u_short ag_tag;
u_short ag_state;
#define AGS_SUPPRESS 0x001 /* combine with coaser mask */
#define AGS_PROMOTE 0x002 /* synthesize combined routes */
#define AGS_REDUN0 0x004 /* redundant, finer routes output */
#define AGS_REDUN1 0x008
#define AG_IS_REDUN(state) (((state) & (AGS_REDUN0 | AGS_REDUN1)) \
== (AGS_REDUN0 | AGS_REDUN1))
#define AGS_GATEWAY 0x010 /* tell kernel RTF_GATEWAY */
#define AGS_IF 0x020 /* for an interface */
#define AGS_RIPV2 0x040 /* send only as RIPv2 */
#define AGS_FINE_GATE 0x080 /* ignore differing ag_gate when this
* has the finer netmask */
#define AGS_CORS_GATE 0x100 /* ignore differing gate when this
* has the coarser netmaks */
#define AGS_SPLIT_HZ 0x200 /* suppress for split horizon */
/* some bits are set if they are set on either route */
#define AGS_PROMOTE_EITHER (AGS_RIPV2 | AGS_GATEWAY | \
AGS_SUPPRESS | AGS_CORS_GATE)
};
/* parameters for interfaces */
extern struct parm {
struct parm *parm_next;
char parm_name[IFNAMSIZ+1];
naddr parm_addr_h;
naddr parm_mask;
char parm_d_metric;
u_int parm_int_state;
int parm_rdisc_pref;
int parm_rdisc_int;
char parm_passwd[RIP_AUTH_PW_LEN+1];
} *parms;
/* authority for internal networks */
extern struct intnet {
struct intnet *intnet_next;
naddr intnet_addr;
naddr intnet_mask;
char intnet_metric;
} *intnets;
extern pid_t mypid;
extern naddr myaddr; /* main address of this system */
extern int stopint; /* !=0 to stop */
extern int sock_max;
extern int rip_sock; /* RIP socket */
extern struct interface *rip_sock_mcast; /* current multicast interface */
extern int rt_sock; /* routing socket */
extern int rt_sock_seqno;
extern int rdisc_sock; /* router-discovery raw socket */
extern int seqno; /* sequence number for messages */
extern int supplier; /* process should supply updates */
extern int lookforinterfaces; /* 1=probe for new up interfaces */
extern int supplier_set; /* -s or -q requested */
extern int ridhosts; /* 1=reduce host routes */
extern int mhome; /* 1=want multi-homed host route */
extern int advertise_mhome; /* 1=must continue adverising it */
extern int auth_ok; /* 1=ignore auth if we do not care */
extern struct timeval epoch; /* when started */
extern struct timeval now; /* current idea of time */
extern time_t now_stale;
extern time_t now_garbage;
extern struct timeval next_bcast; /* next general broadcast */
extern struct timeval age_timer; /* next check of old routes */
extern struct timeval no_flash; /* inhibit flash update until then */
extern struct timeval rdisc_timer; /* next advert. or solicitation */
extern int rdisc_ok; /* using solicited route */
extern struct timeval ifinit_timer; /* time to check interfaces */
extern naddr loopaddr; /* our address on loopback */
extern int tot_interfaces; /* # of remote and local interfaces */
extern int rip_interfaces; /* # of interfaces doing RIP */
extern struct interface *ifnet; /* all interfaces */
extern int have_ripv1_out; /* have a RIPv1 interface */
extern int have_ripv1_in;
extern int need_flash; /* flash update needed */
extern struct timeval need_kern; /* need to update kernel table */
extern int update_seqno; /* a route has changed */
extern u_int tracelevel, new_tracelevel;
#define MAX_TRACELEVEL 3
#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */
#define TRACEPACKETS (tracelevel >= 2) /* note packets */
#define TRACEACTIONS (tracelevel != 0)
extern FILE *ftrace; /* output trace file */
extern struct radix_node_head *rhead;
#ifdef sgi
/* Fix conflicts */
#define dup2(x,y) BSDdup2(x,y)
#endif /* sgi */
extern void fix_sock(int, char *);
extern void fix_select(void);
extern void rip_off(void);
extern void rip_on(struct interface *);
enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST,
NO_OUT_MULTICAST, NO_OUT_RIPV2};
extern int output(enum output_type, struct sockaddr_in *,
struct interface *, struct rip *, int);
extern void rip_query(void);
extern void rip_bcast(int);
extern void supply(struct sockaddr_in *, struct interface *,
enum output_type, int, int);
extern void msglog(char *, ...);
#define LOGERR(msg) msglog(msg ": %s", strerror(errno))
extern void logbad(int, char *, ...);
#define BADERR(dump,msg) logbad(dump,msg ": %s", strerror(errno))
#ifdef DEBUG
#define DBGERR(dump,msg) BADERR(dump,msg)
#else
#define DBGERR(dump,msg) LOGERR(msg)
#endif
extern char *naddr_ntoa(naddr);
extern char *saddr_ntoa(struct sockaddr *);
extern void *rtmalloc(size_t, char *);
extern void timevaladd(struct timeval *, struct timeval *);
extern void intvl_random(struct timeval *, u_long, u_long);
extern int getnet(char *, naddr *, naddr *);
extern int gethost(char *, naddr *);
extern void gwkludge(void);
extern char *parse_parms(char *);
extern char *check_parms(struct parm *);
extern void get_parms(struct interface *);
extern void lastlog(void);
extern void trace_on(char *, int);
extern void trace_off(char*, ...);
extern void trace_flush(void);
extern void set_tracelevel(void);
extern void trace_act(char *, ...);
extern void trace_pkt(char *, ...);
extern void trace_add_del(char *, struct rt_entry *);
extern void trace_change(struct rt_entry *, u_int, naddr, naddr, int,
u_short, struct interface *, time_t, char *);
extern void trace_if(char *, struct interface *);
extern void trace_upslot(struct rt_entry *, struct rt_spare *,
naddr, naddr,
struct interface *, int, u_short, time_t);
extern void trace_rip(char*, char*, struct sockaddr_in *,
struct interface *, struct rip *, int);
extern char *addrname(naddr, naddr, int);
extern void rdisc_age(naddr);
extern void set_rdisc_mg(struct interface *, int);
extern void set_supplier(void);
extern void if_bad_rdisc(struct interface *);
extern void if_ok_rdisc(struct interface *);
extern void read_rip(int, struct interface *);
extern void read_rt(void);
extern void read_d(void);
extern void rdisc_adv(void);
extern void rdisc_sol(void);
extern void sigalrm(int);
extern void sigterm(int);
extern void sigtrace_on(int);
extern void sigtrace_off(int);
extern void flush_kern(void);
extern void age(naddr);
extern void ag_flush(naddr, naddr, void (*)(struct ag_info *));
extern void ag_check(naddr, naddr, naddr, naddr, char, char, u_int,
u_short, u_short, void (*)(struct ag_info *));
extern void del_static(naddr, naddr, int);
extern void del_redirects(naddr, time_t);
extern struct rt_entry *rtget(naddr, naddr);
extern struct rt_entry *rtfind(naddr);
extern void rtinit(void);
extern void rtadd(naddr, naddr, naddr, naddr,
int, u_short, u_int, struct interface *);
extern void rtchange(struct rt_entry *, u_int, naddr,naddr, int, u_short,
struct interface *ifp, time_t, char *);
extern void rtdelete(struct rt_entry *);
extern void rtbad_sub(struct rt_entry *);
extern void rtswitch(struct rt_entry *, struct rt_spare *);
extern void rtbad(struct rt_entry *);
#define S_ADDR(x) (((struct sockaddr_in *)(x))->sin_addr.s_addr)
#define INFO_DST(I) ((I)->rti_info[RTAX_DST])
#define INFO_GATE(I) ((I)->rti_info[RTAX_GATEWAY])
#define INFO_MASK(I) ((I)->rti_info[RTAX_NETMASK])
#define INFO_IFA(I) ((I)->rti_info[RTAX_IFA])
#define INFO_IFP(I) ((I)->rti_info[RTAX_IFP])
#define INFO_AUTHOR(I) ((I)->rti_info[RTAX_AUTHOR])
#define INFO_BRD(I) ((I)->rti_info[RTAX_BRD])
void rt_xaddrs(struct rt_addrinfo *, struct sockaddr *, struct sockaddr *,
int);
extern naddr std_mask(naddr);
extern naddr ripv1_mask_net(naddr, struct interface *);
extern naddr ripv1_mask_host(naddr,struct interface *);
#define on_net(a,net,mask) (((ntohl(a) ^ (net)) & (mask)) == 0)
extern int check_dst(naddr);
extern void addrouteforif(register struct interface *);
extern void ifinit(void);
extern int walk_bad(struct radix_node *, struct walkarg *);
extern int if_ok(struct interface *, char *);
extern void if_sick(struct interface *);
extern void if_bad(struct interface *);
extern struct interface *ifwithaddr(naddr, int, int);
extern struct interface *ifwithname(char *, naddr);
extern struct interface *ifwithindex(u_short);
extern struct interface *iflookup(naddr);

File diff suppressed because it is too large Load Diff

View File

@ -1,714 +0,0 @@
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.1.3.3 $"
#include "defs.h"
static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
static void input_route(struct interface *, naddr,
naddr, naddr, naddr, struct netinfo *);
/* process RIP input
*/
void
read_rip(int sock,
struct interface *ifp)
{
struct sockaddr_in from;
int fromlen, cc;
union pkt_buf inbuf;
for (;;) {
fromlen = sizeof(from);
cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
(struct sockaddr*)&from, &fromlen);
if (cc <= 0) {
if (cc < 0 && errno != EWOULDBLOCK)
LOGERR("recvfrom(rip)");
break;
}
if (fromlen != sizeof(struct sockaddr_in))
logbad(1,"impossible recvfrom(rip) fromlen=%d",
fromlen);
input(&from,
(ifp != 0) ? ifp : iflookup(from.sin_addr.s_addr),
&inbuf.rip, cc);
}
}
/* Process a RIP packet
*/
static void
input(struct sockaddr_in *from, /* received from this IP address */
struct interface *ifp,
struct rip *rip,
int size)
{
# define FROM_NADDR from->sin_addr.s_addr
static naddr use_auth, bad_len, bad_mask;
static naddr unk_router, bad_router, bad_nhop;
struct rt_entry *rt;
struct netinfo *n, *lim;
struct interface *ifp1;
naddr gate, mask, v1_mask, dst, ddst_h;
int i;
if (ifp != 0)
ifp->int_state |= IS_ACTIVE;
trace_rip("Recv", "from", from, ifp, rip, size);
if (rip->rip_vers == 0) {
if (from->sin_addr.s_addr != bad_router)
msglog("RIP version 0, cmd %d, packet received"
" from %s",
rip->rip_cmd, naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
return;
}
if (size > MAXPACKETSIZE) {
if (from->sin_addr.s_addr != bad_router)
msglog("packet at least %d bytes too long received"
" from %s",
size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
return;
}
n = rip->rip_nets;
lim = (struct netinfo *)((char*)rip + size);
/* Notice authentication.
* As required by section 4.2 in RFC 1723, discard authenticated
* RIPv2 messages, but only if configured for that silliness.
*
* RIPv2 authentication is lame, since snooping on the wire makes
* its simple passwords evident. Also, why authenticate queries?
* Why should a RIPv2 implementation with authentication disabled
* not be able to listen to RIPv2 packets with authenication, while
* RIPv1 systems will listen? Crazy!
*/
if (!auth_ok
&& rip->rip_vers >= RIPv2
&& n < lim && n->n_family == RIP_AF_AUTH) {
if (from->sin_addr.s_addr != use_auth)
msglog("RIPv2 message with authentication"
" from %s discarded",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
trace_pkt("discard authenticated RIPv2 message\n");
return;
}
switch (rip->rip_cmd) {
case RIPCMD_REQUEST:
/* did the request come from a router?
*/
if (from->sin_port == htons(RIP_PORT)) {
/* yes, ignore it if RIP is off so that it does not
* depend on us.
*/
if (rip_sock < 0) {
trace_pkt("ignore request while RIP off\n");
return;
}
/* Ignore the request if we talking to ourself
* (and not a remote gateway).
*/
if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
trace_pkt("discard our own RIP request\n");
return;
}
}
/* According to RFC 1723, we should ignore unathenticated
* queries. That is too silly to bother with. Sheesh!
* Are forwarding tables supposed to be secret? When
* a bad guy can infer them with test traffic?
* Maybe on firewalls you'd care, but not enough to
* give up the diagnostic facilities of remote probing.
*/
if (n >= lim
|| size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
if (from->sin_addr.s_addr != bad_len)
msglog("request of bad length (%d) from %s",
size, naddr_ntoa(FROM_NADDR));
bad_len = from->sin_addr.s_addr;
}
for (; n < lim; n++) {
n->n_metric = ntohl(n->n_metric);
/* A single entry with family RIP_AF_UNSPEC and
* metric HOPCNT_INFINITY means "all routes".
* We respond to routers only if we are acting
* as a supplier, or to anyone other than a router
* (i.e. a query).
*
* Answer a query from a stray program with all
* we know. Filter the answer to a query from a
* router in the about same way broadcasts are
* filtered.
*
* Only answer a router if we are a supplier
* to keep an unwary host that is just starting
* from picking us an a router.
*/
if (n->n_family == RIP_AF_UNSPEC
&& n->n_metric == HOPCNT_INFINITY
&& n == rip->rip_nets
&& n+1 == lim) {
if (from->sin_port != htons(RIP_PORT)) {
/* query from `rtquery` or similar
*/
supply(from, ifp,
OUT_QUERY, 0, rip->rip_vers);
} else if (supplier) {
/* a router trying to prime its
* tables.
*/
supply(from, ifp,
OUT_UNICAST, 0, rip->rip_vers);
}
return;
}
if (n->n_family != RIP_AF_INET) {
if (from->sin_addr.s_addr != bad_router)
msglog("request from %s"
" for unsupported (af %d) %s",
naddr_ntoa(FROM_NADDR),
ntohs(n->n_family),
naddr_ntoa(n->n_dst));
bad_router = from->sin_addr.s_addr;
return;
}
dst = n->n_dst;
if (!check_dst(dst)) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad queried destination"
" %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
return;
}
if (rip->rip_vers == RIPv1
|| 0 == (mask = ntohl(n->n_mask))
|| 0 != (ntohl(dst) & ~mask))
mask = ripv1_mask_host(dst,ifp);
rt = rtget(dst, mask);
if (!rt && dst != RIP_DEFAULT)
rt = rtfind(n->n_dst);
n->n_tag = 0;
n->n_nhop = 0;
if (rip->rip_vers == RIPv1) {
n->n_mask = 0;
} else {
n->n_mask = mask;
}
if (rt == 0) {
n->n_metric = HOPCNT_INFINITY;
} else {
n->n_metric = rt->rt_metric+1;
n->n_metric += (ifp!=0) ? ifp->int_metric : 1;
if (n->n_metric > HOPCNT_INFINITY)
n->n_metric = HOPCNT_INFINITY;
if (rip->rip_vers != RIPv1) {
n->n_tag = rt->rt_tag;
if (ifp != 0
&& on_net(rt->rt_gate,
ifp->int_net,
ifp->int_mask)
&& rt->rt_gate != ifp->int_addr)
n->n_nhop = rt->rt_gate;
}
}
HTONL(n->n_metric);
}
/* Answer about specific routes.
* Only answer a router if we are a supplier
* to keep an unwary host that is just starting
* from picking us an a router.
*/
rip->rip_cmd = RIPCMD_RESPONSE;
rip->rip_res1 = 0;
if (rip->rip_vers != RIPv1)
rip->rip_vers = RIPv2;
if (from->sin_port != htons(RIP_PORT)) {
/* query */
(void)output(OUT_QUERY, from, ifp, rip, size);
} else if (supplier) {
(void)output(OUT_UNICAST, from, ifp, rip, size);
}
return;
case RIPCMD_TRACEON:
case RIPCMD_TRACEOFF:
/* verify message came from a privileged port */
if (ntohs(from->sin_port) > IPPORT_RESERVED) {
msglog("trace command from untrusted port on %s",
naddr_ntoa(FROM_NADDR));
return;
}
if (ifp == 0) {
msglog("trace command from unknown router %s",
naddr_ntoa(FROM_NADDR));
return;
}
if (rip->rip_cmd == RIPCMD_TRACEON) {
rip->rip_tracefile[size-4] = '\0';
trace_on((char*)rip->rip_tracefile, 0);
} else {
trace_off("tracing turned off by %s\n",
naddr_ntoa(FROM_NADDR));
}
return;
case RIPCMD_RESPONSE:
if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
if (from->sin_addr.s_addr != bad_len)
msglog("response of bad length (%d) from %s",
size, naddr_ntoa(FROM_NADDR));
bad_len = from->sin_addr.s_addr;
}
/* verify message came from a router */
if (from->sin_port != ntohs(RIP_PORT)) {
trace_pkt("discard RIP response from unknown port\n");
return;
}
if (rip_sock < 0) {
trace_pkt("discard response while RIP off\n");
return;
}
/* Are we talking to ourself or a remote gateway?
*/
ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
if (ifp1) {
if (ifp1->int_state & IS_REMOTE) {
if (ifp1->int_state & IS_PASSIVE) {
msglog("bogus input from %s on"
" supposedly passive %s",
naddr_ntoa(FROM_NADDR),
ifp1->int_name);
} else {
ifp1->int_act_time = now.tv_sec;
if (if_ok(ifp1, "remote "))
addrouteforif(ifp1);
}
} else {
trace_pkt("discard our own RIP response\n");
}
return;
}
/* Check the 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 (from->sin_addr.s_addr != unk_router)
msglog("packet from unknown router %s"
" or via unidentified interface",
naddr_ntoa(FROM_NADDR));
unk_router = from->sin_addr.s_addr;
return;
}
if (ifp->int_state & IS_PASSIVE) {
trace_act("packet from %s via passive interface %s\n",
naddr_ntoa(FROM_NADDR),
ifp->int_name);
return;
}
/* Check required version
*/
if (((ifp->int_state & IS_NO_RIPV1_IN)
&& rip->rip_vers == RIPv1)
|| ((ifp->int_state & IS_NO_RIPV2_IN)
&& rip->rip_vers != RIPv1)) {
trace_pkt("discard RIPv%d response\n",
rip->rip_vers);
return;
}
/* Ignore routes via dead interface.
*/
if (ifp->int_state & IS_BROKE) {
trace_pkt("discard response via broken interface %s\n",
ifp->int_name);
return;
}
/* Authenticate the packet if we have a secret.
*/
if (ifp->int_passwd[0] != '\0') {
if (n >= lim
|| n->n_family != RIP_AF_AUTH
|| ((struct netauth*)n)->a_type != RIP_AUTH_PW) {
if (from->sin_addr.s_addr != use_auth)
msglog("missing password from %s",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
return;
} else if (0 != bcmp(((struct netauth*)n)->au.au_pw,
ifp->int_passwd,
sizeof(ifp->int_passwd))) {
if (from->sin_addr.s_addr != use_auth)
msglog("bad password from %s",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
return;
}
}
for (; n < lim; n++) {
if (n->n_family == RIP_AF_AUTH)
continue;
NTOHL(n->n_metric);
dst = n->n_dst;
if (n->n_family != RIP_AF_INET
&& (n->n_family != RIP_AF_UNSPEC
|| dst != RIP_DEFAULT)) {
if (from->sin_addr.s_addr != bad_router)
msglog("route from %s to unsupported"
" address family %d,"
" destination %s",
naddr_ntoa(FROM_NADDR),
n->n_family,
naddr_ntoa(dst));
bad_router = from->sin_addr.s_addr;
continue;
}
if (!check_dst(dst)) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad destination %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
return;
}
if (n->n_metric == 0
|| n->n_metric > HOPCNT_INFINITY) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad metric %d from %s"
" for destination %s",
n->n_metric,
naddr_ntoa(FROM_NADDR),
naddr_ntoa(dst));
bad_router = from->sin_addr.s_addr;
return;
}
/* Notice the next-hop.
*/
gate = from->sin_addr.s_addr;
if (n->n_nhop != 0
&& rip->rip_vers == RIPv2) {
/* Ignore the route if it points to us */
if (0 != ifwithaddr(n->n_nhop, 1, 0))
continue;
/* Use it only if it is valid. */
if (on_net(n->n_nhop,
ifp->int_net, ifp->int_mask)
&& check_dst(n->n_nhop)) {
gate = n->n_nhop;
} else {
if (bad_nhop != from->sin_addr.s_addr)
msglog("router %s to %s has"
" bad next hop %s",
naddr_ntoa(FROM_NADDR),
naddr_ntoa(dst),
naddr_ntoa(n->n_nhop));
bad_nhop = from->sin_addr.s_addr;
}
}
if (rip->rip_vers == RIPv1
|| 0 == (mask = ntohl(n->n_mask))) {
mask = ripv1_mask_host(dst,ifp);
} else if ((ntohl(dst) & ~mask) != 0) {
if (bad_mask != from->sin_addr.s_addr) {
msglog("router %s sent bad netmask"
" %#x with %s",
naddr_ntoa(FROM_NADDR),
mask,
naddr_ntoa(dst));
bad_mask = from->sin_addr.s_addr;
}
continue;
}
if (rip->rip_vers == RIPv1)
n->n_tag = 0;
/* Adjust metric according to incoming interface..
*/
n->n_metric += ifp->int_metric;
if (n->n_metric > HOPCNT_INFINITY)
n->n_metric = HOPCNT_INFINITY;
/* Recognize and ignore a default route we faked
* which is being sent back to us by a machine with
* broken split-horizon.
* Be a little more paranoid than that, and reject
* default routes with the same metric we advertised.
*/
if (ifp->int_d_metric != 0
&& dst == RIP_DEFAULT
&& n->n_metric >= ifp->int_d_metric)
continue;
/* We can receive aggregated RIPv2 routes that must
* be broken down before they are transmitted by
* RIPv1 via an interface on a subnet.
* We might also receive the same routes aggregated
* via other RIPv2 interfaces.
* This could cause duplicate routes to be sent on
* the RIPv1 interfaces. "Longest matching variable
* length netmasks" lets RIPv2 listeners understand,
* but breaking down the aggregated routes for RIPv1
* listeners can produce duplicate routes.
*
* Breaking down aggregated routes here bloats
* the daemon table, but does not hurt the kernel
* table, since routes are always aggregated for
* the kernel.
*
* Notice that this does not break down network
* routes corresponding to subnets. This is part
* of the defense against RS_NET_SYN.
*/
if (have_ripv1_out
&& (v1_mask = ripv1_mask_net(dst,0)) > mask
&& (((rt = rtget(dst,mask)) == 0
|| !(rt->rt_state & RS_NET_SYN)))) {
ddst_h = v1_mask & -v1_mask;
i = (v1_mask & ~mask)/ddst_h;
if (i >= 511) {
/* Punt if we would have to generate
* an unreasonable number of routes.
*/
#ifdef DEBUG
msglog("accept %s from %s as 1"
" instead of %d routes",
addrname(dst,mask,0),
naddr_ntoa(FROM_NADDR),
i+1);
#endif
i = 0;
} else {
mask = v1_mask;
}
} else {
i = 0;
}
for (;;) {
input_route(ifp, FROM_NADDR,
dst, mask, gate, n);
if (i-- == 0)
break;
dst = htonl(ntohl(dst) + ddst_h);
}
}
break;
}
}
/* Process a single input route.
*/
static void
input_route(struct interface *ifp,
naddr from,
naddr dst,
naddr mask,
naddr gate,
struct netinfo *n)
{
int i;
struct rt_entry *rt;
struct rt_spare *rts, *rts0;
struct interface *ifp1;
time_t new_time;
/* See if the other guy is telling us to send our packets to him.
* Sometimes network routes arrive over a point-to-point link for
* the network containing the address(es) of the link.
*
* If our interface is broken, switch to using the other guy.
*/
ifp1 = ifwithaddr(dst, 1, 1);
if (ifp1 != 0
&& !(ifp1->int_state & IS_BROKE))
return;
/* Look for the route in our table.
*/
rt = rtget(dst, mask);
/* Consider adding the route if we do not already have it.
*/
if (rt == 0) {
/* Ignore unknown routes being poisoned.
*/
if (n->n_metric == HOPCNT_INFINITY)
return;
if (total_routes < MAX_ROUTES)
rtadd(dst, mask, gate, from, n->n_metric,
n->n_tag, 0, ifp);
return;
}
/* We already know about the route. Consider this update.
*
* If (rt->rt_state & RS_NET_SYN), then this route
* is the same as a network route we have inferred
* for subnets we know, in order to tell RIPv1 routers
* about the subnets.
*
* It is impossible to tell if the route is coming
* from a distant RIPv2 router with the standard
* netmask because that router knows about the entire
* network, or if it is a round-about echo of a
* synthetic, RIPv1 network route of our own.
* The worst is that both kinds of routes might be
* received, and the bad one might have the smaller
* metric. Partly solve this problem by faking the
* RIPv1 route with a metric that reflects the most
* distant part of the subnet. Also never
* aggregate into such a route. Also keep it
* around as long as the interface exists.
*/
rts0 = rt->rt_spares;
for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
if (rts->rts_router == from)
break;
/* Note the worst slot to reuse,
* other than the current slot.
*/
if (rts0 == rt->rt_spares
|| BETTER_LINK(rt, rts0, rts))
rts0 = rts;
}
if (i != 0) {
/* Found the router
*/
int old_metric = rts->rts_metric;
/* Keep poisoned routes around only long enough to pass
* the poison on. Get a new timestamp for good routes.
*/
new_time =((old_metric == HOPCNT_INFINITY)
? rts->rts_time
: now.tv_sec);
/* If this is an update for the router we currently prefer,
* then note it.
*/
if (i == NUM_SPARES) {
rtchange(rt,rt->rt_state, gate,rt->rt_router,
n->n_metric, n->n_tag, ifp, new_time, 0);
/* If the route got worse, check for something better.
*/
if (n->n_metric > old_metric)
rtswitch(rt, 0);
return;
}
/* This is an update for a spare route.
* Finished if the route is unchanged.
*/
if (rts->rts_gate == gate
&& old_metric == n->n_metric
&& rts->rts_tag == n->n_tag) {
rts->rts_time = new_time;
return;
}
} else {
/* The update is for a route we know about,
* but not from a familiar router.
*/
rts = rts0;
/* Save the route as a spare only if it has
* a better metric than our worst spare.
* This also ignores poisoned routes (those
* received with metric HOPCNT_INFINITY).
*/
if (n->n_metric >= rts->rts_metric)
return;
new_time = now.tv_sec;
}
trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
rts->rts_gate = gate;
rts->rts_router = from;
rts->rts_metric = n->n_metric;
rts->rts_tag = n->n_tag;
rts->rts_time = new_time;
rts->rts_ifp = ifp;
/* try to switch to a better route */
rtswitch(rt, rts);
}

View File

@ -1,824 +0,0 @@
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
char copyright[] =
"@(#) Copyright (c) 1983, 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.1.3.3 $"
#include "defs.h"
#include "pathnames.h"
#ifdef sgi
#include "math.h"
#endif
#include <signal.h>
#include <fcntl.h>
#include <sys/file.h>
pid_t mypid;
naddr myaddr; /* system address */
char myname[MAXHOSTNAMELEN+1];
int supplier; /* supply or broadcast updates */
int supplier_set;
int ipforwarding = 1; /* kernel forwarding on */
int default_gateway; /* 1=advertise default */
int background = 1;
int ridhosts; /* 1=reduce host routes */
int mhome; /* 1=want multi-homed host route */
int advertise_mhome; /* 1=must continue adverising it */
int auth_ok = 1; /* 1=ignore auth if we do not care */
struct timeval epoch; /* when started */
struct timeval clk, prev_clk;
struct timeval now; /* current idea of time */
time_t now_stale;
time_t now_garbage;
struct timeval next_bcast; /* next general broadcast */
struct timeval no_flash = {EPOCH+SUPPLY_INTERVAL}; /* inhibit flash update */
fd_set fdbits;
int sock_max;
int rip_sock = -1; /* RIP socket */
struct interface *rip_sock_mcast; /* current multicast interface */
int rt_sock; /* routing socket */
int rt_sock_seqno;
static int get_rip_sock(naddr, int);
static void timevalsub(struct timeval *, struct timeval *, struct timeval *);
int
main(int argc,
char *argv[])
{
int n, mib[4], off;
size_t len;
char *p, *q;
struct timeval wtime, t2;
time_t dt;
fd_set ibits;
naddr p_addr, p_mask;
struct interface *ifp;
struct parm parm;
char *tracename = 0;
openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
ftrace = stdout;
gettimeofday(&clk, 0);
prev_clk = clk;
epoch = clk;
epoch.tv_sec -= EPOCH;
now.tv_sec = EPOCH;
now_stale = EPOCH - STALE_TIME;
now_garbage = EPOCH - GARBAGE_TIME;
wtime.tv_sec = 0;
(void)gethostname(myname, sizeof(myname)-1);
(void)gethost(myname, &myaddr);
while ((n = getopt(argc, argv, "sqdghmAtT:F:P:")) != EOF) {
switch (n) {
case 's':
supplier = 1;
supplier_set = 1;
break;
case 'q':
supplier = 0;
supplier_set = 1;
break;
case 'd':
background = 0;
break;
case 'g':
bzero(&parm, sizeof(parm));
parm.parm_d_metric = 1;
p = check_parms(&parm);
if (p != 0)
msglog("bad -g: %s", p);
else
default_gateway = 1;
break;
case 'h': /* suppress extra host routes */
ridhosts = 1;
break;
case 'm': /* advertise host route */
mhome = 1; /* on multi-homed hosts */
break;
case 'A':
/* Ignore authentication if we do not care.
* Crazy as it is, that is what RFC 1723 requires.
*/
auth_ok = 0;
break;
case 't':
new_tracelevel++;
break;
case 'T':
tracename = optarg;
break;
case 'F': /* minimal routes for SLIP */
n = HOPCNT_INFINITY-2;
p = strchr(optarg,',');
if (p && *p != '\0') {
n = (int)strtoul(p+1, &q, 0);
if (*q == '\0'
&& n <= HOPCNT_INFINITY-1
&& n >= 1)
*p = '\0';
}
if (!getnet(optarg, &p_addr, &p_mask)) {
msglog("bad network; \"-F %s\"",
optarg);
break;
}
bzero(&parm, sizeof(parm));
parm.parm_addr_h = ntohl(p_addr);
parm.parm_mask = p_mask;
parm.parm_d_metric = n;
p = check_parms(&parm);
if (p != 0)
msglog("bad -F: %s", p);
break;
case 'P':
/* handle arbirary, (usually) per-interface
* parameters.
*/
p = parse_parms(optarg);
if (p != 0)
msglog("bad \"%s\" in \"%s\"",
p, optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (tracename == 0 && argc >= 1) {
tracename = *argv++;
argc--;
}
if (argc != 0) {
usage:
logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]"
" [-F net[,metric]] [-P parms]");
}
if (geteuid() != 0)
logbad(0, "requires UID 0");
mib[0] = CTL_NET;
mib[1] = PF_INET;
mib[2] = IPPROTO_IP;
mib[3] = IPCTL_FORWARDING;
len = sizeof(ipforwarding);
if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0)
LOGERR("sysctl(IPCTL_FORWARDING)");
if (!ipforwarding) {
if (supplier)
msglog("-s incompatible with ipforwarding=0");
if (default_gateway) {
msglog("-g incompatible with ipforwarding=0");
default_gateway = 0;
}
supplier = 0;
supplier_set = 1;
}
if (default_gateway) {
if (supplier_set && !supplier) {
msglog("-g and -q incompatible");
} else {
supplier = 1;
supplier_set = 1;
}
}
/* get into the background */
if (background) {
#ifdef sgi
if (0 > _daemonize(_DF_NOCHDIR,
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
BADERR(0, "_daemonize()");
#else
if (daemon(1, 1) < 0)
BADERR(0,"daemon()");
#endif
}
mypid = getpid();
srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid));
/* prepare socket connected to the kernel.
*/
rt_sock = socket(AF_ROUTE, SOCK_RAW, 0);
if (rt_sock < 0)
BADERR(1,"rt_sock = socket()");
if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1)
logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno));
off = 0;
if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK,
&off,sizeof(off)) < 0)
LOGERR("setsockopt(SO_USELOOPBACK,0)");
fix_select();
if (background && new_tracelevel == 0)
ftrace = 0;
if (tracename != 0) {
trace_on(tracename, 1);
if (new_tracelevel == 0) /* use stdout if file is bad */
new_tracelevel = 1;
}
set_tracelevel();
/* initialize radix tree */
rtinit();
/* Pick a random part of the second for our output to minimize
* collisions.
*
* Start broadcasting after hearing from other routers, and
* at a random time so a bunch of systems do not get synchronized
* after a power failure.
*/
intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL);
age_timer.tv_usec = next_bcast.tv_usec;
age_timer.tv_sec = EPOCH+MIN_WAITTIME;
rdisc_timer = next_bcast;
ifinit_timer.tv_usec = next_bcast.tv_usec;
signal(SIGALRM, sigalrm);
signal(SIGHUP, sigterm);
signal(SIGTERM, sigterm);
signal(SIGINT, sigterm);
signal(SIGUSR1, sigtrace_on);
signal(SIGUSR2, sigtrace_off);
/* Collect an initial view of the world by checking the interface
* configuration and the kludge file.
*/
gwkludge();
ifinit();
flush_kern();
/* Ask for routes */
rip_query();
if (!supplier)
rdisc_sol();
/* Loop forever, listening and broadcasting.
*/
for (;;) {
prev_clk = clk;
gettimeofday(&clk, 0);
timevalsub(&t2, &clk, &prev_clk);
if (t2.tv_sec < 0
|| t2.tv_sec > wtime.tv_sec + 5) {
/* Deal with time changes before other housekeeping to
* keep everything straight.
*/
dt = t2.tv_sec;
if (dt > 0)
dt -= wtime.tv_sec;
trace_act("time changed by %d sec\n", dt);
epoch.tv_sec += dt;
}
timevalsub(&now, &clk, &epoch);
now_stale = now.tv_sec - STALE_TIME;
now_garbage = now.tv_sec - GARBAGE_TIME;
/* deal with interrupts that should affect tracing */
set_tracelevel();
if (stopint != 0) {
if (supplier) {
rip_bcast(0);
rdisc_adv();
}
trace_off("exiting with signal %d\n", stopint);
exit(stopint | 128);
}
/* look for new or dead interfaces */
timevalsub(&wtime, &ifinit_timer, &now);
if (wtime.tv_sec <= 0) {
wtime.tv_sec = 0;
ifinit();
rip_query();
continue;
}
/* If it is time, then broadcast our routes.
*/
if (supplier || advertise_mhome) {
timevalsub(&t2, &next_bcast, &now);
if (t2.tv_sec <= 0) {
/* Synchronize the aging and broadcast
* timers to minimize awakenings
*/
age(0);
rip_bcast(0);
/* It is desirable to send routing updates
* regularly. So schedule the next update
* 30 seconds after the previous one was
* secheduled, instead of 30 seconds after
* the previous update was finished.
* Even if we just started after discovering
* a 2nd interface or were otherwise delayed,
* pick a 30-second aniversary of the
* original broadcast time.
*/
n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL;
next_bcast.tv_sec += n*SUPPLY_INTERVAL;
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
}
/* If we need a flash update, either do it now or
* set the delay to end when it is time.
*
* If we are within MIN_WAITTIME seconds of a full update,
* do not bother.
*/
if (need_flash
&& supplier
&& no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) {
/* accurate to the millisecond */
if (!timercmp(&no_flash, &now, >))
rip_bcast(1);
timevalsub(&t2, &no_flash, &now);
if (timercmp(&t2, &wtime, <))
wtime = t2;
}
/* trigger the main aging timer.
*/
timevalsub(&t2, &age_timer, &now);
if (t2.tv_sec <= 0) {
age(0);
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* update the kernel routing table
*/
timevalsub(&t2, &need_kern, &now);
if (t2.tv_sec <= 0) {
age(0);
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* take care of router discovery,
* but do it to the millisecond
*/
if (!timercmp(&rdisc_timer, &now, >)) {
rdisc_age(0);
continue;
}
timevalsub(&t2, &rdisc_timer, &now);
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* wait for input or a timer to expire.
*/
trace_flush();
ibits = fdbits;
n = select(sock_max, &ibits, 0, 0, &wtime);
if (n <= 0) {
if (n < 0 && errno != EINTR && errno != EAGAIN)
BADERR(1,"select");
continue;
}
if (FD_ISSET(rt_sock, &ibits)) {
read_rt();
n--;
}
if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) {
read_d();
n--;
}
if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) {
read_rip(rip_sock, 0);
n--;
}
for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0
&& FD_ISSET(ifp->int_rip_sock, &ibits)) {
read_rip(ifp->int_rip_sock, ifp);
n--;
}
}
}
}
/* ARGSUSED */
void
sigalrm(int sig)
{
/* Historically, SIGALRM would cause the daemon to check for
* new and broken interfaces.
*/
ifinit_timer.tv_sec = now.tv_sec;
trace_act("SIGALRM\n");
}
/* watch for fatal signals */
void
sigterm(int sig)
{
stopint = sig;
(void)signal(sig, SIG_DFL); /* catch it only once */
}
void
fix_select(void)
{
struct interface *ifp;
FD_ZERO(&fdbits);
sock_max = 0;
FD_SET(rt_sock, &fdbits);
if (sock_max <= rt_sock)
sock_max = rt_sock+1;
if (rip_sock >= 0) {
FD_SET(rip_sock, &fdbits);
if (sock_max <= rip_sock)
sock_max = rip_sock+1;
}
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0) {
FD_SET(ifp->int_rip_sock, &fdbits);
if (sock_max <= ifp->int_rip_sock)
sock_max = ifp->int_rip_sock+1;
}
}
if (rdisc_sock >= 0) {
FD_SET(rdisc_sock, &fdbits);
if (sock_max <= rdisc_sock)
sock_max = rdisc_sock+1;
}
}
void
fix_sock(int sock,
char *name)
{
int on;
#define MIN_SOCKBUF (4*1024)
static int rbuf;
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
logbad(1, "fcntl(%s) O_NONBLOCK: %s",
name, strerror(errno));
on = 1;
if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST,
&on,sizeof(on)) < 0)
msglog("setsockopt(%s,SO_BROADCAST): %s",
name, strerror(errno));
if (rbuf >= MIN_SOCKBUF) {
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&rbuf, sizeof(rbuf)) < 0)
msglog("setsockopt(%s,SO_RCVBUF=%d): %s",
name, rbuf, strerror(errno));
} else {
for (rbuf = 60*1024; ; rbuf -= 4096) {
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&rbuf, sizeof(rbuf)) == 0) {
trace_act("RCVBUF=%d\n", rbuf);
break;
}
if (rbuf < MIN_SOCKBUF) {
msglog("setsockopt(%s,SO_RCVBUF = %d): %s",
name, rbuf, strerror(errno));
break;
}
}
}
}
/* get a rip socket
*/
static int /* <0 or file descriptor */
get_rip_sock(naddr addr,
int serious) /* 1=failure to bind is serious */
{
struct sockaddr_in sin;
unsigned char ttl;
int s;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
BADERR(1,"rip_sock = socket()");
bzero(&sin,sizeof(sin));
#ifdef _HAVE_SIN_LEN
sin.sin_len = sizeof(sin);
#endif
sin.sin_family = AF_INET;
sin.sin_port = htons(RIP_PORT);
sin.sin_addr.s_addr = addr;
if (bind(s, (struct sockaddr *)&sin,sizeof(sin)) < 0) {
if (serious)
BADERR(errno != EADDRINUSE, "bind(rip_sock)");
return -1;
}
fix_sock(s,"rip_sock");
ttl = 1;
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl)) < 0)
DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)");
return s;
}
/* turn off main RIP socket */
void
rip_off(void)
{
struct interface *ifp;
register naddr addr;
if (rip_sock >= 0 && !mhome) {
trace_act("turn off RIP\n");
(void)close(rip_sock);
rip_sock = -1;
/* get non-broadcast sockets to listen to queries.
*/
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (ifp->int_rip_sock < 0
&& !(ifp->int_state & IS_ALIAS)) {
addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
ifp->int_rip_sock = get_rip_sock(addr, 0);
}
}
fix_select();
age(0);
}
}
/* turn on RIP multicast input via an interface
*/
static void
rip_mcast_on(struct interface *ifp)
{
struct ip_mreq m;
if (!IS_RIP_IN_OFF(ifp->int_state)
&& (ifp->int_if_flags & IFF_MULTICAST)
#ifdef MCAST_PPP_BUG
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
#endif
&& !(ifp->int_state & IS_ALIAS)) {
m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
&m, sizeof(m)) < 0)
LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
}
}
/* Prepare socket used for RIP.
*/
void
rip_on(struct interface *ifp)
{
/* If the main RIP socket is already alive, only start receiving
* multicasts for this interface.
*/
if (rip_sock >= 0) {
if (ifp != 0)
rip_mcast_on(ifp);
return;
}
/* If the main RIP socket is off, and it makes sense to turn it on,
* turn it on for all of the interfaces.
*/
if (rip_interfaces > 0 && !rdisc_ok) {
trace_act("turn on RIP\n");
/* Close all of the query sockets so that we can open
* the main socket. SO_REUSEPORT is not a solution,
* since that would let two daemons bind to the broadcast
* socket.
*/
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0) {
(void)close(ifp->int_rip_sock);
ifp->int_rip_sock = -1;
}
}
rip_sock = get_rip_sock(INADDR_ANY, 1);
rip_sock_mcast = 0;
/* Do not advertise anything until we have heard something
*/
if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME)
next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (!IS_RIP_IN_OFF(ifp->int_state))
ifp->int_state &= ~IS_RIP_QUERIED;
rip_mcast_on(ifp);
}
ifinit_timer.tv_sec = now.tv_sec;
fix_select();
} else if (ifp != 0
&& ifp->int_rip_sock < 0
&& !(ifp->int_state & IS_ALIAS)) {
/* RIP is off, so ensure there are sockets on which
* to listen for queries.
*/
ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0);
fix_select();
}
}
/* die if malloc(3) fails
*/
void *
rtmalloc(size_t size,
char *msg)
{
void *p = malloc(size);
if (p == 0)
logbad(1,"malloc() failed in %s", msg);
return p;
}
/* get a random instant in an interval
*/
void
intvl_random(struct timeval *tp, /* put value here */
u_long lo, /* value is after this second */
u_long hi) /* and before this */
{
tp->tv_sec = (time_t)(hi == lo
? lo
: (lo + random() % ((hi - lo))));
tp->tv_usec = random() % 1000000;
}
void
timevaladd(struct timeval *t1,
struct timeval *t2)
{
t1->tv_sec += t2->tv_sec;
if ((t1->tv_usec += t2->tv_usec) > 1000000) {
t1->tv_sec++;
t1->tv_usec -= 1000000;
}
}
/* t1 = t2 - t3
*/
static void
timevalsub(struct timeval *t1,
struct timeval *t2,
struct timeval *t3)
{
t1->tv_sec = t2->tv_sec - t3->tv_sec;
if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) {
t1->tv_sec--;
t1->tv_usec += 1000000;
}
}
void
msglog(char *p, ...)
{
va_list args;
trace_flush();
va_start(args, p);
vsyslog(LOG_ERR, p, args);
if (ftrace != 0) {
if (ftrace == stdout)
(void)fputs("routed: ", ftrace);
(void)vfprintf(ftrace, p, args);
(void)fputc('\n', ftrace);
}
}
void
logbad(int dump, char *p, ...)
{
va_list args;
trace_flush();
va_start(args, p);
vsyslog(LOG_ERR, p, args);
(void)fputs("routed: ", stderr);
(void)vfprintf(stderr, p, args);
(void)fputs("; giving up\n",stderr);
(void)fflush(stderr);
if (dump)
abort();
exit(1);
}

View File

@ -1,858 +0,0 @@
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.1.3.3 $"
#include "defs.h"
int update_seqno;
/* walk the tree of routes with this for output
*/
struct {
struct sockaddr_in to;
naddr to_mask;
naddr to_net;
naddr to_std_mask;
naddr to_std_net;
struct interface *ifp; /* usually output interface */
struct ws_buf { /* info for each buffer */
struct rip *buf;
struct netinfo *n;
struct netinfo *base;
struct netinfo *lim;
enum output_type type;
} v12, v2;
char metric; /* adjust metrics by interface */
int npackets;
int gen_limit;
u_int state;
#define WS_ST_FLASH 0x001 /* send only changed routes */
#define WS_ST_RIP2_SAFE 0x002 /* send RIPv2 safe for RIPv1 */
#define WS_ST_RIP2_ALL 0x004 /* send full featured RIPv2 */
#define WS_ST_AG 0x008 /* ok to aggregate subnets */
#define WS_ST_SUPER_AG 0x010 /* ok to aggregate networks */
#define WS_ST_SUB_AG 0x020 /* aggregate subnets in odd case */
#define WS_ST_QUERY 0x040 /* responding to a query */
#define WS_ST_TO_ON_NET 0x080 /* sending onto one of our nets */
#define WS_ST_DEFAULT 0x100 /* faking a default */
#define WS_ST_PM_RDISC 0x200 /* poor-man's router discovery */
} ws;
/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */
union pkt_buf ripv12_buf;
/* Another for only RIPv2 listeners */
union pkt_buf rip_v2_buf;
/* Send the contents of the global buffer via the non-multicast socket
*/
int /* <0 on failure */
output(enum output_type type,
struct sockaddr_in *dst, /* send to here */
struct interface *ifp,
struct rip *buf,
int size) /* this many bytes */
{
struct sockaddr_in sin;
int flags;
char *msg;
int res;
naddr tgt_mcast;
int soc;
int serrno;
sin = *dst;
if (sin.sin_port == 0)
sin.sin_port = htons(RIP_PORT);
#ifdef _HAVE_SIN_LEN
if (sin.sin_len == 0)
sin.sin_len = sizeof(sin);
#endif
soc = rip_sock;
flags = 0;
switch (type) {
case OUT_QUERY:
msg = "Answer Query";
if (soc < 0)
soc = ifp->int_rip_sock;
break;
case OUT_UNICAST:
msg = "Send";
if (soc < 0)
soc = ifp->int_rip_sock;
flags = MSG_DONTROUTE;
break;
case OUT_BROADCAST:
if (ifp->int_if_flags & IFF_POINTOPOINT) {
msg = "Send";
} else {
msg = "Send bcast";
}
flags = MSG_DONTROUTE;
break;
case OUT_MULTICAST:
if (ifp->int_if_flags & IFF_POINTOPOINT) {
msg = "Send pt-to-pt";
} else if (ifp->int_state & IS_DUP) {
trace_act("abort multicast output via %s"
" with duplicate address\n",
ifp->int_name);
return 0;
} else {
msg = "Send mcast";
if (rip_sock_mcast != ifp) {
#ifdef MCAST_PPP_BUG
/* Do not specifiy the primary interface
* explicitly if we have the multicast
* point-to-point kernel bug, since the
* kernel will do the wrong thing if the
* local address of a point-to-point link
* is the same as the address of an ordinary
* interface.
*/
if (ifp->int_addr == myaddr) {
tgt_mcast = 0;
} else
#endif
tgt_mcast = ifp->int_addr;
if (0 > setsockopt(rip_sock,
IPPROTO_IP, IP_MULTICAST_IF,
&tgt_mcast,
sizeof(tgt_mcast))) {
serrno = errno;
LOGERR("setsockopt(rip_sock,"
"IP_MULTICAST_IF)");
errno = serrno;
ifp = 0;
return -1;
}
rip_sock_mcast = ifp;
}
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
}
case NO_OUT_MULTICAST:
case NO_OUT_RIPV2:
break;
}
trace_rip(msg, "to", &sin, ifp, buf, size);
res = sendto(soc, buf, size, flags,
(struct sockaddr *)&sin, sizeof(sin));
if (res < 0
&& (ifp == 0 || !(ifp->int_state & IS_BROKE))) {
serrno = errno;
msglog("%s sendto(%s%s%s.%d): %s", msg,
ifp != 0 ? ifp->int_name : "",
ifp != 0 ? ", " : "",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port),
strerror(errno));
errno = serrno;
}
return res;
}
/* install authentication if appropriate
*/
static void
set_auth(struct ws_buf *w)
{
if (ws.ifp != 0
&& ws.ifp->int_passwd[0] != '\0'
&& (ws.state & WS_ST_RIP2_SAFE)) {
w->n->n_family = RIP_AF_AUTH;
((struct netauth*)w->n)->a_type = RIP_AUTH_PW;
bcopy(ws.ifp->int_passwd, ((struct netauth*)w->n)->au.au_pw,
sizeof(((struct netauth*)w->n)->au.au_pw));
w->n++;
}
}
/* Send the buffer
*/
static void
supply_write(struct ws_buf *wb)
{
/* Output multicast only if legal.
* If we would multcast and it would be illegal, then discard the
* packet.
*/
switch (wb->type) {
case NO_OUT_MULTICAST:
trace_pkt("skip multicast to %s because impossible\n",
naddr_ntoa(ws.to.sin_addr.s_addr));
break;
case NO_OUT_RIPV2:
break;
default:
if (output(wb->type, &ws.to, ws.ifp, wb->buf,
((char *)wb->n - (char*)wb->buf)) < 0
&& ws.ifp != 0)
if_sick(ws.ifp);
ws.npackets++;
break;
}
bzero(wb->n = wb->base, sizeof(*wb->n)*NETS_LEN);
if (wb->buf->rip_vers == RIPv2)
set_auth(wb);
}
/* put an entry into the packet
*/
static void
supply_out(struct ag_info *ag)
{
int i;
naddr mask, v1_mask, s_mask, dst_h, ddst_h;
struct ws_buf *wb;
/* Skip this route if doing a flash update and it and the routes
* it aggregates have not changed recently.
*/
if (ag->ag_seqno < update_seqno
&& (ws.state & WS_ST_FLASH))
return;
/* Skip this route if required by split-horizon
*/
if (ag->ag_state & AGS_SPLIT_HZ)
return;
dst_h = ag->ag_dst_h;
mask = ag->ag_mask;
v1_mask = ripv1_mask_host(htonl(dst_h),
(ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0);
s_mask = std_mask(htonl(dst_h));
i = 0;
/* If we are sending RIPv2 packets that cannot (or must not) be
* heard by RIPv1 listeners, do not worry about sub- or supernets.
* Subnets (from other networks) can only be sent via multicast.
* A pair of subnet routes might have been promoted so that they
* are legal to send by RIPv1.
* If RIPv1 is off, use the multicast buffer, unless this is the
* fake default route and it is acting as a poor-man's router-
* discovery mechanism.
*/
if (((ws.state & WS_ST_RIP2_ALL)
&& (dst_h != RIP_DEFAULT || !(ws.state & WS_ST_PM_RDISC)))
|| ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) {
/* use the RIPv2-only buffer */
wb = &ws.v2;
} else {
/* use the RIPv1-or-RIPv2 buffer */
wb = &ws.v12;
/* Convert supernet route into corresponding set of network
* routes for RIPv1, but leave non-contiguous netmasks
* to ag_check().
*/
if (v1_mask > mask
&& mask + (mask & -mask) == 0) {
ddst_h = v1_mask & -v1_mask;
i = (v1_mask & ~mask)/ddst_h;
if (i > ws.gen_limit) {
/* Punt if we would have to generate an
* unreasonable number of routes.
*/
#ifdef DEBUG
msglog("sending %s to %s as 1 instead"
" of %d routes",
addrname(htonl(dst_h),mask,1),
naddr_ntoa(ws.to.sin_addr.s_addr),
i+1);
#endif
i = 0;
} else {
mask = v1_mask;
ws.gen_limit -= i;
}
}
}
do {
wb->n->n_family = RIP_AF_INET;
wb->n->n_dst = htonl(dst_h);
/* If the route is from router-discovery or we are
* shutting down, admit only a bad metric.
*/
wb->n->n_metric = ((stopint || ag->ag_metric < 1)
? HOPCNT_INFINITY
: ag->ag_metric);
HTONL(wb->n->n_metric);
if (wb->buf->rip_vers == RIPv2) {
if (ag->ag_nhop != 0
&& (ws.state & WS_ST_RIP2_SAFE)
&& ((ws.state & WS_ST_QUERY)
|| (ag->ag_nhop != ws.ifp->int_addr
&& on_net(ag->ag_nhop,
ws.ifp->int_net,
ws.ifp->int_mask))))
wb->n->n_nhop = ag->ag_nhop;
if ((ws.state & WS_ST_RIP2_ALL)
|| mask != s_mask)
wb->n->n_mask = htonl(mask);
wb->n->n_tag = ag->ag_tag;
}
dst_h += ddst_h;
if (++wb->n >= wb->lim)
supply_write(wb);
} while (i-- != 0);
}
/* supply one route from the table
*/
/* ARGSUSED */
static int
walk_supply(struct radix_node *rn,
struct walkarg *w)
{
#define RT ((struct rt_entry *)rn)
u_short ags = 0;
char metric, pref;
naddr dst, nhop;
/* Do not advertise the loopback interface
* or external remote interfaces
*/
if (RT->rt_ifp != 0
&& ((RT->rt_ifp->int_if_flags & IFF_LOOPBACK)
|| (RT->rt_ifp->int_state & IS_EXTERNAL))
&& !(RT->rt_state & RS_MHOME))
return 0;
/* If being quiet about our ability to forward, then
* do not say anything unless responding to a query.
*/
if (!supplier && !(ws.state & WS_ST_QUERY))
return 0;
dst = RT->rt_dst;
/* do not collide with the fake default route */
if (dst == RIP_DEFAULT
&& (ws.state & WS_ST_DEFAULT))
return 0;
if (RT->rt_state & RS_NET_SYN) {
if (RT->rt_state & RS_NET_INT) {
/* Do not send manual synthetic network routes
* into the subnet.
*/
if (on_net(ws.to.sin_addr.s_addr,
ntohl(dst), RT->rt_mask))
return 0;
} else {
/* Do not send automatic synthetic network routes
* if they are not needed becaus no RIPv1 listeners
* can hear them.
*/
if (ws.state & WS_ST_RIP2_ALL)
return 0;
/* Do not send automatic synthetic network routes to
* the real subnet.
*/
if (on_net(ws.to.sin_addr.s_addr,
ntohl(dst), RT->rt_mask))
return 0;
}
nhop = 0;
} else {
/* Advertise the next hop if this is not a route for one
* of our interfaces and the next hop is on the same
* network as the target.
*/
if (!(RT->rt_state & RS_IF)
&& RT->rt_gate != myaddr
&& RT->rt_gate != loopaddr)
nhop = RT->rt_gate;
else
nhop = 0;
}
/* Adjust the outgoing metric by the cost of the link.
*/
pref = metric = RT->rt_metric + ws.metric;
if (pref < HOPCNT_INFINITY) {
/* Keep track of the best metric with which the
* route has been advertised recently.
*/
if (RT->rt_poison_metric >= metric
|| RT->rt_poison_time <= now_garbage) {
RT->rt_poison_time = now.tv_sec;
RT->rt_poison_metric = RT->rt_metric;
}
} else {
/* Do not advertise stable routes that will be ignored,
* unless they are being held down and poisoned. If the
* route recently was advertised with a metric that would
* have been less than infinity through this interface, we
* need to continue to advertise it in order to poison it.
*/
pref = RT->rt_poison_metric + ws.metric;
if (pref >= HOPCNT_INFINITY)
return 0;
metric = HOPCNT_INFINITY;
}
if (RT->rt_state & RS_MHOME) {
/* retain host route of multi-homed servers */
;
} else if (RT_ISHOST(RT)) {
/* We should always aggregate the host routes
* for the local end of our point-to-point links.
* If we are suppressing host routes in general, then do so.
* Avoid advertising host routes onto their own network,
* where they should be handled by proxy-ARP.
*/
if ((RT->rt_state & RS_LOCAL)
|| ridhosts
|| (ws.state & WS_ST_SUPER_AG)
|| on_net(dst, ws.to_net, ws.to_mask))
ags |= AGS_SUPPRESS;
if (ws.state & WS_ST_SUPER_AG)
ags |= AGS_PROMOTE;
} else if (ws.state & WS_ST_AG) {
/* Aggregate network routes, if we are allowed.
*/
ags |= AGS_SUPPRESS;
/* Generate supernets if allowed.
* If we can be heard by RIPv1 systems, we will
* later convert back to ordinary nets.
* This unifies dealing with received supernets.
*/
if ((RT->rt_state & RS_SUBNET)
|| (ws.state & WS_ST_SUPER_AG))
ags |= AGS_PROMOTE;
}
/* Do not send RIPv1 advertisements of subnets to other
* networks. If possible, multicast them by RIPv2.
*/
if ((RT->rt_state & RS_SUBNET)
&& !(ws.state & WS_ST_RIP2_ALL)
&& !on_net(dst, ws.to_std_net, ws.to_std_mask)) {
ags |= AGS_RIPV2 | AGS_PROMOTE;
if (ws.state & WS_ST_SUB_AG)
ags |= AGS_SUPPRESS;
}
/* Do not send a route back to where it came from, except in
* response to a query. This is "split-horizon". That means not
* advertising back to the same network and so via the same interface.
*
* We want to suppress routes that might have been fragmented
* from this route by a RIPv1 router and sent back to us, and so we
* cannot forget this route here. Let the split-horizon route
* aggregate (suppress) the fragmented routes and then itself be
* forgotten.
*
* Include the routes for both ends of point-to-point interfaces
* since the other side presumably knows them as well as we do.
*/
if (RT->rt_ifp == ws.ifp && ws.ifp != 0
&& !(ws.state & WS_ST_QUERY)
&& (ws.state & WS_ST_TO_ON_NET)
&& (!(RT->rt_state & RS_IF)
|| ws.ifp->int_if_flags & IFF_POINTOPOINT)) {
ags |= AGS_SPLIT_HZ;
ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
}
ag_check(dst, RT->rt_mask, 0, nhop, metric, pref,
RT->rt_seqno, RT->rt_tag, ags, supply_out);
return 0;
#undef RT
}
/* Supply dst with the contents of the routing tables.
* If this won't fit in one packet, chop it up into several.
*/
void
supply(struct sockaddr_in *dst,
struct interface *ifp, /* output interface */
enum output_type type,
int flash, /* 1=flash update */
int vers) /* RIP version */
{
static int init = 1;
struct rt_entry *rt;
ws.state = 0;
ws.gen_limit = 1024;
ws.to = *dst;
ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr);
ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask;
if (ifp != 0) {
ws.to_mask = ifp->int_mask;
ws.to_net = ifp->int_net;
if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask))
ws.state |= WS_ST_TO_ON_NET;
} else {
ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0);
ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask;
rt = rtfind(dst->sin_addr.s_addr);
if (rt)
ifp = rt->rt_ifp;
}
ws.npackets = 0;
if (flash)
ws.state |= WS_ST_FLASH;
if (type == OUT_QUERY)
ws.state |= WS_ST_QUERY;
if ((ws.ifp = ifp) == 0) {
ws.metric = 1;
} else {
/* Adjust the advertised metric by the outgoing interface
* metric.
*/
ws.metric = ifp->int_metric+1;
}
if (init) {
init = 0;
bzero(&ripv12_buf, sizeof(ripv12_buf));
ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE;
ws.v12.buf = &ripv12_buf.rip;
ws.v12.base = &ws.v12.buf->rip_nets[0];
ws.v12.lim = ws.v12.base + NETS_LEN;
bzero(&rip_v2_buf, sizeof(rip_v2_buf));
rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
rip_v2_buf.rip.rip_vers = RIPv2;
ws.v2.buf = &rip_v2_buf.rip;
ws.v2.base = &ws.v2.buf->rip_nets[0];
ws.v2.lim = ws.v2.base + NETS_LEN;
}
ripv12_buf.rip.rip_vers = vers;
ws.v12.n = ws.v12.base;
set_auth(&ws.v12);
ws.v2.n = ws.v2.base;
set_auth(&ws.v2);
switch (type) {
case OUT_BROADCAST:
ws.v2.type = ((ws.ifp != 0
&& (ws.ifp->int_if_flags & IFF_MULTICAST))
? OUT_MULTICAST
: NO_OUT_MULTICAST);
ws.v12.type = OUT_BROADCAST;
break;
case OUT_MULTICAST:
ws.v2.type = ((ws.ifp != 0
&& (ws.ifp->int_if_flags & IFF_MULTICAST))
? OUT_MULTICAST
: NO_OUT_MULTICAST);
ws.v12.type = OUT_BROADCAST;
break;
case OUT_UNICAST:
case OUT_QUERY:
ws.v2.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
ws.v12.type = type;
break;
default:
ws.v2.type = type;
ws.v12.type = type;
break;
}
if (vers == RIPv2) {
/* if asked to send RIPv2, send at least that which can
* be safely heard by RIPv1 listeners.
*/
ws.state |= WS_ST_RIP2_SAFE;
/* full RIPv2 only if cannot be heard by RIPv1 listeners */
if (type != OUT_BROADCAST)
ws.state |= WS_ST_RIP2_ALL;
if (!(ws.state & WS_ST_TO_ON_NET)) {
ws.state |= (WS_ST_AG | WS_ST_SUPER_AG);
} else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) {
ws.state |= WS_ST_AG;
if (type != OUT_BROADCAST
&& (ws.ifp == 0
|| !(ws.ifp->int_state & IS_NO_SUPER_AG)))
ws.state |= WS_ST_SUPER_AG;
}
} else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) {
ws.state |= WS_ST_SUB_AG;
}
if (supplier) {
/* Fake a default route if asked, and if there is not
* a better, real default route.
*/
if (ifp->int_d_metric != 0
&& (0 == (rt = rtget(RIP_DEFAULT, 0))
|| rt->rt_metric+ws.metric >= ifp->int_d_metric)) {
ws.state |= WS_ST_DEFAULT;
ag_check(0, 0, 0, 0,
ifp->int_d_metric,ifp->int_d_metric,
0, 0, 0, supply_out);
}
if ((ws.state & WS_ST_RIP2_ALL)
&& (ifp->int_state & IS_PM_RDISC)) {
ws.state |= WS_ST_PM_RDISC;
ripv12_buf.rip.rip_vers = RIPv1;
}
}
(void)rn_walktree(rhead, walk_supply, 0);
ag_flush(0,0,supply_out);
/* Flush the packet buffers, provided they are not empty and
* do not contain only the password.
*/
if (ws.v12.n != ws.v12.base
&& (ws.v12.n > ws.v12.base+1
|| ws.v12.n->n_family != RIP_AF_AUTH))
supply_write(&ws.v12);
if (ws.v2.n != ws.v2.base
&& (ws.v2.n > ws.v2.base+1
|| ws.v2.n->n_family != RIP_AF_AUTH))
supply_write(&ws.v2);
/* If we sent nothing and this is an answer to a query, send
* an empty buffer.
*/
if (ws.npackets == 0
&& (ws.state & WS_ST_QUERY))
supply_write(&ws.v12);
}
/* send all of the routing table or just do a flash update
*/
void
rip_bcast(int flash)
{
#ifdef _HAVE_SIN_LEN
static struct sockaddr_in dst = {sizeof(dst), AF_INET};
#else
static struct sockaddr_in dst = {AF_INET};
#endif
struct interface *ifp;
enum output_type type;
int vers;
struct timeval rtime;
need_flash = 0;
intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME);
no_flash = rtime;
timevaladd(&no_flash, &now);
if (rip_sock < 0)
return;
trace_act("send %s and inhibit dynamic updates for %.3f sec\n",
flash ? "dynamic update" : "all routes",
rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0);
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
/* skip interfaces not doing RIP, those already queried,
* and aliases. Do try broken interfaces to see
* if they have healed.
*/
if (0 != (ifp->int_state & (IS_PASSIVE | IS_ALIAS)))
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
continue;
/* default to RIPv1 output */
if (ifp->int_state & IS_NO_RIPV1_OUT) {
/* Say nothing if this interface is turned off */
if (ifp->int_state & IS_NO_RIPV2_OUT)
continue;
vers = RIPv2;
} else {
vers = RIPv1;
}
if (ifp->int_if_flags & IFF_BROADCAST) {
/* ordinary, hardware interface */
dst.sin_addr.s_addr = ifp->int_brdaddr;
/* if RIPv1 is not turned off, then broadcast so
* that RIPv1 listeners can hear.
*/
if (vers == RIPv2
&& (ifp->int_state & IS_NO_RIPV1_OUT)) {
type = OUT_MULTICAST;
} else {
type = OUT_BROADCAST;
}
} else if (ifp->int_if_flags & IFF_POINTOPOINT) {
/* point-to-point hardware interface */
dst.sin_addr.s_addr = ifp->int_dstaddr;
type = OUT_UNICAST;
} else {
/* remote interface */
dst.sin_addr.s_addr = ifp->int_addr;
type = OUT_UNICAST;
}
supply(&dst, ifp, type, flash, vers);
}
update_seqno++; /* all routes are up to date */
}
/* Ask for routes
* Do it only once to an interface, and not even after the interface
* was broken and recovered.
*/
void
rip_query(void)
{
#ifdef _HAVE_SIN_LEN
static struct sockaddr_in dst = {sizeof(dst), AF_INET};
#else
static struct sockaddr_in dst = {AF_INET};
#endif
struct interface *ifp;
struct rip buf;
enum output_type type;
if (rip_sock < 0)
return;
bzero(&buf, sizeof(buf));
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
/* skip interfaces not doing RIP, those already queried,
* and aliases. Do try broken interfaces to see
* if they have healed.
*/
if (0 != (ifp->int_state & (IS_RIP_QUERIED
| IS_PASSIVE | IS_ALIAS)))
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
continue;
/* default to RIPv1 output */
if (ifp->int_state & IS_NO_RIPV2_OUT) {
/* Say nothing if this interface is turned off */
if (ifp->int_state & IS_NO_RIPV1_OUT)
continue;
buf.rip_vers = RIPv1;
} else {
buf.rip_vers = RIPv2;
}
buf.rip_cmd = RIPCMD_REQUEST;
buf.rip_nets[0].n_family = RIP_AF_UNSPEC;
buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
if (ifp->int_if_flags & IFF_BROADCAST) {
/* ordinary, hardware interface */
dst.sin_addr.s_addr = ifp->int_brdaddr;
/* if RIPv1 is not turned off, then broadcast so
* that RIPv1 listeners can hear.
*/
if (buf.rip_vers == RIPv2
&& (ifp->int_state & IS_NO_RIPV1_OUT)) {
type = OUT_MULTICAST;
} else {
type = OUT_BROADCAST;
}
} else if (ifp->int_if_flags & IFF_POINTOPOINT) {
/* point-to-point hardware interface */
dst.sin_addr.s_addr = ifp->int_dstaddr;
type = OUT_UNICAST;
} else {
/* remote interface */
dst.sin_addr.s_addr = ifp->int_addr;
type = OUT_UNICAST;
}
ifp->int_state |= IS_RIP_QUERIED;
if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0)
if_sick(ifp);
}
}

View File

@ -1,563 +0,0 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#endif /* not lint */
#ident "$Revision: 1.1 $"
#include "defs.h"
#include "pathnames.h"
struct parm *parms;
struct intnet *intnets;
/* parse a set of parameters for an interface
*/
char * /* error message */
parse_parms(char *line)
{
#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt)))
#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str))))
#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \
parm.parm_int_state |= (b);}
#define DELIMS " ,\t\n"
struct parm parm, *parmp;
struct intnet *intnetp;
char *tok, *tgt, *p;
/* "subnet=x.y.z.u/mask" must be alone on the line */
if (!strncasecmp("subnet=",line,7)) {
intnetp = (struct intnet*)malloc(sizeof(*intnetp));
if (!getnet(&line[7], &intnetp->intnet_addr,
&intnetp->intnet_mask)) {
free(intnetp);
return line;
}
HTONL(intnetp->intnet_addr);
intnetp->intnet_next = intnets;
intnets = intnetp;
return 0;
}
bzero(&parm, sizeof(parm));
tgt = "null";
for (tok = strtok(line, DELIMS);
tok != 0 && tok[0] != '\0';
tgt = 0, tok = strtok(0,DELIMS)) {
if (PARSE("if")) {
if (parm.parm_name[0] != '\0'
|| tok[3] == '\0'
|| strlen(tok) > IFNAMSIZ+3)
break;
strcpy(parm.parm_name, tok+3);
} else if (PARSE("passwd")) {
if (tok[7] == '\0'
|| strlen(tok) > RIP_AUTH_PW_LEN+7)
break;
strcpy(parm.parm_passwd, tok+7);
} else if (PARS("no_ag")) {
parm.parm_int_state |= IS_NO_AG;
} else if (PARS("no_super_ag")) {
parm.parm_int_state |= IS_NO_SUPER_AG;
} else if (PARS("no_rip")) {
parm.parm_int_state |= (IS_NO_RIPV1_IN
| IS_NO_RIPV2_IN
| IS_NO_RIPV1_OUT
| IS_NO_RIPV2_OUT);
} else if (PARS("no_ripv1_in")) {
parm.parm_int_state |= IS_NO_RIPV1_IN;
} else if (PARS("no_ripv2_in")) {
parm.parm_int_state |= IS_NO_RIPV2_IN;
} else if (PARS("no_ripv2_out")) {
parm.parm_int_state |= IS_NO_RIPV2_OUT;
} else if (PARS("ripv2_out")) {
if (parm.parm_int_state & IS_NO_RIPV2_OUT)
break;
parm.parm_int_state |= IS_NO_RIPV1_OUT;
} else if (PARS("no_rdisc")) {
CKF((GROUP_IS_SOL|GROUP_IS_ADV),
IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT);
} else if (PARS("no_solicit")) {
CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
} else if (PARS("send_solicit")) {
CKF(GROUP_IS_SOL, IS_SOL_OUT);
} else if (PARS("no_rdisc_adv")) {
CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
} else if (PARS("rdisc_adv")) {
CKF(GROUP_IS_ADV, IS_ADV_OUT);
} else if (PARS("bcast_rdisc")) {
parm.parm_int_state |= IS_BCAST_RDISC;
} else if (PARSE("rdisc_pref")) {
if (parm.parm_rdisc_pref != 0
|| tok[11] == '\0'
|| (parm.parm_rdisc_pref = (int)strtol(&tok[11],
&p,0),
*p != '\0'))
break;
} else if (PARSE("rdisc_interval")) {
if (parm.parm_rdisc_int != 0
|| tok[15] == '\0'
|| (parm.parm_rdisc_int = (int)strtol(&tok[15],
&p,0),
*p != '\0')
|| parm.parm_rdisc_int < MinMaxAdvertiseInterval
|| parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
break;
} else if (PARSE("fake_default")) {
if (parm.parm_d_metric != 0
|| tok[13] == '\0'
|| (parm.parm_d_metric=(int)strtol(&tok[13],&p,0),
*p != '\0')
|| parm.parm_d_metric >= HOPCNT_INFINITY-2)
break;
} else {
tgt = tok;
break;
}
}
if (tgt != 0)
return tgt;
if (parm.parm_int_state & IS_NO_ADV_IN)
parm.parm_int_state |= IS_NO_SOL_OUT;
/* check for duplicate specification */
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
if (strcmp(parm.parm_name, parmp->parm_name))
continue;
if (parmp->parm_a_h != (parm.parm_a_h & parmp->parm_m)
&& parm.parm_a_h != (parmp->parm_a_h & parm.parm_m))
continue;
if (strcmp(parmp->parm_passwd, parm.parm_passwd)
|| (0 != (parm.parm_int_state & GROUP_IS_SOL)
&& 0 != (parmp->parm_int_state & GROUP_IS_SOL)
&& 0 != ((parm.parm_int_state ^ parmp->parm_int_state)
&& GROUP_IS_SOL))
|| (0 != (parm.parm_int_state & GROUP_IS_ADV)
&& 0 != (parmp->parm_int_state & GROUP_IS_ADV)
&& 0 != ((parm.parm_int_state ^ parmp->parm_int_state)
&& GROUP_IS_ADV))
|| (parm.parm_rdisc_pref != 0
&& parmp->parm_rdisc_pref != 0
&& parm.parm_rdisc_pref != parmp->parm_rdisc_pref)
|| (parm.parm_rdisc_int != 0
&& parmp->parm_rdisc_int != 0
&& parm.parm_rdisc_int != parmp->parm_rdisc_int)
|| (parm.parm_d_metric != 0
&& parmp->parm_d_metric != 0
&& parm.parm_d_metric != parmp->parm_d_metric))
return "duplicate";
}
parmp = (struct parm*)malloc(sizeof(*parmp));
bcopy(&parm, parmp, sizeof(*parmp));
parmp->parm_next = parms;
parms = parmp;
return 0;
#undef DELIMS
#undef PARS
#undef PARSE
}
/* use configured parameters
*/
void
get_parms(struct interface *ifp)
{
struct parm *parmp;
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
if ((parmp->parm_a_h == (ntohl(ifp->int_addr)
& parmp->parm_m)
&& parmp->parm_name[0] == '\0')
|| (parmp->parm_name[0] != '\0'
&& !strcmp(ifp->int_name, parmp->parm_name))) {
ifp->int_state |= parmp->parm_int_state;
bcopy(parmp->parm_passwd, ifp->int_passwd,
sizeof(ifp->int_passwd));
ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
ifp->int_rdisc_int = parmp->parm_rdisc_int;
ifp->int_d_metric = parmp->parm_d_metric;
}
}
if ((ifp->int_state & IS_NO_RIP_IN) == IS_NO_RIP_IN)
ifp->int_state |= IS_NO_RIP_OUT;
if (ifp->int_rdisc_int == 0)
ifp->int_rdisc_int = DefMaxAdvertiseInterval;
if ((ifp->int_state & IS_PASSIVE)
|| (ifp->int_state & IS_REMOTE))
ifp->int_state |= IS_NO_ADV_IN|IS_NO_SOL_OUT|IS_NO_ADV_OUT;
if (!(ifp->int_state & IS_PASSIVE)) {
if (!(ifp->int_if_flags & IFF_MULTICAST)
&& !(ifp->int_if_flags & IFF_POINTOPOINT))
ifp->int_state |= IS_NO_RIPV2_OUT;
}
if (!(ifp->int_if_flags & IFF_MULTICAST))
ifp->int_state |= IS_BCAST_RDISC;
if (ifp->int_if_flags & IFF_POINTOPOINT) {
ifp->int_state |= IS_BCAST_RDISC;
/* point-to-point links should be passive for the sake
* of demand-dialing
*/
if (0 == (ifp->int_state & GROUP_IS_SOL))
ifp->int_state |= IS_NO_SOL_OUT;
if (0 == (ifp->int_state & GROUP_IS_ADV))
ifp->int_state |= IS_NO_ADV_OUT;
}
}
/* Read a list of gateways from /etc/gateways and add them to our tables.
*
* This file contains a list of "remote" gateways. That is usually
* a gateway which we cannot immediately determine if it is present or
* not as we can do for those provided by directly connected hardware.
*
* If a gateway is marked "passive" in the file, then we assume it
* does not understand RIP and assume it is always present. Those
* not marked passive are treated as if they were directly connected
* and assumed to be broken if they do not send us advertisements.
* All remote interfaces are added to our list, and those not marked
* passive are sent routing updates.
*
* A passive interface can also be local, hardware interface exempt
* from RIP.
*/
void
gwkludge(void)
{
FILE *fp;
char *p, *lptr;
char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9];
struct interface *ifp;
naddr dst, netmask, gate;
int metric, n;
u_int state;
char *type;
struct parm *parmp;
fp = fopen(_PATH_GATEWAYS, "r");
if (fp == 0)
return;
for (;;) {
if (0 == fgets(lbuf, sizeof(lbuf)-1, fp))
break;
lptr = lbuf;
while (*lptr == ' ')
lptr++;
if (*lptr == '\n' /* ignore null and comment lines */
|| *lptr == '#')
continue;
/* notice parameter lines */
if (strncasecmp("net", lptr, 3)
&& strncasecmp("host", lptr, 4)) {
p = parse_parms(lptr);
if (p != 0)
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry %s", lptr, p);
continue;
}
/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
n = sscanf(lptr, "%4s %129[^ ] gateway"
" %64[^ / ] metric %d %8s\n",
net_host, dname, gname, &metric, qual);
if (n != 5) {
msglog("bad "_PATH_GATEWAYS" entry %s", lptr);
continue;
}
if (metric < 0 || metric >= HOPCNT_INFINITY) {
msglog("bad metric in "_PATH_GATEWAYS" entry %s",
lptr);
continue;
}
if (!strcmp(net_host, "host")) {
if (!gethost(dname, &dst)) {
msglog("bad host %s in "_PATH_GATEWAYS
" entry %s", dname, lptr);
continue;
}
netmask = HOST_MASK;
} else if (!strcmp(net_host, "net")) {
if (!getnet(dname, &dst, &netmask)) {
msglog("bad net %s in "_PATH_GATEWAYS
" entry %s", dname, lptr);
continue;
}
HTONL(dst);
} else {
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry %s", lptr);
continue;
}
if (!gethost(gname, &gate)) {
msglog("bad gateway %s in "_PATH_GATEWAYS
" entry %s", gname, lptr);
continue;
}
if (strcmp(qual, type = "passive") == 0) {
/* Passive entries are not 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).
*/
state = IS_REMOTE | IS_PASSIVE;
if (metric == 0)
metric = 1;
} else if (strcmp(qual, type = "external") == 0) {
/* External entries are handled by other means
* such as EGP, and are placed only in the daemon
* tables to prevent overriding them with something
* else.
*/
state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
if (metric == 0)
metric = 1;
} else if (qual[0] == '\0') {
if (metric != 0) {
/* Entries that are neither "passive" nor
* "external" are "remote" and must behave
* like physical interfaces. If they are not
* heard from regularly, they are deleted.
*/
state = IS_REMOTE;
type = "remote";
} else {
/* "remote" entries with a metric of 0
* are aliases for our own interfaces
*/
state = IS_REMOTE | IS_PASSIVE;
type = "alias";
}
} else {
msglog("bad "_PATH_GATEWAYS" entry %s", lptr);
continue;
}
if (!(state & IS_EXTERNAL)) {
/* If we are going to send packets to the gateway,
* it must be reachable using our physical interfaces
*/
if (!rtfind(gate)) {
msglog("unreachable gateway %s in "
_PATH_GATEWAYS" entry %s",
gname, lptr);
continue;
}
/* Remember to advertise the corresponding logical
* network.
*/
if (netmask != std_mask(dst))
state |= IS_SUBNET;
}
parmp = (struct parm*)malloc(sizeof(*parmp));
bzero(parmp, sizeof(*parmp));
parmp->parm_next = parms;
parms = parmp;
parmp->parm_a_h = ntohl(dst);
parmp->parm_m = -1;
parmp->parm_d_metric = 0;
parmp->parm_int_state = state;
/* See if this new interface duplicates an existing
* interface.
*/
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_addr == dst
&& ifp->int_mask == netmask)
break;
}
if (ifp != 0) {
/* Let one of our real interfaces be marked passive.
*/
if ((state & IS_PASSIVE) && !(state & IS_EXTERNAL)) {
ifp->int_state |= state;
} else {
msglog("%s is duplicated in "_PATH_GATEWAYS
" by %s",
ifp->int_name, lptr);
}
continue;
}
tot_interfaces++;
ifp = (struct interface *)malloc(sizeof(*ifp));
bzero(ifp, sizeof(*ifp));
if (ifnet != 0) {
ifp->int_next = ifnet;
ifnet->int_prev = ifp;
}
ifnet = ifp;
ifp->int_state = state;
ifp->int_net = ntohl(dst) & netmask;
ifp->int_mask = netmask;
if (netmask == HOST_MASK)
ifp->int_if_flags |= IFF_POINTOPOINT;
ifp->int_dstaddr = dst;
ifp->int_addr = gate;
ifp->int_metric = metric;
(void)sprintf(ifp->int_name, "%s-%s", type, naddr_ntoa(dst));
ifp->int_index = -1;
get_parms(ifp);
if (TRACEACTIONS)
trace_if("Add", ifp);
}
}
/* get a network number as a name or a number, with an optional "/xx"
* netmask.
*/
int /* 0=bad */
getnet(char *name,
naddr *addr_hp,
naddr *maskp)
{
int i;
struct netent *nentp;
naddr mask;
struct in_addr in;
char hname[MAXHOSTNAMELEN+1];
char *mname, *p;
/* Detect and separate "1.2.3.4/24"
*/
if (0 != (mname = rindex(name,'/'))) {
i = (int)(mname - name);
if (i > sizeof(hname)-1) /* name too long */
return 0;
bcopy(name, hname, i);
hname[i] = '\0';
mname++;
name = hname;
}
nentp = getnetbyname(name);
if (nentp != 0) {
in.s_addr = (naddr)nentp->n_net;
} else if (inet_aton(name, &in) == 1) {
NTOHL(in.s_addr);
} else {
return 0;
}
if (mname == 0) {
mask = std_mask(in.s_addr);
} else {
mask = (naddr)strtoul(mname, &p, 0);
if (*p != '\0' || mask > 32)
return 0;
mask = HOST_MASK << (32-mask);
}
*addr_hp = in.s_addr;
*maskp = mask;
return 1;
}
int /* 0=bad */
gethost(char *name,
naddr *addrp)
{
struct hostent *hp;
struct in_addr in;
/* Try for a number first, even in IRIX where gethostbyname()
* is smart. This avoids hitting the name server which
* might be sick because routing is.
*/
if (inet_aton(name, &in) == 1) {
*addrp = in.s_addr;
return 1;
}
hp = gethostbyname(name);
if (hp) {
bcopy(hp->h_addr, addrp, sizeof(*addrp));
return 1;
}
return 0;
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/5/93
*
* $NetBSD$
*/
#include <paths.h>
#define _PATH_GATEWAYS "/etc/gateways"
/* All remotely requested trace files must either start with this prefix
* or be the same as the tracefile specified when the daemon was started.
* If this is a directory, routed will create log files in it. That
* might be a security problem.
*/
#define _PATH_TRACE "/tmp/routed.log"

View File

@ -1,894 +0,0 @@
/*
* Copyright (c) 1988, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)radix.c 8.4 (Berkeley) 11/2/94
*/
/*
* Routines to build and maintain radix trees for routing lookups.
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/domain.h>
#include <sys/syslog.h>
#include <net/radix.h>
#include <stdlib.h>
#define min(a,b) (((a)<(b))?(a):(b))
#define log(x, msg) syslog(x, msg)
#define panic(s) {log(LOG_ERR,s); exit(1);}
int max_keylen;
struct radix_mask *rn_mkfreelist;
struct radix_node_head *mask_rnhead;
static char *addmask_key;
static char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, -1};
static char *rn_zeros, *rn_ones;
#define rn_masktop (mask_rnhead->rnh_treetop)
#undef Bcmp
#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
static int rn_satsifies_leaf(char *, struct radix_node *, int);
/*
* The data structure for the keys is a radix tree with one way
* branching removed. The index rn_b at an internal node n represents a bit
* position to be tested. The tree is arranged so that all descendants
* of a node n have keys whose bits all agree up to position rn_b - 1.
* (We say the index of n is rn_b.)
*
* There is at least one descendant which has a one bit at position rn_b,
* and at least one with a zero there.
*
* A route is determined by a pair of key and mask. We require that the
* bit-wise logical and of the key and mask to be the key.
* We define the index of a route to associated with the mask to be
* the first bit number in the mask where 0 occurs (with bit number 0
* representing the highest order bit).
*
* We say a mask is normal if every bit is 0, past the index of the mask.
* If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
* and m is a normal mask, then the route applies to every descendant of n.
* If the index(m) < rn_b, this implies the trailing last few bits of k
* before bit b are all 0, (and hence consequently true of every descendant
* of n), so the route applies to all descendants of the node as well.
*
* Similar logic shows that a non-normal mask m such that
* index(m) <= index(n) could potentially apply to many children of n.
* Thus, for each non-host route, we attach its mask to a list at an internal
* node as high in the tree as we can go.
*
* The present version of the code makes use of normal routes in short-
* circuiting an explict mask and compare operation when testing whether
* a key satisfies a normal route, and also in remembering the unique leaf
* that governs a subtree.
*/
struct radix_node *
rn_search(v_arg, head)
void *v_arg;
struct radix_node *head;
{
register struct radix_node *x;
register caddr_t v;
for (x = head, v = v_arg; x->rn_b >= 0;) {
if (x->rn_bmask & v[x->rn_off])
x = x->rn_r;
else
x = x->rn_l;
}
return (x);
}
struct radix_node *
rn_search_m(v_arg, head, m_arg)
struct radix_node *head;
void *v_arg, *m_arg;
{
register struct radix_node *x;
register caddr_t v = v_arg, m = m_arg;
for (x = head; x->rn_b >= 0;) {
if ((x->rn_bmask & m[x->rn_off]) &&
(x->rn_bmask & v[x->rn_off]))
x = x->rn_r;
else
x = x->rn_l;
}
return x;
}
int
rn_refines(m_arg, n_arg)
void *m_arg, *n_arg;
{
register caddr_t m = m_arg, n = n_arg;
register caddr_t lim, lim2 = lim = n + *(u_char *)n;
int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
int masks_are_equal = 1;
if (longer > 0)
lim -= longer;
while (n < lim) {
if (*n & ~(*m))
return 0;
if (*n++ != *m++)
masks_are_equal = 0;
}
while (n < lim2)
if (*n++)
return 0;
if (masks_are_equal && (longer < 0))
for (lim2 = m - longer; m < lim2; )
if (*m++)
return 1;
return (!masks_are_equal);
}
struct radix_node *
rn_lookup(v_arg, m_arg, head)
void *v_arg, *m_arg;
struct radix_node_head *head;
{
register struct radix_node *x;
caddr_t netmask = 0;
if (m_arg) {
if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0)
return (0);
netmask = x->rn_key;
}
x = rn_match(v_arg, head);
if (x && netmask) {
while (x && x->rn_mask != netmask)
x = x->rn_dupedkey;
}
return x;
}
static int
rn_satsifies_leaf(char *trial,
register struct radix_node *leaf,
int skip)
{
register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
char *cplim;
int length = min(*(u_char *)cp, *(u_char *)cp2);
if (cp3 == 0)
cp3 = rn_ones;
else
length = min(length, *(u_char *)cp3);
cplim = cp + length; cp3 += skip; cp2 += skip;
for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
if ((*cp ^ *cp2) & *cp3)
return 0;
return 1;
}
struct radix_node *
rn_match(v_arg, head)
void *v_arg;
struct radix_node_head *head;
{
caddr_t v = v_arg;
register struct radix_node *t = head->rnh_treetop, *x;
register caddr_t cp = v, cp2;
caddr_t cplim;
struct radix_node *saved_t, *top = t;
int off = t->rn_off, vlen = *(u_char *)cp, matched_off;
register int test, b, rn_b;
/*
* Open code rn_search(v, top) to avoid overhead of extra
* subroutine call.
*/
for (; t->rn_b >= 0; ) {
if (t->rn_bmask & cp[t->rn_off])
t = t->rn_r;
else
t = t->rn_l;
}
/*
* See if we match exactly as a host destination
* or at least learn how many bits match, for normal mask finesse.
*
* It doesn't hurt us to limit how many bytes to check
* to the length of the mask, since if it matches we had a genuine
* match and the leaf we have is the most specific one anyway;
* if it didn't match with a shorter length it would fail
* with a long one. This wins big for class B&C netmasks which
* are probably the most common case...
*/
if (t->rn_mask)
vlen = *(u_char *)t->rn_mask;
cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
for (; cp < cplim; cp++, cp2++)
if (*cp != *cp2)
goto on1;
/*
* This extra grot is in case we are explicitly asked
* to look up the default. Ugh!
*/
if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey)
t = t->rn_dupedkey;
return t;
on1:
test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
for (b = 7; (test >>= 1) > 0;)
b--;
matched_off = cp - v;
b += matched_off << 3;
rn_b = -1 - b;
/*
* If there is a host route in a duped-key chain, it will be first.
*/
if ((saved_t = t)->rn_mask == 0)
t = t->rn_dupedkey;
for (; t; t = t->rn_dupedkey)
/*
* Even if we don't match exactly as a host,
* we may match if the leaf we wound up at is
* a route to a net.
*/
if (t->rn_flags & RNF_NORMAL) {
if (rn_b <= t->rn_b)
return t;
} else if (rn_satsifies_leaf(v, t, matched_off))
return t;
t = saved_t;
/* start searching up the tree */
do {
register struct radix_mask *m;
t = t->rn_p;
if (m = t->rn_mklist) {
/*
* If non-contiguous masks ever become important
* we can restore the masking and open coding of
* the search and satisfaction test and put the
* calculation of "off" back before the "do".
*/
do {
if (m->rm_flags & RNF_NORMAL) {
if (rn_b <= m->rm_b)
return (m->rm_leaf);
} else {
off = min(t->rn_off, matched_off);
x = rn_search_m(v, t, m->rm_mask);
while (x && x->rn_mask != m->rm_mask)
x = x->rn_dupedkey;
if (x && rn_satsifies_leaf(v, x, off))
return x;
}
} while (m = m->rm_mklist);
}
} while (t != top);
return 0;
}
#ifdef RN_DEBUG
int rn_nodenum;
struct radix_node *rn_clist;
int rn_saveinfo;
int rn_debug = 1;
#endif
struct radix_node *
rn_newpair(v, b, nodes)
void *v;
int b;
struct radix_node nodes[2];
{
register struct radix_node *tt = nodes, *t = tt + 1;
t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7);
t->rn_l = tt; t->rn_off = b >> 3;
tt->rn_b = -1; tt->rn_key = (caddr_t)v; tt->rn_p = t;
tt->rn_flags = t->rn_flags = RNF_ACTIVE;
#ifdef RN_DEBUG
tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
#endif
return t;
}
struct radix_node *
rn_insert(v_arg, head, dupentry, nodes)
void *v_arg;
struct radix_node_head *head;
int *dupentry;
struct radix_node nodes[2];
{
caddr_t v = v_arg;
struct radix_node *top = head->rnh_treetop;
int head_off = top->rn_off, vlen = (int)*((u_char *)v);
register struct radix_node *t = rn_search(v_arg, top);
register caddr_t cp = v + head_off;
register int b;
struct radix_node *tt;
/*
* Find first bit at which v and t->rn_key differ
*/
{
register caddr_t cp2 = t->rn_key + head_off;
register int cmp_res;
caddr_t cplim = v + vlen;
while (cp < cplim)
if (*cp2++ != *cp++)
goto on1;
*dupentry = 1;
return t;
on1:
*dupentry = 0;
cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
for (b = (cp - v) << 3; cmp_res; b--)
cmp_res >>= 1;
}
{
register struct radix_node *p, *x = top;
cp = v;
do {
p = x;
if (cp[x->rn_off] & x->rn_bmask)
x = x->rn_r;
else x = x->rn_l;
} while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */
#ifdef RN_DEBUG
if (rn_debug)
log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
#endif
t = rn_newpair(v_arg, b, nodes); tt = t->rn_l;
if ((cp[p->rn_off] & p->rn_bmask) == 0)
p->rn_l = t;
else
p->rn_r = t;
x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */
if ((cp[t->rn_off] & t->rn_bmask) == 0) {
t->rn_r = x;
} else {
t->rn_r = tt; t->rn_l = x;
}
#ifdef RN_DEBUG
if (rn_debug)
log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
#endif
}
return (tt);
}
struct radix_node *
rn_addmask(n_arg, search, skip)
int search, skip;
void *n_arg;
{
caddr_t netmask = (caddr_t)n_arg;
register struct radix_node *x;
register caddr_t cp, cplim;
register int b = 0, mlen, j;
int maskduplicated, m0, isnormal;
struct radix_node *saved_x;
static int last_zeroed = 0;
if ((mlen = *(u_char *)netmask) > max_keylen)
mlen = max_keylen;
if (skip == 0)
skip = 1;
if (mlen <= skip)
return (mask_rnhead->rnh_nodes);
if (skip > 1)
Bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
if ((m0 = mlen) > skip)
Bcopy(netmask + skip, addmask_key + skip, mlen - skip);
/*
* Trim trailing zeroes.
*/
for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
cp--;
mlen = cp - addmask_key;
if (mlen <= skip) {
if (m0 >= last_zeroed)
last_zeroed = mlen;
return (mask_rnhead->rnh_nodes);
}
if (m0 < last_zeroed)
Bzero(addmask_key + m0, last_zeroed - m0);
*addmask_key = last_zeroed = mlen;
x = rn_search(addmask_key, rn_masktop);
if (Bcmp(addmask_key, x->rn_key, mlen) != 0)
x = 0;
if (x || search)
return (x);
R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
if ((saved_x = x) == 0)
return (0);
Bzero(x, max_keylen + 2 * sizeof (*x));
netmask = cp = (caddr_t)(x + 2);
Bcopy(addmask_key, cp, mlen);
x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
if (maskduplicated) {
log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
Free(saved_x);
return (x);
}
/*
* Calculate index of mask, and check for normalcy.
*/
cplim = netmask + mlen; isnormal = 1;
for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)
cp++;
if (cp != cplim) {
for (j = 0x80; (j & *cp) != 0; j >>= 1)
b++;
if (*cp != normal_chars[b] || cp != (cplim - 1))
isnormal = 0;
}
b += (cp - netmask) << 3;
x->rn_b = -1 - b;
if (isnormal)
x->rn_flags |= RNF_NORMAL;
return (x);
}
static int /* XXX: arbitrary ordering for non-contiguous masks */
rn_lexobetter(void *m_arg, void *n_arg)
{
register u_char *mp = m_arg, *np = n_arg, *lim;
if (*mp > *np)
return 1; /* not really, but need to check longer one first */
if (*mp == *np)
for (lim = mp + *mp; mp < lim;)
if (*mp++ > *np++)
return 1;
return 0;
}
static struct radix_mask *
rn_new_radix_mask(register struct radix_node *tt,
register struct radix_mask *next)
{
register struct radix_mask *m;
MKGet(m);
if (m == 0) {
log(LOG_ERR, "Mask for route not entered\n");
return (0);
}
Bzero(m, sizeof *m);
m->rm_b = tt->rn_b;
m->rm_flags = tt->rn_flags;
if (tt->rn_flags & RNF_NORMAL)
m->rm_leaf = tt;
else
m->rm_mask = tt->rn_mask;
m->rm_mklist = next;
tt->rn_mklist = m;
return m;
}
struct radix_node *
rn_addroute(v_arg, n_arg, head, treenodes)
void *v_arg, *n_arg;
struct radix_node_head *head;
struct radix_node treenodes[2];
{
caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
register struct radix_node *t, *x, *tt;
struct radix_node *saved_tt, *top = head->rnh_treetop;
short b = 0, b_leaf;
int keyduplicated;
caddr_t mmask;
struct radix_mask *m, **mp;
/*
* In dealing with non-contiguous masks, there may be
* many different routes which have the same mask.
* We will find it useful to have a unique pointer to
* the mask to speed avoiding duplicate references at
* nodes and possibly save time in calculating indices.
*/
if (netmask) {
if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0)
return (0);
b_leaf = x->rn_b;
b = -1 - x->rn_b;
netmask = x->rn_key;
}
/*
* Deal with duplicated keys: attach node to previous instance
*/
saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
if (keyduplicated) {
for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
if (tt->rn_mask == netmask)
return (0);
if (netmask == 0 ||
(tt->rn_mask &&
((b_leaf < tt->rn_b) || /* index(netmask) > node */
rn_refines(netmask, tt->rn_mask) ||
rn_lexobetter(netmask, tt->rn_mask))))
break;
}
/*
* If the mask is not duplicated, we wouldn't
* find it among possible duplicate key entries
* anyway, so the above test doesn't hurt.
*
* We sort the masks for a duplicated key the same way as
* in a masklist -- most specific to least specific.
* This may require the unfortunate nuisance of relocating
* the head of the list.
*/
if (tt == saved_tt) {
struct radix_node *xx = x;
/* link in at head of list */
(tt = treenodes)->rn_dupedkey = t;
tt->rn_flags = t->rn_flags;
tt->rn_p = x = t->rn_p;
if (x->rn_l == t) x->rn_l = tt; else x->rn_r = tt;
saved_tt = tt; x = xx;
} else {
(tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
t->rn_dupedkey = tt;
}
#ifdef RN_DEBUG
t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
#endif
tt->rn_key = (caddr_t) v;
tt->rn_b = -1;
tt->rn_flags = RNF_ACTIVE;
}
/*
* Put mask in tree.
*/
if (netmask) {
tt->rn_mask = netmask;
tt->rn_b = x->rn_b;
tt->rn_flags |= x->rn_flags & RNF_NORMAL;
}
t = saved_tt->rn_p;
if (keyduplicated)
goto on2;
b_leaf = -1 - t->rn_b;
if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r;
/* Promote general routes from below */
if (x->rn_b < 0) {
for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) {
if (*mp = m = rn_new_radix_mask(x, 0))
mp = &m->rm_mklist;
}
} else if (x->rn_mklist) {
/*
* Skip over masks whose index is > that of new node
*/
for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist)
if (m->rm_b >= b_leaf)
break;
t->rn_mklist = m; *mp = 0;
}
on2:
/* Add new route to highest possible ancestor's list */
if ((netmask == 0) || (b > t->rn_b ))
return tt; /* can't lift at all */
b_leaf = tt->rn_b;
do {
x = t;
t = t->rn_p;
} while (b <= t->rn_b && x != top);
/*
* Search through routes associated with node to
* insert new route according to index.
* Need same criteria as when sorting dupedkeys to avoid
* double loop on deletion.
*/
for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist) {
if (m->rm_b < b_leaf)
continue;
if (m->rm_b > b_leaf)
break;
if (m->rm_flags & RNF_NORMAL) {
mmask = m->rm_leaf->rn_mask;
if (tt->rn_flags & RNF_NORMAL) {
log(LOG_ERR,
"Non-unique normal route, mask not entered");
return tt;
}
} else
mmask = m->rm_mask;
if (mmask == netmask) {
m->rm_refs++;
tt->rn_mklist = m;
return tt;
}
if (rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask))
break;
}
*mp = rn_new_radix_mask(tt, *mp);
return tt;
}
struct radix_node *
rn_delete(v_arg, netmask_arg, head)
void *v_arg, *netmask_arg;
struct radix_node_head *head;
{
register struct radix_node *t, *p, *x, *tt;
struct radix_mask *m, *saved_m, **mp;
struct radix_node *dupedkey, *saved_tt, *top;
caddr_t v, netmask;
int b, head_off, vlen;
v = v_arg;
netmask = netmask_arg;
x = head->rnh_treetop;
tt = rn_search(v, x);
head_off = x->rn_off;
vlen = *(u_char *)v;
saved_tt = tt;
top = x;
if (tt == 0 ||
Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
return (0);
/*
* Delete our route from mask lists.
*/
if (netmask) {
if ((x = rn_addmask(netmask, 1, head_off)) == 0)
return (0);
netmask = x->rn_key;
while (tt->rn_mask != netmask)
if ((tt = tt->rn_dupedkey) == 0)
return (0);
}
if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
goto on1;
if (tt->rn_flags & RNF_NORMAL) {
if (m->rm_leaf != tt || m->rm_refs > 0) {
log(LOG_ERR, "rn_delete: inconsistent annotation\n");
return 0; /* dangling ref could cause disaster */
}
} else {
if (m->rm_mask != tt->rn_mask) {
log(LOG_ERR, "rn_delete: inconsistent annotation\n");
goto on1;
}
if (--m->rm_refs >= 0)
goto on1;
}
b = -1 - tt->rn_b;
t = saved_tt->rn_p;
if (b > t->rn_b)
goto on1; /* Wasn't lifted at all */
do {
x = t;
t = t->rn_p;
} while (b <= t->rn_b && x != top);
for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist)
if (m == saved_m) {
*mp = m->rm_mklist;
MKFree(m);
break;
}
if (m == 0) {
log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
if (tt->rn_flags & RNF_NORMAL)
return (0); /* Dangling ref to us */
}
on1:
/*
* Eliminate us from tree
*/
if (tt->rn_flags & RNF_ROOT)
return (0);
#ifdef RN_DEBUG
/* Get us out of the creation list */
for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
if (t) t->rn_ybro = tt->rn_ybro;
#endif
t = tt->rn_p;
if (dupedkey = saved_tt->rn_dupedkey) {
if (tt == saved_tt) {
x = dupedkey; x->rn_p = t;
if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x;
} else {
for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
p = p->rn_dupedkey;
if (p) p->rn_dupedkey = tt->rn_dupedkey;
else log(LOG_ERR, "rn_delete: couldn't find us\n");
}
t = tt + 1;
if (t->rn_flags & RNF_ACTIVE) {
#ifndef RN_DEBUG
*++x = *t; p = t->rn_p;
#else
b = t->rn_info; *++x = *t; t->rn_info = b; p = t->rn_p;
#endif
if (p->rn_l == t) p->rn_l = x; else p->rn_r = x;
x->rn_l->rn_p = x; x->rn_r->rn_p = x;
}
goto out;
}
if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l;
p = t->rn_p;
if (p->rn_r == t) p->rn_r = x; else p->rn_l = x;
x->rn_p = p;
/*
* Demote routes attached to us.
*/
if (t->rn_mklist) {
if (x->rn_b >= 0) {
for (mp = &x->rn_mklist; m = *mp;)
mp = &m->rm_mklist;
*mp = t->rn_mklist;
} else {
/* If there are any key,mask pairs in a sibling
duped-key chain, some subset will appear sorted
in the same order attached to our mklist */
for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
if (m == x->rn_mklist) {
struct radix_mask *mm = m->rm_mklist;
x->rn_mklist = 0;
if (--(m->rm_refs) < 0)
MKFree(m);
m = mm;
}
if (m)
#ifdef _KERNEL
printf("%s %x at %x\n",
"rn_delete: Orphaned Mask", m, x);
#else
syslog(LOG_ERR, "%s %x at %x\n",
"rn_delete: Orphaned Mask", m, x);
#endif
}
}
/*
* We may be holding an active internal node in the tree.
*/
x = tt + 1;
if (t != x) {
#ifndef RN_DEBUG
*t = *x;
#else
b = t->rn_info; *t = *x; t->rn_info = b;
#endif
t->rn_l->rn_p = t; t->rn_r->rn_p = t;
p = x->rn_p;
if (p->rn_l == x) p->rn_l = t; else p->rn_r = t;
}
out:
tt->rn_flags &= ~RNF_ACTIVE;
tt[1].rn_flags &= ~RNF_ACTIVE;
return (tt);
}
int
rn_walktree(h, f, w)
struct radix_node_head *h;
register int (*f)();
void *w;
{
int error;
struct radix_node *base, *next;
register struct radix_node *rn = h->rnh_treetop;
/*
* This gets complicated because we may delete the node
* while applying the function f to it, so we need to calculate
* the successor node in advance.
*/
/* First time through node, go left */
while (rn->rn_b >= 0)
rn = rn->rn_l;
for (;;) {
base = rn;
/* If at right child go back up, otherwise, go right */
while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0)
rn = rn->rn_p;
/* Find the next *leaf* since next node might vanish, too */
for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;)
rn = rn->rn_l;
next = rn;
/* Process leaves */
while (rn = base) {
base = rn->rn_dupedkey;
if (!(rn->rn_flags & RNF_ROOT) && (error = (*f)(rn, w)))
return (error);
}
rn = next;
if (rn->rn_flags & RNF_ROOT)
return (0);
}
/* NOTREACHED */
}
int
rn_inithead(head, off)
void **head;
int off;
{
register struct radix_node_head *rnh;
register struct radix_node *t, *tt, *ttt;
if (*head)
return (1);
R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh));
if (rnh == 0)
return (0);
Bzero(rnh, sizeof (*rnh));
*head = rnh;
t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
ttt = rnh->rnh_nodes + 2;
t->rn_r = ttt;
t->rn_p = t;
tt = t->rn_l;
tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
tt->rn_b = -1 - off;
*ttt = *tt;
ttt->rn_key = rn_ones;
rnh->rnh_addaddr = rn_addroute;
rnh->rnh_deladdr = rn_delete;
rnh->rnh_matchaddr = rn_match;
rnh->rnh_lookup = rn_lookup;
rnh->rnh_walktree = rn_walktree;
rnh->rnh_treetop = t;
return (1);
}
void
rn_init()
{
char *cp, *cplim;
#ifdef KERNEL
struct domain *dom;
for (dom = domains; dom; dom = dom->dom_next)
if (dom->dom_maxrtkey > max_keylen)
max_keylen = dom->dom_maxrtkey;
#endif
if (max_keylen == 0) {
printf("rn_init: radix functions require max_keylen be set\n");
return;
}
R_Malloc(rn_zeros, char *, 3 * max_keylen);
if (rn_zeros == NULL)
panic("rn_init");
Bzero(rn_zeros, 3 * max_keylen);
rn_ones = cp = rn_zeros + max_keylen;
addmask_key = cplim = rn_ones + max_keylen;
while (cp < cplim)
*cp++ = -1;
if (rn_inithead((void **)&mask_rnhead, 0) == 0)
panic("rn_init 2");
}

View File

@ -1,161 +0,0 @@
/*
* Copyright (c) 1988, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)radix.h 8.2 (Berkeley) 10/31/94
*/
#ifndef __RADIX_H_
#define __RADIX_H_
#include <sys/cdefs.h>
struct walkarg;
/*
* Radix search tree node layout.
*/
struct radix_node {
struct radix_mask *rn_mklist; /* list of masks contained in subtree */
struct radix_node *rn_p; /* parent */
short rn_b; /* bit offset; -1-index(netmask) */
char rn_bmask; /* node: mask for bit test*/
u_char rn_flags; /* enumerated next */
#define RNF_NORMAL 1 /* leaf contains normal route */
#define RNF_ROOT 2 /* leaf is root leaf for tree */
#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */
union {
struct { /* leaf only data: */
caddr_t rn_Key; /* object of search */
caddr_t rn_Mask; /* netmask, if present */
struct radix_node *rn_Dupedkey;
} rn_leaf;
struct { /* node only data: */
int rn_Off; /* where to start compare */
struct radix_node *rn_L;/* progeny */
struct radix_node *rn_R;/* progeny */
}rn_node;
} rn_u;
#ifdef RN_DEBUG
int rn_info;
struct radix_node *rn_twin;
struct radix_node *rn_ybro;
#endif
};
#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
#define rn_key rn_u.rn_leaf.rn_Key
#define rn_mask rn_u.rn_leaf.rn_Mask
#define rn_off rn_u.rn_node.rn_Off
#define rn_l rn_u.rn_node.rn_L
#define rn_r rn_u.rn_node.rn_R
/*
* Annotations to tree concerning potential routes applying to subtrees.
*/
extern struct radix_mask {
short rm_b; /* bit offset; -1-index(netmask) */
char rm_unused; /* cf. rn_bmask */
u_char rm_flags; /* cf. rn_flags */
struct radix_mask *rm_mklist; /* more masks to try */
union {
caddr_t rmu_mask; /* the mask */
struct radix_node *rmu_leaf; /* for normal routes */
} rm_rmu;
int rm_refs; /* # of references to this struct */
} *rn_mkfreelist;
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
#define MKGet(m) {\
if (rn_mkfreelist) {\
m = rn_mkfreelist; \
rn_mkfreelist = (m)->rm_mklist; \
} else \
R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
struct radix_node_head {
struct radix_node *rnh_treetop;
int rnh_addrsize; /* permit, but not require fixed keys */
int rnh_pktsize; /* permit, but not require fixed keys */
struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
__P((void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]));
struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
__P((void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]));
struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
__P((void *v, void *mask, struct radix_node_head *head));
struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
__P((void *v, void *mask, struct radix_node_head *head));
struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
__P((void *v, struct radix_node_head *head));
struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
__P((void *v, void *mask, struct radix_node_head *head));
struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
__P((void *v, struct radix_node_head *head));
int (*rnh_walktree) /* traverse tree */
(struct radix_node_head *head,
int (*f)(struct radix_node *, struct walkarg *),
struct walkarg *w);
struct radix_node rnh_nodes[3]; /* empty tree for common case */
};
#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((char *)(p), (int)(n));
#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
#define Free(p) free((char *)p);
void rn_init __P((void));
int rn_inithead __P((void **, int));
int rn_refines __P((void *, void *));
int rn_walktree __P((struct radix_node_head *,
int (*)__P((struct radix_node *, struct walkarg*)),
struct walkarg*));
struct radix_node
*rn_addmask __P((void *, int, int)),
*rn_addroute __P((void *, void *, struct radix_node_head *,
struct radix_node [2])),
*rn_delete __P((void *, void *, struct radix_node_head *)),
*rn_insert __P((void *, struct radix_node_head *, int *,
struct radix_node [2])),
*rn_match __P((void *, struct radix_node_head *)),
*rn_newpair __P((void *, int, struct radix_node[2])),
*rn_search __P((void *, struct radix_node *)),
*rn_search_m __P((void *, struct radix_node *, void *));
#endif /* __RADIX_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,602 +0,0 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
.\"
.Dd June 1, 1996
.Dt ROUTED 8
.Os BSD 4.4
.Sh NAME
.Nm routed
.Nd network RIP and router discovery routing daemon
.Sh SYNOPSIS
.Nm
.Op Fl sqdghmAt
.Op Fl T Ar tracefile
.Oo
.Fl F
.Ar net Ns Op /mask Ns Op ,metric
.Oc
.OP Fl P Ar parms
.Sh DESCRIPTION
.Nm Routed
is a dameon invoked at boot time to manage the network
routing tables.
It uses Routing Information Protocol, RIPv1 (RFC\ 1058),
RIPv2 (RFC\ 1723),
and Internet Router Discovery Protocol (RFC 1256)
to maintain the kernel routing table.
The RIPv1 protocol is based on the reference 4.3BSD daemon.
.Pp
It listens on the
.Xr udp 4
socket for the
.Xr route 8
service (see
.Xr services 5 )
for Routing Information Protocol packets.
It also sends and receives multicast Router Discovery ICMP messages.
If the host is a router,
.Nm
periodically supplies copies
of its routing tables to any directly connected hosts and networks.
It also advertise or solicits default routes using Router Discovery
ICMP messages.
.Pp
When started (or when a network interface is later turned on),
.Nm
uses an AF_ROUTE address family facility to find those
directly connected interfaces configured into the
system and marked "up".
It adds necessary routes for the interfaces
to the kernel routing table.
Soon after being first started, and provided there is at least one
interface on which RIP has not been disabled,
.Nm
deletes all pre-existing
non-static routes in kernel table.
Static routes in the kernel table are preserved and
included in RIP responses if they have a valid RIP metric
(see
.Xr route 8 ).
.Pp
If more than one interface is present (not counting the loopback interface),
it is assumed that the host should forward packets among the
connected networks.
After transmitting a RIP
.Em request
and
Router Discovery Advertisements or Solicitations on a new interface,
the daemon enters a loop, listening for
RIP request and response and Router Discover packets from other hosts.
.Pp
When a
.Em request
packet is received,
.Nm
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").
Advertised metrics reflect the metric associated with interface
(see
.Xr ifconfig 8 ),
so setting the metric on an interface
is an effective way to steer traffic.
.Pp
Responses do not contain routes with a first hop on the requesting
network to implement in part
.Em split-horizon .
Requests from query programs
such as
.Xr rtquery 8
are answered with the complete table.
.Pp
The routing table maintained by the daemon
includes space for several gateways for each destination
to speed recovery from a failing router.
RIP
.Em response
packets received are used to update the routing tables provided they are
from one of the several currently recognized gateways or
advertise a better metric than at least one of the existing
gateways.
.Pp
When an update is applied,
.Nm
records the change in its own tables and updates the kernel routing table
if the best route to the destination changes.
The change in the kernel routing tableis reflected in the next batch of
.Em response
packets sent.
If the next response is not scheduled for a while, a
.Em flash update
response containing only recently changed routes is sent.
.Pp
In addition to processing incoming packets,
.Nm
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 until the route has been advertised with
an infinite metric to insure the invalidation
is propagated throughout the local internet.
This is a form of
.Em poison reverse .
.Pp
Routes in the kernel table that are added or changed as a result
of ICMP Redirect messages are deleted after a while to minimize
.Em black-holes .
When a TCP connection suffers a timeout,
the kernel tells
.Nm routed ,
which deletes all redirected routes
through the gateway involved, advances the age of all RIP routes through
the gateway to allow an alternate to be chosen, and advances of the
age of any relevant Router Discovery Protocol default routes.
.Pp
Hosts acting as internetwork routers gratuitously supply their
routing tables every 30 seconds to all directly connected hosts
and networks.
These RIP responses are sent to the broadcast address on nets that support
broadcasting,
to the destination address on point-to-point links, and to the router's
own address on other networks.
If RIPv2 is enabled, multicast packets are sent on interfaces that
support multicasting.
.Pp
If no response is received on a remote interface, if there are errors
while sending responses,
or if there are more errors than input or output (see
.Xr netstat 8 ),
then the cable or some other part of the interface is assumed to be
disconnected or broken, and routes are adjusted appropriately.
.Pp
The
.Em Internet Router Discovery Protocol
is handled similarly.
When the daemon is supplying RIP routes, it also listens for
Router Discovery Solicitations and sends Advertisements.
When it is quiet and only listening to other RIP routers, it
sends Solicitations and listens for Advertisements.
If it receives
a good Advertisement, it stops listening for broadcast or multicast
RIP responses.
It tracks several advertising routers to speed recovery when the
currently chosen router dies.
If all discovered routers disappear,
the daemon resumes listening to RIP responses.
.Pp
While using Router Discovery (which happens by default when
the system has a single network interface and a Router Discover Advertisement
is received), there is a single default route and a variable number of
redirected host routes in the kernel table.
.Pp
The Router Discover standard requires that advertisements
have a default "lifetime" of 30 minutes. That means should
something happen, a client can be without a good route for
30 minutes. It is a good idea to reduce the default to 45
seconds using
.Fl P Cm rdisc_interval=45
on the command line or
.Cm rdisc_interval=45
in the
.Pa /etc/gateways
file.
.Pp
While using Router Discovery (which happens by default when
the system has a single network interface and a Router Discover Advertisement
is received), there is a single default route and a variable number of
redirected host routes in the kernel table.
.Pp
See the
.Cm pm_rdisc
facility described below to support "legacy" systems
that can handle neither RIPv2 nor Router Discovery.
.Pp
By default, neither Router Discovery advertisements nor solicications
are sent over point to point links (e.g. PPP).
.Pp
Options supported by
.Nm routed :
.Bl -tag -width Ds
.It Fl s
this option forces
.Nm
to supply routing information.
This is the default if multiple network interfaces are present on which
RIP or Router Discovery have not been disabled, and if the kernel switch
ipforwarding=1.
.It Fl q
is the opposite of the
.Fl s
option.
.It Fl d
Do not run in the background.
This option is meant for interactive use.
.It Fl g
This flag is used on internetwork routers to offer a route
to the "default" destination.
It is equivalent to
.Fl F
.Cm 0/0,1
and is present mostly for historical reasons.
A better choice is
.Fl P Cm pm_rdisc
on the command line or
.CM pm_rdisc in the
.Pa /etc/gateways
file.
since a larger metric
will be used, reducing the spread of the potentially dangerous
default route.
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.
Notice that because a metric of 1 is used, this feature is
dangerous. It is more commonly accidently used to create chaos with routing
loop than to solve problems.
.It Fl h
This causes host or point-to-point routes to not be advertised,
provided there is a network route going the same direction.
That is a limited kind of aggregation.
This option is useful on gateways to ethernets that have other gateway
machines connected with point-to-point links such as SLIP.
.It Fl m
This causes the machine to advertise a host or point-to-point route to
its primary interface.
It is useful on multi-homed machines such as NFS servers.
This option should not be used except when the cost of
the host routes it generates is justified by the popularity of
the server.
It is effective only when the machine is supplying
routing information, because there is more than one interface.
The
.Fl m
option overrides the
.Fl q
option to the limited extent of advertising the host route.
.It Fl A
do not ignore RIPv2 authentication if we do not care about RIPv2
authentication.
This option is required for conformance with RFC 1723.
However, it makes no sense and breaks using RIP as a discovery protocol
to ignore all RIPv2 packets that carry authentication when this machine
does not care about authentication.
.It Fl T Ar tracefile
increases the debugging level to at least 1 and
causes debugging information to be appended to the trace file.
.It Fl t
increases the debugging level, which causes more information to be logged
on the tracefile specified with
.Fl T
or standard out.
The debugging level can be increased or decreased
with the
.Em SIGUSR1
or
.Em SIGUSR2
signals or with the
.Cm rtquery
command.
.It Fl F Ar net[/mask][,metric]
minimize routes in transmissions via interfaces with addresses that match
.Em net/mask ,
and synthesizes a default route to this machine with the
.Em metric .
The intent is to reduce RIP traffic on slow, point-to-point links
such as PPP links by replacing many large UDP packets of RIP information
with a single, small packet containing a "fake" default route.
If
.Em metric
is absent, a value of 14 is assumed to limit
the spread of the "fake" default route.
This is a dangerous feature that when used carelessly can cause routing
loops.
Notice also that more than one interface can match the specified network
number and mask.
See also
.Fl g .
.It Fl P Ar parms
is equivalent to adding the parameter
line
.Em parms
to the
.Pa /etc/gateways
file.
.El
.Pp
Any other argument supplied is interpreted as the name
of a file in which the actions of
.Nm
should be logged.
It is better to use
.Fl T
instead of
appending the name of the trace file to the command.
.Pp
.Nm
also supports the notion of
"distant"
.Em passive
or
.Em active
gateways.
When
.Nm
is started, it reads the file
.Pa /etc/gateways
to find such distant gateways which may not be located using
only information from a routing socket, to discover if some
of the local gateways are
.Em passive ,
and to obtain other parameters.
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 RIP packets.
Routes through
.Em passive
gateways are installed in the
kernel's routing tables once upon startup and are not included in
transmitted RIP responses.
.Pp
Distant active gateways are treated like network interfaces.
RIP responses are sent
to the distant
.Em active
gateway.
If no responses are received, the associated route is deleted from
the kernel table and RIP responses advertised via other interfaces.
If the distant gateway resumes sending RIP responses, the associated
route is restored.
.Pp
Such gateways can be useful on media that do not support broadcasts
or multicasts but otherwise act like classic shared media like
Ethernets such as some ATM networks.
One can list all RIP routers reachable on the ATM network in
.Pa /etc/gateways
with a series of
"host" lines.
.Pp
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 indicate
that another routing process
will install such a route if ncessary,
and that alternate routes to that destination should not be installed
by
.Nm routed .
Such entries are only required when both routers may learn of routes
to the same destination.
.Pp
The
.Em /etc/gateways
file is comprised of a series of lines, each in
one of the following formats or consist of parameters described below:
.Pp
.Bd -ragged
.Cm net
.Ar Nname[/mask]
.Cm gateway
.Ar Gname
.Cm metric
.Ar value
.Pf < Cm passive No \&|
.Cm active No \&|
.Cm extern Ns >
.Ed
.Bd -ragged
.Cm host
.Ar Hname
.Cm gateway
.Ar Gname
.Cm metric
.Ar value
.Pf < Cm passive No \&|
.Cm active No \&|
.Cm extern Ns >
.Ed
.Pp
.Ar Nname
or
.Ar Hname
is the name of the destination network or host.
It may be a symbolic network name or an Internet address
specified in "dot" notation (see
.Xr inet 3 ).
(If it is a name, then it must either be defined in
.Pa /etc/networks
or
.Pa /etc/hosts ,
or
.Xr named 8 ,
must have been started before
.Xr routed Ns .)
.Pp
.Ar mask
is an optional number between 1 and 32 indicating the netmask associated
with
.Ar Nname .
.Pp
.Ar Gname
is the name or address of the gateway to which RIP responses should
be forwarded.
.Pp
.Ar Value
is the hop count to the destination host or network.
.Ar " host hname "
is equivalent to
.Ar " net nname/32 ".
.Pp
One of the keywords
.Cm passive ,
.Cm active
or
.Cm external
must be present to indicate whether the gateway should be treated as
.Cm passive
or
.Cm active
(as described above),
or whether the gateway is
.Cm external
to the scope of the RIP protocol.
.Pp
Lines that start with neither "net" nor "host" must consist of one
or more of the following parameter settings, separated by commas or
blanks:
.Bl -tag -width Ds
.It Cm if Ns \&= Ns Ar ifname
indicates that the other parameters on the line apply to the interface
name
.Ar ifname .
.It Cm subnet Ns \&= Ns Ar nname[/mask][,metric]
advertises a route to network
.AR nname
with mask
.AR mask
and the supplied metric (default 1).
This is useful for filling "holes" in CIDR allocations.
This parameter must appear by itself on a line.
.Pp
Do not use this feature unless necessary. It is dangerous.
.It Cm passwd Ns \&= Ns Ar XXX
specifies a RIPv2 password that will be included on all RIPv2
responses sent and checked on all RIPv2 responses received.
The password must not contain any blanks, tab characters, commas
or '#' characters.
.It Cm no_ag
turns off aggregation of subnets in RIPv1 and RIPv2 responses.
.It Cm no_super_ag
turns off aggregation of networks into supernets in RIPv2 responses.
.It Cm passive
is equivalent
.Cm no_rip Cm no_rdisc .
.It Cm no_rip
disables all RIP processing on the specified interface.
If no interfaces are allowed to process RIP packets,
.Nm
acts purely as a router discovery daemon.
.Cm No_rip
is equivalent to
.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out .
Note that turning off RIP without explicitly turning on router
discovery advertisements with
.Cm rdisc_adv
or
.Fl s
causes
.Nm routed
to act as a client router discovery daemon, not adveritising.
.It Cm no_ripv1_in
causes RIPv1 received responses to be ignored.
.It Cm no_ripv2_in
causes RIPv2 received responses to be ignored.
.It Cm ripv2_out
turns off RIPv1 output and causes RIPv2 advertisements to be
multicast when possible.
.It Cm no_rdisc
disables the Internet Router Discovery Protocol.
.It Cm no_solicit
disables the tranmission of Router Discovery Solicitations.
.It Cm send_solicit
specifies that Router Discovery solicitations should be sent,
even on point-to-point links,
which by default only listen to Router Discovery messages.
.It Cm no_rdisc_adv
disables the transmission of Router Discovery Advertisements
.It Cm rdisc_adv
specifies that Router Discovery advertisements should be sent,
even on point-to-point links,
which by default only listen to Router Discovery messages
.It Cm bcast_rdisc
specifies that Router Discovery packets should be broadcast instead of
multicast.
.It Cm rdisc_pref Ns \&= Ns Ar N
sets the preference in Router Discovery Advertisements to the integer
.Ar N .
.It Cm rdisc_interval Ns \&= Ns Ar N
sets the nominal interval with which Router Discovery Advertisements
are transmitted to N seconds and their lifetime to 3*N.
.It Cm fake_default Ns \&= Ns Ar metric
has an identical effect to
.Fl F Ar net[/mask][,metric]
with the network and mask coming from the sepcified interface.
.It Cm pm_rdisc
is similar to
.Cm fake_default .
When RIPv2 routes are multicast, so that RIPv1 listeners cannot
receive them, this feature causes a RIPv1 default route to be
broadcast to RIPv1 listeners.
Unless modified with
.Cm fake_default ,
the default route is broadcast with a metric of 14.
That serves as a "poor man's router discovery" protocol.
.El
.Pp
Note that the netmask associated with point-to-point links (such as SLIP
or PPP, with the IFF_POINTOPOINT flag) is used by
.Nm routed
to infer the netmask used by the remote system when RIPv1 is used.
.Pp
.Sh FILES
.Bl -tag -width /etc/gateways -compact
.It Pa /etc/gateways
for distant gateways
.El
.Sh SEE ALSO
.Xr gated 8 ,
.Xr udp 4 ,
.Xr icmp 4 ,
.Xr htable 8 ,
.Xr rtquery 8 .
.Rs
.%T Internet Transport Protocols
.%R XSIS 028112
.%Q Xerox System Integration Standard
.Re
.Sh BUGS
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 .

View File

@ -1,8 +0,0 @@
# From: @(#)Makefile 8.1 (Berkeley) 6/5/93
# $Id$
PROG= rtquery
MAN8= rtquery.8
#COPTS= -g -DDEBUG -Wall
.include <bsd.prog.mk>

View File

@ -1,79 +0,0 @@
.Dd April 9, 1996
.Dt RTQUERY 8
.Os BSD 4.4
.Sh NAME
.Nm rtquery
.Nd query routing daemons for their routing tables
.Sh SYNOPSIS
.Nm
.Op Fl np1
.Op Fl 1 Ar timeout
.Op Fl r Ar addr
.Ar host ...
.Sh DESCRIPTION
.Nm Rtquery
is used to query a network routing daemon,
.Xr routed 8
or
.Xr gated 8 ,
for its routing table by sending a
.Em request
or
.Em poll
command. The routing information in any routing
.Em response
packets returned is displayed numerically and symbolically.
.Pp
.Em Rtquery
by default uses the
.Em request
command.
When the
.B \-p
option is specified,
.Nm rtquery
uses the
.Em poll
command, which is an
undocumented extension to the RIP specification supported by
.IR gated (1M).
When querying
.IR gated (1M),
the
.I poll
command is preferred over the
.I request
command because the response is not subject to Split Horizon and/or
Poisioned Reverse.
.Pp
Options supported by
.Nm rtquery :
.Bl -tag -width Ds
.It Fl n
Normally network and host numbers are displayed both symbolically
and numerically.
The
.Fl n
option displays only the numeric network and host numbers.
.It Fl p
Uses the
.Em poll
command to request full routing information from
.Xr gated 8 ,
This is an undocumented extension supported only by
.Xr gated 8 .
.It Fl 1
query using RIP version 1 instead of RIP version 2.
.It Fl w Ar timeout
changes the delay for an answer from each host.
By default, each host is given 15 seconds to respond.
.It Fl r Ar addr
ask about the route to destination
.Em parms
.Sh SEE ALSO
.Xr routed 8,
.Xr gated 8,
.br
RFC\ 1058 - Routing Information Protocol, RIPv1
.br
RFC\ 1723 - Routing Information Protocol, RIPv2

View File

@ -1,516 +0,0 @@
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1982, 1986, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
#endif /* not lint */
#include <sys/param.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#define RIPVERSION RIPv2
#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>
#ifdef sgi
#include <strings.h>
#include <bstring.h>
#endif
#ifndef sgi
#define _HAVE_SIN_LEN
#endif
#define WTIME 15 /* Time to wait for all responses */
#define STIME (250*1000) /* usec to wait for another response */
int s;
char *pgmname;
union pkt_buf {
char packet[MAXPACKETSIZE+4096];
struct rip rip;
} msg_buf;
#define MSG msg_buf.rip
#define MSG_LIM ((struct rip*)(&msg_buf.packet[MAXPACKETSIZE \
- sizeof(struct netinfo)]))
int nflag; /* numbers, no names */
int pflag; /* play the `gated` game */
int ripv2 = 1; /* use RIP version 2 */
int wtime = WTIME;
int rflag; /* 1=ask about a particular route */
struct timeval start; /* when query sent */
static void rip_input(struct sockaddr_in*, int);
static int query(char *, struct netinfo *);
static int getnet(char *, struct netinfo *);
static u_int std_mask(u_int);
int
main(int argc,
char *argv[])
{
char *p;
struct seen {
struct seen *next;
struct in_addr addr;
} *seen, *sp;
int answered = 0;
int ch, cc, bsize;
fd_set bits;
struct timeval now, delay;
struct sockaddr_in from;
int fromlen;
struct netinfo rt;
bzero(&rt, sizeof(rt));
pgmname = argv[0];
while ((ch = getopt(argc, argv, "np1w:r:")) != EOF)
switch (ch) {
case 'n':
nflag = 1;
break;
case 'p':
pflag = 1;
break;
case '1':
ripv2 = 0;
break;
case 'w':
wtime = (int)strtoul(optarg, &p, 0);
if (*p != '\0'
|| wtime <= 0)
goto usage;
break;
case 'r':
if (rflag)
goto usage;
rflag = getnet(optarg, &rt);
break;
case '?':
default:
goto usage;
}
argv += optind;
argc -= optind;
if (argc == 0) {
usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n");
exit(1);
}
if (!rflag) {
rt.n_dst = RIP_DEFAULT;
rt.n_family = RIP_AF_UNSPEC;
rt.n_metric = htonl(HOPCNT_INFINITY);
}
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
exit(2);
}
for (bsize = 127*1024; ; bsize -= 1024) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
&bsize, sizeof(bsize)) == 0)
break;
if (bsize <= 4*1024) {
perror("setsockopt SO_RCVBUF");
break;
}
}
/* ask the first host */
seen = 0;
while (0 > query(*argv++, &rt) && *argv != 0)
answered++;
FD_ZERO(&bits);
for (;;) {
FD_SET(s, &bits);
delay.tv_sec = 0;
delay.tv_usec = STIME;
cc = select(s+1, &bits, 0,0, &delay);
if (cc > 0) {
fromlen = sizeof(from);
cc = recvfrom(s, msg_buf.packet,
sizeof(msg_buf.packet), 0,
(struct sockaddr *)&from, &fromlen);
if (cc < 0) {
perror("recvfrom");
exit(1);
}
/* count the distinct responding hosts.
* You cannot match responding hosts with
* addresses to which queries were transmitted,
* because a router might respond with a
* different source address.
*/
for (sp = seen; sp != 0; sp = sp->next) {
if (sp->addr.s_addr == from.sin_addr.s_addr)
break;
}
if (sp == 0) {
sp = malloc(sizeof(*sp));
sp->addr = from.sin_addr;
sp->next = seen;
seen = sp;
answered++;
}
rip_input(&from, cc);
continue;
}
if (cc < 0) {
if ( errno == EINTR)
continue;
perror("select");
exit(1);
}
/* After a pause in responses, probe another host.
* This reduces the intermingling of answers.
*/
while (*argv != 0 && 0 > query(*argv++, &rt))
answered++;
/* continue until no more packets arrive
* or we have heard from all hosts
*/
if (answered >= argc)
break;
/* or until we have waited a long time
*/
if (gettimeofday(&now, 0) < 0) {
perror("gettimeofday(now)");
exit(1);
}
if (start.tv_sec + wtime <= now.tv_sec)
break;
}
/* fail if there was no answer */
exit (answered >= argc ? 0 : 1);
/* NOTREACHED */
}
/*
* Poll one host.
*/
static int
query(char *host,
struct netinfo *rt)
{
struct sockaddr_in router;
struct hostent *hp;
if (gettimeofday(&start, 0) < 0) {
perror("gettimeofday(start)");
return -1;
}
bzero(&router, sizeof(router));
router.sin_family = AF_INET;
#ifdef _HAVE_SIN_LEN
router.sin_len = sizeof(router);
#endif
router.sin_addr.s_addr = inet_addr(host);
if (router.sin_addr.s_addr == -1) {
hp = gethostbyname(host);
if (hp == 0) {
fprintf(stderr,"%s: %s:", pgmname, host);
herror(0);
return -1;
}
bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
}
router.sin_port = htons(RIP_PORT);
MSG.rip_cmd = (pflag)? RIPCMD_POLL : RIPCMD_REQUEST;
MSG.rip_nets[0] = *rt;
if (ripv2) {
MSG.rip_vers = RIPv2;
} else {
MSG.rip_vers = RIPv1;
MSG.rip_nets[0].n_mask = 0;
}
if (sendto(s, msg_buf.packet, sizeof(struct rip), 0,
(struct sockaddr *)&router, sizeof(router)) < 0) {
perror(host);
return -1;
}
return 0;
}
/*
* Handle an incoming RIP packet.
*/
static void
rip_input(struct sockaddr_in *from,
int size)
{
struct netinfo *n, *lim;
struct in_addr in;
char *name;
char net_buf[80];
u_int mask, dmask;
char *sp;
int i;
struct hostent *hp;
struct netent *np;
struct netauth *a;
if (nflag) {
printf("%s:", inet_ntoa(from->sin_addr));
} else {
hp = gethostbyaddr((char*)&from->sin_addr,
sizeof(struct in_addr), AF_INET);
if (hp == 0) {
printf("%s:",
inet_ntoa(from->sin_addr));
} else {
printf("%s (%s):", hp->h_name,
inet_ntoa(from->sin_addr));
}
}
if (MSG.rip_cmd != RIPCMD_RESPONSE) {
printf("\n unexpected response type %d\n", MSG.rip_cmd);
return;
}
printf(" RIPv%d%s %d bytes\n", MSG.rip_vers,
(MSG.rip_vers != RIPv1 && MSG.rip_vers != RIPv2) ? " ?" : "",
size);
if (size > MAXPACKETSIZE) {
if (size > sizeof(msg_buf) - sizeof(*n)) {
printf(" at least %d bytes too long\n",
size-MAXPACKETSIZE);
size = sizeof(msg_buf) - sizeof(*n);
} else {
printf(" %d bytes too long\n",
size-MAXPACKETSIZE);
}
} else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
printf(" response of bad length=%d\n", size);
}
n = MSG.rip_nets;
lim = (struct netinfo *)((char*)n + size) - 1;
for (; n <= lim; n++) {
name = "";
if (n->n_family == RIP_AF_INET) {
in.s_addr = n->n_dst;
(void)strcpy(net_buf, inet_ntoa(in));
mask = ntohl(n->n_mask);
dmask = mask & -mask;
if (mask != 0) {
sp = &net_buf[strlen(net_buf)];
if (MSG.rip_vers == RIPv1) {
(void)sprintf(sp," mask=%#x ? ",mask);
mask = 0;
} else if (mask + dmask == 0) {
for (i = 0;
(i != 32
&& ((1<<i)&mask) == 0);
i++)
continue;
(void)sprintf(sp, "/%d",32-i);
} else {
(void)sprintf(sp," (mask %#x)", mask);
}
}
if (!nflag) {
if (mask == 0) {
mask = std_mask(in.s_addr);
if ((ntohl(in.s_addr) & ~mask) != 0)
mask = 0;
}
/* Without a netmask, do not worry about
* whether the destination is a host or a
* network. Try both and use the first name
* we get.
*
* If we have a netmask we can make a
* good guess.
*/
if ((in.s_addr & ~mask) == 0) {
np = getnetbyaddr(in.s_addr, AF_INET);
if (np != 0)
name = np->n_name;
else if (in.s_addr == 0)
name = "default";
}
if (name[0] == '\0'
&& (in.s_addr & ~mask) != 0) {
hp = gethostbyaddr((char*)&in,
sizeof(in),
AF_INET);
if (hp != 0)
name = hp->h_name;
}
}
} else if (n->n_family == RIP_AF_AUTH) {
a = (struct netauth*)n;
(void)printf(" authentication type %d: ",
a->a_type);
for (i = 0; i < sizeof(a->au.au_pw); i++)
(void)printf("%02x ", a->au.au_pw[i]);
putc('\n', stdout);
continue;
} else {
(void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d",
n->n_family,
(char)(n->n_dst >> 24),
(char)(n->n_dst >> 16),
(char)(n->n_dst >> 8),
(char)n->n_dst);
}
(void)printf(" %-18s metric %2d %8s",
net_buf, ntohl(n->n_metric), name);
if (n->n_nhop != 0) {
in.s_addr = n->n_nhop;
if (nflag)
hp = 0;
else
hp = gethostbyaddr((char*)&in, sizeof(in),
AF_INET);
(void)printf(" nhop=%-15s%s",
(hp != 0) ? hp->h_name : inet_ntoa(in),
(MSG.rip_vers == RIPv1) ? " ?" : "");
}
if (n->n_tag != 0)
(void)printf(" tag=%#x%s", n->n_tag,
(MSG.rip_vers == RIPv1) ? " ?" : "");
putc('\n', stdout);
}
}
/* Return the classical netmask for an IP address.
*/
static u_int
std_mask(u_int addr)
{
NTOHL(addr);
if (addr == 0)
return 0;
if (IN_CLASSA(addr))
return IN_CLASSA_NET;
if (IN_CLASSB(addr))
return IN_CLASSB_NET;
return IN_CLASSC_NET;
}
/* get a network number as a name or a number, with an optional "/xx"
* netmask.
*/
static int /* 0=bad */
getnet(char *name,
struct netinfo *rt)
{
int i;
struct netent *nentp;
u_int mask;
struct in_addr in;
char hname[MAXHOSTNAMELEN+1];
char *mname, *p;
/* Detect and separate "1.2.3.4/24"
*/
if (0 != (mname = rindex(name,'/'))) {
i = (int)(mname - name);
if (i > sizeof(hname)-1) /* name too long */
return 0;
bcopy(name, hname, i);
hname[i] = '\0';
mname++;
name = hname;
}
nentp = getnetbyname(name);
if (nentp != 0) {
in.s_addr = nentp->n_net;
} else if (inet_aton(name, &in) == 1) {
NTOHL(in.s_addr);
} else {
return 0;
}
if (mname == 0) {
mask = std_mask(in.s_addr);
} else {
mask = (u_int)strtoul(mname, &p, 0);
if (*p != '\0' || mask > 32)
return 0;
mask = 0xffffffff << (32-mask);
}
rt->n_dst = in.s_addr;
rt->n_family = AF_INET;
rt->n_mask = htonl(mask);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,800 +0,0 @@
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.1.3.3 $"
#define RIPCMDS
#include "defs.h"
#include "pathnames.h"
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#ifdef sgi
/* use *stat64 for files on large filesystems */
#define stat stat64
#endif
#define NRECORDS 50 /* size of circular trace buffer */
u_int tracelevel, new_tracelevel;
FILE *ftrace = stdout; /* output trace file */
static char *tracelevel_pat = "%s\n";
char savetracename[MAXPATHLEN+1];
/* convert IP address to a string, but not into a single buffer
*/
char *
naddr_ntoa(naddr a)
{
#define NUM_BUFS 4
static int bufno;
static struct {
char str[16]; /* xxx.xxx.xxx.xxx\0 */
} bufs[NUM_BUFS];
char *s;
struct in_addr addr;
addr.s_addr = a;
s = strcpy(bufs[bufno].str, inet_ntoa(addr));
bufno = (bufno+1) % NUM_BUFS;
return s;
#undef NUM_BUFS
}
char *
saddr_ntoa(struct sockaddr *sa)
{
return (sa == 0) ? "?" : naddr_ntoa(S_ADDR(sa));
}
static char *
ts(time_t secs) {
static char s[20];
secs += epoch.tv_sec;
#ifdef sgi
(void)cftime(s, "%T", &secs);
#else
bcopy(ctime(&secs)+11, s, 8);
s[8] = '\0';
#endif
return s;
}
/* On each event, display a time stamp.
* This assumes that 'now' is update once for each event, and
* that at least now.tv_usec changes.
*/
void
lastlog(void)
{
static struct timeval last;
if (last.tv_sec != now.tv_sec
|| last.tv_usec != now.tv_usec) {
(void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
last = now;
}
}
static void
tmsg(char *p, ...)
{
va_list args;
if (ftrace != 0) {
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
fflush(ftrace);
}
}
static void
trace_close(void)
{
int fd;
fflush(stdout);
fflush(stderr);
if (ftrace != 0
&& savetracename[0] != '\0') {
fd = open(_PATH_DEVNULL, O_RDWR);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
(void)close(fd);
fclose(ftrace);
ftrace = 0;
}
}
void
trace_flush(void)
{
if (ftrace != 0) {
fflush(ftrace);
if (ferror(ftrace))
trace_off("tracing off: ", strerror(ferror(ftrace)));
}
}
void
trace_off(char *p, ...)
{
va_list args;
if (ftrace != 0) {
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
fflush(ftrace);
}
trace_close();
new_tracelevel = tracelevel = 0;
}
void
trace_on(char *filename,
int trusted)
{
struct stat stbuf;
FILE *n_ftrace;
/* Given a null filename when tracing is already on, increase the
* debugging level and re-open the file in case it has been unlinked.
*/
if (filename[0] == '\0') {
if (tracelevel != 0) {
new_tracelevel++;
tracelevel_pat = "trace command: %s\n";
} else if (savetracename[0] == '\0') {
msglog("missing trace file name");
return;
}
filename = savetracename;
} else if (stat(filename, &stbuf) >= 0) {
if (!trusted) {
msglog("trace file \"%s\" already exists");
return;
}
if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
msglog("wrong type (%#x) of trace file \"%s\"",
stbuf.st_mode, filename);
return;
}
if (!trusted
&& strcmp(filename, savetracename)
&& strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) {
msglog("wrong directory for trace file: \"%s\"",
filename);
return;
}
}
n_ftrace = fopen(filename, "a");
if (n_ftrace == 0) {
msglog("failed to open trace file \"%s\" %s",
filename, strerror(errno));
return;
}
tmsg("switch to trace file %s\n", filename);
trace_close();
if (filename != savetracename)
strncpy(savetracename, filename, sizeof(savetracename)-1);
ftrace = n_ftrace;
fflush(stdout);
fflush(stderr);
dup2(fileno(ftrace), STDOUT_FILENO);
dup2(fileno(ftrace), STDERR_FILENO);
if (new_tracelevel == 0)
new_tracelevel = 1;
set_tracelevel();
}
/* ARGSUSED */
void
sigtrace_on(int s)
{
new_tracelevel++;
tracelevel_pat = "SIGUSR1: %s\n";
}
/* ARGSUSED */
void
sigtrace_off(int s)
{
new_tracelevel--;
tracelevel_pat = "SIGUSR2: %s\n";
}
/* Move to next higher level of tracing when -t option processed or
* SIGUSR1 is received. Successive levels are:
* actions
* actions + packets
* actions + packets + contents
*/
void
set_tracelevel(void)
{
static char *off_msgs[MAX_TRACELEVEL] = {
"Tracing actions stopped",
"Tracing packets stopped",
"Tracing packet contents stopped",
};
static char *on_msgs[MAX_TRACELEVEL] = {
"Tracing actions started",
"Tracing packets started",
"Tracing packet contents started",
};
if (new_tracelevel > MAX_TRACELEVEL) {
new_tracelevel = MAX_TRACELEVEL;
if (new_tracelevel == tracelevel) {
tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
return;
}
}
while (new_tracelevel != tracelevel) {
if (new_tracelevel < tracelevel) {
if (--tracelevel == 0)
trace_off(tracelevel_pat, off_msgs[0]);
else
tmsg(tracelevel_pat, off_msgs[tracelevel]);
} else {
if (ftrace == 0) {
if (savetracename[0] != '\0')
trace_on(savetracename, 1);
else
ftrace = stdout;
}
tmsg(tracelevel_pat, on_msgs[tracelevel++]);
}
}
tracelevel_pat = "%s\n";
}
/* display an address
*/
char *
addrname(naddr addr, /* in network byte order */
naddr mask,
int force) /* 0=show mask if nonstandard, */
{ /* 1=always show mask, 2=never */
#define NUM_BUFS 4
static int bufno;
static struct {
char str[15+20];
} bufs[NUM_BUFS];
char *s, *sp;
naddr dmask;
int i;
s = strcpy(bufs[bufno].str, naddr_ntoa(addr));
bufno = (bufno+1) % NUM_BUFS;
if (force == 1 || (force == 0 && mask != std_mask(addr))) {
sp = &s[strlen(s)];
dmask = mask & -mask;
if (mask + dmask == 0) {
for (i = 0; i != 32 && ((1<<i) & mask) == 0; i++)
continue;
(void)sprintf(sp, "/%d", 32-i);
} else {
(void)sprintf(sp, " (mask %#x)", (u_int)mask);
}
}
return s;
#undef NUM_BUFS
}
/* display a bit-field
*/
struct bits {
int bits_mask;
int bits_clear;
char *bits_name;
};
static struct bits if_bits[] = {
{ IFF_LOOPBACK, 0, "LOOPBACK" },
{ IFF_POINTOPOINT, 0, "PT-TO-PT" },
{ 0, 0, 0}
};
static struct bits is_bits[] = {
{ IS_SUBNET, 0, "" },
{ IS_REMOTE, 0, "REMOTE" },
{ IS_PASSIVE, (IS_NO_RDISC
| IS_BCAST_RDISC
| IS_NO_RIP
| IS_NO_SUPER_AG
| IS_PM_RDISC
| IS_NO_AG), "PASSIVE" },
{ IS_EXTERNAL, 0, "EXTERNAL" },
{ IS_CHECKED, 0, "" },
{ IS_ALL_HOSTS, 0, "" },
{ IS_ALL_ROUTERS, 0, "" },
{ IS_RIP_QUERIED, 0, "" },
{ IS_BROKE, IS_SICK, "BROKEN" },
{ IS_SICK, 0, "SICK" },
{ IS_ACTIVE, 0, "ACTIVE" },
{ IS_NEED_NET_SYN, 0, "" },
{ IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
{ IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
{ (IS_NO_RIPV1_IN
| IS_NO_RIPV2_IN
| IS_NO_RIPV1_OUT
| IS_NO_RIPV2_OUT), 0, "NO_RIP" },
{ (IS_NO_RIPV1_IN
| IS_NO_RIPV1_OUT), 0, "RIPV2" },
{ IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" },
{ IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" },
{ IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" },
{ IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" },
{ (IS_NO_ADV_IN
| IS_NO_SOL_OUT
| IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" },
{ IS_NO_SOL_OUT, 0, "NO_SOLICIT" },
{ IS_SOL_OUT, 0, "SEND_SOLICIT" },
{ IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" },
{ IS_ADV_OUT, 0, "RDISC_ADV" },
{ IS_BCAST_RDISC, 0, "BCAST_RDISC" },
{ IS_PM_RDISC, 0, "PM_RDISC" },
{ 0, 0, "%#x"}
};
static struct bits rs_bits[] = {
{ RS_IF, 0, "IF" },
{ RS_NET_INT, RS_NET_SYN, "NET_INT" },
{ RS_NET_SYN, 0, "NET_SYN" },
{ RS_SUBNET, 0, "" },
{ RS_LOCAL, 0, "LOCAL" },
{ RS_MHOME, 0, "MHOME" },
{ RS_STATIC, 0, "STATIC" },
{ RS_RDISC, 0, "RDISC" },
{ 0, 0, "%#x"}
};
static void
trace_bits(struct bits *tbl,
u_int field,
int force)
{
int b;
char c;
if (force) {
(void)putc('<', ftrace);
c = 0;
} else {
c = '<';
}
while (field != 0
&& (b = tbl->bits_mask) != 0) {
if ((b & field) == b) {
if (tbl->bits_name[0] != '\0') {
if (c)
(void)putc(c, ftrace);
(void)fprintf(ftrace, "%s", tbl->bits_name);
c = '|';
}
if (0 == (field &= ~(b | tbl->bits_clear)))
break;
}
tbl++;
}
if (field != 0 && tbl->bits_name != 0) {
if (c)
(void)putc(c, ftrace);
(void)fprintf(ftrace, tbl->bits_name, field);
c = '|';
}
if (c != '<' || force)
(void)fputs("> ", ftrace);
}
static char *
trace_pair(naddr dst,
naddr mask,
char *gate)
{
static char buf[3*4+3+1+2+3 /* "xxx.xxx.xxx.xxx/xx-->" */
+3*4+3+1]; /* "xxx.xxx.xxx.xxx" */
int i;
i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0));
(void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), gate);
return buf;
}
void
trace_if(char *act,
struct interface *ifp)
{
if (!TRACEACTIONS || ftrace == 0)
return;
lastlog();
(void)fprintf(ftrace, "%s interface %-4s ", act, ifp->int_name);
(void)fprintf(ftrace, "%-15s-->%-15s ",
naddr_ntoa(ifp->int_addr),
addrname(htonl((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_net),
ifp->int_mask, 1));
if (ifp->int_metric != 0)
(void)fprintf(ftrace, "metric=%d ", ifp->int_metric);
trace_bits(if_bits, ifp->int_if_flags, 0);
trace_bits(is_bits, ifp->int_state, 0);
(void)fputc('\n',ftrace);
}
void
trace_upslot(struct rt_entry *rt,
struct rt_spare *rts,
naddr gate,
naddr router,
struct interface *ifp,
int metric,
u_short tag,
time_t new_time)
{
if (!TRACEACTIONS || ftrace == 0)
return;
if (rts->rts_gate == gate
&& rts->rts_router == router
&& rts->rts_metric == metric
&& rts->rts_tag == tag)
return;
lastlog();
if (rts->rts_gate != RIP_DEFAULT) {
(void)fprintf(ftrace, "Chg #%d %-35s ",
rts - rt->rt_spares,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rts->rts_gate)));
if (rts->rts_gate != rts->rts_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_gate));
if (rts->rts_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
if (rts->rts_ifp != 0)
(void)fprintf(ftrace, "%s ",
rts->rts_ifp->int_name);
(void)fprintf(ftrace, "%s\n", ts(rts->rts_time));
(void)fprintf(ftrace, " %19s%-16s ",
"",
gate != rts->rts_gate ? naddr_ntoa(gate) : "");
if (gate != router)
(void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
if (tag != rts->rts_tag)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
if (metric != rts->rts_metric)
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (ifp != rts->rts_ifp && ifp != 0 )
(void)fprintf(ftrace, "%s ", ifp->int_name);
(void)fprintf(ftrace, "%s\n",
new_time != rts->rts_time ? ts(new_time) : "");
} else {
(void)fprintf(ftrace, "Add #%d %-35s ",
rts - rt->rt_spares,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(gate)));
if (gate != router)
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
if (tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (ifp != 0)
(void)fprintf(ftrace, "%s ", ifp->int_name);
(void)fprintf(ftrace, "%s\n", ts(new_time));
}
}
/* display a message if tracing actions
*/
void
trace_act(char *p, ...)
{
va_list args;
if (!TRACEACTIONS || ftrace == 0)
return;
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
}
/* display a message if tracing packets
*/
void
trace_pkt(char *p, ...)
{
va_list args;
if (!TRACEPACKETS || ftrace == 0)
return;
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
}
void
trace_change(struct rt_entry *rt,
u_int state,
naddr gate, /* forward packets here */
naddr router, /* on the authority of this router */
int metric,
u_short tag,
struct interface *ifp,
time_t new_time,
char *label)
{
if (ftrace == 0)
return;
if (rt->rt_metric == metric
&& rt->rt_gate == gate
&& rt->rt_router == router
&& rt->rt_state == state
&& rt->rt_tag == tag)
return;
lastlog();
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
label,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rt->rt_gate)),
rt->rt_metric);
if (rt->rt_router != rt->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rt->rt_router));
if (rt->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
(void)fprintf(ftrace, "%s ",
rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name);
(void)fprintf(ftrace, "%s\n",
AGE_RT(rt, rt->rt_ifp) ? ts(rt->rt_time) : "");
(void)fprintf(ftrace, "%*s %19s%-16s ",
strlen(label), "", "",
rt->rt_gate != gate ? naddr_ntoa(gate) : "");
if (rt->rt_metric != metric)
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (router != gate)
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(router));
if (rt->rt_tag != tag)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
if (rt->rt_state != state)
trace_bits(rs_bits, state, 1);
if (rt->rt_ifp != ifp)
(void)fprintf(ftrace, "%s ",
ifp != 0 ? ifp->int_name : "?");
(void)fprintf(ftrace, "%s\n",
((rt->rt_time == new_time || !AGE_RT(rt, ifp))
? "" : ts(new_time)));
}
void
trace_add_del(char * action, struct rt_entry *rt)
{
u_int state = rt->rt_state;
if (ftrace == 0)
return;
lastlog();
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
action,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rt->rt_gate)),
rt->rt_metric);
if (rt->rt_router != rt->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rt->rt_router));
if (rt->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
trace_bits(rs_bits, state, 0);
(void)fprintf(ftrace, "%s ",
rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?");
(void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
}
void
trace_rip(char *dir1, char *dir2,
struct sockaddr_in *who,
struct interface *ifp,
struct rip *msg,
int size) /* total size of message */
{
struct netinfo *n, *lim;
struct netauth *a;
int i;
if (!TRACEPACKETS || ftrace == 0)
return;
lastlog();
if (msg->rip_cmd >= RIPCMD_MAX
|| msg->rip_vers == 0) {
(void)fprintf(ftrace, "%s bad RIPv%d cmd=%d %s"
" %s.%d size=%d\n",
dir1, msg->rip_vers, msg->rip_cmd, dir2,
naddr_ntoa(who->sin_addr.s_addr),
ntohs(who->sin_port),
size);
return;
}
(void)fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n",
dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2,
naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port),
ifp ? " via " : "", ifp ? ifp->int_name : "");
if (!TRACECONTENTS)
return;
switch (msg->rip_cmd) {
case RIPCMD_REQUEST:
case RIPCMD_RESPONSE:
n = msg->rip_nets;
lim = (struct netinfo *)((char*)msg + size);
for (; n < lim; n++) {
if (n->n_family == RIP_AF_UNSPEC
&& ntohl(n->n_metric) == HOPCNT_INFINITY
&& n+1 == lim
&& n == msg->rip_nets
&& msg->rip_cmd == RIPCMD_REQUEST) {
(void)fputs("\tQUERY ", ftrace);
if (n->n_dst != 0)
(void)fprintf(ftrace, "%s ",
naddr_ntoa(n->n_dst));
if (n->n_mask != 0)
(void)fprintf(ftrace, "mask=%#x ",
(u_int)ntohl(n->n_mask));
if (n->n_nhop != 0)
(void)fprintf(ftrace, " nhop=%s ",
naddr_ntoa(n->n_nhop));
if (n->n_tag != 0)
(void)fprintf(ftrace, "tag=%#x",
ntohs(n->n_tag));
(void)fputc('\n',ftrace);
continue;
}
if (n->n_family == RIP_AF_AUTH) {
a = (struct netauth*)n;
(void)fprintf(ftrace,
"\tAuthentication type %d: ",
ntohs(a->a_type));
for (i = 0;
i < sizeof(a->au.au_pw);
i++)
(void)fprintf(ftrace, "%02x ",
a->au.au_pw[i]);
(void)fputc('\n',ftrace);
continue;
}
if (n->n_family != RIP_AF_INET) {
(void)fprintf(ftrace,
"\t(af %d) %-18s mask=%#x",
ntohs(n->n_family),
naddr_ntoa(n->n_dst),
(u_int)ntohl(n->n_mask));
} else if (msg->rip_vers == RIPv1) {
(void)fprintf(ftrace, "\t%-18s ",
addrname(n->n_dst,
ntohl(n->n_mask),
n->n_mask==0 ? 2 : 1));
} else {
(void)fprintf(ftrace, "\t%-18s ",
addrname(n->n_dst,
ntohl(n->n_mask),
n->n_mask==0 ? 2 : 0));
}
(void)fprintf(ftrace, "metric=%-2d ",
(u_int)ntohl(n->n_metric));
if (n->n_nhop != 0)
(void)fprintf(ftrace, " nhop=%s ",
naddr_ntoa(n->n_nhop));
if (n->n_tag != 0)
(void)fprintf(ftrace, "tag=%#x",
ntohs(n->n_tag));
(void)fputc('\n',ftrace);
}
if (size != (char *)n - (char *)msg)
(void)fprintf(ftrace, "truncated record, len %d\n",
size);
break;
case RIPCMD_TRACEON:
fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
break;
case RIPCMD_TRACEOFF:
break;
}
}