New version of Vern's routed. This includes more byte-order fixes,

some MD5 fixes, better tracing, configurable redirect processing,
and a fix to split-horizon/poisoned-reverse treatment.

Submitted by:	Vernon J. Schryver <vjs@mica.denver.sgi.com>
This commit is contained in:
Garrett Wollman 1996-12-11 20:59:33 +00:00
parent c9c588ef9b
commit 71965874ee
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/SGI/dist_v_2_21/; revision=20339
svn path=/vendor/SGI/vjs_961211/; revision=20341; tag=vendor/SGI/vjs_961211
14 changed files with 697 additions and 526 deletions

View File

@ -36,7 +36,7 @@
*/
#ifndef __NetBSD__
#ident "$Revision: 1.17 $"
#ident "$Revision: 1.19 $"
#endif
/* Definitions for RIPv2 routing process.
@ -123,7 +123,8 @@
*/
/* #define MCAST_PPP_BUG */
#define NEVER (24*60*60) /* a long time */
#define DAY (24*60*60)
#define NEVER DAY /* a long time */
#define EPOCH NEVER /* bias time by this to avoid <0 */
/* Scan the kernel regularly to see if any interfaces have appeared or been
@ -292,15 +293,13 @@ struct interface {
#endif
time_t ts; /* timestamp on network stats */
} int_data;
# define MAX_AUTH_KEYS 5
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;
u_char key[RIP_AUTH_PW_LEN];
u_char keyid;
time_t start, end;
} int_auth[MAX_AUTH_KEYS];
int int_rdisc_pref; /* advertised rdisc preference */
int int_rdisc_int; /* MaxAdvertiseInterval */
int int_rdisc_cnt;
@ -317,10 +316,10 @@ struct interface {
#define IS_ALL_HOSTS 0x0000040 /* in INADDR_ALLHOSTS_GROUP */
#define IS_ALL_ROUTERS 0x0000080 /* in INADDR_ALLROUTERS_GROUP */
#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 */
/* 0x0001000 spare */
#define IS_REDIRECT_OK 0x0000200 /* accept ICMP redirects */
#define IS_BROKE 0x0000400 /* seems to be broken */
#define IS_SICK 0x0000800 /* seems to be broken */
#define IS_DUP 0x0001000 /* has a duplicate address */
#define IS_NEED_NET_SYN 0x0002000 /* need RS_NET_SYN route */
#define IS_NO_AG 0x0004000 /* do not aggregate subnets */
#define IS_NO_SUPER_AG 0x0008000 /* do not aggregate networks */
@ -399,7 +398,7 @@ extern struct parm {
u_int parm_int_state;
int parm_rdisc_pref;
int parm_rdisc_int;
struct auth parm_auth;
struct auth parm_auth[MAX_AUTH_KEYS];
} *parms;
/* authority for internal networks */
@ -475,13 +474,14 @@ extern int need_flash; /* flash update needed */
extern struct timeval need_kern; /* need to update kernel table */
extern int update_seqno; /* a route has changed */
extern u_int tracelevel, new_tracelevel;
extern int tracelevel, new_tracelevel;
#define MAX_TRACELEVEL 4
#define TRACEKERNEL (tracelevel >= 4) /* log kernel changes */
#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */
#define TRACEPACKETS (tracelevel >= 2) /* note packets */
#define TRACEACTIONS (tracelevel != 0)
extern FILE *ftrace; /* output trace file */
extern char inittracename[MAXPATHLEN+1];
extern struct radix_node_head *rhead;
@ -499,7 +499,7 @@ extern void rip_on(struct interface *);
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 clr_ws_buf(struct ws_buf *, struct auth *);
extern void rip_query(void);
extern void rip_bcast(int);
extern void supply(struct sockaddr_in *, struct interface *,
@ -507,8 +507,12 @@ extern void supply(struct sockaddr_in *, struct interface *,
extern void msglog(char *, ...);
struct msg_limit {
time_t reuse;
struct msg_sub {
naddr addr;
time_t until;
# define MSG_SUBJECT_N 8
} subs[MSG_SUBJECT_N];
};
extern void msglim(struct msg_limit *, naddr, char *, ...);
#define LOGERR(msg) msglog(msg ": %s", strerror(errno))
@ -528,15 +532,16 @@ extern void intvl_random(struct timeval *, u_long, u_long);
extern int getnet(char *, naddr *, naddr *);
extern int gethost(char *, naddr *);
extern void gwkludge(void);
extern char *parse_parms(char *);
extern char *parse_parms(char *, int);
extern char *check_parms(struct parm *);
extern void get_parms(struct interface *);
extern void lastlog(void);
extern void trace_on(char *, int);
extern void set_tracefile(char *, char *, int);
extern void tracelevel_msg(char *, int);
extern void trace_off(char*, ...);
extern void set_tracelevel(void);
extern void trace_flush(void);
extern void set_tracelevel(int);
extern void trace_kernel(char *, ...);
extern void trace_act(char *, ...);
extern void trace_pkt(char *, ...);
@ -619,8 +624,8 @@ 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 *);
extern struct auth *find_auth(struct interface *);
extern void end_md5_auth(struct ws_buf *, struct auth *);
#define MD5_DIGEST_LEN 16
typedef struct {

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.18 $"
#ident "$Revision: 1.21 $"
#include "defs.h"
#include "pathnames.h"
@ -208,42 +208,54 @@ ifwithindex(u_short index)
/* Find an interface from which the specified address
* should have come from. Used for figuring out which
* interface a packet came in on -- for tracing.
* interface a packet came in on.
*/
struct interface *
iflookup(naddr addr)
{
struct interface *ifp, *maybe;
static struct timeval retried;
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)
return ifp;
for (;;) {
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
if (ifp->int_if_flags & IFF_POINTOPOINT) {
/* finished with a match */
if (ifp->int_dstaddr == addr)
return ifp;
} else {
/* finished with an exact match */
if (ifp->int_addr == addr)
return ifp;
} else {
/* finished with an exact match */
if (ifp->int_addr == addr)
return ifp;
/* Look for the longest approximate match.
*/
if (on_net(addr, ifp->int_net, ifp->int_mask)
&& (maybe == 0
|| ifp->int_mask > maybe->int_mask))
maybe = ifp;
/* Look for the longest approximate match.
*/
if (on_net(addr, ifp->int_net, ifp->int_mask)
&& (maybe == 0
|| ifp->int_mask > maybe->int_mask))
maybe = ifp;
}
}
}
return maybe;
if (maybe != 0
|| (retried.tv_sec == now.tv_sec
&& retried.tv_usec == now.tv_usec))
return maybe;
/* If there is no known interface, maybe there is a
* new interface. So just once look for new interfaces.
*/
ifinit();
retried = now;
}
}
/* Return the classical netmask for an IP address.
*/
naddr
std_mask(naddr addr) /* in network order */
naddr /* host byte order */
std_mask(naddr addr) /* network byte order */
{
NTOHL(addr); /* was a host, not a network */
@ -338,9 +350,9 @@ check_dst(naddr addr)
/* See a new interface duplicates an existing interface.
*/
struct interface *
check_dup(naddr addr,
naddr dstaddr,
naddr mask,
check_dup(naddr addr, /* IP address, so network byte order */
naddr dstaddr, /* ditto */
naddr mask, /* mask, so host byte order */
int if_flags)
{
struct interface *ifp;
@ -691,6 +703,7 @@ ifinit(void)
ifs0.int_index = ifm->ifm_index;
ifs0.int_if_flags = ifm->ifm_flags;
ifs0.int_state = IS_CHECKED;
ifs0.int_query_time = NEVER;
ifs0.int_act_time = now.tv_sec;
ifs0.int_data.ts = now.tv_sec;
ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets;
@ -1006,10 +1019,20 @@ ifinit(void)
if (ifp != 0) {
if (!(prev_complaints & COMP_DUP)) {
complaints |= COMP_DUP;
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));
msglog("%s (%s%s%s) is duplicated by"
" %s (%s%s%s)",
ifs.int_name,
addrname(ifs.int_addr,ifs.int_mask,1),
((ifs.int_if_flags & IFF_POINTOPOINT)
? "-->" : ""),
((ifs.int_if_flags & IFF_POINTOPOINT)
? naddr_ntoa(ifs.int_dstaddr) : ""),
ifp->int_name,
addrname(ifp->int_addr,ifp->int_mask,1),
((ifp->int_if_flags & IFF_POINTOPOINT)
? "-->" : ""),
((ifp->int_if_flags & IFF_POINTOPOINT)
? naddr_ntoa(ifp->int_dstaddr) : ""));
}
ifp->int_state |= IS_DUP;
continue;
@ -1263,7 +1286,7 @@ addrouteforif(struct interface *ifp)
* it must be reachable using our physical interfaces
*/
if ((ifp->int_state & IS_REMOTE)
&& !(ifp->int_state && IS_EXTERNAL)
&& !(ifp->int_state & IS_EXTERNAL)
&& !check_remote(ifp))
return 0;

View File

@ -36,7 +36,7 @@ static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.17 $"
#ident "$Revision: 1.19 $"
#include "defs.h"
@ -54,16 +54,20 @@ void
read_rip(int sock,
struct interface *sifp)
{
static struct msg_limit bad_name;
struct sockaddr_in from;
struct interface *aifp;
int fromlen, cc;
struct {
#ifdef USE_PASSIFNAME
static struct msg_limit bad_name;
struct {
char ifname[IFNAMSIZ];
#endif
union pkt_buf pbuf;
} inbuf;
#else
struct {
union pkt_buf pbuf;
} inbuf;
#endif
for (;;) {
@ -148,7 +152,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
struct netinfo *n, *lim;
struct interface *ifp1;
naddr gate, mask, v1_mask, dst, ddst_h;
struct auth_key *ap;
struct auth *ap;
int i;
/* Notice when we hear from a remote gateway
@ -262,17 +266,16 @@ input(struct sockaddr_in *from, /* received from this IP address */
* do not disclose our secret unless the other guy
* already knows it.
*/
if (aifp != 0
&& aifp->int_auth.type == RIP_AUTH_PW
ap = find_auth(aifp);
if (aifp == 0 && ap->type == RIP_AUTH_PW
&& n->n_family == RIP_AF_AUTH
&& !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);
clr_ws_buf(&v12buf, ap);
do {
NTOHL(n->n_metric);
@ -397,7 +400,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
/* Send the answer about specific routes.
*/
if (ap != 0 && aifp->int_auth.type == RIP_AUTH_MD5)
if (ap != 0 && ap->type == RIP_AUTH_MD5)
end_md5_auth(&v12buf, ap);
if (from->sin_port != htons(RIP_PORT)) {
@ -433,7 +436,8 @@ input(struct sockaddr_in *from, /* received from this IP address */
}
if (rip->rip_cmd == RIPCMD_TRACEON) {
rip->rip_tracefile[cc-4] = '\0';
trace_on((char*)rip->rip_tracefile, 0);
set_tracefile((char*)rip->rip_tracefile,
"trace command: %s\n", 0);
} else {
trace_off("tracing turned off by %s\n",
naddr_ntoa(FROM_NADDR));
@ -519,8 +523,8 @@ input(struct sockaddr_in *from, /* received from this IP address */
}
/* If the interface cares, ignore bad routers.
* Trace but do not log this problem because when it
* happens it happens a lot.
* Trace but do not log this problem, because where it
* happens, it happens frequently.
*/
if (aifp->int_state & IS_DISTRUST) {
struct tgate *tg = tgates;
@ -536,14 +540,13 @@ input(struct sockaddr_in *from, /* received from this IP address */
}
/* Authenticate the packet if we have a secret.
* If we do not, ignore the silliness in RFC 1723
* and accept it regardless.
* If we do not have any secrets, ignore the error 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;
}
if (aifp->int_auth[0].type != RIP_AUTH_NONE
&& rip->rip_vers != RIPv1
&& !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
return;
do {
if (n->n_family == RIP_AF_AUTH)
@ -860,9 +863,8 @@ ck_passwd(struct interface *aifp,
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;
struct auth *ap;
MD5_CTX md5_ctx;
u_char hash[RIP_AUTH_PW_LEN];
int i;
@ -874,35 +876,24 @@ ck_passwd(struct interface *aifp,
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;
}
/* accept any current (+/- 24 hours) password
*/
for (ap = aifp->int_auth, i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
if (ap->type != NA->a_type
|| (u_long)ap->start > (u_long)clk.tv_sec+DAY
|| (u_long)ap->end+DAY < (u_long)clk.tv_sec)
continue;
if (NA->a_type == RIP_AUTH_PW) {
/* 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)
if (NA->a_type == RIP_AUTH_PW) {
if (!bcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN))
return 1;
} else {
/* accept MD5 secret with the right key ID
*/
if (NA->au.a_md5.md5_keyid != ap->keyid)
continue;
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
@ -917,13 +908,14 @@ ck_passwd(struct interface *aifp,
MD5Update(&md5_ctx, (u_char *)NA,
(char *)na2->au.au_pw - (char *)NA);
MD5Update(&md5_ctx,
(u_char *)akp->key, sizeof(akp->key));
(u_char *)ap->key, sizeof(ap->key));
MD5Final(hash, &md5_ctx);
if (na2->a_family == RIP_AF_AUTH
&& na2->a_type == 1
&& NA->au.a_md5.md5_auth_len == RIP_AUTH_PW_LEN
&& !bcmp(hash, na2->au.au_pw, sizeof(hash)))
return 1;
if (na2->a_family != RIP_AF_AUTH
|| na2->a_type != 1
|| NA->au.a_md5.md5_auth_len != RIP_AUTH_PW_LEN
|| bcmp(hash, na2->au.au_pw, sizeof(hash)))
return 0;
return 1;
}
}

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.18 $"
#ident "$Revision: 1.20 $"
#include "defs.h"
#include "pathnames.h"
@ -201,10 +201,13 @@ main(int argc,
/* handle arbirary, (usually) per-interface
* parameters.
*/
p = parse_parms(optarg);
if (p != 0)
msglog("bad \"%s\" in \"%s\"",
p, optarg);
p = parse_parms(optarg, 0);
if (p != 0) {
if (strcasecmp(p,optarg))
msglog("%s in \"%s\"", p, optarg);
else
msglog("bad \"-P %s\"", optarg);
}
break;
default:
@ -218,9 +221,11 @@ main(int argc,
tracename = *argv++;
argc--;
}
if (tracename != 0 && tracename[0] == '\0')
goto usage;
if (argc != 0) {
usage:
logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]"
logbad(0, "usage: routed [-sqdghmpAt] [-T tracefile]"
" [-F net[,metric]] [-P parms]");
}
if (geteuid() != 0)
@ -263,18 +268,16 @@ main(int argc,
signal(SIGUSR2, sigtrace_off);
/* get into the background */
if (background) {
#ifdef sgi
if (0 > _daemonize(_DF_NOCHDIR,
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
BADERR(0, "_daemonize()");
if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK),
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
BADERR(0, "_daemonize()");
#else
if (daemon(1, 1) < 0)
BADERR(0,"daemon()");
if (background && daemon(0, new_tracelevel) < 0)
BADERR(0,"daemon()");
#endif
}
mypid = getpid();
srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid));
@ -297,11 +300,11 @@ main(int argc,
if (background && new_tracelevel == 0)
ftrace = 0;
if (tracename != 0) {
trace_on(tracename, 1);
if (new_tracelevel == 0) /* use stdout if file is bad */
new_tracelevel = 1;
strncpy(inittracename, tracename, sizeof(inittracename)-1);
set_tracefile(inittracename, "%s\n", -1);
} else {
tracelevel_msg("%s\n", -1); /* turn on tracing to stdio */
}
set_tracelevel(1);
bufinit();
@ -354,8 +357,8 @@ main(int argc,
now_expire = now.tv_sec - EXPIRE_TIME;
now_garbage = now.tv_sec - GARBAGE_TIME;
/* deal with interrupts that should affect tracing */
set_tracelevel(0);
/* deal with signals that should affect tracing */
set_tracelevel();
if (stopint != 0) {
rip_bcast(0);
@ -491,7 +494,7 @@ main(int argc,
/* ARGSUSED */
void
sigalrm(int sig)
sigalrm(int s)
{
/* Historically, SIGALRM would cause the daemon to check for
* new and broken interfaces.
@ -816,20 +819,53 @@ msglog(char *p, ...)
}
/* Put a message about a bad router into the system log if
/* Put a message about a bad system into the system log if
* we have not complained about it recently.
*
* It is desirable to complain about all bad systems, but not too often.
* In the worst case, it is not practical to keep track of all bad systems.
* For example, there can be many systems with the wrong password.
*/
void
msglim(struct msg_limit *lim, naddr addr, char *p, ...)
{
va_list args;
int i;
struct msg_sub *ms1, *ms;
char *p1;
va_start(args, p);
if ( lim->addr != addr || lim->until <= now.tv_sec) {
lim->addr = addr;
lim->until = now.tv_sec + 60*60;
/* look for the oldest slot in the table
* or the slot for the bad router.
*/
ms = ms1 = lim->subs;
for (i = MSG_SUBJECT_N; ; i--, ms1++) {
if (i == 0) {
/* Reuse a slot at most once every 10 minutes.
*/
if (lim->reuse > now.tv_sec) {
ms = 0;
} else {
ms = ms1;
lim->reuse = now.tv_sec + 10*60;
}
break;
}
if (ms->addr == addr) {
/* Repeat a complaint about a given system at
* most once an hour.
*/
if (ms->until > now.tv_sec)
ms = 0;
break;
}
if (ms->until < ms1->until)
ms = ms1;
}
if (ms != 0) {
ms->addr = addr;
ms->until = now.tv_sec + 60*60; /* 60 minutes */
trace_flush();
for (p1 = p; *p1 == ' '; p1++)
@ -837,6 +873,7 @@ msglim(struct msg_limit *lim, naddr addr, char *p, ...)
vsyslog(LOG_ERR, p1, args);
}
/* always display the message if tracing */
if (ftrace != 0) {
(void)vfprintf(ftrace, p, args);
(void)fputc('\n', ftrace);

View File

@ -22,7 +22,7 @@
* documentation and/or software.
*/
#ident "$Revision: 1.2 $"
#ident "$Revision: 1.3 $"
#ifdef sgi
#include <strings.h>

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.18 $"
#ident "$Revision: 1.21 $"
#include "defs.h"
@ -53,7 +53,7 @@ struct {
naddr to_std_mask;
naddr to_std_net;
struct interface *ifp; /* usually output interface */
struct auth_key *a;
struct auth *a;
char metric; /* adjust metrics by interface */
int npackets;
int gen_limit;
@ -180,10 +180,15 @@ output(enum output_type type,
}
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
}
break;
case NO_OUT_MULTICAST:
case NO_OUT_RIPV2:
break;
default:
#ifdef DEBUG
abort();
#endif
return -1;
}
trace_rip(msg, "to", &sin, ifp, buf, size);
@ -206,28 +211,42 @@ output(enum output_type type,
}
/* Find the first key that has not expired, but settle for
/* Find the first key for a packet to send.
* Try for a key that is eligable and has not expired, but settle for
* the last key if they have all expired.
* If no key is ready yet, give up.
*/
struct auth_key *
struct auth *
find_auth(struct interface *ifp)
{
struct auth_key *ap, *res;
struct auth *ap, *res;
int i;
if (ifp == 0 || ifp->int_auth.type == RIP_AUTH_NONE)
if (ifp == 0)
return 0;
res = 0;
ap = ifp->int_auth.keys;
ap = ifp->int_auth;
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;
/* stop looking after the last key */
if (ap->type == RIP_AUTH_NONE)
break;
/* ignore keys that are not ready yet */
if ((u_long)ap->start > (u_long)clk.tv_sec)
continue;
if ((u_long)ap->end < (u_long)clk.tv_sec) {
/* note best expired password as a fall-back */
if (res == 0 || (u_long)ap->end > (u_long)res->end)
res = ap;
continue;
}
/* note key with the best future */
if (res == 0 || (u_long)res->end < (u_long)ap->end)
res = ap;
}
return res;
}
@ -235,8 +254,7 @@ find_auth(struct interface *ifp)
void
clr_ws_buf(struct ws_buf *wb,
struct auth_key *ap,
struct interface *ifp)
struct auth *ap)
{
struct netauth *na;
@ -249,13 +267,13 @@ clr_ws_buf(struct ws_buf *wb,
if (ap == 0)
return;
na = (struct netauth*)wb->n;
if (ifp->int_auth.type == RIP_AUTH_PW) {
if (ap->type == RIP_AUTH_PW) {
na->a_family = RIP_AF_AUTH;
na->a_type = RIP_AUTH_PW;
bcopy(ap->key, na->au.au_pw, sizeof(na->au.au_pw));
wb->n++;
} else if (ifp->int_auth.type == RIP_AUTH_MD5) {
} else if (ap->type == RIP_AUTH_MD5) {
na->a_family = RIP_AF_AUTH;
na->a_type = RIP_AUTH_MD5;
na->au.a_md5.md5_keyid = ap->keyid;
@ -269,7 +287,7 @@ clr_ws_buf(struct ws_buf *wb,
void
end_md5_auth(struct ws_buf *wb,
struct auth_key *ap)
struct auth *ap)
{
struct netauth *na, *na2;
MD5_CTX md5_ctx;
@ -306,7 +324,7 @@ supply_write(struct ws_buf *wb)
case NO_OUT_RIPV2:
break;
default:
if (ws.ifp->int_auth.type == RIP_AUTH_MD5)
if (ws.a != 0 && ws.a->type == RIP_AUTH_MD5)
end_md5_auth(wb,ws.a);
if (output(wb->type, &ws.to, ws.ifp, wb->buf,
((char *)wb->n - (char*)wb->buf)) < 0
@ -316,7 +334,7 @@ supply_write(struct ws_buf *wb)
break;
}
clr_ws_buf(wb,ws.a,ws.ifp);
clr_ws_buf(wb,ws.a);
}
@ -326,7 +344,7 @@ static void
supply_out(struct ag_info *ag)
{
int i;
naddr mask, v1_mask, dst_h, ddst_h;
naddr mask, v1_mask, dst_h, ddst_h = 0;
struct ws_buf *wb;
@ -563,25 +581,33 @@ walk_supply(struct radix_node *rn,
* forgotten.
*
* Include the routes for both ends of point-to-point interfaces
* since the other side presumably knows them as well as we do.
* among those suppressed by split-horizon, since the other side
* should knows them as well as we do.
*/
if (RT->rt_ifp == ws.ifp && ws.ifp != 0
&& !(ws.state & WS_ST_QUERY)
&& (ws.state & WS_ST_TO_ON_NET)
&& (!(RT->rt_state & RS_IF)
|| ws.ifp->int_if_flags & IFF_POINTOPOINT)) {
/* Poison-reverse the route instead of only not advertising it
* it is recently changed from some other route.
/* If we do not mark the route with AGS_SPLIT_HZ here,
* it will be poisoned-reverse, or advertised back toward
* its source with an infinite metric. If we have recently
* advertised the route with a better metric than we now
* have, then we should poison-reverse the route before
* suppressing it for split-horizon.
*
* In almost all cases, if there is no spare for the route
* then it is either old or a brand new route, and if it
* is brand new, there is no need for poison-reverse.
* then it is either old and dead or a brand new route.
* If it is brand new, there is no need for poison-reverse.
* If it is old and dead, it is already poisoned.
*/
metric = HOPCNT_INFINITY;
if (RT->rt_poison_time < now_expire
|| RT->rt_spares[1].rts_gate ==0) {
|| RT->rt_poison_metric >= metric
|| RT->rt_spares[1].rts_gate == 0) {
ags |= AGS_SPLIT_HZ;
ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
}
metric = HOPCNT_INFINITY;
}
/* Adjust the outgoing metric by the cost of the link.
@ -716,10 +742,10 @@ supply(struct sockaddr_in *dst,
}
ws.a = (vers == RIPv2) ? find_auth(ifp) : 0;
if (ws.a != 0 && !passwd_ok && ifp->int_auth.type == RIP_AUTH_PW)
if (!passwd_ok && ws.a != 0 && ws.a->type == RIP_AUTH_PW)
ws.a = 0;
clr_ws_buf(&v12buf,ws.a,ifp);
clr_ws_buf(&v2buf,ws.a,ifp);
clr_ws_buf(&v12buf,ws.a);
clr_ws_buf(&v2buf,ws.a);
/* Fake a default route if asked and if there is not already
* a better, real default route.

View File

@ -36,10 +36,11 @@ static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.10 $"
#ident "$Revision: 1.12 $"
#include "defs.h"
#include "pathnames.h"
#include <sys/stat.h>
struct parm *parms;
@ -54,6 +55,7 @@ get_parms(struct interface *ifp)
{
static warned_auth_in, warned_auth_out;
struct parm *parmp;
int i, num_passwds = 0;
/* get all relevant parameters
*/
@ -68,9 +70,14 @@ get_parms(struct interface *ifp)
* so get its settings
*/
ifp->int_state |= parmp->parm_int_state;
if (parmp->parm_auth.type != RIP_AUTH_NONE)
bcopy(&parmp->parm_auth, &ifp->int_auth,
sizeof(ifp->int_auth));
for (i = 0; i < MAX_AUTH_KEYS; i++) {
if (parmp->parm_auth[0].type == RIP_AUTH_NONE
|| num_passwds >= MAX_AUTH_KEYS)
break;
bcopy(&parmp->parm_auth[i],
&ifp->int_auth[num_passwds++],
sizeof(ifp->int_auth[0]));
}
if (parmp->parm_rdisc_pref != 0)
ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
if (parmp->parm_rdisc_int != 0)
@ -114,7 +121,7 @@ get_parms(struct interface *ifp)
ifp->int_state |= IS_NO_RIP;
if (!IS_RIP_IN_OFF(ifp->int_state)
&& ifp->int_auth.type != RIP_AUTH_NONE
&& ifp->int_auth[0].type != RIP_AUTH_NONE
&& !(ifp->int_state & IS_NO_RIPV1_IN)
&& !warned_auth_in) {
msglog("Warning: RIPv1 input via %s"
@ -123,14 +130,14 @@ get_parms(struct interface *ifp)
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;
&& ifp->int_auth[0].type != RIP_AUTH_NONE
&& !(ifp->int_state & IS_NO_RIPV1_OUT)) {
if (!warned_auth_out) {
msglog("Warning: RIPv1 output via %s"
" will be sent without authentication",
ifp->int_name);
warned_auth_out = 1;
}
}
}
@ -160,6 +167,7 @@ gwkludge(void)
struct interface *ifp;
naddr dst, netmask, gate;
int metric, n;
struct stat sb;
u_int state;
char *type;
@ -168,6 +176,12 @@ gwkludge(void)
if (fp == 0)
return;
if (0 > fstat(fileno(fp), &sb)) {
msglog("could not stat() "_PATH_GATEWAYS);
(void)fclose(fp);
return;
}
for (;;) {
if (0 == fgets(lbuf, sizeof(lbuf)-1, fp))
break;
@ -185,10 +199,12 @@ gwkludge(void)
*/
if (strncasecmp("net", lptr, 3)
&& strncasecmp("host", lptr, 4)) {
p = parse_parms(lptr);
p = parse_parms(lptr,
(sb.st_uid == 0
&& !(sb.st_mode&(S_IRWXG|S_IRWXO))));
if (p != 0) {
if (strcasecmp(p,lptr))
msglog("bad %s in "_PATH_GATEWAYS
msglog("%s in "_PATH_GATEWAYS
" entry \"%s\"", p, lptr);
else
msglog("bad \"%s\" in "_PATH_GATEWAYS,
@ -225,6 +241,7 @@ gwkludge(void)
" entry \"%s\"", dname, lptr);
continue;
}
HTONL(dst); /* make network # into IP address */
} else {
msglog("bad \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"", lptr);
@ -333,12 +350,14 @@ gwkludge(void)
trace_if("Add", ifp);
}
(void)fclose(fp);
}
/* strtok(), but honoring backslash
*/
static int /* -1=bad */
static int /* 0=ok, -1=bad */
parse_quote(char **linep,
char *delims,
char *delimp,
@ -352,9 +371,7 @@ parse_quote(char **linep,
if (*pc == '\0')
return -1;
for (;;) {
if (lim == 0)
return -1;
while (lim != 0) {
c = *pc++;
if (c == '\0')
break;
@ -388,11 +405,13 @@ parse_quote(char **linep,
--lim;
}
exit:
if (lim == 0)
return -1;
*buf = '\0';
if (delimp != 0)
*delimp = c;
*linep = pc-1;
if (lim != 0)
*buf = '\0';
return 0;
}
@ -413,7 +432,7 @@ parse_ts(time_t *tp,
buf,bufsize)
|| buf[bufsize-1] != '\0'
|| buf[bufsize-2] != '\0') {
sprintf(buf,"timestamp %.25s", val0);
sprintf(buf,"bad timestamp %.25s", val0);
return buf;
}
strcat(buf,"\n");
@ -421,14 +440,14 @@ parse_ts(time_t *tp,
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);
sprintf(buf,"bad timestamp %.25s", val0);
return buf;
}
if (tm.tm_year <= 37)
tm.tm_year += 100;
if ((*tp = mktime(&tm)) == -1) {
sprintf(buf,"timestamp %.25s", val0);
sprintf(buf,"bad timestamp %.25s", val0);
return buf;
}
@ -436,92 +455,93 @@ parse_ts(time_t *tp,
}
/* 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|...
/* Get a password, key ID, and expiration date in the format
* passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min
*/
static char * /* 0 or error message */
get_passwds(char *tgt,
char *val,
struct parm *parmp,
u_char type)
get_passwd(char *tgt,
char *val,
struct parm *parmp,
u_char type,
int safe) /* 1=from secure file */
{
static char buf[80];
char *val0, *p, delim;
struct auth_key *akp, *akp2;
struct auth k, *ap, *ap2;
int i;
u_long l;
if (parmp->parm_auth.type != RIP_AUTH_NONE)
return "duplicate authentication";
parmp->parm_auth.type = type;
if (!safe)
return "unsafe password";
bzero(buf, sizeof(buf));
for (ap = parmp->parm_auth, i = 0;
ap->type != RIP_AUTH_NONE; i++, ap++) {
if (i >= MAX_AUTH_KEYS)
return "too many passwords";
}
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;
bzero(&k, sizeof(k));
k.type = type;
k.end = -1-DAY;
akp->end = -1;
val0 = val;
if (0 > parse_quote(&val, "| ,\n\r", &delim,
(char *)k.key, sizeof(k.key)))
return tgt;
if (delim != '|') {
if (type == RIP_AUTH_MD5)
return "missing Keyid";
break;
}
if (delim != '|') {
if (type == RIP_AUTH_MD5)
return "missing Keyid";
} else {
val0 = ++val;
buf[sizeof(buf)-1] = '\0';
if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf))
|| buf[sizeof(buf)-1] != '\0'
|| (l = strtoul(buf,&p,0)) > 255
|| *p != '\0') {
sprintf(buf,"KeyID \"%.20s\"", val0);
sprintf(buf,"bad KeyID \"%.20s\"", val0);
return buf;
}
for (akp2 = parmp->parm_auth.keys; akp2 < akp; akp2++) {
if (akp2->keyid == l) {
*val = '\0';
for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) {
if (ap2->keyid == l) {
sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
return buf;
}
}
akp->keyid = (int)l;
k.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 == '|') {
val0 = ++val;
if (0 != (p = parse_ts(&k.start,&val,val0,&delim,
buf,sizeof(buf))))
return p;
if (delim != '|')
return "missing second timestamp";
val0 = ++val;
if (0 != (p = parse_ts(&k.end,&val,val0,&delim,
buf,sizeof(buf))))
return p;
if ((u_long)k.start > (u_long)k.end) {
sprintf(buf,"out of order timestamp %.30s",
val0);
return buf;
}
}
if (delim != '|')
break;
}
if (delim != '\0')
return tgt;
return (delim != '\0') ? tgt : 0;
bcopy(&k, ap, sizeof(*ap));
return 0;
}
/* Parse a set of parameters for an interface.
*/
char * /* 0 or error message */
parse_parms(char *line)
parse_parms(char *line,
int safe) /* 1=from secure file */
{
#define PARS(str) (!strcasecmp(tgt, str))
#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str)))
@ -554,6 +574,7 @@ parse_parms(char *line)
free(intnetp);
return line;
}
HTONL(intnetp->intnet_addr);
intnetp->intnet_next = intnets;
intnets = intnetp;
return 0;
@ -591,7 +612,7 @@ parse_parms(char *line)
* The parm_net stuff is needed to allow several
* -F settings.
*/
if (!getnet(val, &addr, &mask)
if (!getnet(val0, &addr, &mask)
|| parm.parm_name[0] != '\0')
return tgt;
parm.parm_net = addr;
@ -599,14 +620,21 @@ parse_parms(char *line)
parm.parm_name[0] = '\n';
} else if (PARSEQ("passwd")) {
tgt = get_passwds(tgt, val0, &parm, RIP_AUTH_PW);
if (tgt)
/* since cleartext passwords are so weak allow
* them anywhere
*/
tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
if (tgt) {
*val0 = '\0';
return tgt;
}
} else if (PARSEQ("md5_passwd")) {
tgt = get_passwds(tgt, val0, &parm, RIP_AUTH_MD5);
if (tgt)
tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
if (tgt) {
*val0 = '\0';
return tgt;
}
} else if (PARS("no_ag")) {
parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
@ -693,6 +721,9 @@ parse_parms(char *line)
tgates = tg;
parm.parm_int_state |= IS_DISTRUST;
} else if (PARS("redirect_ok")) {
parm.parm_int_state |= IS_REDIRECT_OK;
} else {
return tgt; /* error */
}
@ -708,16 +739,24 @@ parse_parms(char *line)
char * /* 0 or error message */
check_parms(struct parm *new)
{
struct parm *parmp;
struct parm *parmp, **parmpp;
int i, num_passwds;
/* set implicit values
*/
if (new->parm_int_state & IS_NO_ADV_IN)
new->parm_int_state |= IS_NO_SOL_OUT;
for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
if (new->parm_auth[i].type != RIP_AUTH_NONE)
num_passwds++;
}
/* compare with existing sets of parameters
*/
for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
for (parmpp = &parms;
(parmp = *parmpp) != 0;
parmpp = &parmp->parm_next) {
if (strcmp(new->parm_name, parmp->parm_name))
continue;
if (!on_net(htonl(parmp->parm_net),
@ -726,12 +765,12 @@ check_parms(struct parm *new)
parmp->parm_net, parmp->parm_mask))
continue;
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";
for (i = 0; i < MAX_AUTH_KEYS; i++) {
if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
num_passwds++;
}
if (num_passwds > MAX_AUTH_KEYS)
return "too many conflicting passwords";
if ((0 != (new->parm_int_state & GROUP_IS_SOL)
&& 0 != (parmp->parm_int_state & GROUP_IS_SOL)
@ -760,10 +799,12 @@ check_parms(struct parm *new)
}
}
/* link new entry on the so that when the entries are scanned,
* they affect the result in the order the operator specified.
*/
parmp = (struct parm*)malloc(sizeof(*parmp));
bcopy(new, parmp, sizeof(*parmp));
parmp->parm_next = parms;
parms = parmp;
*parmpp = parmp;
return 0;
}
@ -774,13 +815,13 @@ check_parms(struct parm *new)
*/
int /* 0=bad */
getnet(char *name,
naddr *netp, /* host byte order */
naddr *maskp)
naddr *netp, /* a network so host byte order */
naddr *maskp) /* masks are always in host order */
{
int i;
struct netent *np;
naddr mask;
struct in_addr in;
naddr mask; /* in host byte order */
struct in_addr in; /* a network and so host byte order */
char hname[MAXHOSTNAMELEN+1];
char *mname, *p;
@ -812,7 +853,7 @@ getnet(char *name,
/* we cannot use the interfaces here because we have not
* looked at them yet.
*/
mask = std_mask(in.s_addr);
mask = std_mask(htonl(in.s_addr));
if ((~mask & in.s_addr) != 0)
mask = HOST_MASK;
} else {

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.17 $"
#ident "$Revision: 1.19 $"
#include "defs.h"
#include <netinet/in_systm.h>
@ -127,7 +127,7 @@ trace_rdisc(char *act,
wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)];
for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) {
(void)fprintf(ftrace, "\t%s preference=%#x",
(void)fprintf(ftrace, "\t%s preference=%d",
naddr_ntoa(wp[0]), (int)ntohl(wp[1]));
wp += p->ad.icmp_ad_asize;
}
@ -689,6 +689,7 @@ send_rdisc(union ad_u *p,
switch (type) {
case 0: /* unicast */
default:
msg = "Send";
break;

View File

@ -514,11 +514,13 @@ 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
.It Cm passwd Ns \&= Ns Ar XXX1[|KeyID[start|stop]]
specifies a RIPv2 cleartext password that will be included on
all RIPv2 responses sent, and checked on all RIPv2 responses received.
Any blanks, tab characters, commas, or '#' or '|' characters in the
Any blanks, tab characters, commas, or '#', '|', or NULL characters in the
password must be escaped with a backslash (\\).
The common escape sequences \\n, \\r, \\t, \\b, and \\xxx have their
usual meanings.
The
.Cm KeyID
must be unique but is ignored for cleartext passwords.
@ -528,15 +530,21 @@ 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.
The valid password with the most future is used on output packets, unless
all passwords have expired, in which case the password that expired most
recently is used, or unless no passwords are valid yet, in which case
no password is output.
Incoming packets can carry any password that is valid, will
be valid within 24 hours, or that was valid within 24 hours.
.It Cm md5_passwd Ns \&= Ns Ar XXX1|KeyID[start|stop][XXX2...]
specifes one or more RIPv2 MD5 passwords.
.It Cm md5_passwd Ns \&= Ns Ar XXX1|KeyID[start|stop]
specifes a RIPv2 MD5 password.
Except that a
.Cm KeyID
is required, this keyword is the similar to
is required, this keyword is similar to
.Cm passwd .
To protect the secrets, this parameter setting is valid only in the
.Em /etc/gateways
file and only when that file is readable only by UID 0.
.It Cm no_ag
turns off aggregation of subnets in RIPv1 and RIPv2 responses.
.It Cm no_super_ag
@ -612,6 +620,10 @@ causes RIP packets from that router and other routers named in
other
.Cm trust_gateway
keywords to be accept, and packets from other routers to be ignored.
.It Cm redirect_ok
causes RIP to allow ICMP Redirect messages when the system is acting
as a router and forwarding packets.
Otherwise, ICMP Redirect messages are are overridden.
.El
.Pp
.Sh FILES

View File

@ -40,7 +40,7 @@
#ifdef __cplusplus
extern "C" {
#endif
#ident "$Revision: 1.10 $"
#ident "$Revision: 1.11 $"
/*
* Routing Information Protocol

View File

@ -22,7 +22,7 @@
* documentation and/or software.
*/
#ident "$Revision: 1.2 $"
#ident "$Revision: 1.3 $"
#ifdef sgi
#include <strings.h>

View File

@ -40,7 +40,7 @@ static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
static char rcsid[] = "$NetBSD$";
#endif
#ident "$Revision: 1.9 $"
#ident "$Revision: 1.10 $"
#include <sys/param.h>
#include <sys/protosw.h>

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.26 $"
#ident "$Revision: 1.28 $"
#include "defs.h"
@ -746,7 +746,7 @@ static struct khash {
#define KS_DELETED 0x100 /* already deleted */
time_t k_keep;
#define K_KEEP_LIM 30
time_t k_redirect_time;
time_t k_redirect_time; /* when redirected route 1st seen */
} *khash_bins[KHASH_SIZE];
@ -832,8 +832,7 @@ rtm_add(struct rt_msghdr *rtm,
} else if (INFO_MASK(info) != 0) {
mask = ntohl(S_ADDR(INFO_MASK(info)));
} else {
msglog("ignore %s without mask",
rtm_type_name(rtm->rtm_type));
msglog("ignore %s without mask", rtm_type_name(rtm->rtm_type));
return;
}
@ -860,20 +859,32 @@ rtm_add(struct rt_msghdr *rtm,
k->k_state |= KS_STATIC;
if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
if (supplier) {
if (INFO_AUTHOR(info) != 0
&& INFO_AUTHOR(info)->sa_family == AF_INET)
ifp = iflookup(S_ADDR(INFO_AUTHOR(info)));
else
ifp = 0;
if (supplier
&& (ifp == 0 || !(ifp->int_state & IS_REDIRECT_OK))) {
/* Routers are not supposed to listen to redirects,
* so delete it.
* so delete it if it came via an unknown interface
* or the interface does not have special permission.
*/
k->k_state &= ~KS_DYNAMIC;
k->k_state |= KS_DELETE;
LIM_SEC(need_kern, 0);
trace_act("mark redirected %s --> %s for deletion"
" since this is a router",
trace_act("mark for deletion redirected %s --> %s"
" via %s",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate));
naddr_ntoa(k->k_gate),
ifp ? ifp->int_name : "unknown interface");
} else {
k->k_state |= KS_DYNAMIC;
k->k_redirect_time = now.tv_sec;
trace_act("accept redirected %s --> %s via %s",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate),
ifp ? ifp->int_name : "unknown interface");
}
return;
}
@ -893,17 +904,10 @@ rtm_add(struct rt_msghdr *rtm,
* Find the interface toward the gateway.
*/
ifp = iflookup(k->k_gate);
if (ifp == 0) {
/* if there is no known interface,
* maybe there is a new interface
*/
ifinit();
ifp = iflookup(k->k_gate);
if (ifp == 0)
msglog("static route %s --> %s impossibly lacks ifp",
addrname(S_ADDR(INFO_DST(info)), mask, 0),
naddr_ntoa(k->k_gate));
}
if (ifp == 0)
msglog("static route %s --> %s impossibly lacks ifp",
addrname(S_ADDR(INFO_DST(info)), mask, 0),
naddr_ntoa(k->k_gate));
kern_check_static(k, ifp);
}
@ -917,8 +921,8 @@ rtm_lose(struct rt_msghdr *rtm,
{
if (INFO_GATE(info) == 0
|| INFO_GATE(info)->sa_family != AF_INET) {
msglog("ignore %s without gateway",
rtm_type_name(rtm->rtm_type));
trace_act("ignore %s without gateway",
rtm_type_name(rtm->rtm_type));
return;
}

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.14 $"
#ident "$Revision: 1.16 $"
#define RIPCMDS
#include "defs.h"
@ -53,11 +53,12 @@ static char rcsid[] = "$NetBSD$";
#define NRECORDS 50 /* size of circular trace buffer */
u_int tracelevel, new_tracelevel;
int tracelevel, new_tracelevel;
FILE *ftrace = stdout; /* output trace file */
static char *tracelevel_pat = "%s\n";
char savetracename[MAXPATHLEN+1];
static char *sigtrace_pat = "%s\n";
static char savetracename[MAXPATHLEN+1];
char inittracename[MAXPATHLEN+1];
int file_trace; /* 1=tracing to file, not stdout */
static void trace_dump(void);
@ -162,15 +163,15 @@ ts(time_t secs) {
* This assumes that 'now' is update once for each event, and
* that at least now.tv_usec changes.
*/
static struct timeval lastlog_time;
void
lastlog(void)
{
static struct timeval last;
if (last.tv_sec != now.tv_sec
|| last.tv_usec != now.tv_usec) {
if (lastlog_time.tv_sec != now.tv_sec
|| lastlog_time.tv_usec != now.tv_usec) {
(void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
last = now;
lastlog_time = now;
}
}
@ -198,15 +199,17 @@ trace_close(void)
fflush(stdout);
fflush(stderr);
if (ftrace != 0
&& savetracename[0] != '\0') {
if (ftrace != 0 && file_trace) {
if (ftrace != stdout)
fclose(ftrace);
ftrace = 0;
fd = open(_PATH_DEVNULL, O_RDWR);
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
(void)close(fd);
fclose(ftrace);
ftrace = 0;
}
lastlog_time.tv_sec = 0;
}
@ -231,7 +234,6 @@ trace_off(char *p, ...)
lastlog();
va_start(args, p);
vfprintf(ftrace, p, args);
fflush(ftrace);
}
trace_close();
@ -239,107 +241,11 @@ trace_off(char *p, ...)
}
void
trace_on(char *filename,
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
* debugging level and re-open the file in case it has been unlinked.
*/
if (filename[0] == '\0') {
if (tracelevel != 0) {
new_tracelevel++;
tracelevel_pat = "trace command: %s\n";
} else if (savetracename[0] == '\0') {
msglog("missing trace file name");
return;
}
filename = savetracename;
} else if (!strcmp(filename,"dump/../table")) {
trace_dump();
return;
} else {
if (stat(filename, &stbuf) >= 0
&& (stbuf.st_mode & S_IFMT) != S_IFREG) {
msglog("wrong type (%#x) of trace file \"%s\"",
stbuf.st_mode, filename);
return;
}
if (!initial
#ifdef _PATH_TRACE
&& (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)
|| strstr(filename,"../")
|| 0 > stat(_PATH_TRACE, &stbuf))
#endif
&& strcmp(filename, savetracename)) {
msglog("wrong directory for trace file \"%s\"",
filename);
return;
}
}
n_ftrace = fopen(filename, "a");
if (n_ftrace == 0) {
msglog("failed to open trace file \"%s\" %s",
filename, strerror(errno));
return;
}
tmsg("switch to trace file %s\n", filename);
trace_close();
if (filename != savetracename)
strncpy(savetracename, filename, sizeof(savetracename)-1);
ftrace = n_ftrace;
fflush(stdout);
fflush(stderr);
dup2(fileno(ftrace), STDOUT_FILENO);
dup2(fileno(ftrace), STDERR_FILENO);
if (new_tracelevel == 0)
new_tracelevel = 1;
old_tracelevel = tracelevel;
set_tracelevel(initial);
if (!initial && old_tracelevel == 0)
trace_dump();
}
/* ARGSUSED */
void
sigtrace_on(int s)
{
new_tracelevel++;
tracelevel_pat = "SIGUSR1: %s\n";
}
/* ARGSUSED */
void
sigtrace_off(int s)
{
new_tracelevel--;
tracelevel_pat = "SIGUSR2: %s\n";
}
/* Move to next higher level of tracing when -t option processed or
* SIGUSR1 is received. Successive levels are:
* actions
* actions + packets
* actions + packets + contents
/* log a change in tracing
*/
void
set_tracelevel(int initial)
tracelevel_msg(char *pat,
int dump) /* -1=no dump, 0=default, 1=force */
{
static char *off_msgs[MAX_TRACELEVEL] = {
"Tracing actions stopped",
@ -353,34 +259,165 @@ set_tracelevel(int initial)
"Tracing packet contents started",
"Tracing kernel changes started",
};
u_int old_tracelevel = tracelevel;
if (new_tracelevel > MAX_TRACELEVEL) {
if (new_tracelevel < 0)
new_tracelevel = 0;
else if (new_tracelevel > MAX_TRACELEVEL)
new_tracelevel = MAX_TRACELEVEL;
if (new_tracelevel == tracelevel) {
tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
if (new_tracelevel < tracelevel) {
if (new_tracelevel <= 0) {
trace_off(pat, off_msgs[0]);
} else do {
tmsg(pat, off_msgs[tracelevel]);
}
while (--tracelevel != new_tracelevel);
} else if (new_tracelevel > tracelevel) {
do {
tmsg(pat, on_msgs[tracelevel++]);
} while (tracelevel != new_tracelevel);
}
if (dump > 0
|| (dump == 0 && old_tracelevel == 0 && tracelevel != 0))
trace_dump();
}
void
set_tracefile(char *filename,
char *pat,
int dump) /* -1=no dump, 0=default, 1=force */
{
struct stat stbuf;
FILE *n_ftrace;
char *fn;
/* Allow a null filename to increase the level if the trace file
* is already open or if coming from a trusted source, such as
* a signal or the command line.
*/
if (filename == 0 || filename[0] == '\0') {
filename = 0;
if (ftrace == 0) {
if (inittracename[0] == '\0') {
msglog("missing trace file name");
return;
}
fn = inittracename;
} else {
fn = 0;
}
} else if (!strcmp(filename,"dump/../table")) {
trace_dump();
return;
} else {
/* Allow the file specified with "-T file" to be reopened,
* but require all other names specified over the net to
* match the official path. The path can specify a directory
* in which the file is to be created.
*/
if (strcmp(filename, inittracename)
#ifdef _PATH_TRACE
&& (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)
|| strstr(filename,"../")
|| 0 > stat(_PATH_TRACE, &stbuf))
#endif
) {
msglog("wrong trace file \"%s\"", filename);
return;
}
/* If the new tracefile exists, it must be a regular file.
*/
if (stat(filename, &stbuf) >= 0
&& (stbuf.st_mode & S_IFMT) != S_IFREG) {
msglog("wrong type (%#x) of trace file \"%s\"",
stbuf.st_mode, filename);
return;
}
fn = filename;
}
for (; new_tracelevel != tracelevel; tracelevel++) {
if (new_tracelevel < tracelevel) {
if (--tracelevel == 0)
trace_off(tracelevel_pat, off_msgs[0]);
else
tmsg(tracelevel_pat, off_msgs[tracelevel]);
} else {
if (ftrace == 0) {
if (savetracename[0] != '\0')
trace_on(savetracename, 1);
else
ftrace = stdout;
}
if (!initial || tracelevel+1 == new_tracelevel)
tmsg(tracelevel_pat, on_msgs[tracelevel]);
if (fn != 0) {
n_ftrace = fopen(fn, "a");
if (n_ftrace == 0) {
msglog("failed to open trace file \"%s\" %s",
fn, strerror(errno));
if (fn == inittracename)
inittracename[0] = '\0';
return;
}
tmsg("switch to trace file %s\n", fn);
file_trace = 1;
trace_close();
if (fn != savetracename)
strncpy(savetracename, fn, sizeof(savetracename)-1);
ftrace = n_ftrace;
fflush(stdout);
fflush(stderr);
dup2(fileno(ftrace), STDOUT_FILENO);
dup2(fileno(ftrace), STDERR_FILENO);
}
if (new_tracelevel == 0 || filename == 0)
new_tracelevel++;
tracelevel_msg(pat, dump != 0 ? dump : (filename != 0));
}
/* ARGSUSED */
void
sigtrace_on(int s)
{
new_tracelevel++;
sigtrace_pat = "SIGUSR1: %s\n";
}
/* ARGSUSED */
void
sigtrace_off(int s)
{
new_tracelevel--;
sigtrace_pat = "SIGUSR2: %s\n";
}
/* Set tracing after a signal.
*/
void
set_tracelevel(void)
{
if (new_tracelevel == tracelevel)
return;
/* If tracing entirely off, and there was no tracefile specified
* on the command line, then leave it off.
*/
if (new_tracelevel > tracelevel && ftrace == 0) {
if (savetracename[0] != '\0') {
set_tracefile(savetracename,sigtrace_pat,0);
} else if (inittracename[0] != '\0') {
set_tracefile(inittracename,sigtrace_pat,0);
} else {
new_tracelevel = 0;
return;
}
} else {
tracelevel_msg(sigtrace_pat, 0);
}
tracelevel_pat = "%s\n";
}
@ -454,6 +491,7 @@ static struct bits is_bits[] = {
{ IS_BROKE, IS_SICK, "BROKEN" },
{ IS_SICK, 0, "SICK" },
{ IS_DUP, 0, "DUPLICATE" },
{ IS_REDIRECT_OK, 0, "REDIRECT_OK" },
{ IS_NEED_NET_SYN, 0, "" },
{ IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
{ IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
@ -548,6 +586,32 @@ trace_pair(naddr dst,
}
static void
print_rts(struct rt_spare *rts,
int force_metric, /* -1=suppress, 0=default */
int force_ifp, /* -1=suppress, 0=default */
int force_router, /* -1=suppress, 0=default, 1=display */
int force_tag, /* -1=suppress, 0=default, 1=display */
int force_time) /* 0=suppress, 1=display */
{
if (force_metric >= 0)
(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
if (force_ifp >= 0)
(void)fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ?
"if?" : rts->rts_ifp->int_name));
if (force_router > 0
|| (force_router == 0 && rts->rts_router != rts->rts_gate))
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_router));
if (force_time > 0)
(void)fprintf(ftrace, "%s ", ts(rts->rts_time));
if (force_tag > 0
|| (force_tag == 0 && rts->rts_tag != 0))
(void)fprintf(ftrace, "tag=%#x ",
ntohs(rts->rts_tag));
}
void
trace_if(char *act,
struct interface *ifp)
@ -584,13 +648,22 @@ trace_upslot(struct rt_entry *rt,
u_short tag,
time_t new_time)
{
struct rt_spare new;
if (!TRACEACTIONS || ftrace == 0)
return;
if (rts->rts_gate == gate
&& rts->rts_router == router
&& rts->rts_metric == metric
&& rts->rts_tag == tag)
return;
new.rts_ifp = ifp;
new.rts_gate = gate;
new.rts_router = router;
new.rts_metric = metric;
new.rts_time = new_time;
new.rts_tag = tag;
lastlog();
if (rts->rts_gate != RIP_DEFAULT) {
@ -598,45 +671,32 @@ trace_upslot(struct rt_entry *rt,
rts - rt->rt_spares,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rts->rts_gate)));
if (rts->rts_gate != rts->rts_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_gate));
if (rts->rts_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
if (rts->rts_ifp != 0)
(void)fprintf(ftrace, "%s ",
rts->rts_ifp->int_name);
(void)fprintf(ftrace, "%s\n", ts(rts->rts_time));
print_rts(rts, 0,0,
rts->rts_gate != gate,
rts->rts_tag != tag,
rts != rt->rt_spares || AGE_RT(rt->rt_state,
rt->rt_ifp));
(void)fprintf(ftrace, " %19s%-16s ",
"",
(void)fprintf(ftrace, "\n %19s%-16s ", "",
gate != rts->rts_gate ? naddr_ntoa(gate) : "");
if (gate != router)
(void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
if (tag != rts->rts_tag)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
if (metric != rts->rts_metric)
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (ifp != rts->rts_ifp && ifp != 0 )
(void)fprintf(ftrace, "%s ", ifp->int_name);
(void)fprintf(ftrace, "%s\n",
new_time != rts->rts_time ? ts(new_time) : "");
print_rts(&new,
-(metric == rts->rts_metric),
-(ifp == rts->rts_ifp),
0,
rts->rts_tag != tag,
new_time != rts->rts_time && (rts != rt->rt_spares
|| AGE_RT(rt->rt_state,
ifp)));
} else {
(void)fprintf(ftrace, "Add #%d %-35s ",
rts - rt->rt_spares,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(gate)));
if (gate != router)
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
if (tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (ifp != 0)
(void)fprintf(ftrace, "%s ", ifp->int_name);
(void)fprintf(ftrace, "%s\n", ts(new_time));
print_rts(&new, 0,0,0,0,
rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp));
}
(void)fputc('\n',ftrace);
}
@ -701,6 +761,8 @@ trace_change(struct rt_entry *rt,
time_t new_time,
char *label)
{
struct rt_spare new;
if (ftrace == 0)
return;
@ -710,67 +772,51 @@ trace_change(struct rt_entry *rt,
&& rt->rt_state == state
&& rt->rt_tag == tag)
return;
new.rts_ifp = ifp;
new.rts_gate = gate;
new.rts_router = router;
new.rts_metric = metric;
new.rts_time = new_time;
new.rts_tag = tag;
lastlog();
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
(void)fprintf(ftrace, "%s %-35s ",
label,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rt->rt_gate)),
rt->rt_metric);
if (rt->rt_router != rt->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rt->rt_router));
if (rt->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
naddr_ntoa(rt->rt_gate)));
print_rts(rt->rt_spares,
0,0,0,0, AGE_RT(rt->rt_state, rt->rt_ifp));
trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
(void)fprintf(ftrace, "%s ",
rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name);
(void)fprintf(ftrace, "%s\n",
AGE_RT(rt->rt_state, rt->rt_ifp) ? ts(rt->rt_time) : "");
(void)fprintf(ftrace, "%*s %19s%-16s ",
(void)fprintf(ftrace, "\n%*s %19s%-16s ",
strlen(label), "", "",
rt->rt_gate != gate ? naddr_ntoa(gate) : "");
if (rt->rt_metric != metric)
(void)fprintf(ftrace, "metric=%-2d ", metric);
if (router != gate)
(void)fprintf(ftrace, "router=%s ", naddr_ntoa(router));
if (rt->rt_tag != tag)
(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
print_rts(&new,
-(metric == rt->rt_metric),
-(ifp == rt->rt_ifp),
0,
rt->rt_tag != tag,
rt->rt_time != new_time && AGE_RT(rt->rt_state,ifp));
if (rt->rt_state != state)
trace_bits(rs_bits, state, 1);
if (rt->rt_ifp != ifp)
(void)fprintf(ftrace, "%s ",
ifp != 0 ? ifp->int_name : "?");
(void)fprintf(ftrace, "%s\n",
((rt->rt_time == new_time || !AGE_RT(rt->rt_state, ifp))
? "" : ts(new_time)));
(void)fputc('\n',ftrace);
}
void
trace_add_del(char * action, struct rt_entry *rt)
{
u_int state = rt->rt_state;
if (ftrace == 0)
return;
lastlog();
(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
(void)fprintf(ftrace, "%s %-35s ",
action,
trace_pair(rt->rt_dst, rt->rt_mask,
naddr_ntoa(rt->rt_gate)),
rt->rt_metric);
if (rt->rt_router != rt->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rt->rt_router));
if (rt->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
trace_bits(rs_bits, state, 0);
(void)fprintf(ftrace, "%s ",
rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?");
(void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
naddr_ntoa(rt->rt_gate)));
print_rts(rt->rt_spares, 0,0,0,0,AGE_RT(rt->rt_state,rt->rt_ifp));
trace_bits(rs_bits, rt->rt_state, 0);
(void)fputc('\n',ftrace);
}
@ -781,42 +827,24 @@ walk_trace(struct radix_node *rn,
{
#define RT ((struct rt_entry *)rn)
struct rt_spare *rts;
int i, age;
int i, age = AGE_RT(RT->rt_state, RT->rt_ifp);
(void)fprintf(ftrace, " %-35s metric=%-2d ",
trace_pair(RT->rt_dst, RT->rt_mask,
naddr_ntoa(RT->rt_gate)),
RT->rt_metric);
if (RT->rt_router != RT->rt_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(RT->rt_router));
if (RT->rt_tag != 0)
(void)fprintf(ftrace, "tag=%#x ",
ntohs(RT->rt_tag));
(void)fprintf(ftrace, " %-35s ", trace_pair(RT->rt_dst, RT->rt_mask,
naddr_ntoa(RT->rt_gate)));
print_rts(&RT->rt_spares[0], 0,0,0,0,age);
trace_bits(rs_bits, RT->rt_state, 0);
(void)fprintf(ftrace, "%s ",
RT->rt_ifp == 0 ? "?" : RT->rt_ifp->int_name);
age = AGE_RT(RT->rt_state, RT->rt_ifp);
if (age)
(void)fprintf(ftrace, "%s", ts(RT->rt_time));
if (RT->rt_poison_time >= now_garbage
&& RT->rt_poison_metric < RT->rt_metric)
(void)fprintf(ftrace, "pm=%d@%s",
RT->rt_poison_metric,
ts(RT->rt_poison_time));
rts = &RT->rt_spares[1];
for (i = 1; i < NUM_SPARES; i++, rts++) {
if (rts->rts_metric != HOPCNT_INFINITY) {
(void)fprintf(ftrace,"\n #%d%15s%-16s metric=%-2d ",
i, "", naddr_ntoa(rts->rts_gate),
rts->rts_metric);
if (rts->rts_router != rts->rts_gate)
(void)fprintf(ftrace, "router=%s ",
naddr_ntoa(rts->rts_router));
if (rts->rts_tag != 0)
(void)fprintf(ftrace, "tag=%#x ",
ntohs(rts->rts_tag));
(void)fprintf(ftrace, "%s ",
(rts->rts_ifp == 0
? "?" : rts->rts_ifp->int_name));
if (age)
(void)fprintf(ftrace, "%s", ts(rts->rts_time));
if (rts->rts_gate != RIP_DEFAULT) {
(void)fprintf(ftrace,"\n #%d%15s%-16s ",
i, "", naddr_ntoa(rts->rts_gate));
print_rts(rts, 0,0,0,0,1);
}
}
(void)fputc('\n',ftrace);
@ -834,6 +862,7 @@ trace_dump(void)
return;
lastlog();
(void)fputs("current daemon state:\n", ftrace);
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next)
trace_if("", ifp);
(void)rn_walktree(rhead, walk_trace, 0);
@ -976,7 +1005,8 @@ trace_rip(char *dir1, char *dir2,
break;
case RIPCMD_TRACEON:
fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
fprintf(ftrace, "\tfile=\"%.*s\"\n", size-4,
msg->rip_tracefile);
break;
case RIPCMD_TRACEOFF: