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:
Garrett Wollman 1996-07-22 20:56:54 +00:00
parent 9979ce1560
commit 1823680765
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/SGI/dist/; revision=17250
15 changed files with 2411 additions and 1833 deletions

View File

@ -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>

View File

@ -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 \
&& 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)))
#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \
&& now_stale <= (A)->rts_time \
&& ((A)->rts_metric < (B)->rts_metric \
|| ((A)->rts_gate == (A)->rts_router \
&& (B)->rts_gate != (B)->rts_router) \
|| ((A)->rts_metric == (B)->rts_metric \
&& now_stale > (B)->rts_time) \
|| (RT_ISHOST(rt) \
&& (rt)->rt_dst == (A)->rts_router \
&& (A)->rts_metric == (B)->rts_metric)))
/* An "interface" is similar to a kernel ifnet structure, except it also
@ -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_PROMOTE 0x002 /* synthesize combined routes */
#define AGS_REDUN0 0x004 /* redundant, finer routes output */
#define AGS_REDUN1 0x008
#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_GATEWAY 0x010 /* tell kernel RTF_GATEWAY */
#define AGS_IF 0x020 /* for an interface */
#define AGS_RIPV2 0x040 /* send only as RIPv2 */
#define AGS_FINE_GATE 0x080 /* ignore differing ag_gate when this
* has the finer netmask */
#define AGS_CORS_GATE 0x100 /* ignore differing gate when this
* has the coarser netmaks */
#define AGS_SPLIT_HZ 0x200 /* suppress for split horizon */
/* some bits are set if they are set on either route */
#define AGS_PROMOTE_EITHER (AGS_RIPV2 | AGS_GATEWAY | \
AGS_SUPPRESS | AGS_CORS_GATE)
};
@ -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

View File

@ -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,8 +97,7 @@ 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);
trace_rip("Recv", "from", from, ifp, rip, size);
if (rip->rip_vers == 0) {
if (from->sin_addr.s_addr != bad_router)
@ -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_PASSIVE) {
msglog("bogus input from %s on supposedly"
" passive interface %s",
naddr_ntoa(FROM_NADDR),
ifp1->int_name);
} else if (ifp1->int_state & IS_REMOTE) {
ifp1->int_act_time = now.tv_sec;
if (ifok(ifp1, "remote "))
addrouteforif(ifp1);
} else if (TRACEPACKETS) {
trace_msg("discard our own packet\n");
if (ifp1->int_state & IS_REMOTE) {
if (ifp1->int_state & IS_PASSIVE) {
msglog("bogus input from %s on"
" supposedly passive %s",
naddr_ntoa(FROM_NADDR),
ifp1->int_name);
} else {
ifp1->int_act_time = now.tv_sec;
if (if_ok(ifp1, "remote "))
addrouteforif(ifp1);
}
} else {
trace_pkt("discard our own RIP response\n");
}
return;
}
@ -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,19 +372,16 @@ 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",
rip->rip_vers);
trace_pkt("discard RIPv%d response\n",
rip->rip_vers);
return;
}
/* Ignore routes via dead interface.
*/
if (ifp->int_state & IS_BROKE) {
if (TRACEPACKETS)
trace_msg("discard response via"
" broken interface %s\n",
ifp->int_name);
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) {
/* Keep poisoned routes around only long
* enough to pass the poison on.
*/
if (old_metric < HOPCNT_INFINITY)
new_time = now.tv_sec;
} else {
/* Keep poisoned routes around only long
* enough to pass the poison on.
*/
new_time = rts->rts_time;
if (new_time > now.tv_sec-POISON_SECS)
new_time = now.tv_sec-POISON_SECS;
}
/* If this is an update for the router we currently prefer,
* then note it.
*/
if (i == NUM_SPARES) {
rtchange(rt,rt->rt_state, gate,rt->rt_router,
metric, tag, ifp, new_time, 0);
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;

View File

@ -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,7 +133,13 @@ main(int argc,
break;
case 'g':
default_gateway = 1;
bzero(&parm, sizeof(parm));
parm.parm_d_metric = 1;
p = check_parms(&parm);
if (p != 0)
msglog("bad -g: %s", p);
else
default_gateway = 1;
break;
case 'h': /* suppress extra host routes */
@ -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)
}
/* turn on RIP multicast input via an interface
*/
static void
rip_mcast_on(struct interface *ifp)
{
struct ip_mreq m;
if (!IS_RIP_IN_OFF(ifp->int_state)
&& (ifp->int_if_flags & IFF_MULTICAST)
#ifdef MCAST_PPP_BUG
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
#endif
&& !(ifp->int_state & IS_ALIAS)) {
m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
&m, sizeof(m)) < 0)
LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
}
}
/* Prepare socket used for RIP.
*/
void
rip_on(struct interface *ifp)
{
struct ip_mreq m;
/* If the main RIP socket is already alive, only start receiving
* multicasts for this interface.
*/
if (rip_sock >= 0) {
if (ifp != 0
&& 0 == (ifp->int_state & (IS_NO_RIP_IN|IS_PASSIVE))
&& (ifp->int_if_flags & IFF_MULTICAST)
#ifdef MCAST_PPP_BUG
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
#endif
&& !(ifp->int_state & IS_ALIAS)) {
m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
m.imr_interface.s_addr = ((ifp->int_if_flags
& IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
&m, sizeof(m)) < 0)
DBGERR(1,"setsockopt(IP_ADD_MEMBERSHIP RIP)");
}
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;

View File

@ -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)
@ -106,7 +109,7 @@ output(enum output_type type,
soc = rip_sock;
flags = 0;
switch (type) {
case OUT_QUERY:
msg = "Answer Query";
@ -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,
IPPROTO_IP, IP_MULTICAST_IF,
&tgt_mcast, sizeof(tgt_mcast)))
BADERR(1,"setsockopt(rip_sock,"
if (0 > setsockopt(rip_sock,
IPPROTO_IP, IP_MULTICAST_IF,
&tgt_mcast,
sizeof(tgt_mcast))) {
serrno = errno;
LOGERR("setsockopt(rip_sock,"
"IP_MULTICAST_IF)");
errno = serrno;
ifp = 0;
return -1;
}
rip_sock_mcast = ifp;
}
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
}
}
if (TRACEPACKETS)
trace_rip(msg, "to", &sin, ifp, buf, size);
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) {
/* Do not send authority routes into the subnet,
* or when RIP is off.
*/
if ((RT->rt_state & RS_NET_INT)
&& (on_net(dst, ws.to_net, ws.to_mask)
|| rip_sock < 0))
return 0;
/* Do not send RIPv1 advertisements of subnets to
* other networks.
*
* If possible, multicast them by RIPv2.
*/
if (!(ws.state & WS_ST_RIP2_ALL)
&& !on_net(dst, ws.to_std_net, ws.to_std_mask))
ags |= AGS_RIPV2;
} else if (RT->rt_state & RS_NET_SUB) {
/* do not send synthetic network routes if no RIPv1
* listeners might hear.
*/
if (ws.state & WS_ST_RIP2_ALL)
return 0;
/* Do not send synthetic network routes on the real subnet */
if (on_net(dst, ws.to_std_net, ws.to_std_mask))
return 0;
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;
}
/* 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.
/* Do not send a route back to where it came from, except in
* response to a query. This is "split-horizon". That means not
* advertising back to the same network and so via the same interface.
*
* We want to suppress routes that might have been fragmented
* from this route by a RIPv1 router and sent back to us, and so we
* cannot forget this route here. Let the split-horizon route
* aggregate (suppress) the fragmented routes and then itself be
* forgotten.
*
* Include the routes for both ends of point-to-point interfaces
* since the other side presumably knows them as well as we do.
*/
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);
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);
}
/* 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 ((metric = ifp->int_d_metric) != 0) {
/* Fake a default route if asked */
ws.state |= WS_ST_DEFAULT;
/* Use the metric of a real default, if there is one.
if (supplier) {
/* Fake a default route if asked, and if there is not
* a better, real default route.
*/
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);
if (ifp->int_d_metric != 0
&& (0 == (rt = rtget(RIP_DEFAULT, 0))
|| rt->rt_metric+ws.metric >= ifp->int_d_metric)) {
ws.state |= WS_ST_DEFAULT;
ag_check(0, 0, 0, 0,
ifp->int_d_metric,ifp->int_d_metric,
0, 0, 0, supply_out);
}
if ((ws.state & WS_ST_RIP2_ALL)
&& (ifp->int_state & IS_PM_RDISC)) {
ws.state |= WS_ST_PM_RDISC;
ripv12_buf.rip.rip_vers = RIPv1;
}
}
(void)rn_walktree(rhead, walk_supply, 0);
ag_flush(0,0,supply_out);
/* Flush the packet buffers */
/* 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);
}
}

View File

@ -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;
bcopy(parmp->parm_passwd, ifp->int_passwd,
sizeof(ifp->int_passwd));
ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
ifp->int_rdisc_int = parmp->parm_rdisc_int;
ifp->int_d_metric = parmp->parm_d_metric;
}
if (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_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)
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry %s", lptr, p);
if (p != 0) {
if (strcmp(p,lptr))
msglog("bad \"%s\" in "_PATH_GATEWAYS
" 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
*/
if (!rtfind(gate)) {
msglog("unreachable gateway %s in "
_PATH_GATEWAYS" entry %s",
gname, lptr);
continue;
}
/* Remember to advertise the corresponding logical network.
*/
if (!(state & IS_EXTERNAL)
&& netmask != std_mask(dst))
state |= IS_SUBNET;
/* Remember to advertise the corresponding logical
* network.
*/
if (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);
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;
}

