mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 01:30:30 -04:00
Copy SGI routed onto head.
This commit is contained in:
parent
703f599354
commit
892201b43f
9 changed files with 4529 additions and 1320 deletions
|
|
@ -1,12 +1,8 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/19/93
|
||||
# $Id$
|
||||
|
||||
PROG= routed
|
||||
SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c \
|
||||
trace.c inet.c
|
||||
SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
|
||||
MAN8= routed.8
|
||||
#SUBDIR= query trace
|
||||
DPADD= ${LIBCOMPAT}
|
||||
LDADD= -lcompat
|
||||
SUBDIR= rtquery rttrace
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
|||
|
|
@ -33,71 +33,510 @@
|
|||
* @(#)defs.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Internal data structure definitions for
|
||||
* user routing process. Based on Xerox NS
|
||||
* protocol specs with mods relevant to more
|
||||
* general addressing scheme.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#ident "$Revision: 1.1.3.1 $"
|
||||
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <protocols/routed.h>
|
||||
/* 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>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/radix.h>
|
||||
#ifndef sgi
|
||||
struct walkarg;
|
||||
#endif
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#define RIPVERSION RIPv2
|
||||
#include <protocols/routed.h>
|
||||
|
||||
#include "trace.h"
|
||||
#include "interface.h"
|
||||
#include "table.h"
|
||||
#include "af.h"
|
||||
|
||||
/*
|
||||
* When we find any interfaces marked down we rescan the
|
||||
* kernel every CHECK_INTERVAL seconds to see if they've
|
||||
* come up.
|
||||
/* 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.
|
||||
*/
|
||||
#define CHECK_INTERVAL (1*60)
|
||||
#ifdef sgi
|
||||
#define naddr __uint32_t
|
||||
#else
|
||||
#define naddr u_long
|
||||
#define _HAVE_SA_LEN
|
||||
#define _HAVE_SIN_LEN
|
||||
#endif
|
||||
|
||||
#define equal(a1, a2) \
|
||||
(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
|
||||
#ifdef sgi
|
||||
/* 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
|
||||
#endif
|
||||
|
||||
struct sockaddr_in addr; /* address of daemon's socket */
|
||||
#define NEVER (24*60*60) /* a long time */
|
||||
#define EPOCH NEVER /* bias time by this to avoid <0 */
|
||||
|
||||
int s; /* source and sink of all data */
|
||||
int r; /* routing socket */
|
||||
pid_t pid; /* process id for identifying messages */
|
||||
uid_t uid; /* user id for identifying messages */
|
||||
int seqno; /* sequence number for identifying messages */
|
||||
int kmem;
|
||||
int supplier; /* process should supply updates */
|
||||
int install; /* if 1 call kernel */
|
||||
int lookforinterfaces; /* if 1 probe kernel for new up interfaces */
|
||||
int performnlist; /* if 1 check if /kernel has changed */
|
||||
int externalinterfaces; /* # of remote and local interfaces */
|
||||
struct timeval now; /* current idea of time */
|
||||
struct timeval lastbcast; /* last time all/changes broadcast */
|
||||
struct timeval lastfullupdate; /* last time full table broadcast */
|
||||
struct timeval nextbcast; /* time to wait before changes broadcast */
|
||||
int needupdate; /* true if we need update at nextbcast */
|
||||
/* 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 */
|
||||
|
||||
char packet[MAXPACKETSIZE+1];
|
||||
struct rip *msg;
|
||||
|
||||
char **argv0;
|
||||
struct servent *sp;
|
||||
/* set times to this to continue poisoning a route */
|
||||
#define POISON_SECS (GARBAGE_TIME - POISON_TIME)
|
||||
|
||||
struct in_addr inet_makeaddr();
|
||||
int inet_addr();
|
||||
int inet_maskof();
|
||||
int sndmsg();
|
||||
int supply();
|
||||
int cleanup();
|
||||
#define NET_S_METRIC 1 /* metric used on synthetic routes */
|
||||
|
||||
int rtioctl();
|
||||
#define ADD 1
|
||||
#define DELETE 2
|
||||
#define CHANGE 3
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
/* 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_SUB 0x002 /* fake net route for subnet */
|
||||
# define RS_NET_HOST 0x004 /* fake net route for host */
|
||||
# define RS_NET_INT 0x008 /* authority route */
|
||||
# define RS_NET_S (RS_NET_SUB | RS_NET_HOST | RS_NET_INT)
|
||||
# define RS_SUBNET 0x010 /* subnet route from any source */
|
||||
# define RS_LOCAL 0x020 /* loopback for pt-to-pt */
|
||||
# define RS_MHOME 0x040 /* from -m */
|
||||
# define RS_GW 0x080 /* from -g */
|
||||
# define RS_STATIC 0x100 /* from the kernel */
|
||||
# define RS_RDISC 0x200 /* from router discovery */
|
||||
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_hold_metric;
|
||||
time_t rt_hold_down;
|
||||
};
|
||||
#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_GW | RS_MHOME | RS_STATIC \
|
||||
| RS_NET_SUB | RS_NET_HOST \
|
||||
| RS_RDISC)) \
|
||||
&& (!((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
|
||||
*/
|
||||
#define BETTER_LINK(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)))
|
||||
|
||||
|
||||
/* 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_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) */
|
||||
naddr int_host_addr; /* RIPv1 net for pt-to-pt link (h) */
|
||||
naddr int_host_mask; /* RIPv1 mask for pt-to-pt (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 */
|
||||
time_t int_quiet_time; /* last inactive */
|
||||
u_short int_transitions; /* times gone up-down */
|
||||
char int_metric;
|
||||
char int_d_metric; /* for faked default route */
|
||||
u_int int_data_ipackets; /* previous network stats */
|
||||
u_int int_data_ierrors;
|
||||
u_int int_data_opackets;
|
||||
u_int int_data_oerrors;
|
||||
#ifdef sgi
|
||||
u_int int_data_odrops;
|
||||
#endif
|
||||
time_t int_data_ts; /* timestamp on network stats */
|
||||
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_ACTIVE 0x0000400 /* heard from it at least once */
|
||||
#define IS_QUIET 0x0000800 /* have not heard from it recently */
|
||||
#define IS_NEED_NET_SUB 0x0001000 /* need RS_NET_SUB route */
|
||||
#define IS_NO_AG 0x0002000 /* do not aggregate subnets */
|
||||
#define IS_NO_SUPER_AG 0x0004000 /* do not aggregate networks */
|
||||
#define IS_NO_RIPV1_IN 0x0008000 /* no RIPv1 input at all */
|
||||
#define IS_NO_RIPV2_IN 0x0010000 /* no RIPv2 input at all */
|
||||
#define IS_NO_RIP_IN (IS_NO_RIPV2_IN | IS_NO_RIPV2_IN)
|
||||
#define IS_NO_RIPV1_OUT 0x0020000 /* no RIPv1 output at all */
|
||||
#define IS_NO_RIPV2_OUT 0x0040000 /* no RIPv2 output at all */
|
||||
#define IS_NO_RIP_OUT (IS_NO_RIPV1_OUT | IS_NO_RIPV2_OUT)
|
||||
#define IS_NO_ADV_IN 0x0080000
|
||||
#define IS_NO_SOL_OUT 0x0100000 /* no solicitations */
|
||||
#define IS_SOL_OUT 0x0200000 /* send solicitations */
|
||||
#define GROUP_IS_SOL (IS_NO_ADV_IN|IS_NO_SOL_OUT)
|
||||
#define IS_NO_ADV_OUT 0x0400000 /* do not advertise rdisc */
|
||||
#define IS_ADV_OUT 0x0800000 /* advertise rdisc */
|
||||
#define GROUP_IS_ADV (IS_NO_ADV_OUT|IS_ADV_OUT)
|
||||
#define IS_BCAST_RDISC 0x1000000 /* broadcast instead of multicast */
|
||||
|
||||
#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;
|
||||
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 0x01 /* 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_RIPV2 0x020 /* send only as RIPv2 */
|
||||
#define AGS_DEAD 0x080 /* dead--ignore differing gate */
|
||||
#define AGS_RDISC 0x100 /* suppresses most routes */
|
||||
};
|
||||
|
||||
|
||||
/* parameters for interfaces */
|
||||
extern struct parm {
|
||||
struct parm *parm_next;
|
||||
char parm_name[IFNAMSIZ+1];
|
||||
naddr parm_a_h;
|
||||
naddr parm_m;
|
||||
|
||||
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;
|
||||
} *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 default_gateway; /* 1=advertise default */
|
||||
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 ppp_noage; /* 1=do not age quiet link 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; /* have a RIPv1 interface */
|
||||
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 TRACEPACKETS (tracelevel >= 2) /* note packets */
|
||||
#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */
|
||||
#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};
|
||||
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
|
||||
#ifdef MCAST_PPP_BUG
|
||||
extern void mcasterr(struct interface *, int, char *);
|
||||
#define MCASTERR(ifp,dump,msg) mcasterr(ifp, dump, "setsockopt(IP_"msg")")
|
||||
#else
|
||||
#define MCASTERR(ifp, dump,msg) DBGERR(dump,"setsockopt(IP_" msg ")")
|
||||
#endif
|
||||
extern char *naddr_ntoa(naddr);
|
||||
extern char *saddr_ntoa(struct sockaddr *);
|
||||
|
||||
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 void get_parms(struct interface *);
|
||||
|
||||
extern void lastlog(void);
|
||||
extern void trace_on(char *, int);
|
||||
extern void trace_off(char*, char*);
|
||||
extern void trace_flush(void);
|
||||
extern void set_tracelevel(void);
|
||||
extern void trace_msg(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 ifbad_rdisc(struct interface *);
|
||||
extern void ifok_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 fix_kern(void);
|
||||
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, 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 *);
|
||||
|
||||
|
||||
extern struct rt_addrinfo rtinfo;
|
||||
#define S_ADDR(x) (((struct sockaddr_in *)(x))->sin_addr.s_addr)
|
||||
#define RTINFO_DST rtinfo.rti_info[RTAX_DST]
|
||||
#define RTINFO_GATE rtinfo.rti_info[RTAX_GATEWAY]
|
||||
#define RTINFO_NETMASK rtinfo.rti_info[RTAX_NETMASK]
|
||||
#define RTINFO_IFA rtinfo.rti_info[RTAX_IFA]
|
||||
#define RTINFO_AUTHOR rtinfo.rti_info[RTAX_AUTHOR]
|
||||
#define RTINFO_BRD rtinfo.rti_info[RTAX_BRD]
|
||||
#define RTINFO_IFP ((struct sockaddr_dl *)rtinfo.rti_info[RTAX_IFP])
|
||||
void rt_xaddrs(struct sockaddr *, struct sockaddr *, int);
|
||||
|
||||
extern naddr std_mask(naddr);
|
||||
extern naddr ripv1_mask_net(naddr, struct interface *, struct interface *);
|
||||
extern naddr ripv1_mask_host(naddr,struct interface *, struct interface *);
|
||||
#define on_net(tgt, net, mask) ((ntohl(tgt) & mask) == (net & mask))
|
||||
extern int check_dst(naddr);
|
||||
#ifdef sgi
|
||||
extern int sysctl(int *, u_int, void *, size_t *, void *, size_t);
|
||||
#endif
|
||||
extern void addrouteforif(register struct interface *);
|
||||
extern void ifinit(void);
|
||||
extern int walk_bad(struct radix_node *, struct walkarg *);
|
||||
extern int ifok(struct interface *, char *);
|
||||
extern void ifbad(struct interface *, char *);
|
||||
extern struct interface *ifwithaddr(naddr, int, int);
|
||||
extern struct interface *ifwithname(char *, naddr);
|
||||
extern struct interface *ifwithindex(u_short);
|
||||
extern struct interface *iflookup(naddr);
|
||||
|
|
|
|||
1083
usr.sbin/routed/if.c
1083
usr.sbin/routed/if.c
File diff suppressed because it is too large
Load diff
|
|
@ -35,328 +35,672 @@
|
|||
static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routing Table Management Daemon
|
||||
*/
|
||||
#ident "$Revision: 1.1.3.1 $"
|
||||
|
||||
#include "defs.h"
|
||||
#include <sys/syslog.h>
|
||||
|
||||
/*
|
||||
* Process a newly received packet.
|
||||
static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
|
||||
static void input_route(struct interface *, naddr,
|
||||
naddr, naddr, naddr, int, u_short);
|
||||
|
||||
|
||||
/* process RIP input
|
||||
*/
|
||||
rip_input(from, rip, size)
|
||||
struct sockaddr *from;
|
||||
register struct rip *rip;
|
||||
int size;
|
||||
void
|
||||
read_rip(int sock,
|
||||
struct interface *ifp)
|
||||
{
|
||||
register struct rt_entry *rt;
|
||||
register struct netinfo *n;
|
||||
register struct interface *ifp;
|
||||
struct interface *if_ifwithdstaddr();
|
||||
int count, changes = 0;
|
||||
register struct afswitch *afp;
|
||||
static struct sockaddr badfrom, badfrom2;
|
||||
struct sockaddr_in from;
|
||||
int fromlen, cc;
|
||||
union pkt_buf inbuf;
|
||||
|
||||
ifp = 0;
|
||||
TRACE_INPUT(ifp, from, (char *)rip, size);
|
||||
if (from->sa_family >= af_max ||
|
||||
(afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) {
|
||||
syslog(LOG_INFO,
|
||||
"\"from\" address in unsupported address family (%d), cmd %d\n",
|
||||
from->sa_family, rip->rip_cmd);
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
if (TRACEPACKETS)
|
||||
trace_rip("Recv", "from", from, ifp, rip, size);
|
||||
|
||||
if (rip->rip_vers == 0) {
|
||||
syslog(LOG_ERR,
|
||||
"RIP version 0 packet received from %s! (cmd %d)",
|
||||
(*afswitch[from->sa_family].af_format)(from), rip->rip_cmd);
|
||||
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;
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard authenticated RIPv2 message\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rip->rip_cmd) {
|
||||
|
||||
case RIPCMD_REQUEST:
|
||||
n = rip->rip_nets;
|
||||
count = size - ((char *)n - (char *)rip);
|
||||
if (count < sizeof (struct netinfo))
|
||||
return;
|
||||
for (; count > 0; n++) {
|
||||
if (count < sizeof (struct netinfo))
|
||||
break;
|
||||
count -= sizeof (struct netinfo);
|
||||
|
||||
#if BSD < 198810
|
||||
if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
|
||||
n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
|
||||
#else
|
||||
#define osa(x) ((struct osockaddr *)(&(x)))
|
||||
n->rip_dst.sa_family =
|
||||
ntohs(osa(n->rip_dst)->sa_family);
|
||||
n->rip_dst.sa_len = sizeof(n->rip_dst);
|
||||
#endif
|
||||
n->rip_metric = ntohl(n->rip_metric);
|
||||
/*
|
||||
* A single entry with sa_family == AF_UNSPEC and
|
||||
* metric ``infinity'' means ``all routes''.
|
||||
* We respond to routers only if we are acting
|
||||
* as a supplier, or to anyone other than a router
|
||||
* (eg, query).
|
||||
/* did the request come from a router?
|
||||
*/
|
||||
if (from->sin_port == htons(RIP_PORT)) {
|
||||
/* yes, ignore it if RIP is off
|
||||
*/
|
||||
if (n->rip_dst.sa_family == AF_UNSPEC &&
|
||||
n->rip_metric == HOPCNT_INFINITY && count == 0) {
|
||||
if (supplier || (*afp->af_portmatch)(from) == 0)
|
||||
supply(from, 0, 0, 0);
|
||||
if (rip_sock < 0) {
|
||||
trace_msg("ignore request while RIP off");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore the request if we talking to ourself
|
||||
* (and not a remote gateway).
|
||||
*/
|
||||
ifp1 = ifwithaddr(FROM_NADDR, 0, 0);
|
||||
if (ifp1 != 0
|
||||
&& (!(ifp1->int_state & IS_REMOTE)
|
||||
|| ifp->int_metric != 0)) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard our own packet\n");
|
||||
return;
|
||||
}
|
||||
if (n->rip_dst.sa_family < af_max &&
|
||||
afswitch[n->rip_dst.sa_family].af_hash)
|
||||
rt = rtlookup(&n->rip_dst);
|
||||
else
|
||||
rt = 0;
|
||||
#define min(a, b) (a < b ? a : b)
|
||||
n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
|
||||
min(rt->rt_metric + 1, HOPCNT_INFINITY);
|
||||
#if BSD < 198810
|
||||
if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
|
||||
n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
|
||||
#else
|
||||
osa(n->rip_dst)->sa_family =
|
||||
htons(n->rip_dst.sa_family);
|
||||
#endif
|
||||
n->rip_metric = htonl(n->rip_metric);
|
||||
}
|
||||
|
||||
/* According to RFC 1723, we should ignore unathenticated
|
||||
* queries. That is too silly to bother with.
|
||||
*/
|
||||
|
||||
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 */
|
||||
supply(from, ifp,
|
||||
OUT_QUERY, 0, rip->rip_vers);
|
||||
} else if (supplier) {
|
||||
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) {
|
||||
mask = ripv1_mask_host(dst,ifp,0);
|
||||
} else {
|
||||
mask = ntohl(n->n_mask);
|
||||
if (mask == 0)
|
||||
mask = ripv1_mask_host(dst,ifp,0);
|
||||
}
|
||||
rt = rtget(dst, mask);
|
||||
if (!rt)
|
||||
rt = rtfind(n->n_dst);
|
||||
|
||||
n->n_tag = 0;
|
||||
n->n_nhop = 0;
|
||||
if (!rt) {
|
||||
n->n_metric = HOPCNT_INFINITY;
|
||||
} else {
|
||||
n->n_metric = (rt->rt_metric
|
||||
+ (ifp ? ifp->int_metric : 1));
|
||||
if (n->n_metric > HOPCNT_INFINITY)
|
||||
n->n_metric = HOPCNT_INFINITY;
|
||||
if (rip->rip_vers == RIPv1) {
|
||||
n->n_mask = 0;
|
||||
} else {
|
||||
n->n_tag = rt->rt_tag;
|
||||
if (!ifp
|
||||
|| !on_net(rt->rt_gate,
|
||||
ifp->int_net,
|
||||
ifp->int_mask)
|
||||
|| rt->rt_gate != ifp->int_addr)
|
||||
n->n_nhop = 0;
|
||||
else
|
||||
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;
|
||||
bcopy((char *)rip, packet, size);
|
||||
(*afp->af_output)(s, 0, from, size);
|
||||
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 ((*afp->af_portcheck)(from) == 0)
|
||||
return;
|
||||
if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
|
||||
(IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
|
||||
ifp->int_flags & IFF_PASSIVE) {
|
||||
syslog(LOG_ERR, "trace command from unknown router, %s",
|
||||
(*afswitch[from->sa_family].af_format)(from));
|
||||
if (ntohs(from->sin_port) > IPPORT_RESERVED) {
|
||||
msglog("trace command from untrusted port on %s",
|
||||
naddr_ntoa(FROM_NADDR));
|
||||
return;
|
||||
}
|
||||
((char *)rip)[size] = '\0';
|
||||
if (rip->rip_cmd == RIPCMD_TRACEON)
|
||||
traceon(rip->rip_tracefile);
|
||||
else
|
||||
traceoff();
|
||||
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(rip->rip_tracefile, 0);
|
||||
} else {
|
||||
trace_off("tracing turned off by ",
|
||||
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 ((*afp->af_portmatch)(from) == 0)
|
||||
if (from->sin_port != ntohs(RIP_PORT)) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard response"
|
||||
" from unknown port\n");
|
||||
return;
|
||||
(*afp->af_canon)(from);
|
||||
/* are we talking to ourselves? */
|
||||
ifp = if_ifwithaddr(from);
|
||||
if (ifp) {
|
||||
if (ifp->int_flags & IFF_PASSIVE) {
|
||||
syslog(LOG_ERR,
|
||||
"bogus input (from passive interface, %s)",
|
||||
(*afswitch[from->sa_family].af_format)(from));
|
||||
}
|
||||
|
||||
if (rip_sock < 0) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard response while RIP off");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Are we talking to ourself or a remote gateway?
|
||||
*/
|
||||
ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
|
||||
if (ifp1) {
|
||||
if (ifp1->int_state & IS_PASSIVE) {
|
||||
msglog("bogus input from %s on supposedly"
|
||||
" passive interface %s",
|
||||
naddr_ntoa(FROM_NADDR),
|
||||
ifp1->int_name);
|
||||
|
||||
} else if (ifp1->int_state & IS_REMOTE) {
|
||||
ifp1->int_act_time = now.tv_sec;
|
||||
if (ifok(ifp1, "remote "))
|
||||
addrouteforif(ifp1);
|
||||
} else if (TRACEPACKETS) {
|
||||
trace_msg("discard our own packet\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 || (ifp->int_state & IS_PASSIVE)) {
|
||||
if (from->sin_addr.s_addr != unk_router)
|
||||
msglog("packet from unknown router %s",
|
||||
naddr_ntoa(FROM_NADDR));
|
||||
unk_router = from->sin_addr.s_addr;
|
||||
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)) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard RIPv%d response\n",
|
||||
rip->rip_vers);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore routes via dead interface.
|
||||
*/
|
||||
if (ifp->int_state & IS_BROKE) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard response via"
|
||||
" broken interface %s\n",
|
||||
ifp->int_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Authenticate the packet.
|
||||
*/
|
||||
if (ifp->int_passwd[0] != '\0'
|
||||
&& (n >= lim
|
||||
|| n->n_family != RIP_AF_AUTH
|
||||
|| ((struct netauth*)n)->a_type != RIP_AUTH_PW
|
||||
|| 0 != bcmp(((struct netauth*)n)->au.au_pw,
|
||||
ifp->int_passwd,
|
||||
sizeof(ifp->int_passwd)))) {
|
||||
if (from->sin_addr.s_addr != use_auth)
|
||||
msglog("missing authentication 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;
|
||||
}
|
||||
rt = rtfind(from);
|
||||
if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) &&
|
||||
rt->rt_metric >= ifp->int_metric)
|
||||
addrouteforif(ifp);
|
||||
else
|
||||
rt->rt_timer = 0;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Update timer for interface on which the packet arrived.
|
||||
* If from other end of a point-to-point link that isn't
|
||||
* in the routing tables, (re-)add the route.
|
||||
*/
|
||||
if ((rt = rtfind(from)) &&
|
||||
(rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
|
||||
rt->rt_timer = 0;
|
||||
else if ((ifp = if_ifwithdstaddr(from)) &&
|
||||
(rt == 0 || rt->rt_metric >= ifp->int_metric))
|
||||
addrouteforif(ifp);
|
||||
/*
|
||||
* "Authenticate" router from which message originated.
|
||||
* We accept routing packets from routers directly connected
|
||||
* via broadcast or point-to-point networks,
|
||||
* and from those listed in /etc/gateways.
|
||||
*/
|
||||
if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
|
||||
(IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
|
||||
ifp->int_flags & IFF_PASSIVE) {
|
||||
if (bcmp((char *)from, (char *)&badfrom,
|
||||
sizeof(badfrom)) != 0) {
|
||||
syslog(LOG_ERR,
|
||||
"packet from unknown router, %s",
|
||||
(*afswitch[from->sa_family].af_format)(from));
|
||||
badfrom = *from;
|
||||
}
|
||||
return;
|
||||
}
|
||||
size -= 4 * sizeof (char);
|
||||
n = rip->rip_nets;
|
||||
for (; size > 0; size -= sizeof (struct netinfo), n++) {
|
||||
if (size < sizeof (struct netinfo))
|
||||
break;
|
||||
#if BSD < 198810
|
||||
if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
|
||||
n->rip_dst.sa_family =
|
||||
ntohs(n->rip_dst.sa_family);
|
||||
#else
|
||||
n->rip_dst.sa_family =
|
||||
ntohs(osa(n->rip_dst)->sa_family);
|
||||
n->rip_dst.sa_len = sizeof(n->rip_dst);
|
||||
#endif
|
||||
n->rip_metric = ntohl(n->rip_metric);
|
||||
if (n->rip_dst.sa_family >= af_max ||
|
||||
(afp = &afswitch[n->rip_dst.sa_family])->af_hash ==
|
||||
(int (*)())0) {
|
||||
syslog(LOG_INFO,
|
||||
"route in unsupported address family (%d), from %s (af %d)\n",
|
||||
n->rip_dst.sa_family,
|
||||
(*afswitch[from->sa_family].af_format)(from),
|
||||
from->sa_family);
|
||||
continue;
|
||||
}
|
||||
if (((*afp->af_checkhost)(&n->rip_dst)) == 0) {
|
||||
syslog(LOG_DEBUG,
|
||||
"bad host in route from %s (af %d)\n",
|
||||
(*afswitch[from->sa_family].af_format)(from),
|
||||
from->sa_family);
|
||||
continue;
|
||||
}
|
||||
if (n->rip_metric == 0 ||
|
||||
(unsigned) n->rip_metric > HOPCNT_INFINITY) {
|
||||
if (bcmp((char *)from, (char *)&badfrom2,
|
||||
sizeof(badfrom2)) != 0) {
|
||||
syslog(LOG_ERR,
|
||||
"bad metric (%d) from %s\n",
|
||||
n->rip_metric,
|
||||
(*afswitch[from->sa_family].af_format)(from));
|
||||
badfrom2 = *from;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Adjust metric according to incoming interface.
|
||||
*/
|
||||
if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
|
||||
n->rip_metric += ifp->int_metric;
|
||||
if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
|
||||
n->rip_metric = HOPCNT_INFINITY;
|
||||
rt = rtlookup(&n->rip_dst);
|
||||
if (rt == 0 ||
|
||||
(rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
|
||||
(RTS_INTERNAL|RTS_INTERFACE)) {
|
||||
/*
|
||||
* If we're hearing a logical network route
|
||||
* back from a peer to which we sent it,
|
||||
* ignore it.
|
||||
*/
|
||||
if (rt && rt->rt_state & RTS_SUBNET &&
|
||||
(*afp->af_sendroute)(rt, from))
|
||||
continue;
|
||||
if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
|
||||
/*
|
||||
* Look for an equivalent route that
|
||||
* includes this one before adding
|
||||
* this route.
|
||||
*/
|
||||
rt = rtfind(&n->rip_dst);
|
||||
if (rt && equal(from, &rt->rt_router))
|
||||
continue;
|
||||
rtadd(&n->rip_dst, from, n->rip_metric, 0);
|
||||
changes++;
|
||||
}
|
||||
continue;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update if from gateway and different,
|
||||
* shorter, or equivalent but old route
|
||||
* is getting stale.
|
||||
/* Notice the next-hop.
|
||||
*/
|
||||
if (equal(from, &rt->rt_router)) {
|
||||
if (n->rip_metric != rt->rt_metric) {
|
||||
rtchange(rt, from, n->rip_metric);
|
||||
changes++;
|
||||
rt->rt_timer = 0;
|
||||
if (rt->rt_metric >= HOPCNT_INFINITY)
|
||||
rt->rt_timer =
|
||||
GARBAGE_TIME - EXPIRE_TIME;
|
||||
} else if (rt->rt_metric < HOPCNT_INFINITY)
|
||||
rt->rt_timer = 0;
|
||||
} else if ((unsigned) n->rip_metric < rt->rt_metric ||
|
||||
(rt->rt_metric == n->rip_metric &&
|
||||
rt->rt_timer > (EXPIRE_TIME/2) &&
|
||||
(unsigned) n->rip_metric < HOPCNT_INFINITY)) {
|
||||
rtchange(rt, from, n->rip_metric);
|
||||
changes++;
|
||||
rt->rt_timer = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mask = ntohl(n->n_mask);
|
||||
if (rip->rip_vers == RIPv1 || mask == 0) {
|
||||
mask = ripv1_mask_host(dst,ifp,0);
|
||||
} 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;
|
||||
}
|
||||
v1_mask = (have_ripv1
|
||||
? ripv1_mask_host(dst,0,0)
|
||||
: mask);
|
||||
|
||||
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.
|
||||
*/
|
||||
if (ifp->int_d_metric != 0
|
||||
&& dst == RIP_DEFAULT
|
||||
&& n->n_family == RIP_AF_UNSPEC
|
||||
&& n->n_metric > ifp->int_d_metric)
|
||||
continue;
|
||||
|
||||
/* We can receive aggregated RIPv2 routes via one
|
||||
* interface that must be broken down before
|
||||
* they are transmitted by RIPv1 via an interface
|
||||
* on a subnet. We might receive the same routes
|
||||
* aggregated otherwise 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_SUB.
|
||||
*/
|
||||
if (0 != (ntohl(dst) & (v1_mask & ~mask))) {
|
||||
ddst_h = v1_mask & -v1_mask;
|
||||
i = (v1_mask & ~mask)/ddst_h;
|
||||
if (i >= 1024) {
|
||||
/* Punt if we would have to generate
|
||||
* an unreasonable number of routes.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
msglog("accept %s from %s as-is"
|
||||
" instead of as %d routes",
|
||||
addrname(dst,mask,0),
|
||||
naddr_ntoa(FROM_NADDR), i);
|
||||
#endif
|
||||
i = 0;
|
||||
} else {
|
||||
mask = v1_mask;
|
||||
}
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
input_route(ifp, FROM_NADDR,
|
||||
dst, mask, gate,
|
||||
n->n_metric, n->n_tag);
|
||||
if (i-- == 0)
|
||||
break;
|
||||
dst = htonl(ntohl(dst) + ddst_h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If changes have occurred, and if we have not sent a broadcast
|
||||
* recently, send a dynamic update. This update is sent only
|
||||
* on interfaces other than the one on which we received notice
|
||||
* of the change. If we are within MIN_WAITTIME of a full update,
|
||||
* don't bother sending; if we just sent a dynamic update
|
||||
* and set a timer (nextbcast), delay until that time.
|
||||
* If we just sent a full update, delay the dynamic update.
|
||||
* Set a timer for a randomized value to suppress additional
|
||||
* dynamic updates until it expires; if we delayed sending
|
||||
* the current changes, set needupdate.
|
||||
*/
|
||||
if (changes && supplier &&
|
||||
now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
|
||||
u_long delay;
|
||||
extern long random();
|
||||
|
||||
if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
|
||||
timercmp(&nextbcast, &now, <)) {
|
||||
if (traceactions)
|
||||
fprintf(ftrace, "send dynamic update\n");
|
||||
toall(supply, RTS_CHANGED, ifp);
|
||||
lastbcast = now;
|
||||
needupdate = 0;
|
||||
nextbcast.tv_sec = 0;
|
||||
} else {
|
||||
needupdate++;
|
||||
if (traceactions)
|
||||
fprintf(ftrace, "delay dynamic update\n");
|
||||
}
|
||||
#define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \
|
||||
(u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
|
||||
|
||||
if (nextbcast.tv_sec == 0) {
|
||||
delay = RANDOMDELAY();
|
||||
if (traceactions)
|
||||
fprintf(ftrace,
|
||||
"inhibit dynamic update for %d usec\n",
|
||||
delay);
|
||||
nextbcast.tv_sec = delay / 1000000;
|
||||
nextbcast.tv_usec = delay % 1000000;
|
||||
timevaladd(&nextbcast, &now);
|
||||
/*
|
||||
* If the next possibly dynamic update
|
||||
* is within MIN_WAITTIME of the next full update,
|
||||
* force the delay past the full update,
|
||||
* or we might send a dynamic update just before
|
||||
* the full update.
|
||||
*/
|
||||
if (nextbcast.tv_sec > lastfullupdate.tv_sec +
|
||||
SUPPLY_INTERVAL - MIN_WAITTIME)
|
||||
nextbcast.tv_sec = lastfullupdate.tv_sec +
|
||||
SUPPLY_INTERVAL + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Process a single input route.
|
||||
*/
|
||||
static void
|
||||
input_route(struct interface *ifp,
|
||||
naddr from,
|
||||
naddr dst,
|
||||
naddr mask,
|
||||
naddr gate,
|
||||
int metric,
|
||||
u_short tag)
|
||||
{
|
||||
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) {
|
||||
/* Usually ignore routes being poisoned.
|
||||
*/
|
||||
if (metric == HOPCNT_INFINITY)
|
||||
return;
|
||||
|
||||
rtadd(dst, mask, gate, from, metric, tag, 0, ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We already know about the route. Consider
|
||||
* this update.
|
||||
*
|
||||
* If (rt->rt_state & RS_NET_SUB), 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(rts0, rts))
|
||||
rts0 = rts;
|
||||
}
|
||||
if (i != 0) {
|
||||
/* Found the router
|
||||
*/
|
||||
int old_metric = rts->rts_metric;
|
||||
|
||||
if (old_metric < HOPCNT_INFINITY) {
|
||||
new_time = now.tv_sec;
|
||||
} else {
|
||||
/* Keep poisoned routes around only long
|
||||
* enough to pass the poison on.
|
||||
*/
|
||||
new_time = rts->rts_time;
|
||||
if (new_time > now.tv_sec-POISON_SECS)
|
||||
new_time = now.tv_sec-POISON_SECS;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
metric, tag, ifp, new_time, 0);
|
||||
/* If the route got worse, check for something better.
|
||||
*/
|
||||
if (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 == metric
|
||||
&& rts->rts_tag == 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
|
||||
* with metric HOPCNT_INFINITY).
|
||||
*/
|
||||
if (metric >= rts->rts_metric)
|
||||
return;
|
||||
|
||||
new_time = now.tv_sec;
|
||||
}
|
||||
|
||||
if (TRACEACTIONS)
|
||||
trace_upslot(rt, rts, gate, from, ifp, metric, tag, new_time);
|
||||
rts->rts_gate = gate;
|
||||
rts->rts_router = from;
|
||||
rts->rts_metric = metric;
|
||||
rts->rts_tag = tag;
|
||||
rts->rts_time = new_time;
|
||||
rts->rts_ifp = ifp;
|
||||
|
||||
/* try to switch to a better route */
|
||||
rtswitch(rt, rts);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -35,138 +35,714 @@
|
|||
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routing Table Management Daemon
|
||||
*/
|
||||
#ident "$Revision: 1.1.3.1 $"
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/*
|
||||
* Apply the function "f" to all non-passive
|
||||
* interfaces. If the interface supports the
|
||||
* use of broadcasting use it, otherwise address
|
||||
* the output to the known router.
|
||||
*/
|
||||
toall(f, rtstate, skipif)
|
||||
int (*f)();
|
||||
int rtstate;
|
||||
struct interface *skipif;
|
||||
{
|
||||
register struct interface *ifp;
|
||||
register struct sockaddr *dst;
|
||||
register int flags;
|
||||
extern struct interface *ifnet;
|
||||
|
||||
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
|
||||
if (ifp->int_flags & IFF_PASSIVE || ifp == skipif)
|
||||
continue;
|
||||
dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
|
||||
ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
|
||||
&ifp->int_addr;
|
||||
flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
|
||||
(*f)(dst, flags, ifp, rtstate);
|
||||
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 { /* for each buffer */
|
||||
struct rip *buf;
|
||||
struct netinfo *n;
|
||||
struct netinfo *base;
|
||||
struct netinfo *lim;
|
||||
enum output_type type;
|
||||
} v2, mcast;
|
||||
char metric; /* adjust metrics by interface */
|
||||
int npackets;
|
||||
int state;
|
||||
#define WS_ST_FLASH 0x01 /* send only changed routes */
|
||||
#define WS_ST_RIP2_SAFE 0x02 /* send RIPv2 safe for RIPv1 */
|
||||
#define WS_ST_RIP2_ALL 0x04 /* full featured RIPv2 */
|
||||
#define WS_ST_AG 0x08 /* ok to aggregate subnets */
|
||||
#define WS_ST_SUPER_AG 0x10 /* ok to aggregate networks */
|
||||
#define WS_ST_QUERY 0x20 /* responding to a query */
|
||||
#define WS_ST_TO_ON_NET 0x40 /* sending onto one of our nets */
|
||||
#define WS_ST_DEFAULT 0x80 /* faking a default */
|
||||
} ws;
|
||||
|
||||
/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */
|
||||
union pkt_buf ripv2_buf;
|
||||
|
||||
/* Another for only RIPv2 listeners */
|
||||
union pkt_buf rip_mcast_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, serrno;
|
||||
naddr tgt_mcast;
|
||||
int soc;
|
||||
|
||||
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 pt-to-pt";
|
||||
} else {
|
||||
msg = "Send";
|
||||
}
|
||||
flags = MSG_DONTROUTE;
|
||||
break;
|
||||
case OUT_MULTICAST:
|
||||
if (ifp->int_if_flags & IFF_POINTOPOINT) {
|
||||
msg = "Send pt-to-pt";
|
||||
} 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 (setsockopt(rip_sock,
|
||||
IPPROTO_IP, IP_MULTICAST_IF,
|
||||
&tgt_mcast, sizeof(tgt_mcast)))
|
||||
BADERR(1,"setsockopt(rip_sock,"
|
||||
"IP_MULTICAST_IF)");
|
||||
rip_sock_mcast = ifp;
|
||||
}
|
||||
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
if (TRACEPACKETS)
|
||||
trace_rip(msg, "to", &sin, ifp, buf, size);
|
||||
|
||||
res = sendto(soc, buf, size, flags,
|
||||
(struct sockaddr *)&sin, sizeof(sin));
|
||||
if (res < 0) {
|
||||
serrno = errno;
|
||||
msglog("sendto(%s%s%s.%d): %s",
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a preformed packet.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
sndmsg(dst, flags, ifp, rtstate)
|
||||
struct sockaddr *dst;
|
||||
int flags;
|
||||
struct interface *ifp;
|
||||
int rtstate;
|
||||
{
|
||||
|
||||
(*afswitch[dst->sa_family].af_output)(s, flags,
|
||||
dst, sizeof (struct rip));
|
||||
TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
|
||||
/* Send the buffer
|
||||
*/
|
||||
static void
|
||||
supply_write(struct ws_buf *w)
|
||||
{
|
||||
/* Output multicast only if legal.
|
||||
* If we would multcast and it would be illegal, then discard the
|
||||
* packet.
|
||||
*/
|
||||
if (w != &ws.mcast
|
||||
|| ((ws.state & WS_ST_RIP2_SAFE)
|
||||
&& (ws.ifp == 0
|
||||
|| (ws.ifp->int_if_flags & IFF_MULTICAST)))) {
|
||||
if (output(w->type, &ws.to, ws.ifp, w->buf,
|
||||
((char *)w->n - (char*)w->buf)) < 0
|
||||
&& ws.ifp != 0)
|
||||
ifbad(ws.ifp, 0);
|
||||
ws.npackets++;
|
||||
}
|
||||
|
||||
bzero(w->n = w->base, sizeof(*w->n)*NETS_LEN);
|
||||
|
||||
if (w->buf->rip_vers == RIPv2)
|
||||
set_auth(w);
|
||||
}
|
||||
|
||||
/*
|
||||
* Supply dst with the contents of the routing tables.
|
||||
|
||||
/* 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 *w;
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
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,
|
||||
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.
|
||||
*/
|
||||
if ((ws.state & WS_ST_RIP2_ALL)
|
||||
|| ((ag->ag_state & AGS_RIPV2)
|
||||
&& v1_mask != mask)) {
|
||||
w = &ws.mcast; /* use the multicast-only buffer */
|
||||
|
||||
} else {
|
||||
w = &ws.v2;
|
||||
|
||||
/* 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 >= 1024) {
|
||||
/* Punt if we would have to generate an
|
||||
* unreasonable number of routes.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
msglog("sending %s to %s as-is instead"
|
||||
" of as %d routes",
|
||||
addrname(htonl(dst_h),mask,0),
|
||||
naddr_ntoa(ws.to.sin_addr.s_addr), i);
|
||||
#endif
|
||||
i = 0;
|
||||
|
||||
} else {
|
||||
mask = v1_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
w->n->n_family = RIP_AF_INET;
|
||||
w->n->n_dst = htonl(dst_h);
|
||||
w->n->n_metric = stopint ? HOPCNT_INFINITY : ag->ag_metric;
|
||||
HTONL(w->n->n_metric);
|
||||
if (w->buf->rip_vers == RIPv2) {
|
||||
w->n->n_nhop = ag->ag_gate;
|
||||
if ((ws.state & WS_ST_RIP2_ALL)
|
||||
|| mask != s_mask)
|
||||
w->n->n_mask = htonl(mask);
|
||||
w->n->n_tag = ag->ag_tag;
|
||||
}
|
||||
dst_h += ddst_h;
|
||||
|
||||
if (++w->n >= w->lim)
|
||||
supply_write(w);
|
||||
} 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;
|
||||
char metric, pref;
|
||||
naddr dst, gate;
|
||||
|
||||
/* 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)))
|
||||
return 0;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
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))
|
||||
return 0;
|
||||
|
||||
dst = RT->rt_dst;
|
||||
|
||||
/* If being quiet about our ability to forward, then
|
||||
* do not say anything except our own host number,
|
||||
* unless responding to a query.
|
||||
*/
|
||||
if (!supplier
|
||||
&& (!mhome || myaddr != dst)
|
||||
&& !(ws.state & WS_ST_QUERY))
|
||||
return 0;
|
||||
|
||||
ags = 0;
|
||||
|
||||
/* do not override the fake default route */
|
||||
if (dst == RIP_DEFAULT
|
||||
&& (ws.state & WS_ST_DEFAULT))
|
||||
return 0;
|
||||
|
||||
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, then do so.
|
||||
*/
|
||||
if ((RT->rt_state & RS_LOCAL)
|
||||
|| ridhosts)
|
||||
ags |= AGS_SUPPRESS;
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
/* Never aggregate our own interfaces,
|
||||
* or the host route for multi-homed servers.
|
||||
*/
|
||||
if (0 != (RT->rt_state & (RS_IF | RS_MHOME)))
|
||||
ags &= ~(AGS_SUPPRESS | AGS_PROMOTE);
|
||||
|
||||
|
||||
if (RT->rt_state & RS_SUBNET) {
|
||||
/* Do not send authority routes into the subnet,
|
||||
* or when RIP is off.
|
||||
*/
|
||||
if ((RT->rt_state & RS_NET_INT)
|
||||
&& (on_net(dst, ws.to_net, ws.to_mask)
|
||||
|| rip_sock < 0))
|
||||
return 0;
|
||||
|
||||
/* Do not send RIPv1 advertisements of subnets to
|
||||
* other networks.
|
||||
*
|
||||
* If possible, multicast them by RIPv2.
|
||||
*/
|
||||
if (!(ws.state & WS_ST_RIP2_ALL)
|
||||
&& !on_net(dst, ws.to_std_net, ws.to_std_mask))
|
||||
ags |= AGS_RIPV2;
|
||||
|
||||
} else if (RT->rt_state & RS_NET_SUB) {
|
||||
/* do not send synthetic network routes if no RIPv1
|
||||
* listeners might hear.
|
||||
*/
|
||||
if (ws.state & WS_ST_RIP2_ALL)
|
||||
return 0;
|
||||
|
||||
/* Do not send synthetic network routes on the real subnet */
|
||||
if (on_net(dst, ws.to_std_net, ws.to_std_mask))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* forget synthetic routes when RIP is off */
|
||||
if (rip_sock < 0 && 0 != (RT->rt_state & RS_NET_S))
|
||||
return 0;
|
||||
|
||||
|
||||
/* Adjust outgoing metric by the cost of the link.
|
||||
* Interface routes have already been adjusted.
|
||||
*/
|
||||
pref = metric = RT->rt_metric + ws.metric;
|
||||
if (metric >= HOPCNT_INFINITY) {
|
||||
metric = HOPCNT_INFINITY;
|
||||
pref = ((RT->rt_hold_down > now.tv_sec)
|
||||
? RT->rt_hold_metric
|
||||
: metric);
|
||||
}
|
||||
|
||||
/* 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 ((ws.state & WS_ST_RIP2_SAFE)
|
||||
&& !(RT->rt_state & RS_IF)
|
||||
&& ((ws.state & WS_ST_QUERY)
|
||||
|| (on_net(RT->rt_gate, ws.ifp->int_net, ws.ifp->int_mask)
|
||||
&& RT->rt_gate != ws.ifp->int_addr))) {
|
||||
gate = RT->rt_gate;
|
||||
} else {
|
||||
gate = 0;
|
||||
}
|
||||
|
||||
ag_check(dst, RT->rt_mask, gate, 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.
|
||||
*/
|
||||
supply(dst, flags, ifp, rtstate)
|
||||
struct sockaddr *dst;
|
||||
int flags;
|
||||
register struct interface *ifp;
|
||||
int rtstate;
|
||||
void
|
||||
supply(struct sockaddr_in *dst,
|
||||
struct interface *ifp, /* output interface */
|
||||
enum output_type type,
|
||||
int flash, /* 1=flash update */
|
||||
int vers) /* RIP version */
|
||||
{
|
||||
register struct rt_entry *rt;
|
||||
register struct netinfo *n = msg->rip_nets;
|
||||
register struct rthash *rh;
|
||||
struct rthash *base = hosthash;
|
||||
int doinghost = 1, size;
|
||||
int (*output)() = afswitch[dst->sa_family].af_output;
|
||||
int (*sendroute)() = afswitch[dst->sa_family].af_sendroute;
|
||||
int npackets = 0;
|
||||
static int init = 1;
|
||||
struct rt_entry *rt;
|
||||
int metric;
|
||||
|
||||
msg->rip_cmd = RIPCMD_RESPONSE;
|
||||
msg->rip_vers = RIPVERSION;
|
||||
bzero(msg->rip_res1, sizeof(msg->rip_res1));
|
||||
again:
|
||||
for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
|
||||
for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
|
||||
/*
|
||||
* Don't resend the information on the network
|
||||
* from which it was received (unless sending
|
||||
* in response to a query).
|
||||
|
||||
ws.state = 0;
|
||||
|
||||
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, 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 = 0;
|
||||
} else {
|
||||
/* Adjust the advertised metric by the outgoing interface
|
||||
* metric, but reduced by 1 to avoid counting this hop
|
||||
* twice.
|
||||
*/
|
||||
if (ifp && rt->rt_ifp == ifp &&
|
||||
(rt->rt_state & RTS_INTERFACE) == 0)
|
||||
continue;
|
||||
if (rt->rt_state & RTS_EXTERNAL)
|
||||
continue;
|
||||
/*
|
||||
* For dynamic updates, limit update to routes
|
||||
* with the specified state.
|
||||
*/
|
||||
if (rtstate && (rt->rt_state & rtstate) == 0)
|
||||
continue;
|
||||
/*
|
||||
* Limit the spread of subnet information
|
||||
* to those who are interested.
|
||||
*/
|
||||
if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
|
||||
if (rt->rt_dst.sa_family != dst->sa_family)
|
||||
continue;
|
||||
if ((*sendroute)(rt, dst) == 0)
|
||||
continue;
|
||||
ws.metric = ifp->int_metric;
|
||||
if (ws.metric > 0)
|
||||
ws.metric--;
|
||||
}
|
||||
|
||||
if (init) {
|
||||
init = 0;
|
||||
|
||||
bzero(&ripv2_buf, sizeof(ripv2_buf));
|
||||
ripv2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
|
||||
ws.v2.buf = &ripv2_buf.rip;
|
||||
ws.v2.base = &ws.v2.buf->rip_nets[0];
|
||||
ws.v2.lim = ws.v2.base + NETS_LEN;
|
||||
|
||||
bzero(&rip_mcast_buf, sizeof(rip_mcast_buf));
|
||||
rip_mcast_buf.rip.rip_cmd = RIPCMD_RESPONSE;
|
||||
rip_mcast_buf.rip.rip_vers = RIPv2;
|
||||
ws.mcast.buf = &rip_mcast_buf.rip;
|
||||
ws.mcast.base = &ws.mcast.buf->rip_nets[0];
|
||||
ws.mcast.lim = ws.mcast.base + NETS_LEN;
|
||||
}
|
||||
ripv2_buf.rip.rip_vers = vers;
|
||||
|
||||
ws.v2.type = type;
|
||||
ws.v2.n = ws.v2.base;
|
||||
set_auth(&ws.v2);
|
||||
|
||||
ws.mcast.type = (type == OUT_BROADCAST) ? OUT_MULTICAST : type;
|
||||
ws.mcast.n = ws.mcast.base;
|
||||
set_auth(&ws.mcast);
|
||||
|
||||
if (vers == RIPv2) {
|
||||
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;
|
||||
}
|
||||
size = (char *)n - packet;
|
||||
if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
|
||||
TRACE_OUTPUT(ifp, dst, size);
|
||||
(*output)(s, flags, dst, size);
|
||||
/*
|
||||
* If only sending to ourselves,
|
||||
* one packet is enough to monitor interface.
|
||||
*/
|
||||
if (ifp && (ifp->int_flags &
|
||||
(IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0)
|
||||
return;
|
||||
n = msg->rip_nets;
|
||||
npackets++;
|
||||
}
|
||||
n->rip_dst = rt->rt_dst;
|
||||
#if BSD < 198810
|
||||
if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
|
||||
n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
|
||||
}
|
||||
|
||||
/* send the routes
|
||||
*/
|
||||
if ((metric = ifp->int_d_metric) != 0) {
|
||||
/* Fake a default route if asked */
|
||||
ws.state |= WS_ST_DEFAULT;
|
||||
|
||||
/* Use the metric of a real default, if there is one.
|
||||
*/
|
||||
rt = rtget(RIP_DEFAULT, 0);
|
||||
if (rt != 0
|
||||
&& rt->rt_metric+ws.metric < metric)
|
||||
metric = rt->rt_metric+ws.metric;
|
||||
|
||||
if (metric < HOPCNT_INFINITY)
|
||||
ag_check(0, 0, 0, metric,metric, 0, 0, 0, supply_out);
|
||||
}
|
||||
(void)rn_walktree(rhead, walk_supply, 0);
|
||||
ag_flush(0,0,supply_out);
|
||||
|
||||
/* Flush the packet buffers */
|
||||
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 (ws.mcast.n != ws.mcast.base
|
||||
&& (ws.mcast.n > ws.mcast.base+1
|
||||
|| ws.mcast.n->n_family != RIP_AF_AUTH))
|
||||
supply_write(&ws.mcast);
|
||||
|
||||
/* 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.v2);
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
#define osa(x) ((struct osockaddr *)(&(x)))
|
||||
osa(n->rip_dst)->sa_family = htons(n->rip_dst.sa_family);
|
||||
static struct sockaddr_in dst = {AF_INET};
|
||||
#endif
|
||||
n->rip_metric = htonl(rt->rt_metric);
|
||||
n++;
|
||||
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_msg("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;
|
||||
|
||||
/* Prefer RIPv1 announcements unless RIPv2 is on and
|
||||
* RIPv2 is off.
|
||||
*/
|
||||
if (ifp->int_state & IS_NO_RIPV1_OUT) {
|
||||
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 (!(ifp->int_state & IS_NO_RIPV1_OUT)) {
|
||||
type = OUT_BROADCAST;
|
||||
} else {
|
||||
type = OUT_MULTICAST;
|
||||
}
|
||||
|
||||
} 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);
|
||||
}
|
||||
if (doinghost) {
|
||||
doinghost = 0;
|
||||
base = nethash;
|
||||
goto again;
|
||||
}
|
||||
if (n != msg->rip_nets || (npackets == 0 && rtstate == 0)) {
|
||||
size = (char *)n - packet;
|
||||
TRACE_OUTPUT(ifp, dst, size);
|
||||
(*output)(s, flags, dst, size);
|
||||
|
||||
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;
|
||||
|
||||
/* prefer RIPv2 queries */
|
||||
if (ifp->int_state & IS_NO_RIPV2_OUT) {
|
||||
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 (!(ifp->int_state & IS_NO_RIPV1_OUT)) {
|
||||
type = OUT_BROADCAST;
|
||||
} else {
|
||||
type = OUT_MULTICAST;
|
||||
}
|
||||
|
||||
} 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)
|
||||
ifbad(ifp,0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,3 +36,8 @@
|
|||
#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.
|
||||
*/
|
||||
#define _PATH_TRACE "/tmp"
|
||||
|
|
|
|||
|
|
@ -31,314 +31,483 @@
|
|||
.\"
|
||||
.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd December 11, 1993
|
||||
.Dd March 1, 1996
|
||||
.Dt ROUTED 8
|
||||
.Os BSD 4.2
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm routed
|
||||
.Nd network routing daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm routed
|
||||
.Op Fl d
|
||||
.Op Fl g
|
||||
.Op Fl q
|
||||
.Op Fl s
|
||||
.Op Fl t
|
||||
.Op Ar logfile
|
||||
.Nm
|
||||
.Op Fl sqdghmpAt
|
||||
.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 invoked at boot time to manage the network routing tables.
|
||||
The routing daemon uses a variant of the Xerox NS Routing
|
||||
Information Protocol in maintaining up to date kernel routing
|
||||
table entries.
|
||||
It used a generalized protocol capable of use with multiple
|
||||
address types, but is currently used only for Internet routing
|
||||
within a cluster of networks.
|
||||
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 version of the RIPv1 protocol implemented
|
||||
is based on the RIPv1 protocol implemented in the reference 4.3BSD daemon.
|
||||
.Pp
|
||||
In normal operation
|
||||
.Nm routed
|
||||
listens on the
|
||||
It listens on the
|
||||
.Xr udp 4
|
||||
socket for the
|
||||
.Xr route 8
|
||||
service (see
|
||||
.Xr services 5 )
|
||||
for routing information packets. If the host is an
|
||||
internetwork router, it periodically supplies copies
|
||||
of its routing tables to any directly connected hosts
|
||||
and networks.
|
||||
for Routing Information Protocol packets.
|
||||
It also sends and receives multicast Router Discovery ICMP messages.
|
||||
If the host is an 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
|
||||
.Nm routed
|
||||
is started, it uses the
|
||||
.Dv SIOCGIFCONF
|
||||
.Xr ioctl 2
|
||||
to find those
|
||||
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'' (the software loopback interface
|
||||
is ignored). If multiple interfaces
|
||||
are present, it is assumed that the host will forward packets
|
||||
between networks.
|
||||
.Nm Routed
|
||||
then transmits a
|
||||
.Em request
|
||||
packet on each interface (using a broadcast packet if
|
||||
the interface supports it) and enters a loop, listening
|
||||
for
|
||||
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
|
||||
.Em response
|
||||
packets from other hosts.
|
||||
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 routed
|
||||
packet is received,
|
||||
.Nm
|
||||
formulates a reply based on the information maintained in its
|
||||
internal tables. The
|
||||
internal tables.
|
||||
The
|
||||
.Em response
|
||||
packet generated contains a list of known routes, each marked
|
||||
with a ``hop count'' metric (a count of 16, or greater, is
|
||||
considered ``infinite''). The metric associated with each
|
||||
route returned provides a metric
|
||||
.Em relative to the sender .
|
||||
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
|
||||
.Em Response
|
||||
packets received by
|
||||
.Nm routed
|
||||
are used to update the routing tables if one of the following
|
||||
conditions is satisfied:
|
||||
.Bl -enum
|
||||
.It
|
||||
No routing table entry exists for the destination network
|
||||
or host, and the metric indicates the destination is ``reachable''
|
||||
(i.e. the hop count is not infinite).
|
||||
.It
|
||||
The source host of the packet is the same as the router in the
|
||||
existing routing table entry. That is, updated information is
|
||||
being received from the very internetwork router through which
|
||||
packets for the destination are being routed.
|
||||
.It
|
||||
The existing entry in the routing table has not been updated for
|
||||
some time (defined to be 90 seconds) and the route is at least
|
||||
as cost effective as the current route.
|
||||
.It
|
||||
The new route describes a shorter route to the destination than
|
||||
the one currently stored in the routing tables; the metric of
|
||||
the new route is compared against the one stored in the table
|
||||
to decide this.
|
||||
.El
|
||||
Responses do not contain routes with a first hop on the resquesting
|
||||
network to implement
|
||||
.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 routed
|
||||
records the change in its internal tables and updates the kernel
|
||||
routing table.
|
||||
The change is reflected in the next
|
||||
.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
|
||||
packet sent.
|
||||
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 routed
|
||||
.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
|
||||
an additional 60 seconds to insure the invalidation is propagated
|
||||
throughout the local internet.
|
||||
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 minimze
|
||||
.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.
|
||||
The response is sent to the broadcast address on nets capable of that function,
|
||||
The response is 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.
|
||||
The normal routing tables are bypassed when sending gratuitous responses.
|
||||
The reception of responses on each network is used to determine that the
|
||||
network and interface are functioning correctly.
|
||||
If no response is received on an interface, another route may be chosen
|
||||
to route around the interface, or the route may be dropped if no alternative
|
||||
is available.
|
||||
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
|
||||
Options supported by
|
||||
.Nm routed :
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d
|
||||
Enable additional debugging information to be logged,
|
||||
such as bad packets received.
|
||||
.It Fl g
|
||||
This flag is used on internetwork routers to offer a route
|
||||
to the ``default'' destination.
|
||||
This is typically used on a gateway to the Internet,
|
||||
or on a gateway that uses another routing protocol whose routes
|
||||
are not reported to other local routers.
|
||||
.It Fl s
|
||||
Supplying this
|
||||
option forces
|
||||
.Nm routed
|
||||
to supply routing information whether it is acting as an internetwork
|
||||
router or not.
|
||||
This is the default if multiple network interfaces are present,
|
||||
or if a point-to-point link is in use.
|
||||
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
|
||||
This
|
||||
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.
|
||||
This is typically used on a gateway to the Internet,
|
||||
or on a gateway that uses another routing protocol whose routes
|
||||
are not reported to other local routers.
|
||||
.It Fl 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 p
|
||||
causes routes received over point-to-point links to not be timed
|
||||
out while the link is idle.
|
||||
This is handy for "demand dialed" PPP links that filter routing packets.
|
||||
.It Fl A
|
||||
do not ignore RIPv2 authentication if we do not care about RIPv2
|
||||
authentication.
|
||||
This option is required for conformance wiht RFC 1723,
|
||||
but it makes little 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 file.
|
||||
.It Fl t
|
||||
If the
|
||||
.Fl t
|
||||
option is specified, all packets sent or received are
|
||||
printed on the standard output. In addition,
|
||||
.Nm routed
|
||||
will not divorce itself from the controlling terminal
|
||||
so that interrupts from the keyboard will kill the process.
|
||||
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.
|
||||
.It Fl F Ar net[/mask][,metric]
|
||||
minimize routes in transmissions to network
|
||||
.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.
|
||||
.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 file in which
|
||||
.Nm routed Ns \'s
|
||||
actions should be logged. This log contains information
|
||||
about any changes to the routing tables and, if not tracing all packets,
|
||||
a history of recent messages sent and received which are related to
|
||||
the changed route.
|
||||
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
|
||||
In addition to the facilities described above,
|
||||
.Nm routed
|
||||
supports the notion of ``distant''
|
||||
.Nm
|
||||
also supports the notion of
|
||||
"distant"
|
||||
.Em passive
|
||||
and
|
||||
or
|
||||
.Em active
|
||||
gateways. When
|
||||
.Nm routed
|
||||
is started up, it reads the file
|
||||
gateways.
|
||||
When
|
||||
.Nm
|
||||
is started, it reads the file
|
||||
.Pa /etc/gateways
|
||||
to find gateways which may not be located using
|
||||
only information from the
|
||||
.Dv SIOCGIFCONF
|
||||
.Xr ioctl 2 .
|
||||
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 routing information (i.e.
|
||||
they should have a
|
||||
.Nm routed
|
||||
process running on the machine).
|
||||
Routes through passive gateways are installed in the
|
||||
kernel's routing tables once upon startup.
|
||||
Such routes are not included in
|
||||
any routing information transmitted.
|
||||
Active gateways are treated equally to network
|
||||
interfaces. Routing information is distributed
|
||||
to the gateway and if no routing information is
|
||||
received for a period of time, the associated
|
||||
route is deleted.
|
||||
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 and if no responses are received
|
||||
in turn for a period of the time, the associated route 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 inform
|
||||
.Nm routed
|
||||
The function of external entries is to indicate
|
||||
that another routing process
|
||||
will install such a route, and that alternate routes to that destination
|
||||
should not be installed.
|
||||
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
|
||||
.Pa /etc/gateways
|
||||
is comprised of a series of lines, each in
|
||||
the following format:
|
||||
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
|
||||
.Pf < Cm net No \&|
|
||||
.Cm host Ns >
|
||||
.Ar name1
|
||||
.Cm net
|
||||
.Ar Nname[/mask]
|
||||
.Cm gateway
|
||||
.Ar name2
|
||||
.Ar Gname
|
||||
.Cm metric
|
||||
.Ar value
|
||||
.Pf < Cm passive No \&|
|
||||
.Cm external Ns >
|
||||
.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
|
||||
The
|
||||
.Cm net
|
||||
.Ar Nname
|
||||
or
|
||||
.Cm host
|
||||
keyword indicates if the route is to a network or specific host.
|
||||
.Pp
|
||||
.Ar Name1
|
||||
is the name of the destination network or host. This may be a
|
||||
symbolic name located in
|
||||
.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, if started after
|
||||
.Pa /etc/hosts ,
|
||||
or
|
||||
.Xr named 8 ,
|
||||
known to the name server),
|
||||
or an Internet address specified in ``dot'' notation; see
|
||||
.Xr inet 3 .
|
||||
must have been started before
|
||||
.Xr routed Ns .)
|
||||
.Pp
|
||||
.Ar Name2
|
||||
is the name or address of the gateway to which messages should
|
||||
.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 a metric indicating the hop count to the destination host
|
||||
or network.
|
||||
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 passive ,
|
||||
.Cm active
|
||||
or
|
||||
.Cm external
|
||||
indicates if the gateway should be treated as
|
||||
must be present to indicate whether the gateway should be treated as
|
||||
.Em passive
|
||||
or
|
||||
.Em active
|
||||
(as described above),
|
||||
or whether the gateway is
|
||||
.Em external
|
||||
to the scope of the
|
||||
.Nm routed
|
||||
protocol.
|
||||
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:
|
||||
.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]
|
||||
causes other routes to be aggregated as if a compatible route to
|
||||
Ar nname/mask
|
||||
had been received.
|
||||
This is useful for filling "holes" in CIDR allocations.
|
||||
This parameter must appear by itself on a line.
|
||||
.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.
|
||||
.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 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.
|
||||
.Ar " No_rip "
|
||||
is equivalent to
|
||||
.Ar " no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out ."
|
||||
.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
|
||||
disables the RIPv2 responses that are otherwise multicast containing
|
||||
information that cannot be sent in RIPv2 packets.
|
||||
.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 affected interface.
|
||||
.El
|
||||
.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 IPXrouted 8
|
||||
.\" .Xr XNSrouted 8 ,
|
||||
.\" .Xr htable 8
|
||||
.Xr htable 8 ,
|
||||
.Xr rtquery 8 .
|
||||
.Rs
|
||||
.%T Internet Transport Protocols
|
||||
.%R XSIS 028112
|
||||
.%Q Xerox System Integration Standard
|
||||
.Re
|
||||
.Sh BUGS
|
||||
The kernel's routing tables may not correspond to those of
|
||||
.Nm routed
|
||||
when redirects change or add routes.
|
||||
.Nm Routed
|
||||
should note any redirects received by reading
|
||||
the
|
||||
.Tn ICMP
|
||||
packets received via a raw socket.
|
||||
.Pp
|
||||
.Nm Routed
|
||||
should incorporate other routing protocols,
|
||||
such as Xerox
|
||||
.Tn \&NS
|
||||
.Pq Xr XNSrouted 8
|
||||
and
|
||||
.Tn EGP .
|
||||
Using separate processes for each requires configuration options
|
||||
to avoid redundant or competing routes.
|
||||
.Pp
|
||||
.Nm Routed
|
||||
should listen to intelligent interfaces, such as an
|
||||
.Tn IMP ,
|
||||
to gather more information.
|
||||
It does not always detect unidirectional failures in network interfaces
|
||||
(e.g., when the output side fails).
|
||||
.Sh HISTORY
|
||||
|
|
|
|||
|
|
@ -35,392 +35,679 @@
|
|||
static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routing Table Management Daemon
|
||||
*/
|
||||
#ident "$Revision: 1.1.3.1 $"
|
||||
|
||||
#define RIPCMDS
|
||||
#include "defs.h"
|
||||
#include "pathnames.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include "pathnames.h"
|
||||
|
||||
|
||||
#ifdef sgi
|
||||
/* use *stat64 for files on large filesystems */
|
||||
#define stat stat64
|
||||
#endif
|
||||
|
||||
#define NRECORDS 50 /* size of circular trace buffer */
|
||||
#ifdef DEBUG
|
||||
FILE *ftrace = stdout;
|
||||
int traceactions = 0;
|
||||
|
||||
u_int tracelevel, new_tracelevel;
|
||||
FILE *ftrace = stdout; /* output trace file */
|
||||
char *tracelevel_msg = "";
|
||||
|
||||
char savetracename[MAXPATHLEN+1];
|
||||
|
||||
|
||||
char *
|
||||
naddr_ntoa(naddr a)
|
||||
{
|
||||
#define NUM_BUFS 4
|
||||
static int i;
|
||||
static struct {
|
||||
char str[16]; /* xxx.xxx.xxx.xxx\0 */
|
||||
} bufs[NUM_BUFS];
|
||||
struct in_addr addr;
|
||||
char *s;
|
||||
|
||||
addr.s_addr = a;
|
||||
s = strcpy(bufs[i].str, inet_ntoa(addr));
|
||||
i = (i+1) % NUM_BUFS;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
static struct timeval lastlog;
|
||||
static char *savetracename;
|
||||
|
||||
traceinit(ifp)
|
||||
register struct interface *ifp;
|
||||
{
|
||||
static int iftraceinit();
|
||||
|
||||
if (iftraceinit(ifp, &ifp->int_input) &&
|
||||
iftraceinit(ifp, &ifp->int_output))
|
||||
return;
|
||||
tracehistory = 0;
|
||||
fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
|
||||
return s;
|
||||
}
|
||||
|
||||
static
|
||||
iftraceinit(ifp, ifd)
|
||||
struct interface *ifp;
|
||||
register struct ifdebug *ifd;
|
||||
{
|
||||
register struct iftrace *t;
|
||||
|
||||
ifd->ifd_records =
|
||||
(struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
|
||||
if (ifd->ifd_records == 0)
|
||||
return (0);
|
||||
ifd->ifd_front = ifd->ifd_records;
|
||||
ifd->ifd_count = 0;
|
||||
for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
|
||||
t->ift_size = 0;
|
||||
t->ift_packet = 0;
|
||||
/* 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;
|
||||
}
|
||||
ifd->ifd_if = ifp;
|
||||
return (1);
|
||||
}
|
||||
|
||||
traceon(file)
|
||||
char *file;
|
||||
{
|
||||
struct stat stbuf;
|
||||
|
||||
if (ftrace != NULL)
|
||||
return;
|
||||
if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
|
||||
return;
|
||||
savetracename = file;
|
||||
(void) gettimeofday(&now, (struct timezone *)NULL);
|
||||
ftrace = fopen(file, "a");
|
||||
if (ftrace == NULL)
|
||||
return;
|
||||
dup2(fileno(ftrace), 1);
|
||||
dup2(fileno(ftrace), 2);
|
||||
traceactions = 1;
|
||||
fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
|
||||
static void
|
||||
tmsg(char *msg1, char* msg2)
|
||||
{
|
||||
if (ftrace != 0) {
|
||||
lastlog();
|
||||
(void)fprintf(ftrace, "%s%s\n", msg1,msg2);
|
||||
}
|
||||
}
|
||||
|
||||
traceoff()
|
||||
{
|
||||
if (!traceactions)
|
||||
return;
|
||||
if (ftrace != NULL) {
|
||||
int fd = open(_PATH_DEVNULL, O_RDWR);
|
||||
|
||||
fprintf(ftrace, "Tracing disabled %s\n",
|
||||
ctime((time_t *)&now.tv_sec));
|
||||
static void
|
||||
trace_close(char *msg1, char *msg2)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
if (ftrace != 0) {
|
||||
tmsg(msg1,msg2);
|
||||
fflush(ftrace);
|
||||
(void) dup2(fd, 1);
|
||||
(void) dup2(fd, 2);
|
||||
(void) close(fd);
|
||||
fclose(ftrace);
|
||||
ftrace = NULL;
|
||||
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
traceactions = 0;
|
||||
tracehistory = 0;
|
||||
tracepackets = 0;
|
||||
tracecontents = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sigtrace(s)
|
||||
int s;
|
||||
trace_flush(void)
|
||||
{
|
||||
|
||||
if (s == SIGUSR2)
|
||||
traceoff();
|
||||
else if (ftrace == NULL && savetracename)
|
||||
traceon(savetracename);
|
||||
else
|
||||
bumploglevel();
|
||||
}
|
||||
|
||||
/*
|
||||
* Move to next higher level of tracing when -t option processed or
|
||||
* SIGUSR1 is received. Successive levels are:
|
||||
* traceactions
|
||||
* traceactions + tracepackets
|
||||
* traceactions + tracehistory (packets and contents after change)
|
||||
* traceactions + tracepackets + tracecontents
|
||||
*/
|
||||
bumploglevel()
|
||||
{
|
||||
|
||||
(void) gettimeofday(&now, (struct timezone *)NULL);
|
||||
if (traceactions == 0) {
|
||||
traceactions++;
|
||||
if (ftrace)
|
||||
fprintf(ftrace, "Tracing actions started %s\n",
|
||||
ctime((time_t *)&now.tv_sec));
|
||||
} else if (tracepackets == 0) {
|
||||
tracepackets++;
|
||||
tracehistory = 0;
|
||||
tracecontents = 0;
|
||||
if (ftrace)
|
||||
fprintf(ftrace, "Tracing packets started %s\n",
|
||||
ctime((time_t *)&now.tv_sec));
|
||||
} else if (tracehistory == 0) {
|
||||
tracehistory++;
|
||||
if (ftrace)
|
||||
fprintf(ftrace, "Tracing history started %s\n",
|
||||
ctime((time_t *)&now.tv_sec));
|
||||
} else {
|
||||
tracepackets++;
|
||||
tracecontents++;
|
||||
tracehistory = 0;
|
||||
if (ftrace)
|
||||
fprintf(ftrace, "Tracing packet contents started %s\n",
|
||||
ctime((time_t *)&now.tv_sec));
|
||||
}
|
||||
if (ftrace)
|
||||
if (ftrace != 0) {
|
||||
fflush(ftrace);
|
||||
if (ferror(ftrace))
|
||||
trace_off("tracing off: ", strerror(ferror(ftrace)));
|
||||
}
|
||||
}
|
||||
|
||||
trace(ifd, who, p, len, m)
|
||||
register struct ifdebug *ifd;
|
||||
struct sockaddr *who;
|
||||
char *p;
|
||||
int len, m;
|
||||
{
|
||||
register struct iftrace *t;
|
||||
|
||||
if (ifd->ifd_records == 0)
|
||||
void
|
||||
trace_off(char *msg1, char *msg2)
|
||||
{
|
||||
trace_close(msg1, msg2);
|
||||
|
||||
new_tracelevel = tracelevel = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
trace_on(char *filename,
|
||||
int trusted)
|
||||
{
|
||||
struct stat stbuf;
|
||||
FILE *n_ftrace;
|
||||
|
||||
|
||||
if (stat(filename, &stbuf) >= 0 &&
|
||||
(stbuf.st_mode & S_IFMT) != S_IFREG) {
|
||||
msglog("wrong type (%#x) of trace file \"%s\"",
|
||||
stbuf.st_mode, filename);
|
||||
return;
|
||||
t = ifd->ifd_front++;
|
||||
if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
|
||||
ifd->ifd_front = ifd->ifd_records;
|
||||
if (ifd->ifd_count < NRECORDS)
|
||||
ifd->ifd_count++;
|
||||
if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
|
||||
free(t->ift_packet);
|
||||
t->ift_packet = 0;
|
||||
}
|
||||
t->ift_stamp = now;
|
||||
t->ift_who = *who;
|
||||
if (len > 0 && t->ift_packet == 0) {
|
||||
t->ift_packet = malloc(len);
|
||||
if (t->ift_packet == 0)
|
||||
len = 0;
|
||||
if (!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;
|
||||
}
|
||||
|
||||
trace_close("switch to trace file ", filename);
|
||||
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) {
|
||||
tracelevel_msg = "trace command: ";
|
||||
new_tracelevel = 1;
|
||||
} else {
|
||||
tmsg("trace command","");
|
||||
}
|
||||
if (len > 0)
|
||||
bcopy(p, t->ift_packet, len);
|
||||
t->ift_size = len;
|
||||
t->ift_metric = m;
|
||||
}
|
||||
|
||||
traceaction(fd, action, rt)
|
||||
FILE *fd;
|
||||
char *action;
|
||||
struct rt_entry *rt;
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
sigtrace_on(int s)
|
||||
{
|
||||
struct sockaddr_in *dst, *gate;
|
||||
static struct bits {
|
||||
int t_bits;
|
||||
char *t_name;
|
||||
} flagbits[] = {
|
||||
{ RTF_UP, "UP" },
|
||||
{ RTF_GATEWAY, "GATEWAY" },
|
||||
{ RTF_HOST, "HOST" },
|
||||
{ 0 }
|
||||
}, statebits[] = {
|
||||
{ RTS_PASSIVE, "PASSIVE" },
|
||||
{ RTS_REMOTE, "REMOTE" },
|
||||
{ RTS_INTERFACE,"INTERFACE" },
|
||||
{ RTS_CHANGED, "CHANGED" },
|
||||
{ RTS_INTERNAL, "INTERNAL" },
|
||||
{ RTS_EXTERNAL, "EXTERNAL" },
|
||||
{ RTS_SUBNET, "SUBNET" },
|
||||
{ 0 }
|
||||
new_tracelevel++;
|
||||
tracelevel_msg = "SIGUSR1: ";
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
sigtrace_off(int s)
|
||||
{
|
||||
new_tracelevel--;
|
||||
tracelevel_msg = "SIGUSR2: ";
|
||||
}
|
||||
|
||||
|
||||
/* 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",
|
||||
};
|
||||
register struct bits *p;
|
||||
register int first;
|
||||
char *cp;
|
||||
struct interface *ifp;
|
||||
|
||||
if (fd == NULL)
|
||||
return;
|
||||
if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
|
||||
fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
|
||||
lastlog = now;
|
||||
}
|
||||
fprintf(fd, "%s ", action);
|
||||
dst = (struct sockaddr_in *)&rt->rt_dst;
|
||||
gate = (struct sockaddr_in *)&rt->rt_router;
|
||||
fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
|
||||
fprintf(fd, "router %s, metric %d, flags",
|
||||
inet_ntoa(gate->sin_addr), rt->rt_metric);
|
||||
cp = " %s";
|
||||
for (first = 1, p = flagbits; p->t_bits > 0; p++) {
|
||||
if ((rt->rt_flags & p->t_bits) == 0)
|
||||
continue;
|
||||
fprintf(fd, cp, p->t_name);
|
||||
if (first) {
|
||||
cp = "|%s";
|
||||
first = 0;
|
||||
|
||||
if (new_tracelevel > MAX_TRACELEVEL)
|
||||
new_tracelevel = MAX_TRACELEVEL;
|
||||
while (new_tracelevel != tracelevel) {
|
||||
if (new_tracelevel < tracelevel) {
|
||||
if (--tracelevel == 0)
|
||||
trace_off(tracelevel_msg, off_msgs[0]);
|
||||
else
|
||||
tmsg(tracelevel_msg, off_msgs[tracelevel]);
|
||||
} else {
|
||||
if (ftrace == 0) {
|
||||
if (savetracename[0] != '\0')
|
||||
trace_on(savetracename, 1);
|
||||
else
|
||||
ftrace = stdout;
|
||||
}
|
||||
tmsg(tracelevel_msg, on_msgs[tracelevel++]);
|
||||
}
|
||||
}
|
||||
fprintf(fd, " state");
|
||||
cp = " %s";
|
||||
for (first = 1, p = statebits; p->t_bits > 0; p++) {
|
||||
if ((rt->rt_state & p->t_bits) == 0)
|
||||
continue;
|
||||
fprintf(fd, cp, p->t_name);
|
||||
if (first) {
|
||||
cp = "|%s";
|
||||
first = 0;
|
||||
}
|
||||
|
||||
|
||||
/* 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 */
|
||||
static char s[15+20];
|
||||
char *sp;
|
||||
naddr dmask;
|
||||
int i;
|
||||
|
||||
(void)strcpy(s, naddr_ntoa(addr));
|
||||
|
||||
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)", mask);
|
||||
}
|
||||
}
|
||||
fprintf(fd, " timer %d\n", rt->rt_timer);
|
||||
if (tracehistory && !tracepackets &&
|
||||
(rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
|
||||
dumpif(fd, rt->rt_ifp);
|
||||
fflush(fd);
|
||||
if (ferror(fd))
|
||||
traceoff();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
tracenewmetric(fd, rt, newmetric)
|
||||
FILE *fd;
|
||||
struct rt_entry *rt;
|
||||
int newmetric;
|
||||
{
|
||||
struct sockaddr_in *dst, *gate;
|
||||
|
||||
if (fd == NULL)
|
||||
return;
|
||||
if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
|
||||
fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
|
||||
lastlog = now;
|
||||
/* display a bit-field
|
||||
*/
|
||||
struct bits {
|
||||
int bits_mask;
|
||||
char *bits_name;
|
||||
};
|
||||
|
||||
static struct bits if_bits[] = {
|
||||
{ IFF_UP, "" },
|
||||
{ IFF_BROADCAST, "" },
|
||||
{ IFF_LOOPBACK, "LOOPBACK" },
|
||||
{ IFF_POINTOPOINT, "PT-TO-PT" },
|
||||
{ IFF_RUNNING, "" },
|
||||
{ IFF_MULTICAST, "" },
|
||||
{ -1, ""},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct bits is_bits[] = {
|
||||
{ IS_SUBNET, "" },
|
||||
{ IS_REMOTE, "REMOTE" },
|
||||
{ IS_PASSIVE, "PASSIVE" },
|
||||
{ IS_EXTERNAL, "EXTERNAL" },
|
||||
{ IS_CHECKED, "" },
|
||||
{ IS_ALL_HOSTS, "" },
|
||||
{ IS_ALL_ROUTERS, "" },
|
||||
{ IS_RIP_QUERIED, "" },
|
||||
{ IS_BROKE, "BROKE" },
|
||||
{ IS_ACTIVE, "ACTIVE" },
|
||||
{ IS_QUIET, "QUIET" },
|
||||
{ IS_NEED_NET_SUB, "" },
|
||||
{ IS_NO_AG, "NO_AG" },
|
||||
{ IS_NO_SUPER_AG, "NO_SUPER_AG" },
|
||||
{ (IS_NO_RIPV1_IN
|
||||
| IS_NO_RIPV2_IN
|
||||
| IS_NO_RIPV1_OUT
|
||||
| IS_NO_RIPV2_OUT), "NO_RIP" },
|
||||
{ IS_NO_RIPV1_IN, "NO_RIPV1_IN" },
|
||||
{ IS_NO_RIPV2_IN, "NO_RIPV2_IN" },
|
||||
{ IS_NO_RIPV1_OUT, "NO_RIPV1_OUT" },
|
||||
{ IS_NO_RIPV2_OUT, "NO_RIPV2_OUT" },
|
||||
{ (IS_NO_ADV_IN
|
||||
| IS_NO_SOL_OUT
|
||||
| IS_NO_ADV_OUT), "NO_RDISC" },
|
||||
{ IS_NO_SOL_OUT, "NO_SOLICIT" },
|
||||
{ IS_SOL_OUT, "SEND_SOLICIT" },
|
||||
{ IS_NO_ADV_OUT, "NO_RDISC_ADV" },
|
||||
{ IS_ADV_OUT, "RDISC_ADV" },
|
||||
{ IS_BCAST_RDISC, "BCAST_RDISC" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct bits rs_bits[] = {
|
||||
{ RS_IF, "IF" },
|
||||
{ RS_NET_SUB, "NET_SUB" },
|
||||
{ RS_NET_HOST, "NET_HOST" },
|
||||
{ RS_NET_INT, "NET_INT" },
|
||||
{ RS_SUBNET, "" },
|
||||
{ RS_LOCAL, "LOCAL" },
|
||||
{ RS_MHOME, "MHOME" },
|
||||
{ RS_GW, "GW" },
|
||||
{ RS_STATIC, "STATIC" },
|
||||
{ RS_RDISC, "RDISC" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
trace_bits(struct bits *tbl,
|
||||
u_int field)
|
||||
{
|
||||
int first = 1;
|
||||
int b;
|
||||
|
||||
|
||||
while (field != 0) {
|
||||
b = tbl->bits_mask;
|
||||
if (b == 0)
|
||||
break;
|
||||
if ((b & field) == b
|
||||
&& tbl->bits_name[0] != '\0') {
|
||||
(void)fprintf(ftrace, first ? "<%s" : "|%s",
|
||||
tbl->bits_name);
|
||||
first = 0;
|
||||
}
|
||||
field &= ~b;
|
||||
tbl++;
|
||||
}
|
||||
dst = (struct sockaddr_in *)&rt->rt_dst;
|
||||
gate = (struct sockaddr_in *)&rt->rt_router;
|
||||
fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
|
||||
fprintf(fd, "router %s, from %d to %d\n",
|
||||
inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
|
||||
fflush(fd);
|
||||
if (ferror(fd))
|
||||
traceoff();
|
||||
if (field != 0) {
|
||||
(void)fputc(first ? '<' : '|', ftrace);
|
||||
(void)fprintf(ftrace, "%#x", field);
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
(void)fputs("> ", ftrace);
|
||||
}
|
||||
|
||||
dumpif(fd, ifp)
|
||||
FILE *fd;
|
||||
register struct interface *ifp;
|
||||
|
||||
void
|
||||
trace_if(char *act,
|
||||
struct interface *ifp)
|
||||
{
|
||||
if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
|
||||
fprintf(fd, "*** Packet history for interface %s ***\n",
|
||||
ifp->int_name);
|
||||
#ifdef notneeded
|
||||
dumptrace(fd, "to", &ifp->int_output);
|
||||
#endif
|
||||
dumptrace(fd, "from", &ifp->int_input);
|
||||
fprintf(fd, "*** end packet history ***\n");
|
||||
if (ftrace == 0)
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
(void)fprintf(ftrace, "%s interface %-4s ", act, ifp->int_name);
|
||||
(void)fprintf(ftrace, "%-15s --> %s ",
|
||||
naddr_ntoa(ifp->int_addr),
|
||||
((ifp->int_if_flags & IFF_POINTOPOINT)
|
||||
? naddr_ntoa(ifp->int_dstaddr)
|
||||
: addrname(htonl(ifp->int_net), ifp->int_mask, 0)));
|
||||
(void)fprintf(ftrace, "metric=%d ", ifp->int_metric);
|
||||
trace_bits(if_bits, ifp->int_if_flags);
|
||||
trace_bits(is_bits, ifp->int_state);
|
||||
(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 (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 %-16s--> ",
|
||||
rts - rt->rt_spares,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0));
|
||||
(void)fprintf(ftrace, "%-15s ",
|
||||
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 ", 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, " %-16s--> ",
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0));
|
||||
(void)fprintf(ftrace, "%-15s ",
|
||||
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 ", 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 %-16s--> ",
|
||||
rts - rt->rt_spares,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0));
|
||||
(void)fprintf(ftrace, "%-15s ", naddr_ntoa(gate));
|
||||
if (gate != router)
|
||||
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
|
||||
if (tag != 0)
|
||||
(void)fprintf(ftrace, "tag=%#x ", 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));
|
||||
}
|
||||
}
|
||||
|
||||
dumptrace(fd, dir, ifd)
|
||||
FILE *fd;
|
||||
char *dir;
|
||||
register struct ifdebug *ifd;
|
||||
{
|
||||
register struct iftrace *t;
|
||||
char *cp = !strcmp(dir, "to") ? "Output" : "Input";
|
||||
|
||||
if (ifd->ifd_front == ifd->ifd_records &&
|
||||
ifd->ifd_front->ift_size == 0) {
|
||||
fprintf(fd, "%s: no packets.\n", cp);
|
||||
fflush(fd);
|
||||
void
|
||||
trace_msg(char *p, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!TRACEACTIONS || ftrace == 0)
|
||||
return;
|
||||
}
|
||||
fprintf(fd, "%s trace:\n", cp);
|
||||
t = ifd->ifd_front - ifd->ifd_count;
|
||||
if (t < ifd->ifd_records)
|
||||
t += NRECORDS;
|
||||
for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
|
||||
if (t >= ifd->ifd_records + NRECORDS)
|
||||
t = ifd->ifd_records;
|
||||
if (t->ift_size == 0)
|
||||
continue;
|
||||
dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
|
||||
&t->ift_stamp);
|
||||
}
|
||||
|
||||
lastlog();
|
||||
va_start(args, p);
|
||||
vfprintf(ftrace, p, args);
|
||||
}
|
||||
|
||||
dumppacket(fd, dir, who, cp, size, stamp)
|
||||
FILE *fd;
|
||||
struct sockaddr_in *who; /* should be sockaddr */
|
||||
char *dir, *cp;
|
||||
register int size;
|
||||
struct timeval *stamp;
|
||||
{
|
||||
register struct rip *msg = (struct rip *)cp;
|
||||
register struct netinfo *n;
|
||||
|
||||
if (fd == NULL)
|
||||
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 (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
|
||||
fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
|
||||
dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
|
||||
ctime((time_t *)&stamp->tv_sec));
|
||||
else {
|
||||
fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd,
|
||||
dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
|
||||
fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet,
|
||||
ctime((time_t *)&stamp->tv_sec));
|
||||
fflush(fd);
|
||||
|
||||
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 %-16s--> %-15s metric=%-2d ",
|
||||
label,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0),
|
||||
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 ", rt->rt_tag);
|
||||
trace_bits(rs_bits, rt->rt_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 %-16s--> %-15s ",
|
||||
strlen(label), "",
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0),
|
||||
(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 ", tag);
|
||||
if (rt->rt_state != state)
|
||||
trace_bits(rs_bits, state);
|
||||
if (rt->rt_ifp != ifp)
|
||||
(void)fprintf(ftrace, "%s ",
|
||||
ifp != 0 ? ifp->int_name : "-");
|
||||
if (rt->rt_hold_down > now.tv_sec)
|
||||
(void)fprintf(ftrace, "hold-down=%d ",
|
||||
rt->rt_hold_down - now.tv_sec);
|
||||
(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 %-16s--> %-15s metric=%-2d ",
|
||||
action,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0),
|
||||
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 ", rt->rt_tag);
|
||||
trace_bits(rs_bits, state);
|
||||
if (rt->rt_ifp != 0)
|
||||
(void)fprintf(ftrace, "%s ", 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 (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%s%s"
|
||||
" size=%d msg=%#x\n",
|
||||
dir1, msg->rip_vers, msg->rip_cmd, dir2,
|
||||
naddr_ntoa(who->sin_addr.s_addr),
|
||||
ntohs(who->sin_port),
|
||||
size, msg);
|
||||
return;
|
||||
}
|
||||
if (tracepackets && tracecontents == 0) {
|
||||
fflush(fd);
|
||||
|
||||
(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:
|
||||
size -= 4 * sizeof (char);
|
||||
n = msg->rip_nets;
|
||||
for (; size > 0; n++, size -= sizeof (struct netinfo)) {
|
||||
if (size < sizeof (struct netinfo)) {
|
||||
fprintf(fd, "(truncated record, len %d)\n",
|
||||
size);
|
||||
break;
|
||||
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 ",
|
||||
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",
|
||||
n->n_tag);
|
||||
(void)fputc('\n',ftrace);
|
||||
continue;
|
||||
}
|
||||
if (sizeof(n->rip_dst.sa_family) > 1)
|
||||
n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
|
||||
|
||||
switch ((int)n->rip_dst.sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
fprintf(fd, "\tdst %s metric %d\n",
|
||||
#define satosin(sa) ((struct sockaddr_in *)&sa)
|
||||
inet_ntoa(satosin(n->rip_dst)->sin_addr),
|
||||
ntohl(n->rip_metric));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(fd, "\taf %d? metric %d\n",
|
||||
n->rip_dst.sa_family,
|
||||
ntohl(n->rip_metric));
|
||||
break;
|
||||
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),
|
||||
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 ",
|
||||
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",
|
||||
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(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
|
||||
fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
|
||||
break;
|
||||
|
||||
case RIPCMD_TRACEOFF:
|
||||
break;
|
||||
}
|
||||
fflush(fd);
|
||||
if (ferror(fd))
|
||||
traceoff();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue