The latest and greatest routed from Vern Schryver. This version includes
many fixes to router discovery, including a number of endianness bug fixes. (Router discovery appears to actually work now.) This should be the end of it for the Sun `rdisc' program. (People currently using rdisc(8) should be able to go back to routed again.) Obtained from: Vernon J. Schryver <vjs@mica.denver.sgi.com>
This commit is contained in:
parent
9979ce1560
commit
1823680765
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/SGI/dist/; revision=17250
@ -3,6 +3,6 @@
|
||||
PROG= routed
|
||||
SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
|
||||
MAN8= routed.8
|
||||
SUBDIR= rtquery rttrace
|
||||
SUBDIR= rtquery
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -33,7 +33,7 @@
|
||||
* @(#)defs.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#ident "$Revision: 1.1 $"
|
||||
#ident "$Revision: 1.11 $"
|
||||
|
||||
/* Definitions for RIPv2 routing process.
|
||||
*
|
||||
@ -104,12 +104,10 @@ struct walkarg;
|
||||
#define _HAVE_SIN_LEN
|
||||
#endif
|
||||
|
||||
#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
|
||||
/* #define MCAST_PPP_BUG */
|
||||
|
||||
#define NEVER (24*60*60) /* a long time */
|
||||
#define EPOCH NEVER /* bias time by this to avoid <0 */
|
||||
@ -121,12 +119,6 @@ struct walkarg;
|
||||
#define CHECK_ACT_INTERVAL 30 /* when advertising */
|
||||
#define CHECK_QUIET_INTERVAL 300 /* when not */
|
||||
|
||||
|
||||
/* set times to this to continue poisoning a route */
|
||||
#define POISON_SECS (GARBAGE_TIME - POISON_TIME)
|
||||
|
||||
#define NET_S_METRIC 1 /* metric used on synthetic routes */
|
||||
|
||||
#define LIM_SEC(s,l) ((s).tv_sec = MIN((s).tv_sec, (l)))
|
||||
|
||||
|
||||
@ -162,16 +154,15 @@ 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 */
|
||||
# define RS_NET_INT 0x002 /* authority route */
|
||||
# define RS_NET_SYN 0x004 /* fake net route for subnet */
|
||||
# define RS_NO_NET_SYN (RS_LOCAL | RS_LOCAL | RS_IF)
|
||||
# define RS_SUBNET 0x008 /* subnet route from any source */
|
||||
# define RS_LOCAL 0x010 /* loopback for pt-to-pt */
|
||||
# define RS_MHOME 0x020 /* from -m */
|
||||
# define RS_STATIC 0x040 /* from the kernel */
|
||||
# define RS_RDISC 0x080 /* from router discovery */
|
||||
# define RS_PERMANENT (RS_MHOME | RS_STATIC | RS_NET_SYN | RS_RDISC)
|
||||
struct sockaddr_in rt_dst_sock;
|
||||
naddr rt_mask;
|
||||
struct rt_spare {
|
||||
@ -184,8 +175,8 @@ struct rt_entry {
|
||||
#define NUM_SPARES 4
|
||||
} rt_spares[NUM_SPARES];
|
||||
u_int rt_seqno; /* when last changed */
|
||||
char rt_hold_metric;
|
||||
time_t rt_hold_down;
|
||||
char rt_poison_metric; /* to notice maximum recently */
|
||||
time_t rt_poison_time; /* advertised metric */
|
||||
};
|
||||
#define rt_dst rt_dst_sock.sin_addr.s_addr
|
||||
#define rt_ifp rt_spares[0].rts_ifp
|
||||
@ -205,9 +196,7 @@ struct rt_entry {
|
||||
* 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)) \
|
||||
#define AGE_RT(rt,ifp) (0 == ((rt)->rt_state & RS_PERMANENT) \
|
||||
&& (!((rt)->rt_state & RS_IF) \
|
||||
|| (ifp) == 0 \
|
||||
|| (((ifp)->int_state & IS_REMOTE) \
|
||||
@ -220,14 +209,18 @@ struct rt_entry {
|
||||
* - and A has a shorter path
|
||||
* - or is the router speaking for itself
|
||||
* - or the current route is equal but stale
|
||||
* - or it is a host route advertised by a system for itself
|
||||
*/
|
||||
#define BETTER_LINK(A, B) ((A)->rts_metric != HOPCNT_INFINITY \
|
||||
#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \
|
||||
&& now_stale <= (A)->rts_time \
|
||||
&& ((A)->rts_metric < (B)->rts_metric \
|
||||
|| ((A)->rts_gate == (A)->rts_router \
|
||||
&& (B)->rts_gate != (B)->rts_router) \
|
||||
|| ((A)->rts_metric == (B)->rts_metric \
|
||||
&& now_stale > (B)->rts_time)))
|
||||
&& now_stale > (B)->rts_time) \
|
||||
|| (RT_ISHOST(rt) \
|
||||
&& (rt)->rt_dst == (A)->rts_router \
|
||||
&& (A)->rts_metric == (B)->rts_metric)))
|
||||
|
||||
|
||||
/* An "interface" is similar to a kernel ifnet structure, except it also
|
||||
@ -242,27 +235,27 @@ struct interface {
|
||||
naddr int_dstaddr; /* other end of pt-to-pt link (n) */
|
||||
naddr int_net; /* working network # (host order)*/
|
||||
naddr int_mask; /* working net mask (host order) */
|
||||
naddr int_ripv1_mask; /* for inferring a mask (n) */
|
||||
naddr int_std_addr; /* class A/B/C address (n) */
|
||||
naddr int_std_net; /* class A/B/C network (h) */
|
||||
naddr int_std_mask; /* class A/B/C netmask (h) */
|
||||
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;
|
||||
struct int_data {
|
||||
u_int ipackets; /* previous network stats */
|
||||
u_int ierrors;
|
||||
u_int opackets;
|
||||
u_int oerrors;
|
||||
#ifdef sgi
|
||||
u_int int_data_odrops;
|
||||
u_int odrops;
|
||||
#endif
|
||||
time_t int_data_ts; /* timestamp on network stats */
|
||||
time_t ts; /* timestamp on network stats */
|
||||
} int_data;
|
||||
char int_passwd[RIP_AUTH_PW_LEN]; /* RIPv2 password */
|
||||
int int_rdisc_pref; /* advertised rdisc preference */
|
||||
int int_rdisc_int; /* MaxAdvertiseInterval */
|
||||
@ -280,25 +273,32 @@ struct interface {
|
||||
#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_SICK 0x0000400 /* seems to be broken */
|
||||
#define IS_DUP 0x0000800 /* has a duplicate address */
|
||||
#define IS_ACTIVE 0x0001000 /* heard from it at least once */
|
||||
#define IS_NEED_NET_SYN 0x0002000 /* need RS_NET_SYN route */
|
||||
#define IS_NO_AG 0x0004000 /* do not aggregate subnets */
|
||||
#define IS_NO_SUPER_AG 0x0008000 /* do not aggregate networks */
|
||||
#define IS_NO_RIPV1_IN 0x0010000 /* no RIPv1 input at all */
|
||||
#define IS_NO_RIPV2_IN 0x0020000 /* no RIPv2 input at all */
|
||||
#define IS_NO_RIP_IN (IS_NO_RIPV1_IN | IS_NO_RIPV2_IN)
|
||||
#define IS_RIP_IN_OFF(s) (((s) & IS_NO_RIP_IN) == IS_NO_RIP_IN)
|
||||
#define IS_NO_RIPV1_OUT 0x0040000 /* no RIPv1 output at all */
|
||||
#define IS_NO_RIPV2_OUT 0x0080000 /* no RIPv2 output at all */
|
||||
#define IS_NO_RIP_OUT (IS_NO_RIPV1_OUT | IS_NO_RIPV2_OUT)
|
||||
#define IS_NO_ADV_IN 0x0080000
|
||||
#define IS_NO_SOL_OUT 0x0100000 /* no solicitations */
|
||||
#define IS_SOL_OUT 0x0200000 /* send solicitations */
|
||||
#define IS_NO_RIP (IS_NO_RIP_OUT | IS_NO_RIP_IN)
|
||||
#define IS_RIP_OUT_OFF(s) (((s) & IS_NO_RIP_OUT) == IS_NO_RIP_OUT)
|
||||
#define IS_RIP_OFF(s) (((s) & IS_NO_RIP) == IS_NO_RIP)
|
||||
#define IS_NO_ADV_IN 0x0100000
|
||||
#define IS_NO_SOL_OUT 0x0200000 /* no solicitations */
|
||||
#define IS_SOL_OUT 0x0400000 /* send solicitations */
|
||||
#define GROUP_IS_SOL (IS_NO_ADV_IN|IS_NO_SOL_OUT)
|
||||
#define IS_NO_ADV_OUT 0x0400000 /* do not advertise rdisc */
|
||||
#define IS_ADV_OUT 0x0800000 /* advertise rdisc */
|
||||
#define IS_NO_ADV_OUT 0x0800000 /* do not advertise rdisc */
|
||||
#define IS_ADV_OUT 0x1000000 /* advertise rdisc */
|
||||
#define GROUP_IS_ADV (IS_NO_ADV_OUT|IS_ADV_OUT)
|
||||
#define IS_BCAST_RDISC 0x1000000 /* broadcast instead of multicast */
|
||||
#define IS_BCAST_RDISC 0x2000000 /* broadcast instead of multicast */
|
||||
#define IS_NO_RDISC (IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT)
|
||||
#define IS_PM_RDISC 0x4000000 /* poor-man's router discovery */
|
||||
|
||||
#ifdef sgi
|
||||
#define IFF_UP_RUNNING (IFF_RUNNING|IFF_UP)
|
||||
@ -316,21 +316,30 @@ struct ag_info {
|
||||
naddr ag_dst_h; /* destination in host byte order */
|
||||
naddr ag_mask;
|
||||
naddr ag_gate;
|
||||
naddr ag_nhop;
|
||||
char ag_metric; /* metric to be advertised */
|
||||
char ag_pref; /* aggregate based on this */
|
||||
u_int ag_seqno;
|
||||
u_short ag_tag;
|
||||
u_short ag_state;
|
||||
#define AGS_SUPPRESS 0x01 /* combine with coaser mask */
|
||||
#define AGS_SUPPRESS 0x001 /* combine with coaser mask */
|
||||
#define AGS_PROMOTE 0x002 /* synthesize combined routes */
|
||||
#define AGS_REDUN0 0x004 /* redundant, finer routes output */
|
||||
#define AGS_REDUN1 0x008
|
||||
#define AG_IS_REDUN(state) (((state) & (AGS_REDUN0 | AGS_REDUN1)) \
|
||||
== (AGS_REDUN0 | AGS_REDUN1))
|
||||
#define AGS_GATEWAY 0x010 /* tell kernel RTF_GATEWAY */
|
||||
#define AGS_RIPV2 0x020 /* send only as RIPv2 */
|
||||
#define AGS_DEAD 0x080 /* dead--ignore differing gate */
|
||||
#define AGS_RDISC 0x100 /* suppresses most routes */
|
||||
#define AGS_IF 0x020 /* for an interface */
|
||||
#define AGS_RIPV2 0x040 /* send only as RIPv2 */
|
||||
#define AGS_FINE_GATE 0x080 /* ignore differing ag_gate when this
|
||||
* has the finer netmask */
|
||||
#define AGS_CORS_GATE 0x100 /* ignore differing gate when this
|
||||
* has the coarser netmaks */
|
||||
#define AGS_SPLIT_HZ 0x200 /* suppress for split horizon */
|
||||
|
||||
/* some bits are set if they are set on either route */
|
||||
#define AGS_PROMOTE_EITHER (AGS_RIPV2 | AGS_GATEWAY | \
|
||||
AGS_SUPPRESS | AGS_CORS_GATE)
|
||||
};
|
||||
|
||||
|
||||
@ -338,8 +347,8 @@ struct ag_info {
|
||||
extern struct parm {
|
||||
struct parm *parm_next;
|
||||
char parm_name[IFNAMSIZ+1];
|
||||
naddr parm_a_h;
|
||||
naddr parm_m;
|
||||
naddr parm_addr_h;
|
||||
naddr parm_mask;
|
||||
|
||||
char parm_d_metric;
|
||||
u_int parm_int_state;
|
||||
@ -353,6 +362,7 @@ extern struct intnet {
|
||||
struct intnet *intnet_next;
|
||||
naddr intnet_addr;
|
||||
naddr intnet_mask;
|
||||
char intnet_metric;
|
||||
} *intnets;
|
||||
|
||||
|
||||
@ -371,11 +381,9 @@ 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 */
|
||||
@ -397,15 +405,16 @@ 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 have_ripv1_out; /* have a RIPv1 interface */
|
||||
extern int have_ripv1_in;
|
||||
extern int need_flash; /* flash update needed */
|
||||
extern struct timeval need_kern; /* need to update kernel table */
|
||||
extern int update_seqno; /* a route has changed */
|
||||
|
||||
extern u_int tracelevel, new_tracelevel;
|
||||
#define MAX_TRACELEVEL 3
|
||||
#define TRACEPACKETS (tracelevel >= 2) /* note packets */
|
||||
#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */
|
||||
#define TRACEPACKETS (tracelevel >= 2) /* note packets */
|
||||
#define TRACEACTIONS (tracelevel != 0)
|
||||
extern FILE *ftrace; /* output trace file */
|
||||
|
||||
@ -422,7 +431,8 @@ 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};
|
||||
enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST,
|
||||
NO_OUT_MULTICAST, NO_OUT_RIPV2};
|
||||
extern int output(enum output_type, struct sockaddr_in *,
|
||||
struct interface *, struct rip *, int);
|
||||
extern void rip_query(void);
|
||||
@ -454,14 +464,16 @@ extern int getnet(char *, naddr *, naddr *);
|
||||
extern int gethost(char *, naddr *);
|
||||
extern void gwkludge(void);
|
||||
extern char *parse_parms(char *);
|
||||
extern char *check_parms(struct parm *);
|
||||
extern void get_parms(struct interface *);
|
||||
|
||||
extern void lastlog(void);
|
||||
extern void trace_on(char *, int);
|
||||
extern void trace_off(char*, char*);
|
||||
extern void trace_off(char*, ...);
|
||||
extern void trace_flush(void);
|
||||
extern void set_tracelevel(void);
|
||||
extern void trace_msg(char *, ...);
|
||||
extern void trace_act(char *, ...);
|
||||
extern void trace_pkt(char *, ...);
|
||||
extern void trace_add_del(char *, struct rt_entry *);
|
||||
extern void trace_change(struct rt_entry *, u_int, naddr, naddr, int,
|
||||
u_short, struct interface *, time_t, char *);
|
||||
@ -476,8 +488,8 @@ 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 if_bad_rdisc(struct interface *);
|
||||
extern void if_ok_rdisc(struct interface *);
|
||||
extern void read_rip(int, struct interface *);
|
||||
extern void read_rt(void);
|
||||
extern void read_d(void);
|
||||
@ -490,12 +502,11 @@ 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,
|
||||
extern void ag_check(naddr, naddr, naddr, naddr, char, char, u_int,
|
||||
u_short, u_short, void (*)(struct ag_info *));
|
||||
extern void del_static(naddr, naddr, int);
|
||||
extern void del_redirects(naddr, time_t);
|
||||
@ -512,21 +523,21 @@ 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);
|
||||
#define INFO_DST(I) ((I)->rti_info[RTAX_DST])
|
||||
#define INFO_GATE(I) ((I)->rti_info[RTAX_GATEWAY])
|
||||
#define INFO_MASK(I) ((I)->rti_info[RTAX_NETMASK])
|
||||
#define INFO_IFA(I) ((I)->rti_info[RTAX_IFA])
|
||||
#define INFO_IFP(I) ((I)->rti_info[RTAX_IFP])
|
||||
#define INFO_AUTHOR(I) ((I)->rti_info[RTAX_AUTHOR])
|
||||
#define INFO_BRD(I) ((I)->rti_info[RTAX_BRD])
|
||||
void rt_xaddrs(struct rt_addrinfo *, struct sockaddr *, struct sockaddr *,
|
||||
int);
|
||||
|
||||
extern naddr std_mask(naddr);
|
||||
extern naddr ripv1_mask_net(naddr, struct interface *, struct interface *);
|
||||
extern naddr ripv1_mask_host(naddr,struct interface *, struct interface *);
|
||||
#define on_net(tgt, net, mask) ((ntohl(tgt) & mask) == (net & mask))
|
||||
extern naddr ripv1_mask_net(naddr, struct interface *);
|
||||
extern naddr ripv1_mask_host(naddr,struct interface *);
|
||||
#define on_net(a,net,mask) (((ntohl(a) ^ (net)) & (mask)) == 0)
|
||||
extern int check_dst(naddr);
|
||||
#ifdef sgi
|
||||
extern int sysctl(int *, u_int, void *, size_t *, void *, size_t);
|
||||
@ -534,8 +545,9 @@ extern int sysctl(int *, u_int, void *, size_t *, void *, size_t);
|
||||
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 int if_ok(struct interface *, char *);
|
||||
extern void if_sick(struct interface *);
|
||||
extern void if_bad(struct interface *);
|
||||
extern struct interface *ifwithaddr(naddr, int, int);
|
||||
extern struct interface *ifwithname(char *, naddr);
|
||||
extern struct interface *ifwithindex(u_short);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,17 +31,17 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#ident "$Revision: 1.1 $"
|
||||
#ident "$Revision: 1.10 $"
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
|
||||
static void input_route(struct interface *, naddr,
|
||||
naddr, naddr, naddr, int, u_short);
|
||||
naddr, naddr, naddr, struct netinfo *);
|
||||
|
||||
|
||||
/* process RIP input
|
||||
@ -97,7 +97,6 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
if (ifp != 0)
|
||||
ifp->int_state |= IS_ACTIVE;
|
||||
|
||||
if (TRACEPACKETS)
|
||||
trace_rip("Recv", "from", from, ifp, rip, size);
|
||||
|
||||
if (rip->rip_vers == 0) {
|
||||
@ -138,8 +137,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
" from %s discarded",
|
||||
naddr_ntoa(FROM_NADDR));
|
||||
use_auth = from->sin_addr.s_addr;
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard authenticated RIPv2 message\n");
|
||||
trace_pkt("discard authenticated RIPv2 message\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -148,28 +146,29 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
/* did the request come from a router?
|
||||
*/
|
||||
if (from->sin_port == htons(RIP_PORT)) {
|
||||
/* yes, ignore it if RIP is off
|
||||
/* yes, ignore it if RIP is off so that it does not
|
||||
* depend on us.
|
||||
*/
|
||||
if (rip_sock < 0) {
|
||||
trace_msg("ignore request while RIP off");
|
||||
trace_pkt("ignore request while RIP off\n");
|
||||
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");
|
||||
if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
|
||||
trace_pkt("discard our own RIP request\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* According to RFC 1723, we should ignore unathenticated
|
||||
* queries. That is too silly to bother with.
|
||||
* queries. That is too silly to bother with. Sheesh!
|
||||
* Are forwarding tables supposed to be secret? When
|
||||
* a bad guy can infer them with test traffic?
|
||||
* Maybe on firewalls you'd care, but not enough to
|
||||
* give up the diagnostic facilities of remote probing.
|
||||
*/
|
||||
|
||||
if (n >= lim
|
||||
@ -234,13 +233,10 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
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);
|
||||
}
|
||||
if (rip->rip_vers == RIPv1
|
||||
|| 0 == (mask = ntohl(n->n_mask)))
|
||||
mask = ripv1_mask_host(dst,ifp);
|
||||
|
||||
rt = rtget(dst, mask);
|
||||
if (!rt)
|
||||
rt = rtfind(n->n_dst);
|
||||
@ -250,8 +246,9 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
if (!rt) {
|
||||
n->n_metric = HOPCNT_INFINITY;
|
||||
} else {
|
||||
n->n_metric = (rt->rt_metric
|
||||
+ (ifp ? ifp->int_metric : 1));
|
||||
n->n_metric = rt->rt_metric+1;
|
||||
if (ifp != 0)
|
||||
n->n_metric += ifp->int_metric;
|
||||
if (n->n_metric > HOPCNT_INFINITY)
|
||||
n->n_metric = HOPCNT_INFINITY;
|
||||
if (rip->rip_vers == RIPv1) {
|
||||
@ -304,7 +301,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
rip->rip_tracefile[size-4] = '\0';
|
||||
trace_on(rip->rip_tracefile, 0);
|
||||
} else {
|
||||
trace_off("tracing turned off by ",
|
||||
trace_off("tracing turned off by %s\n",
|
||||
naddr_ntoa(FROM_NADDR));
|
||||
}
|
||||
return;
|
||||
@ -319,15 +316,12 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
|
||||
/* verify message came from a router */
|
||||
if (from->sin_port != ntohs(RIP_PORT)) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard response"
|
||||
" from unknown port\n");
|
||||
trace_pkt("discard RIP response from unknown port\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rip_sock < 0) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard response while RIP off");
|
||||
trace_pkt("discard response while RIP off\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -335,18 +329,19 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
*/
|
||||
ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
|
||||
if (ifp1) {
|
||||
if (ifp1->int_state & IS_REMOTE) {
|
||||
if (ifp1->int_state & IS_PASSIVE) {
|
||||
msglog("bogus input from %s on supposedly"
|
||||
" passive interface %s",
|
||||
msglog("bogus input from %s on"
|
||||
" supposedly passive %s",
|
||||
naddr_ntoa(FROM_NADDR),
|
||||
ifp1->int_name);
|
||||
|
||||
} else if (ifp1->int_state & IS_REMOTE) {
|
||||
} else {
|
||||
ifp1->int_act_time = now.tv_sec;
|
||||
if (ifok(ifp1, "remote "))
|
||||
if (if_ok(ifp1, "remote "))
|
||||
addrouteforif(ifp1);
|
||||
} else if (TRACEPACKETS) {
|
||||
trace_msg("discard our own packet\n");
|
||||
}
|
||||
} else {
|
||||
trace_pkt("discard our own RIP response\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -356,13 +351,20 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
* broadcast or point-to-point networks, and from
|
||||
* those listed in /etc/gateways.
|
||||
*/
|
||||
if (!ifp || (ifp->int_state & IS_PASSIVE)) {
|
||||
if (!ifp) {
|
||||
if (from->sin_addr.s_addr != unk_router)
|
||||
msglog("packet from unknown router %s",
|
||||
msglog("packet from unknown router %s"
|
||||
" or via unidentified interface",
|
||||
naddr_ntoa(FROM_NADDR));
|
||||
unk_router = from->sin_addr.s_addr;
|
||||
return;
|
||||
}
|
||||
if (ifp->int_state & IS_PASSIVE) {
|
||||
trace_act("packet from %s via passive interface %s\n",
|
||||
naddr_ntoa(FROM_NADDR),
|
||||
ifp->int_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check required version
|
||||
*/
|
||||
@ -370,8 +372,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
&& rip->rip_vers == RIPv1)
|
||||
|| ((ifp->int_state & IS_NO_RIPV2_IN)
|
||||
&& rip->rip_vers != RIPv1)) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard RIPv%d response\n",
|
||||
trace_pkt("discard RIPv%d response\n",
|
||||
rip->rip_vers);
|
||||
return;
|
||||
}
|
||||
@ -379,9 +380,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
/* Ignore routes via dead interface.
|
||||
*/
|
||||
if (ifp->int_state & IS_BROKE) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard response via"
|
||||
" broken interface %s\n",
|
||||
trace_pkt("discard response via broken interface %s\n",
|
||||
ifp->int_name);
|
||||
return;
|
||||
}
|
||||
@ -466,9 +465,9 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
}
|
||||
}
|
||||
|
||||
mask = ntohl(n->n_mask);
|
||||
if (rip->rip_vers == RIPv1 || mask == 0) {
|
||||
mask = ripv1_mask_host(dst,ifp,0);
|
||||
if (rip->rip_vers == RIPv1
|
||||
|| 0 == (mask = ntohl(n->n_mask))) {
|
||||
mask = ripv1_mask_host(dst,ifp);
|
||||
} else if ((ntohl(dst) & ~mask) != 0) {
|
||||
if (bad_mask != from->sin_addr.s_addr) {
|
||||
msglog("router %s sent bad netmask"
|
||||
@ -480,14 +479,10 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
}
|
||||
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.
|
||||
/* Adjust metric according to incoming interface..
|
||||
*/
|
||||
n->n_metric += ifp->int_metric;
|
||||
if (n->n_metric > HOPCNT_INFINITY)
|
||||
@ -496,18 +491,19 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
/* Recognize and ignore a default route we faked
|
||||
* which is being sent back to us by a machine with
|
||||
* broken split-horizon.
|
||||
* Be a little more paranoid than that, and reject
|
||||
* default routes with the same metric we advertised.
|
||||
*/
|
||||
if (ifp->int_d_metric != 0
|
||||
&& dst == RIP_DEFAULT
|
||||
&& n->n_family == RIP_AF_UNSPEC
|
||||
&& n->n_metric > ifp->int_d_metric)
|
||||
&& 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.
|
||||
/* We can receive aggregated RIPv2 routes that must
|
||||
* be broken down before they are transmitted by
|
||||
* RIPv1 via an interface on a subnet.
|
||||
* We might also receive the same routes aggregated
|
||||
* via other RIPv2 interfaces.
|
||||
* This could cause duplicate routes to be sent on
|
||||
* the RIPv1 interfaces. "Longest matching variable
|
||||
* length netmasks" lets RIPv2 listeners understand,
|
||||
@ -521,9 +517,12 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
*
|
||||
* Notice that this does not break down network
|
||||
* routes corresponding to subnets. This is part
|
||||
* of the defense against RS_NET_SUB.
|
||||
* of the defense against RS_NET_SYN.
|
||||
*/
|
||||
if (0 != (ntohl(dst) & (v1_mask & ~mask))) {
|
||||
if (have_ripv1_out
|
||||
&& (v1_mask = ripv1_mask_net(dst,0)) > mask
|
||||
&& (((rt = rtget(dst,mask)) == 0
|
||||
|| !(rt->rt_state & RS_NET_SYN)))) {
|
||||
ddst_h = v1_mask & -v1_mask;
|
||||
i = (v1_mask & ~mask)/ddst_h;
|
||||
if (i >= 1024) {
|
||||
@ -546,8 +545,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
|
||||
|
||||
for (;;) {
|
||||
input_route(ifp, FROM_NADDR,
|
||||
dst, mask, gate,
|
||||
n->n_metric, n->n_tag);
|
||||
dst, mask, gate, n);
|
||||
if (i-- == 0)
|
||||
break;
|
||||
dst = htonl(ntohl(dst) + ddst_h);
|
||||
@ -566,8 +564,7 @@ input_route(struct interface *ifp,
|
||||
naddr dst,
|
||||
naddr mask,
|
||||
naddr gate,
|
||||
int metric,
|
||||
u_short tag)
|
||||
struct netinfo *n)
|
||||
{
|
||||
int i;
|
||||
struct rt_entry *rt;
|
||||
@ -594,19 +591,18 @@ input_route(struct interface *ifp,
|
||||
/* Consider adding the route if we do not already have it.
|
||||
*/
|
||||
if (rt == 0) {
|
||||
/* Usually ignore routes being poisoned.
|
||||
/* Ignore unknown routes being poisoned.
|
||||
*/
|
||||
if (metric == HOPCNT_INFINITY)
|
||||
if (n->n_metric == HOPCNT_INFINITY)
|
||||
return;
|
||||
|
||||
rtadd(dst, mask, gate, from, metric, tag, 0, ifp);
|
||||
rtadd(dst, mask, gate, from, n->n_metric, n->n_tag, 0, ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We already know about the route. Consider
|
||||
* this update.
|
||||
/* We already know about the route. Consider this update.
|
||||
*
|
||||
* If (rt->rt_state & RS_NET_SUB), then this route
|
||||
* If (rt->rt_state & RS_NET_SYN), then this route
|
||||
* is the same as a network route we have inferred
|
||||
* for subnets we know, in order to tell RIPv1 routers
|
||||
* about the subnets.
|
||||
@ -633,7 +629,7 @@ input_route(struct interface *ifp,
|
||||
* other than the current slot.
|
||||
*/
|
||||
if (rts0 == rt->rt_spares
|
||||
|| BETTER_LINK(rts0, rts))
|
||||
|| BETTER_LINK(rt, rts0, rts))
|
||||
rts0 = rts;
|
||||
}
|
||||
if (i != 0) {
|
||||
@ -641,26 +637,21 @@ input_route(struct interface *ifp,
|
||||
*/
|
||||
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 (old_metric < HOPCNT_INFINITY)
|
||||
new_time = now.tv_sec;
|
||||
|
||||
/* If this is an update for the router we currently prefer,
|
||||
* then note it.
|
||||
*/
|
||||
if (i == NUM_SPARES) {
|
||||
rtchange(rt,rt->rt_state, gate,rt->rt_router,
|
||||
metric, tag, ifp, new_time, 0);
|
||||
n->n_metric, n->n_tag, ifp, new_time, 0);
|
||||
/* If the route got worse, check for something better.
|
||||
*/
|
||||
if (metric > old_metric)
|
||||
if (n->n_metric > old_metric)
|
||||
rtswitch(rt, 0);
|
||||
return;
|
||||
}
|
||||
@ -669,8 +660,8 @@ input_route(struct interface *ifp,
|
||||
* Finished if the route is unchanged.
|
||||
*/
|
||||
if (rts->rts_gate == gate
|
||||
&& old_metric == metric
|
||||
&& rts->rts_tag == tag) {
|
||||
&& old_metric == n->n_metric
|
||||
&& rts->rts_tag == n->n_tag) {
|
||||
rts->rts_time = new_time;
|
||||
return;
|
||||
}
|
||||
@ -684,20 +675,20 @@ input_route(struct interface *ifp,
|
||||
/* 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).
|
||||
* received with metric HOPCNT_INFINITY).
|
||||
*/
|
||||
if (metric >= rts->rts_metric)
|
||||
if (n->n_metric >= rts->rts_metric)
|
||||
return;
|
||||
|
||||
new_time = now.tv_sec;
|
||||
}
|
||||
|
||||
if (TRACEACTIONS)
|
||||
trace_upslot(rt, rts, gate, from, ifp, metric, tag, new_time);
|
||||
trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
|
||||
|
||||
rts->rts_gate = gate;
|
||||
rts->rts_router = from;
|
||||
rts->rts_metric = metric;
|
||||
rts->rts_tag = tag;
|
||||
rts->rts_metric = n->n_metric;
|
||||
rts->rts_tag = n->n_tag;
|
||||
rts->rts_time = new_time;
|
||||
rts->rts_ifp = ifp;
|
||||
|
||||
|
@ -31,15 +31,14 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1988, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#ident "$Revision: 1.2 $"
|
||||
#ident "$Revision: 1.13 $"
|
||||
|
||||
#include "defs.h"
|
||||
#include "pathnames.h"
|
||||
@ -62,7 +61,6 @@ int ipforwarding = 1; /* kernel forwarding on */
|
||||
int default_gateway; /* 1=advertise default */
|
||||
int background = 1;
|
||||
int ridhosts; /* 1=reduce host routes */
|
||||
int ppp_noage; /* do not age routes on quiet links */
|
||||
int mhome; /* 1=want multi-homed host route */
|
||||
int advertise_mhome; /* 1=must continue adverising it */
|
||||
int auth_ok = 1; /* 1=ignore auth if we do not care */
|
||||
@ -94,12 +92,12 @@ main(int argc,
|
||||
int n, mib[4], off;
|
||||
size_t len;
|
||||
char *p, *q;
|
||||
struct timeval wtime, wtime2;
|
||||
struct timeval wtime, t2;
|
||||
time_t dt;
|
||||
fd_set ibits;
|
||||
naddr p_addr_h, p_mask;
|
||||
struct parm *parmp;
|
||||
naddr p_addr, p_mask;
|
||||
struct interface *ifp;
|
||||
struct parm parm;
|
||||
char *tracename = 0;
|
||||
|
||||
|
||||
@ -135,6 +133,12 @@ main(int argc,
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
bzero(&parm, sizeof(parm));
|
||||
parm.parm_d_metric = 1;
|
||||
p = check_parms(&parm);
|
||||
if (p != 0)
|
||||
msglog("bad -g: %s", p);
|
||||
else
|
||||
default_gateway = 1;
|
||||
break;
|
||||
|
||||
@ -146,10 +150,6 @@ main(int argc,
|
||||
mhome = 1; /* on multi-homed hosts */
|
||||
break;
|
||||
|
||||
case 'p': /* do not age routes on quiet */
|
||||
ppp_noage = 1; /* point-to-point links */
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
/* Ignore authentication if we do not care.
|
||||
* Crazy as it is, that is what RFC 1723 requires.
|
||||
@ -171,23 +171,22 @@ main(int argc,
|
||||
if (p && *p != '\0') {
|
||||
n = (int)strtoul(p+1, &q, 0);
|
||||
if (*q == '\0'
|
||||
&& n <= HOPCNT_INFINITY-2
|
||||
&& n <= HOPCNT_INFINITY-1
|
||||
&& n >= 1)
|
||||
*p = '\0';
|
||||
}
|
||||
if (!getnet(optarg, &p_addr_h, &p_mask)) {
|
||||
msglog("routed: bad network;"
|
||||
" \"-F %s\" ignored",
|
||||
if (!getnet(optarg, &p_addr, &p_mask)) {
|
||||
msglog("bad network; \"-F %s\"",
|
||||
optarg);
|
||||
break;
|
||||
}
|
||||
parmp = (struct parm*)malloc(sizeof(*parmp));
|
||||
bzero(parmp, sizeof(*parmp));
|
||||
parmp->parm_next = parms;
|
||||
parms = parmp;
|
||||
parmp->parm_a_h = p_addr_h;
|
||||
parmp->parm_m = p_mask;
|
||||
parmp->parm_d_metric = n;
|
||||
bzero(&parm, sizeof(parm));
|
||||
parm.parm_addr_h = ntohl(p_addr);
|
||||
parm.parm_mask = p_mask;
|
||||
parm.parm_d_metric = n;
|
||||
p = check_parms(&parm);
|
||||
if (p != 0)
|
||||
msglog("bad -F: %s", p);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
@ -195,10 +194,9 @@ main(int argc,
|
||||
* parameters.
|
||||
*/
|
||||
p = parse_parms(optarg);
|
||||
if (p != 0) {
|
||||
msglog("routed: bad \"%s\" in \"%s\"",
|
||||
if (p != 0)
|
||||
msglog("bad \"%s\" in \"%s\"",
|
||||
p, optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -217,6 +215,8 @@ main(int argc,
|
||||
logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]"
|
||||
" [-F net[,metric]] [-P parms]");
|
||||
}
|
||||
if (geteuid() != 0)
|
||||
logbad(0, "requires UID 0");
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_INET;
|
||||
@ -249,7 +249,10 @@ main(int argc,
|
||||
/* get into the background */
|
||||
if (background) {
|
||||
#ifdef sgi
|
||||
if (_daemonize(_DF_NOCHDIR,STDOUT_FILENO,STDERR_FILENO,-1)<0)
|
||||
if (0 > _daemonize(_DF_NOCHDIR,
|
||||
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
|
||||
new_tracelevel == 0 ? -1 : STDERR_FILENO,
|
||||
-1))
|
||||
BADERR(0, "_daemonize()");
|
||||
#else
|
||||
if (daemon(1, 1) < 0)
|
||||
@ -286,7 +289,7 @@ main(int argc,
|
||||
ftrace = 0;
|
||||
if (tracename != 0) {
|
||||
trace_on(tracename, 1);
|
||||
if (new_tracelevel == 0)
|
||||
if (new_tracelevel == 0) /* use stdout if file is bad */
|
||||
new_tracelevel = 1;
|
||||
}
|
||||
set_tracelevel();
|
||||
@ -314,15 +317,6 @@ main(int argc,
|
||||
signal(SIGUSR1, sigtrace_on);
|
||||
signal(SIGUSR2, sigtrace_off);
|
||||
|
||||
/* If we have an interface to the wide, wide world, add an entry for
|
||||
* an Internet default route to the internal tables and advertise it.
|
||||
* This route is not added to the kernel routes, but this entry
|
||||
* prevents us from listening to default routes from other
|
||||
* systems and installing them in the kernel.
|
||||
*/
|
||||
if (default_gateway > 0)
|
||||
rtadd(RIP_DEFAULT, 0, myaddr, myaddr, 1, 0, RS_GW, 0);
|
||||
|
||||
/* Collect an initial view of the world by checking the interface
|
||||
* configuration and the kludge file.
|
||||
*/
|
||||
@ -340,16 +334,16 @@ main(int argc,
|
||||
for (;;) {
|
||||
prev_clk = clk;
|
||||
gettimeofday(&clk, 0);
|
||||
timevalsub(&wtime2, &clk, &prev_clk);
|
||||
if (wtime2.tv_sec < 0
|
||||
|| wtime2.tv_sec > wtime.tv_sec + 5) {
|
||||
timevalsub(&t2, &clk, &prev_clk);
|
||||
if (t2.tv_sec < 0
|
||||
|| t2.tv_sec > wtime.tv_sec + 5) {
|
||||
/* Deal with time changes before other housekeeping to
|
||||
* keep everything straight.
|
||||
*/
|
||||
dt = wtime2.tv_sec;
|
||||
dt = t2.tv_sec;
|
||||
if (dt > 0)
|
||||
dt -= wtime.tv_sec;
|
||||
trace_msg("time changed by %d sec\n", dt);
|
||||
trace_act("time changed by %d sec\n", dt);
|
||||
epoch.tv_sec += dt;
|
||||
}
|
||||
timevalsub(&now, &clk, &epoch);
|
||||
@ -364,13 +358,14 @@ main(int argc,
|
||||
rip_bcast(0);
|
||||
rdisc_adv();
|
||||
}
|
||||
trace_off("exiting","");
|
||||
trace_off("exiting with signal %d\n", stopint);
|
||||
exit(stopint | 128);
|
||||
}
|
||||
|
||||
/* look for new or dead interfaces */
|
||||
timevalsub(&wtime, &ifinit_timer, &now);
|
||||
if (wtime.tv_sec <= 0) {
|
||||
wtime.tv_sec = 0;
|
||||
ifinit();
|
||||
rip_query();
|
||||
continue;
|
||||
@ -379,8 +374,8 @@ main(int argc,
|
||||
/* If it is time, then broadcast our routes.
|
||||
*/
|
||||
if (supplier || advertise_mhome) {
|
||||
timevalsub(&wtime2, &next_bcast, &now);
|
||||
if (wtime2.tv_sec <= 0) {
|
||||
timevalsub(&t2, &next_bcast, &now);
|
||||
if (t2.tv_sec <= 0) {
|
||||
/* Synchronize the aging and broadcast
|
||||
* timers to minimize awakenings
|
||||
*/
|
||||
@ -398,14 +393,14 @@ main(int argc,
|
||||
* pick a 30-second aniversary of the
|
||||
* original broadcast time.
|
||||
*/
|
||||
n = 1 + (0-wtime2.tv_sec)/SUPPLY_INTERVAL;
|
||||
n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL;
|
||||
next_bcast.tv_sec += n*SUPPLY_INTERVAL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (timercmp(&wtime2, &wtime, <))
|
||||
wtime = wtime2;
|
||||
if (timercmp(&t2, &wtime, <))
|
||||
wtime = t2;
|
||||
}
|
||||
|
||||
/* If we need a flash update, either do it now or
|
||||
@ -420,30 +415,30 @@ main(int argc,
|
||||
/* accurate to the millisecond */
|
||||
if (!timercmp(&no_flash, &now, >))
|
||||
rip_bcast(1);
|
||||
timevalsub(&wtime2, &no_flash, &now);
|
||||
if (timercmp(&wtime2, &wtime, <))
|
||||
wtime = wtime2;
|
||||
timevalsub(&t2, &no_flash, &now);
|
||||
if (timercmp(&t2, &wtime, <))
|
||||
wtime = t2;
|
||||
}
|
||||
|
||||
/* trigger the main aging timer.
|
||||
*/
|
||||
timevalsub(&wtime2, &age_timer, &now);
|
||||
if (wtime2.tv_sec <= 0) {
|
||||
timevalsub(&t2, &age_timer, &now);
|
||||
if (t2.tv_sec <= 0) {
|
||||
age(0);
|
||||
continue;
|
||||
}
|
||||
if (timercmp(&wtime2, &wtime, <))
|
||||
wtime = wtime2;
|
||||
if (timercmp(&t2, &wtime, <))
|
||||
wtime = t2;
|
||||
|
||||
/* update the kernel routing table
|
||||
*/
|
||||
timevalsub(&wtime2, &need_kern, &now);
|
||||
if (wtime2.tv_sec <= 0) {
|
||||
timevalsub(&t2, &need_kern, &now);
|
||||
if (t2.tv_sec <= 0) {
|
||||
age(0);
|
||||
continue;
|
||||
}
|
||||
if (timercmp(&wtime2, &wtime, <))
|
||||
wtime = wtime2;
|
||||
if (timercmp(&t2, &wtime, <))
|
||||
wtime = t2;
|
||||
|
||||
/* take care of router discovery,
|
||||
* but do it to the millisecond
|
||||
@ -452,15 +447,15 @@ main(int argc,
|
||||
rdisc_age(0);
|
||||
continue;
|
||||
}
|
||||
timevalsub(&wtime2, &rdisc_timer, &now);
|
||||
if (timercmp(&wtime2, &wtime, <))
|
||||
wtime = wtime2;
|
||||
timevalsub(&t2, &rdisc_timer, &now);
|
||||
if (timercmp(&t2, &wtime, <))
|
||||
wtime = t2;
|
||||
|
||||
|
||||
/* wait for input or a timer to expire.
|
||||
*/
|
||||
ibits = fdbits;
|
||||
trace_flush();
|
||||
ibits = fdbits;
|
||||
n = select(sock_max, &ibits, 0, 0, &wtime);
|
||||
if (n <= 0) {
|
||||
if (n < 0 && errno != EINTR && errno != EAGAIN)
|
||||
@ -500,6 +495,7 @@ sigalrm(int sig)
|
||||
* new and broken interfaces.
|
||||
*/
|
||||
ifinit_timer.tv_sec = now.tv_sec;
|
||||
trace_act("SIGALRM\n");
|
||||
}
|
||||
|
||||
|
||||
@ -569,7 +565,7 @@ fix_sock(int sock,
|
||||
for (rbuf = 60*1024; ; rbuf -= 4096) {
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
|
||||
&rbuf, sizeof(rbuf)) == 0) {
|
||||
trace_msg("RCVBUF=%d\n", rbuf);
|
||||
trace_act("RCVBUF=%d\n", rbuf);
|
||||
break;
|
||||
}
|
||||
if (rbuf < MIN_SOCKBUF) {
|
||||
@ -627,8 +623,8 @@ rip_off(void)
|
||||
register naddr addr;
|
||||
|
||||
|
||||
if (rip_sock >= 0) {
|
||||
trace_msg("turn off RIP\n");
|
||||
if (rip_sock >= 0 && !mhome) {
|
||||
trace_act("turn off RIP\n");
|
||||
|
||||
(void)close(rip_sock);
|
||||
rip_sock = -1;
|
||||
@ -652,36 +648,49 @@ rip_off(void)
|
||||
}
|
||||
|
||||
|
||||
/* Prepare socket used for RIP.
|
||||
/* turn on RIP multicast input via an interface
|
||||
*/
|
||||
void
|
||||
rip_on(struct interface *ifp)
|
||||
static void
|
||||
rip_mcast_on(struct interface *ifp)
|
||||
{
|
||||
struct ip_mreq m;
|
||||
|
||||
|
||||
if (rip_sock >= 0) {
|
||||
if (ifp != 0
|
||||
&& 0 == (ifp->int_state & (IS_NO_RIP_IN|IS_PASSIVE))
|
||||
if (!IS_RIP_IN_OFF(ifp->int_state)
|
||||
&& (ifp->int_if_flags & IFF_MULTICAST)
|
||||
#ifdef MCAST_PPP_BUG
|
||||
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
|
||||
#endif
|
||||
&& !(ifp->int_state & IS_ALIAS)) {
|
||||
m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
|
||||
m.imr_interface.s_addr = ((ifp->int_if_flags
|
||||
& IFF_POINTOPOINT)
|
||||
m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
|
||||
? ifp->int_dstaddr
|
||||
: ifp->int_addr);
|
||||
if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&m, sizeof(m)) < 0)
|
||||
DBGERR(1,"setsockopt(IP_ADD_MEMBERSHIP RIP)");
|
||||
LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Prepare socket used for RIP.
|
||||
*/
|
||||
void
|
||||
rip_on(struct interface *ifp)
|
||||
{
|
||||
/* If the main RIP socket is already alive, only start receiving
|
||||
* multicasts for this interface.
|
||||
*/
|
||||
if (rip_sock >= 0) {
|
||||
if (ifp != 0)
|
||||
rip_mcast_on(ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the main RIP socket is off, and it makes sense to turn it on,
|
||||
* turn it on for all of the interfaces.
|
||||
*/
|
||||
if (rip_interfaces > 0 && !rdisc_ok) {
|
||||
trace_msg("turn on RIP\n");
|
||||
trace_act("turn on RIP\n");
|
||||
|
||||
/* Close all of the query sockets so that we can open
|
||||
* the main socket. SO_REUSEPORT is not a solution,
|
||||
@ -704,18 +713,9 @@ rip_on(struct interface *ifp)
|
||||
next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
|
||||
|
||||
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
|
||||
if ((ifp->int_state & IS_NO_RIP_IN) != IS_NO_RIP_IN)
|
||||
if (!IS_RIP_IN_OFF(ifp->int_state))
|
||||
ifp->int_state &= ~IS_RIP_QUERIED;
|
||||
|
||||
if ((ifp->int_if_flags & IFF_MULTICAST)
|
||||
&& !(ifp->int_state & IS_ALIAS)) {
|
||||
m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
|
||||
m.imr_interface.s_addr = ifp->int_addr;
|
||||
if (setsockopt(rip_sock, IPPROTO_IP,
|
||||
IP_ADD_MEMBERSHIP,
|
||||
&m, sizeof(m)) < 0)
|
||||
DBGERR(1,"setsockopt(IP_ADD_MEMBERSHIP RIP)");
|
||||
}
|
||||
rip_mcast_on(ifp);
|
||||
}
|
||||
|
||||
ifinit_timer.tv_sec = now.tv_sec;
|
||||
|
@ -31,11 +31,11 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#ident "$Revision: 1.1 $"
|
||||
#ident "$Revision: 1.14 $"
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
@ -52,31 +52,33 @@ struct {
|
||||
naddr to_std_mask;
|
||||
naddr to_std_net;
|
||||
struct interface *ifp; /* usually output interface */
|
||||
struct ws_buf { /* for each buffer */
|
||||
struct ws_buf { /* info for each buffer */
|
||||
struct rip *buf;
|
||||
struct netinfo *n;
|
||||
struct netinfo *base;
|
||||
struct netinfo *lim;
|
||||
enum output_type type;
|
||||
} v2, mcast;
|
||||
} v12, v2;
|
||||
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 */
|
||||
u_int state;
|
||||
#define WS_ST_FLASH 0x001 /* send only changed routes */
|
||||
#define WS_ST_RIP2_SAFE 0x002 /* send RIPv2 safe for RIPv1 */
|
||||
#define WS_ST_RIP2_ALL 0x004 /* send full featured RIPv2 */
|
||||
#define WS_ST_AG 0x008 /* ok to aggregate subnets */
|
||||
#define WS_ST_SUPER_AG 0x010 /* ok to aggregate networks */
|
||||
#define WS_ST_SUB_AG 0x020 /* aggregate subnets in odd case */
|
||||
#define WS_ST_QUERY 0x040 /* responding to a query */
|
||||
#define WS_ST_TO_ON_NET 0x080 /* sending onto one of our nets */
|
||||
#define WS_ST_DEFAULT 0x100 /* faking a default */
|
||||
#define WS_ST_PM_RDISC 0x200 /* poor-man's router discovery */
|
||||
} ws;
|
||||
|
||||
/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */
|
||||
union pkt_buf ripv2_buf;
|
||||
union pkt_buf ripv12_buf;
|
||||
|
||||
/* Another for only RIPv2 listeners */
|
||||
union pkt_buf rip_mcast_buf;
|
||||
union pkt_buf rip_v2_buf;
|
||||
|
||||
|
||||
|
||||
@ -92,9 +94,10 @@ output(enum output_type type,
|
||||
struct sockaddr_in sin;
|
||||
int flags;
|
||||
char *msg;
|
||||
int res, serrno;
|
||||
int res;
|
||||
naddr tgt_mcast;
|
||||
int soc;
|
||||
int serrno;
|
||||
|
||||
sin = *dst;
|
||||
if (sin.sin_port == 0)
|
||||
@ -121,15 +124,20 @@ output(enum output_type type,
|
||||
break;
|
||||
case OUT_BROADCAST:
|
||||
if (ifp->int_if_flags & IFF_POINTOPOINT) {
|
||||
msg = "Send pt-to-pt";
|
||||
} else {
|
||||
msg = "Send";
|
||||
} else {
|
||||
msg = "Send bcast";
|
||||
}
|
||||
flags = MSG_DONTROUTE;
|
||||
break;
|
||||
case OUT_MULTICAST:
|
||||
if (ifp->int_if_flags & IFF_POINTOPOINT) {
|
||||
msg = "Send pt-to-pt";
|
||||
} else if (ifp->int_state & IS_DUP) {
|
||||
trace_act("abort multicast output via %s"
|
||||
" with duplicate address\n",
|
||||
ifp->int_name);
|
||||
return 0;
|
||||
} else {
|
||||
msg = "Send mcast";
|
||||
if (rip_sock_mcast != ifp) {
|
||||
@ -147,25 +155,31 @@ output(enum output_type type,
|
||||
} else
|
||||
#endif
|
||||
tgt_mcast = ifp->int_addr;
|
||||
if (setsockopt(rip_sock,
|
||||
if (0 > setsockopt(rip_sock,
|
||||
IPPROTO_IP, IP_MULTICAST_IF,
|
||||
&tgt_mcast, sizeof(tgt_mcast)))
|
||||
BADERR(1,"setsockopt(rip_sock,"
|
||||
&tgt_mcast,
|
||||
sizeof(tgt_mcast))) {
|
||||
serrno = errno;
|
||||
LOGERR("setsockopt(rip_sock,"
|
||||
"IP_MULTICAST_IF)");
|
||||
errno = serrno;
|
||||
ifp = 0;
|
||||
return -1;
|
||||
}
|
||||
rip_sock_mcast = ifp;
|
||||
}
|
||||
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
if (TRACEPACKETS)
|
||||
trace_rip(msg, "to", &sin, ifp, buf, size);
|
||||
|
||||
res = sendto(soc, buf, size, flags,
|
||||
(struct sockaddr *)&sin, sizeof(sin));
|
||||
if (res < 0) {
|
||||
if (res < 0
|
||||
&& (ifp == 0 || !(ifp->int_state & IS_BROKE))) {
|
||||
serrno = errno;
|
||||
msglog("sendto(%s%s%s.%d): %s",
|
||||
msglog("%s sendto(%s%s%s.%d): %s", msg,
|
||||
ifp != 0 ? ifp->int_name : "",
|
||||
ifp != 0 ? ", " : "",
|
||||
inet_ntoa(sin.sin_addr),
|
||||
@ -198,27 +212,31 @@ set_auth(struct ws_buf *w)
|
||||
/* Send the buffer
|
||||
*/
|
||||
static void
|
||||
supply_write(struct ws_buf *w)
|
||||
supply_write(struct ws_buf *wb)
|
||||
{
|
||||
/* 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
|
||||
switch (wb->type) {
|
||||
case NO_OUT_MULTICAST:
|
||||
trace_pkt("skip multicast to %s because impossible\n",
|
||||
naddr_ntoa(ws.to.sin_addr.s_addr));
|
||||
break;
|
||||
case NO_OUT_RIPV2:
|
||||
break;
|
||||
default:
|
||||
if (output(wb->type, &ws.to, ws.ifp, wb->buf,
|
||||
((char *)wb->n - (char*)wb->buf)) < 0
|
||||
&& ws.ifp != 0)
|
||||
ifbad(ws.ifp, 0);
|
||||
if_sick(ws.ifp);
|
||||
ws.npackets++;
|
||||
break;
|
||||
}
|
||||
|
||||
bzero(w->n = w->base, sizeof(*w->n)*NETS_LEN);
|
||||
|
||||
if (w->buf->rip_vers == RIPv2)
|
||||
set_auth(w);
|
||||
bzero(wb->n = wb->base, sizeof(*wb->n)*NETS_LEN);
|
||||
if (wb->buf->rip_vers == RIPv2)
|
||||
set_auth(wb);
|
||||
}
|
||||
|
||||
|
||||
@ -229,35 +247,46 @@ supply_out(struct ag_info *ag)
|
||||
{
|
||||
int i;
|
||||
naddr mask, v1_mask, s_mask, dst_h, ddst_h;
|
||||
struct ws_buf *w;
|
||||
struct ws_buf *wb;
|
||||
|
||||
|
||||
/* Skip this route if doing a flash update and it and the routes
|
||||
* it aggregates have not changed recently.
|
||||
*/
|
||||
if (ag->ag_seqno <= update_seqno
|
||||
if (ag->ag_seqno < update_seqno
|
||||
&& (ws.state & WS_ST_FLASH))
|
||||
return;
|
||||
|
||||
/* Skip this route if required by split-horizon
|
||||
*/
|
||||
if (ag->ag_state & AGS_SPLIT_HZ)
|
||||
return;
|
||||
|
||||
dst_h = ag->ag_dst_h;
|
||||
mask = ag->ag_mask;
|
||||
v1_mask = ripv1_mask_host(htonl(dst_h),
|
||||
(ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0,
|
||||
0);
|
||||
(ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0);
|
||||
s_mask = std_mask(htonl(dst_h));
|
||||
i = 0;
|
||||
|
||||
/* If we are sending RIPv2 packets that cannot (or must not) be
|
||||
* heard by RIPv1 listeners, do not worry about sub- or supernets.
|
||||
* Subnets (from other networks) can only be sent via multicast.
|
||||
* A pair of subnet routes might have been promoted so that they
|
||||
* are legal to send by RIPv1.
|
||||
* If RIPv1 is off, use the multicast buffer, unless this is the
|
||||
* fake default route and it is acting as a poor-man's router-
|
||||
* discovery mechanism.
|
||||
*/
|
||||
if ((ws.state & WS_ST_RIP2_ALL)
|
||||
|| ((ag->ag_state & AGS_RIPV2)
|
||||
&& v1_mask != mask)) {
|
||||
w = &ws.mcast; /* use the multicast-only buffer */
|
||||
if (((ws.state & WS_ST_RIP2_ALL)
|
||||
&& (dst_h != RIP_DEFAULT || !(ws.state & WS_ST_PM_RDISC)))
|
||||
|| ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) {
|
||||
/* use the RIPv2-only buffer */
|
||||
wb = &ws.v2;
|
||||
|
||||
} else {
|
||||
w = &ws.v2;
|
||||
/* use the RIPv1-or-RIPv2 buffer */
|
||||
wb = &ws.v12;
|
||||
|
||||
/* Convert supernet route into corresponding set of network
|
||||
* routes for RIPv1, but leave non-contiguous netmasks
|
||||
@ -287,21 +316,33 @@ supply_out(struct ag_info *ag)
|
||||
}
|
||||
|
||||
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;
|
||||
wb->n->n_family = RIP_AF_INET;
|
||||
wb->n->n_dst = htonl(dst_h);
|
||||
/* If the route is from router-discovery or we are
|
||||
* shutting down, admit only a bad metric.
|
||||
*/
|
||||
wb->n->n_metric = ((stopint || ag->ag_metric < 1)
|
||||
? HOPCNT_INFINITY
|
||||
: ag->ag_metric);
|
||||
HTONL(wb->n->n_metric);
|
||||
if (wb->buf->rip_vers == RIPv2) {
|
||||
if (ag->ag_nhop != 0
|
||||
&& (ws.state & WS_ST_RIP2_SAFE)
|
||||
&& ((ws.state & WS_ST_QUERY)
|
||||
|| (ag->ag_nhop != ws.ifp->int_addr
|
||||
&& on_net(ag->ag_nhop,
|
||||
ws.ifp->int_net,
|
||||
ws.ifp->int_mask))))
|
||||
wb->n->n_nhop = ag->ag_nhop;
|
||||
if ((ws.state & WS_ST_RIP2_ALL)
|
||||
|| mask != s_mask)
|
||||
w->n->n_mask = htonl(mask);
|
||||
w->n->n_tag = ag->ag_tag;
|
||||
wb->n->n_mask = htonl(mask);
|
||||
wb->n->n_tag = ag->ag_tag;
|
||||
}
|
||||
dst_h += ddst_h;
|
||||
|
||||
if (++w->n >= w->lim)
|
||||
supply_write(w);
|
||||
if (++wb->n >= wb->lim)
|
||||
supply_write(wb);
|
||||
} while (i-- != 0);
|
||||
}
|
||||
|
||||
@ -314,57 +355,119 @@ walk_supply(struct radix_node *rn,
|
||||
struct walkarg *w)
|
||||
{
|
||||
#define RT ((struct rt_entry *)rn)
|
||||
u_short ags;
|
||||
u_short ags = 0;
|
||||
char metric, pref;
|
||||
naddr dst, gate;
|
||||
naddr dst, nhop;
|
||||
|
||||
|
||||
/* Do not advertise the loopback interface
|
||||
* or external remote interfaces
|
||||
*/
|
||||
if (RT->rt_ifp != 0
|
||||
&& ((RT->rt_ifp->int_if_flags & IFF_LOOPBACK)
|
||||
|| (RT->rt_ifp->int_state & IS_EXTERNAL)))
|
||||
|| (RT->rt_ifp->int_state & IS_EXTERNAL))
|
||||
&& !(RT->rt_state & RS_MHOME))
|
||||
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 being quiet about our ability to forward, then
|
||||
* do not say anything unless responding to a query.
|
||||
*/
|
||||
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))
|
||||
if (!supplier && !(ws.state & WS_ST_QUERY))
|
||||
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 */
|
||||
/* do not collide with the fake default route */
|
||||
if (dst == RIP_DEFAULT
|
||||
&& (ws.state & WS_ST_DEFAULT))
|
||||
return 0;
|
||||
|
||||
if (RT_ISHOST(RT)) {
|
||||
if (RT->rt_state & RS_NET_SYN) {
|
||||
if (RT->rt_state & RS_NET_INT) {
|
||||
/* Do not send manual synthetic network routes
|
||||
* into the subnet.
|
||||
*/
|
||||
if (on_net(ws.to.sin_addr.s_addr,
|
||||
ntohl(dst), RT->rt_mask))
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
/* Do not send automatic synthetic network routes
|
||||
* if they are not needed becaus no RIPv1 listeners
|
||||
* can hear them.
|
||||
*/
|
||||
if (ws.state & WS_ST_RIP2_ALL)
|
||||
return 0;
|
||||
|
||||
/* Do not send automatic synthetic network routes to
|
||||
* the real subnet.
|
||||
*/
|
||||
if (on_net(ws.to.sin_addr.s_addr,
|
||||
ntohl(dst), RT->rt_mask))
|
||||
return 0;
|
||||
}
|
||||
nhop = 0;
|
||||
|
||||
} else {
|
||||
/* Advertise the next hop if this is not a route for one
|
||||
* of our interfaces and the next hop is on the same
|
||||
* network as the target.
|
||||
*/
|
||||
if (!(RT->rt_state & RS_IF)
|
||||
&& RT->rt_gate != myaddr
|
||||
&& RT->rt_gate != loopaddr)
|
||||
nhop = RT->rt_gate;
|
||||
else
|
||||
nhop = 0;
|
||||
}
|
||||
|
||||
/* Adjust the outgoing metric by the cost of the link.
|
||||
*/
|
||||
pref = metric = RT->rt_metric + ws.metric;
|
||||
if (pref < HOPCNT_INFINITY) {
|
||||
/* Keep track of the best metric with which the
|
||||
* route has been advertised recently.
|
||||
*/
|
||||
if (RT->rt_poison_metric >= metric
|
||||
|| RT->rt_poison_time <= now_garbage) {
|
||||
RT->rt_poison_time = now.tv_sec;
|
||||
RT->rt_poison_metric = RT->rt_metric;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Do not advertise stable routes that will be ignored,
|
||||
* unless they are being held down and poisoned. If the
|
||||
* route recently was advertised with a metric that would
|
||||
* have been less than infinity through this interface, we
|
||||
* need to continue to advertise it in order to poison it.
|
||||
*/
|
||||
pref = RT->rt_poison_metric + ws.metric;
|
||||
if (pref >= HOPCNT_INFINITY)
|
||||
return 0;
|
||||
|
||||
metric = HOPCNT_INFINITY;
|
||||
}
|
||||
|
||||
if (RT->rt_state & RS_MHOME) {
|
||||
/* retain host route of multi-homed servers */
|
||||
;
|
||||
|
||||
} else if (RT_ISHOST(RT)) {
|
||||
/* We should always aggregate the host routes
|
||||
* for the local end of our point-to-point links.
|
||||
* If we are suppressing host routes, then do so.
|
||||
* If we are suppressing host routes in general, then do so.
|
||||
* Avoid advertising host routes onto their own network,
|
||||
* where they should be handled by proxy-ARP.
|
||||
*/
|
||||
if ((RT->rt_state & RS_LOCAL)
|
||||
|| ridhosts)
|
||||
|| ridhosts
|
||||
|| (ws.state & WS_ST_SUPER_AG)
|
||||
|| on_net(dst, ws.to_net, ws.to_mask))
|
||||
ags |= AGS_SUPPRESS;
|
||||
|
||||
if (ws.state & WS_ST_SUPER_AG)
|
||||
ags |= AGS_PROMOTE;
|
||||
|
||||
} else if (ws.state & WS_ST_AG) {
|
||||
/* Aggregate network routes, if we are allowed.
|
||||
*/
|
||||
@ -372,82 +475,49 @@ walk_supply(struct radix_node *rn,
|
||||
|
||||
/* 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.
|
||||
* 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.
|
||||
/* Do not send RIPv1 advertisements of subnets to other
|
||||
* networks. If possible, multicast them by RIPv2.
|
||||
*/
|
||||
if (0 != (RT->rt_state & (RS_IF | RS_MHOME)))
|
||||
ags &= ~(AGS_SUPPRESS | AGS_PROMOTE);
|
||||
if ((RT->rt_state & RS_SUBNET)
|
||||
&& !(ws.state & WS_ST_RIP2_ALL)
|
||||
&& !on_net(dst, ws.to_std_net, ws.to_std_mask)) {
|
||||
ags |= AGS_RIPV2 | AGS_PROMOTE;
|
||||
if (ws.state & WS_ST_SUB_AG)
|
||||
ags |= AGS_SUPPRESS;
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
/* 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 possible, multicast them by RIPv2.
|
||||
* We want to suppress routes that might have been fragmented
|
||||
* from this route by a RIPv1 router and sent back to us, and so we
|
||||
* cannot forget this route here. Let the split-horizon route
|
||||
* aggregate (suppress) the fragmented routes and then itself be
|
||||
* forgotten.
|
||||
*
|
||||
* Include the routes for both ends of point-to-point interfaces
|
||||
* since the other side presumably knows them as well as we do.
|
||||
*/
|
||||
if (!(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;
|
||||
if (RT->rt_ifp == ws.ifp && ws.ifp != 0
|
||||
&& !(ws.state & WS_ST_QUERY)
|
||||
&& (ws.state & WS_ST_TO_ON_NET)
|
||||
&& (!(RT->rt_state & RS_IF)
|
||||
|| ws.ifp->int_if_flags & IFF_POINTOPOINT)) {
|
||||
ags |= AGS_SPLIT_HZ;
|
||||
ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
ag_check(dst, RT->rt_mask, 0, nhop, metric, pref,
|
||||
RT->rt_seqno, RT->rt_tag, ags, supply_out);
|
||||
return 0;
|
||||
#undef RT
|
||||
@ -466,7 +536,6 @@ supply(struct sockaddr_in *dst,
|
||||
{
|
||||
static int init = 1;
|
||||
struct rt_entry *rt;
|
||||
int metric;
|
||||
|
||||
|
||||
ws.state = 0;
|
||||
@ -482,7 +551,7 @@ supply(struct sockaddr_in *dst,
|
||||
ws.state |= WS_ST_TO_ON_NET;
|
||||
|
||||
} else {
|
||||
ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0, 0);
|
||||
ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0);
|
||||
ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask;
|
||||
rt = rtfind(dst->sin_addr.s_addr);
|
||||
if (rt)
|
||||
@ -496,45 +565,69 @@ supply(struct sockaddr_in *dst,
|
||||
ws.state |= WS_ST_QUERY;
|
||||
|
||||
if ((ws.ifp = ifp) == 0) {
|
||||
ws.metric = 0;
|
||||
ws.metric = 1;
|
||||
} else {
|
||||
/* Adjust the advertised metric by the outgoing interface
|
||||
* metric, but reduced by 1 to avoid counting this hop
|
||||
* twice.
|
||||
* metric.
|
||||
*/
|
||||
ws.metric = ifp->int_metric;
|
||||
if (ws.metric > 0)
|
||||
ws.metric--;
|
||||
ws.metric = ifp->int_metric+1;
|
||||
}
|
||||
|
||||
if (init) {
|
||||
init = 0;
|
||||
|
||||
bzero(&ripv2_buf, sizeof(ripv2_buf));
|
||||
ripv2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
|
||||
ws.v2.buf = &ripv2_buf.rip;
|
||||
bzero(&ripv12_buf, sizeof(ripv12_buf));
|
||||
ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE;
|
||||
ws.v12.buf = &ripv12_buf.rip;
|
||||
ws.v12.base = &ws.v12.buf->rip_nets[0];
|
||||
ws.v12.lim = ws.v12.base + NETS_LEN;
|
||||
|
||||
bzero(&rip_v2_buf, sizeof(rip_v2_buf));
|
||||
rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
|
||||
rip_v2_buf.rip.rip_vers = RIPv2;
|
||||
ws.v2.buf = &rip_v2_buf.rip;
|
||||
ws.v2.base = &ws.v2.buf->rip_nets[0];
|
||||
ws.v2.lim = ws.v2.base + NETS_LEN;
|
||||
|
||||
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;
|
||||
ripv12_buf.rip.rip_vers = vers;
|
||||
|
||||
ws.v2.type = type;
|
||||
ws.v12.n = ws.v12.base;
|
||||
set_auth(&ws.v12);
|
||||
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);
|
||||
switch (type) {
|
||||
case OUT_BROADCAST:
|
||||
ws.v2.type = ((ws.ifp != 0
|
||||
&& (ws.ifp->int_if_flags & IFF_MULTICAST))
|
||||
? OUT_MULTICAST
|
||||
: NO_OUT_MULTICAST);
|
||||
ws.v12.type = OUT_BROADCAST;
|
||||
break;
|
||||
case OUT_MULTICAST:
|
||||
ws.v2.type = ((ws.ifp != 0
|
||||
&& (ws.ifp->int_if_flags & IFF_MULTICAST))
|
||||
? OUT_MULTICAST
|
||||
: NO_OUT_MULTICAST);
|
||||
ws.v12.type = OUT_BROADCAST;
|
||||
break;
|
||||
case OUT_UNICAST:
|
||||
case OUT_QUERY:
|
||||
ws.v2.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
|
||||
ws.v12.type = type;
|
||||
break;
|
||||
default:
|
||||
ws.v2.type = type;
|
||||
ws.v12.type = type;
|
||||
break;
|
||||
}
|
||||
|
||||
if (vers == RIPv2) {
|
||||
/* if asked to send RIPv2, send at least that which can
|
||||
* be safely heard by RIPv1 listeners.
|
||||
*/
|
||||
ws.state |= WS_ST_RIP2_SAFE;
|
||||
|
||||
/* full RIPv2 only if cannot be heard by RIPv1 listeners */
|
||||
if (type != OUT_BROADCAST)
|
||||
ws.state |= WS_ST_RIP2_ALL;
|
||||
@ -547,43 +640,51 @@ supply(struct sockaddr_in *dst,
|
||||
|| !(ws.ifp->int_state & IS_NO_SUPER_AG)))
|
||||
ws.state |= WS_ST_SUPER_AG;
|
||||
}
|
||||
|
||||
} else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) {
|
||||
ws.state |= WS_ST_SUB_AG;
|
||||
}
|
||||
|
||||
/* send the routes
|
||||
if (supplier) {
|
||||
/* Fake a default route if asked, and if there is not
|
||||
* a better, real default route.
|
||||
*/
|
||||
if ((metric = ifp->int_d_metric) != 0) {
|
||||
/* Fake a default route if asked */
|
||||
if (ifp->int_d_metric != 0
|
||||
&& (0 == (rt = rtget(RIP_DEFAULT, 0))
|
||||
|| rt->rt_metric+ws.metric >= ifp->int_d_metric)) {
|
||||
ws.state |= WS_ST_DEFAULT;
|
||||
|
||||
/* 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);
|
||||
ag_check(0, 0, 0, 0,
|
||||
ifp->int_d_metric,ifp->int_d_metric,
|
||||
0, 0, 0, supply_out);
|
||||
}
|
||||
if ((ws.state & WS_ST_RIP2_ALL)
|
||||
&& (ifp->int_state & IS_PM_RDISC)) {
|
||||
ws.state |= WS_ST_PM_RDISC;
|
||||
ripv12_buf.rip.rip_vers = RIPv1;
|
||||
}
|
||||
}
|
||||
|
||||
(void)rn_walktree(rhead, walk_supply, 0);
|
||||
ag_flush(0,0,supply_out);
|
||||
|
||||
/* Flush the packet buffers */
|
||||
/* Flush the packet buffers, provided they are not empty and
|
||||
* do not contain only the password.
|
||||
*/
|
||||
if (ws.v12.n != ws.v12.base
|
||||
&& (ws.v12.n > ws.v12.base+1
|
||||
|| ws.v12.n->n_family != RIP_AF_AUTH))
|
||||
supply_write(&ws.v12);
|
||||
if (ws.v2.n != ws.v2.base
|
||||
&& (ws.v2.n > ws.v2.base+1
|
||||
|| ws.v2.n->n_family != RIP_AF_AUTH))
|
||||
supply_write(&ws.v2);
|
||||
if (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);
|
||||
supply_write(&ws.v12);
|
||||
}
|
||||
|
||||
|
||||
@ -611,7 +712,7 @@ rip_bcast(int flash)
|
||||
if (rip_sock < 0)
|
||||
return;
|
||||
|
||||
trace_msg("send %s and inhibit dynamic updates for %.3f sec\n",
|
||||
trace_act("send %s and inhibit dynamic updates for %.3f sec\n",
|
||||
flash ? "dynamic update" : "all routes",
|
||||
rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0);
|
||||
|
||||
@ -620,18 +721,16 @@ rip_bcast(int flash)
|
||||
* and aliases. Do try broken interfaces to see
|
||||
* if they have healed.
|
||||
*/
|
||||
if (0 != (ifp->int_state & (IS_PASSIVE
|
||||
| IS_ALIAS)))
|
||||
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.
|
||||
*/
|
||||
/* default to RIPv1 output */
|
||||
if (ifp->int_state & IS_NO_RIPV1_OUT) {
|
||||
/* Say nothing if this interface is turned off */
|
||||
if (ifp->int_state & IS_NO_RIPV2_OUT)
|
||||
continue;
|
||||
vers = RIPv2;
|
||||
@ -645,10 +744,11 @@ rip_bcast(int flash)
|
||||
/* 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 {
|
||||
if (vers == RIPv2
|
||||
&& (ifp->int_state & IS_NO_RIPV1_OUT)) {
|
||||
type = OUT_MULTICAST;
|
||||
} else {
|
||||
type = OUT_BROADCAST;
|
||||
}
|
||||
|
||||
} else if (ifp->int_if_flags & IFF_POINTOPOINT) {
|
||||
@ -697,16 +797,16 @@ rip_query(void)
|
||||
* if they have healed.
|
||||
*/
|
||||
if (0 != (ifp->int_state & (IS_RIP_QUERIED
|
||||
| IS_PASSIVE
|
||||
| IS_ALIAS)))
|
||||
| IS_PASSIVE | IS_ALIAS)))
|
||||
continue;
|
||||
|
||||
/* skip turned off interfaces */
|
||||
if (!iff_alive(ifp->int_if_flags))
|
||||
continue;
|
||||
|
||||
/* prefer RIPv2 queries */
|
||||
/* default to RIPv1 output */
|
||||
if (ifp->int_state & IS_NO_RIPV2_OUT) {
|
||||
/* Say nothing if this interface is turned off */
|
||||
if (ifp->int_state & IS_NO_RIPV1_OUT)
|
||||
continue;
|
||||
buf.rip_vers = RIPv1;
|
||||
@ -724,10 +824,11 @@ rip_query(void)
|
||||
/* 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 {
|
||||
if (buf.rip_vers == RIPv2
|
||||
&& (ifp->int_state & IS_NO_RIPV1_OUT)) {
|
||||
type = OUT_MULTICAST;
|
||||
} else {
|
||||
type = OUT_BROADCAST;
|
||||
}
|
||||
|
||||
} else if (ifp->int_if_flags & IFF_POINTOPOINT) {
|
||||
@ -743,6 +844,6 @@ rip_query(void)
|
||||
|
||||
ifp->int_state |= IS_RIP_QUERIED;
|
||||
if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0)
|
||||
ifbad(ifp,0);
|
||||
if_sick(ifp);
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,11 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#ident "$Revision: 1.1 $"
|
||||
#ident "$Revision: 1.7 $"
|
||||
|
||||
#include "defs.h"
|
||||
#include "pathnames.h"
|
||||
@ -45,177 +45,6 @@ struct parm *parms;
|
||||
struct intnet *intnets;
|
||||
|
||||
|
||||
/* parse a set of parameters for an interface
|
||||
*/
|
||||
char * /* error message */
|
||||
parse_parms(char *line)
|
||||
{
|
||||
#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt)))
|
||||
#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str))))
|
||||
#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \
|
||||
parm.parm_int_state |= (b);}
|
||||
#define DELIMS " ,\t\n"
|
||||
struct parm parm, *parmp;
|
||||
struct intnet *intnetp;
|
||||
char *tok, *tgt, *p;
|
||||
|
||||
|
||||
/* "subnet=x.y.z.u/mask" must be alone on the line */
|
||||
if (!strncasecmp("subnet=",line,7)) {
|
||||
intnetp = (struct intnet*)malloc(sizeof(*intnetp));
|
||||
if (!getnet(&line[7], &intnetp->intnet_addr,
|
||||
&intnetp->intnet_mask)) {
|
||||
free(intnetp);
|
||||
return line;
|
||||
}
|
||||
HTONL(intnetp->intnet_addr);
|
||||
intnetp->intnet_next = intnets;
|
||||
intnets = intnetp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bzero(&parm, sizeof(parm));
|
||||
|
||||
tgt = "null";
|
||||
for (tok = strtok(line, DELIMS);
|
||||
tok != 0 && tok[0] != '\0';
|
||||
tgt = 0, tok = strtok(0,DELIMS)) {
|
||||
if (PARSE("if")) {
|
||||
if (parm.parm_name[0] != '\0'
|
||||
|| tok[3] == '\0'
|
||||
|| strlen(tok) > IFNAMSIZ+3)
|
||||
break;
|
||||
strcpy(parm.parm_name, tok+3);
|
||||
|
||||
} else if (PARSE("passwd")) {
|
||||
if (tok[7] == '\0'
|
||||
|| strlen(tok) > RIP_AUTH_PW_LEN+7)
|
||||
break;
|
||||
strcpy(parm.parm_passwd, tok+7);
|
||||
|
||||
} else if (PARS("no_ag")) {
|
||||
parm.parm_int_state |= IS_NO_AG;
|
||||
|
||||
} else if (PARS("no_super_ag")) {
|
||||
parm.parm_int_state |= IS_NO_SUPER_AG;
|
||||
|
||||
} else if (PARS("no_rip")) {
|
||||
parm.parm_int_state |= (IS_NO_RIPV1_IN
|
||||
| IS_NO_RIPV2_IN
|
||||
| IS_NO_RIPV1_OUT
|
||||
| IS_NO_RIPV2_OUT);
|
||||
|
||||
} else if (PARS("no_ripv1_in")) {
|
||||
parm.parm_int_state |= IS_NO_RIPV1_IN;
|
||||
|
||||
} else if (PARS("no_ripv2_in")) {
|
||||
parm.parm_int_state |= IS_NO_RIPV2_IN;
|
||||
|
||||
} else if (PARS("no_ripv2_out")) {
|
||||
parm.parm_int_state |= IS_NO_RIPV2_OUT;
|
||||
|
||||
} else if (PARS("ripv2_out")) {
|
||||
if (parm.parm_int_state & IS_NO_RIPV2_OUT)
|
||||
break;
|
||||
parm.parm_int_state |= IS_NO_RIPV1_OUT;
|
||||
|
||||
} else if (PARS("no_rdisc")) {
|
||||
CKF((GROUP_IS_SOL|GROUP_IS_ADV),
|
||||
IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT);
|
||||
|
||||
} else if (PARS("no_solicit")) {
|
||||
CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
|
||||
|
||||
} else if (PARS("send_solicit")) {
|
||||
CKF(GROUP_IS_SOL, IS_SOL_OUT);
|
||||
|
||||
} else if (PARS("no_rdisc_adv")) {
|
||||
CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
|
||||
|
||||
} else if (PARS("rdisc_adv")) {
|
||||
CKF(GROUP_IS_ADV, IS_ADV_OUT);
|
||||
|
||||
} else if (PARS("bcast_rdisc")) {
|
||||
parm.parm_int_state |= IS_BCAST_RDISC;
|
||||
|
||||
} else if (PARSE("rdisc_pref")) {
|
||||
if (parm.parm_rdisc_pref != 0
|
||||
|| tok[11] == '\0'
|
||||
|| (parm.parm_rdisc_pref = (int)strtol(&tok[11],
|
||||
&p,0),
|
||||
*p != '\0'))
|
||||
break;
|
||||
|
||||
} else if (PARSE("rdisc_interval")) {
|
||||
if (parm.parm_rdisc_int != 0
|
||||
|| tok[15] == '\0'
|
||||
|| (parm.parm_rdisc_int = (int)strtol(&tok[15],
|
||||
&p,0),
|
||||
*p != '\0')
|
||||
|| parm.parm_rdisc_int < MinMaxAdvertiseInterval
|
||||
|| parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
|
||||
break;
|
||||
|
||||
} else if (PARSE("fake_default")) {
|
||||
if (parm.parm_d_metric != 0
|
||||
|| tok[13] == '\0'
|
||||
|| (parm.parm_d_metric=(int)strtol(&tok[13],&p,0),
|
||||
*p != '\0')
|
||||
|| parm.parm_d_metric >= HOPCNT_INFINITY-2)
|
||||
break;
|
||||
|
||||
} else {
|
||||
tgt = tok;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tgt != 0)
|
||||
return tgt;
|
||||
|
||||
if (parm.parm_int_state & IS_NO_ADV_IN)
|
||||
parm.parm_int_state |= IS_NO_SOL_OUT;
|
||||
|
||||
/* check for duplicate specification */
|
||||
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
|
||||
if (strcmp(parm.parm_name, parmp->parm_name))
|
||||
continue;
|
||||
if (parmp->parm_a_h != (parm.parm_a_h & parmp->parm_m)
|
||||
&& parm.parm_a_h != (parmp->parm_a_h & parm.parm_m))
|
||||
continue;
|
||||
|
||||
if (strcmp(parmp->parm_passwd, parm.parm_passwd)
|
||||
|| (0 != (parm.parm_int_state & GROUP_IS_SOL)
|
||||
&& 0 != (parmp->parm_int_state & GROUP_IS_SOL)
|
||||
&& 0 != ((parm.parm_int_state ^ parmp->parm_int_state)
|
||||
&& GROUP_IS_SOL))
|
||||
|| (0 != (parm.parm_int_state & GROUP_IS_ADV)
|
||||
&& 0 != (parmp->parm_int_state & GROUP_IS_ADV)
|
||||
&& 0 != ((parm.parm_int_state ^ parmp->parm_int_state)
|
||||
&& GROUP_IS_ADV))
|
||||
|| (parm.parm_rdisc_pref != 0
|
||||
&& parmp->parm_rdisc_pref != 0
|
||||
&& parm.parm_rdisc_pref != parmp->parm_rdisc_pref)
|
||||
|| (parm.parm_rdisc_int != 0
|
||||
&& parmp->parm_rdisc_int != 0
|
||||
&& parm.parm_rdisc_int != parmp->parm_rdisc_int)
|
||||
|| (parm.parm_d_metric != 0
|
||||
&& parmp->parm_d_metric != 0
|
||||
&& parm.parm_d_metric != parmp->parm_d_metric))
|
||||
return "duplicate";
|
||||
}
|
||||
|
||||
parmp = (struct parm*)malloc(sizeof(*parmp));
|
||||
bcopy(&parm, parmp, sizeof(*parmp));
|
||||
parmp->parm_next = parms;
|
||||
parms = parmp;
|
||||
|
||||
return 0;
|
||||
#undef DELIMS
|
||||
#undef PARS
|
||||
#undef PARSE
|
||||
}
|
||||
|
||||
|
||||
/* use configured parameters
|
||||
*/
|
||||
void
|
||||
@ -223,51 +52,66 @@ get_parms(struct interface *ifp)
|
||||
{
|
||||
struct parm *parmp;
|
||||
|
||||
/* get all relevant parameters
|
||||
*/
|
||||
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
|
||||
if ((parmp->parm_a_h == (ntohl(ifp->int_addr)
|
||||
& parmp->parm_m)
|
||||
&& parmp->parm_name[0] == '\0')
|
||||
if ((parmp->parm_name[0] == '\0'
|
||||
&& on_net(ifp->int_addr,
|
||||
parmp->parm_addr_h, parmp->parm_mask))
|
||||
|| (parmp->parm_name[0] != '\0'
|
||||
&& !strcmp(ifp->int_name, parmp->parm_name))) {
|
||||
/* this group of parameters is relevant,
|
||||
* so get its settings
|
||||
*/
|
||||
ifp->int_state |= parmp->parm_int_state;
|
||||
if (parmp->parm_passwd[0] != '\0')
|
||||
bcopy(parmp->parm_passwd, ifp->int_passwd,
|
||||
sizeof(ifp->int_passwd));
|
||||
if (parmp->parm_rdisc_pref != 0)
|
||||
ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
|
||||
if (parmp->parm_rdisc_int != 0)
|
||||
ifp->int_rdisc_int = parmp->parm_rdisc_int;
|
||||
if (parmp->parm_d_metric != 0)
|
||||
ifp->int_d_metric = parmp->parm_d_metric;
|
||||
}
|
||||
}
|
||||
/* default poor-man's router discovery to a metric that will
|
||||
* be heard by old versions of routed.
|
||||
*/
|
||||
if ((ifp->int_state & IS_PM_RDISC)
|
||||
&& ifp->int_d_metric == 0)
|
||||
ifp->int_d_metric = HOPCNT_INFINITY-2;
|
||||
|
||||
if ((ifp->int_state & IS_NO_RIP_IN) == IS_NO_RIP_IN)
|
||||
if (IS_RIP_IN_OFF(ifp->int_state))
|
||||
ifp->int_state |= IS_NO_RIP_OUT;
|
||||
|
||||
if (ifp->int_rdisc_int == 0)
|
||||
ifp->int_rdisc_int = DefMaxAdvertiseInterval;
|
||||
|
||||
if ((ifp->int_state & IS_PASSIVE)
|
||||
|| (ifp->int_state & IS_REMOTE))
|
||||
ifp->int_state |= IS_NO_ADV_IN|IS_NO_SOL_OUT|IS_NO_ADV_OUT;
|
||||
|
||||
|
||||
if (!(ifp->int_state & IS_PASSIVE)) {
|
||||
if (!(ifp->int_if_flags & IFF_MULTICAST)
|
||||
&& !(ifp->int_if_flags & IFF_POINTOPOINT))
|
||||
ifp->int_state |= IS_NO_RIPV2_OUT;
|
||||
}
|
||||
|
||||
if (!(ifp->int_if_flags & IFF_MULTICAST))
|
||||
ifp->int_state |= IS_BCAST_RDISC;
|
||||
|
||||
if (ifp->int_if_flags & IFF_POINTOPOINT) {
|
||||
ifp->int_state |= IS_BCAST_RDISC;
|
||||
/* point-to-point links should be passive for the sake
|
||||
* of demand-dialing
|
||||
/* By default, point-to-point links should be passive
|
||||
* about router-discovery for the sake of demand-dialing.
|
||||
*/
|
||||
if (0 == (ifp->int_state & GROUP_IS_SOL))
|
||||
ifp->int_state |= IS_NO_SOL_OUT;
|
||||
if (0 == (ifp->int_state & GROUP_IS_ADV))
|
||||
ifp->int_state |= IS_NO_ADV_OUT;
|
||||
}
|
||||
|
||||
if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
|
||||
ifp->int_state |= IS_NO_RDISC;
|
||||
if (ifp->int_state & IS_PASSIVE)
|
||||
ifp->int_state |= (IS_NO_RIP | IS_NO_RDISC);
|
||||
if (ifp->int_state&(IS_NO_RIP|IS_NO_RDISC) == (IS_NO_RIP|IS_NO_RDISC))
|
||||
ifp->int_state |= IS_PASSIVE;
|
||||
}
|
||||
|
||||
|
||||
@ -314,53 +158,62 @@ gwkludge(void)
|
||||
if (*lptr == '\n' /* ignore null and comment lines */
|
||||
|| *lptr == '#')
|
||||
continue;
|
||||
p = lptr+strlen(lptr)-1;
|
||||
while (*p == '\n'
|
||||
|| *p == ' ')
|
||||
*p-- = '\0';
|
||||
|
||||
/* notice parameter lines */
|
||||
/* notice newfangled parameter lines
|
||||
*/
|
||||
if (strncasecmp("net", lptr, 3)
|
||||
&& strncasecmp("host", lptr, 4)) {
|
||||
p = parse_parms(lptr);
|
||||
if (p != 0)
|
||||
if (p != 0) {
|
||||
if (strcmp(p,lptr))
|
||||
msglog("bad \"%s\" in "_PATH_GATEWAYS
|
||||
" entry %s", lptr, p);
|
||||
" entry \"%s\"", lptr, p);
|
||||
else
|
||||
msglog("bad \"%s\" in "_PATH_GATEWAYS,
|
||||
lptr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
|
||||
n = sscanf(lptr, "%4s %129[^ ] gateway"
|
||||
" %64[^ / ] metric %d %8s\n",
|
||||
n = sscanf(lptr, "%4s %129[^ \t] gateway"
|
||||
" %64[^ / \t] metric %d %8s\n",
|
||||
net_host, dname, gname, &metric, qual);
|
||||
if (n != 5) {
|
||||
msglog("bad "_PATH_GATEWAYS" entry %s", lptr);
|
||||
msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
|
||||
continue;
|
||||
}
|
||||
if (metric < 0 || metric >= HOPCNT_INFINITY) {
|
||||
msglog("bad metric in "_PATH_GATEWAYS" entry %s",
|
||||
msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"",
|
||||
lptr);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(net_host, "host")) {
|
||||
if (!gethost(dname, &dst)) {
|
||||
msglog("bad host %s in "_PATH_GATEWAYS
|
||||
" entry %s", dname, lptr);
|
||||
msglog("bad host \"%s\" in "_PATH_GATEWAYS
|
||||
" entry \"%s\"", dname, lptr);
|
||||
continue;
|
||||
}
|
||||
netmask = HOST_MASK;
|
||||
} else if (!strcmp(net_host, "net")) {
|
||||
if (!getnet(dname, &dst, &netmask)) {
|
||||
msglog("bad net %s in "_PATH_GATEWAYS
|
||||
" entry %s", dname, lptr);
|
||||
msglog("bad net \"%s\" in "_PATH_GATEWAYS
|
||||
" entry \"%s\"", dname, lptr);
|
||||
continue;
|
||||
}
|
||||
HTONL(dst);
|
||||
} else {
|
||||
msglog("bad \"%s\" in "_PATH_GATEWAYS
|
||||
" entry %s", lptr);
|
||||
" entry \"%s\"", lptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!gethost(gname, &gate)) {
|
||||
msglog("bad gateway %s in "_PATH_GATEWAYS
|
||||
" entry %s", gname, lptr);
|
||||
msglog("bad gateway \"%s\" in "_PATH_GATEWAYS
|
||||
" entry \"%s\"", gname, lptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -403,34 +256,29 @@ gwkludge(void)
|
||||
}
|
||||
|
||||
} else {
|
||||
msglog("bad "_PATH_GATEWAYS" entry %s", lptr);
|
||||
msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(state & IS_EXTERNAL)) {
|
||||
/* If we are going to send packets to the gateway,
|
||||
* it must be reachable using our physical interfaces
|
||||
/* Remember to advertise the corresponding logical network.
|
||||
*/
|
||||
if (!rtfind(gate)) {
|
||||
msglog("unreachable gateway %s in "
|
||||
_PATH_GATEWAYS" entry %s",
|
||||
gname, lptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remember to advertise the corresponding logical
|
||||
* network.
|
||||
*/
|
||||
if (netmask != std_mask(dst))
|
||||
if (!(state & IS_EXTERNAL)
|
||||
&& netmask != std_mask(dst))
|
||||
state |= IS_SUBNET;
|
||||
}
|
||||
|
||||
if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
|
||||
state |= IS_NO_RDISC;
|
||||
if (state & IS_PASSIVE)
|
||||
state |= (IS_NO_RIP | IS_NO_RDISC);
|
||||
if (state & (IS_NO_RIP|IS_NO_RDISC) == (IS_NO_RIP|IS_NO_RDISC))
|
||||
state |= IS_PASSIVE;
|
||||
|
||||
parmp = (struct parm*)malloc(sizeof(*parmp));
|
||||
bzero(parmp, sizeof(*parmp));
|
||||
parmp->parm_next = parms;
|
||||
parms = parmp;
|
||||
parmp->parm_a_h = ntohl(dst);
|
||||
parmp->parm_m = -1;
|
||||
parmp->parm_addr_h = ntohl(dst);
|
||||
parmp->parm_mask = -1;
|
||||
parmp->parm_d_metric = 0;
|
||||
parmp->parm_int_state = state;
|
||||
|
||||
@ -438,8 +286,11 @@ gwkludge(void)
|
||||
* interface.
|
||||
*/
|
||||
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
|
||||
if (ifp->int_addr == dst
|
||||
&& ifp->int_mask == netmask)
|
||||
if (ifp->int_mask == netmask
|
||||
&& ((ifp->int_addr == dst
|
||||
&& netmask != HOST_MASK)
|
||||
|| (ifp->int_dstaddr == dst
|
||||
&& netmask == HOST_MASK)))
|
||||
break;
|
||||
}
|
||||
if (ifp != 0) {
|
||||
@ -478,22 +329,218 @@ gwkludge(void)
|
||||
|
||||
get_parms(ifp);
|
||||
|
||||
if (TRACEACTIONS)
|
||||
trace_if("Add", ifp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse a set of parameters for an interface
|
||||
*/
|
||||
char * /* 0 or error message */
|
||||
parse_parms(char *line)
|
||||
{
|
||||
#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt)))
|
||||
#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str))))
|
||||
#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \
|
||||
parm.parm_int_state |= (b);}
|
||||
#define DELIMS " ,\t\n"
|
||||
struct parm parm;
|
||||
struct intnet *intnetp;
|
||||
char *tok, *tgt, *p;
|
||||
|
||||
|
||||
/* "subnet=x.y.z.u/mask" must be alone on the line */
|
||||
if (!strncasecmp("subnet=",line,7)) {
|
||||
intnetp = (struct intnet*)malloc(sizeof(*intnetp));
|
||||
intnetp->intnet_metric = 1;
|
||||
if (p = strrchr(line,',')) {
|
||||
*p++ = '\0';
|
||||
intnetp->intnet_metric = (int)strtol(p,&p,0);
|
||||
if (*p != '\0'
|
||||
|| intnetp->intnet_metric <= 0
|
||||
|| intnetp->intnet_metric >= HOPCNT_INFINITY)
|
||||
return line;
|
||||
}
|
||||
if (!getnet(&line[7], &intnetp->intnet_addr,
|
||||
&intnetp->intnet_mask)
|
||||
|| intnetp->intnet_mask == HOST_MASK
|
||||
|| intnetp->intnet_addr == RIP_DEFAULT) {
|
||||
free(intnetp);
|
||||
return line;
|
||||
}
|
||||
intnetp->intnet_next = intnets;
|
||||
intnets = intnetp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bzero(&parm, sizeof(parm));
|
||||
|
||||
tgt = "null";
|
||||
for (tok = strtok(line, DELIMS);
|
||||
tok != 0 && tok[0] != '\0';
|
||||
tgt = 0, tok = strtok(0,DELIMS)) {
|
||||
if (PARSE("if")) {
|
||||
if (parm.parm_name[0] != '\0'
|
||||
|| tok[3] == '\0'
|
||||
|| strlen(tok) > IFNAMSIZ+3)
|
||||
break;
|
||||
strcpy(parm.parm_name, tok+3);
|
||||
|
||||
} else if (PARSE("passwd")) {
|
||||
if (tok[7] == '\0'
|
||||
|| strlen(tok) > RIP_AUTH_PW_LEN+7)
|
||||
break;
|
||||
strcpy(parm.parm_passwd, tok+7);
|
||||
|
||||
} else if (PARS("no_ag")) {
|
||||
parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
|
||||
|
||||
} else if (PARS("no_super_ag")) {
|
||||
parm.parm_int_state |= IS_NO_SUPER_AG;
|
||||
|
||||
} else if (PARS("no_ripv1_in")) {
|
||||
parm.parm_int_state |= IS_NO_RIPV1_IN;
|
||||
|
||||
} else if (PARS("no_ripv2_in")) {
|
||||
parm.parm_int_state |= IS_NO_RIPV2_IN;
|
||||
|
||||
} else if (PARS("ripv2_out")) {
|
||||
if (parm.parm_int_state & IS_NO_RIPV2_OUT)
|
||||
break;
|
||||
parm.parm_int_state |= IS_NO_RIPV1_OUT;
|
||||
|
||||
} else if (PARS("no_rip")) {
|
||||
parm.parm_int_state |= IS_NO_RIP;
|
||||
|
||||
} else if (PARS("no_rdisc")) {
|
||||
CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
|
||||
|
||||
} else if (PARS("no_solicit")) {
|
||||
CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
|
||||
|
||||
} else if (PARS("send_solicit")) {
|
||||
CKF(GROUP_IS_SOL, IS_SOL_OUT);
|
||||
|
||||
} else if (PARS("no_rdisc_adv")) {
|
||||
CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
|
||||
|
||||
} else if (PARS("rdisc_adv")) {
|
||||
CKF(GROUP_IS_ADV, IS_ADV_OUT);
|
||||
|
||||
} else if (PARS("bcast_rdisc")) {
|
||||
parm.parm_int_state |= IS_BCAST_RDISC;
|
||||
|
||||
} else if (PARS("passive")) {
|
||||
CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
|
||||
parm.parm_int_state |= IS_NO_RIP;
|
||||
|
||||
} else if (PARSE("rdisc_pref")) {
|
||||
if (parm.parm_rdisc_pref != 0
|
||||
|| tok[11] == '\0'
|
||||
|| (parm.parm_rdisc_pref = (int)strtol(&tok[11],
|
||||
&p,0),
|
||||
*p != '\0'))
|
||||
break;
|
||||
|
||||
} else if (PARS("pm_rdisc")) {
|
||||
parm.parm_int_state |= IS_PM_RDISC;
|
||||
|
||||
} else if (PARSE("rdisc_interval")) {
|
||||
if (parm.parm_rdisc_int != 0
|
||||
|| tok[15] == '\0'
|
||||
|| (parm.parm_rdisc_int = (int)strtol(&tok[15],
|
||||
&p,0),
|
||||
*p != '\0')
|
||||
|| parm.parm_rdisc_int < MinMaxAdvertiseInterval
|
||||
|| parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
|
||||
break;
|
||||
|
||||
} else if (PARSE("fake_default")) {
|
||||
if (parm.parm_d_metric != 0
|
||||
|| tok[13] == '\0'
|
||||
|| (parm.parm_d_metric=(int)strtol(&tok[13],&p,0),
|
||||
*p != '\0')
|
||||
|| parm.parm_d_metric > HOPCNT_INFINITY-1)
|
||||
break;
|
||||
|
||||
} else {
|
||||
tgt = tok;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tgt != 0)
|
||||
return tgt;
|
||||
|
||||
if (parm.parm_int_state & IS_NO_ADV_IN)
|
||||
parm.parm_int_state |= IS_NO_SOL_OUT;
|
||||
|
||||
if ((parm.parm_int_state & (IS_NO_RIP | IS_NO_RDISC))
|
||||
== (IS_NO_RIP | IS_NO_RDISC))
|
||||
parm.parm_int_state |= IS_PASSIVE;
|
||||
|
||||
return check_parms(&parm);
|
||||
#undef DELIMS
|
||||
#undef PARS
|
||||
#undef PARSE
|
||||
}
|
||||
|
||||
|
||||
/* check for duplicate parameter specifications */
|
||||
char * /* 0 or error message */
|
||||
check_parms(struct parm *new)
|
||||
{
|
||||
struct parm *parmp;
|
||||
|
||||
|
||||
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
|
||||
if (strcmp(new->parm_name, parmp->parm_name))
|
||||
continue;
|
||||
if (!on_net(htonl(parmp->parm_addr_h),
|
||||
new->parm_addr_h, new->parm_mask)
|
||||
&& !on_net(htonl(new->parm_addr_h),
|
||||
parmp->parm_addr_h, parmp->parm_mask))
|
||||
continue;
|
||||
|
||||
if (strcmp(parmp->parm_passwd, new->parm_passwd)
|
||||
|| (0 != (new->parm_int_state & GROUP_IS_SOL)
|
||||
&& 0 != (parmp->parm_int_state & GROUP_IS_SOL)
|
||||
&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
|
||||
&& GROUP_IS_SOL))
|
||||
|| (0 != (new->parm_int_state & GROUP_IS_ADV)
|
||||
&& 0 != (parmp->parm_int_state & GROUP_IS_ADV)
|
||||
&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
|
||||
&& GROUP_IS_ADV))
|
||||
|| (new->parm_rdisc_pref != 0
|
||||
&& parmp->parm_rdisc_pref != 0
|
||||
&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
|
||||
|| (new->parm_rdisc_int != 0
|
||||
&& parmp->parm_rdisc_int != 0
|
||||
&& new->parm_rdisc_int != parmp->parm_rdisc_int)
|
||||
|| (new->parm_d_metric != 0
|
||||
&& parmp->parm_d_metric != 0
|
||||
&& new->parm_d_metric != parmp->parm_d_metric))
|
||||
return "duplicate";
|
||||
}
|
||||
|
||||
parmp = (struct parm*)malloc(sizeof(*parmp));
|
||||
bcopy(new, parmp, sizeof(*parmp));
|
||||
parmp->parm_next = parms;
|
||||
parms = parmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* get a network number as a name or a number, with an optional "/xx"
|
||||
* netmask.
|
||||
*/
|
||||
int /* 0=bad */
|
||||
getnet(char *name,
|
||||
naddr *addr_hp,
|
||||
naddr *addrp, /* host byte order */
|
||||
naddr *maskp)
|
||||
{
|
||||
int i;
|
||||
struct netent *nentp;
|
||||
struct netent *np;
|
||||
naddr mask;
|
||||
struct in_addr in;
|
||||
char hname[MAXHOSTNAMELEN+1];
|
||||
@ -512,25 +559,34 @@ getnet(char *name,
|
||||
name = hname;
|
||||
}
|
||||
|
||||
nentp = getnetbyname(name);
|
||||
if (nentp != 0) {
|
||||
in.s_addr = (naddr)nentp->n_net;
|
||||
np = getnetbyname(name);
|
||||
if (np != 0) {
|
||||
in.s_addr = (naddr)np->n_net;
|
||||
} else if (inet_aton(name, &in) == 1) {
|
||||
NTOHL(in.s_addr);
|
||||
HTONL(in.s_addr);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mname == 0) {
|
||||
/* we cannot use the interfaces here because we have not
|
||||
* looked at them yet.
|
||||
*/
|
||||
mask = std_mask(in.s_addr);
|
||||
if ((~mask & ntohl(in.s_addr)) != 0)
|
||||
mask = HOST_MASK;
|
||||
} else {
|
||||
mask = (naddr)strtoul(mname, &p, 0);
|
||||
if (*p != '\0' || mask > 32)
|
||||
return 0;
|
||||
mask = HOST_MASK << (32-mask);
|
||||
}
|
||||
if (mask != 0 && in.s_addr == RIP_DEFAULT)
|
||||
return 0;
|
||||
if ((~mask & ntohl(in.s_addr)) != 0)
|
||||
return 0;
|
||||
|
||||
*addr_hp = in.s_addr;
|
||||
*addrp = in.s_addr;
|
||||
*maskp = mask;
|
||||
return 1;
|
||||
}
|
||||
|
@ -37,7 +37,9 @@
|
||||
|
||||
#define _PATH_GATEWAYS "/etc/gateways"
|
||||
|
||||
/* all remotely requested trace files must either start with this prefix
|
||||
/* All remotely requested trace files must either start with this prefix
|
||||
* or be the same as the tracefile specified when the daemon was started.
|
||||
* If this is a directory, routed will create log files in it. That
|
||||
* might be a security problem.
|
||||
*/
|
||||
#define _PATH_TRACE "/tmp"
|
||||
#define _PATH_TRACE "/tmp/routed.log"
|
||||
|
@ -31,11 +31,11 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#ident "$Revision: 1.1 $"
|
||||
#ident "$Revision: 1.14 $"
|
||||
|
||||
#include "defs.h"
|
||||
#include <netinet/in_systm.h>
|
||||
@ -89,8 +89,8 @@ struct dr { /* accumulated advertisements */
|
||||
} *cur_drp, drs[MAX_ADS];
|
||||
|
||||
/* adjust preference by interface metric without driving it to infinity */
|
||||
#define PREF(p, ifp) ((p) < (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \
|
||||
: (p) - ((ifp)->int_metric-1))
|
||||
#define PREF(p, ifp) ((p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \
|
||||
: (p) - ((ifp)->int_metric))
|
||||
|
||||
static void rdisc_sort(void);
|
||||
|
||||
@ -109,7 +109,7 @@ trace_rdisc(char *act,
|
||||
n_long *wp, *lim;
|
||||
|
||||
|
||||
if (ftrace == 0)
|
||||
if (!TRACEPACKETS || ftrace == 0)
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
@ -119,7 +119,7 @@ trace_rdisc(char *act,
|
||||
" from %s to %s via %s life=%d\n",
|
||||
act, naddr_ntoa(from), naddr_ntoa(to),
|
||||
ifp ? ifp->int_name : "?",
|
||||
p->ad.icmp_ad_life);
|
||||
ntohs(p->ad.icmp_ad_life));
|
||||
if (!TRACECONTENTS)
|
||||
return;
|
||||
|
||||
@ -133,7 +133,7 @@ trace_rdisc(char *act,
|
||||
(void)fputc('\n',ftrace);
|
||||
|
||||
} else {
|
||||
trace_msg("%s Router Solic. from %s to %s via %s"
|
||||
trace_act("%s Router Solic. from %s to %s via %s"
|
||||
" value=%#x\n",
|
||||
act, naddr_ntoa(from), naddr_ntoa(to),
|
||||
ifp ? ifp->int_name : "?",
|
||||
@ -173,7 +173,7 @@ set_rdisc_mg(struct interface *ifp,
|
||||
if (setsockopt(rdisc_sock, IPPROTO_IP,
|
||||
IP_DROP_MEMBERSHIP,
|
||||
&m, sizeof(m)) < 0)
|
||||
DBGERR(1,"IP_DROP_MEMBERSHIP ALLHOSTS");
|
||||
LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS");
|
||||
ifp->int_state &= ~IS_ALL_HOSTS;
|
||||
}
|
||||
|
||||
@ -181,10 +181,12 @@ set_rdisc_mg(struct interface *ifp,
|
||||
/* start listening to advertisements */
|
||||
m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
|
||||
if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&m, sizeof(m)) < 0)
|
||||
DBGERR(1,"IP_ADD_MEMBERSHIP ALLHOSTS");
|
||||
&m, sizeof(m)) < 0) {
|
||||
LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS");
|
||||
} else {
|
||||
ifp->int_state |= IS_ALL_HOSTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!supplier
|
||||
|| (ifp->int_state & IS_NO_ADV_OUT)
|
||||
@ -195,7 +197,7 @@ set_rdisc_mg(struct interface *ifp,
|
||||
if (setsockopt(rdisc_sock, IPPROTO_IP,
|
||||
IP_DROP_MEMBERSHIP,
|
||||
&m, sizeof(m)) < 0)
|
||||
DBGERR(1,"IP_DROP_MEMBERSHIP ALLROUTERS");
|
||||
LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS");
|
||||
ifp->int_state &= ~IS_ALL_ROUTERS;
|
||||
}
|
||||
|
||||
@ -203,10 +205,12 @@ set_rdisc_mg(struct interface *ifp,
|
||||
/* start hearing solicitations */
|
||||
m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP);
|
||||
if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&m, sizeof(m)) < 0)
|
||||
DBGERR(1,"IP_ADD_MEMBERSHIP ALLROUTERS");
|
||||
&m, sizeof(m)) < 0) {
|
||||
LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS");
|
||||
} else {
|
||||
ifp->int_state |= IS_ALL_ROUTERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -221,7 +225,7 @@ set_supplier(void)
|
||||
if (supplier_set)
|
||||
return;
|
||||
|
||||
trace_msg("start suppying routes\n");
|
||||
trace_act("start suppying routes\n");
|
||||
|
||||
/* Forget discovered routes.
|
||||
*/
|
||||
@ -248,6 +252,9 @@ set_supplier(void)
|
||||
ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME;
|
||||
set_rdisc_mg(ifp, 1);
|
||||
}
|
||||
|
||||
/* get rid of any redirects */
|
||||
del_redirects(0,0);
|
||||
}
|
||||
|
||||
|
||||
@ -260,8 +267,13 @@ rdisc_age(naddr bad_gate)
|
||||
struct dr *drp;
|
||||
|
||||
|
||||
if (supplier) {
|
||||
/* If only adverising, then do only that. */
|
||||
if (supplier) {
|
||||
/* if switching from client to server, get rid of old
|
||||
* default routes.
|
||||
*/
|
||||
if (cur_drp != 0)
|
||||
rdisc_sort();
|
||||
rdisc_adv();
|
||||
return;
|
||||
}
|
||||
@ -287,7 +299,7 @@ rdisc_age(naddr bad_gate)
|
||||
sec = (now.tv_sec - drp->dr_life
|
||||
+ SUPPLY_INTERVAL);
|
||||
if (drp->dr_ts > sec) {
|
||||
trace_msg("age 0.0.0.0 --> %s"
|
||||
trace_act("age 0.0.0.0 --> %s"
|
||||
" via %s\n",
|
||||
naddr_ntoa(drp->dr_gate),
|
||||
drp->dr_ifp->int_name);
|
||||
@ -309,10 +321,11 @@ rdisc_age(naddr bad_gate)
|
||||
}
|
||||
|
||||
|
||||
/* zap all routes discovered via an interface that has gone bad
|
||||
/* Zap all routes discovered via an interface that has gone bad
|
||||
* This should only be called when !(ifp->int_state & IS_ALIAS)
|
||||
*/
|
||||
void
|
||||
ifbad_rdisc(struct interface *ifp)
|
||||
if_bad_rdisc(struct interface *ifp)
|
||||
{
|
||||
struct dr *drp;
|
||||
|
||||
@ -330,7 +343,7 @@ ifbad_rdisc(struct interface *ifp)
|
||||
/* mark an interface ok for router discovering.
|
||||
*/
|
||||
void
|
||||
ifok_rdisc(struct interface *ifp)
|
||||
if_ok_rdisc(struct interface *ifp)
|
||||
{
|
||||
set_rdisc_mg(ifp, 1);
|
||||
|
||||
@ -373,7 +386,8 @@ del_rdisc(struct dr *drp)
|
||||
*/
|
||||
if (i == 0
|
||||
&& ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
|
||||
trace_msg("re-solicit routers via %s\n", ifp->int_name);
|
||||
trace_act("discovered route is bad"
|
||||
"--re-solicit routers via %s\n", ifp->int_name);
|
||||
ifp->int_rdisc_cnt = 0;
|
||||
ifp->int_rdisc_timer.tv_sec = 0;
|
||||
rdisc_sol();
|
||||
@ -390,10 +404,11 @@ rdisc_sort(void)
|
||||
struct dr *drp, *new_drp;
|
||||
struct rt_entry *rt;
|
||||
struct interface *ifp;
|
||||
time_t sec;
|
||||
u_int new_st;
|
||||
n_long new_pref;
|
||||
|
||||
|
||||
/* find the best discovered route
|
||||
/* Find the best discovered route.
|
||||
*/
|
||||
new_drp = 0;
|
||||
for (drp = drs; drp < &drs[MAX_ADS]; drp++) {
|
||||
@ -401,33 +416,14 @@ rdisc_sort(void)
|
||||
continue;
|
||||
ifp = drp->dr_ifp;
|
||||
|
||||
/* Get rid of expired discovered routes.
|
||||
* Routes received over PPP links do not die until
|
||||
* the link has been active long enough to be certain
|
||||
* we should have heard from the router.
|
||||
/* Get rid of expired discovered routers.
|
||||
*/
|
||||
if (drp->dr_ts + drp->dr_life <= now.tv_sec) {
|
||||
if (drp->dr_recv_pref == 0
|
||||
|| !ppp_noage
|
||||
|| !(ifp->int_if_flags & IFF_POINTOPOINT)
|
||||
|| !(ifp->int_state & IS_QUIET)
|
||||
|| (ifp->int_quiet_time
|
||||
+ (sec = MIN(MaxMaxAdvertiseInterval,
|
||||
drp->dr_life)) <= now.tv_sec)) {
|
||||
del_rdisc(drp);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the PPP link is quiet, keep checking
|
||||
* in case the link becomes active.
|
||||
* After the link is active, the timer on the
|
||||
* discovered route might force its deletion.
|
||||
*/
|
||||
sec += now.tv_sec+1;
|
||||
} else {
|
||||
sec = drp->dr_ts+drp->dr_life+1;
|
||||
}
|
||||
LIM_SEC(rdisc_timer, sec);
|
||||
LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1);
|
||||
|
||||
/* Update preference with possibly changed interface
|
||||
* metric.
|
||||
@ -437,14 +433,21 @@ rdisc_sort(void)
|
||||
/* Prefer the current route to prevent thrashing.
|
||||
* Prefer shorter lifetimes to speed the detection of
|
||||
* bad routers.
|
||||
* Avoid sick interfaces.
|
||||
*/
|
||||
if (new_drp == 0
|
||||
|| new_drp->dr_pref < drp->dr_pref
|
||||
|| (new_drp->dr_pref == drp->dr_pref
|
||||
|| (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK)
|
||||
&& (new_pref < drp->dr_pref
|
||||
|| (new_pref == drp->dr_pref
|
||||
&& (drp == cur_drp
|
||||
|| (new_drp != cur_drp
|
||||
&& new_drp->dr_life > drp->dr_life))))
|
||||
&& new_drp->dr_life > drp->dr_life)))))
|
||||
|| ((new_st & IS_SICK)
|
||||
&& !(drp->dr_ifp->int_state & IS_SICK))) {
|
||||
new_drp = drp;
|
||||
new_st = drp->dr_ifp->int_state;
|
||||
new_pref = drp->dr_pref;
|
||||
}
|
||||
}
|
||||
|
||||
/* switch to a better default route
|
||||
@ -455,12 +458,12 @@ rdisc_sort(void)
|
||||
/* Stop using discovered routes if they are all bad
|
||||
*/
|
||||
if (new_drp == 0) {
|
||||
trace_msg("turn off Router Discovery\n");
|
||||
trace_act("turn off Router Discovery client\n");
|
||||
rdisc_ok = 0;
|
||||
|
||||
if (rt != 0
|
||||
&& (rt->rt_state & RS_RDISC)) {
|
||||
rtchange(rt, rt->rt_state,
|
||||
rtchange(rt, rt->rt_state & ~RS_RDISC,
|
||||
rt->rt_gate, rt->rt_router,
|
||||
HOPCNT_INFINITY, 0, rt->rt_ifp,
|
||||
now.tv_sec - GARBAGE_TIME, 0);
|
||||
@ -472,16 +475,15 @@ rdisc_sort(void)
|
||||
|
||||
} else {
|
||||
if (cur_drp == 0) {
|
||||
trace_msg("turn on Router Discovery using"
|
||||
" %s via %s\n",
|
||||
trace_act("turn on Router Discovery client"
|
||||
" using %s via %s\n",
|
||||
naddr_ntoa(new_drp->dr_gate),
|
||||
new_drp->dr_ifp->int_name);
|
||||
|
||||
rdisc_ok = 1;
|
||||
rip_off();
|
||||
|
||||
} else {
|
||||
trace_msg("switch Router Discovery from"
|
||||
trace_act("switch Router Discovery from"
|
||||
" %s via %s to %s via %s\n",
|
||||
naddr_ntoa(cur_drp->dr_gate),
|
||||
cur_drp->dr_ifp->int_name,
|
||||
@ -499,6 +501,12 @@ rdisc_sort(void)
|
||||
new_drp->dr_gate, new_drp->dr_gate,
|
||||
0, 0, RS_RDISC, new_drp->dr_ifp);
|
||||
}
|
||||
|
||||
/* Now turn off RIP and delete RIP routes,
|
||||
* which might otherwise include the default
|
||||
* we just modified.
|
||||
*/
|
||||
rip_off();
|
||||
}
|
||||
|
||||
cur_drp = new_drp;
|
||||
@ -512,14 +520,13 @@ static void
|
||||
parse_ad(naddr from,
|
||||
naddr gate,
|
||||
n_long pref,
|
||||
int life,
|
||||
u_short life,
|
||||
struct interface *ifp)
|
||||
{
|
||||
static naddr bad_gate;
|
||||
struct dr *drp, *new_drp;
|
||||
|
||||
|
||||
NTOHL(gate);
|
||||
if (gate == RIP_DEFAULT
|
||||
|| !check_dst(gate)) {
|
||||
if (bad_gate != from) {
|
||||
@ -534,54 +541,78 @@ parse_ad(naddr from,
|
||||
/* ignore pointers to ourself and routes via unreachable networks
|
||||
*/
|
||||
if (ifwithaddr(gate, 1, 0) != 0) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard our own packet\n");
|
||||
trace_pkt("\tdiscard our own Router Discovery Ad\n");
|
||||
return;
|
||||
}
|
||||
if (!on_net(gate, ifp->int_net, ifp->int_mask)) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("discard packet from unreachable net\n");
|
||||
trace_pkt("\tdiscard Router Discovery Ad"
|
||||
" from unreachable net\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert preference to an unsigned value
|
||||
* and bias it by the metric of the interface.
|
||||
* and later bias it by the metric of the interface.
|
||||
*/
|
||||
pref = ntohl(pref) ^ MIN_PreferenceLevel;
|
||||
|
||||
for (new_drp = drs, drp = drs; drp < &drs[MAX_ADS]; drp++) {
|
||||
if (drp->dr_ts == 0) {
|
||||
new_drp = drp;
|
||||
continue;
|
||||
if (pref == 0 || life == 0) {
|
||||
pref = 0;
|
||||
life = 0;
|
||||
}
|
||||
|
||||
for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) {
|
||||
/* accept new info for a familiar entry
|
||||
*/
|
||||
if (drp->dr_gate == gate) {
|
||||
/* Zap an entry we are being told is kaput */
|
||||
if (pref == 0 || life == 0) {
|
||||
drp->dr_recv_pref = 0;
|
||||
drp->dr_life = 0;
|
||||
return;
|
||||
}
|
||||
new_drp = drp;
|
||||
break;
|
||||
}
|
||||
|
||||
/* look for least valueable entry */
|
||||
if (new_drp->dr_pref > drp->dr_pref)
|
||||
if (life == 0)
|
||||
continue; /* do not worry about dead ads */
|
||||
|
||||
if (drp->dr_ts == 0) {
|
||||
new_drp = drp; /* use unused entry */
|
||||
|
||||
} else if (new_drp == 0) {
|
||||
/* look for an entry worse than the new one to
|
||||
* reuse.
|
||||
*/
|
||||
if ((!(ifp->int_state & IS_SICK)
|
||||
&& (drp->dr_ifp->int_state & IS_SICK))
|
||||
|| (pref > drp->dr_pref
|
||||
&& !((ifp->int_state ^ drp->dr_ifp->int_state)
|
||||
& IS_SICK)))
|
||||
new_drp = drp;
|
||||
|
||||
} else if (new_drp->dr_ts != 0) {
|
||||
/* look for the least valueable entry to reuse
|
||||
*/
|
||||
if ((!(new_drp->dr_ifp->int_state & IS_SICK)
|
||||
&& (drp->dr_ifp->int_state & IS_SICK))
|
||||
|| (new_drp->dr_pref > drp->dr_pref
|
||||
&& !((new_drp->dr_ifp->int_state
|
||||
^ drp->dr_ifp->int_state)
|
||||
& IS_SICK)))
|
||||
new_drp = drp;
|
||||
}
|
||||
}
|
||||
|
||||
/* ignore zap of an entry we do not know about. */
|
||||
if (pref == 0 || life == 0)
|
||||
/* forget it if all of the current entries are better */
|
||||
if (new_drp == 0)
|
||||
return;
|
||||
|
||||
new_drp->dr_ifp = ifp;
|
||||
new_drp->dr_gate = gate;
|
||||
new_drp->dr_ts = now.tv_sec;
|
||||
new_drp->dr_life = ntohl(life);
|
||||
new_drp->dr_life = ntohs(life);
|
||||
new_drp->dr_recv_pref = pref;
|
||||
/* bias functional preference by metric of the interface */
|
||||
new_drp->dr_pref = PREF(pref,ifp);
|
||||
|
||||
/* after hearing a good advertisement, stop asking
|
||||
*/
|
||||
if (!(ifp->int_state & IS_SICK))
|
||||
ifp->int_rdisc_cnt = MAX_SOLICITATIONS;
|
||||
}
|
||||
|
||||
@ -638,13 +669,19 @@ send_rdisc(union ad_u *p,
|
||||
msg = "Send pt-to-pt";
|
||||
sin.sin_addr.s_addr = ifp->int_dstaddr;
|
||||
} else {
|
||||
msg = "Broadcast";
|
||||
msg = "Send broadcast";
|
||||
sin.sin_addr.s_addr = ifp->int_brdaddr;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* multicast */
|
||||
msg = "Multicast";
|
||||
msg = "Send multicast";
|
||||
if (ifp->int_state & IS_DUP) {
|
||||
trace_act("abort multicast output via %s"
|
||||
" with duplicate address\n",
|
||||
ifp->int_name);
|
||||
return;
|
||||
}
|
||||
if (rdisc_sock_mcast != ifp) {
|
||||
/* select the right interface. */
|
||||
#ifdef MCAST_PPP_BUG
|
||||
@ -660,11 +697,12 @@ send_rdisc(union ad_u *p,
|
||||
} else
|
||||
#endif
|
||||
tgt_mcast = ifp->int_addr;
|
||||
if (setsockopt(rdisc_sock,
|
||||
if (0 > setsockopt(rdisc_sock,
|
||||
IPPROTO_IP, IP_MULTICAST_IF,
|
||||
&tgt_mcast, sizeof(tgt_mcast))) {
|
||||
DBGERR(1,"setsockopt(rdisc_sock,"
|
||||
LOGERR("setsockopt(rdisc_sock,"
|
||||
"IP_MULTICAST_IF)");
|
||||
rdisc_sock_mcast = 0;
|
||||
return;
|
||||
}
|
||||
rdisc_sock_mcast = ifp;
|
||||
@ -673,19 +711,19 @@ send_rdisc(union ad_u *p,
|
||||
break;
|
||||
}
|
||||
|
||||
if (TRACEPACKETS)
|
||||
trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp,
|
||||
p, p_size);
|
||||
|
||||
if (0 > sendto(rdisc_sock, p, p_size, flags,
|
||||
(struct sockaddr *)&sin, sizeof(sin))) {
|
||||
if (ifp == 0 || !(ifp->int_state & IS_BROKE))
|
||||
msglog("sendto(%s%s%s): %s",
|
||||
ifp != 0 ? ifp->int_name : "",
|
||||
ifp != 0 ? ", " : "",
|
||||
inet_ntoa(sin.sin_addr),
|
||||
strerror(errno));
|
||||
if (ifp != 0)
|
||||
ifbad(ifp, 0);
|
||||
if_sick(ifp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -707,9 +745,7 @@ send_adv(struct interface *ifp,
|
||||
u.ad.icmp_ad_num = 1;
|
||||
u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4;
|
||||
|
||||
u.ad.icmp_ad_life = stopint ? 0 : htonl(ifp->int_rdisc_int*3);
|
||||
|
||||
u.ad.icmp_ad_life = stopint ? 0 : htonl(ifp->int_rdisc_int*3);
|
||||
u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3);
|
||||
pref = ifp->int_rdisc_pref ^ MIN_PreferenceLevel;
|
||||
pref = PREF(pref, ifp) ^ MIN_PreferenceLevel;
|
||||
u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(pref);
|
||||
@ -741,8 +777,8 @@ rdisc_adv(void)
|
||||
|
||||
if (!timercmp(&ifp->int_rdisc_timer, &now, >)
|
||||
|| stopint) {
|
||||
send_adv(ifp, INADDR_ALLHOSTS_GROUP,
|
||||
(ifp->int_if_flags&IS_BCAST_RDISC) ? 1 : 2);
|
||||
send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP),
|
||||
(ifp->int_state&IS_BCAST_RDISC) ? 1 : 2);
|
||||
ifp->int_rdisc_cnt++;
|
||||
|
||||
intvl_random(&ifp->int_rdisc_timer,
|
||||
@ -788,9 +824,8 @@ rdisc_sol(void)
|
||||
u.so.icmp_cksum = in_cksum((u_short*)&u.so,
|
||||
sizeof(u.so));
|
||||
send_rdisc(&u, sizeof(u.so), ifp,
|
||||
INADDR_ALLROUTERS_GROUP,
|
||||
((ifp->int_if_flags & IS_BCAST_RDISC)
|
||||
? 1 : 2));
|
||||
htonl(INADDR_ALLROUTERS_GROUP),
|
||||
((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2));
|
||||
|
||||
if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
|
||||
continue;
|
||||
@ -833,19 +868,17 @@ ck_icmp(char *act,
|
||||
}
|
||||
|
||||
if (p->icmp.icmp_code != 0) {
|
||||
if (TRACEPACKETS)
|
||||
msglog("unrecognized ICMP Router"
|
||||
trace_pkt("unrecognized ICMP Router"
|
||||
" %s code=%d from %s to %s\n",
|
||||
type, p->icmp.icmp_code,
|
||||
naddr_ntoa(from), naddr_ntoa(to));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (TRACEPACKETS)
|
||||
trace_rdisc(act, from, to, ifp, p, len);
|
||||
|
||||
if (ifp == 0 && TRACEPACKETS)
|
||||
msglog("unknown interface for router-discovery %s"
|
||||
if (ifp == 0)
|
||||
trace_pkt("unknown interface for router-discovery %s"
|
||||
" from %s to %s",
|
||||
type, naddr_ntoa(from), naddr_ntoa(to));
|
||||
|
||||
@ -897,7 +930,7 @@ read_d(void)
|
||||
if (ifp == 0)
|
||||
continue;
|
||||
if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) {
|
||||
trace_msg("\tdiscard our own packet\n");
|
||||
trace_pkt("\tdiscard our own Router Discovery msg\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -914,8 +947,7 @@ read_d(void)
|
||||
continue;
|
||||
}
|
||||
if (p->ad.icmp_ad_num == 0) {
|
||||
if (TRACEPACKETS)
|
||||
trace_msg("\tempty?\n");
|
||||
trace_pkt("\tempty?\n");
|
||||
continue;
|
||||
}
|
||||
if (cc != (sizeof(p->ad) - sizeof(p->ad.icmp_ad_info)
|
||||
@ -938,7 +970,7 @@ read_d(void)
|
||||
for (n = 0; n < p->ad.icmp_ad_num; n++) {
|
||||
parse_ad(from.sin_addr.s_addr,
|
||||
wp[0], wp[1],
|
||||
p->ad.icmp_ad_life,
|
||||
ntohs(p->ad.icmp_ad_life),
|
||||
ifp);
|
||||
wp += p->ad.icmp_ad_asize;
|
||||
}
|
||||
|
@ -31,12 +31,12 @@
|
||||
.\"
|
||||
.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd March 1, 1996
|
||||
.Dd June 1, 1996
|
||||
.Dt ROUTED 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm routed
|
||||
.Nd network routing daemon
|
||||
.Nd network RIP and router discovery routing daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl sqdghmpAt
|
||||
@ -54,8 +54,7 @@ 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.
|
||||
The RIPv1 protocol is based on the reference 4.3BSD daemon.
|
||||
.Pp
|
||||
It listens on the
|
||||
.Xr udp 4
|
||||
@ -65,7 +64,7 @@ service (see
|
||||
.Xr services 5 )
|
||||
for Routing Information Protocol packets.
|
||||
It also sends and receives multicast Router Discovery ICMP messages.
|
||||
If the host is an router,
|
||||
If the host is a router,
|
||||
.Nm
|
||||
periodically supplies copies
|
||||
of its routing tables to any directly connected hosts and networks.
|
||||
@ -116,8 +115,8 @@ Advertised metrics reflect the metric associated with interface
|
||||
so setting the metric on an interface
|
||||
is an effective way to steer traffic.
|
||||
.Pp
|
||||
Responses do not contain routes with a first hop on the resquesting
|
||||
network to implement
|
||||
Responses do not contain routes with a first hop on the requesting
|
||||
network to implement in part
|
||||
.Em split-horizon .
|
||||
Requests from query programs
|
||||
such as
|
||||
@ -157,7 +156,7 @@ 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
|
||||
of ICMP Redirect messages are deleted after a while to minimize
|
||||
.Em black-holes .
|
||||
When a TCP connection suffers a timeout,
|
||||
the kernel tells
|
||||
@ -170,7 +169,7 @@ age of any relevant Router Discovery Protocol default routes.
|
||||
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 that support
|
||||
These RIP responses are sent to the broadcast address on nets that support
|
||||
broadcasting,
|
||||
to the destination address on point-to-point links, and to the router's
|
||||
own address on other networks.
|
||||
@ -198,6 +197,37 @@ It tracks several advertising routers to speed recovery when the
|
||||
currently chosen router dies.
|
||||
If all discovered routers disappear,
|
||||
the daemon resumes listening to RIP responses.
|
||||
.Pp
|
||||
While using Router Discovery (which happens by default when
|
||||
the system has a single network interface and a Router Discover Advertisement
|
||||
is received), there is a single default route and a variable number of
|
||||
redirected host routes in the kernel table.
|
||||
.Pp
|
||||
The Router Discover standard requires that advertisements
|
||||
have a default "lifetime" of 30 minutes. That means should
|
||||
something happen, a client can be without a good route for
|
||||
30 minutes. It is a good idea to reduce the default to 45
|
||||
seconds using
|
||||
.Fl P Cm rdisc_interval=45
|
||||
on the command line or
|
||||
.Cm rdisc_interval=45
|
||||
in the
|
||||
.Pa /etc/gateways
|
||||
file.
|
||||
.Pp
|
||||
While using Router Discovery (which happens by default when
|
||||
the system has a single network interface and a Router Discover Advertisement
|
||||
is received), there is a single default route and a variable number of
|
||||
redirected host routes in the kernel table.
|
||||
.Pp
|
||||
See the
|
||||
.Cm pm_rdisc
|
||||
facility described below to support "legacy" systems
|
||||
that can handle neither RIPv2 nor Router Discovery.
|
||||
.Pp
|
||||
By default, neither Router Discovery advertisements nor solicications
|
||||
are sent over point to point links (e.g. PPP).
|
||||
|
||||
.Pp
|
||||
Options supported by
|
||||
.Nm routed :
|
||||
@ -219,9 +249,25 @@ This option is meant for interactive use.
|
||||
.It Fl g
|
||||
This flag is used on internetwork routers to offer a route
|
||||
to the "default" destination.
|
||||
It is equivalent to
|
||||
.Fl F
|
||||
.Cm 0/0,1
|
||||
and is present mostly for historical reasons.
|
||||
A better choice is
|
||||
.Fl P Cm pm_rdisc
|
||||
on the command line or
|
||||
.CM pm_rdisc in the
|
||||
.Pa /etc/gateways
|
||||
file.
|
||||
since a larger metric
|
||||
will be used, reducing the spread of the potentially dangerous
|
||||
default route.
|
||||
This is typically used on a gateway to the Internet,
|
||||
or on a gateway that uses another routing protocol whose routes
|
||||
are not reported to other local routers.
|
||||
Notice that because a metric of 1 is used, this feature is
|
||||
dangerous. It is more commonly accidently used to create chaos with routing
|
||||
loop than to solve problems.
|
||||
.It Fl h
|
||||
This causes host or point-to-point routes to not be advertised,
|
||||
provided there is a network route going the same direction.
|
||||
@ -242,20 +288,16 @@ The
|
||||
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
|
||||
This option is required for conformance with RFC 1723.
|
||||
However, it makes no sense and breaks using RIP as a discovery protocol
|
||||
to ignore all RIPv2 packets that carry authentication when this machine
|
||||
does not care about authentication.
|
||||
.It Fl T Ar tracefile
|
||||
increases the debugging level to at least 1 and
|
||||
causes debugging information to be appended to the file.
|
||||
causes debugging information to be appended to the trace file.
|
||||
.It Fl t
|
||||
increases the debugging level, which causes more information to be logged
|
||||
on the tracefile specified with
|
||||
@ -266,9 +308,11 @@ with the
|
||||
.Em SIGUSR1
|
||||
or
|
||||
.Em SIGUSR2
|
||||
signals.
|
||||
signals or with the
|
||||
.Cm rtquery
|
||||
command.
|
||||
.It Fl F Ar net[/mask][,metric]
|
||||
minimize routes in transmissions to network
|
||||
minimize routes in transmissions via interfaces with addresses that match
|
||||
.Em net/mask ,
|
||||
and synthesizes a default route to this machine with the
|
||||
.Em metric .
|
||||
@ -279,6 +323,13 @@ If
|
||||
.Em metric
|
||||
is absent, a value of 14 is assumed to limit
|
||||
the spread of the "fake" default route.
|
||||
|
||||
This is a dangerous feature that when used carelessly can cause routing
|
||||
loops.
|
||||
Notice also that more than one interface can match the specified network
|
||||
number and mask.
|
||||
See also
|
||||
.Fl g .
|
||||
.It Fl P Ar parms
|
||||
is equivalent to adding the parameter
|
||||
line
|
||||
@ -327,8 +378,8 @@ 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
|
||||
gateway.
|
||||
If no responses are received, the associated route is deleted from
|
||||
the kernel table and RIP responses advertised via other interfaces.
|
||||
If the distant gateway resumes sending RIP responses, the associated
|
||||
route is restored.
|
||||
@ -419,49 +470,68 @@ One of the keywords
|
||||
or
|
||||
.Cm external
|
||||
must be present to indicate whether the gateway should be treated as
|
||||
.Em passive
|
||||
.Cm passive
|
||||
or
|
||||
.Em active
|
||||
.Cm active
|
||||
(as described above),
|
||||
or whether the gateway is
|
||||
.Em external
|
||||
.Cm external
|
||||
to the scope of the RIP protocol.
|
||||
.Pp
|
||||
Lines that start with neither "net" nor "host" must consist of one
|
||||
or more of the following parameter settings:
|
||||
or more of the following parameter settings, separated by commas or
|
||||
blanks:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm if Ns \&= Ns Ar ifname
|
||||
indicates that the other parameters on the line apply to the interface
|
||||
name
|
||||
.Ar ifname .
|
||||
.It Cm subnet Ns \&= Ns Ar nname[/mask]
|
||||
causes other routes to be aggregated as if a compatible route to
|
||||
Ar nname/mask
|
||||
had been received.
|
||||
.It Cm subnet Ns \&= Ns Ar nname[/mask][,metric]
|
||||
advertises a route to network
|
||||
.AR nname
|
||||
with mask
|
||||
.AR mask
|
||||
and the supplied metric (default 1).
|
||||
This is useful for filling "holes" in CIDR allocations.
|
||||
This parameter must appear by itself on a line.
|
||||
.Pp
|
||||
Do not use this feature unless necessary. It is dangerous.
|
||||
.It Cm passwd Ns \&= Ns Ar XXX
|
||||
specifies a RIPv2 password that will be included on all RIPv2
|
||||
responses sent and checked on all RIPv2 responses received.
|
||||
The password must not contain any blanks, tab characters, commas
|
||||
or '#' characters.
|
||||
.It Cm no_ag
|
||||
turns off aggregation of subnets in RIPv1 and RIPv2 responses.
|
||||
.It Cm no_super_ag
|
||||
turns off aggregation of networks into supernets in RIPv2 responses.
|
||||
.It Cm passive
|
||||
is equivalent
|
||||
.Cm no_rip Cm no_rdisc .
|
||||
.It Cm no_rip
|
||||
disables all RIP processing on the specified interface.
|
||||
If no interfaces are allowed to process RIP packets,
|
||||
.Nm
|
||||
acts purely as a router discovery daemon.
|
||||
.Ar " No_rip "
|
||||
.Cm No_rip
|
||||
is equivalent to
|
||||
.Ar " no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out ."
|
||||
.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out .
|
||||
|
||||
Note that turning off RIP without explicitly turning on router
|
||||
discovery advertisements with
|
||||
.Cm rdisc_adv
|
||||
or
|
||||
.Fl s
|
||||
causes
|
||||
.Nm routed
|
||||
to act as a client router discovery daemon, not adveritising.
|
||||
.It Cm no_ripv1_in
|
||||
causes RIPv1 received responses to be ignored.
|
||||
.It Cm no_ripv2_in
|
||||
causes RIPv2 received responses to be ignored.
|
||||
.It Cm ripv2_out
|
||||
disables the RIPv2 responses that are otherwise multicast containing
|
||||
information that cannot be sent in RIPv2 packets.
|
||||
turns off RIPv1 output and causes RIPv2 advertisements to be
|
||||
multicast when possible.
|
||||
.It Cm no_rdisc
|
||||
disables the Internet Router Discovery Protocol.
|
||||
.It Cm no_solicit
|
||||
@ -488,9 +558,24 @@ 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.
|
||||
with the network and mask coming from the sepcified interface.
|
||||
.It Cm pm_rdisc
|
||||
is similar to
|
||||
.Cm fake_default .
|
||||
When RIPv2 routes are multicast, so that RIPv1 listeners cannot
|
||||
receive them, this feature causes a RIPv1 default route to be
|
||||
broadcast to RIPv1 listeners.
|
||||
Unless modified with
|
||||
.Cm fake_default ,
|
||||
the default route is broadcast with a metric of 14.
|
||||
That serves as a "poor man's router discovery" protocol.
|
||||
.El
|
||||
.Pp
|
||||
Note that the netmask associated with point-to-point links (such as SLIP
|
||||
or PPP, with the IFF_POINTOPOINT flag) is used by
|
||||
.Nm routed
|
||||
to infer the netmask used by the remote system when RIPv1 is used.
|
||||
.Pp
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/gateways -compact
|
||||
.It Pa /etc/gateways
|
||||
|
@ -3,4 +3,5 @@
|
||||
PROG= rtquery
|
||||
MAN8= rtquery.8
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,4 +1,4 @@
|
||||
.Dd April 9, 1996
|
||||
.Dd June 1, 1996
|
||||
.Dt RTQUERY 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
@ -7,7 +7,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl np1
|
||||
.Op Fl 1 Ar timeout
|
||||
.Op Fl w Ar timeout
|
||||
.Op Fl r Ar addr
|
||||
.Ar host ...
|
||||
.Sh DESCRIPTION
|
||||
@ -29,22 +29,26 @@ by default uses the
|
||||
.Em request
|
||||
command.
|
||||
When the
|
||||
.B \-p
|
||||
.Ar -p
|
||||
option is specified,
|
||||
.Nm rtquery
|
||||
uses the
|
||||
.Em poll
|
||||
command, which is an
|
||||
undocumented extension to the RIP specification supported by
|
||||
.IR gated (1M).
|
||||
When querying
|
||||
.IR gated (1M),
|
||||
the
|
||||
.I poll
|
||||
command, an
|
||||
undocumented extension to the RIP protocol supported by
|
||||
.Xr gated 8 .
|
||||
When querying gated, the
|
||||
.Em poll
|
||||
command is preferred over the
|
||||
.I request
|
||||
.I Request
|
||||
command because the response is not subject to Split Horizon and/or
|
||||
Poisioned Reverse.
|
||||
Poisoned Reverse, and because some versions of gated do not answer
|
||||
the Request command. Routed does not answer the Poll command, but
|
||||
recognizes Requests coming from rtquery and so answers completely.
|
||||
.Pp
|
||||
.Em Rtquery
|
||||
is also used to turn tracing on or off in
|
||||
.Em routed .
|
||||
.Pp
|
||||
Options supported by
|
||||
.Nm rtquery :
|
||||
@ -57,10 +61,10 @@ The
|
||||
option displays only the numeric network and host numbers.
|
||||
.It Fl p
|
||||
Uses the
|
||||
.Em poll
|
||||
.Em Poll
|
||||
command to request full routing information from
|
||||
.Xr gated 8 ,
|
||||
This is an undocumented extension supported only by
|
||||
This is an undocumented extension RIP protocol supported only by
|
||||
.Xr gated 8 .
|
||||
.It Fl 1
|
||||
query using RIP version 1 instead of RIP version 2.
|
||||
@ -69,10 +73,28 @@ changes the delay for an answer from each host.
|
||||
By default, each host is given 15 seconds to respond.
|
||||
.It Fl r Ar addr
|
||||
ask about the route to destination
|
||||
.Em parms
|
||||
.Em addr .
|
||||
.It Fl t Ar op
|
||||
change tracing, where
|
||||
.Em op
|
||||
is one of the following.
|
||||
Requests from processes not running with UID 0 or on distant networks
|
||||
are generally ignored.
|
||||
.El
|
||||
.Bl -tag -width Ds -offset indent-two
|
||||
.It Em on=filename
|
||||
turn tracing on into the specified file. That file must usually
|
||||
have been specified when the daemon was started or be the same
|
||||
as a fixed name, often
|
||||
.Pa /tmp/routed.log .
|
||||
.It Em more
|
||||
increases the debugging level.
|
||||
.It Em off
|
||||
turns off tracing.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr routed 8,
|
||||
.Xr gated 8,
|
||||
.Xr routed 8 ,
|
||||
.Xr gated 8 .
|
||||
.br
|
||||
RFC\ 1058 - Routing Information Protocol, RIPv1
|
||||
.br
|
||||
|
@ -31,13 +31,11 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1982, 1986, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
@ -71,24 +69,33 @@ int s;
|
||||
|
||||
char *pgmname;
|
||||
|
||||
union pkt_buf {
|
||||
char packet[MAXPACKETSIZE+4096];
|
||||
union {
|
||||
struct rip rip;
|
||||
} msg_buf;
|
||||
#define MSG msg_buf.rip
|
||||
#define MSG_LIM ((struct rip*)(&msg_buf.packet[MAXPACKETSIZE \
|
||||
- sizeof(struct netinfo)]))
|
||||
char packet[MAXPACKETSIZE+MAXPATHLEN];
|
||||
} omsg_buf;
|
||||
#define OMSG omsg_buf.rip
|
||||
int omsg_len = sizeof(struct rip);
|
||||
|
||||
union {
|
||||
struct rip rip;
|
||||
char packet[MAXPACKETSIZE+1024];
|
||||
} imsg_buf;
|
||||
#define IMSG imsg_buf.rip
|
||||
|
||||
int nflag; /* numbers, no names */
|
||||
int pflag; /* play the `gated` game */
|
||||
int ripv2 = 1; /* use RIP version 2 */
|
||||
int wtime = WTIME;
|
||||
int rflag; /* 1=ask about a particular route */
|
||||
int trace;
|
||||
int not_trace;
|
||||
|
||||
struct timeval start; /* when query sent */
|
||||
struct timeval sent; /* when query sent */
|
||||
|
||||
static void rip_input(struct sockaddr_in*, int);
|
||||
static int query(char *, struct netinfo *);
|
||||
static int out(char *);
|
||||
static void trace_loop(char *argv[]);
|
||||
static void query_loop(char *argv[], int);
|
||||
static int getnet(char *, struct netinfo *);
|
||||
static u_int std_mask(u_int);
|
||||
|
||||
@ -97,67 +104,120 @@ int
|
||||
main(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char *p;
|
||||
struct seen {
|
||||
struct seen *next;
|
||||
struct in_addr addr;
|
||||
} *seen, *sp;
|
||||
int answered = 0;
|
||||
int ch, cc, bsize;
|
||||
fd_set bits;
|
||||
struct timeval now, delay;
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
struct netinfo rt;
|
||||
int ch, bsize;
|
||||
char *p, *options, *value;
|
||||
|
||||
|
||||
bzero(&rt, sizeof(rt));
|
||||
OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
|
||||
OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
|
||||
OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
|
||||
|
||||
pgmname = argv[0];
|
||||
while ((ch = getopt(argc, argv, "np1w:r:")) != EOF)
|
||||
while ((ch = getopt(argc, argv, "np1w:r:t:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
not_trace = 1;
|
||||
nflag = 1;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
not_trace = 1;
|
||||
pflag = 1;
|
||||
break;
|
||||
|
||||
case '1':
|
||||
ripv2 = 0;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
not_trace = 1;
|
||||
wtime = (int)strtoul(optarg, &p, 0);
|
||||
if (*p != '\0'
|
||||
|| wtime <= 0)
|
||||
goto usage;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
not_trace = 1;
|
||||
if (rflag)
|
||||
goto usage;
|
||||
rflag = getnet(optarg, &rt);
|
||||
rflag = getnet(optarg, &OMSG.rip_nets[0]);
|
||||
if (!rflag) {
|
||||
struct hostent *hp = gethostbyname(optarg);
|
||||
if (hp == 0) {
|
||||
fprintf(stderr, "%s: %s:",
|
||||
pgmname, optarg);
|
||||
herror(0);
|
||||
exit(1);
|
||||
}
|
||||
bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst,
|
||||
sizeof(OMSG.rip_nets[0].n_dst));
|
||||
OMSG.rip_nets[0].n_family = AF_INET;
|
||||
OMSG.rip_nets[0].n_mask = -1;
|
||||
rflag = 1;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
|
||||
case 't':
|
||||
trace = 1;
|
||||
options = optarg;
|
||||
while (*options != '\0') {
|
||||
char *traceopts[] = {
|
||||
# define TRACE_ON 0
|
||||
"on",
|
||||
# define TRACE_MORE 1
|
||||
"more",
|
||||
# define TRACE_OFF 2
|
||||
"off",
|
||||
0
|
||||
};
|
||||
switch (getsubopt(&options,traceopts,&value)) {
|
||||
case TRACE_ON:
|
||||
OMSG.rip_cmd = RIPCMD_TRACEON;
|
||||
if (!value
|
||||
|| strlen(value) > MAXPATHLEN)
|
||||
goto usage;
|
||||
strcpy(OMSG.rip_tracefile, value);
|
||||
omsg_len += (strlen(value)
|
||||
- sizeof(OMSG.ripun));
|
||||
break;
|
||||
case TRACE_MORE:
|
||||
if (value)
|
||||
goto usage;
|
||||
OMSG.rip_cmd = RIPCMD_TRACEON;
|
||||
OMSG.rip_tracefile[0] = '\0';
|
||||
break;
|
||||
case TRACE_OFF:
|
||||
if (value)
|
||||
goto usage;
|
||||
OMSG.rip_cmd = RIPCMD_TRACEOFF;
|
||||
OMSG.rip_tracefile[0] = '\0';
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
if (argc == 0) {
|
||||
usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n");
|
||||
if ((not_trace && trace) || argc == 0) {
|
||||
usage: fprintf(stderr, "%s: [-np1v] [-r tgt_rt] [-w wtime]"
|
||||
" host1 [host2 ...]\n"
|
||||
"or\t-t {on=filename|more|off} host1 host2 ...\n",
|
||||
pgmname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!rflag) {
|
||||
rt.n_dst = RIP_DEFAULT;
|
||||
rt.n_family = RIP_AF_UNSPEC;
|
||||
rt.n_metric = htonl(HOPCNT_INFINITY);
|
||||
}
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* be prepared to receive a lot of routes */
|
||||
for (bsize = 127*1024; ; bsize -= 1024) {
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
|
||||
&bsize, sizeof(bsize)) == 0)
|
||||
@ -168,10 +228,89 @@ usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* ask the first host */
|
||||
if (trace)
|
||||
trace_loop(argv);
|
||||
else
|
||||
query_loop(argv, argc);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
/* tell the target hosts about tracing
|
||||
*/
|
||||
static void
|
||||
trace_loop(char *argv[])
|
||||
{
|
||||
struct sockaddr_in myaddr;
|
||||
int res;
|
||||
|
||||
if (geteuid() != 0) {
|
||||
(void)fprintf(stderr, "-t requires UID 0\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ripv2) {
|
||||
OMSG.rip_vers = RIPv2;
|
||||
} else {
|
||||
OMSG.rip_vers = RIPv1;
|
||||
}
|
||||
|
||||
bzero(&myaddr, sizeof(myaddr));
|
||||
myaddr.sin_family = AF_INET;
|
||||
#ifdef _HAVE_SIN_LEN
|
||||
myaddr.sin_len = sizeof(myaddr);
|
||||
#endif
|
||||
myaddr.sin_port = htons(IPPORT_RESERVED-1);
|
||||
while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
|
||||
if (errno != EADDRINUSE
|
||||
|| myaddr.sin_port == 0) {
|
||||
perror("bind");
|
||||
exit(2);
|
||||
}
|
||||
myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1);
|
||||
}
|
||||
|
||||
res = 1;
|
||||
while (*argv != 0) {
|
||||
if (out(*argv++) <= 0)
|
||||
res = 0;
|
||||
}
|
||||
exit(res);
|
||||
}
|
||||
|
||||
|
||||
/* query all of the listed hosts
|
||||
*/
|
||||
static void
|
||||
query_loop(char *argv[], int argc)
|
||||
{
|
||||
struct seen {
|
||||
struct seen *next;
|
||||
struct in_addr addr;
|
||||
} *seen, *sp;
|
||||
int answered = 0;
|
||||
int cc;
|
||||
fd_set bits;
|
||||
struct timeval now, delay;
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
|
||||
|
||||
OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
|
||||
if (ripv2) {
|
||||
OMSG.rip_vers = RIPv2;
|
||||
} else {
|
||||
OMSG.rip_vers = RIPv1;
|
||||
OMSG.rip_nets[0].n_mask = 0;
|
||||
}
|
||||
|
||||
/* ask the first (valid) host */
|
||||
seen = 0;
|
||||
while (0 > query(*argv++, &rt) && *argv != 0)
|
||||
while (0 > out(*argv++)) {
|
||||
if (*argv == 0)
|
||||
exit(-1);
|
||||
answered++;
|
||||
}
|
||||
|
||||
FD_ZERO(&bits);
|
||||
for (;;) {
|
||||
@ -181,8 +320,8 @@ usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n");
|
||||
cc = select(s+1, &bits, 0,0, &delay);
|
||||
if (cc > 0) {
|
||||
fromlen = sizeof(from);
|
||||
cc = recvfrom(s, msg_buf.packet,
|
||||
sizeof(msg_buf.packet), 0,
|
||||
cc = recvfrom(s, imsg_buf.packet,
|
||||
sizeof(imsg_buf.packet), 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
if (cc < 0) {
|
||||
perror("recvfrom");
|
||||
@ -220,7 +359,7 @@ usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n");
|
||||
/* After a pause in responses, probe another host.
|
||||
* This reduces the intermingling of answers.
|
||||
*/
|
||||
while (*argv != 0 && 0 > query(*argv++, &rt))
|
||||
while (*argv != 0 && 0 > out(*argv++))
|
||||
answered++;
|
||||
|
||||
/* continue until no more packets arrive
|
||||
@ -235,28 +374,25 @@ usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n");
|
||||
perror("gettimeofday(now)");
|
||||
exit(1);
|
||||
}
|
||||
if (start.tv_sec + wtime <= now.tv_sec)
|
||||
if (sent.tv_sec + wtime <= now.tv_sec)
|
||||
break;
|
||||
}
|
||||
|
||||
/* fail if there was no answer */
|
||||
exit (answered >= argc ? 0 : 1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Poll one host.
|
||||
/* sent do one host
|
||||
*/
|
||||
static int
|
||||
query(char *host,
|
||||
struct netinfo *rt)
|
||||
out(char *host)
|
||||
{
|
||||
struct sockaddr_in router;
|
||||
struct hostent *hp;
|
||||
|
||||
if (gettimeofday(&start, 0) < 0) {
|
||||
perror("gettimeofday(start)");
|
||||
if (gettimeofday(&sent, 0) < 0) {
|
||||
perror("gettimeofday(sent)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -265,29 +401,17 @@ query(char *host,
|
||||
#ifdef _HAVE_SIN_LEN
|
||||
router.sin_len = sizeof(router);
|
||||
#endif
|
||||
router.sin_addr.s_addr = inet_addr(host);
|
||||
if (router.sin_addr.s_addr == -1) {
|
||||
if (!inet_aton(host, &router.sin_addr)) {
|
||||
hp = gethostbyname(host);
|
||||
if (hp == 0) {
|
||||
fprintf(stderr,"%s: %s:", pgmname, host);
|
||||
herror(0);
|
||||
herror(host);
|
||||
return -1;
|
||||
}
|
||||
bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
|
||||
bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr));
|
||||
}
|
||||
|
||||
router.sin_port = htons(RIP_PORT);
|
||||
|
||||
MSG.rip_cmd = (pflag)? RIPCMD_POLL : RIPCMD_REQUEST;
|
||||
MSG.rip_nets[0] = *rt;
|
||||
if (ripv2) {
|
||||
MSG.rip_vers = RIPv2;
|
||||
} else {
|
||||
MSG.rip_vers = RIPv1;
|
||||
MSG.rip_nets[0].n_mask = 0;
|
||||
}
|
||||
|
||||
if (sendto(s, msg_buf.packet, sizeof(struct rip), 0,
|
||||
if (sendto(s, &omsg_buf, omsg_len, 0,
|
||||
(struct sockaddr *)&router, sizeof(router)) < 0) {
|
||||
perror(host);
|
||||
return -1;
|
||||
@ -329,18 +453,18 @@ rip_input(struct sockaddr_in *from,
|
||||
inet_ntoa(from->sin_addr));
|
||||
}
|
||||
}
|
||||
if (MSG.rip_cmd != RIPCMD_RESPONSE) {
|
||||
printf("\n unexpected response type %d\n", MSG.rip_cmd);
|
||||
if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
|
||||
printf("\n unexpected response type %d\n", IMSG.rip_cmd);
|
||||
return;
|
||||
}
|
||||
printf(" RIPv%d%s %d bytes\n", MSG.rip_vers,
|
||||
(MSG.rip_vers != RIPv1 && MSG.rip_vers != RIPv2) ? " ?" : "",
|
||||
printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers,
|
||||
(IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
|
||||
size);
|
||||
if (size > MAXPACKETSIZE) {
|
||||
if (size > sizeof(msg_buf) - sizeof(*n)) {
|
||||
if (size > sizeof(imsg_buf) - sizeof(*n)) {
|
||||
printf(" at least %d bytes too long\n",
|
||||
size-MAXPACKETSIZE);
|
||||
size = sizeof(msg_buf) - sizeof(*n);
|
||||
size = sizeof(imsg_buf) - sizeof(*n);
|
||||
} else {
|
||||
printf(" %d bytes too long\n",
|
||||
size-MAXPACKETSIZE);
|
||||
@ -349,7 +473,7 @@ rip_input(struct sockaddr_in *from,
|
||||
printf(" response of bad length=%d\n", size);
|
||||
}
|
||||
|
||||
n = MSG.rip_nets;
|
||||
n = IMSG.rip_nets;
|
||||
lim = (struct netinfo *)((char*)n + size) - 1;
|
||||
for (; n <= lim; n++) {
|
||||
name = "";
|
||||
@ -361,7 +485,7 @@ rip_input(struct sockaddr_in *from,
|
||||
dmask = mask & -mask;
|
||||
if (mask != 0) {
|
||||
sp = &net_buf[strlen(net_buf)];
|
||||
if (MSG.rip_vers == RIPv1) {
|
||||
if (IMSG.rip_vers == RIPv1) {
|
||||
(void)sprintf(sp," mask=%#x ? ",mask);
|
||||
mask = 0;
|
||||
} else if (mask + dmask == 0) {
|
||||
@ -391,14 +515,16 @@ rip_input(struct sockaddr_in *from,
|
||||
* good guess.
|
||||
*/
|
||||
if ((in.s_addr & ~mask) == 0) {
|
||||
np = getnetbyaddr(in.s_addr, AF_INET);
|
||||
np = getnetbyaddr((long)in.s_addr,
|
||||
AF_INET);
|
||||
if (np != 0)
|
||||
name = np->n_name;
|
||||
else if (in.s_addr == 0)
|
||||
name = "default";
|
||||
}
|
||||
if (name[0] == '\0'
|
||||
&& (in.s_addr & ~mask) != 0) {
|
||||
&& ((in.s_addr & ~mask) != 0
|
||||
|| mask == 0xffffffff)) {
|
||||
hp = gethostbyaddr((char*)&in,
|
||||
sizeof(in),
|
||||
AF_INET);
|
||||
@ -425,7 +551,7 @@ rip_input(struct sockaddr_in *from,
|
||||
(char)n->n_dst);
|
||||
}
|
||||
|
||||
(void)printf(" %-18s metric %2d %8s",
|
||||
(void)printf(" %-18s metric %2d %-10s",
|
||||
net_buf, ntohl(n->n_metric), name);
|
||||
|
||||
if (n->n_nhop != 0) {
|
||||
@ -437,11 +563,11 @@ rip_input(struct sockaddr_in *from,
|
||||
AF_INET);
|
||||
(void)printf(" nhop=%-15s%s",
|
||||
(hp != 0) ? hp->h_name : inet_ntoa(in),
|
||||
(MSG.rip_vers == RIPv1) ? " ?" : "");
|
||||
(IMSG.rip_vers == RIPv1) ? " ?" : "");
|
||||
}
|
||||
if (n->n_tag != 0)
|
||||
(void)printf(" tag=%#x%s", n->n_tag,
|
||||
(MSG.rip_vers == RIPv1) ? " ?" : "");
|
||||
(IMSG.rip_vers == RIPv1) ? " ?" : "");
|
||||
putc('\n', stdout);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,11 +31,11 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if !defined(lint) && !defined(sgi)
|
||||
static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#ident "$Revision: 1.1 $"
|
||||
#ident "$Revision: 1.8 $"
|
||||
|
||||
#define RIPCMDS
|
||||
#include "defs.h"
|
||||
@ -54,11 +54,13 @@ static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
|
||||
|
||||
u_int tracelevel, new_tracelevel;
|
||||
FILE *ftrace = stdout; /* output trace file */
|
||||
char *tracelevel_msg = "";
|
||||
static char *tracelevel_pat = "%s\n";
|
||||
|
||||
char savetracename[MAXPATHLEN+1];
|
||||
|
||||
|
||||
/* convert IP address to a string, but not into a single buffer
|
||||
*/
|
||||
char *
|
||||
naddr_ntoa(naddr a)
|
||||
{
|
||||
@ -110,35 +112,37 @@ lastlog(void)
|
||||
|
||||
if (last.tv_sec != now.tv_sec
|
||||
|| last.tv_usec != now.tv_usec) {
|
||||
(void)fprintf(ftrace, "--- %s ---\n", ts(now.tv_sec));
|
||||
(void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
tmsg(char *msg1, char* msg2)
|
||||
tmsg(char *p, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (ftrace != 0) {
|
||||
lastlog();
|
||||
(void)fprintf(ftrace, "%s%s\n", msg1,msg2);
|
||||
va_start(args, p);
|
||||
vfprintf(ftrace, p, args);
|
||||
fflush(ftrace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
trace_close(char *msg1, char *msg2)
|
||||
trace_close(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
if (ftrace != 0) {
|
||||
tmsg(msg1,msg2);
|
||||
fflush(ftrace);
|
||||
|
||||
if (savetracename[0] != '\0') {
|
||||
if (ftrace != 0
|
||||
&& savetracename[0] != '\0') {
|
||||
fd = open(_PATH_DEVNULL, O_RDWR);
|
||||
(void)dup2(fd, STDOUT_FILENO);
|
||||
(void)dup2(fd, STDERR_FILENO);
|
||||
@ -146,7 +150,6 @@ trace_close(char *msg1, char *msg2)
|
||||
fclose(ftrace);
|
||||
ftrace = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -162,9 +165,18 @@ trace_flush(void)
|
||||
|
||||
|
||||
void
|
||||
trace_off(char *msg1, char *msg2)
|
||||
trace_off(char *p, ...)
|
||||
{
|
||||
trace_close(msg1, msg2);
|
||||
va_list args;
|
||||
|
||||
|
||||
if (ftrace != 0) {
|
||||
lastlog();
|
||||
va_start(args, p);
|
||||
vfprintf(ftrace, p, args);
|
||||
fflush(ftrace);
|
||||
}
|
||||
trace_close();
|
||||
|
||||
new_tracelevel = tracelevel = 0;
|
||||
}
|
||||
@ -178,26 +190,48 @@ trace_on(char *filename,
|
||||
FILE *n_ftrace;
|
||||
|
||||
|
||||
if (stat(filename, &stbuf) >= 0 &&
|
||||
(stbuf.st_mode & S_IFMT) != S_IFREG) {
|
||||
/* Given a null filename when tracing is already on, increase the
|
||||
* debugging level and re-open the file in case it has been unlinked.
|
||||
*/
|
||||
if (filename[0] == '\0') {
|
||||
if (tracelevel != 0) {
|
||||
new_tracelevel++;
|
||||
tracelevel_pat = "trace command: %s\n";
|
||||
} else if (savetracename[0] == '\0') {
|
||||
msglog("missing trace file name");
|
||||
return;
|
||||
}
|
||||
filename = savetracename;
|
||||
|
||||
} else if (stat(filename, &stbuf) >= 0) {
|
||||
if (!trusted) {
|
||||
msglog("trace file \"%s\" already exists");
|
||||
return;
|
||||
}
|
||||
if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
|
||||
msglog("wrong type (%#x) of trace file \"%s\"",
|
||||
stbuf.st_mode, filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!trusted
|
||||
&& strcmp(filename, savetracename)
|
||||
&& strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) {
|
||||
msglog("wrong directory for trace file %s", filename);
|
||||
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",
|
||||
msglog("failed to open trace file \"%s\" %s",
|
||||
filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
trace_close("switch to trace file ", filename);
|
||||
tmsg("switch to trace file %s\n", filename);
|
||||
trace_close();
|
||||
if (filename != savetracename)
|
||||
strncpy(savetracename, filename, sizeof(savetracename)-1);
|
||||
ftrace = n_ftrace;
|
||||
@ -207,12 +241,9 @@ trace_on(char *filename,
|
||||
dup2(fileno(ftrace), STDOUT_FILENO);
|
||||
dup2(fileno(ftrace), STDERR_FILENO);
|
||||
|
||||
if (new_tracelevel == 0) {
|
||||
tracelevel_msg = "trace command: ";
|
||||
if (new_tracelevel == 0)
|
||||
new_tracelevel = 1;
|
||||
} else {
|
||||
tmsg("trace command","");
|
||||
}
|
||||
set_tracelevel();
|
||||
}
|
||||
|
||||
|
||||
@ -221,7 +252,7 @@ void
|
||||
sigtrace_on(int s)
|
||||
{
|
||||
new_tracelevel++;
|
||||
tracelevel_msg = "SIGUSR1: ";
|
||||
tracelevel_pat = "SIGUSR1: %s\n";
|
||||
}
|
||||
|
||||
|
||||
@ -230,7 +261,7 @@ void
|
||||
sigtrace_off(int s)
|
||||
{
|
||||
new_tracelevel--;
|
||||
tracelevel_msg = "SIGUSR2: ";
|
||||
tracelevel_pat = "SIGUSR2: %s\n";
|
||||
}
|
||||
|
||||
|
||||
@ -255,14 +286,19 @@ set_tracelevel(void)
|
||||
};
|
||||
|
||||
|
||||
if (new_tracelevel > MAX_TRACELEVEL)
|
||||
if (new_tracelevel > MAX_TRACELEVEL) {
|
||||
new_tracelevel = MAX_TRACELEVEL;
|
||||
if (new_tracelevel == tracelevel) {
|
||||
tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (new_tracelevel != tracelevel) {
|
||||
if (new_tracelevel < tracelevel) {
|
||||
if (--tracelevel == 0)
|
||||
trace_off(tracelevel_msg, off_msgs[0]);
|
||||
trace_off(tracelevel_pat, off_msgs[0]);
|
||||
else
|
||||
tmsg(tracelevel_msg, off_msgs[tracelevel]);
|
||||
tmsg(tracelevel_pat, off_msgs[tracelevel]);
|
||||
} else {
|
||||
if (ftrace == 0) {
|
||||
if (savetracename[0] != '\0')
|
||||
@ -270,9 +306,10 @@ set_tracelevel(void)
|
||||
else
|
||||
ftrace = stdout;
|
||||
}
|
||||
tmsg(tracelevel_msg, on_msgs[tracelevel++]);
|
||||
tmsg(tracelevel_pat, on_msgs[tracelevel++]);
|
||||
}
|
||||
}
|
||||
tracelevel_pat = "%s\n";
|
||||
}
|
||||
|
||||
|
||||
@ -312,106 +349,132 @@ addrname(naddr addr, /* in network byte order */
|
||||
*/
|
||||
struct bits {
|
||||
int bits_mask;
|
||||
int bits_clear;
|
||||
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 }
|
||||
{ IFF_LOOPBACK, 0, "LOOPBACK" },
|
||||
{ IFF_POINTOPOINT, 0, "PT-TO-PT" },
|
||||
{ 0, 0, 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_SUBNET, 0, "" },
|
||||
{ IS_REMOTE, 0, "REMOTE" },
|
||||
{ IS_PASSIVE, (IS_NO_RDISC
|
||||
| IS_BCAST_RDISC
|
||||
| IS_NO_RIP
|
||||
| IS_NO_SUPER_AG
|
||||
| IS_PM_RDISC
|
||||
| IS_NO_AG), "PASSIVE" },
|
||||
{ IS_EXTERNAL, 0, "EXTERNAL" },
|
||||
{ IS_CHECKED, 0, "" },
|
||||
{ IS_ALL_HOSTS, 0, "" },
|
||||
{ IS_ALL_ROUTERS, 0, "" },
|
||||
{ IS_RIP_QUERIED, 0, "" },
|
||||
{ IS_BROKE, IS_SICK, "BROKEN" },
|
||||
{ IS_SICK, 0, "SICK" },
|
||||
{ IS_ACTIVE, 0, "ACTIVE" },
|
||||
{ IS_NEED_NET_SYN, 0, "" },
|
||||
{ IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
|
||||
{ IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
|
||||
{ (IS_NO_RIPV1_IN
|
||||
| IS_NO_RIPV2_IN
|
||||
| IS_NO_RIPV1_OUT
|
||||
| IS_NO_RIPV2_OUT), "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_RIPV2_OUT), 0, "NO_RIP" },
|
||||
{ (IS_NO_RIPV1_IN
|
||||
| IS_NO_RIPV1_OUT), 0, "RIPV2" },
|
||||
{ IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" },
|
||||
{ IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" },
|
||||
{ IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" },
|
||||
{ IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" },
|
||||
{ (IS_NO_ADV_IN
|
||||
| IS_NO_SOL_OUT
|
||||
| IS_NO_ADV_OUT), "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 }
|
||||
| IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" },
|
||||
{ IS_NO_SOL_OUT, 0, "NO_SOLICIT" },
|
||||
{ IS_SOL_OUT, 0, "SEND_SOLICIT" },
|
||||
{ IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" },
|
||||
{ IS_ADV_OUT, 0, "RDISC_ADV" },
|
||||
{ IS_BCAST_RDISC, 0, "BCAST_RDISC" },
|
||||
{ IS_PM_RDISC, 0, "PM_RDISC" },
|
||||
{ 0, 0, "%#x"}
|
||||
};
|
||||
|
||||
static struct bits rs_bits[] = {
|
||||
{ RS_IF, "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 }
|
||||
{ RS_IF, 0, "IF" },
|
||||
{ RS_NET_INT, RS_NET_SYN, "NET_INT" },
|
||||
{ RS_NET_SYN, 0, "NET_SYN" },
|
||||
{ RS_SUBNET, 0, "" },
|
||||
{ RS_LOCAL, 0, "LOCAL" },
|
||||
{ RS_MHOME, 0, "MHOME" },
|
||||
{ RS_STATIC, 0, "STATIC" },
|
||||
{ RS_RDISC, 0, "RDISC" },
|
||||
{ 0, 0, "%#x"}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
trace_bits(struct bits *tbl,
|
||||
u_int field)
|
||||
u_int field,
|
||||
int force)
|
||||
{
|
||||
int first = 1;
|
||||
int b;
|
||||
char c;
|
||||
|
||||
|
||||
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;
|
||||
if (force) {
|
||||
(void)putc('<', ftrace);
|
||||
c = 0;
|
||||
} else {
|
||||
c = '<';
|
||||
}
|
||||
|
||||
while (field != 0
|
||||
&& (b = tbl->bits_mask) != 0) {
|
||||
if ((b & field) == b) {
|
||||
if (tbl->bits_name[0] != '\0') {
|
||||
if (c)
|
||||
(void)putc(c, ftrace);
|
||||
(void)fprintf(ftrace, "%s", tbl->bits_name);
|
||||
c = '|';
|
||||
}
|
||||
if (0 == (field &= ~(b | tbl->bits_clear)))
|
||||
break;
|
||||
}
|
||||
field &= ~b;
|
||||
tbl++;
|
||||
}
|
||||
if (field != 0) {
|
||||
(void)fputc(first ? '<' : '|', ftrace);
|
||||
(void)fprintf(ftrace, "%#x", field);
|
||||
first = 0;
|
||||
if (field != 0 && tbl->bits_name != 0) {
|
||||
if (c)
|
||||
(void)putc(c, ftrace);
|
||||
(void)fprintf(ftrace, tbl->bits_name, field);
|
||||
c = '|';
|
||||
}
|
||||
|
||||
if (!first)
|
||||
if (c || force)
|
||||
(void)fputs("> ", ftrace);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
trace_pair(naddr dst,
|
||||
naddr mask,
|
||||
char *gate)
|
||||
{
|
||||
static char buf[3*4+3+1+2+3 /* "xxx.xxx.xxx.xxx/xx-->" */
|
||||
+3*4+3+1]; /* "xxx.xxx.xxx.xxx" */
|
||||
int i;
|
||||
|
||||
i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0));
|
||||
(void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), gate);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
trace_if(char *act,
|
||||
struct interface *ifp)
|
||||
{
|
||||
if (ftrace == 0)
|
||||
if (!TRACEACTIONS || ftrace == 0)
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
@ -422,8 +485,8 @@ trace_if(char *act,
|
||||
? 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);
|
||||
trace_bits(if_bits, ifp->int_if_flags, 0);
|
||||
trace_bits(is_bits, ifp->int_state, 0);
|
||||
(void)fputc('\n',ftrace);
|
||||
}
|
||||
|
||||
@ -438,7 +501,7 @@ trace_upslot(struct rt_entry *rt,
|
||||
u_short tag,
|
||||
time_t new_time)
|
||||
{
|
||||
if (ftrace == 0)
|
||||
if (!TRACEACTIONS || ftrace == 0)
|
||||
return;
|
||||
if (rts->rts_gate == gate
|
||||
&& rts->rts_router == router
|
||||
@ -448,11 +511,10 @@ trace_upslot(struct rt_entry *rt,
|
||||
|
||||
lastlog();
|
||||
if (rts->rts_gate != RIP_DEFAULT) {
|
||||
(void)fprintf(ftrace, "Chg #%d %-16s--> ",
|
||||
(void)fprintf(ftrace, "Chg #%d %-35s ",
|
||||
rts - rt->rt_spares,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0));
|
||||
(void)fprintf(ftrace, "%-15s ",
|
||||
naddr_ntoa(rts->rts_gate));
|
||||
trace_pair(rt->rt_dst, rt->rt_mask,
|
||||
naddr_ntoa(rts->rts_gate)));
|
||||
if (rts->rts_gate != rts->rts_gate)
|
||||
(void)fprintf(ftrace, "router=%s ",
|
||||
naddr_ntoa(rts->rts_gate));
|
||||
@ -464,9 +526,8 @@ trace_upslot(struct rt_entry *rt,
|
||||
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 ",
|
||||
(void)fprintf(ftrace, " %19s%-16s ",
|
||||
"",
|
||||
gate != rts->rts_gate ? naddr_ntoa(gate) : "");
|
||||
if (gate != router)
|
||||
(void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
|
||||
@ -480,10 +541,10 @@ trace_upslot(struct rt_entry *rt,
|
||||
new_time != rts->rts_time ? ts(new_time) : "");
|
||||
|
||||
} else {
|
||||
(void)fprintf(ftrace, "Add #%d %-16s--> ",
|
||||
(void)fprintf(ftrace, "Add #%d %-35s ",
|
||||
rts - rt->rt_spares,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0));
|
||||
(void)fprintf(ftrace, "%-15s ", naddr_ntoa(gate));
|
||||
trace_pair(rt->rt_dst, rt->rt_mask,
|
||||
naddr_ntoa(gate)));
|
||||
if (gate != router)
|
||||
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
|
||||
if (tag != 0)
|
||||
@ -496,8 +557,10 @@ trace_upslot(struct rt_entry *rt,
|
||||
}
|
||||
|
||||
|
||||
/* display a message if tracing actions
|
||||
*/
|
||||
void
|
||||
trace_msg(char *p, ...)
|
||||
trace_act(char *p, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
@ -510,6 +573,22 @@ trace_msg(char *p, ...)
|
||||
}
|
||||
|
||||
|
||||
/* display a message if tracing packets
|
||||
*/
|
||||
void
|
||||
trace_pkt(char *p, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!TRACEPACKETS || ftrace == 0)
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
va_start(args, p);
|
||||
vfprintf(ftrace, p, args);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
trace_change(struct rt_entry *rt,
|
||||
u_int state,
|
||||
@ -532,25 +611,25 @@ trace_change(struct rt_entry *rt,
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
(void)fprintf(ftrace, "%s %-16s--> %-15s metric=%-2d ",
|
||||
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
|
||||
label,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0),
|
||||
naddr_ntoa(rt->rt_gate), rt->rt_metric);
|
||||
trace_pair(rt->rt_dst, rt->rt_mask,
|
||||
naddr_ntoa(rt->rt_gate)),
|
||||
rt->rt_metric);
|
||||
if (rt->rt_router != rt->rt_gate)
|
||||
(void)fprintf(ftrace, "router=%s ",
|
||||
naddr_ntoa(rt->rt_router));
|
||||
if (rt->rt_tag != 0)
|
||||
(void)fprintf(ftrace, "tag=%#x ", rt->rt_tag);
|
||||
trace_bits(rs_bits, rt->rt_state);
|
||||
trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
|
||||
(void)fprintf(ftrace, "%s ",
|
||||
rt->rt_ifp == 0 ? "-" : rt->rt_ifp->int_name);
|
||||
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) : "");
|
||||
(void)fprintf(ftrace, "%*s %19s%-16s ",
|
||||
strlen(label), "", "",
|
||||
rt->rt_gate != gate ? naddr_ntoa(gate) : "");
|
||||
if (rt->rt_metric != metric)
|
||||
(void)fprintf(ftrace, "metric=%-2d ", metric);
|
||||
if (router != gate)
|
||||
@ -558,13 +637,10 @@ trace_change(struct rt_entry *rt,
|
||||
if (rt->rt_tag != tag)
|
||||
(void)fprintf(ftrace, "tag=%#x ", tag);
|
||||
if (rt->rt_state != state)
|
||||
trace_bits(rs_bits, state);
|
||||
trace_bits(rs_bits, state, 1);
|
||||
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);
|
||||
ifp != 0 ? ifp->int_name : "?");
|
||||
(void)fprintf(ftrace, "%s\n",
|
||||
((rt->rt_time == new_time || !AGE_RT(rt, ifp))
|
||||
? "" : ts(new_time)));
|
||||
@ -580,16 +656,17 @@ trace_add_del(char * action, struct rt_entry *rt)
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
(void)fprintf(ftrace, "%s %-16s--> %-15s metric=%-2d ",
|
||||
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
|
||||
action,
|
||||
addrname(rt->rt_dst, rt->rt_mask, 0),
|
||||
naddr_ntoa(rt->rt_gate), rt->rt_metric);
|
||||
trace_pair(rt->rt_dst, rt->rt_mask,
|
||||
naddr_ntoa(rt->rt_gate)),
|
||||
rt->rt_metric);
|
||||
if (rt->rt_router != rt->rt_gate)
|
||||
(void)fprintf(ftrace, "router=%s ",
|
||||
naddr_ntoa(rt->rt_router));
|
||||
if (rt->rt_tag != 0)
|
||||
(void)fprintf(ftrace, "tag=%#x ", rt->rt_tag);
|
||||
trace_bits(rs_bits, state);
|
||||
trace_bits(rs_bits, state, 0);
|
||||
if (rt->rt_ifp != 0)
|
||||
(void)fprintf(ftrace, "%s ", rt->rt_ifp->int_name);
|
||||
(void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
|
||||
@ -607,7 +684,7 @@ trace_rip(char *dir1, char *dir2,
|
||||
struct netauth *a;
|
||||
int i;
|
||||
|
||||
if (ftrace == 0)
|
||||
if (!TRACEPACKETS || ftrace == 0)
|
||||
return;
|
||||
|
||||
lastlog();
|
||||
|
Loading…
Reference in New Issue
Block a user