Latest version of SGI routed courtesy of Vern Schryver. This version

adds the capability to use MD5 authentication as defined in the latest
documents.

Submitted by:	Vernon J. Schryver <vjs@mica.denver.sgi.com>
This commit is contained in:
Garrett Wollman 1996-11-19 20:23:47 +00:00
parent 7b6ab19dde
commit d5b718b3ee
16 changed files with 2404 additions and 961 deletions

View File

@ -2,21 +2,10 @@
PROG= routed
SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
MAN8= routed.0
MAN8= routed.8
SUBDIR= rtquery
DPADD= ${LIBCOMPAT}
LDADD= -lcompat
LDADD+= -lmd
DPADD+= ${LIBMD}
#COPTS= -g -DDEBUG -Wall
.include <bsd.prog.mk>
.if (${MACHINE} == "vax")
# The following can be deleted where not appropriate to use the kernel's
# inline code expansions.
INLINE= /sys/vax/inline/obj/inline
C2= /usr/libexec/c2
.c.o:
${CC} -S ${CFLAGS} ${.CURDIR}/${.PREFIX}.c
@${C2} ${.PREFIX}.s | ${INLINE} | ${AS} -o ${.PREFIX}.o
@rm -f ${.PREFIX}.s
.endif

View File

@ -36,7 +36,7 @@
*/
#ifndef __NetBSD__
#ident "$Revision: 1.16 $"
#ident "$Revision: 1.17 $"
#endif
/* Definitions for RIPv2 routing process.
@ -95,6 +95,10 @@
#define RIPVERSION RIPv2
#include <protocols/routed.h>
#ifdef sgi
#define USE_PASSIFNAME
#endif
/* Type of an IP address.
* Some systems do not like to pass structures, so do not use in_addr.
@ -131,6 +135,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
@ -151,15 +162,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;
@ -243,7 +258,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) */
@ -259,6 +278,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 */
@ -272,7 +292,15 @@ struct interface {
#endif
time_t ts; /* timestamp on network stats */
} int_data;
char int_passwd[RIP_AUTH_PW_LEN]; /* RIPv2 password */
struct auth { /* authentication info */
u_char type;
# define MAX_AUTH_KEYS 3
struct auth_key {
u_char key[RIP_AUTH_PW_LEN];
u_char keyid;
time_t start, end;
} keys[MAX_AUTH_KEYS];
} int_auth;
int int_rdisc_pref; /* advertised rdisc preference */
int int_rdisc_int; /* MaxAdvertiseInterval */
int int_rdisc_cnt;
@ -288,11 +316,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_DISTRUST 0x0000100 /* ignore untrusted routers */
#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 */
/* 0x0001000 spare */
#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 */
@ -364,14 +392,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;
} *parms;
/* authority for internal networks */
@ -382,7 +410,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 */
@ -405,7 +449,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;
@ -423,6 +468,7 @@ 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 */
@ -450,16 +496,21 @@ 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_key *, struct interface *);
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 {
naddr addr;
time_t until;
};
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))
@ -485,7 +536,7 @@ extern void lastlog(void);
extern void trace_on(char *, int);
extern void trace_off(char*, ...);
extern void trace_flush(void);
extern void set_tracelevel(void);
extern void set_tracelevel(int);
extern void trace_kernel(char *, ...);
extern void trace_act(char *, ...);
extern void trace_pkt(char *, ...);
@ -554,13 +605,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 *, struct walkarg *);
extern int if_ok(struct interface *, char *);
extern void if_sick(struct interface *);
extern void if_bad(struct interface *);
extern void if_link(struct interface *);
extern struct interface *ifwithaddr(naddr, int, int);
extern struct interface *ifwithname(char *, naddr);
extern struct interface *ifwithindex(u_short);
extern struct interface *iflookup(naddr);
extern struct auth_key *find_auth(struct interface *);
extern void end_md5_auth(struct ws_buf *, struct auth_key *);
#include <md5.h>

View File

@ -36,12 +36,35 @@ static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.17 $"
#ident "$Revision: 1.18 $"
#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[(a)%AHASH_LEN]
struct interface *ahash[AHASH_LEN];
#define BHASH_LEN 211 /* must be prime */
#define BHASH(a) &bhash[(a)%BHASH_LEN]
struct interface *bhash[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 put on the end of the hash chains.
*/
#define NHASH_LEN 97
struct interface *nhash[NHASH_LEN];
int tot_interfaces; /* # of remote and local interfaces */
int rip_interfaces; /* # of interfaces doing RIP */
int foundloopback; /* valid flag for loopaddr */
@ -53,6 +76,58 @@ int have_ripv1_out; /* have a RIPv1 interface */
int have_ripv1_in;
void
if_link(struct interface *ifp)
{
int i;
char *p;
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;
ifp->int_ahash = *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 = *hifp;
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;
}
for (i = 0, p = ifp->int_name; *p != '\0'; p++)
i += *p;
hifp = &nhash[i % NHASH_LEN];
if (ifp->int_state & IS_ALIAS) {
while (*hifp != 0)
hifp = &(*hifp)->int_nhash;
}
ifp->int_nhash = *hifp;
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 *
@ -62,20 +137,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;
@ -89,12 +173,19 @@ ifwithname(char *name, /* "ec0" or whatever */
naddr addr) /* 0 or network address */
{
struct interface *ifp;
int i;
char *p;
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
for (i = 0, p = name; *p != '\0'; p++)
i += *p;
for (ifp = nhash[i % NHASH_LEN]; 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)
&& (ifp->int_addr == addr
|| (addr == 0 && !(ifp->int_state & IS_ALIAS))))
&& ((addr == 0 && !(ifp->int_state & IS_ALIAS))
|| (ifp->int_addr == addr)))
return ifp;
}
return 0;
@ -127,17 +218,14 @@ iflookup(naddr addr)
maybe = 0;
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (ifp->int_if_flags & IFF_POINTOPOINT) {
/* finished with a match */
if (ifp->int_dstaddr == addr)
/* finished with a match */
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;
/* Look for the longest approximate match.
*/
@ -247,6 +335,68 @@ check_dst(naddr addr)
}
/* See a new interface duplicates an existing interface.
*/
struct interface *
check_dup(naddr addr,
naddr dstaddr,
naddr mask,
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
@ -262,17 +412,25 @@ 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;
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
@ -295,6 +453,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);
@ -327,6 +487,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);
@ -348,7 +509,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);
@ -376,16 +538,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;
@ -397,6 +559,11 @@ if_ok(struct interface *ifp,
}
if_ok_rdisc(ifp);
}
if (ifp->int_state & IS_REMOTE) {
if (!addrouteforif(ifp))
return 0;
}
return 1;
}
@ -452,15 +619,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;
@ -468,7 +634,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;
@ -516,6 +681,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
*/
@ -535,22 +702,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;
@ -558,16 +733,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
@ -575,41 +747,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
@ -618,7 +772,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;
@ -630,35 +784,48 @@ ifinit(void)
if (!(prev_complaints & COMP_NODST))
msglog("%s has a bad"
" destination address",
sdl->sdl_data);
ifs.int_name);
complaints |= COMP_NODST;
}
continue;
}
ifs.int_mask = HOST_MASK;
ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info)));
ifs.int_net = ntohl(ifs.int_dstaddr);
ifs.int_std_mask = std_mask(ifs.int_dstaddr);
ifs.int_net = ntohl(ifs.int_dstaddr);
} else if (ifs.int_if_flags & IFF_LOOPBACK) {
ifs.int_state |= IS_PASSIVE | IS_NO_RIP;
ifs.int_dstaddr = ifs.int_addr;
ifs.int_mask = HOST_MASK;
ifs.int_ripv1_mask = HOST_MASK;
ifs.int_net = ntohl(ifs.int_dstaddr);
ifs.int_std_mask = std_mask(ifs.int_dstaddr);
if (!foundloopback) {
foundloopback = 1;
loopaddr = ifs.int_addr;
} else {
if (INFO_MASK(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOMASK))
msglog("%s has no netmask",
ifs.int_name);
complaints |= COMP_NOMASK;
}
continue;
}
ifs.int_dstaddr = ifs.int_addr;
ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info)));
ifs.int_ripv1_mask = ifs.int_mask;
ifs.int_std_mask = std_mask(ifs.int_addr);
ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
if (ifs.int_mask != ifs.int_std_mask)
ifs.int_state |= IS_SUBNET;
} else {
if (!(prev_complaints & COMP_WIERD))
trace_act("%s is neither broadcast"
" nor point-to-point nor loopback",
sdl->sdl_data);
complaints |= COMP_WIERD;
continue;
if (ifs.int_if_flags & IFF_BROADCAST) {
if (INFO_BRD(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (!(prev_complaints
& COMP_NOBADR))
msglog("%s has"
"no broadcast address",
ifs.int_name);
complaints |= COMP_NOBADR;
}
continue;
}
ifs.int_brdaddr = S_ADDR(INFO_BRD(&info));
}
}
ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
ifs.int_std_addr = htonl(ifs.int_std_net);
@ -671,7 +838,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;
@ -687,7 +854,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);
}
}
@ -696,9 +863,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;
@ -717,7 +884,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;
@ -737,7 +904,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;
}
@ -799,18 +966,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);
}
@ -830,73 +997,60 @@ 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.
*/
if ((ifp->int_state & IS_PASSIVE)
&& !(ifp->int_state & IS_EXTERNAL))
continue;
/* It does duplicate an existing interface,
* so complain about it, mark the other one
* duplicated, and for get this one.
*/
ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask,
ifs.int_if_flags);
if (ifp != 0) {
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 is duplicated by %s at %s to %s",
ifs.int_name, ifp->int_name,
naddr_ntoa(ifp->int_addr),
naddr_ntoa(ifp->int_dstaddr));
}
ifp->int_state |= IS_DUP;
break;
}
if (ifp != 0)
continue;
}
/* It is new and ok. So make it real
*/
strncpy(ifs.int_name, sdl->sdl_data,
MIN(sizeof(ifs.int_name)-1, sdl->sdl_nlen));
get_parms(&ifs);
if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST))
&& !(ifs.int_state & IS_PASSIVE)) {
trace_act("%s is neither broadcast, point-to-point,"
" nor loopback",
ifs.int_name);
if (!(ifs.int_state & IFF_MULTICAST))
ifs.int_state |= IS_NO_RDISC;
}
/* Add it to the list of interfaces
/* It is new and ok. Add it to the list of interfaces
*/
ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit");
bcopy(&ifs, ifp, sizeof(*ifp));
if (ifnet != 0) {
ifp->int_next = ifnet;
ifnet->int_prev = ifp;
}
ifnet = ifp;
get_parms(ifp);
if_link(ifp);
trace_if("Add", ifp);
/* Notice likely bad netmask.
*/
if (!(prev_complaints & COMP_NETMASK)
&& !(ifp->int_if_flags & IFF_POINTOPOINT)) {
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
&& ifp->int_addr != RIP_DEFAULT) {
for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
if (ifp1->int_mask == ifp->int_mask)
continue;
if (ifp1->int_if_flags & IFF_POINTOPOINT)
continue;
if (on_net(ifp->int_addr,
if (ifp1->int_dstaddr == RIP_DEFAULT)
continue;
if (on_net(ifp->int_dstaddr,
ifp1->int_net, ifp1->int_mask)
|| on_net(ifp1->int_addr,
|| on_net(ifp1->int_dstaddr,
ifp->int_net, ifp->int_mask)) {
msglog("possible netmask problem"
" betwen %s:%s and %s:%s",
" between %s:%s and %s:%s",
ifp->int_name,
addrname(htonl(ifp->int_net),
ifp->int_mask, 1),
@ -908,20 +1062,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)
@ -959,7 +1114,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;
@ -983,7 +1138,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.
@ -1080,7 +1236,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;
@ -1090,7 +1246,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).
@ -1098,28 +1254,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
@ -1144,10 +1290,12 @@ addrouteforif(struct interface *ifp)
}
if (rt == 0) {
if (ifp->int_transitions++ > 0)
trace_act("re-install interface %s\n",
trace_act("re-install interface %s",
ifp->int_name);
rtadd(dst, ifp->int_mask, gate, gate,
ifp->int_metric, 0, RS_IF, ifp);
}
return 1;
}

View File

@ -36,24 +36,34 @@ static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.16 $"
#ident "$Revision: 1.17 $"
#include "defs.h"
static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
static void input(struct sockaddr_in *, struct interface *, struct interface *,
struct rip *, int);
static void input_route(struct interface *, naddr,
naddr, naddr, naddr, struct netinfo *);
static int ck_passwd(struct interface *, struct rip *, void *,
naddr, struct msg_limit *);
/* process RIP input
*/
void
read_rip(int sock,
struct interface *ifp)
struct interface *sifp)
{
static struct msg_limit bad_name;
struct sockaddr_in from;
struct interface *aifp;
int fromlen, cc;
union pkt_buf inbuf;
struct {
#ifdef USE_PASSIFNAME
char ifname[IFNAMSIZ];
#endif
union pkt_buf pbuf;
} inbuf;
for (;;) {
@ -69,7 +79,54 @@ 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) {
/* maybe it is a new interface */
ifinit();
aifp = ifwithname(inbuf.ifname, 0);
if (aifp == 0) {
msglim(&bad_name, from.sin_addr.s_addr,
"impossible interface name"
" %.*s", IFNAMSIZ,
inbuf.ifname);
}
}
/* If it came via the wrong interface, do not
* trust it.
*/
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)))
aifp = 0;
}
#else
aifp = iflookup(from.sin_addr.s_addr);
#endif
if (sifp == 0)
sifp = aifp;
input(&from, sifp, aifp, &inbuf.pbuf.rip, cc);
}
}
@ -78,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_key *ap;
int i;
aifp = iflookup(from->sin_addr.s_addr);
if (sifp == 0)
sifp = aifp;
/* Notice when we hear from a remote gateway
*/
if (aifp != 0
&& (aifp->int_state & IS_REMOTE))
aifp->int_act_time = now.tv_sec;
if (sifp != 0)
sifp->int_state |= IS_ACTIVE;
trace_rip("Recv", "from", from, sifp, rip, size);
trace_rip("Recv", "from", from, sifp, rip, cc);
if (rip->rip_vers == 0) {
if (from->sin_addr.s_addr != bad_router)
msglog("RIP version 0, cmd %d, packet received"
" from %s",
rip->rip_cmd, naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"RIP version 0, cmd %d, packet received from %s",
rip->rip_cmd, naddr_ntoa(FROM_NADDR));
return;
} else if (rip->rip_vers > RIPv2) {
rip->rip_vers = RIPv2;
}
if (size > MAXPACKETSIZE) {
if (from->sin_addr.s_addr != bad_router)
msglog("packet at least %d bytes too long received"
" from %s",
size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
if (cc > OVER_MAXPACKETSIZE) {
msglim(&bad_router, FROM_NADDR,
"packet at least %d bytes too long received from %s",
cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
return;
}
n = rip->rip_nets;
lim = (struct netinfo *)((char*)rip + size);
lim = (struct netinfo *)((char*)rip + cc);
/* Notice authentication.
* As required by section 4.2 in RFC 1723, discard authenticated
* RIPv2 messages, but only if configured for that silliness.
*
* RIPv2 authentication is lame, since snooping on the wire makes
* its simple passwords evident. Also, why authenticate queries?
* RIPv2 authentication is lame. Why authenticate queries?
* Why should a RIPv2 implementation with authentication disabled
* not be able to listen to RIPv2 packets with authenication, while
* RIPv1 systems will listen? Crazy!
@ -137,54 +189,93 @@ input(struct sockaddr_in *from, /* received from this IP address */
if (!auth_ok
&& rip->rip_vers == RIPv2
&& n < lim && n->n_family == RIP_AF_AUTH) {
if (from->sin_addr.s_addr != use_auth)
msglog("RIPv2 message with authentication"
" from %s discarded",
naddr_ntoa(FROM_NADDR));
use_auth = from->sin_addr.s_addr;
trace_pkt("discard authenticated RIPv2 message\n");
msglim(&use_auth, FROM_NADDR,
"RIPv2 message with authentication from %s discarded",
naddr_ntoa(FROM_NADDR));
return;
}
switch (rip->rip_cmd) {
case RIPCMD_REQUEST:
/* For mere requests, be a little sloppy about the source
*/
if (aifp == 0)
aifp = sifp;
/* Are we talking to ourself or a remote gateway?
*/
ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
if (ifp1) {
if (ifp1->int_state & IS_REMOTE) {
/* remote gateway */
aifp = ifp1;
if (check_remote(aifp)) {
aifp->int_act_time = now.tv_sec;
(void)if_ok(aifp, "remote ");
}
} else if (from->sin_port == htons(RIP_PORT)) {
trace_pkt(" discard our own RIP request");
return;
}
}
/* did the request come from a router?
*/
if (from->sin_port == htons(RIP_PORT)) {
/* yes, ignore it if RIP is off so that it does not
* depend on us.
/* yes, ignore the request if RIP is off so that
* the router does not depend on us.
*/
if (rip_sock < 0) {
trace_pkt("ignore request while RIP off\n");
return;
}
/* Ignore the request if we talking to ourself
* (and not a remote gateway).
*/
if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
trace_pkt("discard our own RIP request\n");
if (rip_sock < 0
|| (aifp != 0
&& IS_RIP_OUT_OFF(aifp->int_state))) {
trace_pkt(" discard request while RIP off");
return;
}
}
/* According to RFC 1723, we should ignore unathenticated
* queries. That is too silly to bother with. Sheesh!
* Are forwarding tables supposed to be secret? When
* a bad guy can infer them with test traffic?
* Are forwarding tables supposed to be secret, when
* a bad guy can infer them with test traffic? When RIP
* is still the most common router-discovery protocol
* and so hosts need to send queries that will be answered?
* What about `rtquery`?
* Maybe on firewalls you'd care, but not enough to
* give up the diagnostic facilities of remote probing.
*/
if (n >= lim
|| size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
if (from->sin_addr.s_addr != bad_len)
msglog("request of bad length (%d) from %s",
size, naddr_ntoa(FROM_NADDR));
bad_len = from->sin_addr.s_addr;
if (n >= lim) {
msglim(&bad_len, FROM_NADDR, "empty request from %s",
naddr_ntoa(FROM_NADDR));
return;
}
for (; n < lim; n++) {
n->n_metric = ntohl(n->n_metric);
if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
msglim(&bad_len, FROM_NADDR,
"request of bad length (%d) from %s",
cc, naddr_ntoa(FROM_NADDR));
}
if (rip->rip_vers == RIPv2
&& (aifp == 0 || (aifp->int_state & IS_NO_RIPV1_OUT))) {
v12buf.buf->rip_vers = RIPv2;
/* If we have a secret but it is a cleartext secret,
* do not disclose our secret unless the other guy
* already knows it.
*/
if (aifp != 0
&& aifp->int_auth.type == RIP_AUTH_PW
&& !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
ap = 0;
else
ap = find_auth(aifp);
} else {
v12buf.buf->rip_vers = RIPv1;
ap = 0;
}
clr_ws_buf(&v12buf, ap, aifp);
do {
NTOHL(n->n_metric);
/* A single entry with family RIP_AF_UNSPEC and
* metric HOPCNT_INFINITY means "all routes".
@ -193,17 +284,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.
@ -216,91 +306,115 @@ input(struct sockaddr_in *from, /* received from this IP address */
* the remote router from getting the wrong
* initial idea of the routes we send.
*/
if (!supplier
|| aifp == 0
|| (aifp->int_state & IS_PASSIVE)
|| (aifp->int_state & IS_ALIAS)
|| ((aifp->int_state & IS_NO_RIPV1_OUT)
&& (aifp->int_state&IS_NO_RIPV2_OUT)))
if (aifp == 0) {
trace_pkt("ignore distant router");
return;
}
if (!supplier
|| IS_RIP_OFF(aifp->int_state)) {
trace_pkt("ignore; not supplying");
return;
}
supply(from, aifp, OUT_UNICAST, 0,
(aifp->int_state&IS_NO_RIPV1_OUT)
? RIPv2 : RIPv1);
? RIPv2 : RIPv1,
ap != 0);
return;
}
/* Ignore authentication */
if (n->n_family == RIP_AF_AUTH)
continue;
if (n->n_family != RIP_AF_INET) {
if (from->sin_addr.s_addr != bad_router)
msglog("request from %s"
" for unsupported (af %d) %s",
naddr_ntoa(FROM_NADDR),
ntohs(n->n_family),
naddr_ntoa(n->n_dst));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"request from %s for unsupported (af"
" %d) %s",
naddr_ntoa(FROM_NADDR),
ntohs(n->n_family),
naddr_ntoa(n->n_dst));
return;
}
/* We are being asked about a specific destination.
*/
dst = n->n_dst;
if (!check_dst(dst)) {
if (from->sin_addr.s_addr != bad_router)
msglog("bad queried destination"
" %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
bad_router = from->sin_addr.s_addr;
msglim(&bad_router, FROM_NADDR,
"bad queried destination %s from %s",
naddr_ntoa(dst),
naddr_ntoa(FROM_NADDR));
return;
}
/* decide what mask was intended */
if (rip->rip_vers == RIPv1
|| 0 == (mask = ntohl(n->n_mask))
|| 0 != (ntohl(dst) & ~mask))
mask = ripv1_mask_host(dst,sifp);
mask = ripv1_mask_host(dst, aifp);
/* try to find the answer */
rt = rtget(dst, mask);
if (!rt && dst != RIP_DEFAULT)
rt = rtfind(n->n_dst);
n->n_tag = 0;
n->n_nhop = 0;
if (rip->rip_vers == RIPv1) {
n->n_mask = 0;
} else {
n->n_mask = mask;
}
if (v12buf.buf->rip_vers != RIPv1)
v12buf.n->n_mask = mask;
if (rt == 0) {
n->n_metric = HOPCNT_INFINITY;
/* we do not have the answer */
v12buf.n->n_metric = HOPCNT_INFINITY;
} else {
n->n_metric = rt->rt_metric+1;
n->n_metric += (sifp!=0)?sifp->int_metric : 1;
if (n->n_metric > HOPCNT_INFINITY)
n->n_metric = HOPCNT_INFINITY;
if (rip->rip_vers != RIPv1) {
n->n_tag = rt->rt_tag;
if (sifp != 0
/* we have the answer, so compute the
* right metric and next hop.
*/
v12buf.n->n_family = RIP_AF_INET;
v12buf.n->n_dst = dst;
v12buf.n->n_metric = (rt->rt_metric+1
+ ((aifp!=0)
? aifp->int_metric
: 1));
if (v12buf.n->n_metric > HOPCNT_INFINITY)
v12buf.n->n_metric = HOPCNT_INFINITY;
if (v12buf.buf->rip_vers != RIPv1) {
v12buf.n->n_tag = rt->rt_tag;
v12buf.n->n_mask = mask;
if (aifp != 0
&& on_net(rt->rt_gate,
sifp->int_net,
sifp->int_mask)
&& rt->rt_gate != sifp->int_addr)
n->n_nhop = rt->rt_gate;
aifp->int_net,
aifp->int_mask)
&& rt->rt_gate != aifp->int_addr)
v12buf.n->n_nhop = rt->rt_gate;
}
}
HTONL(n->n_metric);
}
/* Answer about specific routes.
* Only answer a router if we are a supplier
* to keep an unwary host that is just starting
* from picking us an a router.
HTONL(v12buf.n->n_metric);
/* Stop paying attention if we fill the output buffer.
*/
if (++v12buf.n >= v12buf.lim)
break;
} while (++n < lim);
/* Send the answer about specific routes.
*/
rip->rip_cmd = RIPCMD_RESPONSE;
rip->rip_res1 = 0;
if (rip->rip_vers != RIPv1)
rip->rip_vers = RIPv2;
if (ap != 0 && aifp->int_auth.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;
@ -318,7 +432,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
return;
}
if (rip->rip_cmd == RIPCMD_TRACEON) {
rip->rip_tracefile[size-4] = '\0';
rip->rip_tracefile[cc-4] = '\0';
trace_on((char*)rip->rip_tracefile, 0);
} else {
trace_off("tracing turned off by %s\n",
@ -327,21 +441,22 @@ input(struct sockaddr_in *from, /* received from this IP address */
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;
}
@ -350,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;
}
@ -401,35 +513,39 @@ 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 when it
* happens it happens a lot.
*/
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, ignore the silliness in RFC 1723
* and accept it regardless.
*/
if (aifp->int_auth.type != RIP_AUTH_NONE
&& rip->rip_vers != RIPv1) {
if (!ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
return;
}
do {
if (n->n_family == RIP_AF_AUTH)
continue;
@ -438,39 +554,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;
@ -481,14 +593,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;
}
}
}
@ -497,14 +608,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)
@ -548,9 +657,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) {
@ -579,9 +688,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
}
@ -610,7 +720,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.
@ -739,3 +850,85 @@ 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)
# define DAY (24*60*60)
struct netauth *na2;
struct auth_key *akp = aifp->int_auth.keys;
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;
}
if (NA->a_type != aifp->int_auth.type) {
msglim(use_authp, from, "wrong type of password from %s",
naddr_ntoa(from));
return 0;
}
if (NA->a_type == RIP_AUTH_PW) {
/* accept any current cleartext password
*/
for (i = 0; i < MAX_AUTH_KEYS; i++, akp++) {
if ((u_long)akp->start-DAY > (u_long)clk.tv_sec
|| (u_long)akp->end+DAY < (u_long)clk.tv_sec)
continue;
if (!bcmp(NA->au.au_pw, akp->key, RIP_AUTH_PW_LEN))
return 1;
}
} else {
/* accept any current MD5 secret with the right key ID
*/
for (i = 0; i < MAX_AUTH_KEYS; i++, akp++) {
if (NA->au.a_md5.md5_keyid == akp->keyid
&& (u_long)akp->start-DAY <= (u_long)clk.tv_sec
&& (u_long)akp->end+DAY >= (u_long)clk.tv_sec)
break;
}
if (i < MAX_AUTH_KEYS) {
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 *)akp->key, sizeof(akp->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 1;
}
}
msglim(use_authp, from, "bad password from %s",
naddr_ntoa(from));
return 0;
#undef NA
}

