- resolve conflicts.

- remove md5 stuff; it is in libc.
- define MCAST_PPP_BUG, until we fix if_ppp.c
This commit is contained in:
christos 1997-02-03 22:02:51 +00:00
parent 5bd33fc853
commit e7512e5a5e
16 changed files with 2735 additions and 2029 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.16 1996/08/10 01:48:41 thorpej Exp $
# $NetBSD: Makefile,v 1.17 1997/02/03 22:02:51 christos Exp $
# from: @(#)Makefile 8.1 (Berkeley) 6/19/93
PROG= routed
@ -8,5 +8,6 @@ SUBDIR= rtquery
# By popular demand...
MLINKS= routed.8 rdisc.8
#COPTS=-g -DDEBUG -Wall
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: defs.h,v 1.13 1996/09/24 16:24:12 christos Exp $ */
/* $NetBSD: defs.h,v 1.14 1997/02/03 22:02:53 christos Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -73,6 +73,7 @@
#include <stdarg.h>
#include <syslog.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
@ -112,9 +113,12 @@
/* 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 */
#if defined(__NetBSD__)
#define MCAST_PPP_BUG
#endif
#define NEVER (24*60*60) /* a long time */
#define DAY (24*60*60)
#define NEVER DAY /* a long time */
#define EPOCH NEVER /* bias time by this to avoid <0 */
/* Scan the kernel regularly to see if any interfaces have appeared or been
@ -126,6 +130,13 @@
#define LIM_SEC(s,l) ((s).tv_sec = MIN((s).tv_sec, (l)))
/* Metric used for fake default routes. It ought to be 15, but when
* processing advertised routes, previous versions of `routed` added
* to the received metric and discarded the route if the total was 16
* or larger.
*/
#define FAKE_METRIC (HOPCNT_INFINITY-2)
/* Router Discovery parameters */
#ifndef sgi
@ -146,15 +157,19 @@
#define MAX_SOLICITATIONS 3
/* Bloated packet size for systems that simply add authentication to
* full-sized packets
*/
#define OVER_MAXPACKETSIZE (MAXPACKETSIZE+sizeof(struct netinfo)*2)
/* typical packet buffers */
union pkt_buf {
char packet[MAXPACKETSIZE+1];
char packet[OVER_MAXPACKETSIZE*2];
struct rip rip;
};
/* no more routes than this, to protect ourself in case something goes
* whacko and starts broadcast zillions of bogus routes.
/* No more routes than this, to protect ourself in case something goes
* whacko and starts broadcasting zillions of bogus routes.
*/
#define MAX_ROUTES (128*1024)
extern int total_routes;
@ -222,7 +237,7 @@ struct rt_entry {
* - or the current route is equal but stale
* - or it is a host route advertised by a system for itself
*/
#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \
#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 \
@ -238,7 +253,11 @@ struct rt_entry {
* handles "logical" or "IS_REMOTE" interfaces (remote gateways).
*/
struct interface {
struct interface *int_next, *int_prev;
struct interface *int_next, **int_prev;
struct interface *int_ahash, **int_ahash_prev;
struct interface *int_bhash, **int_bhash_prev;
struct interface *int_rlink, **int_rlink_prev;
struct interface *int_nhash, **int_nhash_prev;
char int_name[IFNAMSIZ+15+1]; /* big enough for IS_REMOTE */
u_short int_index;
naddr int_addr; /* address on this host (net order) */
@ -254,6 +273,7 @@ struct interface {
int int_if_flags; /* some bits copied from kernel */
u_int int_state;
time_t int_act_time; /* last thought healthy */
time_t int_query_time;
u_short int_transitions; /* times gone up-down */
char int_metric;
char int_d_metric; /* for faked default route */
@ -267,7 +287,13 @@ struct interface {
#endif
time_t ts; /* timestamp on network stats */
} int_data;
char int_passwd[RIP_AUTH_PW_LEN]; /* RIPv2 password */
# define MAX_AUTH_KEYS 5
struct auth { /* authentication info */
u_char type;
u_char key[RIP_AUTH_PW_LEN];
u_char keyid;
time_t start, end;
} int_auth[MAX_AUTH_KEYS];
int int_rdisc_pref; /* advertised rdisc preference */
int int_rdisc_int; /* MaxAdvertiseInterval */
int int_rdisc_cnt;
@ -283,11 +309,11 @@ struct interface {
#define IS_CHECKED 0x0000020 /* still exists */
#define IS_ALL_HOSTS 0x0000040 /* in INADDR_ALLHOSTS_GROUP */
#define IS_ALL_ROUTERS 0x0000080 /* in INADDR_ALLROUTERS_GROUP */
#define IS_RIP_QUERIED 0x0000100 /* query broadcast */
#define IS_BROKE 0x0000200 /* seems to be broken */
#define IS_SICK 0x0000400 /* seems to be broken */
#define IS_DUP 0x0000800 /* has a duplicate address */
#define IS_ACTIVE 0x0001000 /* heard from it at least once */
#define IS_DISTRUST 0x0000100 /* ignore untrusted routers */
#define IS_REDIRECT_OK 0x0000200 /* accept ICMP redirects */
#define IS_BROKE 0x0000400 /* seems to be broken */
#define IS_SICK 0x0000800 /* seems to be broken */
#define IS_DUP 0x0001000 /* has a duplicate address */
#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 */
@ -359,14 +385,14 @@ struct ag_info {
extern struct parm {
struct parm *parm_next;
char parm_name[IFNAMSIZ+1];
naddr parm_addr_h;
naddr parm_net;
naddr parm_mask;
char parm_d_metric;
u_int parm_int_state;
int parm_rdisc_pref;
int parm_rdisc_int;
char parm_passwd[RIP_AUTH_PW_LEN+1];
struct auth parm_auth[MAX_AUTH_KEYS];
} *parms;
/* authority for internal networks */
@ -377,7 +403,23 @@ extern struct intnet {
char intnet_metric;
} *intnets;
/* trusted routers */
extern struct tgate {
struct tgate *tgate_next;
naddr tgate_addr;
} *tgates;
enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST,
NO_OUT_MULTICAST, NO_OUT_RIPV2};
/* common output buffers */
extern struct ws_buf {
struct rip *buf;
struct netinfo *n;
struct netinfo *base;
struct netinfo *lim;
enum output_type type;
} v12buf, v2buf;
extern pid_t mypid;
extern naddr myaddr; /* main address of this system */
@ -400,7 +442,8 @@ extern int mhome; /* 1=want multi-homed host route */
extern int advertise_mhome; /* 1=must continue adverising it */
extern int auth_ok; /* 1=ignore auth if we do not care */
extern struct timeval epoch; /* when started */
extern struct timeval clk; /* system clock's idea of time */
extern struct timeval epoch; /* system clock when started */
extern struct timeval now; /* current idea of time */
extern time_t now_stale;
extern time_t now_expire;
@ -418,19 +461,21 @@ 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 struct interface *remote_if; /* remote interfaces */
extern int have_ripv1_out; /* have a RIPv1 interface */
extern int have_ripv1_in;
extern int need_flash; /* flash update needed */
extern struct timeval need_kern; /* need to update kernel table */
extern int update_seqno; /* a route has changed */
extern u_int tracelevel, new_tracelevel;
extern int tracelevel, new_tracelevel;
#define MAX_TRACELEVEL 4
#define TRACEKERNEL (tracelevel >= 4) /* log kernel changes */
#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */
#define TRACEPACKETS (tracelevel >= 2) /* note packets */
#define TRACEACTIONS (tracelevel != 0)
extern FILE *ftrace; /* output trace file */
extern char inittracename[MAXPATHLEN+1];
extern struct radix_node_head *rhead;
@ -445,16 +490,25 @@ extern void fix_select(void);
extern void rip_off(void);
extern void rip_on(struct interface *);
enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST,
NO_OUT_MULTICAST, NO_OUT_RIPV2};
extern int output(enum output_type, struct sockaddr_in *,
struct interface *, struct rip *, int);
extern void bufinit(void);
extern int output(enum output_type, struct sockaddr_in *,
struct interface *, struct rip *, int);
extern void clr_ws_buf(struct ws_buf *, struct auth *);
extern void rip_query(void);
extern void rip_bcast(int);
extern void supply(struct sockaddr_in *, struct interface *,
enum output_type, int, int);
enum output_type, int, int, int);
extern void msglog(char *, ...);
struct msg_limit {
time_t reuse;
struct msg_sub {
naddr addr;
time_t until;
# define MSG_SUBJECT_N 8
} subs[MSG_SUBJECT_N];
};
extern void msglim(struct msg_limit *, naddr, char *, ...);
#define LOGERR(msg) msglog(msg ": %s", strerror(errno))
extern void logbad(int, char *, ...);
#define BADERR(dump,msg) logbad(dump,msg ": %s", strerror(errno))
@ -472,15 +526,16 @@ extern void intvl_random(struct timeval *, u_long, u_long);
extern int getnet(char *, naddr *, naddr *);
extern int gethost(char *, naddr *);
extern void gwkludge(void);
extern char *parse_parms(char *);
extern char *parse_parms(char *, int);
extern char *check_parms(struct parm *);
extern void get_parms(struct interface *);
extern void lastlog(void);
extern void trace_on(char *, int);
extern void set_tracefile(char *, char *, int);
extern void tracelevel_msg(char *, int);
extern void trace_off(char*, ...);
extern void trace_flush(void);
extern void set_tracelevel(void);
extern void trace_flush(void);
extern void trace_kernel(char *, ...);
extern void trace_act(char *, ...);
extern void trace_pkt(char *, ...);
@ -494,6 +549,7 @@ extern void trace_upslot(struct rt_entry *, struct rt_spare *,
extern void trace_rip(char*, char*, struct sockaddr_in *,
struct interface *, struct rip *, int);
extern char *addrname(naddr, naddr, int);
extern char *rtname(naddr, naddr, naddr);
extern void rdisc_age(naddr);
extern void set_rdisc_mg(struct interface *, int);
@ -528,6 +584,7 @@ extern void rtadd(naddr, naddr, naddr, naddr,
extern void rtchange(struct rt_entry *, u_int, naddr,naddr, int, u_short,
struct interface *ifp, time_t, char *);
extern void rtdelete(struct rt_entry *);
extern void rts_delete(struct rt_entry *, struct rt_spare *);
extern void rtbad_sub(struct rt_entry *);
extern void rtswitch(struct rt_entry *, struct rt_spare *);
extern void rtbad(struct rt_entry *);
@ -549,13 +606,29 @@ extern naddr ripv1_mask_net(naddr, struct interface *);
extern naddr ripv1_mask_host(naddr,struct interface *);
#define on_net(a,net,mask) (((ntohl(a) ^ (net)) & (mask)) == 0)
extern int check_dst(naddr);
extern void addrouteforif(register struct interface *);
extern struct interface *check_dup(naddr, naddr, naddr, int);
extern int check_remote(struct interface *);
extern int addrouteforif(register struct interface *);
extern void ifinit(void);
extern int walk_bad(struct radix_node *, struct walkarg *);
extern int if_ok(struct interface *, char *);
extern void if_sick(struct interface *);
extern void if_bad(struct interface *);
extern void if_link(struct interface *);
extern struct interface *ifwithaddr(naddr, int, int);
extern struct interface *ifwithname(char *, naddr);
extern struct interface *ifwithindex(u_short);
extern struct interface *ifwithindex(u_short, int);
extern struct interface *iflookup(naddr);
extern struct auth *find_auth(struct interface *);
extern void end_md5_auth(struct ws_buf *, struct auth *);
#define MD5_DIGEST_LEN 16
typedef struct {
u_int32_t state[4]; /* state (ABCD) */
u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
extern void MD5Init(MD5_CTX*);
extern void MD5Update(MD5_CTX*, u_char*, u_int);
extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.c,v 1.10 1996/09/24 16:24:13 christos Exp $ */
/* $NetBSD: if.c,v 1.11 1997/02/03 22:02:54 christos Exp $ */
/*
* Copyright (c) 1983, 1993
@ -36,24 +36,109 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: if.c,v 1.10 1996/09/24 16:24:13 christos Exp $";
static char rcsid[] = "$NetBSD: if.c,v 1.11 1997/02/03 22:02:54 christos Exp $";
#endif
#include "defs.h"
#include "pathnames.h"
struct interface *ifnet; /* all interfaces */
struct interface *ifnet; /* all interfaces */
/* hash table for all interfaces, big enough to tolerate ridiculous
* numbers of IP aliases. Crazy numbers of aliases such as 7000
* still will not do well, but not just in looking up interfaces
* by name or address.
*/
#define AHASH_LEN 211 /* must be prime */
#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN]
struct interface *ahash_tbl[AHASH_LEN];
#define BHASH_LEN 211 /* must be prime */
#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN]
struct interface *bhash_tbl[BHASH_LEN];
struct interface *remote_if; /* remote interfaces */
/* hash for physical interface names.
* Assume there are never more 100 or 200 real interfaces, and that
* aliases are put on the end of the hash chains.
*/
#define NHASH_LEN 97
struct interface *nhash_tbl[NHASH_LEN];
int tot_interfaces; /* # of remote and local interfaces */
int rip_interfaces; /* # of interfaces doing RIP */
int foundloopback; /* valid flag for loopaddr */
naddr loopaddr; /* our address on loopback */
struct timeval ifinit_timer;
static struct timeval last_ifinit;
int have_ripv1_out; /* have a RIPv1 interface */
int have_ripv1_in;
static struct interface**
nhash(register char *p)
{
register u_int i;
for (i = 0; *p != '\0'; p++) {
i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1);
i ^= *p;
}
return &nhash_tbl[i % NHASH_LEN];
}
/* Link a new interface into the lists and hash tables.
*/
void
if_link(struct interface *ifp)
{
struct interface **hifp;
ifp->int_prev = &ifnet;
ifp->int_next = ifnet;
if (ifnet != 0)
ifnet->int_prev = &ifp->int_next;
ifnet = ifp;
hifp = AHASH(ifp->int_addr);
ifp->int_ahash_prev = hifp;
if ((ifp->int_ahash = *hifp) != 0)
(*hifp)->int_ahash_prev = &ifp->int_ahash;
*hifp = ifp;
if (ifp->int_if_flags & IFF_BROADCAST) {
hifp = BHASH(ifp->int_brdaddr);
ifp->int_bhash_prev = hifp;
if ((ifp->int_bhash = *hifp) != 0)
(*hifp)->int_bhash_prev = &ifp->int_bhash;
*hifp = ifp;
}
if (ifp->int_state & IS_REMOTE) {
ifp->int_rlink_prev = &remote_if;
ifp->int_rlink = remote_if;
if (remote_if != 0)
remote_if->int_rlink_prev = &ifp->int_rlink;
remote_if = ifp;
}
hifp = nhash(ifp->int_name);
if (ifp->int_state & IS_ALIAS) {
/* put aliases on the end of the hash chain */
while (*hifp != 0)
hifp = &(*hifp)->int_nhash;
}
ifp->int_nhash_prev = hifp;
if ((ifp->int_nhash = *hifp) != 0)
(*hifp)->int_nhash_prev = &ifp->int_nhash;
*hifp = ifp;
}
/* Find the interface with an address
*/
struct interface *
@ -63,20 +148,29 @@ ifwithaddr(naddr addr,
{
struct interface *ifp, *possible = 0;
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (ifp->int_addr == addr
|| ((ifp->int_if_flags & IFF_BROADCAST)
&& ifp->int_brdaddr == addr
&& bcast)) {
if ((ifp->int_state & IS_REMOTE) && !remote)
continue;
remote = (remote == 0) ? IS_REMOTE : 0;
if (!(ifp->int_state & IS_BROKE)
&& !(ifp->int_state & IS_PASSIVE))
return ifp;
for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) {
if (ifp->int_addr != addr)
continue;
if ((ifp->int_state & remote) != 0)
continue;
if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0)
return ifp;
possible = ifp;
}
possible = ifp;
}
if (possible || !bcast)
return possible;
for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) {
if (ifp->int_brdaddr != addr)
continue;
if ((ifp->int_state & remote) != 0)
continue;
if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0)
return ifp;
possible = ifp;
}
return possible;
@ -91,34 +185,56 @@ ifwithname(char *name, /* "ec0" or whatever */
{
struct interface *ifp;
for (;;) {
for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) {
/* If the network address is not specified,
* ignore any alias interfaces. Otherwise, look
* for the interface with the target name and address.
*/
if (!strcmp(ifp->int_name, name)
&& ((addr == 0 && !(ifp->int_state & IS_ALIAS))
|| (ifp->int_addr == addr)))
return ifp;
}
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (!strcmp(ifp->int_name, name)
&& (ifp->int_addr == addr
|| (addr == 0 && !(ifp->int_state & IS_ALIAS))))
return ifp;
/* If there is no known interface, maybe there is a
* new interface. So just once look for new interfaces.
*/
if (last_ifinit.tv_sec == now.tv_sec
&& last_ifinit.tv_usec == now.tv_usec)
return 0;
ifinit();
}
return 0;
}
struct interface *
ifwithindex(u_short index)
ifwithindex(u_short index,
int rescan_ok)
{
struct interface *ifp;
for (;;) {
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_index == index)
return ifp;
}
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_index == index)
return ifp;
/* If there is no known interface, maybe there is a
* new interface. So just once look for new interfaces.
*/
if (!rescan_ok
|| (last_ifinit.tv_sec == now.tv_sec
&& last_ifinit.tv_usec == now.tv_usec))
return 0;
ifinit();
}
return 0;
}
/* Find an interface from which the specified address
* should have come from. Used for figuring out which
* interface a packet came in on -- for tracing.
* interface a packet came in on.
*/
struct interface *
iflookup(naddr addr)
@ -126,37 +242,44 @@ iflookup(naddr addr)
struct interface *ifp, *maybe;
maybe = 0;
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (ifp->int_if_flags & IFF_POINTOPOINT) {
if (ifp->int_dstaddr == addr)
for (;;) {
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (ifp->int_if_flags & IFF_POINTOPOINT) {
/* finished with a match */
return ifp;
if (ifp->int_dstaddr == addr)
return ifp;
} else {
/* finished with an exact match */
if (ifp->int_addr == addr)
return ifp;
if ((ifp->int_if_flags & IFF_BROADCAST)
&& ifp->int_brdaddr == addr)
return ifp;
} else {
/* finished with an exact match */
if (ifp->int_addr == addr)
return ifp;
/* Look for the longest approximate match.
*/
if (on_net(addr, ifp->int_net, ifp->int_mask)
&& (maybe == 0
|| ifp->int_mask > maybe->int_mask))
maybe = ifp;
/* Look for the longest approximate match.
*/
if (on_net(addr, ifp->int_net, ifp->int_mask)
&& (maybe == 0
|| ifp->int_mask > maybe->int_mask))
maybe = ifp;
}
}
}
return maybe;
if (maybe != 0
|| (last_ifinit.tv_sec == now.tv_sec
&& last_ifinit.tv_usec == now.tv_usec))
return maybe;
/* If there is no known interface, maybe there is a
* new interface. So just once look for new interfaces.
*/
ifinit();
}
}
/* Return the classical netmask for an IP address.
*/
naddr
std_mask(naddr addr) /* in network order */
naddr /* host byte order */
std_mask(naddr addr) /* network byte order */
{
NTOHL(addr); /* was a host, not a network */
@ -248,6 +371,68 @@ check_dst(naddr addr)
}
/* See a new interface duplicates an existing interface.
*/
struct interface *
check_dup(naddr addr, /* IP address, so network byte order */
naddr dstaddr, /* ditto */
naddr mask, /* mask, so host byte order */
int if_flags)
{
struct interface *ifp;
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_mask != mask)
continue;
if (!iff_alive(ifp->int_if_flags))
continue;
/* The local address can only be shared with a point-to-point
* link.
*/
if (ifp->int_addr == addr
&& (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0))
return ifp;
if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask))
return ifp;
}
return 0;
}
/* See that a remote gateway is reachable.
* Note that the answer can change as real interfaces come and go.
*/
int /* 0=bad */
check_remote(struct interface *ifp)
{
struct rt_entry *rt;
/* do not worry about other kinds */
if (!(ifp->int_state & IS_REMOTE))
return 1;
rt = rtfind(ifp->int_addr);
if (rt != 0
&& rt->rt_ifp != 0
&&on_net(ifp->int_addr,
rt->rt_ifp->int_net, rt->rt_ifp->int_mask))
return 1;
/* the gateway cannot be reached directly from one of our
* interfaces
*/
if (!(ifp->int_state & IS_BROKE)) {
msglog("unreachable gateway %s in "_PATH_GATEWAYS,
naddr_ntoa(ifp->int_addr));
if_bad(ifp);
}
return 0;
}
/* Delete an interface.
*/
static void
@ -263,17 +448,28 @@ ifdel(struct interface *ifp)
/* unlink the interface
*/
if (rip_sock_mcast == ifp)
rip_sock_mcast = 0;
*ifp->int_prev = ifp->int_next;
if (ifp->int_next != 0)
ifp->int_next->int_prev = ifp->int_prev;
if (ifp->int_prev != 0)
ifp->int_prev->int_next = ifp->int_next;
else
ifnet = ifp->int_next;
*ifp->int_ahash_prev = ifp->int_ahash;
if (ifp->int_ahash != 0)
ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev;
*ifp->int_nhash_prev = ifp->int_nhash;
if (ifp->int_nhash != 0)
ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev;
if (ifp->int_if_flags & IFF_BROADCAST) {
*ifp->int_bhash_prev = ifp->int_bhash;
if (ifp->int_bhash != 0)
ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev;
}
if (ifp->int_state & IS_REMOTE) {
*ifp->int_rlink_prev = ifp->int_rlink;
if (ifp->int_rlink != 0)
ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev;
}
if (!(ifp->int_state & IS_ALIAS)) {
/* delete aliases
/* delete aliases when the main interface dies
*/
for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
if (ifp1 != ifp
@ -296,6 +492,8 @@ ifdel(struct interface *ifp)
&& errno != EADDRNOTAVAIL
&& !TRACEACTIONS)
LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)");
if (rip_sock_mcast == ifp)
rip_sock_mcast = 0;
}
if (ifp->int_rip_sock >= 0) {
(void)close(ifp->int_rip_sock);
@ -328,6 +526,7 @@ if_sick(struct interface *ifp)
{
if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
ifp->int_state |= IS_SICK;
ifp->int_act_time = NEVER;
trace_if("Chg", ifp);
LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
@ -349,7 +548,8 @@ if_bad(struct interface *ifp)
LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
ifp->int_state |= (IS_BROKE | IS_SICK);
ifp->int_state &= ~(IS_RIP_QUERIED | IS_ACTIVE);
ifp->int_act_time = NEVER;
ifp->int_query_time = NEVER;
ifp->int_data.ts = 0;
trace_if("Chg", ifp);
@ -377,16 +577,16 @@ if_ok(struct interface *ifp,
if (!(ifp->int_state & IS_BROKE)) {
if (ifp->int_state & IS_SICK) {
trace_act("%sinterface %s to %s working better\n",
trace_act("%sinterface %s to %s working better",
type,
ifp->int_name, naddr_ntoa(ifp->int_addr));
ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
ifp->int_state &= ~IS_SICK;
}
return 0;
}
msglog("%sinterface %s to %s restored",
type, ifp->int_name, naddr_ntoa(ifp->int_addr));
type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
ifp->int_state &= ~(IS_BROKE | IS_SICK);
ifp->int_data.ts = 0;
@ -398,6 +598,11 @@ if_ok(struct interface *ifp,
}
if_ok_rdisc(ifp);
}
if (ifp->int_state & IS_REMOTE) {
if (!addrouteforif(ifp))
return 0;
}
return 1;
}
@ -453,15 +658,14 @@ ifinit(void)
uint complaints = 0;
static u_int prev_complaints = 0;
# define COMP_NOT_INET 0x001
# define COMP_WIERD 0x002
# define COMP_NOADDR 0x004
# define COMP_BADADDR 0x008
# define COMP_NODST 0x010
# define COMP_NOBADR 0x020
# define COMP_NOMASK 0x040
# define COMP_DUP 0x080
# define COMP_BAD_METRIC 0x100
# define COMP_NETMASK 0x200
# define COMP_NOADDR 0x002
# define COMP_BADADDR 0x004
# define COMP_NODST 0x008
# define COMP_NOBADR 0x010
# define COMP_NOMASK 0x020
# define COMP_DUP 0x040
# define COMP_BAD_METRIC 0x080
# define COMP_NETMASK 0x100
struct interface ifs, ifs0, *ifp, *ifp1;
struct rt_entry *rt;
@ -469,7 +673,6 @@ ifinit(void)
int mib[6];
struct if_msghdr *ifm;
struct ifa_msghdr *ifam, *ifam_lim, *ifam2;
struct sockaddr_dl *sdl;
int in, ierr, out, oerr;
struct intnet *intnetp;
struct rt_addrinfo info;
@ -478,6 +681,7 @@ ifinit(void)
#endif
last_ifinit = now;
ifinit_timer.tv_sec = now.tv_sec + (supplier
? CHECK_ACT_INTERVAL
: CHECK_QUIET_INTERVAL);
@ -517,6 +721,8 @@ ifinit(void)
ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen);
if (ifam->ifam_type == RTM_IFINFO) {
struct sockaddr_dl *sdl;
ifm = (struct if_msghdr *)ifam;
/* make prototype structure for the IP aliases
*/
@ -525,6 +731,7 @@ ifinit(void)
ifs0.int_index = ifm->ifm_index;
ifs0.int_if_flags = ifm->ifm_flags;
ifs0.int_state = IS_CHECKED;
ifs0.int_query_time = NEVER;
ifs0.int_act_time = now.tv_sec;
ifs0.int_data.ts = now.tv_sec;
ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets;
@ -536,22 +743,30 @@ ifinit(void)
#endif
sdl = (struct sockaddr_dl *)(ifm + 1);
sdl->sdl_data[sdl->sdl_nlen] = 0;
strncpy(ifs0.int_name, sdl->sdl_data,
MIN(sizeof(ifs0.int_name), sdl->sdl_nlen));
continue;
}
if (ifam->ifam_type != RTM_NEWADDR) {
logbad(1,"ifinit: out of sync");
continue;
}
rt_xaddrs(&info, (struct sockaddr *)(ifam+1),
(struct sockaddr *)ifam2,
ifam->ifam_addrs);
/* Prepare for the next address of this interface, which
* will be an alias.
* Do not output RIP or Router-Discovery packets via aliases.
*/
bcopy(&ifs0, &ifs, sizeof(ifs));
ifs0.int_state |= (IS_ALIAS | IS_NO_RIP | IS_NO_RDISC);
if (INFO_IFA(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOADDR))
msglog("%s has no address",
sdl->sdl_data);
ifs.int_name);
complaints |= COMP_NOADDR;
}
continue;
@ -559,16 +774,13 @@ ifinit(void)
if (INFO_IFA(&info)->sa_family != AF_INET) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOT_INET))
trace_act("%s: not AF_INET\n",
sdl->sdl_data);
trace_act("%s: not AF_INET",
ifs.int_name);
complaints |= COMP_NOT_INET;
}
continue;
}
bcopy(&ifs0, &ifs, sizeof(ifs0));
ifs0.int_state |= IS_ALIAS; /* next will be an alias */
ifs.int_addr = S_ADDR(INFO_IFA(&info));
if (ntohl(ifs.int_addr)>>24 == 0
@ -576,41 +788,23 @@ ifinit(void)
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_BADADDR))
msglog("%s has a bad address",
sdl->sdl_data);
ifs.int_name);
complaints |= COMP_BADADDR;
}
continue;
}
if (ifs.int_if_flags & IFF_BROADCAST) {
if (INFO_MASK(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOMASK))
msglog("%s has no netmask",
sdl->sdl_data);
complaints |= COMP_NOMASK;
}
continue;
}
if (ifs.int_if_flags & IFF_LOOPBACK) {
ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC;
ifs.int_dstaddr = ifs.int_addr;
ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info)));
ifs.int_ripv1_mask = ifs.int_mask;
ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
ifs.int_std_mask = std_mask(ifs.int_addr);
if (ifs.int_mask != ifs.int_std_mask)
ifs.int_state |= IS_SUBNET;
if (INFO_BRD(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOBADR))
msglog("%s has no"
" broadcast address",
sdl->sdl_data);
complaints |= COMP_NOBADR;
}
continue;
ifs.int_mask = HOST_MASK;
ifs.int_ripv1_mask = HOST_MASK;
ifs.int_std_mask = std_mask(ifs.int_dstaddr);
ifs.int_net = ntohl(ifs.int_dstaddr);
if (!foundloopback) {
foundloopback = 1;
loopaddr = ifs.int_addr;
}
ifs.int_brdaddr = S_ADDR(INFO_BRD(&info));
} else if (ifs.int_if_flags & IFF_POINTOPOINT) {
if (INFO_BRD(&info) == 0
@ -619,7 +813,7 @@ ifinit(void)
if (!(prev_complaints & COMP_NODST))
msglog("%s has a bad"
" destination address",
sdl->sdl_data);
ifs.int_name);
complaints |= COMP_NODST;
}
continue;
@ -631,35 +825,48 @@ ifinit(void)
if (!(prev_complaints & COMP_NODST))
msglog("%s has a bad"
" destination address",
sdl->sdl_data);
ifs.int_name);
complaints |= COMP_NODST;
}
continue;
}
ifs.int_mask = HOST_MASK;
ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info)));
ifs.int_net = ntohl(ifs.int_dstaddr);
ifs.int_std_mask = std_mask(ifs.int_dstaddr);
ifs.int_net = ntohl(ifs.int_dstaddr);
} else if (ifs.int_if_flags & IFF_LOOPBACK) {
ifs.int_state |= IS_PASSIVE | IS_NO_RIP;
ifs.int_dstaddr = ifs.int_addr;
ifs.int_mask = HOST_MASK;
ifs.int_ripv1_mask = HOST_MASK;
ifs.int_net = ntohl(ifs.int_dstaddr);
ifs.int_std_mask = std_mask(ifs.int_dstaddr);
if (!foundloopback) {
foundloopback = 1;
loopaddr = ifs.int_addr;
} else {
if (INFO_MASK(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOMASK))
msglog("%s has no netmask",
ifs.int_name);
complaints |= COMP_NOMASK;
}
continue;
}
ifs.int_dstaddr = ifs.int_addr;
ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info)));
ifs.int_ripv1_mask = ifs.int_mask;
ifs.int_std_mask = std_mask(ifs.int_addr);
ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
if (ifs.int_mask != ifs.int_std_mask)
ifs.int_state |= IS_SUBNET;
} else {
if (!(prev_complaints & COMP_WIERD))
trace_act("%s is neither broadcast"
" nor point-to-point nor loopback",
sdl->sdl_data);
complaints |= COMP_WIERD;
continue;
if (ifs.int_if_flags & IFF_BROADCAST) {
if (INFO_BRD(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints
& COMP_NOBADR))
msglog("%s has"
"no broadcast address",
ifs.int_name);
complaints |= COMP_NOBADR;
}
continue;
}
ifs.int_brdaddr = S_ADDR(INFO_BRD(&info));
}
}
ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
ifs.int_std_addr = htonl(ifs.int_std_net);
@ -672,7 +879,7 @@ ifinit(void)
* SIOCSIFMETRIC ioctl.
*/
#ifdef SIOCGIFMETRIC
strncpy(ifr.ifr_name, sdl->sdl_data, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name));
if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) {
DBGERR(1, "ioctl(SIOCGIFMETRIC)");
ifs.int_metric = 0;
@ -688,7 +895,7 @@ ifinit(void)
&& iff_alive(ifs.int_if_flags)) {
complaints |= COMP_BAD_METRIC;
msglog("%s has a metric of %d",
sdl->sdl_data, ifs.int_metric);
ifs.int_name, ifs.int_metric);
}
}
@ -697,9 +904,9 @@ ifinit(void)
* Start it over if it now is to somewhere else, as happens
* frequently with PPP and SLIP.
*/
ifp = ifwithname(sdl->sdl_data, ((ifs.int_state & IS_ALIAS)
? ifs.int_addr
: 0));
ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS)
? ifs.int_addr
: 0));
if (ifp != 0) {
ifp->int_state |= IS_CHECKED;
@ -718,7 +925,7 @@ ifinit(void)
/* Forget old information about
* a changed interface.
*/
trace_act("interface %s has changed\n",
trace_act("interface %s has changed",
ifp->int_name);
ifdel(ifp);
ifp = 0;
@ -738,7 +945,7 @@ ifinit(void)
if (iff_alive(ifp->int_if_flags)) {
msglog("interface %s to %s turned off",
ifp->int_name,
naddr_ntoa(ifp->int_addr));
naddr_ntoa(ifp->int_dstaddr));
if_bad(ifp);
ifp->int_if_flags &= ~IFF_UP_RUNNING;
}
@ -762,7 +969,7 @@ ifinit(void)
oerr = ifs.int_data.oerrors - ifp->int_data.oerrors;
#ifdef sgi
/* Through at least IRIX 6.2, PPP and SLIP
* count packets dropped by the filters.
* count packets dropped by the filters.
* But FDDI rings stuck non-operational count
* dropped packets as they wait for improvement.
*/
@ -800,18 +1007,18 @@ ifinit(void)
if (!(ifp->int_state & IS_SICK)) {
trace_act("interface %s to %s"
" sick: in=%d ierr=%d"
" out=%d oerr=%d\n",
" out=%d oerr=%d",
ifp->int_name,
naddr_ntoa(ifp->int_addr),
naddr_ntoa(ifp->int_dstaddr),
in, ierr, out, oerr);
if_sick(ifp);
continue;
}
if (!(ifp->int_state & IS_BROKE)) {
msglog("interface %s to %s bad:"
msglog("interface %s to %s broken:"
" in=%d ierr=%d out=%d oerr=%d",
ifp->int_name,
naddr_ntoa(ifp->int_addr),
naddr_ntoa(ifp->int_dstaddr),
in, ierr, out, oerr);
if_bad(ifp);
}
@ -831,73 +1038,76 @@ ifinit(void)
if (!iff_alive(ifs.int_if_flags))
continue;
/* See if it duplicates an existing interface.
/* If it duplicates an existing interface,
* complain about it, mark the other one
* duplicated, and forget this one.
*/
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_mask != ifs.int_mask)
continue;
if (((ifp->int_addr != ifs.int_addr
&& ifs.int_mask != HOST_MASK)
|| (ifp->int_dstaddr != ifs.int_dstaddr
&& ifs.int_mask == HOST_MASK)))
continue;
if (!iff_alive(ifp->int_if_flags))
continue;
/* Let one of our real interfaces be marked
* passive.
ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask,
ifs.int_if_flags);
if (ifp != 0) {
/* Ignore duplicates of itself, caused by having
* IP aliases on the same network.
*/
if ((ifp->int_state & IS_PASSIVE)
&& !(ifp->int_state & IS_EXTERNAL))
if (!strcmp(ifp->int_name, ifs.int_name))
continue;
/* It does duplicate an existing interface,
* so complain about it, mark the other one
* duplicated, and for get this one.
*/
if (!(prev_complaints & COMP_DUP)) {
complaints |= COMP_DUP;
msglog("%s is duplicated by %s at %s",
sdl->sdl_data, ifp->int_name,
naddr_ntoa(ifp->int_addr));
msglog("%s (%s%s%s) is duplicated by"
" %s (%s%s%s)",
ifs.int_name,
addrname(ifs.int_addr,ifs.int_mask,1),
((ifs.int_if_flags & IFF_POINTOPOINT)
? "-->" : ""),
((ifs.int_if_flags & IFF_POINTOPOINT)
? naddr_ntoa(ifs.int_dstaddr) : ""),
ifp->int_name,
addrname(ifp->int_addr,ifp->int_mask,1),
((ifp->int_if_flags & IFF_POINTOPOINT)
? "-->" : ""),
((ifp->int_if_flags & IFF_POINTOPOINT)
? naddr_ntoa(ifp->int_dstaddr) : ""));
}
ifp->int_state |= IS_DUP;
break;
}
if (ifp != 0)
continue;
}
/* It is new and ok. So make it real
*/
strncpy(ifs.int_name, sdl->sdl_data,
MIN(sizeof(ifs.int_name)-1, sdl->sdl_nlen));
get_parms(&ifs);
if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST))
&& !(ifs.int_state & IS_PASSIVE)) {
trace_act("%s is neither broadcast, point-to-point,"
" nor loopback",
ifs.int_name);
if (!(ifs.int_state & IFF_MULTICAST))
ifs.int_state |= IS_NO_RDISC;
}
/* Add it to the list of interfaces
/* It is new and ok. Add it to the list of interfaces
*/
ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit");
bcopy(&ifs, ifp, sizeof(*ifp));
if (ifnet != 0) {
ifp->int_next = ifnet;
ifnet->int_prev = ifp;
}
ifnet = ifp;
get_parms(ifp);
if_link(ifp);
trace_if("Add", ifp);
/* Notice likely bad netmask.
*/
if (!(prev_complaints & COMP_NETMASK)
&& !(ifp->int_if_flags & IFF_POINTOPOINT)) {
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
&& ifp->int_addr != RIP_DEFAULT) {
for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
if (ifp1->int_mask == ifp->int_mask)
continue;
if (ifp1->int_if_flags & IFF_POINTOPOINT)
continue;
if (on_net(ifp->int_addr,
if (ifp1->int_dstaddr == RIP_DEFAULT)
continue;
if (on_net(ifp->int_dstaddr,
ifp1->int_net, ifp1->int_mask)
|| on_net(ifp1->int_addr,
|| on_net(ifp1->int_dstaddr,
ifp->int_net, ifp->int_mask)) {
msglog("possible netmask problem"
" betwen %s:%s and %s:%s",
" between %s:%s and %s:%s",
ifp->int_name,
addrname(htonl(ifp->int_net),
ifp->int_mask, 1),
@ -909,20 +1119,21 @@ ifinit(void)
}
}
/* Count the # of directly connected networks.
*/
if (!(ifp->int_state & IS_ALIAS)) {
/* Count the # of directly connected networks.
*/
if (!(ifp->int_if_flags & IFF_LOOPBACK))
tot_interfaces++;
if (!IS_RIP_OFF(ifp->int_state))
rip_interfaces++;
}
if_ok_rdisc(ifp);
rip_on(ifp);
/* turn on router discovery and RIP If needed */
if_ok_rdisc(ifp);
rip_on(ifp);
}
}
/* If we are multi-homed and have at least one interface
/* If we are multi-homed and have at least two interfaces
* listening to RIP, then output by default.
*/
if (!supplier_set && rip_interfaces > 1)
@ -960,7 +1171,7 @@ ifinit(void)
/* Forget any interfaces that have disappeared.
*/
if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
trace_act("interface %s has disappeared\n",
trace_act("interface %s has disappeared",
ifp->int_name);
ifdel(ifp);
continue;
@ -984,7 +1195,8 @@ ifinit(void)
* after any dead interfaces have been deleted, which
* might affect routes for point-to-point links.
*/
addrouteforif(ifp);
if (!addrouteforif(ifp))
continue;
/* Add routes to the local end of point-to-point interfaces
* using loopback.
@ -1081,7 +1293,7 @@ check_net_syn(struct interface *ifp)
* Create route to other end if a point-to-point link,
* otherwise a route to this (sub)network.
*/
void
int /* 0=bad interface */
addrouteforif(struct interface *ifp)
{
struct rt_entry *rt;
@ -1091,7 +1303,7 @@ addrouteforif(struct interface *ifp)
/* skip sick interfaces
*/
if (ifp->int_state & IS_BROKE)
return;
return 0;
/* If the interface on a subnet, then install a RIPv1 route to
* the network as well (unless it is sick).
@ -1099,28 +1311,18 @@ addrouteforif(struct interface *ifp)
if (ifp->int_state & IS_SUBNET)
check_net_syn(ifp);
if (ifp->int_state & IS_REMOTE) {
dst = ifp->int_addr;
gate = ifp->int_dstaddr;
/* If we are going to send packets to the gateway,
* it must be reachable using our physical interfaces
*/
if (!(ifp->int_state && IS_EXTERNAL)
&& !rtfind(ifp->int_dstaddr)
&& ifp->int_transitions == 0) {
msglog("unreachable gateway %s in "
_PATH_GATEWAYS" entry %s",
naddr_ntoa(gate), ifp->int_name);
return;
}
gate = ifp->int_addr;
dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))
? ifp->int_dstaddr
: htonl(ifp->int_net));
} else {
dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT
| IFF_LOOPBACK))
? ifp->int_dstaddr
: htonl(ifp->int_net));
gate = ifp->int_addr;
}
/* If we are going to send packets to the gateway,
* it must be reachable using our physical interfaces
*/
if ((ifp->int_state & IS_REMOTE)
&& !(ifp->int_state & IS_EXTERNAL)
&& !check_remote(ifp))
return 0;
/* We are finished if the correct main interface route exists.
* The right route must be for the right interface, not synthesized
@ -1145,10 +1347,12 @@ addrouteforif(struct interface *ifp)
}
if (rt == 0) {
if (ifp->int_transitions++ > 0)
trace_act("re-install interface %s\n",
trace_act("re-install interface %s",
ifp->int_name);
rtadd(dst, ifp->int_mask, gate, gate,
ifp->int_metric, 0, RS_IF, ifp);
}
return 1;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: input.c,v 1.18 1996/09/24 16:24:14 christos Exp $ */
/* $NetBSD: input.c,v 1.19 1997/02/03 22:02:56 christos Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -36,25 +36,39 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: input.c,v 1.18 1996/09/24 16:24:14 christos Exp $";
static char rcsid[] = "$NetBSD: input.c,v 1.19 1997/02/03 22:02:56 christos Exp $";
#endif
#include "defs.h"
static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
static void input(struct sockaddr_in *, struct interface *, struct interface *,
struct rip *, int);
static void input_route(struct interface *, naddr,
naddr, naddr, naddr, struct netinfo *);
static int ck_passwd(struct interface *, struct rip *, void *,
naddr, struct msg_limit *);
/* process RIP input
*/
void
read_rip(int sock,
struct interface *ifp)
struct interface *sifp)
{
struct sockaddr_in from;
struct interface *aifp;
int fromlen, cc;
union pkt_buf inbuf;
#ifdef USE_PASSIFNAME
static struct msg_limit bad_name;
struct {
char ifname[IFNAMSIZ];
union pkt_buf pbuf;
} inbuf;
#else
struct {
union pkt_buf pbuf;
} inbuf;
#endif
for (;;) {
@ -70,7 +84,48 @@ read_rip(int sock,
logbad(1,"impossible recvfrom(rip) fromlen=%d",
fromlen);
input(&from, ifp, &inbuf.rip, cc);
/* aifp is the "authenticated" interface via which the packet
* arrived. In fact, it is only the interface on which
* the packet should have arrived based on is source
* address.
* sifp is interface associated with the socket through which
* the packet was received.
*/
#ifdef USE_PASSIFNAME
if ((cc -= sizeof(inbuf.ifname)) < 0)
logbad(0,"missing USE_PASSIFNAME; only %d bytes",
cc+sizeof(inbuf.ifname));
/* check the remote interfaces first */
for (aifp = remote_if; aifp; aifp = aifp->int_rlink) {
if (aifp->int_addr == from.sin_addr.s_addr)
break;
}
if (aifp == 0) {
aifp = ifwithname(inbuf.ifname, 0);
if (aifp == 0) {
msglim(&bad_name, from.sin_addr.s_addr,
"impossible interface name %.*s",
IFNAMSIZ, inbuf.ifname);
} else if (((aifp->int_if_flags & IFF_POINTOPOINT)
&& aifp->int_dstaddr!=from.sin_addr.s_addr)
|| (!(aifp->int_if_flags & IFF_POINTOPOINT)
&& !on_net(from.sin_addr.s_addr,
aifp->int_net,
aifp->int_mask))) {
/* If it came via the wrong interface, do not
* trust it.
*/
aifp = 0;
}
}
#else
aifp = iflookup(from.sin_addr.s_addr);
#endif
if (sifp == 0)
sifp = aifp;
input(&from, sifp, aifp, &inbuf.pbuf.rip, cc);
}
}
@ -79,58 +134,53 @@ read_rip(int sock,
*/
static void
input(struct sockaddr_in *from, /* received from this IP address */
struct interface *sifp, /* interface by which it arrived */
struct interface *sifp, /* interface of incoming socket */
struct interface *aifp, /* "authenticated" interface */
struct rip *rip,
int size)
int cc)
{
# define FROM_NADDR from->sin_addr.s_addr
static naddr use_auth, bad_len, bad_mask;
static naddr unk_router, bad_router, bad_nhop;
static struct msg_limit use_auth, bad_len, bad_mask;
static struct msg_limit unk_router, bad_router, bad_nhop;
struct interface *aifp; /* interface if via 1 hop */
struct rt_entry *rt;
struct netinfo *n, *lim;
struct interface *ifp1;
naddr gate, mask, v1_mask, dst, ddst_h;
struct auth *ap;
int i;
aifp = iflookup(from->sin_addr.s_addr);
if (sifp == 0)
sifp = aifp;
/* Notice when we hear from a remote gateway
*/
if (aifp != 0
&& (aifp->int_state & IS_REMOTE))
aifp->int_act_time = now.tv_sec;
if (sifp != 0)
sifp->int_state |= IS_ACTIVE;
trace_rip("Recv", "from", from, sifp, rip, size);
trace_rip("Recv", "from", from, sifp, rip, cc);
if (rip->rip_vers == 0) {
if (from->sin_addr.s_addr != bad_router)
msglog("RIP version 0, cmd %d, packet received"
" from %s",
rip->rip_cmd, naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"RIP version 0, cmd %d, packet received from %s",
rip->rip_cmd, naddr_ntoa(FROM_NADDR));
return;
} else if (rip->rip_vers > RIPv2) {
rip->rip_vers = RIPv2;
}
if (size > MAXPACKETSIZE) {
if (from->sin_addr.s_addr != bad_router)
msglog("packet at least %d bytes too long received"
" from %s",
size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
if (cc > OVER_MAXPACKETSIZE) {
msglim(&bad_router, FROM_NADDR,
"packet at least %d bytes too long received from %s",
cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
return;
}
n = rip->rip_nets;
lim = (struct netinfo *)((char*)rip + size);
lim = (struct netinfo *)((char*)rip + cc);
/* Notice authentication.
* As required by section 4.2 in RFC 1723, discard authenticated
* RIPv2 messages, but only if configured for that silliness.
*
* RIPv2 authentication is lame, since snooping on the wire makes
* its simple passwords evident. Also, why authenticate queries?
* RIPv2 authentication is lame. Why authenticate queries?
* Why should a RIPv2 implementation with authentication disabled
* not be able to listen to RIPv2 packets with authenication, while
* RIPv1 systems will listen? Crazy!
@ -138,54 +188,92 @@ input(struct sockaddr_in *from, /* received from this IP address */
if (!auth_ok
&& rip->rip_vers == RIPv2
&& n < lim && n->n_family == RIP_AF_AUTH) {
if (from->sin_addr.s_addr != use_auth)
msglog("RIPv2 message with authentication"
" from %s discarded",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
trace_pkt("discard authenticated RIPv2 message\n");
msglim(&use_auth, FROM_NADDR,
"RIPv2 message with authentication from %s discarded",
naddr_ntoa(FROM_NADDR));
return;
}
switch (rip->rip_cmd) {
case RIPCMD_REQUEST:
/* For mere requests, be a little sloppy about the source
*/
if (aifp == 0)
aifp = sifp;
/* Are we talking to ourself or a remote gateway?
*/
ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
if (ifp1) {
if (ifp1->int_state & IS_REMOTE) {
/* remote gateway */
aifp = ifp1;
if (check_remote(aifp)) {
aifp->int_act_time = now.tv_sec;
(void)if_ok(aifp, "remote ");
}
} else if (from->sin_port == htons(RIP_PORT)) {
trace_pkt(" discard our own RIP request");
return;
}
}
/* did the request come from a router?
*/
if (from->sin_port == htons(RIP_PORT)) {
/* yes, ignore it if RIP is off so that it does not
* depend on us.
/* yes, ignore the request if RIP is off so that
* the router does not depend on us.
*/
if (rip_sock < 0) {
trace_pkt("ignore request while RIP off\n");
return;
}
/* Ignore the request if we talking to ourself
* (and not a remote gateway).
*/
if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
trace_pkt("discard our own RIP request\n");
if (rip_sock < 0
|| (aifp != 0
&& IS_RIP_OUT_OFF(aifp->int_state))) {
trace_pkt(" discard request while RIP off");
return;
}
}
/* According to RFC 1723, we should ignore unathenticated
* queries. That is too silly to bother with. Sheesh!
* Are forwarding tables supposed to be secret? When
* a bad guy can infer them with test traffic?
* Are forwarding tables supposed to be secret, when
* a bad guy can infer them with test traffic? When RIP
* is still the most common router-discovery protocol
* and so hosts need to send queries that will be answered?
* What about `rtquery`?
* Maybe on firewalls you'd care, but not enough to
* give up the diagnostic facilities of remote probing.
*/
if (n >= lim
|| size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
if (from->sin_addr.s_addr != bad_len)
msglog("request of bad length (%d) from %s",
size, naddr_ntoa(FROM_NADDR));
bad_len = from->sin_addr.s_addr;
if (n >= lim) {
msglim(&bad_len, FROM_NADDR, "empty request from %s",
naddr_ntoa(FROM_NADDR));
return;
}
for (; n < lim; n++) {
n->n_metric = ntohl(n->n_metric);
if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
msglim(&bad_len, FROM_NADDR,
"request of bad length (%d) from %s",
cc, naddr_ntoa(FROM_NADDR));
}
if (rip->rip_vers == RIPv2
&& (aifp == 0 || (aifp->int_state & IS_NO_RIPV1_OUT))) {
v12buf.buf->rip_vers = RIPv2;
/* If we have a secret but it is a cleartext secret,
* do not disclose our secret unless the other guy
* already knows it.
*/
ap = find_auth(aifp);
if (ap != 0 && ap->type == RIP_AUTH_PW
&& n->n_family == RIP_AF_AUTH
&& !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
ap = 0;
} else {
v12buf.buf->rip_vers = RIPv1;
ap = 0;
}
clr_ws_buf(&v12buf, ap);
do {
NTOHL(n->n_metric);
/* A single entry with family RIP_AF_UNSPEC and
* metric HOPCNT_INFINITY means "all routes".
@ -194,17 +282,16 @@ input(struct sockaddr_in *from, /* received from this IP address */
* (i.e. a query).
*/
if (n->n_family == RIP_AF_UNSPEC
&& n->n_metric == HOPCNT_INFINITY
&& n == rip->rip_nets
&& n+1 == lim) {
&& n->n_metric == HOPCNT_INFINITY) {
if (from->sin_port != htons(RIP_PORT)) {
/* Answer a query from a utility
* program with all we know.
*/
supply(from, sifp, OUT_QUERY, 0,
rip->rip_vers);
supply(from, aifp, OUT_QUERY, 0,
rip->rip_vers, ap != 0);
return;
}
/* A router trying to prime its tables.
* Filter the answer in the about same way
* broadcasts are filtered.
@ -217,91 +304,115 @@ input(struct sockaddr_in *from, /* received from this IP address */
* the remote router from getting the wrong
* initial idea of the routes we send.
*/
if (!supplier
|| aifp == 0
|| (aifp->int_state & IS_PASSIVE)
|| (aifp->int_state & IS_ALIAS)
|| ((aifp->int_state & IS_NO_RIPV1_OUT)
&& (aifp->int_state&IS_NO_RIPV2_OUT)))
if (aifp == 0) {
trace_pkt("ignore distant router");
return;
}
if (!supplier
|| IS_RIP_OFF(aifp->int_state)) {
trace_pkt("ignore; not supplying");
return;
}
supply(from, aifp, OUT_UNICAST, 0,
(aifp->int_state&IS_NO_RIPV1_OUT)
? RIPv2 : RIPv1);
? RIPv2 : RIPv1,
ap != 0);
return;
}
/* Ignore authentication */
if (n->n_family == RIP_AF_AUTH)
continue;
if (n->n_family != RIP_AF_INET) {
if (from->sin_addr.s_addr != bad_router)
msglog("request from %s"
" for unsupported (af %d) %s",
naddr_ntoa(FROM_NADDR),
ntohs(n->n_family),
naddr_ntoa(n->n_dst));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"request from %s for unsupported (af"
" %d) %s",
naddr_ntoa(FROM_NADDR),
ntohs(n->n_family),
naddr_ntoa(n->n_dst));
return;
}
/* We are being asked about a specific destination.
*/
dst = n->n_dst;
if (!check_dst(dst)) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad queried destination"
" %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"bad queried destination %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
return;
}
/* decide what mask was intended */
if (rip->rip_vers == RIPv1
|| 0 == (mask = ntohl(n->n_mask))
|| 0 != (ntohl(dst) & ~mask))
mask = ripv1_mask_host(dst,sifp);
mask = ripv1_mask_host(dst, aifp);
/* try to find the answer */
rt = rtget(dst, mask);
if (!rt && dst != RIP_DEFAULT)
rt = rtfind(n->n_dst);
n->n_tag = 0;
n->n_nhop = 0;
if (rip->rip_vers == RIPv1) {
n->n_mask = 0;
} else {
n->n_mask = mask;
}
if (v12buf.buf->rip_vers != RIPv1)
v12buf.n->n_mask = mask;
if (rt == 0) {
n->n_metric = HOPCNT_INFINITY;
/* we do not have the answer */
v12buf.n->n_metric = HOPCNT_INFINITY;
} else {
n->n_metric = rt->rt_metric+1;
n->n_metric += (sifp!=0)?sifp->int_metric : 1;
if (n->n_metric > HOPCNT_INFINITY)
n->n_metric = HOPCNT_INFINITY;
if (rip->rip_vers != RIPv1) {
n->n_tag = rt->rt_tag;
if (sifp != 0
/* we have the answer, so compute the
* right metric and next hop.
*/
v12buf.n->n_family = RIP_AF_INET;
v12buf.n->n_dst = dst;
v12buf.n->n_metric = (rt->rt_metric+1
+ ((aifp!=0)
? aifp->int_metric
: 1));
if (v12buf.n->n_metric > HOPCNT_INFINITY)
v12buf.n->n_metric = HOPCNT_INFINITY;
if (v12buf.buf->rip_vers != RIPv1) {
v12buf.n->n_tag = rt->rt_tag;
v12buf.n->n_mask = mask;
if (aifp != 0
&& on_net(rt->rt_gate,
sifp->int_net,
sifp->int_mask)
&& rt->rt_gate != sifp->int_addr)
n->n_nhop = rt->rt_gate;
aifp->int_net,
aifp->int_mask)
&& rt->rt_gate != aifp->int_addr)
v12buf.n->n_nhop = rt->rt_gate;
}
}
HTONL(n->n_metric);
}
/* Answer about specific routes.
* Only answer a router if we are a supplier
* to keep an unwary host that is just starting
* from picking us an a router.
HTONL(v12buf.n->n_metric);
/* Stop paying attention if we fill the output buffer.
*/
if (++v12buf.n >= v12buf.lim)
break;
} while (++n < lim);
/* Send the answer about specific routes.
*/
rip->rip_cmd = RIPCMD_RESPONSE;
rip->rip_res1 = 0;
if (rip->rip_vers != RIPv1)
rip->rip_vers = RIPv2;
if (ap != 0 && ap->type == RIP_AUTH_MD5)
end_md5_auth(&v12buf, ap);
if (from->sin_port != htons(RIP_PORT)) {
/* query */
(void)output(OUT_QUERY, from, sifp, rip, size);
(void)output(OUT_QUERY, from, aifp,
v12buf.buf,
((char *)v12buf.n - (char*)v12buf.buf));
} else if (supplier) {
(void)output(OUT_UNICAST, from, sifp, rip, size);
(void)output(OUT_UNICAST, from, aifp,
v12buf.buf,
((char *)v12buf.n - (char*)v12buf.buf));
} else {
/* Only answer a router if we are a supplier
* to keep an unwary host that is just starting
* from picking us an a router.
*/
;
}
return;
@ -319,30 +430,32 @@ input(struct sockaddr_in *from, /* received from this IP address */
return;
}
if (rip->rip_cmd == RIPCMD_TRACEON) {
rip->rip_tracefile[size-4] = '\0';
trace_on((char*)rip->rip_tracefile, 0);
rip->rip_tracefile[cc-4] = '\0';
set_tracefile((char*)rip->rip_tracefile,
"trace command: %s\n", 0);
} else {
trace_off("tracing turned off by %s\n",
trace_off("tracing turned off by %s",
naddr_ntoa(FROM_NADDR));
}
return;
case RIPCMD_RESPONSE:
if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
if (from->sin_addr.s_addr != bad_len)
msglog("response of bad length (%d) from %s",
size, naddr_ntoa(FROM_NADDR));
bad_len = from->sin_addr.s_addr;
if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
msglim(&bad_len, FROM_NADDR,
"response of bad length (%d) from %s",
cc, naddr_ntoa(FROM_NADDR));
}
/* verify message came from a router */
if (from->sin_port != ntohs(RIP_PORT)) {
trace_pkt("discard RIP response from unknown port\n");
msglim(&bad_router, FROM_NADDR,
" discard RIP response from unknown port"
" %d", from->sin_port);
return;
}
if (rip_sock < 0) {
trace_pkt("discard response while RIP off\n");
trace_pkt(" discard response while RIP off");
return;
}
@ -351,50 +464,47 @@ input(struct sockaddr_in *from, /* received from this IP address */
ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
if (ifp1) {
if (ifp1->int_state & IS_REMOTE) {
if (ifp1->int_state & IS_PASSIVE) {
msglog("bogus input from %s on"
" supposedly passive %s",
naddr_ntoa(FROM_NADDR),
ifp1->int_name);
} else {
ifp1->int_act_time = now.tv_sec;
if (if_ok(ifp1, "remote "))
addrouteforif(ifp1);
/* remote gateway */
aifp = ifp1;
if (check_remote(aifp)) {
aifp->int_act_time = now.tv_sec;
(void)if_ok(aifp, "remote ");
}
} else {
trace_pkt("discard our own RIP response\n");
trace_pkt(" discard our own RIP response");
return;
}
return;
}
/* Check the router from which message originated. We accept
* routing packets from routers directly connected via
* broadcast or point-to-point networks, and from
/* Accept routing packets from routers directly connected
* via broadcast or point-to-point networks, and from
* those listed in /etc/gateways.
*/
if (!aifp) {
if (from->sin_addr.s_addr != unk_router)
msglog("discard packet from unknown router %s"
" or via unidentified interface",
naddr_ntoa(FROM_NADDR));
unk_router = from->sin_addr.s_addr;
if (aifp == 0) {
msglim(&unk_router, FROM_NADDR,
" discard response from %s"
" via unexpected interface",
naddr_ntoa(FROM_NADDR));
return;
}
if (aifp->int_state & IS_PASSIVE) {
trace_act("discard packet from %s"
" via passive interface %s\n",
naddr_ntoa(FROM_NADDR),
aifp->int_name);
if (IS_RIP_IN_OFF(aifp->int_state)) {
trace_pkt(" discard RIPv%d response"
" via disabled interface %s",
rip->rip_vers, aifp->int_name);
return;
}
if (n >= lim) {
msglim(&bad_len, FROM_NADDR, "empty response from %s",
naddr_ntoa(FROM_NADDR));
return;
}
/* Check required version
*/
if (((aifp->int_state & IS_NO_RIPV1_IN)
&& rip->rip_vers == RIPv1)
|| ((aifp->int_state & IS_NO_RIPV2_IN)
&& rip->rip_vers != RIPv1)) {
trace_pkt("discard RIPv%d response\n",
trace_pkt(" discard RIPv%d response",
rip->rip_vers);
return;
}
@ -402,37 +512,38 @@ input(struct sockaddr_in *from, /* received from this IP address */
/* Ignore routes via dead interface.
*/
if (aifp->int_state & IS_BROKE) {
trace_pkt("discard response via broken interface %s\n",
trace_pkt("%sdiscard response via broken interface %s",
aifp->int_name);
return;
}
/* Authenticate the packet if we have a secret.
/* If the interface cares, ignore bad routers.
* Trace but do not log this problem, because where it
* happens, it happens frequently.
*/
if (aifp->int_passwd[0] != '\0') {
if (n >= lim
|| n->n_family != RIP_AF_AUTH
|| ((struct netauth*)n)->a_type != RIP_AUTH_PW) {
if (from->sin_addr.s_addr != use_auth)
msglog("missing password from %s",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
return;
} else if (0 != bcmp(((struct netauth*)n)->au.au_pw,
aifp->int_passwd,
sizeof(aifp->int_passwd))) {
if (from->sin_addr.s_addr != use_auth)
msglog("bad password from %s",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
return;
if (aifp->int_state & IS_DISTRUST) {
struct tgate *tg = tgates;
while (tg->tgate_addr != FROM_NADDR) {
tg = tg->tgate_next;
if (tg == 0) {
trace_pkt(" discard RIP response"
" from untrusted router %s",
naddr_ntoa(FROM_NADDR));
return;
}
}
}
auth_ok:
/* Authenticate the packet if we have a secret.
* If we do not have any secrets, ignore the error in
* RFC 1723 and accept it regardless.
*/
if (aifp->int_auth[0].type != RIP_AUTH_NONE
&& rip->rip_vers != RIPv1
&& !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
return;
for (; n < lim; n++) {
do {
if (n->n_family == RIP_AF_AUTH)
continue;
@ -441,39 +552,35 @@ input(struct sockaddr_in *from, /* received from this IP address */
if (n->n_family != RIP_AF_INET
&& (n->n_family != RIP_AF_UNSPEC
|| dst != RIP_DEFAULT)) {
if (from->sin_addr.s_addr != bad_router)
msglog("route from %s to unsupported"
" address family %d,"
" destination %s",
naddr_ntoa(FROM_NADDR),
n->n_family,
naddr_ntoa(dst));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"route from %s to unsupported"
" address family=%d destination=%s",
naddr_ntoa(FROM_NADDR),
n->n_family,
naddr_ntoa(dst));
continue;
}
if (!check_dst(dst)) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad destination %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"bad destination %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
return;
}
if (n->n_metric == 0
|| n->n_metric > HOPCNT_INFINITY) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad metric %d from %s"
" for destination %s",
n->n_metric,
naddr_ntoa(FROM_NADDR),
naddr_ntoa(dst));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"bad metric %d from %s"
" for destination %s",
n->n_metric,
naddr_ntoa(FROM_NADDR),
naddr_ntoa(dst));
return;
}
/* Notice the next-hop.
*/
gate = from->sin_addr.s_addr;
gate = FROM_NADDR;
if (n->n_nhop != 0) {
if (rip->rip_vers == RIPv2) {
n->n_nhop = 0;
@ -484,14 +591,13 @@ input(struct sockaddr_in *from, /* received from this IP address */
&& check_dst(n->n_nhop)) {
gate = n->n_nhop;
} else {
if (bad_nhop != from->sin_addr.s_addr)
msglog("router %s to %s has"
" bad next hop %s",
naddr_ntoa(FROM_NADDR),
naddr_ntoa(dst),
naddr_ntoa(n->n_nhop));
bad_nhop = from->sin_addr.s_addr;
n->n_nhop = 0;
msglim(&bad_nhop, FROM_NADDR,
"router %s to %s"
" has bad next hop %s",
naddr_ntoa(FROM_NADDR),
naddr_ntoa(dst),
naddr_ntoa(n->n_nhop));
n->n_nhop = 0;
}
}
}
@ -500,14 +606,12 @@ input(struct sockaddr_in *from, /* received from this IP address */
|| 0 == (mask = ntohl(n->n_mask))) {
mask = ripv1_mask_host(dst,aifp);
} else if ((ntohl(dst) & ~mask) != 0) {
if (bad_mask != from->sin_addr.s_addr) {
msglog("router %s sent bad netmask"
" %#x with %s",
naddr_ntoa(FROM_NADDR),
mask,
naddr_ntoa(dst));
bad_mask = from->sin_addr.s_addr;
}
msglim(&bad_mask, FROM_NADDR,
"router %s sent bad netmask"
" %#x with %s",
naddr_ntoa(FROM_NADDR),
mask,
naddr_ntoa(dst));
continue;
}
if (rip->rip_vers == RIPv1)
@ -551,9 +655,9 @@ input(struct sockaddr_in *from, /* received from this IP address */
* of the defense against RS_NET_SYN.
*/
if (have_ripv1_out
&& (v1_mask = ripv1_mask_net(dst,0)) > mask
&& (((rt = rtget(dst,mask)) == 0
|| !(rt->rt_state & RS_NET_SYN)))) {
|| !(rt->rt_state & RS_NET_SYN)))
&& (v1_mask = ripv1_mask_net(dst,0)) > mask) {
ddst_h = v1_mask & -v1_mask;
i = (v1_mask & ~mask)/ddst_h;
if (i >= 511) {
@ -582,9 +686,10 @@ input(struct sockaddr_in *from, /* received from this IP address */
break;
dst = htonl(ntohl(dst) + ddst_h);
}
}
} while (++n < lim);
break;
}
#undef FROM_NADDR
}
@ -613,7 +718,8 @@ input_route(struct interface *ifp,
*/
ifp1 = ifwithaddr(dst, 1, 1);
if (ifp1 != 0
&& !(ifp1->int_state & IS_BROKE))
&& (!(ifp1->int_state & IS_BROKE)
|| (ifp1->int_state & IS_PASSIVE)))
return;
/* Look for the route in our table.
@ -699,12 +805,16 @@ input_route(struct interface *ifp,
/* This is an update for a spare route.
* Finished if the route is unchanged.
* Forget it if it has gone bad.
*/
if (rts->rts_gate == gate
&& old_metric == n->n_metric
&& rts->rts_tag == n->n_tag) {
rts->rts_time = new_time;
return;
} else if (n->n_metric == HOPCNT_INFINITY) {
rts_delete(rt, rts);
return;
}
} else {
@ -731,7 +841,6 @@ input_route(struct interface *ifp,
}
trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
rts->rts_gate = gate;
rts->rts_router = from;
rts->rts_metric = n->n_metric;
@ -742,3 +851,74 @@ input_route(struct interface *ifp,
/* try to switch to a better route */
rtswitch(rt, rts);
}
static int /* 0 if bad */
ck_passwd(struct interface *aifp,
struct rip *rip,
void *lim,
naddr from,
struct msg_limit *use_authp)
{
# define NA (rip->rip_auths)
struct netauth *na2;
struct auth *ap;
MD5_CTX md5_ctx;
u_char hash[RIP_AUTH_PW_LEN];
int i;
if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) {
msglim(use_authp, from, "missing password from %s",
naddr_ntoa(from));
return 0;
}
/* accept any current (+/- 24 hours) password
*/
for (ap = aifp->int_auth, i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
if (ap->type != NA->a_type
|| (u_long)ap->start > (u_long)clk.tv_sec+DAY
|| (u_long)ap->end+DAY < (u_long)clk.tv_sec)
continue;
if (NA->a_type == RIP_AUTH_PW) {
if (!bcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN))
return 1;
} else {
/* accept MD5 secret with the right key ID
*/
if (NA->au.a_md5.md5_keyid != ap->keyid)
continue;
na2 = (struct netauth *)((char *)(NA+1)
+ NA->au.a_md5.md5_pkt_len);
if (NA->au.a_md5.md5_pkt_len % sizeof(*NA) != 0
|| lim < (void *)(na2+1)) {
msglim(use_authp, from,
"bad MD5 RIP-II pkt length %d from %s",
NA->au.a_md5.md5_pkt_len,
naddr_ntoa(from));
return 0;
}
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, (u_char *)NA,
(char *)na2->au.au_pw - (char *)NA);
MD5Update(&md5_ctx,
(u_char *)ap->key, sizeof(ap->key));
MD5Final(hash, &md5_ctx);
if (na2->a_family != RIP_AF_AUTH
|| na2->a_type != 1
|| NA->au.a_md5.md5_auth_len != RIP_AUTH_PW_LEN
|| bcmp(hash, na2->au.au_pw, sizeof(hash)))
return 0;
return 1;
}
}
msglim(use_authp, from, "bad password from %s",
naddr_ntoa(from));
return 0;
#undef NA
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.15 1996/09/24 16:24:15 christos Exp $ */
/* $NetBSD: main.c,v 1.16 1997/02/03 22:02:58 christos Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -39,7 +39,7 @@ char copyright[] =
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: main.c,v 1.15 1996/09/24 16:24:15 christos Exp $";
static char rcsid[] = "$NetBSD: main.c,v 1.16 1997/02/03 22:02:58 christos Exp $";
#endif
#include "defs.h"
@ -98,12 +98,17 @@ main(int argc,
struct timeval wtime, t2;
time_t dt;
fd_set ibits;
naddr p_addr, p_mask;
naddr p_net, p_mask;
struct interface *ifp;
struct parm parm;
char *tracename = 0;
/* Some shells are badly broken and send SIGHUP to backgrounded
* processes.
*/
signal(SIGHUP, SIG_IGN);
openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
ftrace = stdout;
@ -170,7 +175,7 @@ main(int argc,
break;
case 'F': /* minimal routes for SLIP */
n = HOPCNT_INFINITY-2;
n = FAKE_METRIC;
p = strchr(optarg,',');
if (p && *p != '\0') {
n = (int)strtoul(p+1, &q, 0);
@ -179,13 +184,13 @@ main(int argc,
&& n >= 1)
*p = '\0';
}
if (!getnet(optarg, &p_addr, &p_mask)) {
if (!getnet(optarg, &p_net, &p_mask)) {
msglog("bad network; \"-F %s\"",
optarg);
break;
}
bzero(&parm, sizeof(parm));
parm.parm_addr_h = ntohl(p_addr);
parm.parm_net = p_net;
parm.parm_mask = p_mask;
parm.parm_d_metric = n;
p = check_parms(&parm);
@ -197,10 +202,13 @@ main(int argc,
/* handle arbirary, (usually) per-interface
* parameters.
*/
p = parse_parms(optarg);
if (p != 0)
msglog("bad \"%s\" in \"%s\"",
p, optarg);
p = parse_parms(optarg, 0);
if (p != 0) {
if (strcasecmp(p,optarg))
msglog("%s in \"%s\"", p, optarg);
else
msglog("bad \"-P %s\"", optarg);
}
break;
default:
@ -214,9 +222,11 @@ main(int argc,
tracename = *argv++;
argc--;
}
if (tracename != 0 && tracename[0] == '\0')
goto usage;
if (argc != 0) {
usage:
logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]"
logbad(0, "usage: routed [-sqdghmpAt] [-T tracefile]"
" [-F net[,metric]] [-P parms]");
}
if (geteuid() != 0)
@ -253,26 +263,22 @@ usage:
signal(SIGALRM, sigalrm);
if (!background)
signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */
else
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, sigterm);
signal(SIGINT, sigterm);
signal(SIGUSR1, sigtrace_on);
signal(SIGUSR2, sigtrace_off);
/* get into the background */
if (background) {
#ifdef sgi
if (0 > _daemonize(_DF_NOCHDIR,
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
BADERR(0, "_daemonize()");
if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK),
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
BADERR(0, "_daemonize()");
#else
if (daemon(1, 1) < 0)
BADERR(0,"daemon()");
if (background && daemon(0, new_tracelevel) < 0)
BADERR(0,"daemon()");
#endif
}
mypid = getpid();
srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid));
@ -295,11 +301,13 @@ usage:
if (background && new_tracelevel == 0)
ftrace = 0;
if (tracename != 0) {
trace_on(tracename, 1);
if (new_tracelevel == 0) /* use stdout if file is bad */
new_tracelevel = 1;
strncpy(inittracename, tracename, sizeof(inittracename)-1);
set_tracefile(inittracename, "%s", -1);
} else {
tracelevel_msg("%s", -1); /* turn on tracing to stdio */
}
set_tracelevel();
bufinit();
/* initialize radix tree */
rtinit();
@ -326,8 +334,7 @@ usage:
/* Ask for routes */
rip_query();
if (!supplier)
rdisc_sol();
rdisc_sol();
/* Loop forever, listening and broadcasting.
*/
@ -343,7 +350,7 @@ usage:
dt = t2.tv_sec;
if (dt > 0)
dt -= wtime.tv_sec;
trace_act("time changed by %d sec\n", dt);
trace_act("time changed by %d sec", dt);
epoch.tv_sec += dt;
}
timevalsub(&now, &clk, &epoch);
@ -351,15 +358,13 @@ usage:
now_expire = now.tv_sec - EXPIRE_TIME;
now_garbage = now.tv_sec - GARBAGE_TIME;
/* deal with interrupts that should affect tracing */
/* deal with signals that should affect tracing */
set_tracelevel();
if (stopint != 0) {
if (supplier) {
rip_bcast(0);
rdisc_adv();
}
trace_off("exiting with signal %d\n", stopint);
rip_bcast(0);
rdisc_adv();
trace_off("exiting with signal %d", stopint);
exit(stopint | 128);
}
@ -490,13 +495,13 @@ usage:
/* ARGSUSED */
void
sigalrm(int sig)
sigalrm(int s)
{
/* Historically, SIGALRM would cause the daemon to check for
* new and broken interfaces.
*/
ifinit_timer.tv_sec = now.tv_sec;
trace_act("SIGALRM\n");
trace_act("SIGALRM");
}
@ -553,10 +558,16 @@ fix_sock(int sock,
logbad(1, "fcntl(%s) O_NONBLOCK: %s",
name, strerror(errno));
on = 1;
if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST,
&on,sizeof(on)) < 0)
if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0)
msglog("setsockopt(%s,SO_BROADCAST): %s",
name, strerror(errno));
#ifdef USE_PASSIFNAME
on = 1;
if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0)
msglog("setsockopt(%s,SO_PASSIFNAME): %s",
name, strerror(errno));
#endif
if (rbuf >= MIN_SOCKBUF) {
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&rbuf, sizeof(rbuf)) < 0)
@ -566,7 +577,7 @@ fix_sock(int sock,
for (rbuf = 60*1024; ; rbuf -= 4096) {
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&rbuf, sizeof(rbuf)) == 0) {
trace_act("RCVBUF=%d\n", rbuf);
trace_act("RCVBUF=%d", rbuf);
break;
}
if (rbuf < MIN_SOCKBUF) {
@ -625,7 +636,7 @@ rip_off(void)
if (rip_sock >= 0 && !mhome) {
trace_act("turn off RIP\n");
trace_act("turn off RIP");
(void)close(rip_sock);
rip_sock = -1;
@ -633,8 +644,9 @@ rip_off(void)
/* get non-broadcast sockets to listen to queries.
*/
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (ifp->int_rip_sock < 0
&& !(ifp->int_state & IS_ALIAS)) {
if (ifp->int_state & IS_REMOTE)
continue;
if (ifp->int_rip_sock < 0) {
addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
@ -687,11 +699,11 @@ rip_on(struct interface *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 the main RIP socket is off and it makes sense to turn it on,
* then turn it on for all of the interfaces.
*/
if (rip_interfaces > 0 && !rdisc_ok) {
trace_act("turn on RIP\n");
trace_act("turn on RIP");
/* Close all of the query sockets so that we can open
* the main socket. SO_REUSEPORT is not a solution,
@ -714,25 +726,21 @@ rip_on(struct interface *ifp)
next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (!IS_RIP_IN_OFF(ifp->int_state))
ifp->int_state &= ~IS_RIP_QUERIED;
ifp->int_query_time = NEVER;
rip_mcast_on(ifp);
}
ifinit_timer.tv_sec = now.tv_sec;
fix_select();
} else if (ifp != 0
&& ifp->int_rip_sock < 0
&& !(ifp->int_state & IS_ALIAS)) {
&& !(ifp->int_state & IS_REMOTE)
&& ifp->int_rip_sock < 0) {
/* RIP is off, so ensure there are sockets on which
* to listen for queries.
*/
ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0);
fix_select();
}
fix_select();
}
@ -791,6 +799,8 @@ timevalsub(struct timeval *t1,
}
/* put a message into the system log
*/
void
msglog(char *p, ...)
{
@ -810,6 +820,68 @@ msglog(char *p, ...)
}
/* Put a message about a bad system into the system log if
* we have not complained about it recently.
*
* It is desirable to complain about all bad systems, but not too often.
* In the worst case, it is not practical to keep track of all bad systems.
* For example, there can be many systems with the wrong password.
*/
void
msglim(struct msg_limit *lim, naddr addr, char *p, ...)
{
va_list args;
int i;
struct msg_sub *ms1, *ms;
char *p1;
va_start(args, p);
/* look for the oldest slot in the table
* or the slot for the bad router.
*/
ms = ms1 = lim->subs;
for (i = MSG_SUBJECT_N; ; i--, ms1++) {
if (i == 0) {
/* Reuse a slot at most once every 10 minutes.
*/
if (lim->reuse > now.tv_sec) {
ms = 0;
} else {
ms = ms1;
lim->reuse = now.tv_sec + 10*60;
}
break;
}
if (ms->addr == addr) {
/* Repeat a complaint about a given system at
* most once an hour.
*/
if (ms->until > now.tv_sec)
ms = 0;
break;
}
if (ms->until < ms1->until)
ms = ms1;
}
if (ms != 0) {
ms->addr = addr;
ms->until = now.tv_sec + 60*60; /* 60 minutes */
trace_flush();
for (p1 = p; *p1 == ' '; p1++)
continue;
vsyslog(LOG_ERR, p1, args);
}
/* always display the message if tracing */
if (ftrace != 0) {
(void)vfprintf(ftrace, p, args);
(void)fputc('\n', ftrace);
}
}
void
logbad(int dump, char *p, ...)
{

View File

@ -1,325 +0,0 @@
/* This code could be made a lot faster for PPP */
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
* rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD5 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
#ident "$Revision: 1.1.1.1 $"
#include <strings.h>
#ifdef sgi
#include <bstring.h>
#endif
#include <sys/types.h>
#define MD5_DIGEST_LEN 16
typedef struct {
u_int32_t state[4]; /* state (ABCD) */
u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
extern void MD5Init(MD5_CTX*);
extern void MD5Update(MD5_CTX*, u_char*, u_int);
extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);
/* UINT4 defines a four byte word */
#define UINT4 u_int32_t
#define MD5_memcpy(d,s,l) bcopy(s,d,l)
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform(UINT4[4], unsigned char [64]);
static void Encode(unsigned char *, UINT4 *, unsigned int);
static void Decode(UINT4 *, unsigned char *, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
* Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void
MD5Init(MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
* operation, processing another message block, and updating the
* context.
*/
void
MD5Update(MD5_CTX *context, /* context */
unsigned char *input, /* input block */
unsigned int inputLen) /* length of input block */
{
unsigned int i, indx, partLen;
/* Compute number of bytes mod 64 */
indx = ((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - indx;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
bcopy(input, &context->buffer[indx], partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
indx = 0;
} else {
i = 0;
}
/* Buffer remaining input */
bcopy(&input[i], &context->buffer[indx], inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void
MD5Final(unsigned char digest[MD5_DIGEST_LEN], /* message digest */
MD5_CTX *context) /* context */
{
unsigned char bits[8];
unsigned int indx, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
indx = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (indx < 56) ? (56 - indx) : (120 - indx);
MD5Update(context, PADDING, padLen);
/* Append length (before padding) */
MD5Update(context, bits, 8);
/* Store state in digest */
Encode(digest, context->state, MD5_DIGEST_LEN);
/* Zeroize sensitive information.
*/
bzero(context, sizeof(*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void
MD5Transform(UINT4 state[4],
unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
bzero(x, sizeof(x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
* a multiple of 4.
*/
static void
Encode(unsigned char *output,
UINT4 *input,
unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
* a multiple of 4.
*/
static void
Decode (UINT4 *output,
unsigned char *input,
unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: output.c,v 1.11 1996/09/24 16:24:16 christos Exp $ */
/* $NetBSD: output.c,v 1.12 1997/02/03 22:03:01 christos Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -36,7 +36,7 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: output.c,v 1.11 1996/09/24 16:24:16 christos Exp $";
static char rcsid[] = "$NetBSD: output.c,v 1.12 1997/02/03 22:03:01 christos Exp $";
#endif
#include "defs.h"
@ -54,37 +54,45 @@ struct {
naddr to_std_mask;
naddr to_std_net;
struct interface *ifp; /* usually output interface */
struct ws_buf { /* info for each buffer */
struct rip *buf;
struct netinfo *n;
struct netinfo *base;
struct netinfo *lim;
enum output_type type;
} v12, v2;
struct auth *a;
char metric; /* adjust metrics by interface */
int npackets;
int gen_limit;
u_int state;
#define WS_ST_FLASH 0x001 /* send only changed routes */
#define WS_ST_RIP2_SAFE 0x002 /* send RIPv2 safe for RIPv1 */
#define WS_ST_RIP2_ALL 0x004 /* send full featured RIPv2 */
#define WS_ST_AG 0x008 /* ok to aggregate subnets */
#define WS_ST_SUPER_AG 0x010 /* ok to aggregate networks */
#define WS_ST_SUB_AG 0x020 /* aggregate subnets in odd case */
#define WS_ST_QUERY 0x040 /* responding to a query */
#define WS_ST_TO_ON_NET 0x080 /* sending onto one of our nets */
#define WS_ST_DEFAULT 0x100 /* faking a default */
#define WS_ST_PM_RDISC 0x200 /* poor-man's router discovery */
#define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */
#define WS_ST_AG 0x004 /* ok to aggregate subnets */
#define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */
#define WS_ST_SUB_AG 0x010 /* aggregate subnets in odd case */
#define WS_ST_QUERY 0x020 /* responding to a query */
#define WS_ST_TO_ON_NET 0x040 /* sending onto one of our nets */
#define WS_ST_DEFAULT 0x080 /* faking a default */
} ws;
/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */
struct ws_buf v12buf;
union pkt_buf ripv12_buf;
/* Another for only RIPv2 listeners */
struct ws_buf v2buf;
union pkt_buf rip_v2_buf;
void
bufinit(void)
{
ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE;
v12buf.buf = &ripv12_buf.rip;
v12buf.base = &v12buf.buf->rip_nets[0];
rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
rip_v2_buf.rip.rip_vers = RIPv2;
v2buf.buf = &rip_v2_buf.rip;
v2buf.base = &v2buf.buf->rip_nets[0];
}
/* Send the contents of the global buffer via the non-multicast socket
*/
int /* <0 on failure */
@ -138,7 +146,7 @@ output(enum output_type type,
msg = "Send pt-to-pt";
} else if (ifp->int_state & IS_DUP) {
trace_act("abort multicast output via %s"
" with duplicate address\n",
" with duplicate address",
ifp->int_name);
return 0;
} else {
@ -173,10 +181,15 @@ output(enum output_type type,
}
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
}
break;
case NO_OUT_MULTICAST:
case NO_OUT_RIPV2:
break;
default:
#ifdef DEBUG
abort();
#endif
return -1;
}
trace_rip(msg, "to", &sin, ifp, buf, size);
@ -199,20 +212,99 @@ output(enum output_type type,
}
/* install authentication if appropriate
/* Find the first key for a packet to send.
* Try for a key that is eligable and has not expired, but settle for
* the last key if they have all expired.
* If no key is ready yet, give up.
*/
static void
set_auth(struct ws_buf *w)
struct auth *
find_auth(struct interface *ifp)
{
if (ws.ifp != 0
&& ws.ifp->int_passwd[0] != '\0'
&& (ws.state & WS_ST_RIP2_SAFE)) {
w->n->n_family = RIP_AF_AUTH;
((struct netauth*)w->n)->a_type = RIP_AUTH_PW;
bcopy(ws.ifp->int_passwd, ((struct netauth*)w->n)->au.au_pw,
sizeof(((struct netauth*)w->n)->au.au_pw));
w->n++;
struct auth *ap, *res;
int i;
if (ifp == 0)
return 0;
res = 0;
ap = ifp->int_auth;
for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
/* stop looking after the last key */
if (ap->type == RIP_AUTH_NONE)
break;
/* ignore keys that are not ready yet */
if ((u_long)ap->start > (u_long)clk.tv_sec)
continue;
if ((u_long)ap->end < (u_long)clk.tv_sec) {
/* note best expired password as a fall-back */
if (res == 0 || (u_long)ap->end > (u_long)res->end)
res = ap;
continue;
}
/* note key with the best future */
if (res == 0 || (u_long)res->end < (u_long)ap->end)
res = ap;
}
return res;
}
void
clr_ws_buf(struct ws_buf *wb,
struct auth *ap)
{
struct netauth *na;
wb->lim = wb->base + NETS_LEN;
wb->n = wb->base;
bzero(wb->n, NETS_LEN*sizeof(*wb->n));
/* install authentication if appropriate
*/
if (ap == 0)
return;
na = (struct netauth*)wb->n;
if (ap->type == RIP_AUTH_PW) {
na->a_family = RIP_AF_AUTH;
na->a_type = RIP_AUTH_PW;
bcopy(ap->key, na->au.au_pw, sizeof(na->au.au_pw));
wb->n++;
} else if (ap->type == RIP_AUTH_MD5) {
na->a_family = RIP_AF_AUTH;
na->a_type = RIP_AUTH_MD5;
na->au.a_md5.md5_keyid = ap->keyid;
na->au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN;
na->au.a_md5.md5_seqno = clk.tv_sec;
wb->n++;
wb->lim--; /* make room for trailer */
}
}
void
end_md5_auth(struct ws_buf *wb,
struct auth *ap)
{
struct netauth *na, *na2;
MD5_CTX md5_ctx;
na = (struct netauth*)wb->base;
na2 = (struct netauth*)wb->n;
na2->a_family = RIP_AF_AUTH;
na2->a_type = 1;
bcopy(ap->key, na2->au.au_pw, sizeof(na2->au.au_pw));
na->au.a_md5.md5_pkt_len = (char *)na2-(char *)(na+1);
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, (u_char *)na,
(char *)(na2+1) - (char *)na);
MD5Final(na2->au.au_pw, &md5_ctx);
wb->n++;
}
@ -227,12 +319,14 @@ supply_write(struct ws_buf *wb)
*/
switch (wb->type) {
case NO_OUT_MULTICAST:
trace_pkt("skip multicast to %s because impossible\n",
trace_pkt("skip multicast to %s because impossible",
naddr_ntoa(ws.to.sin_addr.s_addr));
break;
case NO_OUT_RIPV2:
break;
default:
if (ws.a != 0 && ws.a->type == RIP_AUTH_MD5)
end_md5_auth(wb,ws.a);
if (output(wb->type, &ws.to, ws.ifp, wb->buf,
((char *)wb->n - (char*)wb->buf)) < 0
&& ws.ifp != 0)
@ -241,9 +335,7 @@ supply_write(struct ws_buf *wb)
break;
}
bzero(wb->n = wb->base, sizeof(*wb->n)*NETS_LEN);
if (wb->buf->rip_vers == RIPv2)
set_auth(wb);
clr_ws_buf(wb,ws.a);
}
@ -253,7 +345,7 @@ static void
supply_out(struct ag_info *ag)
{
int i;
naddr mask, v1_mask, s_mask, dst_h, ddst_h;
naddr mask, v1_mask, dst_h, ddst_h = 0;
struct ws_buf *wb;
@ -273,7 +365,6 @@ supply_out(struct ag_info *ag)
mask = ag->ag_mask;
v1_mask = ripv1_mask_host(htonl(dst_h),
(ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0);
s_mask = std_mask(htonl(dst_h));
i = 0;
/* If we are sending RIPv2 packets that cannot (or must not) be
@ -281,19 +372,16 @@ supply_out(struct ag_info *ag)
* 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 RIPv1 is off, use the multicast buffer.
*/
if (((ws.state & WS_ST_RIP2_ALL)
&& (dst_h != RIP_DEFAULT || !(ws.state & WS_ST_PM_RDISC)))
if ((ws.state & WS_ST_RIP2_ALL)
|| ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) {
/* use the RIPv2-only buffer */
wb = &ws.v2;
wb = &v2buf;
} else {
/* use the RIPv1-or-RIPv2 buffer */
wb = &ws.v12;
wb = &v12buf;
/* Convert supernet route into corresponding set of network
* routes for RIPv1, but leave non-contiguous netmasks
@ -334,18 +422,20 @@ supply_out(struct ag_info *ag)
? HOPCNT_INFINITY
: ag->ag_metric);
HTONL(wb->n->n_metric);
if (wb->buf->rip_vers == RIPv2) {
/* Any non-zero bits in the supposedly unused RIPv1 fields
* cause the old `routed` to ignore the route.
* That means the mask and so forth cannot be sent
* in the hybrid RIPv1/RIPv2 mode.
*/
if (ws.state & WS_ST_RIP2_ALL) {
if (ag->ag_nhop != 0
&& (ws.state & WS_ST_RIP2_SAFE)
&& ((ws.state & WS_ST_QUERY)
|| (ag->ag_nhop != ws.ifp->int_addr
&& on_net(ag->ag_nhop,
ws.ifp->int_net,
ws.ifp->int_mask))))
wb->n->n_nhop = ag->ag_nhop;
if ((ws.state & WS_ST_RIP2_ALL)
|| mask != s_mask)
wb->n->n_mask = htonl(mask);
wb->n->n_mask = htonl(mask);
wb->n->n_tag = ag->ag_tag;
}
dst_h += ddst_h;
@ -366,22 +456,24 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
u_short ags;
char metric, pref;
naddr dst, nhop;
struct rt_spare *rts;
int i;
/* Do not advertise the loopback interface
* or external remote interfaces
/* Do not advertise external remote interfaces or passive interfaces.
*/
if ((RT->rt_state & RS_IF)
&& RT->rt_ifp != 0
&& ((RT->rt_ifp->int_if_flags & IFF_LOOPBACK)
|| (RT->rt_ifp->int_state & IS_EXTERNAL))
&& (RT->rt_ifp->int_if_flags & IS_PASSIVE)
&& !(RT->rt_state & RS_MHOME))
return 0;
/* If being quiet about our ability to forward, then
* do not say anything unless responding to a query.
* do not say anything unless responding to a query,
* except about our main interface.
*/
if (!supplier && !(ws.state & WS_ST_QUERY))
if (!supplier && !(ws.state & WS_ST_QUERY)
&& !(RT->rt_state & RS_MHOME))
return 0;
dst = RT->rt_dst;
@ -491,51 +583,72 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
* forgotten.
*
* Include the routes for both ends of point-to-point interfaces
* since the other side presumably knows them as well as we do.
* among those suppressed by split-horizon, since the other side
* should knows them as well as we do.
*
* Notice spare routes with the same metric that we are about to
* advertise, to split the horizon on redunant, inactive paths.
*/
if (RT->rt_ifp == ws.ifp && ws.ifp != 0
if (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)) {
/* Poison-reverse the route instead of only not advertising it
* it is recently changed from some other route.
* In almost all cases, if there is no spare for the route
* then it is either old or a brand new route, and if it
* is brand new, there is no need for poison-reverse.
*/
metric = HOPCNT_INFINITY;
if (RT->rt_poison_time < now_expire
|| RT->rt_spares[1].rts_gate ==0) {
ags |= AGS_SPLIT_HZ;
ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) {
if (rts->rts_ifp == ws.ifp
&& rts->rts_metric <= metric)
break;
}
if (i != 0) {
/* If we do not mark the route with AGS_SPLIT_HZ here,
* it will be poisoned-reverse, or advertised back
* toward its source with an infinite metric.
* If we have recently advertised the route with a
* better metric than we now have, then we should
* poison-reverse the route before suppressing it for
* split-horizon.
*
* In almost all cases, if there is no spare for the
* route then it is either old and dead or a brand
* new route. If it is brand new, there is no need
* for poison-reverse. If it is old and dead, it
* is already poisoned.
*/
if (RT->rt_poison_time < now_expire
|| RT->rt_poison_metric >= metric
|| RT->rt_spares[1].rts_gate == 0) {
ags |= AGS_SPLIT_HZ;
ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
}
metric = HOPCNT_INFINITY;
}
}
/* Adjust the outgoing metric by the cost of the link.
/* Keep track of the best metric with which the
* route has been advertised recently.
*/
pref = 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_expire) {
RT->rt_poison_time = now.tv_sec;
RT->rt_poison_metric = metric;
}
metric = pref;
if (RT->rt_poison_metric >= metric
|| RT->rt_poison_time < now_expire) {
RT->rt_poison_time = now.tv_sec;
RT->rt_poison_metric = 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
|| RT->rt_poison_time < now_garbage )
/* Adjust the outgoing metric by the cost of the link.
* Avoid aggregation when a route is counting to infinity.
*/
pref = RT->rt_poison_metric + ws.metric;
metric += ws.metric;
/* Do not advertise stable routes that will be ignored,
* unless we are answering a query.
* 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.
*/
if (metric >= HOPCNT_INFINITY) {
if (!(ws.state & WS_ST_QUERY)
&& (pref >= HOPCNT_INFINITY
|| RT->rt_poison_time < now_garbage))
return 0;
metric = HOPCNT_INFINITY;
@ -556,10 +669,11 @@ supply(struct sockaddr_in *dst,
struct interface *ifp, /* output interface */
enum output_type type,
int flash, /* 1=flash update */
int vers) /* RIP version */
int vers, /* RIP version */
int passwd_ok) /* OK to include cleartext password */
{
static int init = 1;
struct rt_entry *rt;
int def_metric;
ws.state = 0;
@ -598,94 +712,79 @@ supply(struct sockaddr_in *dst,
ws.metric = ifp->int_metric+1;
}
if (init) {
init = 0;
bzero(&ripv12_buf, sizeof(ripv12_buf));
ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE;
ws.v12.buf = &ripv12_buf.rip;
ws.v12.base = &ws.v12.buf->rip_nets[0];
ws.v12.lim = ws.v12.base + NETS_LEN;
bzero(&rip_v2_buf, sizeof(rip_v2_buf));
rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
rip_v2_buf.rip.rip_vers = RIPv2;
ws.v2.buf = &rip_v2_buf.rip;
ws.v2.base = &ws.v2.buf->rip_nets[0];
ws.v2.lim = ws.v2.base + NETS_LEN;
}
ripv12_buf.rip.rip_vers = vers;
ws.v12.n = ws.v12.base;
set_auth(&ws.v12);
ws.v2.n = ws.v2.base;
set_auth(&ws.v2);
switch (type) {
case OUT_BROADCAST:
ws.v2.type = ((ws.ifp != 0
&& (ws.ifp->int_if_flags & IFF_MULTICAST))
v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST))
? OUT_MULTICAST
: NO_OUT_MULTICAST);
ws.v12.type = OUT_BROADCAST;
v12buf.type = OUT_BROADCAST;
break;
case OUT_MULTICAST:
ws.v2.type = ((ws.ifp != 0
&& (ws.ifp->int_if_flags & IFF_MULTICAST))
v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST))
? OUT_MULTICAST
: NO_OUT_MULTICAST);
ws.v12.type = OUT_BROADCAST;
v12buf.type = OUT_BROADCAST;
break;
case OUT_UNICAST:
case OUT_QUERY:
ws.v2.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
ws.v12.type = type;
v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
v12buf.type = type;
break;
default:
ws.v2.type = type;
ws.v12.type = type;
v2buf.type = type;
v12buf.type = type;
break;
}
if (vers == RIPv2) {
/* if asked to send RIPv2, send at least that which can
* be safely heard by RIPv1 listeners.
*/
ws.state |= WS_ST_RIP2_SAFE;
/* full RIPv2 only if cannot be heard by RIPv1 listeners */
if (type != OUT_BROADCAST)
ws.state |= WS_ST_RIP2_ALL;
if (!(ws.state & WS_ST_TO_ON_NET)) {
ws.state |= (WS_ST_AG | WS_ST_SUPER_AG);
} else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) {
} else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) {
ws.state |= WS_ST_AG;
if (type != OUT_BROADCAST
&& (ws.ifp == 0
|| !(ws.ifp->int_state & IS_NO_SUPER_AG)))
&& (ifp == 0 || !(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)) {
} else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) {
ws.state |= WS_ST_SUB_AG;
}
if (supplier) {
/* Fake a default route if asked, and if there is not
* a better, real default route.
*/
if (ifp->int_d_metric != 0
&& (0 == (rt = rtget(RIP_DEFAULT, 0))
|| rt->rt_metric+ws.metric >= ifp->int_d_metric)) {
ws.a = (vers == RIPv2) ? find_auth(ifp) : 0;
if (!passwd_ok && ws.a != 0 && ws.a->type == RIP_AUTH_PW)
ws.a = 0;
clr_ws_buf(&v12buf,ws.a);
clr_ws_buf(&v2buf,ws.a);
/* Fake a default route if asked and if there is not already
* a better, real default route.
*/
if (supplier && (def_metric = ifp->int_d_metric) != 0) {
if (0 == (rt = rtget(RIP_DEFAULT, 0))
|| rt->rt_metric+ws.metric >= def_metric) {
ws.state |= WS_ST_DEFAULT;
ag_check(0, 0, 0, 0,
ifp->int_d_metric,ifp->int_d_metric,
ag_check(0, 0, 0, 0, def_metric, def_metric,
0, 0, 0, supply_out);
} else {
def_metric = rt->rt_metric+ws.metric;
}
/* If both RIPv2 and the poor-man's router discovery
* kludge are on, arrange to advertise an extra
* default route via RIPv1.
*/
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;
v12buf.n->n_family = RIP_AF_INET;
v12buf.n->n_dst = htonl(RIP_DEFAULT);
v12buf.n->n_metric = htonl(def_metric);
v12buf.n++;
}
}
@ -695,21 +794,21 @@ supply(struct sockaddr_in *dst,
/* 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 (v12buf.n != v12buf.base
&& (v12buf.n > v12buf.base+1
|| v12buf.base->n_family != RIP_AF_AUTH))
supply_write(&v12buf);
if (v2buf.n != v2buf.base
&& (v2buf.n > v2buf.base+1
|| v2buf.base->n_family != RIP_AF_AUTH))
supply_write(&v2buf);
/* If we sent nothing and this is an answer to a query, send
* an empty buffer.
*/
if (ws.npackets == 0
&& (ws.state & WS_ST_QUERY))
supply_write(&ws.v12);
supply_write(&v12buf);
}
@ -737,36 +836,28 @@ rip_bcast(int flash)
if (rip_sock < 0)
return;
trace_act("send %s and inhibit dynamic updates for %.3f sec\n",
trace_act("send %s and inhibit dynamic updates for %.3f sec",
flash ? "dynamic update" : "all routes",
rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0);
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
/* skip interfaces not doing RIP, those already queried,
* and aliases. Do try broken interfaces to see
* if they have healed.
/* Skip interfaces not doing RIP.
* Do try broken interfaces to see if they have healed.
*/
if (0 != (ifp->int_state & (IS_PASSIVE | IS_ALIAS)))
if (IS_RIP_OUT_OFF(ifp->int_state))
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
continue;
/* default to RIPv1 output */
if (ifp->int_state & IS_NO_RIPV1_OUT) {
/* Say nothing if this interface is turned off */
if (ifp->int_state & IS_NO_RIPV2_OUT)
continue;
vers = RIPv2;
} else {
vers = RIPv1;
}
vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1;
if (ifp->int_if_flags & IFF_BROADCAST) {
/* ordinary, hardware interface */
dst.sin_addr.s_addr = ifp->int_brdaddr;
/* if RIPv1 is not turned off, then broadcast so
/* If RIPv1 is not turned off, then broadcast so
* that RIPv1 listeners can hear.
*/
if (vers == RIPv2
@ -781,13 +872,17 @@ rip_bcast(int flash)
dst.sin_addr.s_addr = ifp->int_dstaddr;
type = OUT_UNICAST;
} else {
} else if (ifp->int_state & IS_REMOTE) {
/* remote interface */
dst.sin_addr.s_addr = ifp->int_addr;
type = OUT_UNICAST;
} else {
/* ATM, HIPPI, etc. */
continue;
}
supply(&dst, ifp, type, flash, vers);
supply(&dst, ifp, type, flash, vers, 1);
}
update_seqno++; /* all routes are up to date */
@ -817,28 +912,21 @@ rip_query(void)
bzero(&buf, sizeof(buf));
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
/* skip interfaces not doing RIP, those already queried,
* and aliases. Do try broken interfaces to see
* if they have healed.
/* Skip interfaces those already queried.
* Do not ask via interfaces through which we don't
* accept input. Do not ask via interfaces that cannot
* send RIP packets.
* Do try broken interfaces to see if they have healed.
*/
if (0 != (ifp->int_state & (IS_RIP_QUERIED
| IS_PASSIVE | IS_ALIAS)))
if (IS_RIP_IN_OFF(ifp->int_state)
|| ifp->int_query_time != NEVER)
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
continue;
/* default to RIPv1 output */
if (ifp->int_state & IS_NO_RIPV2_OUT) {
/* Say nothing if this interface is turned off */
if (ifp->int_state & IS_NO_RIPV1_OUT)
continue;
buf.rip_vers = RIPv1;
} else {
buf.rip_vers = RIPv2;
}
buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1;
buf.rip_cmd = RIPCMD_REQUEST;
buf.rip_nets[0].n_family = RIP_AF_UNSPEC;
buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
@ -861,13 +949,17 @@ rip_query(void)
dst.sin_addr.s_addr = ifp->int_dstaddr;
type = OUT_UNICAST;
} else {
} else if (ifp->int_state & IS_REMOTE) {
/* remote interface */
dst.sin_addr.s_addr = ifp->int_addr;
type = OUT_UNICAST;
} else {
/* ATM, HIPPI, etc. */
continue;
}
ifp->int_state |= IS_RIP_QUERIED;
ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL;
if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0)
if_sick(ifp);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: parms.c,v 1.4 1997/01/29 12:07:26 ws Exp $ */
/* $NetBSD: parms.c,v 1.5 1997/02/03 22:03:02 christos Exp $ */
/*
* Copyright (c) 1983, 1993
@ -36,15 +36,17 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: parms.c,v 1.4 1997/01/29 12:07:26 ws Exp $";
static char rcsid[] = "$NetBSD: parms.c,v 1.5 1997/02/03 22:03:02 christos Exp $";
#endif
#include "defs.h"
#include "pathnames.h"
#include <sys/stat.h>
struct parm *parms;
struct intnet *intnets;
struct tgate *tgates;
/* use configured parameters
@ -52,49 +54,55 @@ struct intnet *intnets;
void
get_parms(struct interface *ifp)
{
static warned_auth_in, warned_auth_out;
struct parm *parmp;
int i, num_passwds = 0;
/* get all relevant parameters
*/
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
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,
if (parmp->parm_name[0] == '\0'
|| !strcmp(ifp->int_name, parmp->parm_name)
|| (parmp->parm_name[0] == '\n'
&& on_net(ifp->int_addr,
parmp->parm_net, parmp->parm_mask))) {
/* This group of parameters is relevant,
* so get its settings
*/
ifp->int_state |= parmp->parm_int_state;
if (parmp->parm_passwd[0] != '\0')
bcopy(parmp->parm_passwd, ifp->int_passwd,
sizeof(ifp->int_passwd));
for (i = 0; i < MAX_AUTH_KEYS; i++) {
if (parmp->parm_auth[0].type == RIP_AUTH_NONE
|| num_passwds >= MAX_AUTH_KEYS)
break;
bcopy(&parmp->parm_auth[i],
&ifp->int_auth[num_passwds++],
sizeof(ifp->int_auth[0]));
}
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.
/* Set general defaults.
*
* Default poor-man's router discovery to a metric that will
* be heard by old versions of `routed`. They ignored received
* routes with metric 15.
*/
if ((ifp->int_state & IS_PM_RDISC)
&& ifp->int_d_metric == 0)
ifp->int_d_metric = HOPCNT_INFINITY-2;
if (IS_RIP_IN_OFF(ifp->int_state))
ifp->int_state |= IS_NO_RIP_OUT;
ifp->int_d_metric = FAKE_METRIC;
if (ifp->int_rdisc_int == 0)
ifp->int_rdisc_int = DefMaxAdvertiseInterval;
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_REMOTE))
ifp->int_state |= IS_BCAST_RDISC;
if (ifp->int_if_flags & IFF_POINTOPOINT) {
@ -111,10 +119,27 @@ get_parms(struct interface *ifp)
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;
ifp->int_state |= IS_NO_RIP;
if (!IS_RIP_IN_OFF(ifp->int_state)
&& ifp->int_auth[0].type != RIP_AUTH_NONE
&& !(ifp->int_state & IS_NO_RIPV1_IN)
&& !warned_auth_in) {
msglog("Warning: RIPv1 input via %s"
" will be accepted without authentication",
ifp->int_name);
warned_auth_in = 1;
}
if (!IS_RIP_OUT_OFF(ifp->int_state)
&& ifp->int_auth[0].type != RIP_AUTH_NONE
&& !(ifp->int_state & IS_NO_RIPV1_OUT)) {
if (!warned_auth_out) {
msglog("Warning: RIPv1 output via %s"
" will be sent without authentication",
ifp->int_name);
warned_auth_out = 1;
}
}
}
@ -143,15 +168,21 @@ gwkludge(void)
struct interface *ifp;
naddr dst, netmask, gate;
int metric, n;
struct stat sb;
u_int state;
char *type;
struct parm *parmp;
fp = fopen(_PATH_GATEWAYS, "r");
if (fp == 0)
return;
if (0 > fstat(fileno(fp), &sb)) {
msglog("could not stat() "_PATH_GATEWAYS);
(void)fclose(fp);
return;
}
for (;;) {
if (0 == fgets(lbuf, sizeof(lbuf)-1, fp))
break;
@ -162,19 +193,20 @@ gwkludge(void)
|| *lptr == '#')
continue;
p = lptr+strlen(lptr)-1;
while (*p == '\n'
|| *p == ' ')
while (*p == '\n' || *p == ' ')
*p-- = '\0';
/* notice newfangled parameter lines
*/
if (strncasecmp("net", lptr, 3)
&& strncasecmp("host", lptr, 4)) {
p = parse_parms(lptr);
p = parse_parms(lptr,
(sb.st_uid == 0
&& !(sb.st_mode&(S_IRWXG|S_IRWXO))));
if (p != 0) {
if (strcmp(p,lptr))
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"", lptr, p);
if (strcasecmp(p,lptr))
msglog("%s in "_PATH_GATEWAYS
" entry \"%s\"", p, lptr);
else
msglog("bad \"%s\" in "_PATH_GATEWAYS,
lptr);
@ -183,31 +215,34 @@ gwkludge(void)
}
/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
qual[0] = '\0';
n = sscanf(lptr, "%4s %129[^ \t] gateway"
" %64[^ / \t] metric %d %8s\n",
" %64[^ / \t] metric %u %8s\n",
net_host, dname, gname, &metric, qual);
if (n != 5) {
msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
if (n != 4 && n != 5) {
msglog("bad "_PATH_GATEWAYS" entry \"%s\"; %d values",
lptr, n);
continue;
}
if (metric < 0 || metric >= HOPCNT_INFINITY) {
if (metric >= HOPCNT_INFINITY) {
msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"",
lptr);
continue;
}
if (!strcmp(net_host, "host")) {
if (!strcasecmp(net_host, "host")) {
if (!gethost(dname, &dst)) {
msglog("bad host \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"", dname, lptr);
continue;
}
netmask = HOST_MASK;
} else if (!strcmp(net_host, "net")) {
} else if (!strcasecmp(net_host, "net")) {
if (!getnet(dname, &dst, &netmask)) {
msglog("bad net \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"", dname, lptr);
continue;
}
HTONL(dst); /* make network # into IP address */
} else {
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"", lptr);
@ -220,7 +255,7 @@ gwkludge(void)
continue;
}
if (strcmp(qual, type = "passive") == 0) {
if (!strcasecmp(qual, type = "passive")) {
/* Passive entries are not placed in our tables,
* only the kernel's, so we don't copy all of the
* external routing information within a net.
@ -231,17 +266,19 @@ gwkludge(void)
if (metric == 0)
metric = 1;
} else if (strcmp(qual, type = "external") == 0) {
} else if (!strcasecmp(qual, type = "external")) {
/* External entries are handled by other means
* such as EGP, and are placed only in the daemon
* tables to prevent overriding them with something
* else.
*/
strcpy(qual,"external");
state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
if (metric == 0)
metric = 1;
} else if (qual[0] == '\0') {
} else if (!strcasecmp(qual, "active")
|| qual[0] == '\0') {
if (metric != 0) {
/* Entries that are neither "passive" nor
* "external" are "remote" and must behave
@ -254,110 +291,277 @@ gwkludge(void)
/* "remote" entries with a metric of 0
* are aliases for our own interfaces
*/
state = IS_REMOTE | IS_PASSIVE;
state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
type = "alias";
}
} else {
msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
msglog("bad "_PATH_GATEWAYS" entry \"%s\";"
" unknown type %s", lptr, qual);
continue;
}
/* Remember to advertise the corresponding logical network.
*/
if (!(state & IS_EXTERNAL)
&& netmask != std_mask(dst))
state |= IS_SUBNET;
if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
state |= IS_NO_RDISC;
if (state & IS_PASSIVE)
state |= (IS_NO_RIP | IS_NO_RDISC);
if ((state & (IS_NO_RIP | IS_NO_RDISC))
== (IS_NO_RIP|IS_NO_RDISC))
state |= IS_PASSIVE;
state |= IS_NO_RIP;
parmp = (struct parm*)malloc(sizeof(*parmp));
bzero(parmp, sizeof(*parmp));
parmp->parm_next = parms;
parms = parmp;
parmp->parm_addr_h = ntohl(dst);
parmp->parm_mask = -1;
parmp->parm_d_metric = 0;
parmp->parm_int_state = state;
/* See if this new interface duplicates an existing
* interface.
*/
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_mask == netmask
&& ((ifp->int_addr == dst
&& netmask != HOST_MASK)
|| (ifp->int_dstaddr == dst
&& netmask == HOST_MASK)))
break;
}
ifp = check_dup(gate,dst,netmask,0);
if (ifp != 0) {
/* Let one of our real interfaces be marked passive.
*/
if ((state & IS_PASSIVE) && !(state & IS_EXTERNAL)) {
ifp->int_state |= state;
} else {
msglog("%s is duplicated in "_PATH_GATEWAYS
" by %s",
ifp->int_name, lptr);
}
msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr);
continue;
}
tot_interfaces++;
ifp = (struct interface *)malloc(sizeof(*ifp));
bzero(ifp, sizeof(*ifp));
if (ifnet != 0) {
ifp->int_next = ifnet;
ifnet->int_prev = ifp;
}
ifnet = ifp;
ifp->int_state = state;
ifp->int_net = ntohl(dst) & netmask;
ifp->int_mask = netmask;
if (netmask == HOST_MASK)
ifp->int_if_flags |= IFF_POINTOPOINT;
ifp->int_dstaddr = dst;
ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP_RUNNING;
else
ifp->int_if_flags = IFF_UP_RUNNING;
ifp->int_act_time = NEVER;
ifp->int_addr = gate;
ifp->int_dstaddr = dst;
ifp->int_mask = netmask;
ifp->int_ripv1_mask = netmask;
ifp->int_std_mask = std_mask(gate);
ifp->int_net = ntohl(dst);
ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
ifp->int_std_addr = htonl(ifp->int_std_net);
ifp->int_metric = metric;
(void)sprintf(ifp->int_name, "%s-%s", type, naddr_ntoa(dst));
if (!(state & IS_EXTERNAL)
&& ifp->int_mask != ifp->int_std_mask)
ifp->int_state |= IS_SUBNET;
(void)sprintf(ifp->int_name, "%s(%s)", type, gname);
ifp->int_index = -1;
if_link(ifp);
}
/* After all of the parameter lines have been read,
* apply them to any remote interfaces.
*/
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
get_parms(ifp);
tot_interfaces++;
if (!IS_RIP_OFF(ifp->int_state))
rip_interfaces++;
trace_if("Add", ifp);
}
(void)fclose(fp);
}
/* parse a set of parameters for an interface
/* strtok(), but honoring backslash
*/
static int /* 0=ok, -1=bad */
parse_quote(char **linep,
char *delims,
char *delimp,
char *buf,
int lim)
{
char c, *pc, *p;
pc = *linep;
if (*pc == '\0')
return -1;
while (lim != 0) {
c = *pc++;
if (c == '\0')
break;
if (c == '\\' && pc != '\0') {
if ((c = *pc++) == 'n') {
c = '\n';
} else if (c == 'r') {
c = '\r';
} else if (c == 't') {
c = '\t';
} else if (c == 'b') {
c = '\b';
} else if (c >= '0' && c <= '7') {
c -= '0';
if (*pc >= '0' && *pc <= '7') {
c = (c<<3)+(*pc++ - '0');
if (*pc >= '0' && *pc <= '7')
c = (c<<3)+(*pc++ - '0');
}
}
} else {
for (p = delims; *p != '\0'; ++p) {
if (*p == c)
goto exit;
}
}
*buf++ = c;
--lim;
}
exit:
if (lim == 0)
return -1;
*buf = '\0';
if (delimp != 0)
*delimp = c;
*linep = pc-1;
return 0;
}
/* Parse password timestamp
*/
static char *
parse_ts(time_t *tp,
char **valp,
char *val0,
char *delimp,
char *buf,
u_int bufsize)
{
struct tm tm;
if (0 > parse_quote(valp, "| ,\n\r", delimp,
buf,bufsize)
|| buf[bufsize-1] != '\0'
|| buf[bufsize-2] != '\0') {
sprintf(buf,"bad timestamp %.25s", val0);
return buf;
}
strcat(buf,"\n");
bzero(&tm, sizeof(tm));
if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min)) {
sprintf(buf,"bad timestamp %.25s", val0);
return buf;
}
if (tm.tm_year <= 37)
tm.tm_year += 100;
if ((*tp = mktime(&tm)) == -1) {
sprintf(buf,"bad timestamp %.25s", val0);
return buf;
}
return 0;
}
/* Get a password, key ID, and expiration date in the format
* passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min
*/
static char * /* 0 or error message */
get_passwd(char *tgt,
char *val,
struct parm *parmp,
u_char type,
int safe) /* 1=from secure file */
{
static char buf[80];
char *val0, *p, delim;
struct auth k, *ap, *ap2;
int i;
u_long l;
if (!safe)
return "ignore unsafe password";
for (ap = parmp->parm_auth, i = 0;
ap->type != RIP_AUTH_NONE; i++, ap++) {
if (i >= MAX_AUTH_KEYS)
return "too many passwords";
}
bzero(&k, sizeof(k));
k.type = type;
k.end = -1-DAY;
val0 = val;
if (0 > parse_quote(&val, "| ,\n\r", &delim,
(char *)k.key, sizeof(k.key)))
return tgt;
if (delim != '|') {
if (type == RIP_AUTH_MD5)
return "missing Keyid";
} else {
val0 = ++val;
buf[sizeof(buf)-1] = '\0';
if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf))
|| buf[sizeof(buf)-1] != '\0'
|| (l = strtoul(buf,&p,0)) > 255
|| *p != '\0') {
sprintf(buf,"bad KeyID \"%.20s\"", val0);
return buf;
}
for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) {
if (ap2->keyid == l) {
sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
return buf;
}
}
k.keyid = (int)l;
if (delim == '|') {
val0 = ++val;
if (0 != (p = parse_ts(&k.start,&val,val0,&delim,
buf,sizeof(buf))))
return p;
if (delim != '|')
return "missing second timestamp";
val0 = ++val;
if (0 != (p = parse_ts(&k.end,&val,val0,&delim,
buf,sizeof(buf))))
return p;
if ((u_long)k.start > (u_long)k.end) {
sprintf(buf,"out of order timestamp %.30s",
val0);
return buf;
}
}
}
if (delim != '\0')
return tgt;
bcopy(&k, ap, sizeof(*ap));
return 0;
}
/* Parse a set of parameters for an interface.
*/
char * /* 0 or error message */
parse_parms(char *line)
parse_parms(char *line,
int safe) /* 1=from secure file */
{
#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt)))
#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str))))
#define PARS(str) (!strcasecmp(tgt, str))
#define PARSEQ(str) (!strncasecmp(tgt, 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;
struct tgate *tg;
naddr addr, mask;
char delim, *val0, *tgt, *val, *p;
char buf[64];
/* "subnet=x.y.z.u/mask" must be alone on the line */
if (!strncasecmp("subnet=",line,7)) {
/* "subnet=x.y.z.u/mask,metric" must be alone on the line */
if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1)
&& *(val = &line[sizeof("subnet=")]) != '\0') {
intnetp = (struct intnet*)malloc(sizeof(*intnetp));
intnetp->intnet_metric = 1;
if ((p = strrchr(line,','))) {
if ((p = strrchr(val,','))) {
*p++ = '\0';
intnetp->intnet_metric = (int)strtol(p,&p,0);
if (*p != '\0'
@ -365,13 +569,13 @@ parse_parms(char *line)
|| intnetp->intnet_metric >= HOPCNT_INFINITY)
return line;
}
if (!getnet(&line[7], &intnetp->intnet_addr,
&intnetp->intnet_mask)
if (!getnet(val, &intnetp->intnet_addr, &intnetp->intnet_mask)
|| intnetp->intnet_mask == HOST_MASK
|| intnetp->intnet_addr == RIP_DEFAULT) {
free(intnetp);
return line;
}
HTONL(intnetp->intnet_addr);
intnetp->intnet_next = intnets;
intnets = intnetp;
return 0;
@ -380,21 +584,58 @@ parse_parms(char *line)
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);
for (;;) {
tgt = line + strspn(line, " ,\n\r");
if (*tgt == '\0')
break;
} else if (PARSE("passwd")) {
if (tok[7] == '\0'
|| strlen(tok) > RIP_AUTH_PW_LEN+7)
break;
strcpy(parm.parm_passwd, tok+7);
line += strcspn(tgt, "= ,\n\r");
delim = *line;
if (delim == '=') {
val0 = ++line;
if (0 > parse_quote(&line," ,\n\r",&delim,
buf,sizeof(buf)))
return tgt;
}
if (delim != '\0')
*line++ = '\0';
if (PARSEQ("if")) {
if (parm.parm_name[0] != '\0'
|| strlen(buf) > IFNAMSIZ)
return tgt;
strcpy(parm.parm_name, buf);
} else if (PARSEQ("addr")) {
/* This is a bad idea, because the address based
* sets of parameters cannot be checked for
* consistency with the interface name parameters.
* The parm_net stuff is needed to allow several
* -F settings.
*/
if (!getnet(val0, &addr, &mask)
|| parm.parm_name[0] != '\0')
return tgt;
parm.parm_net = addr;
parm.parm_mask = mask;
parm.parm_name[0] = '\n';
} else if (PARSEQ("passwd")) {
/* since cleartext passwords are so weak allow
* them anywhere
*/
tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
if (tgt) {
*val0 = '\0';
return tgt;
}
} else if (PARSEQ("md5_passwd")) {
tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
if (tgt) {
*val0 = '\0';
return tgt;
}
} else if (PARS("no_ag")) {
parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
@ -410,11 +651,18 @@ parse_parms(char *line)
} else if (PARS("ripv2_out")) {
if (parm.parm_int_state & IS_NO_RIPV2_OUT)
break;
return tgt;
parm.parm_int_state |= IS_NO_RIPV1_OUT;
} else if (PARS("ripv2")) {
if ((parm.parm_int_state & IS_NO_RIPV2_OUT)
|| (parm.parm_int_state & IS_NO_RIPV2_IN))
return tgt;
parm.parm_int_state |= (IS_NO_RIPV1_IN
| IS_NO_RIPV1_OUT);
} else if (PARS("no_rip")) {
parm.parm_int_state |= IS_NO_RIP;
CKF(IS_PM_RDISC, IS_NO_RIP);
} else if (PARS("no_rdisc")) {
CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
@ -438,47 +686,53 @@ parse_parms(char *line)
CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
parm.parm_int_state |= IS_NO_RIP;
} else if (PARSE("rdisc_pref")) {
} else if (PARSEQ("rdisc_pref")) {
if (parm.parm_rdisc_pref != 0
|| tok[11] == '\0'
|| (parm.parm_rdisc_pref = (int)strtol(&tok[11],
&p,0),
|| (parm.parm_rdisc_pref = (int)strtoul(buf, &p,0),
*p != '\0'))
break;
return tgt;
} else if (PARS("pm_rdisc")) {
if (IS_RIP_OUT_OFF(parm.parm_int_state))
return tgt;
parm.parm_int_state |= IS_PM_RDISC;
} else if (PARSE("rdisc_interval")) {
} else if (PARSEQ("rdisc_interval")) {
if (parm.parm_rdisc_int != 0
|| tok[15] == '\0'
|| (parm.parm_rdisc_int = (int)strtol(&tok[15],
&p,0),
|| (parm.parm_rdisc_int = (int)strtoul(buf,&p,0),
*p != '\0')
|| parm.parm_rdisc_int < MinMaxAdvertiseInterval
|| parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
break;
return tgt;
} else if (PARSE("fake_default")) {
} else if (PARSEQ("fake_default")) {
if (parm.parm_d_metric != 0
|| tok[13] == '\0'
|| (parm.parm_d_metric=(int)strtol(&tok[13],&p,0),
|| IS_RIP_OUT_OFF(parm.parm_int_state)
|| (parm.parm_d_metric = (int)strtoul(buf,&p,0),
*p != '\0')
|| parm.parm_d_metric > HOPCNT_INFINITY-1)
break;
return tgt;
} else if (PARSEQ("trust_gateway")) {
if (!gethost(buf,&addr))
return tgt;
tg = (struct tgate *)malloc(sizeof(*tg));
tg->tgate_next = tgates;
tg->tgate_addr = addr;
tgates = tg;
parm.parm_int_state |= IS_DISTRUST;
} else if (PARS("redirect_ok")) {
parm.parm_int_state |= IS_REDIRECT_OK;
} else {
tgt = tok;
break;
return tgt; /* error */
}
}
if (tgt != 0)
return tgt;
return check_parms(&parm);
#undef DELIMS
#undef PARS
#undef PARSE
#undef PARSEQ
}
@ -486,38 +740,43 @@ parse_parms(char *line)
char * /* 0 or error message */
check_parms(struct parm *new)
{
struct parm *parmp;
struct parm *parmp, **parmpp;
int i, num_passwds;
/* set implicit values
*/
if (!supplier && supplier_set)
new->parm_int_state |= (IS_NO_RIPV1_OUT
| IS_NO_RIPV2_OUT
| IS_NO_ADV_OUT);
if (new->parm_int_state & IS_NO_ADV_IN)
new->parm_int_state |= IS_NO_SOL_OUT;
if ((new->parm_int_state & (IS_NO_RIP | IS_NO_RDISC))
== (IS_NO_RIP | IS_NO_RDISC))
new->parm_int_state |= IS_PASSIVE;
for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
if (new->parm_auth[i].type != RIP_AUTH_NONE)
num_passwds++;
}
/* compare with existing sets of parameters
*/
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
for (parmpp = &parms;
(parmp = *parmpp) != 0;
parmpp = &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))
if (!on_net(htonl(parmp->parm_net),
new->parm_net, new->parm_mask)
&& !on_net(htonl(new->parm_net),
parmp->parm_net, 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))
for (i = 0; i < MAX_AUTH_KEYS; i++) {
if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
num_passwds++;
}
if (num_passwds > MAX_AUTH_KEYS)
return "too many conflicting passwords";
if ((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)
@ -527,17 +786,26 @@ check_parms(struct parm *new)
&& 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";
&& new->parm_rdisc_int != parmp->parm_rdisc_int)) {
return ("conflicting, duplicate router discovery"
" parameters");
}
if (new->parm_d_metric != 0
&& parmp->parm_d_metric != 0
&& new->parm_d_metric != parmp->parm_d_metric) {
return ("conflicting, duplicate poor man's router"
" discovery or fake default metric");
}
}
/* link new entry on the so that when the entries are scanned,
* they affect the result in the order the operator specified.
*/
parmp = (struct parm*)malloc(sizeof(*parmp));
bcopy(new, parmp, sizeof(*parmp));
parmp->parm_next = parms;
parms = parmp;
*parmpp = parmp;
return 0;
}
@ -548,13 +816,13 @@ check_parms(struct parm *new)
*/
int /* 0=bad */
getnet(char *name,
naddr *addrp, /* host byte order */
naddr *maskp)
naddr *netp, /* a network so host byte order */
naddr *maskp) /* masks are always in host order */
{
int i;
struct netent *np;
naddr mask;
struct in_addr in;
naddr mask; /* in host byte order */
struct in_addr in; /* a network and so host byte order */
char hname[MAXHOSTNAMELEN+1];
char *mname, *p;
@ -575,17 +843,19 @@ getnet(char *name,
if (np != 0) {
in.s_addr = (naddr)np->n_net;
} else if (inet_aton(name, &in) == 1) {
HTONL(in.s_addr);
NTOHL(in.s_addr);
} else if (!mname && !strcasecmp(name,"default")) {
in.s_addr = RIP_DEFAULT;
} else {
return 0;
}
if (mname == 0) {
if (!mname) {
/* 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 = std_mask(htonl(in.s_addr));
if ((~mask & in.s_addr) != 0)
mask = HOST_MASK;
} else {
mask = (naddr)strtoul(mname, &p, 0);
@ -594,12 +864,22 @@ getnet(char *name,
if (mask != 0)
mask = HOST_MASK << (32-mask);
}
/* must have mask of 0 with default */
if (mask != 0 && in.s_addr == RIP_DEFAULT)
return 0;
if ((~mask & ntohl(in.s_addr)) != 0)
/* no host bits allowed in a network number */
if ((~mask & in.s_addr) != 0)
return 0;
/* require non-zero network number */
if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
return 0;
if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT)
return 0;
if (in.s_addr>>24 == 0xff)
return 0;
*addrp = in.s_addr;
*netp = in.s_addr;
*maskp = mask;
return 1;
}
@ -618,6 +898,12 @@ gethost(char *name,
* might be sick because routing is.
*/
if (inet_aton(name, &in) == 1) {
/* get a good number, but check that it it makes some
* sense.
*/
if (ntohl(in.s_addr)>>24 == 0
|| ntohl(in.s_addr)>>24 == 0xff)
return 0;
*addrp = in.s_addr;
return 1;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: rdisc.c,v 1.4 1996/09/24 16:24:20 christos Exp $ */
/* $NetBSD: rdisc.c,v 1.5 1997/02/03 22:03:04 christos Exp $ */
/*
* Copyright (c) 1995
@ -36,7 +36,7 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: rdisc.c,v 1.4 1996/09/24 16:24:20 christos Exp $";
static char rcsid[] = "$NetBSD: rdisc.c,v 1.5 1997/02/03 22:03:04 christos Exp $";
#endif
#include "defs.h"
@ -128,15 +128,14 @@ trace_rdisc(char *act,
wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)];
for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) {
(void)fprintf(ftrace, "\t%s preference=%#x",
(void)fprintf(ftrace, "\t%s preference=%d",
naddr_ntoa(wp[0]), (int)ntohl(wp[1]));
wp += p->ad.icmp_ad_asize;
}
(void)fputc('\n',ftrace);
} else {
trace_act("%s Router Solic. from %s to %s via %s"
" value=%#x\n",
trace_act("%s Router Solic. from %s to %s via %s value=%#x",
act, naddr_ntoa(from), naddr_ntoa(to),
ifp ? ifp->int_name : "?",
ntohl(p->so.icmp_so_rsvd));
@ -162,7 +161,8 @@ get_rdisc_sock(void)
*/
void
set_rdisc_mg(struct interface *ifp,
int on) { /* 0=turn it off */
int on) /* 0=turn it off */
{
struct ip_mreq m;
if (rdisc_sock < 0) {
@ -175,8 +175,7 @@ set_rdisc_mg(struct interface *ifp,
get_rdisc_sock();
}
if (!(ifp->int_if_flags & IFF_MULTICAST)
|| (ifp->int_state & IS_ALIAS)) {
if (!(ifp->int_if_flags & IFF_MULTICAST)) {
ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS);
return;
}
@ -254,7 +253,7 @@ set_supplier(void)
if (supplier_set)
return;
trace_act("start suppying routes\n");
trace_act("start suppying routes");
/* Forget discovered routes.
*/
@ -328,8 +327,7 @@ rdisc_age(naddr bad_gate)
sec = (now.tv_sec - drp->dr_life
+ SUPPLY_INTERVAL);
if (drp->dr_ts > sec) {
trace_act("age 0.0.0.0 --> %s"
" via %s\n",
trace_act("age 0.0.0.0 --> %s via %s",
naddr_ntoa(drp->dr_gate),
drp->dr_ifp->int_name);
drp->dr_ts = sec;
@ -415,8 +413,8 @@ del_rdisc(struct dr *drp)
*/
if (i == 0
&& ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
trace_act("discovered route is bad"
"--re-solicit routers via %s\n", ifp->int_name);
trace_act("discovered route is bad--re-solicit routers via %s",
ifp->int_name);
ifp->int_rdisc_cnt = 0;
ifp->int_rdisc_timer.tv_sec = 0;
rdisc_sol();
@ -487,7 +485,7 @@ rdisc_sort(void)
/* Stop using discovered routes if they are all bad
*/
if (new_drp == 0) {
trace_act("turn off Router Discovery client\n");
trace_act("turn off Router Discovery client");
rdisc_ok = 0;
if (rt != 0
@ -505,7 +503,7 @@ rdisc_sort(void)
} else {
if (cur_drp == 0) {
trace_act("turn on Router Discovery client"
" using %s via %s\n",
" using %s via %s",
naddr_ntoa(new_drp->dr_gate),
new_drp->dr_ifp->int_name);
@ -513,7 +511,7 @@ rdisc_sort(void)
} else {
trace_act("switch Router Discovery from"
" %s via %s to %s via %s\n",
" %s via %s to %s via %s",
naddr_ntoa(cur_drp->dr_gate),
cur_drp->dr_ifp->int_name,
naddr_ntoa(new_drp->dr_gate),
@ -528,7 +526,8 @@ rdisc_sort(void)
} else {
rtadd(RIP_DEFAULT, 0,
new_drp->dr_gate, new_drp->dr_gate,
0, 0, RS_RDISC, new_drp->dr_ifp);
HOPCNT_INFINITY-1, 0,
RS_RDISC, new_drp->dr_ifp);
}
/* Now turn off RIP and delete RIP routes,
@ -552,30 +551,27 @@ parse_ad(naddr from,
u_short life,
struct interface *ifp)
{
static naddr bad_gate;
static struct msg_limit bad_gate;
struct dr *drp, *new_drp;
if (gate == RIP_DEFAULT
|| !check_dst(gate)) {
if (bad_gate != from) {
msglog("router %s advertising bad gateway %s",
naddr_ntoa(from),
naddr_ntoa(gate));
bad_gate = from;
}
msglim(&bad_gate, from,"router %s advertising bad gateway %s",
naddr_ntoa(from),
naddr_ntoa(gate));
return;
}
/* ignore pointers to ourself and routes via unreachable networks
*/
if (ifwithaddr(gate, 1, 0) != 0) {
trace_pkt("\tdiscard Router Discovery Ad pointing at us\n");
trace_pkt(" discard Router Discovery Ad pointing at us");
return;
}
if (!on_net(gate, ifp->int_net, ifp->int_mask)) {
trace_pkt("\tdiscard Router Discovery Ad"
" toward unreachable net\n");
trace_pkt(" discard Router Discovery Ad"
" toward unreachable net");
return;
}
@ -694,6 +690,7 @@ send_rdisc(union ad_u *p,
switch (type) {
case 0: /* unicast */
default:
msg = "Send";
break;
@ -711,7 +708,7 @@ send_rdisc(union ad_u *p,
msg = "Send multicast";
if (ifp->int_state & IS_DUP) {
trace_act("abort multicast output via %s"
" with duplicate address\n",
" with duplicate address",
ifp->int_name);
return;
}
@ -801,14 +798,13 @@ rdisc_adv(void)
{
struct interface *ifp;
if (!supplier)
return;
rdisc_timer.tv_sec = now.tv_sec + NEVER;
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (0 != (ifp->int_state & (IS_NO_ADV_OUT
| IS_PASSIVE
| IS_ALIAS
| IS_BROKE)))
if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)))
continue;
if (!timercmp(&ifp->int_rdisc_timer, &now, >)
@ -844,13 +840,13 @@ rdisc_sol(void)
union ad_u u;
if (supplier)
return;
rdisc_timer.tv_sec = now.tv_sec + NEVER;
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (0 != (ifp->int_state & (IS_NO_SOL_OUT
| IS_PASSIVE
| IS_ALIAS
| IS_BROKE))
if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE))
|| ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
continue;
@ -881,20 +877,14 @@ rdisc_sol(void)
static struct interface * /* 0 if bad */
ck_icmp(char *act,
naddr from,
struct interface *ifp,
naddr to,
union ad_u *p,
u_int len)
{
struct interface *ifp;
char *type;
/* If we could tell the interface on which a packet from address 0
* arrived, we could deal with such solicitations.
*/
ifp = ((from == 0) ? 0 : iflookup(from));
if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
type = "advertisement";
} else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) {
@ -904,8 +894,7 @@ ck_icmp(char *act,
}
if (p->icmp.icmp_code != 0) {
trace_pkt("unrecognized ICMP Router"
" %s code=%d from %s to %s\n",
trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s",
type, p->icmp.icmp_code,
naddr_ntoa(from), naddr_ntoa(to));
return 0;
@ -927,14 +916,22 @@ ck_icmp(char *act,
void
read_d(void)
{
static naddr bad_asize, bad_len;
static struct msg_limit bad_asize, bad_len;
#ifdef USE_PASSIFNAME
static struct msg_limit bad_name;
#endif
struct sockaddr_in from;
int n, fromlen, cc, hlen;
union {
struct ip ip;
u_short s[512/2];
u_char b[512];
} pkt;
struct {
#ifdef USE_PASSIFNAME
char ifname[IFNAMSIZ];
#endif
union {
struct ip ip;
u_short s[512/2];
u_char b[512];
} pkt;
} buf;
union ad_u *p;
n_long *wp;
struct interface *ifp;
@ -942,7 +939,7 @@ read_d(void)
for (;;) {
fromlen = sizeof(from);
cc = recvfrom(rdisc_sock, &pkt, sizeof(pkt), 0,
cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0,
(struct sockaddr*)&from,
&fromlen);
if (cc <= 0) {
@ -953,20 +950,38 @@ read_d(void)
if (fromlen != sizeof(struct sockaddr_in))
logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d",
fromlen);
#ifdef USE_PASSIFNAME
if ((cc -= sizeof(buf.ifname)) < 0)
logbad(0,"missing USE_PASSIFNAME; only %d bytes",
cc+sizeof(buf.ifname));
#endif
hlen = pkt.ip.ip_hl << 2;
hlen = buf.pkt.ip.ip_hl << 2;
if (cc < hlen + ICMP_MINLEN)
continue;
p = (union ad_u *)&pkt.b[hlen];
p = (union ad_u *)&buf.pkt.b[hlen];
cc -= hlen;
ifp = ck_icmp("Recv",
from.sin_addr.s_addr, pkt.ip.ip_dst.s_addr,
p, cc);
#ifdef USE_PASSIFNAME
ifp = ifwithname(buf.ifname, 0);
if (ifp == 0)
msglim(&bad_name, from.sin_addr.s_addr,
"impossible rdisc if_ name %.*s",
IFNAMSIZ, buf.ifname);
#else
/* If we could tell the interface on which a packet from
* address 0 arrived, we could deal with such solicitations.
*/
ifp = ((from.sin_addr.s_addr == 0)
? 0 : iflookup(from.sin_addr.s_addr));
#endif
ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp,
buf.pkt.ip.ip_dst.s_addr, p, cc);
if (ifp == 0)
continue;
if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) {
trace_pkt("\tdiscard our own Router Discovery msg\n");
trace_pkt(" "
"discard our own Router Discovery message");
continue;
}
@ -974,27 +989,21 @@ read_d(void)
case ICMP_ROUTERADVERT:
if (p->ad.icmp_ad_asize*4
< sizeof(p->ad.icmp_ad_info[0])) {
if (bad_asize != from.sin_addr.s_addr) {
msglog("intolerable rdisc address"
" size=%d",
p->ad.icmp_ad_asize);
bad_asize = from.sin_addr.s_addr;
}
msglim(&bad_asize, from.sin_addr.s_addr,
"intolerable rdisc address size=%d",
p->ad.icmp_ad_asize);
continue;
}
if (p->ad.icmp_ad_num == 0) {
trace_pkt("\tempty?\n");
trace_pkt(" empty?");
continue;
}
if (cc != (sizeof(p->ad) - sizeof(p->ad.icmp_ad_info)
+ (p->ad.icmp_ad_num
* sizeof(p->ad.icmp_ad_info[0])))) {
if (bad_len != from.sin_addr.s_addr) {
msglog("rdisc length %d does not"
" match ad_num %d",
cc, p->ad.icmp_ad_num);
bad_len = from.sin_addr.s_addr;
}
msglim(&bad_len, from.sin_addr.s_addr,
"rdisc length %d does not match ad_num"
" %d", cc, p->ad.icmp_ad_num);
continue;
}
if (supplier)

View File

@ -1,4 +1,4 @@
.\" $NetBSD: routed.8,v 1.11 1997/01/27 15:01:58 perry Exp $
.\" $NetBSD: routed.8,v 1.12 1997/02/03 22:03:06 christos Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -98,7 +98,7 @@ After transmitting a RIP
and
Router Discovery Advertisements or Solicitations on a new interface,
the daemon enters a loop, listening for
RIP request and response and Router Discover packets from other hosts.
RIP request and response and Router Discovery packets from other hosts.
.Pp
When a
.Em request
@ -201,7 +201,7 @@ 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
the system has a single network interface and a Router Discovery Advertisement
is received), there is a single default route and a variable number of
redirected host routes in the kernel table.
.Pp
@ -217,13 +217,27 @@ 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.
On a host with more than one network interface,
this default route will be via only one of the interfaces.
Thus, multi-homed hosts running with \f3\-q\f1 might need
.Cm no_rdisc
described below.
.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
By default, neither Router Discovery advertisements nor solicitations
are sent over point to point links (e.g. PPP).
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
Options supported by
@ -240,6 +254,7 @@ ipforwarding=1.
is the opposite of the
.Fl s
option.
This is the default when only one interface is present.
.It Fl d
Do not run in the background.
This option is meant for interactive use.
@ -263,7 +278,7 @@ 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
dangerous. It is more commonly accidentally 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,
@ -398,7 +413,7 @@ are also passive, but are not placed in the kernel
routing table nor are they included in routing updates.
The function of external entries is to indicate
that another routing process
will install such a route if ncessary,
will install such a route if necessary,
and that alternate routes to that destination should not be installed
by
.Nm routed .
@ -501,21 +516,49 @@ 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 passwd Ns \&= Ns Ar XXX1[|KeyID[start|stop]]
specifies a RIPv2 cleartext password that will be included on
all RIPv2 responses sent, and checked on all RIPv2 responses received.
Any blanks, tab characters, commas, or '#', '|', or NULL characters in the
password must be escaped with a backslash (\\).
The common escape sequences \\n, \\r, \\t, \\b, and \\xxx have their
usual meanings.
The
.Cm KeyID
must be unique but is ignored for cleartext passwords.
If present,
.Cm start
and
.Cm stop
are timestamps in the form year/month/day@hour:minute.
They specify when the password is valid.
The valid password with the most future is used on output packets, unless
all passwords have expired, in which case the password that expired most
recently is used, or unless no passwords are valid yet, in which case
no password is output.
Incoming packets can carry any password that is valid, will
be valid within 24 hours, or that was valid within 24 hours.
To protect the secrets, the passwd settings are valid only in the
.Em /etc/gateways
file and only when that file is readable only by UID 0.
.It Cm md5_passwd Ns \&= Ns Ar XXX1|KeyID[start|stop]
specifes a RIPv2 MD5 password.
Except that a
.Cm KeyID
is required, this keyword is similar to
.Cm passwd .
.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 .
marks the interface to not be advertised in updates sent via other
interfaces, and turns off all RIP and router discovery through the interface.
.It Cm no_rip
disables all RIP processing on the specified interface.
If no interfaces are allowed to process RIP packets,
.Nm
acts purely as a router discovery daemon.
.Cm No_rip
is equivalent to
.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out .
Note that turning off RIP without explicitly turning on router
discovery advertisements with
@ -524,7 +567,7 @@ or
.Fl s
causes
.Nm routed
to act as a client router discovery daemon, not adveritising.
to act as a client router discovery daemon, not advertising.
.It Cm no_ripv1_in
causes RIPv1 received responses to be ignored.
.It Cm no_ripv2_in
@ -532,10 +575,15 @@ causes RIPv2 received responses to be ignored.
.It Cm ripv2_out
turns off RIPv1 output and causes RIPv2 advertisements to be
multicast when possible.
.It Cm ripv2
is equivalent to
.Cm no_ripv1_in
and
.Cm no_ripv1_out .
.It Cm no_rdisc
disables the Internet Router Discovery Protocol.
.It Cm no_solicit
disables the tranmission of Router Discovery Solicitations.
disables the transmission of Router Discovery Solicitations.
.It Cm send_solicit
specifies that Router Discovery solicitations should be sent,
even on point-to-point links,
@ -543,7 +591,7 @@ which by default only listen to Router Discovery messages.
.It Cm no_rdisc_adv
disables the transmission of Router Discovery Advertisements
.It Cm rdisc_adv
specifies that Router Discovery advertisements should be sent,
specifies that Router Discovery Advertisements should be sent,
even on point-to-point links,
which by default only listen to Router Discovery messages
.It Cm bcast_rdisc
@ -557,7 +605,7 @@ sets the nominal interval with which Router Discovery Advertisements
are transmitted to N seconds and their lifetime to 3*N.
.It Cm fake_default Ns \&= Ns Ar metric
has an identical effect to
.Fl F Ar net[/mask][,metric]
.Fl F Ar net[/mask][=metric]
with the network and mask coming from the sepcified interface.
.It Cm pm_rdisc
is similar to
@ -569,13 +617,17 @@ 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.
.It Cm trust_gateway Ns \&= Ns Ar rname
causes RIP packets from that router and other routers named in
other
.Cm trust_gateway
keywords to be accept, and packets from other routers to be ignored.
.It Cm redirect_ok
causes RIP to allow ICMP Redirect messages when the system is acting
as a router and forwarding packets.
Otherwise, ICMP Redirect messages are are overridden.
.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

@ -1,8 +1,9 @@
# $NetBSD: Makefile,v 1.2 1996/08/10 01:30:28 thorpej Exp $
# $NetBSD: Makefile,v 1.3 1997/02/03 22:03:15 christos Exp $
# from: @(#)Makefile 8.1 (Berkeley) 6/5/93
PROG= rtquery
MAN= rtquery.8
#COPTS= -g -DDEBUG -Wall
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View File

@ -1,325 +0,0 @@
/* This code could be made a lot faster for PPP */
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
* rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD5 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
#ident "$Revision: 1.1.1.1 $"
#include <strings.h>
#ifdef sgi
#include <bstring.h>
#endif
#include <sys/types.h>
#define MD5_DIGEST_LEN 16
typedef struct {
u_int32_t state[4]; /* state (ABCD) */
u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
extern void MD5Init(MD5_CTX*);
extern void MD5Update(MD5_CTX*, u_char*, u_int);
extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);
/* UINT4 defines a four byte word */
#define UINT4 u_int32_t
#define MD5_memcpy(d,s,l) bcopy(s,d,l)
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform(UINT4[4], unsigned char [64]);
static void Encode(unsigned char *, UINT4 *, unsigned int);
static void Decode(UINT4 *, unsigned char *, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
* Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void
MD5Init(MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
* operation, processing another message block, and updating the
* context.
*/
void
MD5Update(MD5_CTX *context, /* context */
unsigned char *input, /* input block */
unsigned int inputLen) /* length of input block */
{
unsigned int i, indx, partLen;
/* Compute number of bytes mod 64 */
indx = ((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - indx;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
bcopy(input, &context->buffer[indx], partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
indx = 0;
} else {
i = 0;
}
/* Buffer remaining input */
bcopy(&input[i], &context->buffer[indx], inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void
MD5Final(unsigned char digest[MD5_DIGEST_LEN], /* message digest */
MD5_CTX *context) /* context */
{
unsigned char bits[8];
unsigned int indx, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
indx = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (indx < 56) ? (56 - indx) : (120 - indx);
MD5Update(context, PADDING, padLen);
/* Append length (before padding) */
MD5Update(context, bits, 8);
/* Store state in digest */
Encode(digest, context->state, MD5_DIGEST_LEN);
/* Zeroize sensitive information.
*/
bzero(context, sizeof(*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void
MD5Transform(UINT4 state[4],
unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
bzero(x, sizeof(x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
* a multiple of 4.
*/
static void
Encode(unsigned char *output,
UINT4 *input,
unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
* a multiple of 4.
*/
static void
Decode (UINT4 *output,
unsigned char *input,
unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: rtquery.8,v 1.5 1997/01/27 15:03:06 perry Exp $
.\" $NetBSD: rtquery.8,v 1.6 1997/02/03 22:03:18 christos Exp $
.\"
.Dd June 1, 1996
.Dt RTQUERY 8
@ -11,10 +11,15 @@
.Op Fl np1
.Op Fl w Ar timeout
.Op Fl r Ar addr
.Op Fl a Ar secret
.Ar host ...
.Nm
.Op Fl t Ar op
.Ar host ...
.Sh DESCRIPTION
.Nm Rtquery
is used to query a network routing daemon,
is used to query a RIP network routing daemon,
.Xr routed 8
or
.Xr gated 8 ,
@ -76,12 +81,17 @@ By default, each host is given 15 seconds to respond.
.It Fl r Ar addr
ask about the route to destination
.Em addr .
.It Fl a Ar passwd=XXX
.It Fl a Ar md5_passwd=XXX|KeyID
cause the query to be sent with the indicated cleartext or MD5 password.
.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 by the daemon except for a message in the system log.
.Xr gated 8
is likely to ignore these debugging requests.
.El
.Bl -tag -width Ds -offset indent-two
.It Em on=tracefile

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtquery.c,v 1.3 1996/09/24 16:24:26 christos Exp $ */
/* $NetBSD: rtquery.c,v 1.4 1997/02/03 22:03:20 christos Exp $ */
/*-
* Copyright (c) 1982, 1986, 1993
@ -40,7 +40,7 @@ char copyright[] =
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: rtquery.c,v 1.3 1996/09/24 16:24:26 christos Exp $";
static char rcsid[] = "$NetBSD: rtquery.c,v 1.4 1997/02/03 22:03:20 christos Exp $";
#endif
#include <sys/param.h>
@ -66,6 +66,17 @@ static char rcsid[] = "$NetBSD: rtquery.c,v 1.3 1996/09/24 16:24:26 christos Exp
#define _HAVE_SIN_LEN
#endif
#define MD5_DIGEST_LEN 16
typedef struct {
u_int32_t state[4]; /* state (ABCD) */
u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
extern void MD5Init(MD5_CTX*);
extern void MD5Update(MD5_CTX*, u_char*, u_int);
extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);
#define WTIME 15 /* Time to wait for all responses */
#define STIME (250*1000) /* usec to wait for another response */
@ -91,8 +102,10 @@ 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;
int trace, not_trace; /* send trace command or not */
int auth_type = RIP_AUTH_NONE;
char passwd[RIP_AUTH_PW_LEN];
u_long keyid;
struct timeval sent; /* when query sent */
@ -102,21 +115,22 @@ 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);
static int parse_quote(char **, char *, char *, char *, int);
int
void
main(int argc,
char *argv[])
{
int ch, bsize;
char *p, *options, *value;
char *p, *options, *value, delim;
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:t:")) != EOF)
while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != EOF)
switch (ch) {
case 'n':
not_trace = 1;
@ -209,6 +223,31 @@ main(int argc,
}
break;
case 'a':
not_trace = 1;
p = strchr(optarg,'=');
if (!p)
goto usage;
*p++ = '\0';
if (!strcasecmp("passwd",optarg))
auth_type = RIP_AUTH_PW;
else if (!strcasecmp("md5_passwd",optarg))
auth_type = RIP_AUTH_MD5;
else
goto usage;
if (0 > parse_quote(&p,"|",&delim,
passwd,sizeof(passwd)))
goto usage;
if (auth_type == RIP_AUTH_MD5
&& delim == '|') {
keyid = strtoul(p+1,&p,0);
if (keyid > 255 || *p != '\0')
goto usage;
} else if (delim != '\0') {
goto usage;
}
break;
default:
goto usage;
}
@ -216,8 +255,9 @@ main(int argc,
argc -= optind;
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",
" [-a type=passwd] host1 [host2 ...]\n"
"or\t-t {on=filename|more|off|dump}"
" host1 [host2 ...]\n",
pgmname);
exit(1);
}
@ -295,6 +335,8 @@ trace_loop(char *argv[])
static void
query_loop(char *argv[], int argc)
{
# define NA0 (OMSG.rip_auths[0])
# define NA2 (OMSG.rip_auths[2])
struct seen {
struct seen *next;
struct in_addr addr;
@ -305,11 +347,38 @@ query_loop(char *argv[], int argc)
struct timeval now, delay;
struct sockaddr_in from;
int fromlen;
MD5_CTX md5_ctx;
OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
if (ripv2) {
OMSG.rip_vers = RIPv2;
if (auth_type == RIP_AUTH_PW) {
OMSG.rip_nets[1] = OMSG.rip_nets[0];
NA0.a_family = RIP_AF_AUTH;
NA0.a_type = RIP_AUTH_PW;
bcopy(passwd, NA0.au.au_pw,
RIP_AUTH_PW_LEN);
omsg_len += sizeof(OMSG.rip_nets[0]);
} else if (auth_type == RIP_AUTH_MD5) {
OMSG.rip_nets[1] = OMSG.rip_nets[0];
NA0.a_family = RIP_AF_AUTH;
NA0.a_type = RIP_AUTH_MD5;
NA0.au.a_md5.md5_keyid = (int8_t)keyid;
NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN;
NA0.au.a_md5.md5_seqno = 0;
NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]);
NA2.a_family = RIP_AF_AUTH;
NA2.a_type = 1;
bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw));
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, (u_char *)&NA0,
(char *)(&NA2+1) - (char *)&NA0);
MD5Final(NA2.au.au_pw, &md5_ctx);
omsg_len += 2*sizeof(OMSG.rip_nets[0]);
}
} else {
OMSG.rip_vers = RIPv1;
OMSG.rip_nets[0].n_mask = 0;
@ -394,7 +463,7 @@ query_loop(char *argv[], int argc)
}
/* sent do one host
/* send to one host
*/
static int
out(char *host)
@ -432,6 +501,60 @@ out(char *host)
}
/*
* Convert string to printable characters
*/
static char *
qstring(u_char *s, int len)
{
static char buf[8*20+1];
char *p;
u_char *s2, c;
for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
c = *s++;
if (c == '\0') {
for (s2 = s+1; s2 < &s[len]; s2++) {
if (*s2 != '\0')
break;
}
if (s2 >= &s[len])
goto exit;
}
if (c >= ' ' && c < 0x7f && c != '\\') {
*p++ = c;
continue;
}
*p++ = '\\';
switch (c) {
case '\\':
*p++ = '\\';
break;
case '\n':
*p++= 'n';
break;
case '\r':
*p++= 'r';
break;
case '\t':
*p++ = 't';
break;
case '\b':
*p++ = 'b';
break;
default:
p += sprintf(p,"%o",c);
break;
}
}
exit:
*p = '\0';
return buf;
}
/*
* Handle an incoming RIP packet.
*/
@ -448,7 +571,7 @@ rip_input(struct sockaddr_in *from,
int i;
struct hostent *hp;
struct netent *np;
struct netauth *a;
struct netauth *na;
if (nflag) {
@ -545,11 +668,33 @@ rip_input(struct sockaddr_in *from,
}
} else if (n->n_family == RIP_AF_AUTH) {
a = (struct netauth*)n;
(void)printf(" authentication type %d: ",
a->a_type);
for (i = 0; i < sizeof(a->au.au_pw); i++)
(void)printf("%02x ", a->au.au_pw[i]);
na = (struct netauth*)n;
if (na->a_type == RIP_AUTH_PW
&& n == IMSG.rip_nets) {
(void)printf(" Password Authentication:"
" \"%s\"\n",
qstring(na->au.au_pw,
RIP_AUTH_PW_LEN));
continue;
}
if (na->a_type == RIP_AUTH_MD5
&& n == IMSG.rip_nets) {
(void)printf(" MD5 Authentication"
" len=%d KeyID=%d"
" seqno=%d"
" rsvd=%#x,%#x\n",
na->au.a_md5.md5_pkt_len,
na->au.a_md5.md5_keyid,
na->au.a_md5.md5_seqno,
na->au.a_md5.rsvd[0],
na->au.a_md5.rsvd[1]);
continue;
}
(void)printf(" Authentication type %d: ",
ntohs(na->a_type));
for (i = 0; i < sizeof(na->au.au_pw); i++)
(void)printf("%02x ", na->au.au_pw[i]);
putc('\n', stdout);
continue;
@ -653,3 +798,64 @@ getnet(char *name,
rt->n_mask = htonl(mask);
return 1;
}
/* strtok(), but honoring backslash
*/
static int /* -1=bad */
parse_quote(char **linep,
char *delims,
char *delimp,
char *buf,
int lim)
{
char c, *pc, *p;
pc = *linep;
if (*pc == '\0')
return -1;
for (;;) {
if (lim == 0)
return -1;
c = *pc++;
if (c == '\0')
break;
if (c == '\\' && pc != '\0') {
if ((c = *pc++) == 'n') {
c = '\n';
} else if (c == 'r') {
c = '\r';
} else if (c == 't') {
c = '\t';
} else if (c == 'b') {
c = '\b';
} else if (c >= '0' && c <= '7') {
c -= '0';
if (*pc >= '0' && *pc <= '7') {
c = (c<<3)+(*pc++ - '0');
if (*pc >= '0' && *pc <= '7')
c = (c<<3)+(*pc++ - '0');
}
}
} else {
for (p = delims; *p != '\0'; ++p) {
if (*p == c)
goto exit;
}
}
*buf++ = c;
--lim;
}
exit:
if (delimp != 0)
*delimp = c;
*linep = pc-1;
if (lim != 0)
*buf = '\0';
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: table.c,v 1.3 1996/09/24 16:24:23 christos Exp $ */
/* $NetBSD: table.c,v 1.4 1997/02/03 22:03:08 christos Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -36,12 +36,13 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: table.c,v 1.3 1996/09/24 16:24:23 christos Exp $";
static char rcsid[] = "$NetBSD: table.c,v 1.4 1997/02/03 22:03:08 christos Exp $";
#endif
#include "defs.h"
static struct rt_spare *rts_better(struct rt_entry *);
static struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0};
struct radix_node_head *rhead; /* root of the radix tree */
@ -58,6 +59,7 @@ int stopint;
int total_routes;
/* zap any old routes through this gateway */
naddr age_bad_gate;
@ -657,6 +659,8 @@ rtioctl(int action, /* RTM_DELETE, etc */
#endif
} w;
long cc;
# define PAT " %-10s %s metric=%d flags=%#x"
# define ARGS rtm_type_name(action), rtname(dst,mask,gate), metric, flags
again:
bzero(&w, sizeof(w));
@ -692,37 +696,30 @@ again:
#endif
}
if (TRACEKERNEL)
trace_kernel("write kernel %s %s->%s metric=%d flags=%#x\n",
rtm_type_name(action),
addrname(dst, mask, 0), naddr_ntoa(gate),
metric, flags);
#ifndef NO_INSTALL
cc = write(rt_sock, &w, w.w_rtm.rtm_msglen);
if (cc == w.w_rtm.rtm_msglen)
return;
if (cc < 0) {
if (errno == ESRCH
&& (action == RTM_CHANGE || action == RTM_DELETE)) {
trace_act("route to %s disappeared before %s\n",
addrname(dst, mask, 0),
rtm_type_name(action));
trace_act("route disappeared before" PAT, ARGS);
if (action == RTM_CHANGE) {
action = RTM_ADD;
goto again;
}
return;
}
msglog("write(rt_sock) %s %s --> %s: %s",
rtm_type_name(action),
addrname(dst, mask, 0), naddr_ntoa(gate),
strerror(errno));
} else {
msglog("write(rt_sock) wrote %d instead of %d",
cc, w.w_rtm.rtm_msglen);
msglog("write(rt_sock)" PAT ": ", ARGS, strerror(errno));
return;
} else if (cc != w.w_rtm.rtm_msglen) {
msglog("write(rt_sock) wrote %d instead of %d for" PAT,
cc, w.w_rtm.rtm_msglen, ARGS);
return;
}
#endif
if (TRACEKERNEL)
trace_kernel("write kernel" PAT, ARGS);
#undef PAT
#undef ARGS
}
@ -746,7 +743,7 @@ static struct khash {
#define KS_DELETED 0x100 /* already deleted */
time_t k_keep;
#define K_KEEP_LIM 30
time_t k_redirect_time;
time_t k_redirect_time; /* when redirected route 1st seen */
} *khash_bins[KHASH_SIZE];
@ -815,6 +812,36 @@ kern_check_static(struct khash *k,
}
/* operate on a kernel entry
*/
static void
kern_ioctl(struct khash *k,
int action, /* RTM_DELETE, etc */
int flags)
{
switch (action) {
case RTM_DELETE:
k->k_state &= ~KS_DYNAMIC;
if (k->k_state & KS_DELETED)
return;
k->k_state |= KS_DELETED;
break;
case RTM_ADD:
k->k_state &= ~KS_DELETED;
break;
case RTM_CHANGE:
if (k->k_state & KS_DELETED) {
action = RTM_ADD;
k->k_state &= ~KS_DELETED;
}
break;
}
rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_metric, flags);
}
/* add a route the kernel told us
*/
static void
@ -832,14 +859,13 @@ rtm_add(struct rt_msghdr *rtm,
} else if (INFO_MASK(info) != 0) {
mask = ntohl(S_ADDR(INFO_MASK(info)));
} else {
msglog("punt %s without mask",
rtm_type_name(rtm->rtm_type));
msglog("ignore %s without mask", rtm_type_name(rtm->rtm_type));
return;
}
if (INFO_GATE(info) == 0
|| INFO_GATE(info)->sa_family != AF_INET) {
msglog("punt %s without gateway",
msglog("ignore %s without gateway",
rtm_type_name(rtm->rtm_type));
return;
}
@ -860,20 +886,32 @@ rtm_add(struct rt_msghdr *rtm,
k->k_state |= KS_STATIC;
if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
if (supplier) {
if (INFO_AUTHOR(info) != 0
&& INFO_AUTHOR(info)->sa_family == AF_INET)
ifp = iflookup(S_ADDR(INFO_AUTHOR(info)));
else
ifp = 0;
if (supplier
&& (ifp == 0 || !(ifp->int_state & IS_REDIRECT_OK))) {
/* Routers are not supposed to listen to redirects,
* so delete it.
* so delete it if it came via an unknown interface
* or the interface does not have special permission.
*/
k->k_state &= ~KS_DYNAMIC;
k->k_state |= KS_DELETE;
LIM_SEC(need_kern, 0);
trace_act("mark redirected %s --> %s for deletion"
" since this is a router\n",
trace_act("mark for deletion redirected %s --> %s"
" via %s",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate));
naddr_ntoa(k->k_gate),
ifp ? ifp->int_name : "unknown interface");
} else {
k->k_state |= KS_DYNAMIC;
k->k_redirect_time = now.tv_sec;
trace_act("accept redirected %s --> %s via %s",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate),
ifp ? ifp->int_name : "unknown interface");
}
return;
}
@ -890,20 +928,13 @@ rtm_add(struct rt_msghdr *rtm,
/* Put static routes with real metrics into the daemon table so
* they can be advertised.
*
* Find the interface concerned
* Find the interface toward the gateway.
*/
ifp = iflookup(k->k_gate);
if (ifp == 0) {
/* if there is no known interface,
* maybe there is a new interface
*/
ifinit();
ifp = iflookup(k->k_gate);
if (ifp == 0)
msglog("static route %s --> %s impossibly lacks ifp",
addrname(S_ADDR(INFO_DST(info)), mask, 0),
naddr_ntoa(k->k_gate));
}
if (ifp == 0)
msglog("static route %s --> %s impossibly lacks ifp",
addrname(S_ADDR(INFO_DST(info)), mask, 0),
naddr_ntoa(k->k_gate));
kern_check_static(k, ifp);
}
@ -917,8 +948,8 @@ rtm_lose(struct rt_msghdr *rtm,
{
if (INFO_GATE(info) == 0
|| INFO_GATE(info)->sa_family != AF_INET) {
msglog("punt %s without gateway",
rtm_type_name(rtm->rtm_type));
trace_act("ignore %s without gateway",
rtm_type_name(rtm->rtm_type));
return;
}
@ -982,7 +1013,7 @@ flush_kern(void)
if (INFO_GATE(&info)->sa_family != AF_LINK)
continue;
ifp = ifwithindex(((struct sockaddr_dl *)
INFO_GATE(&info))->sdl_index);
INFO_GATE(&info))->sdl_index, 0);
if (ifp == 0)
continue;
if ((ifp->int_if_flags & IFF_POINTOPOINT)
@ -1063,15 +1094,16 @@ read_rt(void)
if (m.r.rtm.rtm_type == RTM_IFINFO
|| m.r.rtm.rtm_type == RTM_NEWADDR
|| m.r.rtm.rtm_type == RTM_DELADDR) {
ifp = ifwithindex(m.ifm.ifm_index);
ifp = ifwithindex(m.ifm.ifm_index,
m.r.rtm.rtm_type != RTM_DELADDR);
if (ifp == 0)
trace_act("note %s with flags %#x"
" for index #%d\n",
" for interface index #%d",
rtm_type_name(m.r.rtm.rtm_type),
m.ifm.ifm_flags,
m.ifm.ifm_index);
else
trace_act("note %s with flags %#x for %s\n",
trace_act("note %s with flags %#x for %s",
rtm_type_name(m.r.rtm.rtm_type),
m.ifm.ifm_flags,
ifp->int_name);
@ -1099,12 +1131,12 @@ read_rt(void)
m.r.rtm.rtm_addrs);
if (INFO_DST(&info) == 0) {
trace_act("ignore %s without dst\n", str);
trace_act("ignore %s without dst", str);
continue;
}
if (INFO_DST(&info)->sa_family != AF_INET) {
trace_act("ignore %s for AF %d\n", str,
trace_act("ignore %s for AF %d", str,
INFO_DST(&info)->sa_family);
continue;
}
@ -1119,7 +1151,7 @@ read_rt(void)
addrname(S_ADDR(INFO_DST(&info)), mask, 0));
if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) {
trace_act("ignore multicast %s\n", str);
trace_act("ignore multicast %s", str);
continue;
}
@ -1137,31 +1169,31 @@ read_rt(void)
case RTM_CHANGE:
case RTM_REDIRECT:
if (m.r.rtm.rtm_errno != 0) {
trace_act("ignore %s with \"%s\" error\n",
trace_act("ignore %s with \"%s\" error",
str, strerror(m.r.rtm.rtm_errno));
} else {
trace_act("%s\n", str);
trace_act("%s", str);
rtm_add(&m.r.rtm,&info,0);
}
break;
case RTM_DELETE:
if (m.r.rtm.rtm_errno != 0) {
trace_act("ignore %s with \"%s\" error\n",
trace_act("ignore %s with \"%s\" error",
str, strerror(m.r.rtm.rtm_errno));
} else {
trace_act("%s\n", str);
trace_act("%s", str);
del_static(S_ADDR(INFO_DST(&info)), mask, 1);
}
break;
case RTM_LOSING:
trace_act("%s\n", str);
trace_act("%s", str);
rtm_lose(&m.r.rtm,&info);
break;
default:
trace_act("ignore %s\n", str);
trace_act("ignore %s", str);
break;
}
}
@ -1268,8 +1300,7 @@ walk_kern(struct radix_node *rn, struct walkarg *argp)
* the kernel if is not a alias.
*/
if (RT->rt_ifp == 0
|| ((RT->rt_ifp->int_state & IS_REMOTE)
&& RT->rt_ifp->int_metric == 0))
|| (RT->rt_ifp->int_state & IS_REMOTE))
ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE);
}
@ -1297,7 +1328,7 @@ walk_kern(struct radix_node *rn, struct walkarg *argp)
static void
fix_kern(void)
{
int i, flags;
int i;
struct khash *k, **pk;
@ -1325,40 +1356,29 @@ fix_kern(void)
continue;
}
if ((k->k_state & (KS_DELETE | KS_DYNAMIC))
== KS_DELETE) {
if (!(k->k_state & KS_DELETED))
rtioctl(RTM_DELETE,
k->k_dst, k->k_gate, k->k_mask,
0, 0);
if ((k->k_state & KS_DELETE)
&& !(k->k_state & KS_DYNAMIC)) {
kern_ioctl(k, RTM_DELETE, 0);
*pk = k->k_next;
free(k);
continue;
}
if (0 != (k->k_state&(KS_ADD|KS_CHANGE|KS_DEL_ADD))) {
if (k->k_state & KS_DEL_ADD) {
rtioctl(RTM_DELETE,
k->k_dst,k->k_gate,k->k_mask,
0, 0);
k->k_state &= ~KS_DYNAMIC;
}
if (k->k_state & KS_DEL_ADD)
kern_ioctl(k, RTM_DELETE, 0);
flags = 0;
if (0 != (k->k_state&(KS_GATEWAY|KS_DYNAMIC)))
flags |= RTF_GATEWAY;
if (k->k_state & KS_ADD) {
rtioctl(RTM_ADD,
k->k_dst, k->k_gate, k->k_mask,
k->k_metric, flags);
} else if (k->k_state & KS_CHANGE) {
rtioctl(RTM_CHANGE,
k->k_dst,k->k_gate,k->k_mask,
k->k_metric, flags);
}
k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD);
if (k->k_state & KS_ADD) {
kern_ioctl(k, RTM_ADD,
((0 != (k->k_state & (KS_GATEWAY
| KS_DYNAMIC)))
? RTF_GATEWAY : 0));
} else if (k->k_state & KS_CHANGE) {
kern_ioctl(k, RTM_CHANGE,
((0 != (k->k_state & (KS_GATEWAY
| KS_DYNAMIC)))
? RTF_GATEWAY : 0));
}
k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD);
/* Mark this route to be deleted in the next cycle.
* This deletes routes that disappear from the
@ -1431,7 +1451,7 @@ del_redirects(naddr bad_gate,
k->k_state |= KS_DELETE;
k->k_state &= ~KS_DYNAMIC;
need_kern.tv_sec = now.tv_sec;
trace_act("mark redirected %s --> %s for deletion\n",
trace_act("mark redirected %s --> %s for deletion",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate));
}
@ -1679,7 +1699,11 @@ rtswitch(struct rt_entry *rt,
rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC),
rts->rts_gate, rts->rts_router, rts->rts_metric,
rts->rts_tag, rts->rts_ifp, rts->rts_time, label);
*rts = swap;
if (swap.rts_metric == HOPCNT_INFINITY) {
*rts = rts_empty;
} else {
*rts = swap;
}
}
@ -1711,6 +1735,15 @@ rtdelete(struct rt_entry *rt)
}
void
rts_delete(struct rt_entry *rt,
struct rt_spare *rts)
{
trace_upslot(rt, rts, 0, 0, 0, HOPCNT_INFINITY, 0, 0);
*rts = rts_empty;
}
/* Get rid of a bad route, and try to switch to a replacement.
*/
void
@ -1805,7 +1838,6 @@ walk_bad(struct radix_node *rn, struct walkarg *argp)
#define RT ((struct rt_entry *)rn)
struct rt_spare *rts;
int i;
time_t new_time;
/* fix any spare routes through the interface
@ -1813,21 +1845,10 @@ walk_bad(struct radix_node *rn, struct walkarg *argp)
rts = RT->rt_spares;
for (i = NUM_SPARES; i != 1; i--) {
rts++;
if (rts->rts_ifp != 0
&& (rts->rts_ifp->int_state & IS_BROKE)) {
/* mark the spare route to be deleted immediately */
new_time = rts->rts_time;
if (new_time >= now_garbage)
new_time = now_garbage-1;
trace_upslot(RT, rts, rts->rts_gate,
rts->rts_router, 0,
HOPCNT_INFINITY, rts->rts_tag,
new_time);
rts->rts_ifp = 0;
rts->rts_metric = HOPCNT_INFINITY;
rts->rts_time = new_time;
}
if (rts->rts_metric < HOPCNT_INFINITY
&& (rts->rts_ifp == 0
|| (rts->rts_ifp->int_state & IS_BROKE)))
rts_delete(RT, rts);
}
/* Deal with the main route
@ -1895,13 +1916,8 @@ walk_age(struct radix_node *rn, struct walkarg *argp)
/* trash the spare routes when they go bad */
if (rts->rts_metric < HOPCNT_INFINITY
&& now_garbage > rts->rts_time) {
trace_upslot(RT, rts, rts->rts_gate,
rts->rts_router, rts->rts_ifp,
HOPCNT_INFINITY, rts->rts_tag,
rts->rts_time);
rts->rts_metric = HOPCNT_INFINITY;
}
&& now_garbage > rts->rts_time)
rts_delete(RT, rts);
}
@ -1933,29 +1949,46 @@ void
age(naddr bad_gate)
{
struct interface *ifp;
int need_query = 0;
/* If not listening to RIP, there is no need to age the routes in
* the table.
*/
age_timer.tv_sec = (now.tv_sec
+ ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL));
age_timer.tv_sec = now.tv_sec + (rip_sock < 0
? NEVER
: SUPPLY_INTERVAL);
/* Check for dead IS_REMOTE interfaces by timing their
* transmissions.
*/
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
/* Check for dead IS_REMOTE interfaces by timing their
* transmissions.
*/
if ((ifp->int_state & IS_REMOTE)
&& !(ifp->int_state & IS_PASSIVE)
&& (ifp->int_state & IS_ACTIVE)) {
LIM_SEC(age_timer, now.tv_sec+SUPPLY_INTERVAL);
if (!(ifp->int_state & IS_REMOTE))
continue;
if (now.tv_sec - ifp->int_act_time > EXPIRE_TIME
&& !(ifp->int_state & IS_BROKE)) {
msglog("remote interface %s to %s timed out"
"--turned off",
ifp->int_name,
naddr_ntoa(ifp->int_addr));
if_bad(ifp);
}
/* ignore unreachable remote interfaces */
if (!check_remote(ifp))
continue;
/* Restore remote interface that has become reachable
*/
if (ifp->int_state & IS_BROKE)
if_ok(ifp, "remote ");
if (ifp->int_act_time != NEVER
&& now.tv_sec - ifp->int_act_time > EXPIRE_TIME) {
msglog("remote interface %s to %s timed out after"
" %d:%d",
ifp->int_name,
naddr_ntoa(ifp->int_dstaddr),
(now.tv_sec - ifp->int_act_time)/60,
(now.tv_sec - ifp->int_act_time)%60);
if_sick(ifp);
}
/* If we have not heard from the other router
* recently, ask it.
*/
if (now.tv_sec >= ifp->int_query_time) {
ifp->int_query_time = NEVER;
need_query = 1;
}
}
@ -1965,4 +1998,8 @@ age(naddr bad_gate)
/* Update the kernel routing table. */
fix_kern();
/* poke reticent remote gateways */
if (need_query)
rip_query();
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: trace.c,v 1.15 1996/09/24 16:24:24 christos Exp $ */
/* $NetBSD: trace.c,v 1.16 1997/02/03 22:03:10 christos Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -36,7 +36,7 @@
#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD: trace.c,v 1.15 1996/09/24 16:24:24 christos Exp $";
static char rcsid[] = "$NetBSD: trace.c,v 1.16 1997/02/03 22:03:10 christos Exp $";
#endif
#define RIPCMDS
@ -54,15 +54,69 @@ static char rcsid[] = "$NetBSD: trace.c,v 1.15 1996/09/24 16:24:24 christos Exp
#define NRECORDS 50 /* size of circular trace buffer */
u_int tracelevel, new_tracelevel;
int tracelevel, new_tracelevel;
FILE *ftrace = stdout; /* output trace file */
static char *tracelevel_pat = "%s\n";
char savetracename[MAXPATHLEN+1];
static char *sigtrace_pat = "%s";
static char savetracename[MAXPATHLEN+1];
char inittracename[MAXPATHLEN+1];
int file_trace; /* 1=tracing to file, not stdout */
static void trace_dump(void);
/* convert string to printable characters
*/
static char *
qstring(u_char *s, int len)
{
static char buf[8*20+1];
char *p;
u_char *s2, c;
for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
c = *s++;
if (c == '\0') {
for (s2 = s+1; s2 < &s[len]; s2++) {
if (*s2 != '\0')
break;
}
if (s2 >= &s[len])
goto exit;
}
if (c >= ' ' && c < 0x7f && c != '\\') {
*p++ = c;
continue;
}
*p++ = '\\';
switch (c) {
case '\\':
*p++ = '\\';
break;
case '\n':
*p++= 'n';
break;
case '\r':
*p++= 'r';
break;
case '\t':
*p++ = 't';
break;
case '\b':
*p++ = 'b';
break;
default:
p += sprintf(p,"%o",c);
break;
}
}
exit:
*p = '\0';
return buf;
}
/* convert IP address to a string, but not into a single buffer
*/
char *
@ -110,15 +164,15 @@ ts(time_t secs) {
* This assumes that 'now' is update once for each event, and
* that at least now.tv_usec changes.
*/
static struct timeval lastlog_time;
void
lastlog(void)
{
static struct timeval last;
if (last.tv_sec != now.tv_sec
|| last.tv_usec != now.tv_usec) {
if (lastlog_time.tv_sec != now.tv_sec
|| lastlog_time.tv_usec != now.tv_usec) {
(void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
last = now;
lastlog_time = now;
}
}
@ -132,6 +186,7 @@ tmsg(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
fflush(ftrace);
}
}
@ -146,15 +201,17 @@ trace_close(void)
fflush(stdout);
fflush(stderr);
if (ftrace != 0
&& savetracename[0] != '\0') {
if (ftrace != 0 && file_trace) {
if (ftrace != stdout)
fclose(ftrace);
ftrace = 0;
fd = open(_PATH_DEVNULL, O_RDWR);
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
(void)close(fd);
fclose(ftrace);
ftrace = 0;
}
lastlog_time.tv_sec = 0;
}
@ -179,7 +236,7 @@ trace_off(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
fflush(ftrace);
(void)fputc('\n',ftrace);
}
trace_close();
@ -187,102 +244,11 @@ trace_off(char *p, ...)
}
void
trace_on(char *filename,
int trusted)
{
struct stat stbuf;
FILE *n_ftrace;
/* Given a null filename when tracing is already on, increase the
* debugging level and re-open the file in case it has been unlinked.
*/
if (filename[0] == '\0') {
if (tracelevel != 0) {
new_tracelevel++;
tracelevel_pat = "trace command: %s\n";
} else if (savetracename[0] == '\0') {
msglog("missing trace file name");
return;
}
filename = savetracename;
} else if (!strcmp(filename,"dump/../table")) {
trace_dump();
return;
} else {
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
#ifdef _PATH_TRACE
&& (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)
|| strstr(filename,"../")
|| 0 > stat(_PATH_TRACE, &stbuf))
#endif
&& strcmp(filename, savetracename)) {
msglog("wrong directory for trace file \"%s\"",
filename);
return;
}
}
n_ftrace = fopen(filename, "a");
if (n_ftrace == 0) {
msglog("failed to open trace file \"%s\" %s",
filename, strerror(errno));
return;
}
tmsg("switch to trace file %s\n", filename);
trace_close();
if (filename != savetracename)
strncpy(savetracename, filename, sizeof(savetracename)-1);
ftrace = n_ftrace;
fflush(stdout);
fflush(stderr);
dup2(fileno(ftrace), STDOUT_FILENO);
dup2(fileno(ftrace), STDERR_FILENO);
if (new_tracelevel == 0)
new_tracelevel = 1;
set_tracelevel();
}
/* ARGSUSED */
void
sigtrace_on(int s)
{
new_tracelevel++;
tracelevel_pat = "SIGUSR1: %s\n";
}
/* ARGSUSED */
void
sigtrace_off(int s)
{
new_tracelevel--;
tracelevel_pat = "SIGUSR2: %s\n";
}
/* Move to next higher level of tracing when -t option processed or
* SIGUSR1 is received. Successive levels are:
* actions
* actions + packets
* actions + packets + contents
/* log a change in tracing
*/
void
set_tracelevel(void)
tracelevel_msg(char *pat,
int dump) /* -1=no dump, 0=default, 1=force */
{
static char *off_msgs[MAX_TRACELEVEL] = {
"Tracing actions stopped",
@ -296,32 +262,165 @@ set_tracelevel(void)
"Tracing packet contents started",
"Tracing kernel changes started",
};
u_int old_tracelevel = tracelevel;
if (new_tracelevel > MAX_TRACELEVEL) {
if (new_tracelevel < 0)
new_tracelevel = 0;
else if (new_tracelevel > MAX_TRACELEVEL)
new_tracelevel = MAX_TRACELEVEL;
if (new_tracelevel == tracelevel) {
tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
if (new_tracelevel < tracelevel) {
if (new_tracelevel <= 0) {
trace_off(pat, off_msgs[0]);
} else do {
tmsg(pat, off_msgs[tracelevel]);
}
while (--tracelevel != new_tracelevel);
} else if (new_tracelevel > tracelevel) {
do {
tmsg(pat, on_msgs[tracelevel++]);
} while (tracelevel != new_tracelevel);
}
if (dump > 0
|| (dump == 0 && old_tracelevel == 0 && tracelevel != 0))
trace_dump();
}
void
set_tracefile(char *filename,
char *pat,
int dump) /* -1=no dump, 0=default, 1=force */
{
struct stat stbuf;
FILE *n_ftrace;
char *fn;
/* Allow a null filename to increase the level if the trace file
* is already open or if coming from a trusted source, such as
* a signal or the command line.
*/
if (filename == 0 || filename[0] == '\0') {
filename = 0;
if (ftrace == 0) {
if (inittracename[0] == '\0') {
msglog("missing trace file name");
return;
}
fn = inittracename;
} else {
fn = 0;
}
} else if (!strcmp(filename,"dump/../table")) {
trace_dump();
return;
} else {
/* Allow the file specified with "-T file" to be reopened,
* but require all other names specified over the net to
* match the official path. The path can specify a directory
* in which the file is to be created.
*/
if (strcmp(filename, inittracename)
#ifdef _PATH_TRACE
&& (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)
|| strstr(filename,"../")
|| 0 > stat(_PATH_TRACE, &stbuf))
#endif
) {
msglog("wrong trace file \"%s\"", filename);
return;
}
}
while (new_tracelevel != tracelevel) {
if (new_tracelevel < tracelevel) {
if (--tracelevel == 0)
trace_off(tracelevel_pat, off_msgs[0]);
else
tmsg(tracelevel_pat, off_msgs[tracelevel]);
} else {
if (ftrace == 0) {
if (savetracename[0] != '\0')
trace_on(savetracename, 1);
else
ftrace = stdout;
}
tmsg(tracelevel_pat, on_msgs[tracelevel++]);
/* If the new tracefile exists, it must be a regular file.
*/
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;
}
fn = filename;
}
if (fn != 0) {
n_ftrace = fopen(fn, "a");
if (n_ftrace == 0) {
msglog("failed to open trace file \"%s\" %s",
fn, strerror(errno));
if (fn == inittracename)
inittracename[0] = '\0';
return;
}
tmsg("switch to trace file %s", fn);
file_trace = 1;
trace_close();
if (fn != savetracename)
strncpy(savetracename, fn, sizeof(savetracename)-1);
ftrace = n_ftrace;
fflush(stdout);
fflush(stderr);
dup2(fileno(ftrace), STDOUT_FILENO);
dup2(fileno(ftrace), STDERR_FILENO);
}
if (new_tracelevel == 0 || filename == 0)
new_tracelevel++;
tracelevel_msg(pat, dump != 0 ? dump : (filename != 0));
}
/* ARGSUSED */
void
sigtrace_on(int s)
{
new_tracelevel++;
sigtrace_pat = "SIGUSR1: %s";
}
/* ARGSUSED */
void
sigtrace_off(int s)
{
new_tracelevel--;
sigtrace_pat = "SIGUSR2: %s";
}
/* Set tracing after a signal.
*/
void
set_tracelevel(void)
{
if (new_tracelevel == tracelevel)
return;
/* If tracing entirely off, and there was no tracefile specified
* on the command line, then leave it off.
*/
if (new_tracelevel > tracelevel && ftrace == 0) {
if (savetracename[0] != '\0') {
set_tracefile(savetracename,sigtrace_pat,0);
} else if (inittracename[0] != '\0') {
set_tracefile(inittracename,sigtrace_pat,0);
} else {
new_tracelevel = 0;
return;
}
} else {
tracelevel_msg(sigtrace_pat, 0);
}
tracelevel_pat = "%s\n";
}
@ -378,10 +477,11 @@ static struct bits if_bits[] = {
};
static struct bits is_bits[] = {
{ IS_ALIAS, 0, "ALIAS" },
{ IS_SUBNET, 0, "" },
{ IS_REMOTE, 0, "REMOTE" },
{ IS_REMOTE, (IS_NO_RDISC
| IS_BCAST_RDISC), "REMOTE" },
{ IS_PASSIVE, (IS_NO_RDISC
| IS_BCAST_RDISC
| IS_NO_RIP
| IS_NO_SUPER_AG
| IS_PM_RDISC
@ -390,10 +490,11 @@ static struct bits is_bits[] = {
{ IS_CHECKED, 0, "" },
{ IS_ALL_HOSTS, 0, "" },
{ IS_ALL_ROUTERS, 0, "" },
{ IS_RIP_QUERIED, 0, "" },
{ IS_DISTRUST, 0, "DISTRUST" },
{ IS_BROKE, IS_SICK, "BROKEN" },
{ IS_SICK, 0, "SICK" },
{ IS_ACTIVE, 0, "ACTIVE" },
{ IS_DUP, 0, "DUPLICATE" },
{ IS_REDIRECT_OK, 0, "REDIRECT_OK" },
{ IS_NEED_NET_SYN, 0, "" },
{ IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
{ IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
@ -415,7 +516,7 @@ static struct bits is_bits[] = {
{ 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" },
{ IS_PM_RDISC, 0, "" },
{ 0, 0, "%#x"}
};
@ -473,21 +574,47 @@ trace_bits(struct bits *tbl,
}
static char *
trace_pair(naddr dst,
naddr mask,
char *gate)
char *
rtname(naddr dst,
naddr mask,
naddr 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);
(void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), naddr_ntoa(gate));
return buf;
}
static void
print_rts(struct rt_spare *rts,
int force_metric, /* -1=suppress, 0=default */
int force_ifp, /* -1=suppress, 0=default */
int force_router, /* -1=suppress, 0=default, 1=display */
int force_tag, /* -1=suppress, 0=default, 1=display */
int force_time) /* 0=suppress, 1=display */
{
if (force_metric >= 0)
(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
if (force_ifp >= 0)
(void)fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ?
"if?" : rts->rts_ifp->int_name));
if (force_router > 0
|| (force_router == 0 && rts->rts_router != rts->rts_gate))
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_router));
if (force_time > 0)
(void)fprintf(ftrace, "%s ", ts(rts->rts_time));
if (force_tag > 0
|| (force_tag == 0 && rts->rts_tag != 0))
(void)fprintf(ftrace, "tag=%#x ",
ntohs(rts->rts_tag));
}
void
trace_if(char *act,
struct interface *ifp)
@ -496,15 +623,18 @@ trace_if(char *act,
return;
lastlog();
(void)fprintf(ftrace, "%s interface %-4s ", act, ifp->int_name);
(void)fprintf(ftrace, "%-3s interface %-4s ", act, ifp->int_name);
(void)fprintf(ftrace, "%-15s-->%-15s ",
naddr_ntoa(ifp->int_addr),
addrname(htonl((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_net),
addrname(((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: htonl(ifp->int_net)),
ifp->int_mask, 1));
if (ifp->int_metric != 0)
(void)fprintf(ftrace, "metric=%d ", ifp->int_metric);
if (!IS_RIP_OUT_OFF(ifp->int_state)
&& ifp->int_d_metric != 0)
(void)fprintf(ftrace, "fake_default=%d ", ifp->int_d_metric);
trace_bits(if_bits, ifp->int_if_flags, 0);
trace_bits(is_bits, ifp->int_state, 0);
(void)fputc('\n',ftrace);
@ -521,59 +651,60 @@ trace_upslot(struct rt_entry *rt,
u_short tag,
time_t new_time)
{
struct rt_spare new;
if (!TRACEACTIONS || ftrace == 0)
return;
if (rts->rts_gate == gate
&& rts->rts_router == router
&& rts->rts_metric == metric
&& rts->rts_tag == tag)
return;
new.rts_ifp = ifp;
new.rts_gate = gate;
new.rts_router = router;
new.rts_metric = metric;
new.rts_time = new_time;
new.rts_tag = tag;
lastlog();
if (rts->rts_gate != RIP_DEFAULT) {
if (gate == 0) {
(void)fprintf(ftrace, "Del #%d %-35s ",
rts - rt->rt_spares,
rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
print_rts(&new, 0,0,0,0,
rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp));
} else if (rts->rts_gate != RIP_DEFAULT) {
(void)fprintf(ftrace, "Chg #%d %-35s ",
rts - rt->rt_spares,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rts->rts_gate)));
if (rts->rts_gate != rts->rts_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_gate));
if (rts->rts_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
if (rts->rts_ifp != 0)
(void)fprintf(ftrace, "%s ",
rts->rts_ifp->int_name);
(void)fprintf(ftrace, "%s\n", ts(rts->rts_time));
rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
print_rts(rts, 0,0,
rts->rts_gate != gate,
rts->rts_tag != tag,
rts != rt->rt_spares || AGE_RT(rt->rt_state,
rt->rt_ifp));
(void)fprintf(ftrace, " %19s%-16s ",
"",
(void)fprintf(ftrace, "\n %19s%-16s ", "",
gate != rts->rts_gate ? naddr_ntoa(gate) : "");
if (gate != router)
(void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
if (tag != rts->rts_tag)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
if (metric != rts->rts_metric)
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (ifp != rts->rts_ifp && ifp != 0 )
(void)fprintf(ftrace, "%s ", ifp->int_name);
(void)fprintf(ftrace, "%s\n",
new_time != rts->rts_time ? ts(new_time) : "");
print_rts(&new,
-(metric == rts->rts_metric),
-(ifp == rts->rts_ifp),
0,
rts->rts_tag != tag,
new_time != rts->rts_time && (rts != rt->rt_spares
|| AGE_RT(rt->rt_state,
ifp)));
} else {
(void)fprintf(ftrace, "Add #%d %-35s ",
rts - rt->rt_spares,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(gate)));
if (gate != router)
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
if (tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (ifp != 0)
(void)fprintf(ftrace, "%s ", ifp->int_name);
(void)fprintf(ftrace, "%s\n", ts(new_time));
rtname(rt->rt_dst, rt->rt_mask, gate));
print_rts(&new, 0,0,0,0,
rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp));
}
(void)fputc('\n',ftrace);
}
@ -590,6 +721,7 @@ trace_kernel(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
}
@ -606,6 +738,7 @@ trace_act(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
}
@ -622,6 +755,7 @@ trace_pkt(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
}
@ -636,6 +770,8 @@ trace_change(struct rt_entry *rt,
time_t new_time,
char *label)
{
struct rt_spare new;
if (ftrace == 0)
return;
@ -645,67 +781,49 @@ trace_change(struct rt_entry *rt,
&& rt->rt_state == state
&& rt->rt_tag == tag)
return;
new.rts_ifp = ifp;
new.rts_gate = gate;
new.rts_router = router;
new.rts_metric = metric;
new.rts_time = new_time;
new.rts_tag = tag;
lastlog();
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
(void)fprintf(ftrace, "%s %-35s ",
label,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rt->rt_gate)),
rt->rt_metric);
if (rt->rt_router != rt->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rt->rt_router));
if (rt->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate));
print_rts(rt->rt_spares,
0,0,0,0, AGE_RT(rt->rt_state, rt->rt_ifp));
trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
(void)fprintf(ftrace, "%s ",
rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name);
(void)fprintf(ftrace, "%s\n",
AGE_RT(rt->rt_state, rt->rt_ifp) ? ts(rt->rt_time) : "");
(void)fprintf(ftrace, "%*s %19s%-16s ",
(void)fprintf(ftrace, "\n%*s %19s%-16s ",
strlen(label), "", "",
rt->rt_gate != gate ? naddr_ntoa(gate) : "");
if (rt->rt_metric != metric)
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (router != gate)
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(router));
if (rt->rt_tag != tag)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
print_rts(&new,
-(metric == rt->rt_metric),
-(ifp == rt->rt_ifp),
0,
rt->rt_tag != tag,
rt->rt_time != new_time && AGE_RT(rt->rt_state,ifp));
if (rt->rt_state != state)
trace_bits(rs_bits, state, 1);
if (rt->rt_ifp != ifp)
(void)fprintf(ftrace, "%s ",
ifp != 0 ? ifp->int_name : "?");
(void)fprintf(ftrace, "%s\n",
((rt->rt_time == new_time || !AGE_RT(rt->rt_state, ifp))
? "" : ts(new_time)));
(void)fputc('\n',ftrace);
}
void
trace_add_del(char * action, struct rt_entry *rt)
{
u_int state = rt->rt_state;
if (ftrace == 0)
return;
lastlog();
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
(void)fprintf(ftrace, "%s %-35s ",
action,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rt->rt_gate)),
rt->rt_metric);
if (rt->rt_router != rt->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rt->rt_router));
if (rt->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
trace_bits(rs_bits, state, 0);
(void)fprintf(ftrace, "%s ",
rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?");
(void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate));
print_rts(rt->rt_spares, 0,0,0,0,AGE_RT(rt->rt_state,rt->rt_ifp));
trace_bits(rs_bits, rt->rt_state, 0);
(void)fputc('\n',ftrace);
}
@ -716,42 +834,23 @@ walk_trace(struct radix_node *rn,
{
#define RT ((struct rt_entry *)rn)
struct rt_spare *rts;
int i, age;
int i, age = AGE_RT(RT->rt_state, RT->rt_ifp);
(void)fprintf(ftrace, " %-35s metric=%-2d ",
trace_pair(RT->rt_dst, RT->rt_mask,
naddr_ntoa(RT->rt_gate)),
RT->rt_metric);
if (RT->rt_router != RT->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(RT->rt_router));
if (RT->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ",
ntohs(RT->rt_tag));
(void)fprintf(ftrace, " %-35s ",
rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate));
print_rts(&RT->rt_spares[0], 0,0,0,0,age);
trace_bits(rs_bits, RT->rt_state, 0);
(void)fprintf(ftrace, "%s ",
RT->rt_ifp == 0 ? "?" : RT->rt_ifp->int_name);
age = AGE_RT(RT->rt_state, RT->rt_ifp);
if (age)
(void)fprintf(ftrace, "%s", ts(RT->rt_time));
if (RT->rt_poison_time >= now_garbage
&& RT->rt_poison_metric < RT->rt_metric)
(void)fprintf(ftrace, "pm=%d@%s",
RT->rt_poison_metric, ts(RT->rt_poison_time));
rts = &RT->rt_spares[1];
for (i = 1; i < NUM_SPARES; i++, rts++) {
if (rts->rts_metric != HOPCNT_INFINITY) {
(void)fprintf(ftrace,"\n #%d%15s%-16s metric=%-2d ",
i, "", naddr_ntoa(rts->rts_gate),
rts->rts_metric);
if (rts->rts_router != rts->rts_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_router));
if (rts->rts_tag != 0)
(void)fprintf(ftrace, "tag=%#x ",
ntohs(rts->rts_tag));
(void)fprintf(ftrace, "%s ",
(rts->rts_ifp == 0
? "?" : rts->rts_ifp->int_name));
if (age)
(void)fprintf(ftrace, "%s", ts(rts->rts_time));
if (rts->rts_gate != RIP_DEFAULT) {
(void)fprintf(ftrace,"\n #%d%15s%-16s ",
i, "", naddr_ntoa(rts->rts_gate));
print_rts(rts, 0,0,0,0,1);
}
}
(void)fputc('\n',ftrace);
@ -763,10 +862,15 @@ walk_trace(struct radix_node *rn,
static void
trace_dump(void)
{
struct interface *ifp;
if (ftrace == 0)
return;
lastlog();
(void)fputs("current daemon state:\n", ftrace);
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next)
trace_if("", ifp);
(void)rn_walktree(rhead, walk_trace, 0);
}
@ -779,8 +883,8 @@ trace_rip(char *dir1, char *dir2,
int size) /* total size of message */
{
struct netinfo *n, *lim;
struct netauth *a;
int i;
# define NA (msg->rip_auths)
int i, seen_route;
if (!TRACEPACKETS || ftrace == 0)
return;
@ -804,17 +908,20 @@ trace_rip(char *dir1, char *dir2,
if (!TRACECONTENTS)
return;
seen_route = 0;
switch (msg->rip_cmd) {
case RIPCMD_REQUEST:
case RIPCMD_RESPONSE:
n = msg->rip_nets;
lim = (struct netinfo *)((char*)msg + size);
for (; n < lim; n++) {
if (n->n_family == RIP_AF_UNSPEC
if (!seen_route
&& n->n_family == RIP_AF_UNSPEC
&& ntohl(n->n_metric) == HOPCNT_INFINITY
&& n+1 == lim
&& n == msg->rip_nets
&& msg->rip_cmd == RIPCMD_REQUEST) {
&& msg->rip_cmd == RIPCMD_REQUEST
&& (n+1 == lim
|| (n+2 == lim
&& (n+1)->n_family == RIP_AF_AUTH))) {
(void)fputs("\tQUERY ", ftrace);
if (n->n_dst != 0)
(void)fprintf(ftrace, "%s ",
@ -823,32 +930,57 @@ trace_rip(char *dir1, char *dir2,
(void)fprintf(ftrace, "mask=%#x ",
(u_int)ntohl(n->n_mask));
if (n->n_nhop != 0)
(void)fprintf(ftrace, " nhop=%s ",
(void)fprintf(ftrace, "nhop=%s ",
naddr_ntoa(n->n_nhop));
if (n->n_tag != 0)
(void)fprintf(ftrace, "tag=%#x",
(void)fprintf(ftrace, "tag=%#x ",
ntohs(n->n_tag));
(void)fputc('\n',ftrace);
continue;
}
if (n->n_family == RIP_AF_AUTH) {
a = (struct netauth*)n;
if (NA->a_type == RIP_AUTH_PW
&& n == msg->rip_nets) {
(void)fprintf(ftrace, "\tPassword"
" Authentication:"
" \"%s\"\n",
qstring(NA->au.au_pw,
RIP_AUTH_PW_LEN));
continue;
}
if (NA->a_type == RIP_AUTH_MD5
&& n == msg->rip_nets) {
(void)fprintf(ftrace,
"\tMD5 Authentication"
" len=%d KeyID=%u"
" seqno=%u"
" rsvd=%#x,%#x\n",
NA->au.a_md5.md5_pkt_len,
NA->au.a_md5.md5_keyid,
NA->au.a_md5.md5_seqno,
NA->au.a_md5.rsvd[0],
NA->au.a_md5.rsvd[1]);
continue;
}
(void)fprintf(ftrace,
"\tAuthentication type %d: ",
ntohs(a->a_type));
"\tAuthentication"
" type %d: ",
ntohs(NA->a_type));
for (i = 0;
i < sizeof(a->au.au_pw);
i < sizeof(NA->au.au_pw);
i++)
(void)fprintf(ftrace, "%02x ",
a->au.au_pw[i]);
NA->au.au_pw[i]);
(void)fputc('\n',ftrace);
continue;
}
seen_route = 1;
if (n->n_family != RIP_AF_INET) {
(void)fprintf(ftrace,
"\t(af %d) %-18s mask=%#x",
"\t(af %d) %-18s mask=%#x ",
ntohs(n->n_family),
naddr_ntoa(n->n_dst),
(u_int)ntohl(n->n_mask));
@ -879,7 +1011,8 @@ trace_rip(char *dir1, char *dir2,
break;
case RIPCMD_TRACEON:
fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
fprintf(ftrace, "\tfile=\"%.*s\"\n", size-4,
msg->rip_tracefile);
break;
case RIPCMD_TRACEOFF: