diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 1997-07-30 22:24:49 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 1997-07-30 22:24:49 +0000 |
commit | 8f8968006824e23ac888c36b119b28a019d1faa2 (patch) | |
tree | 2457b0ca7255d4f80fea253921eec882a56bee34 | |
parent | 41488b8b4aff0afcea12013f2220c254191a4060 (diff) |
update to sgi-02apr97
still have problems w/ defaults from pppd
-rw-r--r-- | sbin/routed/Makefile | 7 | ||||
-rw-r--r-- | sbin/routed/defs.h | 117 | ||||
-rw-r--r-- | sbin/routed/if.c | 620 | ||||
-rw-r--r-- | sbin/routed/input.c | 617 | ||||
-rw-r--r-- | sbin/routed/main.c | 224 | ||||
-rw-r--r-- | sbin/routed/output.c | 463 | ||||
-rw-r--r-- | sbin/routed/parms.c | 640 | ||||
-rw-r--r-- | sbin/routed/rdisc.c | 157 | ||||
-rw-r--r-- | sbin/routed/routed.8 | 92 | ||||
-rw-r--r-- | sbin/routed/rtquery/rtquery.8 | 12 | ||||
-rw-r--r-- | sbin/routed/rtquery/rtquery.c | 236 | ||||
-rw-r--r-- | sbin/routed/table.c | 323 | ||||
-rw-r--r-- | sbin/routed/trace.c | 601 |
13 files changed, 2752 insertions, 1357 deletions
diff --git a/sbin/routed/Makefile b/sbin/routed/Makefile index 137c08c6c00..0751fee659d 100644 --- a/sbin/routed/Makefile +++ b/sbin/routed/Makefile @@ -1,14 +1,13 @@ -# $OpenBSD: Makefile,v 1.5 1996/09/06 13:05:51 deraadt Exp $ +# $OpenBSD: Makefile,v 1.6 1997/07/30 22:24:39 mickey Exp $ # @(#)Makefile 8.1 (Berkeley) 6/19/93 PROG= routed SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c MAN= routed.8 +SUBDIR= rtquery +# this is for /sys/net/radix.c only CFLAGS+=-D_ROUTED -D'min(a,b)=(a < b ? a : b)' -D'log=syslog' CFLAGS+=-D'panic(s)={log(LOG_ERR,s); exit(1);}' -SUBDIR= rtquery -DPADD= ${LIBCOMPAT} -LDADD= -lcompat # Do *NOT* turn this flag on unless you like security holes #CFLAGS+=-DPERMIT_TRACE diff --git a/sbin/routed/defs.h b/sbin/routed/defs.h index 6a8b25cc2f9..2f0a9c2882c 100644 --- a/sbin/routed/defs.h +++ b/sbin/routed/defs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: defs.h,v 1.4 1996/10/02 06:51:41 mickey Exp $ */ +/* $OpenBSD: defs.h,v 1.5 1997/07/30 22:24:40 mickey Exp $ */ /* * Copyright (c) 1983, 1988, 1993 @@ -70,6 +70,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> @@ -100,7 +101,8 @@ */ /* #define MCAST_PPP_BUG */ -#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 @@ -112,6 +114,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 @@ -132,15 +141,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; @@ -208,7 +221,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 \ @@ -224,7 +237,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) */ @@ -240,6 +257,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 */ @@ -253,7 +271,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; @@ -269,11 +293,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 */ @@ -345,14 +369,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 */ @@ -363,7 +387,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 */ @@ -386,7 +426,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; @@ -404,19 +445,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; @@ -431,16 +474,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)) @@ -458,15 +510,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 *, ...); @@ -480,6 +533,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); @@ -514,6 +568,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 *); @@ -535,13 +590,21 @@ 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 *, void *); 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 diff --git a/sbin/routed/if.c b/sbin/routed/if.c index 02246359644..0924ef5c49b 100644 --- a/sbin/routed/if.c +++ b/sbin/routed/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.4 1996/10/02 06:51:43 mickey Exp $ */ +/* $OpenBSD: if.c,v 1.5 1997/07/30 22:24:41 mickey Exp $ */ /* * Copyright (c) 1983, 1993 @@ -36,24 +36,109 @@ #if !defined(lint) static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; #else -static char rcsid[] = "$OpenBSD: if.c,v 1.4 1996/10/02 06:51:43 mickey Exp $"; +static char rcsid[] = "$OpenBSD: if.c,v 1.5 1997/07/30 22:24:41 mickey 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); - - } 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; + } + + 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; + } - /* 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); - /* 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; } diff --git a/sbin/routed/input.c b/sbin/routed/input.c index db66da6398b..ed5ce00eb75 100644 --- a/sbin/routed/input.c +++ b/sbin/routed/input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: input.c,v 1.7 1996/10/02 06:51:44 mickey Exp $ */ +/* $OpenBSD: input.c,v 1.8 1997/07/30 22:24:42 mickey Exp $ */ /* * Copyright (c) 1983, 1988, 1993 @@ -36,25 +36,40 @@ #if !defined(lint) static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; #else -static char rcsid[] = "$OpenBSD: input.c,v 1.7 1996/10/02 06:51:44 mickey Exp $"; +static char rcsid[] = "$OpenBSD: input.c,v 1.8 1997/07/30 22:24:42 mickey Exp $"; #endif #include "defs.h" +#include <md5.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; - int fromlen, cc; - union pkt_buf inbuf; + struct interface *aifp; + int fromlen, cc; +#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 +85,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 +135,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; - - if (sifp != 0) - sifp->int_state |= IS_ACTIVE; + /* Notice when we hear from a remote gateway + */ + if (aifp != 0 + && (aifp->int_state & IS_REMOTE)) + aifp->int_act_time = now.tv_sec; - 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 +189,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: - /* did the request come from a router? + /* For mere requests, be a little sloppy about the source */ - if (from->sin_port == htons(RIP_PORT)) { - /* yes, ignore it if RIP is off so that it does not - * depend on us. - */ - if (rip_sock < 0) { - trace_pkt("ignore request while RIP off\n"); + 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; } + } - /* Ignore the request if we talking to ourself - * (and not a remote gateway). + /* did the request come from a router? + */ + if (from->sin_port == htons(RIP_PORT)) { + /* yes, ignore the request if RIP is off so that + * the router does not depend on us. */ - 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; + } + 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; } - for (; n < lim; n++) { - n->n_metric = ntohl(n->n_metric); + 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 +283,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 +305,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 (aifp == 0) { + trace_pkt("ignore distant router"); + return; + } 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))) + || 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 +431,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 +465,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,35 +513,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; + } } } - for (; n < lim; n++) { + /* 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; + + do { if (n->n_family == RIP_AF_AUTH) continue; @@ -439,39 +553,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; @@ -482,14 +592,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; } } } @@ -498,14 +607,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) @@ -549,9 +656,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) { @@ -580,9 +687,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 } @@ -611,7 +719,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. @@ -697,12 +806,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 { @@ -729,7 +842,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; @@ -740,3 +852,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 +} diff --git a/sbin/routed/main.c b/sbin/routed/main.c index 301b60e3d1a..fc3831134c9 100644 --- a/sbin/routed/main.c +++ b/sbin/routed/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.5 1997/01/15 23:41:12 millert Exp $ */ +/* $OpenBSD: main.c,v 1.6 1997/07/30 22:24:43 mickey Exp $ */ /* * Copyright (c) 1983, 1988, 1993 @@ -39,7 +39,7 @@ char copyright[] = #if !defined(lint) static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93"; #else -static char rcsid[] = "$OpenBSD: main.c,v 1.5 1997/01/15 23:41:12 millert Exp $"; +static char rcsid[] = "$OpenBSD: main.c,v 1.6 1997/07/30 22:24:43 mickey Exp $"; #endif #include "defs.h" @@ -50,6 +50,14 @@ static char rcsid[] = "$OpenBSD: main.c,v 1.5 1997/01/15 23:41:12 millert Exp $" #include <signal.h> #include <fcntl.h> #include <sys/file.h> +#if defined(sgi) && !defined(PRE_KUDZU) +#include <sys/capability.h> +int tirix_socket(int,int,int); +int tirix_bind(int, const struct sockaddr *, int); +#else +#define tirix_socket socket +#define tirix_bind bind +#endif pid_t mypid; @@ -98,12 +106,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 +183,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 +192,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 +210,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 +230,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,33 +271,29 @@ 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)); /* prepare socket connected to the kernel. */ - rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); + rt_sock = tirix_socket(AF_ROUTE, SOCK_RAW, 0); if (rt_sock < 0) BADERR(1,"rt_sock = socket()"); if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) @@ -295,11 +309,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 +342,7 @@ usage: /* Ask for routes */ rip_query(); - if (!supplier) - rdisc_sol(); + rdisc_sol(); /* Loop forever, listening and broadcasting. */ @@ -343,7 +358,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 +366,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 +503,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 +566,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 +585,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) { @@ -600,7 +619,7 @@ get_rip_sock(naddr addr, sin.sin_family = AF_INET; sin.sin_port = htons(RIP_PORT); sin.sin_addr.s_addr = addr; - if (bind(s, (struct sockaddr *)&sin,sizeof(sin)) < 0) { + if (tirix_bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { if (serious) BADERR(errno != EADDRINUSE, "bind(rip_sock)"); return -1; @@ -625,7 +644,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 +652,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 +707,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 +734,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 +807,8 @@ timevalsub(struct timeval *t1, } +/* put a message into the system log + */ void msglog(char *p, ...) { @@ -810,6 +828,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, ...) { @@ -829,3 +909,33 @@ logbad(int dump, char *p, ...) abort(); exit(1); } +#if defined(sgi) && !defined(PRE_KUDZU) + + +int +tirix_socket(int domain ,int type, int protocol) +{ + cap_t ocap; + cap_value_t cap_priv_port = CAP_PRIV_PORT; + int r; + + ocap = cap_acquire(1, &cap_priv_port); + r = socket(domain, type, protocol); + cap_surrender(ocap); + return r; +} + + +int +tirix_bind(int s, const struct sockaddr *name, int namelen) +{ + int r; + cap_t ocap; + cap_value_t cap_priv_port = CAP_PRIV_PORT; + + ocap = cap_acquire(1, &cap_priv_port); + r = bind(s, name, namelen); + cap_surrender(ocap); + return r; +} +#endif diff --git a/sbin/routed/output.c b/sbin/routed/output.c index c1ad2fc6a12..7d74b07cba5 100644 --- a/sbin/routed/output.c +++ b/sbin/routed/output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output.c,v 1.3 1996/09/05 14:31:36 mickey Exp $ */ +/* $OpenBSD: output.c,v 1.4 1997/07/30 22:24:43 mickey Exp $ */ /* * Copyright (c) 1983, 1988, 1993 @@ -36,10 +36,11 @@ #if !defined(lint) static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93"; #else -static char rcsid[] = "$OpenBSD: output.c,v 1.3 1996/09/05 14:31:36 mickey Exp $"; +static char rcsid[] = "$OpenBSD: output.c,v 1.4 1997/07/30 22:24:43 mickey Exp $"; #endif #include "defs.h" +#include <md5.h> int update_seqno; @@ -54,37 +55,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 +147,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 +182,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 +213,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 +320,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 +336,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 +346,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 +366,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 +373,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 +423,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; @@ -367,22 +458,24 @@ walk_supply(struct radix_node *rn, 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; @@ -492,51 +585,72 @@ walk_supply(struct radix_node *rn, * 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; @@ -557,10 +671,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; @@ -599,94 +714,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++; } } @@ -696,21 +796,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); } @@ -738,36 +838,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 @@ -782,13 +874,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 */ @@ -818,28 +914,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); @@ -862,13 +951,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); } diff --git a/sbin/routed/parms.c b/sbin/routed/parms.c index 7e632ebea6c..f175e38f745 100644 --- a/sbin/routed/parms.c +++ b/sbin/routed/parms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parms.c,v 1.4 1997/01/17 07:12:22 millert Exp $ */ +/* $OpenBSD: parms.c,v 1.5 1997/07/30 22:24:44 mickey Exp $ */ /* * Copyright (c) 1983, 1993 @@ -39,10 +39,12 @@ static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; #include "defs.h" #include "pathnames.h" +#include <sys/stat.h> struct parm *parms; struct intnet *intnets; +struct tgate *tgates; /* use configured parameters @@ -50,49 +52,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) { @@ -109,10 +117,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; + } + } } @@ -141,15 +166,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; @@ -160,19 +191,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); @@ -181,31 +213,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); @@ -218,7 +253,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. @@ -229,17 +264,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 @@ -252,110 +289,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; - - 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; - } + state |= IS_NO_RIP; + + 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); +} + + +/* 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; } -/* parse a set of parameters for an interface +/* 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=")-1]) != '\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' @@ -363,13 +567,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; @@ -378,21 +582,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")) { + for (;;) { + tgt = line + strspn(line, " ,\n\r"); + if (*tgt == '\0') + break; + + 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' - || tok[3] == '\0' - || strlen(tok) > IFNAMSIZ+3) - break; - strcpy(parm.parm_name, tok+3); + || 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 (PARSE("passwd")) { - if (tok[7] == '\0' - || strlen(tok) > RIP_AUTH_PW_LEN+7) - break; - strcpy(parm.parm_passwd, tok+7); + } 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); @@ -408,11 +649,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); @@ -436,47 +684,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 } @@ -484,38 +738,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) @@ -525,17 +784,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; } @@ -546,13 +814,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; @@ -573,17 +841,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); @@ -591,12 +861,22 @@ getnet(char *name, return 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; } @@ -615,6 +895,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; } diff --git a/sbin/routed/rdisc.c b/sbin/routed/rdisc.c index c90ef80f116..9552e6928b3 100644 --- a/sbin/routed/rdisc.c +++ b/sbin/routed/rdisc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rdisc.c,v 1.2 1996/09/22 20:48:12 millert Exp $ */ +/* $OpenBSD: rdisc.c,v 1.3 1997/07/30 22:24:45 mickey Exp $ */ /* * Copyright (c) 1995 @@ -41,6 +41,12 @@ static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> +#if defined(sgi) && !defined(PRE_KUDZU) +#include <sys/capability.h> +extern int tirix_socket(int,int,int); +#else +#define tirix_socket socket +#endif /* router advertisement ICMP packet */ struct icmp_ad { @@ -126,15 +132,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)); @@ -147,7 +152,7 @@ static void get_rdisc_sock(void) { if (rdisc_sock < 0) { - rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + rdisc_sock = tirix_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (rdisc_sock < 0) BADERR(1,"rdisc_sock = socket()"); fix_sock(rdisc_sock,"rdisc_sock"); @@ -160,7 +165,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) { @@ -173,8 +179,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; } @@ -252,7 +257,7 @@ set_supplier(void) if (supplier_set) return; - trace_act("start suppying routes\n"); + trace_act("start suppying routes"); /* Forget discovered routes. */ @@ -326,8 +331,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; @@ -413,8 +417,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(); @@ -485,7 +489,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 @@ -503,7 +507,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); @@ -511,7 +515,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), @@ -526,7 +530,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, @@ -550,30 +555,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; } @@ -692,6 +694,7 @@ send_rdisc(union ad_u *p, switch (type) { case 0: /* unicast */ + default: msg = "Send"; break; @@ -709,7 +712,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; } @@ -799,14 +802,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, >) @@ -842,13 +844,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; @@ -879,20 +881,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) { @@ -902,8 +898,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; @@ -925,14 +920,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; @@ -940,7 +943,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) { @@ -951,20 +954,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; } @@ -972,27 +993,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) diff --git a/sbin/routed/routed.8 b/sbin/routed/routed.8 index bfd1d3348a9..cf7f61f9f16 100644 --- a/sbin/routed/routed.8 +++ b/sbin/routed/routed.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: routed.8,v 1.9 1997/06/26 21:53:05 deraadt Exp $ +.\" $OpenBSD: routed.8,v 1.10 1997/07/30 22:24:45 mickey 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 @@ -200,12 +200,7 @@ currently chosen router dies. If all discovered routers disappear, the daemon resumes listening to RIP responses. .Pp -While using Router Discovery (which happens by default when -the system has a single network interface and a Router Discover Advertisement -is received), there is a single default route and a variable number of -redirected host routes in the kernel table. -.Pp -The Router Discover standard requires that advertisements +The Router Discovery standard requires that advertisements have a default "lifetime" of 30 minutes. That means should something happen, a client can be without a good route for 30 minutes. It is a good idea to reduce the default to 45 @@ -216,14 +211,23 @@ on the command line or in the .Pa /etc/gateways file. +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 +244,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 +268,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 +403,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 +506,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 +557,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 +565,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 +581,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 +595,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 +607,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 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 diff --git a/sbin/routed/rtquery/rtquery.8 b/sbin/routed/rtquery/rtquery.8 index 229ca09d611..4508defc915 100644 --- a/sbin/routed/rtquery/rtquery.8 +++ b/sbin/routed/rtquery/rtquery.8 @@ -9,10 +9,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 , @@ -74,12 +79,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 diff --git a/sbin/routed/rtquery/rtquery.c b/sbin/routed/rtquery/rtquery.c index 07411c8285e..f5747d975ff 100644 --- a/sbin/routed/rtquery/rtquery.c +++ b/sbin/routed/rtquery/rtquery.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtquery.c,v 1.6 1997/06/30 06:33:31 deraadt Exp $ */ +/* $OpenBSD: rtquery.c,v 1.7 1997/07/30 22:24:48 mickey Exp $ */ /*- * Copyright (c) 1982, 1986, 1993 @@ -64,6 +64,17 @@ static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93"; #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 */ @@ -89,8 +100,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 */ @@ -100,21 +113,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:")) != -1) + while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) switch (ch) { case 'n': not_trace = 1; @@ -207,6 +221,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; } @@ -214,8 +253,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); } @@ -293,6 +333,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; @@ -303,11 +345,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; @@ -392,7 +461,7 @@ query_loop(char *argv[], int argc) } -/* sent do one host +/* send to one host */ static int out(char *host) @@ -431,6 +500,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. */ static void @@ -446,7 +569,7 @@ rip_input(struct sockaddr_in *from, int i; struct hostent *hp; struct netent *np; - struct netauth *a; + struct netauth *na; if (nflag) { @@ -543,11 +666,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; @@ -651,3 +796,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; +} diff --git a/sbin/routed/table.c b/sbin/routed/table.c index 0d3be6f61fe..061542be0f2 100644 --- a/sbin/routed/table.c +++ b/sbin/routed/table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table.c,v 1.3 1996/10/02 06:51:47 mickey Exp $ */ +/* $OpenBSD: table.c,v 1.4 1997/07/30 22:24:46 mickey Exp $ */ /* * Copyright (c) 1983, 1988, 1993 @@ -40,6 +40,7 @@ static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; #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 */ @@ -56,6 +57,7 @@ int stopint; int total_routes; +/* zap any old routes through this gateway */ naddr age_bad_gate; @@ -139,12 +141,14 @@ ag_out(struct ag_info *ag, */ if (ag->ag_state & AGS_REDUN0) { if (ag->ag_state & AGS_REDUN1) - return; + return; /* quit if fully redundant */ + /* make it finer if it is half-redundant */ bit = (-ag->ag_mask) >> 1; ag->ag_dst_h |= bit; ag->ag_mask |= bit; } else if (ag->ag_state & AGS_REDUN1) { + /* make it finer if it is half-redundant */ bit = (-ag->ag_mask) >> 1; ag->ag_mask |= bit; } @@ -470,11 +474,17 @@ ag_check(naddr dst, ag->ag_tag = tag; tag = x; + /* The promoted route is even-redundant only if the + * even twin was fully redundant. It is not + * odd-redundant because the odd-twin will still be + * in the table. + */ x = ag->ag_state; + if (!AG_IS_REDUN(x)) + x &= ~AGS_REDUN0; + x &= ~AGS_REDUN1; ag->ag_state = state; state = x; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN0; x = ag->ag_metric; ag->ag_metric = metric; @@ -484,6 +494,7 @@ ag_check(naddr dst, ag->ag_pref = pref; pref = x; + /* take the newest sequence number */ if (seqno >= ag->ag_seqno) seqno = ag->ag_seqno; else @@ -493,15 +504,20 @@ ag_check(naddr dst, if (!(state & AGS_PROMOTE)) break; /* cannot promote either twin */ - /* promote the new, odd twin by shaving its + /* Promote the new, odd twin by shaving its * mask and address. + * The promoted route is odd-redundant only if the + * odd twin was fully redundant. It is not + * even-redundant because the even twin is still in + * the table. */ + if (!AG_IS_REDUN(state)) + state &= ~AGS_REDUN1; + state &= ~AGS_REDUN0; if (seqno > ag->ag_seqno) seqno = ag->ag_seqno; else ag->ag_seqno = seqno; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN1; } mask <<= 1; @@ -655,6 +671,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)); @@ -690,37 +708,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 } @@ -744,7 +755,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]; @@ -813,6 +824,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 @@ -830,14 +871,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; } @@ -858,20 +898,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; } @@ -888,20 +940,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); } @@ -915,8 +960,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; } @@ -980,7 +1025,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) @@ -1061,15 +1106,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); @@ -1097,12 +1143,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; } @@ -1117,7 +1163,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; } @@ -1135,31 +1181,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; } } @@ -1267,8 +1313,7 @@ walk_kern(struct radix_node *rn, * 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); } @@ -1296,7 +1341,7 @@ walk_kern(struct radix_node *rn, static void fix_kern(void) { - int i, flags; + int i; struct khash *k, **pk; @@ -1324,40 +1369,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; - } - - 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_DEL_ADD) + kern_ioctl(k, RTM_DELETE, 0); + + 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 @@ -1430,7 +1464,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)); } @@ -1678,7 +1712,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; + } } @@ -1710,6 +1748,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 +1852,6 @@ walk_bad(struct radix_node *rn, #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 +1859,10 @@ walk_bad(struct radix_node *rn, 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 @@ -1896,13 +1931,8 @@ walk_age(struct radix_node *rn, /* 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); } @@ -1934,29 +1964,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)) + continue; + + /* ignore unreachable remote interfaces */ + if (!check_remote(ifp)) + continue; + /* Restore remote interface that has become reachable */ - 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 (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); - } + 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; } } @@ -1966,4 +2013,8 @@ age(naddr bad_gate) /* Update the kernel routing table. */ fix_kern(); + + /* poke reticent remote gateways */ + if (need_query) + rip_query(); } diff --git a/sbin/routed/trace.c b/sbin/routed/trace.c index 406fc22e3e3..564cec8350d 100644 --- a/sbin/routed/trace.c +++ b/sbin/routed/trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trace.c,v 1.6 1997/02/27 08:31:28 angelos Exp $ */ +/* $OpenBSD: trace.c,v 1.7 1997/07/30 22:24:47 mickey Exp $ */ /* $NetBSD: trace.c,v 1.13 1995/06/20 22:28:03 christos Exp $ */ /* @@ -37,7 +37,7 @@ #if !defined(lint) static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93"; #else -static char rcsid[] = "$OpenBSD: trace.c,v 1.6 1997/02/27 08:31:28 angelos Exp $"; +static char rcsid[] = "$OpenBSD: trace.c,v 1.7 1997/07/30 22:24:47 mickey Exp $"; #endif #define RIPCMDS @@ -55,15 +55,69 @@ static char rcsid[] = "$OpenBSD: trace.c,v 1.6 1997/02/27 08:31:28 angelos 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 * @@ -111,15 +165,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; } } @@ -133,6 +187,7 @@ tmsg(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); fflush(ftrace); } } @@ -147,15 +202,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; } @@ -180,7 +237,7 @@ trace_off(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); - fflush(ftrace); + (void)fputc('\n',ftrace); } trace_close(); @@ -188,32 +245,101 @@ trace_off(char *p, ...) } +/* log a change in tracing + */ void -trace_on(char *filename, - int trusted) +tracelevel_msg(char *pat, + int dump) /* -1=no dump, 0=default, 1=force */ +{ + static char *off_msgs[MAX_TRACELEVEL] = { + "Tracing actions stopped", + "Tracing packets stopped", + "Tracing packet contents stopped", + "Tracing kernel changes stopped", + }; + static char *on_msgs[MAX_TRACELEVEL] = { + "Tracing actions started", + "Tracing packets started", + "Tracing packet contents started", + "Tracing kernel changes started", + }; + u_int old_tracelevel = tracelevel; + + + if (new_tracelevel < 0) + new_tracelevel = 0; + else if (new_tracelevel > MAX_TRACELEVEL) + new_tracelevel = MAX_TRACELEVEL; + + 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; - /* Given a null filename when tracing is already on, increase the - * debugging level and re-open the file in case it has been unlinked. + /* 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] == '\0') { - if (tracelevel != 0) { - new_tracelevel++; - tracelevel_pat = "trace command: %s\n"; - } else if (savetracename[0] == '\0') { - msglog("missing trace file name"); - return; + 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; } - filename = savetracename; } 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; + } + + /* 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\"", @@ -221,40 +347,37 @@ trace_on(char *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); + 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; } - } - 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", fn); - tmsg("switch to trace file %s\n", filename); - trace_close(); - if (filename != savetracename) - strncpy(savetracename, filename, sizeof(savetracename)-1); - ftrace = n_ftrace; + file_trace = 1; + trace_close(); - fflush(stdout); - fflush(stderr); - dup2(fileno(ftrace), STDOUT_FILENO); - dup2(fileno(ftrace), STDERR_FILENO); + 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) - new_tracelevel = 1; - set_tracelevel(); + if (new_tracelevel == 0 || filename == 0) + new_tracelevel++; + tracelevel_msg(pat, dump != 0 ? dump : (filename != 0)); } @@ -263,7 +386,7 @@ void sigtrace_on(int s) { new_tracelevel++; - tracelevel_pat = "SIGUSR1: %s\n"; + sigtrace_pat = "SIGUSR1: %s"; } @@ -272,57 +395,33 @@ void sigtrace_off(int s) { new_tracelevel--; - tracelevel_pat = "SIGUSR2: %s\n"; + sigtrace_pat = "SIGUSR2: %s"; } -/* Move to next higher level of tracing when -t option processed or - * SIGUSR1 is received. Successive levels are: - * actions - * actions + packets - * actions + packets + contents +/* Set tracing after a signal. */ void set_tracelevel(void) { - static char *off_msgs[MAX_TRACELEVEL] = { - "Tracing actions stopped", - "Tracing packets stopped", - "Tracing packet contents stopped", - "Tracing kernel changes stopped", - }; - static char *on_msgs[MAX_TRACELEVEL] = { - "Tracing actions started", - "Tracing packets started", - "Tracing packet contents started", - "Tracing kernel changes started", - }; - + if (new_tracelevel == tracelevel) + return; - if (new_tracelevel > MAX_TRACELEVEL) { - new_tracelevel = MAX_TRACELEVEL; - if (new_tracelevel == tracelevel) { - tmsg(tracelevel_pat, on_msgs[tracelevel-1]); - return; - } - } - while (new_tracelevel != tracelevel) { - if (new_tracelevel < tracelevel) { - if (--tracelevel == 0) - trace_off(tracelevel_pat, off_msgs[0]); - else - tmsg(tracelevel_pat, off_msgs[tracelevel]); + /* 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 { - if (ftrace == 0) { - if (savetracename[0] != '\0') - trace_on(savetracename, 1); - else - ftrace = stdout; - } - tmsg(tracelevel_pat, on_msgs[tracelevel++]); + new_tracelevel = 0; + return; } + } else { + tracelevel_msg(sigtrace_pat, 0); } - tracelevel_pat = "%s\n"; } @@ -379,10 +478,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 @@ -391,10 +491,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" }, @@ -416,7 +517,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"} }; @@ -474,21 +575,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) @@ -497,15 +624,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); @@ -522,59 +652,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) { - (void)fprintf(ftrace, "Chg #%d %-35s ", + if (gate == 0) { + (void)fprintf(ftrace, "Del #%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(&new, 0,0,0,0, + rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp)); - (void)fprintf(ftrace, " %19s%-16s ", - "", + } else if (rts->rts_gate != RIP_DEFAULT) { + (void)fprintf(ftrace, "Chg #%d %-35s ", + rts - rt->rt_spares, + 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, "\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); } @@ -591,6 +722,7 @@ trace_kernel(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); } @@ -607,6 +739,7 @@ trace_act(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); } @@ -623,6 +756,7 @@ trace_pkt(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); } @@ -637,6 +771,8 @@ trace_change(struct rt_entry *rt, time_t new_time, char *label) { + struct rt_spare new; + if (ftrace == 0) return; @@ -646,67 +782,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); } @@ -717,42 +835,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); @@ -764,10 +863,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); } @@ -780,8 +884,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; @@ -805,17 +909,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 ", @@ -824,32 +931,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)); @@ -880,7 +1012,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: |