View File

@ -39,7 +39,7 @@ static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.17 $"
#ident "$Revision: 1.18 $"
#include "defs.h"
#include "pathnames.h"
@ -97,12 +97,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;
@ -169,7 +174,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);
@ -178,13 +183,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);
@ -252,8 +257,6 @@ main(int argc,
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);
@ -298,7 +301,9 @@ main(int argc,
if (new_tracelevel == 0) /* use stdout if file is bad */
new_tracelevel = 1;
}
set_tracelevel();
set_tracelevel(1);
bufinit();
/* initialize radix tree */
rtinit();
@ -325,8 +330,7 @@ main(int argc,
/* Ask for routes */
rip_query();
if (!supplier)
rdisc_sol();
rdisc_sol();
/* Loop forever, listening and broadcasting.
*/
@ -342,7 +346,7 @@ main(int argc,
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,13 +355,11 @@ main(int argc,
now_garbage = now.tv_sec - GARBAGE_TIME;
/* deal with interrupts that should affect tracing */
set_tracelevel();
set_tracelevel(0);
if (stopint != 0) {
if (supplier) {
rip_bcast(0);
rdisc_adv();
}
rip_bcast(0);
rdisc_adv();
trace_off("exiting with signal %d\n", stopint);
exit(stopint | 128);
}
@ -495,7 +497,7 @@ sigalrm(int sig)
* new and broken interfaces.
*/
ifinit_timer.tv_sec = now.tv_sec;
trace_act("SIGALRM\n");
trace_act("SIGALRM");
}
@ -552,10 +554,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)
@ -565,7 +573,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) {
@ -624,7 +632,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;
@ -632,8 +640,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);
@ -686,11 +695,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,
@ -713,25 +722,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();
}
@ -790,6 +795,8 @@ timevalsub(struct timeval *t1,
}
/* put a message into the system log
*/
void
msglog(char *p, ...)
{
@ -809,6 +816,34 @@ msglog(char *p, ...)
}
/* Put a message about a bad router into the system log if
* we have not complained about it recently.
*/
void
msglim(struct msg_limit *lim, naddr addr, char *p, ...)
{
va_list args;
char *p1;
va_start(args, p);
if ( lim->addr != addr || lim->until <= now.tv_sec) {
lim->addr = addr;
lim->until = now.tv_sec + 60*60;
trace_flush();
for (p1 = p; *p1 == ' '; p1++)
continue;
vsyslog(LOG_ERR, p1, args);
}
if (ftrace != 0) {
(void)vfprintf(ftrace, p, args);
(void)fputc('\n', ftrace);
}
}
void
logbad(int dump, char *p, ...)
{

View File

@ -36,7 +36,7 @@ static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.17 $"
#ident "$Revision: 1.18 $"
#include "defs.h"
@ -53,37 +53,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_key *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 */
@ -137,7 +145,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 {
@ -198,20 +206,86 @@ output(enum output_type type,
}
/* install authentication if appropriate
/* Find the first key that 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_key *
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_key *ap, *res;
int i;
if (ifp == 0 || ifp->int_auth.type == RIP_AUTH_NONE)
return 0;
res = 0;
ap = ifp->int_auth.keys;
for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
if ((u_long)ap->start <= (u_long)clk.tv_sec) {
if ((u_long)ap->end >= (u_long)clk.tv_sec)
return ap;
res = ap;
}
}
return res;
}
void
clr_ws_buf(struct ws_buf *wb,
struct auth_key *ap,
struct interface *ifp)
{
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 (ifp->int_auth.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 (ifp->int_auth.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_key *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++;
}
@ -226,12 +300,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.ifp->int_auth.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)
@ -240,9 +316,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,ws.ifp);
}
@ -252,7 +326,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;
struct ws_buf *wb;
@ -272,7 +346,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
@ -280,19 +353,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
@ -333,18 +403,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;
@ -368,20 +440,20 @@ walk_supply(struct radix_node *rn,
naddr dst, nhop;
/* 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;
@ -528,14 +600,15 @@ walk_supply(struct radix_node *rn,
} 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.
* 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.
*/
pref = RT->rt_poison_metric + ws.metric;
if (pref >= HOPCNT_INFINITY
|| RT->rt_poison_time < now_garbage )
if (!(ws.state & WS_ST_QUERY)
&& (pref >= HOPCNT_INFINITY
|| RT->rt_poison_time < now_garbage))
return 0;
metric = HOPCNT_INFINITY;
@ -556,10 +629,11 @@ supply(struct sockaddr_in *dst,
struct interface *ifp, /* output interface */
enum output_type type,
int flash, /* 1=flash update */
int vers) /* RIP version */
int vers, /* RIP version */
int passwd_ok) /* OK to include cleartext password */
{
static int init = 1;
struct rt_entry *rt;
int def_metric;
ws.state = 0;
@ -598,94 +672,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 (ws.a != 0 && !passwd_ok && ifp->int_auth.type == RIP_AUTH_PW)
ws.a = 0;
clr_ws_buf(&v12buf,ws.a,ifp);
clr_ws_buf(&v2buf,ws.a,ifp);
/* Fake a default route if asked and if there is not already
* a better, real default route.
*/
if (supplier && (def_metric = ifp->int_d_metric) != 0) {
if (0 == (rt = rtget(RIP_DEFAULT, 0))
|| rt->rt_metric+ws.metric >= def_metric) {
ws.state |= WS_ST_DEFAULT;
ag_check(0, 0, 0, 0,
ifp->int_d_metric,ifp->int_d_metric,
ag_check(0, 0, 0, 0, def_metric, def_metric,
0, 0, 0, supply_out);
} else {
def_metric = rt->rt_metric+ws.metric;
}
/* If both RIPv2 and the poor-man's router discovery
* kludge are on, arrange to advertise an extra
* default route via RIPv1.
*/
if ((ws.state & WS_ST_RIP2_ALL)
&& (ifp->int_state & IS_PM_RDISC)) {
ws.state |= WS_ST_PM_RDISC;
ripv12_buf.rip.rip_vers = RIPv1;
v12buf.n->n_family = RIP_AF_INET;
v12buf.n->n_dst = htonl(RIP_DEFAULT);
v12buf.n->n_metric = htonl(def_metric);
v12buf.n++;
}
}
@ -695,21 +754,21 @@ supply(struct sockaddr_in *dst,
/* Flush the packet buffers, provided they are not empty and
* do not contain only the password.
*/
if (ws.v12.n != ws.v12.base
&& (ws.v12.n > ws.v12.base+1
|| ws.v12.n->n_family != RIP_AF_AUTH))
supply_write(&ws.v12);
if (ws.v2.n != ws.v2.base
&& (ws.v2.n > ws.v2.base+1
|| ws.v2.n->n_family != RIP_AF_AUTH))
supply_write(&ws.v2);
if (v12buf.n != v12buf.base
&& (v12buf.n > v12buf.base+1
|| v12buf.base->n_family != RIP_AF_AUTH))
supply_write(&v12buf);
if (v2buf.n != v2buf.base
&& (v2buf.n > v2buf.base+1
|| v2buf.base->n_family != RIP_AF_AUTH))
supply_write(&v2buf);
/* If we sent nothing and this is an answer to a query, send
* an empty buffer.
*/
if (ws.npackets == 0
&& (ws.state & WS_ST_QUERY))
supply_write(&ws.v12);
supply_write(&v12buf);
}
@ -737,36 +796,28 @@ rip_bcast(int flash)
if (rip_sock < 0)
return;
trace_act("send %s and inhibit dynamic updates for %.3f sec\n",
trace_act("send %s and inhibit dynamic updates for %.3f sec",
flash ? "dynamic update" : "all routes",
rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0);
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
/* skip interfaces not doing RIP, those already queried,
* and aliases. Do try broken interfaces to see
* if they have healed.
/* Skip interfaces not doing RIP.
* Do try broken interfaces to see if they have healed.
*/
if (0 != (ifp->int_state & (IS_PASSIVE | IS_ALIAS)))
if (IS_RIP_OUT_OFF(ifp->int_state))
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
continue;
/* default to RIPv1 output */
if (ifp->int_state & IS_NO_RIPV1_OUT) {
/* Say nothing if this interface is turned off */
if (ifp->int_state & IS_NO_RIPV2_OUT)
continue;
vers = RIPv2;
} else {
vers = RIPv1;
}
vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1;
if (ifp->int_if_flags & IFF_BROADCAST) {
/* ordinary, hardware interface */
dst.sin_addr.s_addr = ifp->int_brdaddr;
/* if RIPv1 is not turned off, then broadcast so
/* If RIPv1 is not turned off, then broadcast so
* that RIPv1 listeners can hear.
*/
if (vers == RIPv2
@ -781,13 +832,17 @@ rip_bcast(int flash)
dst.sin_addr.s_addr = ifp->int_dstaddr;
type = OUT_UNICAST;
} else {
} else if (ifp->int_state & IS_REMOTE) {
/* remote interface */
dst.sin_addr.s_addr = ifp->int_addr;
type = OUT_UNICAST;
} else {
/* ATM, HIPPI, etc. */
continue;
}
supply(&dst, ifp, type, flash, vers);
supply(&dst, ifp, type, flash, vers, 1);
}
update_seqno++; /* all routes are up to date */
@ -817,28 +872,21 @@ rip_query(void)
bzero(&buf, sizeof(buf));
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
/* skip interfaces not doing RIP, those already queried,
* and aliases. Do try broken interfaces to see
* if they have healed.
/* Skip interfaces those already queried.
* Do not ask via interfaces through which we don't
* accept input. Do not ask via interfaces that cannot
* send RIP packets.
* Do try broken interfaces to see if they have healed.
*/
if (0 != (ifp->int_state & (IS_RIP_QUERIED
| IS_PASSIVE | IS_ALIAS)))
if (IS_RIP_IN_OFF(ifp->int_state)
|| ifp->int_query_time != NEVER)
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
continue;
/* default to RIPv1 output */
if (ifp->int_state & IS_NO_RIPV2_OUT) {
/* Say nothing if this interface is turned off */
if (ifp->int_state & IS_NO_RIPV1_OUT)
continue;
buf.rip_vers = RIPv1;
} else {
buf.rip_vers = RIPv2;
}
buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1;
buf.rip_cmd = RIPCMD_REQUEST;
buf.rip_nets[0].n_family = RIP_AF_UNSPEC;
buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
@ -861,13 +909,17 @@ rip_query(void)
dst.sin_addr.s_addr = ifp->int_dstaddr;
type = OUT_UNICAST;
} else {
} else if (ifp->int_state & IS_REMOTE) {
/* remote interface */
dst.sin_addr.s_addr = ifp->int_addr;
type = OUT_UNICAST;
} else {
/* ATM, HIPPI, etc. */
continue;
}
ifp->int_state |= IS_RIP_QUERIED;
ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL;
if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0)
if_sick(ifp);
}

View File

@ -36,7 +36,7 @@ static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.9 $"
#ident "$Revision: 1.10 $"
#include "defs.h"
#include "pathnames.h"
@ -44,6 +44,7 @@ static char rcsid[] = "$NetBSD$";
struct parm *parms;
struct intnet *intnets;
struct tgate *tgates;
/* use configured parameters
@ -51,49 +52,49 @@ struct intnet *intnets;
void
get_parms(struct interface *ifp)
{
static warned_auth_in, warned_auth_out;
struct parm *parmp;
/* 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));
if (parmp->parm_auth.type != RIP_AUTH_NONE)
bcopy(&parmp->parm_auth, &ifp->int_auth,
sizeof(ifp->int_auth));
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) {
@ -110,10 +111,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.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.type != RIP_AUTH_NONE
&& !(ifp->int_state & IS_NO_RIPV1_OUT)
&& !warned_auth_out) {
msglog("Warning: RIPv1 output via %s"
" will be sent without authentication",
ifp->int_name);
warned_auth_out = 1;
ifp->int_auth.type = RIP_AUTH_NONE;
}
}
@ -144,7 +162,6 @@ gwkludge(void)
int metric, n;
u_int state;
char *type;
struct parm *parmp;
fp = fopen(_PATH_GATEWAYS, "r");
@ -161,8 +178,7 @@ gwkludge(void)
|| *lptr == '#')
continue;
p = lptr+strlen(lptr)-1;
while (*p == '\n'
|| *p == ' ')
while (*p == '\n' || *p == ' ')
*p-- = '\0';
/* notice newfangled parameter lines
@ -171,9 +187,9 @@ gwkludge(void)
&& strncasecmp("host", lptr, 4)) {
p = parse_parms(lptr);
if (p != 0) {
if (strcmp(p,lptr))
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"", lptr, p);
if (strcasecmp(p,lptr))
msglog("bad %s in "_PATH_GATEWAYS
" entry \"%s\"", p, lptr);
else
msglog("bad \"%s\" in "_PATH_GATEWAYS,
lptr);
@ -182,26 +198,28 @@ 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);
@ -219,7 +237,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.
@ -230,17 +248,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
@ -253,110 +273,274 @@ gwkludge(void)
/* "remote" entries with a metric of 0
* are aliases for our own interfaces
*/
state = IS_REMOTE | IS_PASSIVE;
state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
type = "alias";
}
} else {
msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
msglog("bad "_PATH_GATEWAYS" entry \"%s\";"
" unknown type %s", lptr, qual);
continue;
}
/* Remember to advertise the corresponding logical network.
*/
if (!(state & IS_EXTERNAL)
&& netmask != std_mask(dst))
state |= IS_SUBNET;
if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
state |= IS_NO_RDISC;
if (state & IS_PASSIVE)
state |= (IS_NO_RIP | IS_NO_RDISC);
if ((state & (IS_NO_RIP | IS_NO_RDISC))
== (IS_NO_RIP|IS_NO_RDISC))
state |= IS_PASSIVE;
state |= IS_NO_RIP;
parmp = (struct parm*)malloc(sizeof(*parmp));
bzero(parmp, sizeof(*parmp));
parmp->parm_next = parms;
parms = parmp;
parmp->parm_addr_h = ntohl(dst);
parmp->parm_mask = -1;
parmp->parm_d_metric = 0;
parmp->parm_int_state = state;
/* See if this new interface duplicates an existing
* interface.
*/
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_mask == netmask
&& ((ifp->int_addr == dst
&& netmask != HOST_MASK)
|| (ifp->int_dstaddr == dst
&& netmask == HOST_MASK)))
break;
}
ifp = check_dup(gate,dst,netmask,0);
if (ifp != 0) {
/* Let one of our real interfaces be marked passive.
*/
if ((state & IS_PASSIVE) && !(state & IS_EXTERNAL)) {
ifp->int_state |= state;
} else {
msglog("%s is duplicated in "_PATH_GATEWAYS
" by %s",
ifp->int_name, lptr);
}
msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr);
continue;
}
tot_interfaces++;
ifp = (struct interface *)malloc(sizeof(*ifp));
bzero(ifp, sizeof(*ifp));
if (ifnet != 0) {
ifp->int_next = ifnet;
ifnet->int_prev = ifp;
}
ifnet = ifp;
ifp->int_state = state;
ifp->int_net = ntohl(dst) & netmask;
ifp->int_mask = netmask;
if (netmask == HOST_MASK)
ifp->int_if_flags |= IFF_POINTOPOINT;
ifp->int_dstaddr = dst;
ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP_RUNNING;
else
ifp->int_if_flags = IFF_UP_RUNNING;
ifp->int_act_time = NEVER;
ifp->int_addr = gate;
ifp->int_dstaddr = dst;
ifp->int_mask = netmask;
ifp->int_ripv1_mask = netmask;
ifp->int_std_mask = std_mask(gate);
ifp->int_net = ntohl(dst);
ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
ifp->int_std_addr = htonl(ifp->int_std_net);
ifp->int_metric = metric;
(void)sprintf(ifp->int_name, "%s-%s", type, naddr_ntoa(dst));
if (!(state & IS_EXTERNAL)
&& ifp->int_mask != ifp->int_std_mask)
ifp->int_state |= IS_SUBNET;
(void)sprintf(ifp->int_name, "%s(%s)", type, gname);
ifp->int_index = -1;
if_link(ifp);
}
/* After all of the parameter lines have been read,
* apply them to any remote interfaces.
*/
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
get_parms(ifp);
tot_interfaces++;
if (!IS_RIP_OFF(ifp->int_state))
rip_interfaces++;
trace_if("Add", ifp);
}
}
/* parse a set of parameters for an interface
/* 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;
}
/* 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,"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,"timestamp %.25s", val0);
return buf;
}
if (tm.tm_year <= 37)
tm.tm_year += 100;
if ((*tp = mktime(&tm)) == -1) {
sprintf(buf,"timestamp %.25s", val0);
return buf;
}
return 0;
}
/* Get one or more password, key ID's, and expiration dates in
* the format
* passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min|passwd|...
*/
static char * /* 0 or error message */
get_passwds(char *tgt,
char *val,
struct parm *parmp,
u_char type)
{
static char buf[80];
char *val0, *p, delim;
struct auth_key *akp, *akp2;
int i;
u_long l;
if (parmp->parm_auth.type != RIP_AUTH_NONE)
return "duplicate authentication";
parmp->parm_auth.type = type;
bzero(buf, sizeof(buf));
akp = parmp->parm_auth.keys;
for (i = 0; i < MAX_AUTH_KEYS; i++, val++, akp++) {
if ((delim = *val) == '\0')
break;
val0 = val;
if (0 > parse_quote(&val, "| ,\n\r", &delim,
(char *)akp->key, sizeof(akp->key)))
return tgt;
akp->end = -1;
if (delim != '|') {
if (type == RIP_AUTH_MD5)
return "missing Keyid";
break;
}
val0 = ++val;
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,"KeyID \"%.20s\"", val0);
return buf;
}
for (akp2 = parmp->parm_auth.keys; akp2 < akp; akp2++) {
if (akp2->keyid == l) {
*val = '\0';
sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
return buf;
}
}
akp->keyid = (int)l;
if (delim != '|')
break;
val0 = ++val;
if (0 != (p = parse_ts(&akp->start,&val,val0,&delim,
buf,sizeof(buf))))
return p;
if (delim != '|')
return "missing second timestamp";
val0 = ++val;
if (0 != (p = parse_ts(&akp->end,&val,val0,&delim,
buf,sizeof(buf))))
return p;
if ((u_long)akp->start > (u_long)akp->end) {
sprintf(buf,"out of order timestamp %.30s",val0);
return buf;
}
if (delim != '|')
break;
}
return (delim != '\0') ? tgt : 0;
}
/* Parse a set of parameters for an interface.
*/
char * /* 0 or error message */
parse_parms(char *line)
{
#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt)))
#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str))))
#define PARS(str) (!strcasecmp(tgt, str))
#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str)))
#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \
parm.parm_int_state |= (b);}
#define DELIMS " ,\t\n"
struct parm parm;
struct intnet *intnetp;
char *tok, *tgt, *p;
struct tgate *tg;
naddr addr, mask;
char delim, *val0, *tgt, *val, *p;
char buf[64];
/* "subnet=x.y.z.u/mask" must be alone on the line */
if (!strncasecmp("subnet=",line,7)) {
/* "subnet=x.y.z.u/mask,metric" must be alone on the line */
if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1)
&& *(val = &line[sizeof("subnet=")]) != '\0') {
intnetp = (struct intnet*)malloc(sizeof(*intnetp));
intnetp->intnet_metric = 1;
if ((p = strrchr(line,','))) {
if ((p = strrchr(val,','))) {
*p++ = '\0';
intnetp->intnet_metric = (int)strtol(p,&p,0);
if (*p != '\0'
@ -364,8 +548,7 @@ 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);
@ -379,21 +562,51 @@ parse_parms(char *line)
bzero(&parm, sizeof(parm));
tgt = "null";
for (tok = strtok(line, DELIMS);
tok != 0 && tok[0] != '\0';
tgt = 0, tok = strtok(0,DELIMS)) {
if (PARSE("if")) {
if (parm.parm_name[0] != '\0'
|| tok[3] == '\0'
|| strlen(tok) > IFNAMSIZ+3)
break;
strcpy(parm.parm_name, tok+3);
for (;;) {
tgt = line + strspn(line, " ,\n\r");
if (*tgt == '\0')
break;
} else if (PARSE("passwd")) {
if (tok[7] == '\0'
|| strlen(tok) > RIP_AUTH_PW_LEN+7)
break;
strcpy(parm.parm_passwd, tok+7);
line += strcspn(tgt, "= ,\n\r");
delim = *line;
if (delim == '=') {
val0 = ++line;
if (0 > parse_quote(&line," ,\n\r",&delim,
buf,sizeof(buf)))
return tgt;
}
if (delim != '\0')
*line++ = '\0';
if (PARSEQ("if")) {
if (parm.parm_name[0] != '\0'
|| strlen(buf) > IFNAMSIZ)
return tgt;
strcpy(parm.parm_name, buf);
} else if (PARSEQ("addr")) {
/* This is a bad idea, because the address based
* sets of parameters cannot be checked for
* consistency with the interface name parameters.
* The parm_net stuff is needed to allow several
* -F settings.
*/
if (!getnet(val, &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")) {
tgt = get_passwds(tgt, val0, &parm, RIP_AUTH_PW);
if (tgt)
return tgt;
} else if (PARSEQ("md5_passwd")) {
tgt = get_passwds(tgt, val0, &parm, RIP_AUTH_MD5);
if (tgt)
return tgt;
} else if (PARS("no_ag")) {
parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
@ -409,11 +622,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);
@ -437,47 +657,50 @@ 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 {
tgt = tok;
break;
return tgt; /* error */
}
}
if (tgt != 0)
return tgt;
return check_parms(&parm);
#undef DELIMS
#undef PARS
#undef PARSE
#undef PARSEQ
}
@ -487,36 +710,33 @@ check_parms(struct parm *new)
{
struct parm *parmp;
/* 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;
/* compare with existing sets of parameters
*/
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
if (strcmp(new->parm_name, parmp->parm_name))
continue;
if (!on_net(htonl(parmp->parm_addr_h),
new->parm_addr_h, new->parm_mask)
&& !on_net(htonl(new->parm_addr_h),
parmp->parm_addr_h, parmp->parm_mask))
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))
if (parmp->parm_auth.type != RIP_AUTH_NONE
&& new->parm_auth.type != RIP_AUTH_NONE
&& bcmp(&parmp->parm_auth, &new->parm_auth,
sizeof(parmp->parm_auth))) {
return "conflicting, duplicate authentication";
}
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)
@ -526,11 +746,18 @@ 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");
}
}
parmp = (struct parm*)malloc(sizeof(*parmp));
@ -547,7 +774,7 @@ check_parms(struct parm *new)
*/
int /* 0=bad */
getnet(char *name,
naddr *addrp, /* host byte order */
naddr *netp, /* host byte order */
naddr *maskp)
{
int i;
@ -574,17 +801,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)
if ((~mask & in.s_addr) != 0)
mask = HOST_MASK;
} else {
mask = (naddr)strtoul(mname, &p, 0);
@ -592,12 +821,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;
}
@ -616,6 +855,12 @@ gethost(char *name,
* might be sick because routing is.
*/
if (inet_aton(name, &in) == 1) {
/* get a good number, but check that it it makes some
* sense.
*/
if (ntohl(in.s_addr)>>24 == 0
|| ntohl(in.s_addr)>>24 == 0xff)
return 0;
*addrp = in.s_addr;
return 1;
}

View File

@ -36,7 +36,7 @@ static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.16 $"
#ident "$Revision: 1.17 $"
#include "defs.h"
#include <netinet/in_systm.h>
@ -134,8 +134,7 @@ trace_rdisc(char *act,
(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));
@ -161,7 +160,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) {
@ -174,8 +174,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;
}
@ -253,7 +252,7 @@ set_supplier(void)
if (supplier_set)
return;
trace_act("start suppying routes\n");
trace_act("start suppying routes");
/* Forget discovered routes.
*/
@ -327,8 +326,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;
@ -414,8 +412,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();
@ -486,7 +484,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
@ -504,7 +502,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);
@ -512,7 +510,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),
@ -527,7 +525,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,
@ -551,30 +550,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;
}
@ -710,7 +706,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;
}
@ -800,14 +796,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, >)
@ -843,13 +838,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;
@ -880,20 +875,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) {
@ -903,8 +892,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;
@ -926,14 +914,20 @@ ck_icmp(char *act,
void
read_d(void)
{
static naddr bad_asize, bad_len;
static struct msg_limit bad_asize, bad_len;
struct sockaddr_in from;
int n, fromlen, cc, hlen;
union {
struct ip ip;
u_short s[512/2];
u_char b[512];
} pkt;
struct {
#undef USE_PASSIFNAME /* it is too bad it does not work on raw sockets */
#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;
@ -941,7 +935,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) {
@ -952,20 +946,46 @@ 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;
#ifdef USE_PASSIFNAME
ifp = ifwithname(buf.ifname, 0);
if (ifp == 0) {
/* maybe it is a new interface */
ifinit();
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, pkt.ip.ip_dst.s_addr,
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;
}
@ -973,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)

View File

@ -96,7 +96,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
@ -137,7 +137,7 @@ When an update is applied,
.Nm
records the change in its own tables and updates the kernel routing table
if the best route to the destination changes.
The change in the kernel routing tableis reflected in the next batch of
The change in the kernel routing table is reflected in the next batch of
.Em response
packets sent.
If the next response is not scheduled for a while, a
@ -199,11 +199,11 @@ If all discovered routers disappear,
the daemon resumes listening to RIP responses.
.Pp
While using Router Discovery (which happens by default when
the system has a single network interface and a Router Discover Advertisement
the system has a single network interface and a Router Discovery Advertisement
is received), there is a single default route and a variable number of
redirected host routes in the kernel table.
.Pp
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
@ -219,14 +219,23 @@ While using Router Discovery (which happens by default when
the system has a single network interface and a Router Discover Advertisement
is received), there is a single default route and a variable number of
redirected host routes in the kernel table.
On a host with more than one network interface,
this default route will be via only one of the interfaces.
Thus, multi-homed hosts running with \f3\-q\f1 might need
.Cm no_rdisc
described below.
.Pp
See the
.Cm pm_rdisc
facility described below to support "legacy" systems
that can handle neither RIPv2 nor Router Discovery.
.Pp
By default, neither Router Discovery advertisements nor solicications
By default, neither Router Discovery advertisements nor solicitations
are sent over point to point links (e.g. PPP).
The netmask associated with point-to-point links (such as SLIP
or PPP, with the IFF_POINTOPOINT flag) is used by
.Nm routed
to infer the netmask used by the remote system when RIPv1 is used.
.Pp
Options supported by
@ -243,6 +252,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.
@ -266,7 +276,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,
@ -401,7 +411,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 .
@ -504,21 +514,41 @@ 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]][XXX2...]
specifies one or more RIPv2 cleartext passwords that will be included on
all RIPv2 responses sent, and checked on all RIPv2 responses received.
Any blanks, tab characters, commas, or '#' or '|' characters in the
password must be escaped with a backslash (\\).
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 first valid password is used on output packets.
Incoming packets can carry any password that is valid, will
be valid within 24 hours, or that was valid within 24 hours.
.It Cm md5_passwd Ns \&= Ns Ar XXX1|KeyID[start|stop][XXX2...]
specifes one or more RIPv2 MD5 passwords.
Except that a
.Cm KeyID
is required, this keyword is the 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
@ -527,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
@ -535,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,
@ -546,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
@ -560,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
@ -572,13 +607,13 @@ 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.
.El
.Pp
Note that the netmask associated with point-to-point links (such as SLIP
or PPP, with the IFF_POINTOPOINT flag) is used by
.Nm routed
to infer the netmask used by the remote system when RIPv1 is used.
.Pp
.Sh FILES
.Bl -tag -width /etc/gateways -compact
.It Pa /etc/gateways

View File

@ -40,7 +40,7 @@
#ifdef __cplusplus
extern "C" {
#endif
#ident "$Revision: 1.9 $"
#ident "$Revision: 1.10 $"
/*
* Routing Information Protocol
@ -85,11 +85,22 @@ struct netinfo {
/* RIPv2 authentication */
struct netauth {
u_int16_t a_family; /* always RIP_AF_AUTH */
u_int16_t a_type;
#define RIP_AUTH_NONE 0
#define RIP_AUTH_PW htons(2) /* password type */
#define RIP_AUTH_MD5 htons(3) /* Keyed MD5 */
union {
#define RIP_AUTH_PW_LEN 16
int8_t au_pw[RIP_AUTH_PW_LEN];
u_int8_t au_pw[RIP_AUTH_PW_LEN];
struct a_md5 {
int16_t md5_pkt_len; /* RIP-II packet length */
int8_t md5_keyid; /* key ID and auth data len */
int8_t md5_auth_len; /* 16 */
u_int32_t md5_seqno; /* sequence number */
u_int32_t rsvd[2]; /* must be 0 */
#define RIP_AUTH_MD5_LEN RIP_AUTH_PW_LEN
} a_md5;
} au;
};
@ -103,6 +114,7 @@ struct rip {
struct netauth ru_auth[1];
} ripun;
#define rip_nets ripun.ru_nets
#define rip_auths ripun.ru_auth
#define rip_tracefile ripun.ru_tracefile
};

View File

@ -1,6 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
PROG= rtquery
SRCS= rtquery.c md5.c
MAN8= rtquery.0
#COPTS= -g -DDEBUG -Wall

325
sbin/routed/rtquery/md5.c Normal file
View File

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

View File

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

View File

@ -65,6 +65,17 @@ static char rcsid[] = "$NetBSD$";
#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 */
@ -90,8 +101,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 */
@ -101,6 +114,7 @@ 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
@ -108,14 +122,14 @@ main(int argc,
char *argv[])
{
int ch, bsize;
char *p, *options, *value;
char *p, *options, *value, delim;
OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
pgmname = argv[0];
while ((ch = getopt(argc, argv, "np1w:r:t:")) != EOF)
while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != EOF)
switch (ch) {
case 'n':
not_trace = 1;
@ -208,6 +222,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;
}
@ -215,8 +254,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|on=dump/../table}"
" host1 [host2 ...]\n",
pgmname);
exit(1);
}
@ -294,6 +334,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;
@ -304,11 +346,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;
@ -393,7 +462,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.
*/
@ -447,7 +570,7 @@ rip_input(struct sockaddr_in *from,
int i;
struct hostent *hp;
struct netent *np;
struct netauth *a;
struct netauth *na;
if (nflag) {
@ -544,11 +667,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;
@ -652,3 +797,64 @@ getnet(char *name,
rt->n_mask = htonl(mask);
return 1;
}
/* strtok(), but honoring backslash
*/
static int /* -1=bad */
parse_quote(char **linep,
char *delims,
char *delimp,
char *buf,
int lim)
{
char c, *pc, *p;
pc = *linep;
if (*pc == '\0')
return -1;
for (;;) {
if (lim == 0)
return -1;
c = *pc++;
if (c == '\0')
break;
if (c == '\\' && pc != '\0') {
if ((c = *pc++) == 'n') {
c = '\n';
} else if (c == 'r') {
c = '\r';
} else if (c == 't') {
c = '\t';
} else if (c == 'b') {
c = '\b';
} else if (c >= '0' && c <= '7') {
c -= '0';
if (*pc >= '0' && *pc <= '7') {
c = (c<<3)+(*pc++ - '0');
if (*pc >= '0' && *pc <= '7')
c = (c<<3)+(*pc++ - '0');
}
}
} else {
for (p = delims; *p != '\0'; ++p) {
if (*p == c)
goto exit;
}
}
*buf++ = c;
--lim;
}
exit:
if (delimp != 0)
*delimp = c;
*linep = pc-1;
if (lim != 0)
*buf = '\0';
return 0;
}

View File

@ -36,7 +36,7 @@ static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.25 $"
#ident "$Revision: 1.26 $"
#include "defs.h"
@ -57,6 +57,7 @@ int stopint;
int total_routes;
/* zap any old routes through this gateway */
naddr age_bad_gate;
@ -704,7 +705,7 @@ rtioctl(int action, /* RTM_DELETE, etc */
if (cc < 0) {
if (errno == ESRCH
&& (action == RTM_CHANGE || action == RTM_DELETE)) {
trace_act("route to %s disappeared before %s\n",
trace_act("route to %s disappeared before %s",
addrname(dst, mask, 0),
rtm_type_name(action));
if (action == RTM_CHANGE) {
@ -831,14 +832,14 @@ 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",
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;
}
@ -867,7 +868,7 @@ rtm_add(struct rt_msghdr *rtm,
k->k_state |= KS_DELETE;
LIM_SEC(need_kern, 0);
trace_act("mark redirected %s --> %s for deletion"
" since this is a router\n",
" since this is a router",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate));
} else {
@ -889,7 +890,7 @@ 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) {
@ -916,7 +917,7 @@ rtm_lose(struct rt_msghdr *rtm,
{
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;
}
@ -1065,12 +1066,12 @@ read_rt(void)
ifp = ifwithindex(m.ifm.ifm_index);
if (ifp == 0)
trace_act("note %s with flags %#x"
" for index #%d\n",
" for 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);
@ -1098,12 +1099,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;
}
@ -1118,7 +1119,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;
}
@ -1136,31 +1137,31 @@ read_rt(void)
case RTM_CHANGE:
case RTM_REDIRECT:
if (m.r.rtm.rtm_errno != 0) {
trace_act("ignore %s with \"%s\" error\n",
trace_act("ignore %s with \"%s\" error",
str, strerror(m.r.rtm.rtm_errno));
} else {
trace_act("%s\n", str);
trace_act("%s", str);
rtm_add(&m.r.rtm,&info,0);
}
break;
case RTM_DELETE:
if (m.r.rtm.rtm_errno != 0) {
trace_act("ignore %s with \"%s\" error\n",
trace_act("ignore %s with \"%s\" error",
str, strerror(m.r.rtm.rtm_errno));
} else {
trace_act("%s\n", str);
trace_act("%s", str);
del_static(S_ADDR(INFO_DST(&info)), mask, 1);
}
break;
case RTM_LOSING:
trace_act("%s\n", str);
trace_act("%s", str);
rtm_lose(&m.r.rtm,&info);
break;
default:
trace_act("ignore %s\n", str);
trace_act("ignore %s", str);
break;
}
}
@ -1268,8 +1269,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);
}
@ -1431,7 +1431,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));
}
@ -1935,29 +1935,46 @@ void
age(naddr bad_gate)
{
struct interface *ifp;
int need_query = 0;
/* If not listening to RIP, there is no need to age the routes in
* the table.
*/
age_timer.tv_sec = (now.tv_sec
+ ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL));
age_timer.tv_sec = now.tv_sec + (rip_sock < 0
? NEVER
: SUPPLY_INTERVAL);
/* Check for dead IS_REMOTE interfaces by timing their
* transmissions.
*/
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
/* Check for dead IS_REMOTE interfaces by timing their
* transmissions.
*/
if ((ifp->int_state & IS_REMOTE)
&& !(ifp->int_state & IS_PASSIVE)
&& (ifp->int_state & IS_ACTIVE)) {
LIM_SEC(age_timer, now.tv_sec+SUPPLY_INTERVAL);
if (!(ifp->int_state & IS_REMOTE))
continue;
if (now.tv_sec - ifp->int_act_time > EXPIRE_TIME
&& !(ifp->int_state & IS_BROKE)) {
msglog("remote interface %s to %s timed out"
"--turned off",
ifp->int_name,
naddr_ntoa(ifp->int_addr));
if_bad(ifp);
}
/* ignore unreachable remote interfaces */
if (!check_remote(ifp))
continue;
/* Restore remote interface that has become reachable
*/
if (ifp->int_state & IS_BROKE)
if_ok(ifp, "remote ");
if (ifp->int_act_time != NEVER
&& now.tv_sec - ifp->int_act_time > EXPIRE_TIME) {
msglog("remote interface %s to %s timed out after"
" %d:%d",
ifp->int_name,
naddr_ntoa(ifp->int_dstaddr),
(now.tv_sec - ifp->int_act_time)/60,
(now.tv_sec - ifp->int_act_time)%60);
if_sick(ifp);
}
/* If we have not heard from the other router
* recently, ask it.
*/
if (now.tv_sec >= ifp->int_query_time) {
ifp->int_query_time = NEVER;
need_query = 1;
}
}
@ -1967,4 +1984,8 @@ age(naddr bad_gate)
/* Update the kernel routing table. */
fix_kern();
/* poke reticent remote gateways */
if (need_query)
rip_query();
}