View File

@ -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"

View File

@ -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,9 +181,11 @@ 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");
ifp->int_state |= IS_ALL_HOSTS;
&m, sizeof(m)) < 0) {
LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS");
} else {
ifp->int_state |= IS_ALL_HOSTS;
}
}
if (!supplier
@ -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,9 +205,11 @@ 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");
ifp->int_state |= IS_ALL_ROUTERS;
&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 only adverising, then do only that. */
if (supplier) {
/* If only adverising, then do only that. */
/* 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;
del_rdisc(drp);
continue;
}
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
&& (drp == cur_drp
|| (new_drp != cur_drp
&& new_drp->dr_life > drp->dr_life))))
new_drp = drp;
|| (!((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_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,55 +541,79 @@ 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;
if (pref == 0 || life == 0) {
pref = 0;
life = 0;
}
for (new_drp = drs, drp = drs; drp < &drs[MAX_ADS]; drp++) {
if (drp->dr_ts == 0) {
new_drp = drp;
continue;
}
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)
new_drp = drp;
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);
ifp->int_rdisc_cnt = MAX_SOLICITATIONS;
/* 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,
IPPROTO_IP, IP_MULTICAST_IF,
&tgt_mcast, sizeof(tgt_mcast))) {
DBGERR(1,"setsockopt(rdisc_sock,"
if (0 > setsockopt(rdisc_sock,
IPPROTO_IP, IP_MULTICAST_IF,
&tgt_mcast, sizeof(tgt_mcast))) {
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);
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))) {
msglog("sendto(%s%s%s): %s",
ifp != 0 ? ifp->int_name : "",
ifp != 0 ? ", " : "",
inet_ntoa(sin.sin_addr),
strerror(errno));
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,21 +868,19 @@ ck_icmp(char *act,
}
if (p->icmp.icmp_code != 0) {
if (TRACEPACKETS)
msglog("unrecognized ICMP Router"
" %s code=%d from %s to %s\n",
type, p->icmp.icmp_code,
naddr_ntoa(from), naddr_ntoa(to));
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);
trace_rdisc(act, from, to, ifp, p, len);
if (ifp == 0 && TRACEPACKETS)
msglog("unknown interface for router-discovery %s"
" from %s to %s",
type, naddr_ntoa(from), naddr_ntoa(to));
if (ifp == 0)
trace_pkt("unknown interface for router-discovery %s"
" from %s to %s",
type, naddr_ntoa(from), naddr_ntoa(to));
return ifp;
}
@ -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;
}

View File

@ -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

View File

@ -3,4 +3,5 @@
PROG= rtquery
MAN8= rtquery.8
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View File

@ -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

View File

@ -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;
char packet[MAXPACKETSIZE+MAXPATHLEN];
} omsg_buf;
#define OMSG omsg_buf.rip
int omsg_len = sizeof(struct rip);
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+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) {
@ -435,13 +561,13 @@ rip_input(struct sockaddr_in *from,
else
hp = gethostbyaddr((char*)&in, sizeof(in),
AF_INET);
(void)printf(" nhop=%-15s%s",
(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

View File

@ -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,42 +112,43 @@ 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') {
fd = open(_PATH_DEVNULL, O_RDWR);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
(void)close(fd);
fclose(ftrace);
ftrace = 0;
}
if (ftrace != 0
&& savetracename[0] != '\0') {
fd = open(_PATH_DEVNULL, O_RDWR);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
(void)close(fd);
fclose(ftrace);
ftrace = 0;
}
}
@ -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) {
msglog("wrong type (%#x) of trace file \"%s\"",
stbuf.st_mode, filename);
return;
}
if (!trusted
&& strcmp(filename, savetracename)
&& strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) {
msglog("wrong directory for trace file %s", filename);
return;
/* Given a null filename when tracing is already on, increase the
* debugging level and re-open the file in case it has been unlinked.
*/
if (filename[0] == '\0') {
if (tracelevel != 0) {
new_tracelevel++;
tracelevel_pat = "trace command: %s\n";
} else if (savetracename[0] == '\0') {
msglog("missing trace file name");
return;
}
filename = savetracename;
} else if (stat(filename, &stbuf) >= 0) {
if (!trusted) {
msglog("trace file \"%s\" already exists");
return;
}
if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
msglog("wrong type (%#x) of trace file \"%s\"",
stbuf.st_mode, filename);
return;
}
if (!trusted
&& strcmp(filename, savetracename)
&& strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) {
msglog("wrong directory for trace file: \"%s\"",
filename);
return;
}
}
n_ftrace = fopen(filename, "a");
if (n_ftrace == 0) {
msglog("failed to open trace file \"%s\": %s",
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;
if (force) {
(void)putc('<', ftrace);
c = 0;
} else {
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;
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();