Delete old routed(8).
This commit is contained in:
parent
322bab890f
commit
1c7ee7bf52
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=18321
@ -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>
|
@ -1 +0,0 @@
|
||||
.include "../../Makefile.inc"
|
@ -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);
|
1132
usr.sbin/routed/if.c
1132
usr.sbin/routed/if.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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"
|
@ -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");
|
||||
}
|
@ -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
@ -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 .
|
@ -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>
|
@ -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
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user