View File

@ -36,7 +36,7 @@ static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.13 $"
#ident "$Revision: 1.14 $"
#define RIPCMDS
#include "defs.h"
@ -62,6 +62,59 @@ char savetracename[MAXPATHLEN+1];
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 *
@ -188,10 +241,11 @@ trace_off(char *p, ...)
void
trace_on(char *filename,
int trusted)
int initial) /* 1=setting from command line */
{
struct stat stbuf;
FILE *n_ftrace;
u_int old_tracelevel;
/* Given a null filename when tracing is already on, increase the
@ -219,7 +273,7 @@ trace_on(char *filename,
return;
}
if (!trusted
if (!initial
#ifdef _PATH_TRACE
&& (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)
|| strstr(filename,"../")
@ -252,7 +306,11 @@ trace_on(char *filename,
if (new_tracelevel == 0)
new_tracelevel = 1;
set_tracelevel();
old_tracelevel = tracelevel;
set_tracelevel(initial);
if (!initial && old_tracelevel == 0)
trace_dump();
}
@ -281,7 +339,7 @@ sigtrace_off(int s)
* actions + packets + contents
*/
void
set_tracelevel(void)
set_tracelevel(int initial)
{
static char *off_msgs[MAX_TRACELEVEL] = {
"Tracing actions stopped",
@ -304,7 +362,8 @@ set_tracelevel(void)
return;
}
}
while (new_tracelevel != tracelevel) {
for (; new_tracelevel != tracelevel; tracelevel++) {
if (new_tracelevel < tracelevel) {
if (--tracelevel == 0)
trace_off(tracelevel_pat, off_msgs[0]);
@ -317,7 +376,8 @@ set_tracelevel(void)
else
ftrace = stdout;
}
tmsg(tracelevel_pat, on_msgs[tracelevel++]);
if (!initial || tracelevel+1 == new_tracelevel)
tmsg(tracelevel_pat, on_msgs[tracelevel]);
}
}
tracelevel_pat = "%s\n";
@ -377,10 +437,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
@ -389,10 +450,10 @@ 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_NEED_NET_SYN, 0, "" },
{ IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
{ IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
@ -414,7 +475,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"}
};
@ -495,15 +556,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);
@ -605,6 +669,7 @@ trace_act(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
}
@ -621,6 +686,7 @@ trace_pkt(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
}
@ -762,10 +828,14 @@ walk_trace(struct radix_node *rn,
static void
trace_dump(void)
{
struct interface *ifp;
if (ftrace == 0)
return;
lastlog();
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next)
trace_if("", ifp);
(void)rn_walktree(rhead, walk_trace, 0);
}
@ -778,8 +848,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;
@ -803,17 +873,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 ",
@ -822,32 +895,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));