Merge the 980602 RIPv2/Router Discovery routed. Fixes floods of host routes

generated when one of the interfaces on the network does not support
broadcast (e.g. HIPPI or ATM).

From Vern Schryver <vjs@rhyolite.com>
This commit is contained in:
thorpej 1998-06-02 18:02:55 +00:00
parent c296923d2f
commit 6d8ef4df7c
11 changed files with 1043 additions and 658 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: defs.h,v 1.15 1997/09/15 10:38:11 lukem Exp $ */
/* $NetBSD: defs.h,v 1.16 1998/06/02 18:02:55 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -80,6 +80,7 @@
#include <sys/sysctl.h>
#include <sys/socket.h>
#ifdef sgi
#define _USER_ROUTE_TREE
#include <net/radix.h>
#else
#include "radix.h"
@ -167,6 +168,9 @@ union pkt_buf {
struct rip rip;
};
#define GNAME_LEN 64 /* assumed=64 in parms.c */
/* bigger than IFNAMSIZ, with room for "external()" or "remote()" */
#define IF_NAME_LEN (GNAME_LEN+15)
/* No more routes than this, to protect ourself in case something goes
* whacko and starts broadcasting zillions of bogus routes.
@ -197,19 +201,21 @@ struct rt_entry {
char rts_metric;
u_short rts_tag;
time_t rts_time; /* timer to junk stale routes */
u_int rts_de_ag; /* de-aggregation level */
#define NUM_SPARES 4
} rt_spares[NUM_SPARES];
u_int rt_seqno; /* when last changed */
char rt_poison_metric; /* to notice maximum recently */
time_t rt_poison_time; /* advertised metric */
};
#define rt_dst rt_dst_sock.sin_addr.s_addr
#define rt_ifp rt_spares[0].rts_ifp
#define rt_gate rt_spares[0].rts_gate
#define rt_router rt_spares[0].rts_router
#define rt_metric rt_spares[0].rts_metric
#define rt_tag rt_spares[0].rts_tag
#define rt_time rt_spares[0].rts_time
#define rt_dst rt_dst_sock.sin_addr.s_addr
#define rt_ifp rt_spares[0].rts_ifp
#define rt_gate rt_spares[0].rts_gate
#define rt_router rt_spares[0].rts_router
#define rt_metric rt_spares[0].rts_metric
#define rt_tag rt_spares[0].rts_tag
#define rt_time rt_spares[0].rts_time
#define rt_de_ag rt_spares[0].rts_de_ag
#define HOST_MASK 0xffffffff
#define RT_ISHOST(rt) ((rt)->rt_mask == HOST_MASK)
@ -258,7 +264,7 @@ struct interface {
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 */
char int_name[IF_NAME_LEN+1];
u_short int_index;
naddr int_addr; /* address on this host (net order) */
naddr int_brdaddr; /* broadcast address (n) */
@ -294,7 +300,8 @@ struct interface {
u_char keyid;
time_t start, end;
} int_auth[MAX_AUTH_KEYS];
int int_rdisc_pref; /* advertised rdisc preference */
/* router discovery parameters */
int int_rdisc_pref; /* signed preference to advertise */
int int_rdisc_int; /* MaxAdvertiseInterval */
int int_rdisc_cnt;
struct timeval int_rdisc_timer;
@ -327,23 +334,19 @@ struct interface {
#define IS_NO_RIP (IS_NO_RIP_OUT | IS_NO_RIP_IN)
#define IS_RIP_OUT_OFF(s) (((s) & IS_NO_RIP_OUT) == IS_NO_RIP_OUT)
#define IS_RIP_OFF(s) (((s) & IS_NO_RIP) == IS_NO_RIP)
#define IS_NO_ADV_IN 0x0100000
#define IS_NO_SOL_OUT 0x0200000 /* no solicitations */
#define IS_SOL_OUT 0x0400000 /* send solicitations */
#define GROUP_IS_SOL (IS_NO_ADV_IN|IS_NO_SOL_OUT)
#define IS_NO_ADV_OUT 0x0800000 /* do not advertise rdisc */
#define IS_ADV_OUT 0x1000000 /* advertise rdisc */
#define GROUP_IS_ADV (IS_NO_ADV_OUT|IS_ADV_OUT)
#define IS_BCAST_RDISC 0x2000000 /* broadcast instead of multicast */
#define IS_NO_RIP_MCAST 0x0100000 /* broadcast RIPv2 */
#define IS_NO_ADV_IN 0x0200000 /* do not listen to advertisements */
#define IS_NO_SOL_OUT 0x0400000 /* send no solicitations */
#define IS_SOL_OUT 0x0800000 /* send solicitations */
#define GROUP_IS_SOL_OUT (IS_SOL_OUT | IS_NO_SOL_OUT)
#define IS_NO_ADV_OUT 0x1000000 /* do not advertise rdisc */
#define IS_ADV_OUT 0x2000000 /* advertise rdisc */
#define GROUP_IS_ADV_OUT (IS_NO_ADV_OUT | IS_ADV_OUT)
#define IS_BCAST_RDISC 0x4000000 /* broadcast instead of multicast */
#define IS_NO_RDISC (IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT)
#define IS_PM_RDISC 0x4000000 /* poor-man's router discovery */
#define IS_PM_RDISC 0x8000000 /* poor-man's router discovery */
#ifdef sgi
#define IFF_UP_RUNNING (IFF_RUNNING|IFF_UP)
#else
#define IFF_UP_RUNNING IFF_UP
#endif
#define iff_alive(f) (((f) & IFF_UP_RUNNING) == IFF_UP_RUNNING)
#define iff_up(f) ((f) & IFF_UP)
/* Information for aggregating routes */
@ -361,7 +364,7 @@ struct ag_info {
u_short ag_tag;
u_short ag_state;
#define AGS_SUPPRESS 0x001 /* combine with coaser mask */
#define AGS_PROMOTE 0x002 /* synthesize combined routes */
#define AGS_AGGREGATE 0x002 /* synthesize combined routes */
#define AGS_REDUN0 0x004 /* redundant, finer routes output */
#define AGS_REDUN1 0x008
#define AG_IS_REDUN(state) (((state) & (AGS_REDUN0 | AGS_REDUN1)) \
@ -376,37 +379,50 @@ struct ag_info {
#define AGS_SPLIT_HZ 0x200 /* suppress for split horizon */
/* some bits are set if they are set on either route */
#define AGS_PROMOTE_EITHER (AGS_RIPV2 | AGS_GATEWAY | \
AGS_SUPPRESS | AGS_CORS_GATE)
#define AGS_AGGREGATE_EITHER (AGS_RIPV2 | AGS_GATEWAY | \
AGS_SUPPRESS | AGS_CORS_GATE)
};
/* parameters for interfaces */
extern struct parm {
struct parm *parm_next;
char parm_name[IFNAMSIZ+1];
char parm_name[IF_NAME_LEN+1];
naddr parm_net;
naddr parm_mask;
char parm_d_metric;
u_int parm_int_state;
int parm_rdisc_pref;
int parm_rdisc_int;
int parm_rdisc_pref; /* signed IRDP preference */
int parm_rdisc_int; /* IRDP advertising internval */
struct auth parm_auth[MAX_AUTH_KEYS];
} *parms;
/* authority for internal networks */
extern struct intnet {
struct intnet *intnet_next;
naddr intnet_addr;
naddr intnet_addr; /* network byte order */
naddr intnet_mask;
char intnet_metric;
} *intnets;
/* defined RIPv1 netmasks */
extern struct r1net {
struct r1net *r1net_next;
naddr r1net_net; /* host order */
naddr r1net_match;
naddr r1net_mask;
} *r1nets;
/* trusted routers */
extern struct tgate {
struct tgate *tgate_next;
naddr tgate_addr;
#define MAX_TGATE_NETS 32
struct tgate_net {
naddr net; /* host order */
naddr mask;
} tgate_nets[MAX_TGATE_NETS];
} *tgates;
enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST,
@ -435,8 +451,8 @@ extern int rdisc_sock; /* router-discovery raw socket */
extern int seqno; /* sequence number for messages */
extern int supplier; /* process should supply updates */
extern int lookforinterfaces; /* 1=probe for new up interfaces */
extern int supplier_set; /* -s or -q requested */
extern int lookforinterfaces; /* 1=probe for new up interfaces */
extern int ridhosts; /* 1=reduce host routes */
extern int mhome; /* 1=want multi-homed host route */
extern int advertise_mhome; /* 1=must continue adverising it */
@ -453,7 +469,7 @@ extern struct timeval next_bcast; /* next general broadcast */
extern struct timeval age_timer; /* next check of old routes */
extern struct timeval no_flash; /* inhibit flash update until then */
extern struct timeval rdisc_timer; /* next advert. or solicitation */
extern int rdisc_ok; /* using solicited route */
extern int rdisc_ok; /* using solicted route */
extern struct timeval ifinit_timer; /* time to check interfaces */
@ -531,21 +547,21 @@ extern char *check_parms(struct parm *);
extern void get_parms(struct interface *);
extern void lastlog(void);
extern void trace_close(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 trace_kernel(char *, ...);
extern void trace_misc(char *, ...);
extern void trace_act(char *, ...);
extern void trace_pkt(char *, ...);
extern void trace_add_del(char *, struct rt_entry *);
extern void trace_change(struct rt_entry *, u_int, naddr, naddr, int,
u_short, struct interface *, time_t, char *);
extern void trace_change(struct rt_entry *, u_int, struct rt_spare *,
char *);
extern void trace_if(char *, struct interface *);
extern void trace_upslot(struct rt_entry *, struct rt_spare *,
naddr, naddr,
struct interface *, int, u_short, time_t);
struct rt_spare *);
extern void trace_rip(char*, char*, struct sockaddr_in *,
struct interface *, struct rip *, int);
extern char *addrname(naddr, naddr, int);
@ -574,15 +590,13 @@ extern void age(naddr);
extern void ag_flush(naddr, naddr, void (*)(struct ag_info *));
extern void ag_check(naddr, naddr, naddr, naddr, char, char, u_int,
u_short, u_short, void (*)(struct ag_info *));
extern void del_static(naddr, naddr, int);
extern void del_static(naddr, naddr, naddr, int);
extern void del_redirects(naddr, time_t);
extern struct rt_entry *rtget(naddr, naddr);
extern struct rt_entry *rtfind(naddr);
extern void rtinit(void);
extern void rtadd(naddr, naddr, naddr, naddr,
int, u_short, u_int, struct interface *);
extern void rtchange(struct rt_entry *, u_int, naddr,naddr, int, u_short,
struct interface *ifp, time_t, char *);
extern void rtadd(naddr, naddr, u_int, struct rt_spare *);
extern void rtchange(struct rt_entry *, u_int, struct rt_spare *, char *);
extern void rtdelete(struct rt_entry *);
extern void rts_delete(struct rt_entry *, struct rt_spare *);
extern void rtbad_sub(struct rt_entry *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.c,v 1.13 1997/09/15 11:51:54 lukem Exp $ */
/* $NetBSD: if.c,v 1.14 1998/06/02 18:02:55 thorpej Exp $ */
/*
* Copyright (c) 1983, 1993
@ -37,7 +37,7 @@
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: if.c,v 1.13 1997/09/15 11:51:54 lukem Exp $");
__RCSID("$NetBSD: if.c,v 1.14 1998/06/02 18:02:55 thorpej Exp $");
#endif
#include "defs.h"
@ -71,9 +71,13 @@ int tot_interfaces; /* # of remote and local interfaces */
int rip_interfaces; /* # of interfaces doing RIP */
int foundloopback; /* valid flag for loopaddr */
naddr loopaddr; /* our address on loopback */
struct rt_spare loop_rts;
struct timeval ifinit_timer;
static struct timeval last_ifinit;
#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \
&& last_ifinit.tv_usec == now.tv_usec \
&& timercmp(&ifinit_timer, &now, >))
int have_ripv1_out; /* have a RIPv1 interface */
int have_ripv1_in;
@ -201,8 +205,7 @@ ifwithname(char *name, /* "ec0" or whatever */
/* If there is no known interface, maybe there is a
* new interface. So just once look for new interfaces.
*/
if (last_ifinit.tv_sec == now.tv_sec
&& last_ifinit.tv_usec == now.tv_usec)
if (IF_RESCAN_DELAY())
return 0;
ifinit();
}
@ -225,8 +228,7 @@ ifwithindex(u_short index,
* new interface. So just once look for new interfaces.
*/
if (!rescan_ok
|| (last_ifinit.tv_sec == now.tv_sec
&& last_ifinit.tv_usec == now.tv_usec))
|| IF_RESCAN_DELAY())
return 0;
ifinit();
}
@ -265,8 +267,7 @@ iflookup(naddr addr)
}
if (maybe != 0
|| (last_ifinit.tv_sec == now.tv_sec
&& last_ifinit.tv_usec == now.tv_usec))
|| IF_RESCAN_DELAY())
return maybe;
/* If there is no known interface, maybe there is a
@ -302,12 +303,13 @@ naddr
ripv1_mask_net(naddr addr, /* in network byte order */
struct interface *ifp) /* as seen on this interface */
{
struct r1net *r1p;
naddr mask = 0;
if (addr == 0) /* default always has 0 mask */
return mask;
if (ifp != 0) {
if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) {
/* If the target network is that of the associated interface
* on which it arrived, then use the netmask of the interface.
*/
@ -323,15 +325,26 @@ ripv1_mask_net(naddr addr, /* in network byte order */
*/
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (on_net(addr, ifp->int_std_net, ifp->int_std_mask)
&& ifp->int_ripv1_mask > mask)
&& ifp->int_ripv1_mask > mask
&& ifp->int_ripv1_mask != HOST_MASK)
mask = ifp->int_ripv1_mask;
}
}
/* Otherwise, make the classic A/B/C guess.
*/
if (mask == 0)
mask = std_mask(addr);
/* check special definitions */
if (mask == 0) {
for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) {
if (on_net(addr, r1p->r1net_net, r1p->r1net_match)
&& r1p->r1net_mask > mask)
r1p->r1net_mask = mask;
}
/* Otherwise, make the classic A/B/C guess.
*/
if (mask == 0)
mask = std_mask(addr);
}
return mask;
}
@ -386,7 +399,7 @@ check_dup(naddr addr, /* IP address, so network byte order */
if (ifp->int_mask != mask)
continue;
if (!iff_alive(ifp->int_if_flags))
if (!iff_up(ifp->int_if_flags))
continue;
/* The local address can only be shared with a point-to-point
@ -507,8 +520,8 @@ ifdel(struct interface *ifp)
rip_interfaces--;
/* Zap all routes associated with this interface.
* Assume routes just using gateways beyond this interface will
* timeout naturally, and have probably already died.
* Assume routes just using gateways beyond this interface
* will timeout naturally, and have probably already died.
*/
(void)rn_walktree(rhead, walk_bad, 0);
@ -551,7 +564,7 @@ if_bad(struct interface *ifp)
ifp->int_state |= (IS_BROKE | IS_SICK);
ifp->int_act_time = NEVER;
ifp->int_query_time = NEVER;
ifp->int_data.ts = 0;
ifp->int_data.ts = now.tv_sec;
trace_if("Chg", ifp);
@ -704,14 +717,16 @@ ifinit(void)
if ((needed = sysctl_buf_size) != 0) {
if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0)
break;
/* retry if the table grew */
if (errno != ENOMEM && errno != EFAULT)
BADERR(1, "ifinit: get interface table");
BADERR(1, "ifinit: sysctl(RT_IFLIST)");
free(sysctl_buf);
needed = 0;
}
if (sysctl(mib, 6, 0, &needed, 0, 0) < 0)
BADERR(1,"ifinit: route-sysctl-estimate");
sysctl_buf = rtmalloc(sysctl_buf_size = needed, "ifinit");
BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate");
sysctl_buf = rtmalloc(sysctl_buf_size = needed,
"ifinit sysctl");
}
ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed);
@ -761,10 +776,10 @@ ifinit(void)
* Do not output RIP or Router-Discovery packets via aliases.
*/
memmove(&ifs, &ifs0, sizeof(ifs));
ifs0.int_state |= (IS_ALIAS | IS_NO_RIP | IS_NO_RDISC);
ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC);
if (INFO_IFA(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOADDR))
msglog("%s has no address",
ifs.int_name);
@ -773,7 +788,7 @@ ifinit(void)
continue;
}
if (INFO_IFA(&info)->sa_family != AF_INET) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOT_INET))
trace_act("%s: not AF_INET",
ifs.int_name);
@ -786,7 +801,7 @@ ifinit(void)
if (ntohl(ifs.int_addr)>>24 == 0
|| ntohl(ifs.int_addr)>>24 == 0xff) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_BADADDR))
msglog("%s has a bad address",
ifs.int_name);
@ -805,12 +820,14 @@ ifinit(void)
if (!foundloopback) {
foundloopback = 1;
loopaddr = ifs.int_addr;
loop_rts.rts_gate = loopaddr;
loop_rts.rts_router = loopaddr;
}
} else if (ifs.int_if_flags & IFF_POINTOPOINT) {
if (INFO_BRD(&info) == 0
|| INFO_BRD(&info)->sa_family != AF_INET) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NODST))
msglog("%s has a bad"
" destination address",
@ -822,7 +839,7 @@ ifinit(void)
ifs.int_dstaddr = S_ADDR(INFO_BRD(&info));
if (ntohl(ifs.int_dstaddr)>>24 == 0
|| ntohl(ifs.int_dstaddr)>>24 == 0xff) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NODST))
msglog("%s has a bad"
" destination address",
@ -838,7 +855,7 @@ ifinit(void)
} else {
if (INFO_MASK(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints & COMP_NOMASK))
msglog("%s has no netmask",
ifs.int_name);
@ -856,7 +873,7 @@ ifinit(void)
if (ifs.int_if_flags & IFF_BROADCAST) {
if (INFO_BRD(&info) == 0) {
if (iff_alive(ifs.int_if_flags)) {
if (iff_up(ifs.int_if_flags)) {
if (!(prev_complaints
& COMP_NOBADR))
msglog("%s has"
@ -893,7 +910,7 @@ ifinit(void)
if (ifs.int_metric > HOPCNT_INFINITY) {
ifs.int_metric = 0;
if (!(prev_complaints & COMP_BAD_METRIC)
&& iff_alive(ifs.int_if_flags)) {
&& iff_up(ifs.int_if_flags)) {
complaints |= COMP_BAD_METRIC;
msglog("%s has a metric of %d",
ifs.int_name, ifs.int_metric);
@ -942,19 +959,26 @@ ifinit(void)
/* note interfaces that have been turned off
*/
if (!iff_alive(ifs.int_if_flags)) {
if (iff_alive(ifp->int_if_flags)) {
if (!iff_up(ifs.int_if_flags)) {
if (iff_up(ifp->int_if_flags)) {
msglog("interface %s to %s turned off",
ifp->int_name,
naddr_ntoa(ifp->int_dstaddr));
if_bad(ifp);
ifp->int_if_flags &= ~IFF_UP_RUNNING;
ifp->int_if_flags &= ~IFF_UP;
} else if (now.tv_sec>(ifp->int_data.ts
+ CHECK_BAD_INTERVAL)) {
trace_act("interface %s has been off"
" %d seconds; forget it",
ifp->int_name,
now.tv_sec-ifp->int_data.ts);
ifdel(ifp);
}
continue;
}
/* or that were off and are now ok */
if (!iff_alive(ifp->int_if_flags)) {
ifp->int_if_flags |= IFF_UP_RUNNING;
if (!iff_up(ifp->int_if_flags)) {
ifp->int_if_flags |= IFF_UP;
(void)if_ok(ifp, "");
}
@ -1036,7 +1060,7 @@ ifinit(void)
/* This is a new interface.
* If it is dead, forget it.
*/
if (!iff_alive(ifs.int_if_flags))
if (!iff_up(ifs.int_if_flags))
continue;
/* If it duplicates an existing interface,
@ -1085,7 +1109,7 @@ ifinit(void)
/* It is new and ok. Add it to the list of interfaces
*/
ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit");
ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp");
memmove(ifp, &ifs, sizeof(*ifp));
get_parms(ifp);
if_link(ifp);
@ -1156,14 +1180,18 @@ ifinit(void)
rtdelete(rt);
rt = 0;
} else {
loop_rts.rts_ifp = ifp;
loop_rts.rts_metric = 0;
loop_rts.rts_time = rt->rt_time;
rtchange(rt, rt->rt_state | RS_MHOME,
loopaddr, loopaddr,
0, 0, ifp, rt->rt_time, 0);
&loop_rts, 0);
}
}
if (rt == 0)
rtadd(myaddr, HOST_MASK, loopaddr, loopaddr,
0, 0, RS_MHOME, ifp);
if (rt == 0) {
loop_rts.rts_ifp = ifp;
loop_rts.rts_metric = 0;
rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts);
}
}
for (ifp = ifnet; ifp != 0; ifp = ifp1) {
@ -1208,7 +1236,7 @@ ifinit(void)
/* Delete any routes to the network address through
* foreign routers. Remove even static routes.
*/
del_static(ifp->int_addr, HOST_MASK, 0);
del_static(ifp->int_addr, HOST_MASK, 0, 0);
rt = rtget(ifp->int_addr, HOST_MASK);
if (rt != 0 && rt->rt_router != loopaddr) {
rtdelete(rt);
@ -1221,14 +1249,17 @@ ifinit(void)
} else {
ifp1 = rt->rt_ifp;
}
rtchange(rt,((rt->rt_state & ~RS_NET_SYN)
| (RS_IF|RS_LOCAL)),
loopaddr, loopaddr,
0, 0, ifp1, rt->rt_time, 0);
loop_rts.rts_ifp = ifp1;
loop_rts.rts_metric = 0;
loop_rts.rts_time = rt->rt_time;
rtchange(rt, ((rt->rt_state & ~RS_NET_SYN)
| (RS_IF|RS_LOCAL)),
&loop_rts, 0);
} else {
loop_rts.rts_ifp = ifp;
loop_rts.rts_metric = 0;
rtadd(ifp->int_addr, HOST_MASK,
loopaddr, loopaddr,
0, 0, (RS_IF | RS_LOCAL), ifp);
(RS_IF | RS_LOCAL), &loop_rts);
}
}
}
@ -1242,10 +1273,12 @@ ifinit(void)
rtdelete(rt);
rt = 0;
}
if (rt == 0)
if (rt == 0) {
loop_rts.rts_ifp = 0;
loop_rts.rts_metric = intnetp->intnet_metric-1;
rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
loopaddr, loopaddr, intnetp->intnet_metric-1,
0, RS_NET_SYN | RS_NET_INT, 0);
RS_NET_SYN | RS_NET_INT, &loop_rts);
}
}
prev_complaints = complaints;
@ -1256,6 +1289,7 @@ static void
check_net_syn(struct interface *ifp)
{
struct rt_entry *rt;
static struct rt_spare new;
/* Turn on the need to automatically synthesize a network route
@ -1272,10 +1306,14 @@ check_net_syn(struct interface *ifp)
rtdelete(rt);
rt = 0;
}
if (rt == 0)
if (rt == 0) {
new.rts_ifp = ifp;
new.rts_gate = ifp->int_addr;
new.rts_router = ifp->int_addr;
new.rts_metric = ifp->int_metric;
rtadd(ifp->int_std_addr, ifp->int_std_mask,
ifp->int_addr, ifp->int_addr,
ifp->int_metric, 0, RS_NET_SYN, ifp);
RS_NET_SYN, &new);
}
} else {
ifp->int_state &= ~IS_NEED_NET_SYN;
@ -1298,7 +1336,8 @@ int /* 0=bad interface */
addrouteforif(struct interface *ifp)
{
struct rt_entry *rt;
naddr dst, gate;
static struct rt_spare new;
naddr dst;
/* skip sick interfaces
@ -1312,11 +1351,16 @@ addrouteforif(struct interface *ifp)
if (ifp->int_state & IS_SUBNET)
check_net_syn(ifp);
gate = ifp->int_addr;
dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))
? ifp->int_dstaddr
: htonl(ifp->int_net));
new.rts_ifp = ifp;
new.rts_router = ifp->int_addr;
new.rts_gate = ifp->int_addr;
new.rts_metric = ifp->int_metric;
new.rts_time = now.tv_sec;
/* If we are going to send packets to the gateway,
* it must be reachable using our physical interfaces
*/
@ -1329,7 +1373,7 @@ addrouteforif(struct interface *ifp)
* The right route must be for the right interface, not synthesized
* from a subnet, be a "gateway" or not as appropriate, and so forth.
*/
del_static(dst, ifp->int_mask, 0);
del_static(dst, ifp->int_mask, 0, 0);
rt = rtget(dst, ifp->int_mask);
if (rt != 0) {
if ((rt->rt_ifp != ifp
@ -1342,8 +1386,7 @@ addrouteforif(struct interface *ifp)
} else {
rtchange(rt, ((rt->rt_state | RS_IF)
& ~(RS_NET_SYN | RS_LOCAL)),
ifp->int_addr, ifp->int_addr,
ifp->int_metric, 0, ifp, now.tv_sec, 0);
&new, 0);
}
}
if (rt == 0) {
@ -1351,8 +1394,7 @@ addrouteforif(struct interface *ifp)
trace_act("re-install interface %s",
ifp->int_name);
rtadd(dst, ifp->int_mask, gate, gate,
ifp->int_metric, 0, RS_IF, ifp);
rtadd(dst, ifp->int_mask, RS_IF, &new);
}
return 1;

View File

@ -1,4 +1,4 @@
/* $NetBSD: input.c,v 1.21 1997/09/15 11:51:56 lukem Exp $ */
/* $NetBSD: input.c,v 1.22 1998/06/02 18:02:55 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -37,15 +37,14 @@
static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: input.c,v 1.21 1997/09/15 11:51:56 lukem Exp $");
__RCSID("$NetBSD: input.c,v 1.22 1998/06/02 18:02:55 thorpej Exp $");
#endif
#include "defs.h"
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 void input_route(naddr, naddr, struct rt_spare *, struct netinfo *);
static int ck_passwd(struct interface *, struct rip *, void *,
naddr, struct msg_limit *);
@ -142,14 +141,17 @@ input(struct sockaddr_in *from, /* received from this IP address */
{
# define FROM_NADDR from->sin_addr.s_addr
static struct msg_limit use_auth, bad_len, bad_mask;
static struct msg_limit unk_router, bad_router, bad_nhop;
static struct msg_limit unk_router, bad_router, bad_nhop;
struct rt_entry *rt;
struct rt_spare new;
struct netinfo *n, *lim;
struct interface *ifp1;
naddr gate, mask, v1_mask, dst, ddst_h = 0;
struct auth *ap;
int i;
struct tgate *tg = 0;
struct tgate_net *tn;
int i, j;
/* Notice when we hear from a remote gateway
*/
@ -284,10 +286,10 @@ input(struct sockaddr_in *from, /* received from this IP address */
*/
if (n->n_family == RIP_AF_UNSPEC
&& n->n_metric == HOPCNT_INFINITY) {
/* Answer a query from a utility program
* with all we know.
*/
if (from->sin_port != htons(RIP_PORT)) {
/* Answer a query from a utility
* program with all we know.
*/
supply(from, aifp, OUT_QUERY, 0,
rip->rip_vers, ap != 0);
return;
@ -299,11 +301,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
*
* Only answer a router if we are a supplier
* to keep an unwary host that is just starting
* from picking us as a router. Respond with
* RIPv1 instead of RIPv2 if that is what we
* are broadcasting on the interface to keep
* the remote router from getting the wrong
* initial idea of the routes we send.
* from picking us as a router.
*/
if (aifp == 0) {
trace_pkt("ignore distant router");
@ -315,8 +313,36 @@ input(struct sockaddr_in *from, /* received from this IP address */
return;
}
/* Do not answer a RIPv1 router if
* we are sending RIPv2. But do offer
* poor man's router discovery.
*/
if ((aifp->int_state & IS_NO_RIPV1_OUT)
&& rip->rip_vers == RIPv1) {
if (!(aifp->int_state & IS_PM_RDISC)) {
trace_pkt("ignore; sending RIPv2");
return;
}
v12buf.n->n_family = RIP_AF_INET;
v12buf.n->n_dst = RIP_DEFAULT;
i = aifp->int_d_metric;
if (0 != (rt = rtget(RIP_DEFAULT, 0)))
i = MIN(i, (rt->rt_metric
+aifp->int_metric+1));
v12buf.n->n_metric = htonl(i);
v12buf.n++;
break;
}
/* Respond with RIPv1 instead of RIPv2 if
* that is what we are broadcasting on the
* interface to keep the remote router from
* getting the wrong initial idea of the
* routes we send.
*/
supply(from, aifp, OUT_UNICAST, 0,
(aifp->int_state&IS_NO_RIPV1_OUT)
(aifp->int_state & IS_NO_RIPV1_OUT)
? RIPv2 : RIPv1,
ap != 0);
return;
@ -328,8 +354,8 @@ input(struct sockaddr_in *from, /* received from this IP address */
if (n->n_family != RIP_AF_INET) {
msglim(&bad_router, FROM_NADDR,
"request from %s for unsupported (af"
" %d) %s",
"request from %s for unsupported"
" (af %d) %s",
naddr_ntoa(FROM_NADDR),
ntohs(n->n_family),
naddr_ntoa(n->n_dst));
@ -513,7 +539,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
/* Ignore routes via dead interface.
*/
if (aifp->int_state & IS_BROKE) {
trace_pkt("%sdiscard response via broken interface %s",
trace_pkt("discard response via broken interface %s",
aifp->int_name);
return;
}
@ -523,7 +549,7 @@ input(struct sockaddr_in *from, /* received from this IP address */
* happens, it happens frequently.
*/
if (aifp->int_state & IS_DISTRUST) {
struct tgate *tg = tgates;
tg = tgates;
while (tg->tgate_addr != FROM_NADDR) {
tg = tg->tgate_next;
if (tg == 0) {
@ -624,6 +650,20 @@ input(struct sockaddr_in *from, /* received from this IP address */
if (n->n_metric > HOPCNT_INFINITY)
n->n_metric = HOPCNT_INFINITY;
/* Should we trust this route from this router? */
if (tg && (tn = tg->tgate_nets)->mask != 0) {
for (i = 0; i < MAX_TGATE_NETS; i++, tn++) {
if (on_net(dst, tn->net, tn->mask)
&& tn->mask <= mask)
break;
}
if (i >= MAX_TGATE_NETS || tn->mask == 0) {
trace_pkt(" ignored unauthorized %s",
addrname(dst,mask,0));
continue;
}
}
/* Recognize and ignore a default route we faked
* which is being sent back to us by a machine with
* broken split-horizon.
@ -665,13 +705,12 @@ input(struct sockaddr_in *from, /* received from this IP address */
/* Punt if we would have to generate
* an unreasonable number of routes.
*/
#ifdef DEBUG
msglog("accept %s from %s as 1"
" instead of %d routes",
addrname(dst,mask,0),
naddr_ntoa(FROM_NADDR),
i+1);
#endif
if (TRACECONTENTS)
trace_misc("accept %s-->%s as 1"
" instead of %d routes",
addrname(dst,mask,0),
naddr_ntoa(FROM_NADDR),
i+1);
i = 0;
} else {
mask = v1_mask;
@ -680,10 +719,17 @@ input(struct sockaddr_in *from, /* received from this IP address */
i = 0;
}
new.rts_gate = gate;
new.rts_router = FROM_NADDR;
new.rts_metric = n->n_metric;
new.rts_tag = n->n_tag;
new.rts_time = now.tv_sec;
new.rts_ifp = aifp;
new.rts_de_ag = i;
j = 0;
for (;;) {
input_route(aifp, FROM_NADDR,
dst, mask, gate, n);
if (i-- == 0)
input_route(dst, mask, &new, n);
if (++j > i)
break;
dst = htonl(ntohl(dst) + ddst_h);
}
@ -697,18 +743,15 @@ input(struct sockaddr_in *from, /* received from this IP address */
/* Process a single input route.
*/
static void
input_route(struct interface *ifp,
naddr from,
naddr dst,
input_route(naddr dst, /* network order */
naddr mask,
naddr gate,
struct rt_spare *new,
struct netinfo *n)
{
int i;
struct rt_entry *rt;
struct rt_spare *rts, *rts0;
struct interface *ifp1;
time_t new_time;
/* See if the other guy is telling us to send our packets to him.
@ -732,7 +775,7 @@ input_route(struct interface *ifp,
if (rt == 0) {
/* Ignore unknown routes being poisoned.
*/
if (n->n_metric == HOPCNT_INFINITY)
if (new->rts_metric == HOPCNT_INFINITY)
return;
/* Ignore the route if it points to us */
@ -744,8 +787,7 @@ input_route(struct interface *ifp,
* our memory, accept the new route.
*/
if (total_routes < MAX_ROUTES)
rtadd(dst, mask, gate, from, n->n_metric,
n->n_tag, 0, ifp);
rtadd(dst, mask, 0, new);
return;
}
@ -770,7 +812,7 @@ input_route(struct interface *ifp,
rts0 = rt->rt_spares;
for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
if (rts->rts_router == from)
if (rts->rts_router == new->rts_router)
break;
/* Note the worst slot to reuse,
* other than the current slot.
@ -780,40 +822,51 @@ input_route(struct interface *ifp,
rts0 = rts;
}
if (i != 0) {
/* Found the router
/* Found a route from the router already in the table.
*/
int old_metric = rts->rts_metric;
/* If the new route is a route broken down from an
* aggregated route, and if the previous route is either
* not a broken down route or was broken down from a finer
* netmask, and if the previous route is current,
* then forget this one.
*/
if (new->rts_de_ag > rts->rts_de_ag
&& now_stale <= rts->rts_time)
return;
/* Keep poisoned routes around only long enough to pass
* the poison on. Get a new timestamp for good routes.
* the poison on. Use a new timestamp for good routes.
*/
new_time =((old_metric == HOPCNT_INFINITY)
? rts->rts_time
: now.tv_sec);
if (rts->rts_metric == HOPCNT_INFINITY
&& new->rts_metric == HOPCNT_INFINITY)
new->rts_time = rts->rts_time;
/* If this is an update for the router we currently prefer,
* then note it.
*/
if (i == NUM_SPARES) {
rtchange(rt,rt->rt_state, gate,rt->rt_router,
n->n_metric, n->n_tag, ifp, new_time, 0);
rtchange(rt, rt->rt_state, new, 0);
/* If the route got worse, check for something better.
*/
if (n->n_metric > old_metric)
if (new->rts_metric > rts->rts_metric)
rtswitch(rt, 0);
return;
}
/* This is an update for a spare route.
* Finished if the route is unchanged.
* Forget it if it has gone bad.
*/
if (rts->rts_gate == gate
&& old_metric == n->n_metric
&& rts->rts_tag == n->n_tag) {
rts->rts_time = new_time;
if (rts->rts_gate == new->rts_gate
&& rts->rts_metric == new->rts_metric
&& rts->rts_tag == new->rts_tag) {
trace_upslot(rt, rts, new);
*rts = *new;
return;
} else if (n->n_metric == HOPCNT_INFINITY) {
}
/* Forget it if it has gone bad.
*/
if (new->rts_metric == HOPCNT_INFINITY) {
rts_delete(rt, rts);
return;
}
@ -828,6 +881,7 @@ input_route(struct interface *ifp,
&& 0 != ifwithaddr(n->n_nhop, 1, 0))
return;
/* the loop above set rts0=worst spare */
rts = rts0;
/* Save the route as a spare only if it has
@ -835,19 +889,12 @@ input_route(struct interface *ifp,
* This also ignores poisoned routes (those
* received with metric HOPCNT_INFINITY).
*/
if (n->n_metric >= rts->rts_metric)
if (new->rts_metric >= rts->rts_metric)
return;
new_time = now.tv_sec;
}
trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
rts->rts_gate = gate;
rts->rts_router = from;
rts->rts_metric = n->n_metric;
rts->rts_tag = n->n_tag;
rts->rts_time = new_time;
rts->rts_ifp = ifp;
trace_upslot(rt, rts, new);
*rts = *new;
/* try to switch to a better route */
rtswitch(rt, rts);

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.17 1997/09/15 10:38:15 lukem Exp $ */
/* $NetBSD: main.c,v 1.18 1998/06/02 18:02:55 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -40,7 +40,7 @@ char copyright[] =
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: main.c,v 1.17 1997/09/15 10:38:15 lukem Exp $");
__RCSID("$NetBSD: main.c,v 1.18 1998/06/02 18:02:55 thorpej Exp $");
#endif
#include "defs.h"
@ -51,12 +51,20 @@ __RCSID("$NetBSD: main.c,v 1.17 1997/09/15 10:38:15 lukem Exp $");
#include <signal.h>
#include <fcntl.h>
#include <sys/file.h>
#if defined(sgi) && !defined(PRE_KUDZU)
#include <cap_net.h>
#else
#define cap_socket socket
#define cap_bind bind
#endif
pid_t mypid;
naddr myaddr; /* system address */
char myname[MAXHOSTNAMELEN+1];
int verbose;
int supplier; /* supply or broadcast updates */
int supplier_set;
int ipforwarding = 1; /* kernel forwarding on */
@ -78,6 +86,8 @@ time_t now_garbage;
struct timeval next_bcast; /* next general broadcast */
struct timeval no_flash = {EPOCH+SUPPLY_INTERVAL}; /* inhibit flash update */
struct timeval flush_kern_timer;
fd_set fdbits;
int sock_max;
int rip_sock = -1; /* RIP socket */
@ -126,7 +136,7 @@ main(int argc,
(void)gethostname(myname, sizeof(myname)-1);
(void)gethost(myname, &myaddr);
while ((n = getopt(argc, argv, "sqdghmpAtT:F:P:")) != -1) {
while ((n = getopt(argc, argv, "sqdghmpAtvT:F:P:")) != -1) {
switch (n) {
case 's':
supplier = 1;
@ -200,16 +210,19 @@ main(int argc,
break;
case 'P':
/* handle arbirary, (usually) per-interface
* parameters.
/* handle arbitrary parameters.
*/
p = parse_parms(optarg, 0);
if (p != 0) {
if (strcasecmp(p,optarg))
msglog("%s in \"%s\"", p, optarg);
else
msglog("bad \"-P %s\"", optarg);
}
q = strdup(optarg);
p = parse_parms(q, 0);
if (p != 0)
msglog("%s in \"-P %s\"", p, optarg);
free(q);
break;
case 'v':
/* display version */
verbose++;
msglog("version 2.10");
break;
default:
@ -227,11 +240,14 @@ main(int argc,
goto usage;
if (argc != 0) {
usage:
logbad(0, "usage: routed [-sqdghmpAt] [-T tracefile]"
logbad(0, "usage: routed [-sqdghmpAtv] [-T tracefile]"
" [-F net[,metric]] [-P parms]");
}
if (geteuid() != 0)
if (geteuid() != 0) {
if (verbose)
exit(0);
logbad(0, "requires UID 0");
}
mib[0] = CTL_NET;
mib[1] = PF_INET;
@ -272,12 +288,10 @@ usage:
/* get into the background */
#ifdef sgi
if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK),
new_tracelevel == 0 ? -1 : STDOUT_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO))
BADERR(0, "_daemonize()");
#else
if (background && daemon(0, new_tracelevel) < 0)
if (background && daemon(0, 1) < 0)
BADERR(0,"daemon()");
#endif
@ -286,7 +300,7 @@ usage:
/* prepare socket connected to the kernel.
*/
rt_sock = socket(AF_ROUTE, SOCK_RAW, 0);
rt_sock = cap_socket(AF_ROUTE, SOCK_RAW, 0);
if (rt_sock < 0)
BADERR(1,"rt_sock = socket()");
if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1)
@ -299,8 +313,6 @@ usage:
fix_select();
if (background && new_tracelevel == 0)
ftrace = 0;
if (tracename != 0) {
strncpy(inittracename, tracename, sizeof(inittracename)-1);
set_tracefile(inittracename, "%s", -1);
@ -331,12 +343,15 @@ usage:
*/
gwkludge();
ifinit();
flush_kern();
/* Ask for routes */
rip_query();
rdisc_sol();
/* Now turn off stdio if not tracing */
if (new_tracelevel == 0)
trace_close(background);
/* Loop forever, listening and broadcasting.
*/
for (;;) {
@ -378,6 +393,19 @@ usage:
continue;
}
/* Check the kernel table occassionally for mysteriously
* evaporated routes
*/
timevalsub(&t2, &flush_kern_timer, &now);
if (t2.tv_sec <= 0) {
flush_kern();
flush_kern_timer.tv_sec = (now.tv_sec
+ CHECK_QUIET_INTERVAL);
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* If it is time, then broadcast our routes.
*/
if (supplier || advertise_mhome) {
@ -448,7 +476,7 @@ usage:
wtime = t2;
/* take care of router discovery,
* but do it to the millisecond
* but do it in the correct the millisecond
*/
if (!timercmp(&rdisc_timer, &now, >)) {
rdisc_age(0);
@ -612,7 +640,7 @@ get_rip_sock(naddr addr,
sin.sin_family = AF_INET;
sin.sin_port = htons(RIP_PORT);
sin.sin_addr.s_addr = addr;
if (bind(s, (struct sockaddr *)&sin,sizeof(sin)) < 0) {
if (cap_bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
if (serious)
BADERR(errno != EADDRINUSE, "bind(rip_sock)");
return -1;
@ -702,8 +730,10 @@ rip_on(struct interface *ifp)
/* If the main RIP socket is off and it makes sense to turn it on,
* then turn it on for all of the interfaces.
* It makes sense if either router discovery is off, or if
* router discover is on and at most one interface is doing RIP.
*/
if (rip_interfaces > 0 && !rdisc_ok) {
if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) {
trace_act("turn on RIP");
/* Close all of the query sockets so that we can open
@ -753,7 +783,7 @@ rtmalloc(size_t size,
{
void *p = malloc(size);
if (p == 0)
logbad(1,"malloc() failed in %s", msg);
logbad(1,"malloc(%d) failed in %s", size, msg);
return p;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: output.c,v 1.14 1997/09/15 11:51:57 lukem Exp $ */
/* $NetBSD: output.c,v 1.15 1998/06/02 18:02:55 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -37,7 +37,7 @@
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: output.c,v 1.14 1997/09/15 11:51:57 lukem Exp $");
__RCSID("$NetBSD: output.c,v 1.15 1998/06/02 18:02:55 thorpej Exp $");
#endif
#include "defs.h"
@ -64,10 +64,9 @@ struct {
#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 */
#define WS_ST_QUERY 0x010 /* responding to a query */
#define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */
#define WS_ST_DEFAULT 0x040 /* faking a default */
} ws;
/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */
@ -357,11 +356,6 @@ supply_out(struct ag_info *ag)
&& (ws.state & WS_ST_FLASH))
return;
/* Skip this route if required by split-horizon.
*/
if (ag->ag_state & AGS_SPLIT_HZ)
return;
dst_h = ag->ag_dst_h;
mask = ag->ag_mask;
v1_mask = ripv1_mask_host(htonl(dst_h),
@ -397,13 +391,14 @@ supply_out(struct ag_info *ag)
/* Punt if we would have to generate an
* unreasonable number of routes.
*/
#ifdef DEBUG
msglog("sending %s to %s as 1 instead"
" of %d routes",
addrname(htonl(dst_h),mask,1),
naddr_ntoa(ws.to.sin_addr.s_addr),
i+1);
#endif
if (TRACECONTENTS)
trace_misc("sending %s-->%s as 1"
" instead of %d routes",
addrname(htonl(dst_h), mask,
1),
naddr_ntoa(ws.to.sin_addr
.s_addr),
i+1);
i = 0;
} else {
@ -495,7 +490,7 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
} else {
/* Do not send automatic synthetic network routes
* if they are not needed becaus no RIPv1 listeners
* if they are not needed because no RIPv1 listeners
* can hear them.
*/
if (ws.state & WS_ST_RIP2_ALL)
@ -514,6 +509,7 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
/* Advertise the next hop if this is not a route for one
* of our interfaces and the next hop is on the same
* network as the target.
* The final determination is made by supply_out().
*/
if (!(RT->rt_state & RS_IF)
&& RT->rt_gate != myaddr
@ -531,23 +527,30 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
;
} else if (RT_ISHOST(RT)) {
/* We should always aggregate the host routes
* for the local end of our point-to-point links.
/* We should always suppress (into existing network routes)
* the host routes for the local end of our point-to-point
* links.
* If we are suppressing host routes in general, then do so.
* Avoid advertising host routes onto their own network,
* where they should be handled by proxy-ARP.
*/
if ((RT->rt_state & RS_LOCAL)
|| ridhosts
|| (ws.state & WS_ST_SUPER_AG)
|| on_net(dst, ws.to_net, ws.to_mask))
ags |= AGS_SUPPRESS;
if (ws.state & WS_ST_SUPER_AG)
ags |= AGS_PROMOTE;
/* Aggregate stray host routes into network routes if allowed.
* We cannot aggregate host routes into small network routes
* without confusing RIPv1 listeners into thinking the
* network routes are host routes.
*/
if ((ws.state & WS_ST_AG)
&& !(ws.state & WS_ST_RIP2_ALL))
ags |= AGS_AGGREGATE;
} else if (ws.state & WS_ST_AG) {
/* Aggregate network routes, if we are allowed.
} else {
/* Always suppress network routes into other, existing
* network routes
*/
ags |= AGS_SUPPRESS;
@ -556,10 +559,10 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
* later convert back to ordinary nets.
* This unifies dealing with received supernets.
*/
if ((RT->rt_state & RS_SUBNET)
|| (ws.state & WS_ST_SUPER_AG))
ags |= AGS_PROMOTE;
if ((ws.state & WS_ST_AG)
&& ((RT->rt_state & RS_SUBNET)
|| (ws.state & WS_ST_SUPER_AG)))
ags |= AGS_AGGREGATE;
}
/* Do not send RIPv1 advertisements of subnets to other
@ -567,11 +570,9 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
*/
if ((RT->rt_state & RS_SUBNET)
&& !(ws.state & WS_ST_RIP2_ALL)
&& !on_net(dst, ws.to_std_net, ws.to_std_mask)) {
ags |= AGS_RIPV2 | AGS_PROMOTE;
if (ws.state & WS_ST_SUB_AG)
ags |= AGS_SUPPRESS;
}
&& !on_net(dst, ws.to_std_net, ws.to_std_mask))
ags |= AGS_RIPV2 | AGS_AGGREGATE;
/* Do not send a route back to where it came from, except in
* response to a query. This is "split-horizon". That means not
@ -580,8 +581,7 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
* We want to suppress routes that might have been fragmented
* from this route by a RIPv1 router and sent back to us, and so we
* cannot forget this route here. Let the split-horizon route
* aggregate (suppress) the fragmented routes and then itself be
* forgotten.
* suppress the fragmented routes and then itself be forgotten.
*
* Include the routes for both ends of point-to-point interfaces
* among those suppressed by split-horizon, since the other side
@ -596,11 +596,10 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
&& (!(RT->rt_state & RS_IF)
|| ws.ifp->int_if_flags & IFF_POINTOPOINT)) {
for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) {
if (rts->rts_ifp == ws.ifp
&& rts->rts_metric <= metric)
break;
}
if (i != 0) {
if (rts->rts_metric > metric
|| rts->rts_ifp != ws.ifp)
continue;
/* 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.
@ -619,9 +618,10 @@ walk_supply(struct radix_node *rn, struct walkarg *argp)
|| RT->rt_poison_metric >= metric
|| RT->rt_spares[1].rts_gate == 0) {
ags |= AGS_SPLIT_HZ;
ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
ags &= ~AGS_SUPPRESS;
}
metric = HOPCNT_INFINITY;
break;
}
}
@ -701,8 +701,6 @@ supply(struct sockaddr_in *dst,
ws.npackets = 0;
if (flash)
ws.state |= WS_ST_FLASH;
if (type == OUT_QUERY)
ws.state |= WS_ST_QUERY;
if ((ws.ifp = ifp) == 0) {
ws.metric = 1;
@ -716,44 +714,42 @@ supply(struct sockaddr_in *dst,
ripv12_buf.rip.rip_vers = vers;
switch (type) {
case OUT_BROADCAST:
v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST))
? OUT_MULTICAST
: NO_OUT_MULTICAST);
v12buf.type = OUT_BROADCAST;
break;
case OUT_MULTICAST:
v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST))
? OUT_MULTICAST
: NO_OUT_MULTICAST);
if (ifp->int_if_flags & IFF_MULTICAST)
v2buf.type = OUT_MULTICAST;
else
v2buf.type = NO_OUT_MULTICAST;
v12buf.type = OUT_BROADCAST;
break;
case OUT_UNICAST:
case OUT_QUERY:
ws.state |= WS_ST_QUERY;
/* fall through */
case OUT_BROADCAST:
case OUT_UNICAST:
v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
v12buf.type = type;
break;
default:
v2buf.type = type;
v12buf.type = type;
break;
case NO_OUT_MULTICAST:
case NO_OUT_RIPV2:
break; /* no output */
}
if (vers == RIPv2) {
/* 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)) {
if ((ws.state & WS_ST_QUERY)
|| !(ws.state & WS_ST_TO_ON_NET)) {
ws.state |= (WS_ST_AG | WS_ST_SUPER_AG);
} else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) {
ws.state |= WS_ST_AG;
if (type != OUT_BROADCAST
&& (ifp == 0 || !(ifp->int_state&IS_NO_SUPER_AG)))
&& (ifp == 0
|| !(ifp->int_state & IS_NO_SUPER_AG)))
ws.state |= WS_ST_SUPER_AG;
}
} else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) {
ws.state |= WS_ST_SUB_AG;
}
ws.a = (vers == RIPv2) ? find_auth(ifp) : 0;
@ -849,7 +845,7 @@ rip_bcast(int flash)
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
if (!iff_up(ifp->int_if_flags))
continue;
vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1;
@ -858,11 +854,8 @@ rip_bcast(int flash)
/* ordinary, hardware interface */
dst.sin_addr.s_addr = ifp->int_brdaddr;
/* If RIPv1 is not turned off, then broadcast so
* that RIPv1 listeners can hear.
*/
if (vers == RIPv2
&& (ifp->int_state & IS_NO_RIPV1_OUT)) {
&& !(ifp->int_state & IS_NO_RIP_MCAST)) {
type = OUT_MULTICAST;
} else {
type = OUT_BROADCAST;
@ -924,7 +917,7 @@ rip_query(void)
continue;
/* skip turned off interfaces */
if (!iff_alive(ifp->int_if_flags))
if (!iff_up(ifp->int_if_flags))
continue;
buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1;
@ -932,14 +925,26 @@ rip_query(void)
buf.rip_nets[0].n_family = RIP_AF_UNSPEC;
buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
/* Send a RIPv1 query only if allowed and if we will
* listen to RIPv1 routers.
*/
if ((ifp->int_state & IS_NO_RIPV1_OUT)
|| (ifp->int_state & IS_NO_RIPV1_IN)) {
buf.rip_vers = RIPv2;
} else {
buf.rip_vers = 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
* that RIPv1 listeners can hear.
/* Broadcast RIPv1 queries and RIPv2 queries
* when the hardware cannot multicast.
*/
if (buf.rip_vers == RIPv2
&& (ifp->int_state & IS_NO_RIPV1_OUT)) {
&& (ifp->int_if_flags & IFF_MULTICAST)
&& !(ifp->int_state & IS_NO_RIP_MCAST)) {
type = OUT_MULTICAST;
} else {
type = OUT_BROADCAST;

View File

@ -1,4 +1,4 @@
/* $NetBSD: parms.c,v 1.10 1998/03/30 02:15:27 mrg Exp $ */
/* $NetBSD: parms.c,v 1.11 1998/06/02 18:02:55 thorpej Exp $ */
/*
* Copyright (c) 1983, 1993
@ -37,7 +37,7 @@
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: parms.c,v 1.10 1998/03/30 02:15:27 mrg Exp $");
__RCSID("$NetBSD: parms.c,v 1.11 1998/06/02 18:02:55 thorpej Exp $");
#endif
#include "defs.h"
@ -47,6 +47,7 @@ __RCSID("$NetBSD: parms.c,v 1.10 1998/03/30 02:15:27 mrg Exp $");
struct parm *parms;
struct intnet *intnets;
struct r1net *r1nets;
struct tgate *tgates;
@ -111,9 +112,9 @@ get_parms(struct interface *ifp)
/* By default, point-to-point links should be passive
* about router-discovery for the sake of demand-dialing.
*/
if (0 == (ifp->int_state & GROUP_IS_SOL))
if (0 == (ifp->int_state & GROUP_IS_SOL_OUT))
ifp->int_state |= IS_NO_SOL_OUT;
if (0 == (ifp->int_state & GROUP_IS_ADV))
if (0 == (ifp->int_state & GROUP_IS_ADV_OUT))
ifp->int_state |= IS_NO_ADV_OUT;
}
@ -165,10 +166,11 @@ gwkludge(void)
{
FILE *fp;
char *p, *lptr;
char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9];
char lbuf[200], net_host[5], dname[64+1+64+1];
char gname[GNAME_LEN+1], qual[9];
struct interface *ifp;
naddr dst, netmask, gate;
int metric, n;
int metric, n, lnum;
struct stat sb;
u_int state;
char *type;
@ -184,18 +186,19 @@ gwkludge(void)
return;
}
for (;;) {
for (lnum = 1; ; lnum++) {
if (0 == fgets(lbuf, sizeof(lbuf)-1, fp))
break;
lptr = lbuf;
while (*lptr == ' ')
lptr++;
if (*lptr == '\n' /* ignore null and comment lines */
p = lptr+strlen(lptr)-1;
while (*p == '\n'
|| (*p == ' ' && (p == lptr+1 || *(p-1) != '\\')))
*p-- = '\0';
if (*lptr == '\0' /* ignore null and comment lines */
|| *lptr == '#')
continue;
p = lptr+strlen(lptr)-1;
while (*p == '\n' || *p == ' ')
*p-- = '\0';
/* notice newfangled parameter lines
*/
@ -204,19 +207,15 @@ gwkludge(void)
p = parse_parms(lptr,
(sb.st_uid == 0
&& !(sb.st_mode&(S_IRWXG|S_IRWXO))));
if (p != 0) {
if (strcasecmp(p,lptr))
msglog("%s in "_PATH_GATEWAYS
" entry \"%s\"", p, lptr);
else
msglog("bad \"%s\" in "_PATH_GATEWAYS,
lptr);
}
if (p != 0)
msglog("%s in line %d of "_PATH_GATEWAYS,
p, lnum);
continue;
}
/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
qual[0] = '\0';
/* the '64' here must be GNAME_LEN */
n = sscanf(lptr, "%4s %129[^ \t] gateway"
" %64[^ / \t] metric %u %8s\n",
net_host, dname, gname, &metric, qual);
@ -243,6 +242,12 @@ gwkludge(void)
" entry \"%s\"", dname, lptr);
continue;
}
if (dst == RIP_DEFAULT) {
msglog("bad net \"%s\" in "_PATH_GATEWAYS
" entry \"%s\"--cannot be default",
dname, lptr);
continue;
}
HTONL(dst); /* make network # into IP address */
} else {
msglog("bad \"%s\" in "_PATH_GATEWAYS
@ -313,14 +318,14 @@ gwkludge(void)
continue;
}
ifp = (struct interface *)malloc(sizeof(*ifp));
ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge()");
memset(ifp, 0, sizeof(*ifp));
ifp->int_state = state;
if (netmask == HOST_MASK)
ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP_RUNNING;
ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP;
else
ifp->int_if_flags = IFF_UP_RUNNING;
ifp->int_if_flags = IFF_UP;
ifp->int_act_time = NEVER;
ifp->int_addr = gate;
ifp->int_dstaddr = dst;
@ -357,14 +362,14 @@ gwkludge(void)
}
/* strtok(), but honoring backslash
/* like strtok(), but honoring backslash and not changing the source string
*/
static int /* 0=ok, -1=bad */
parse_quote(char **linep,
char *delims,
char *delimp,
char *buf,
int lim)
parse_quote(char **linep, /* look here */
char *delims, /* for these delimiters */
char *delimp, /* 0 or put found delimiter here */
char *buf, /* copy token to here */
int lim) /* at most this many bytes */
{
char c = '\0';
char *pc, *p;
@ -411,10 +416,10 @@ exit:
if (lim == 0)
return -1;
*buf = '\0';
*buf = '\0'; /* terminate copy of token */
if (delimp != 0)
*delimp = c;
*linep = pc-1;
*delimp = c; /* return delimiter */
*linep = pc-1; /* say where we ended */
return 0;
}
@ -539,6 +544,16 @@ get_passwd(char *tgt,
}
static char *
bad_str(char *estr)
{
static char buf[100+8];
sprintf(buf, "bad \"%.100s\"", estr);
return buf;
}
/* Parse a set of parameters for an interface.
*/
char * /* 0 or error message */
@ -551,30 +566,35 @@ parse_parms(char *line,
parm.parm_int_state |= (b);}
struct parm parm;
struct intnet *intnetp;
struct r1net *r1netp;
struct tgate *tg;
naddr addr, mask;
char delim, *val0 = NULL, *tgt, *val, *p;
char buf[64];
char delim, *val0, *tgt, *val, *p;
char buf[BUFSIZ], buf2[BUFSIZ];
int i;
val0 = NULL; /* XXX gcc -Wuninitialized */
/* "subnet=x.y.z.u/mask,metric" must be alone on the line */
/* "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));
&& *(val = &line[sizeof("subnet=")-1]) != '\0') {
if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)))
return bad_str(line);
intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp),
"parse_parms subnet");
intnetp->intnet_metric = 1;
if ((p = strrchr(val,','))) {
*p++ = '\0';
intnetp->intnet_metric = (int)strtol(p,&p,0);
if (delim == ',') {
intnetp->intnet_metric = (int)strtol(val+1,&p,0);
if (*p != '\0'
|| intnetp->intnet_metric <= 0
|| intnetp->intnet_metric >= HOPCNT_INFINITY)
return line;
return bad_str(line);
}
if (!getnet(val, &intnetp->intnet_addr, &intnetp->intnet_mask)
if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask)
|| intnetp->intnet_mask == HOST_MASK
|| intnetp->intnet_addr == RIP_DEFAULT) {
free(intnetp);
return line;
return bad_str(line);
}
HTONL(intnetp->intnet_addr);
intnetp->intnet_next = intnets;
@ -582,29 +602,60 @@ parse_parms(char *line,
return 0;
}
/* "ripv1_mask=x.y.z.u/mask,mask" must be alone on the line */
if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1)
&& *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') {
if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))
|| delim == '\0')
return bad_str(line);
if ((i = (int)strtol(val+1, &p, 0)) <= 0
|| i > 32 || *p != '\0')
return bad_str(line);
r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp),
"parse_parms ripv1_mask");
r1netp->r1net_mask = HOST_MASK << (32-i);
if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match)
|| r1netp->r1net_net == RIP_DEFAULT
|| r1netp->r1net_mask < r1netp->r1net_match) {
free(r1netp);
return bad_str(line);
}
r1netp->r1net_next = r1nets;
r1nets = r1netp;
return 0;
}
memset(&parm, 0, sizeof(parm));
tgt = "null";
for (;;) {
tgt = line + strspn(line, " ,\n\r");
if (*tgt == '\0')
if (*tgt == '\0' || *tgt == '#')
break;
line += strcspn(tgt, "= ,\n\r");
line = tgt+strcspn(tgt, "= #,\n\r");
delim = *line;
if (delim == '=') {
val0 = ++line;
if (0 > parse_quote(&line," ,\n\r",&delim,
if (0 > parse_quote(&line, " #,\n\r",&delim,
buf,sizeof(buf)))
return tgt;
return bad_str(tgt);
}
if (delim != '\0') {
for (;;) {
*line = '\0';
if (delim == '#')
break;
++line;
if (delim != ' '
|| (delim = *line) != ' ')
break;
}
}
if (delim != '\0')
*line++ = '\0';
if (PARSEQ("if")) {
if (parm.parm_name[0] != '\0'
|| strlen(buf) > IFNAMSIZ)
return tgt;
|| strlen(buf) > IF_NAME_LEN)
return bad_str(tgt);
strcpy(parm.parm_name, buf);
} else if (PARSEQ("addr")) {
@ -616,7 +667,7 @@ parse_parms(char *line,
*/
if (!getnet(val0, &addr, &mask)
|| parm.parm_name[0] != '\0')
return tgt;
return bad_str(tgt);
parm.parm_net = addr;
parm.parm_mask = mask;
parm.parm_name[0] = '\n';
@ -628,14 +679,14 @@ parse_parms(char *line,
tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
if (tgt) {
*val0 = '\0';
return tgt;
return bad_str(tgt);
}
} else if (PARSEQ("md5_passwd")) {
tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
if (tgt) {
*val0 = '\0';
return tgt;
return bad_str(tgt);
}
} else if (PARS("no_ag")) {
@ -652,50 +703,53 @@ parse_parms(char *line,
} else if (PARS("ripv2_out")) {
if (parm.parm_int_state & IS_NO_RIPV2_OUT)
return tgt;
return bad_str(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;
return bad_str(tgt);
parm.parm_int_state |= (IS_NO_RIPV1_IN
| IS_NO_RIPV1_OUT);
} else if (PARS("no_rip")) {
CKF(IS_PM_RDISC, IS_NO_RIP);
} else if (PARS("no_rip_mcast")) {
parm.parm_int_state |= IS_NO_RIP_MCAST;
} else if (PARS("no_rdisc")) {
CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
} else if (PARS("no_solicit")) {
CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT);
} else if (PARS("send_solicit")) {
CKF(GROUP_IS_SOL, IS_SOL_OUT);
CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT);
} else if (PARS("no_rdisc_adv")) {
CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT);
} else if (PARS("rdisc_adv")) {
CKF(GROUP_IS_ADV, IS_ADV_OUT);
CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT);
} else if (PARS("bcast_rdisc")) {
parm.parm_int_state |= IS_BCAST_RDISC;
} else if (PARS("passive")) {
CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
parm.parm_int_state |= IS_NO_RIP;
} else if (PARSEQ("rdisc_pref")) {
if (parm.parm_rdisc_pref != 0
|| (parm.parm_rdisc_pref = (int)strtoul(buf, &p,0),
|| (parm.parm_rdisc_pref = (int)strtol(buf,&p,0),
*p != '\0'))
return tgt;
return bad_str(tgt);
} else if (PARS("pm_rdisc")) {
if (IS_RIP_OUT_OFF(parm.parm_int_state))
return tgt;
return bad_str(tgt);
parm.parm_int_state |= IS_PM_RDISC;
} else if (PARSEQ("rdisc_interval")) {
@ -704,7 +758,7 @@ parse_parms(char *line,
*p != '\0')
|| parm.parm_rdisc_int < MinMaxAdvertiseInterval
|| parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
return tgt;
return bad_str(tgt);
} else if (PARSEQ("fake_default")) {
if (parm.parm_d_metric != 0
@ -712,14 +766,35 @@ parse_parms(char *line,
|| (parm.parm_d_metric = (int)strtoul(buf,&p,0),
*p != '\0')
|| parm.parm_d_metric > HOPCNT_INFINITY-1)
return tgt;
return bad_str(tgt);
} else if (PARSEQ("trust_gateway")) {
if (!gethost(buf,&addr))
return tgt;
tg = (struct tgate *)malloc(sizeof(*tg));
tg->tgate_next = tgates;
/* look for trust_gateway=x.y.z|net/mask|...) */
p = buf;
if (0 > parse_quote(&p, "|", &delim,
buf2, sizeof(buf2))
|| !gethost(buf2,&addr))
return bad_str(tgt);
tg = (struct tgate *)rtmalloc(sizeof(*tg),
"parse_parms"
"trust_gateway");
bzero(tg, sizeof(*tg));
tg->tgate_addr = addr;
i = 0;
/* The default is to trust all routes. */
while (delim == '|') {
p++;
if (i >= MAX_TGATE_NETS
|| 0 > parse_quote(&p, "|", &delim,
buf2, sizeof(buf2))
|| !getnet(buf2, &tg->tgate_nets[i].net,
&tg->tgate_nets[i].mask)
|| tg->tgate_nets[i].net == RIP_DEFAULT
|| tg->tgate_nets[i].mask == 0)
return bad_str(tgt);
i++;
}
tg->tgate_next = tgates;
tgates = tg;
parm.parm_int_state |= IS_DISTRUST;
@ -727,7 +802,7 @@ parse_parms(char *line,
parm.parm_int_state |= IS_REDIRECT_OK;
} else {
return tgt; /* error */
return bad_str(tgt); /* error */
}
}
@ -748,6 +823,8 @@ check_parms(struct parm *new)
*/
if (new->parm_int_state & IS_NO_ADV_IN)
new->parm_int_state |= IS_NO_SOL_OUT;
if (new->parm_int_state & IS_NO_SOL_OUT)
new->parm_int_state |= IS_NO_ADV_IN;
for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
if (new->parm_auth[i].type != RIP_AUTH_NONE)
@ -774,14 +851,14 @@ check_parms(struct parm *new)
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)
if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT)
&& 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT)
&& 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)
&& GROUP_IS_SOL_OUT))
|| (0 != (new->parm_int_state & GROUP_IS_ADV_OUT)
&& 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT)
&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
&& GROUP_IS_ADV))
&& GROUP_IS_ADV_OUT))
|| (new->parm_rdisc_pref != 0
&& parmp->parm_rdisc_pref != 0
&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
@ -804,7 +881,7 @@ 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));
parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms");
memmove(parmp, new, sizeof(*parmp));
*parmpp = parmp;
@ -817,7 +894,7 @@ check_parms(struct parm *new)
*/
int /* 0=bad */
getnet(char *name,
naddr *netp, /* a network so host byte order */
naddr *netp, /* network in host byte order */
naddr *maskp) /* masks are always in host order */
{
int i;
@ -843,6 +920,12 @@ getnet(char *name,
np = getnetbyname(name);
if (np != 0) {
in.s_addr = (naddr)np->n_net;
if (0 == (in.s_addr & 0xff000000))
in.s_addr <<= 8;
if (0 == (in.s_addr & 0xff000000))
in.s_addr <<= 8;
if (0 == (in.s_addr & 0xff000000))
in.s_addr <<= 8;
} else if (inet_aton(name, &in) == 1) {
NTOHL(in.s_addr);
} else if (!mname && !strcasecmp(name,"default")) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: rdisc.c,v 1.6 1997/09/15 10:38:19 lukem Exp $ */
/* $NetBSD: rdisc.c,v 1.7 1998/06/02 18:02:56 thorpej Exp $ */
/*
* Copyright (c) 1995
@ -37,13 +37,18 @@
static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: rdisc.c,v 1.6 1997/09/15 10:38:19 lukem Exp $");
__RCSID("$NetBSD: rdisc.c,v 1.7 1998/06/02 18:02:56 thorpej Exp $");
#endif
#include "defs.h"
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#if defined(sgi) && !defined(PRE_KUDZU)
#include <cap_net.h>
#else
#define cap_socket socket
#endif
/* router advertisement ICMP packet */
struct icmp_ad {
@ -78,10 +83,10 @@ int rdisc_sock = -1; /* router-discovery raw socket */
struct interface *rdisc_sock_mcast; /* current multicast interface */
struct timeval rdisc_timer;
int rdisc_ok; /* using solicited route */
int rdisc_ok; /* using solicted route */
#define MAX_ADS 5
#define MAX_ADS 16 /* at least one per interface */
struct dr { /* accumulated advertisements */
struct interface *dr_ifp;
naddr dr_gate; /* gateway */
@ -91,7 +96,12 @@ struct dr { /* accumulated advertisements */
n_long dr_pref; /* preference adjusted by metric */
} *cur_drp, drs[MAX_ADS];
/* adjust preference by interface metric without driving it to infinity */
/* convert between signed, balanced around zero,
* and unsigned zero-based preferences */
#define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel)
#define UNSIGN_PREF(p) SIGN_PREF(p)
/* adjust unsigned preference by interface metric,
* without driving it to infinity */
#define PREF(p, ifp) ((p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \
: (p) - ((ifp)->int_metric))
@ -149,7 +159,7 @@ static void
get_rdisc_sock(void)
{
if (rdisc_sock < 0) {
rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
rdisc_sock = cap_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rdisc_sock < 0)
BADERR(1,"rdisc_sock = socket()");
fix_sock(rdisc_sock,"rdisc_sock");
@ -298,7 +308,7 @@ rdisc_age(naddr bad_gate)
/* If only adverising, then do only that. */
if (supplier) {
/* if switching from client to server, get rid of old
/* If switching from client to server, get rid of old
* default routes.
*/
if (cur_drp != 0)
@ -338,14 +348,17 @@ rdisc_age(naddr bad_gate)
}
}
/* delete old redirected routes to keep the kernel table small
*/
sec = (cur_drp == 0) ? MaxMaxAdvertiseInterval : cur_drp->dr_life;
del_redirects(bad_gate, now.tv_sec-sec);
rdisc_sol();
rdisc_sort();
/* Delete old redirected routes to keep the kernel table small,
* and to prevent black holes. Check that the kernel table
* matches the daemon table (i.e. has the default route).
* But only if RIP is not running and we are not dealing with
* a bad gateway, since otherwise age() will be called.
*/
if (rip_sock < 0 && bad_gate == 0)
age(0);
}
@ -361,10 +374,12 @@ if_bad_rdisc(struct interface *ifp)
if (drp->dr_ifp != ifp)
continue;
drp->dr_recv_pref = 0;
drp->dr_ts = 0;
drp->dr_life = 0;
}
rdisc_sort();
/* make a note to re-solicit, turn RIP on or off, etc. */
rdisc_timer.tv_sec = 0;
}
@ -390,10 +405,11 @@ static void
del_rdisc(struct dr *drp)
{
struct interface *ifp;
naddr gate;
int i;
del_redirects(drp->dr_gate, 0);
del_redirects(gate = drp->dr_gate, 0);
drp->dr_ts = 0;
drp->dr_life = 0;
@ -412,13 +428,21 @@ del_rdisc(struct dr *drp)
* then solicit a new one.
* This is contrary to RFC 1256, but defends against black holes.
*/
if (i == 0
&& ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
trace_act("discovered route is bad--re-solicit routers via %s",
ifp->int_name);
if (i != 0) {
trace_act("discovered router %s via %s"
" is bad--have %d remaining",
naddr_ntoa(gate), ifp->int_name, i);
} else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
trace_act("last discovered router %s via %s"
" is bad--re-solicit",
naddr_ntoa(gate), ifp->int_name);
ifp->int_rdisc_cnt = 0;
ifp->int_rdisc_timer.tv_sec = 0;
rdisc_sol();
} else {
trace_act("last discovered router %s via %s"
" is bad--wait to solicit",
naddr_ntoa(gate), ifp->int_name);
}
}
@ -431,6 +455,7 @@ rdisc_sort(void)
{
struct dr *drp, *new_drp;
struct rt_entry *rt;
struct rt_spare new;
struct interface *ifp;
u_int new_st;
n_long new_pref;
@ -493,23 +518,20 @@ rdisc_sort(void)
if (rt != 0
&& (rt->rt_state & RS_RDISC)) {
new = rt->rt_spares[0];
new.rts_metric = HOPCNT_INFINITY;
new.rts_time = now.tv_sec - GARBAGE_TIME;
rtchange(rt, rt->rt_state & ~RS_RDISC,
rt->rt_gate, rt->rt_router,
HOPCNT_INFINITY, 0, rt->rt_ifp,
now.tv_sec - GARBAGE_TIME, 0);
&new, 0);
rtswitch(rt, 0);
}
/* turn on RIP if permitted */
rip_on(0);
} else {
if (cur_drp == 0) {
trace_act("turn on Router Discovery client"
" using %s via %s",
naddr_ntoa(new_drp->dr_gate),
new_drp->dr_ifp->int_name);
rdisc_ok = 1;
} else {
@ -521,27 +543,28 @@ rdisc_sort(void)
new_drp->dr_ifp->int_name);
}
bzero(&new, sizeof(new));
new.rts_ifp = new_drp->dr_ifp;
new.rts_gate = new_drp->dr_gate;
new.rts_router = new_drp->dr_gate;
new.rts_metric = HOPCNT_INFINITY-1;
new.rts_time = now.tv_sec;
if (rt != 0) {
rtchange(rt, rt->rt_state | RS_RDISC,
new_drp->dr_gate, new_drp->dr_gate,
0,0, new_drp->dr_ifp,
now.tv_sec, 0);
rtchange(rt, rt->rt_state | RS_RDISC, &new, 0);
} else {
rtadd(RIP_DEFAULT, 0,
new_drp->dr_gate, new_drp->dr_gate,
HOPCNT_INFINITY-1, 0,
RS_RDISC, new_drp->dr_ifp);
rtadd(RIP_DEFAULT, 0, RS_RDISC, &new);
}
/* Now turn off RIP and delete RIP routes,
* which might otherwise include the default
* we just modified.
*/
rip_off();
}
cur_drp = new_drp;
}
/* turn RIP on or off */
if (!rdisc_ok || rip_interfaces > 1) {
rip_on(0);
} else {
rip_off();
}
}
@ -550,7 +573,7 @@ rdisc_sort(void)
static void
parse_ad(naddr from,
naddr gate,
n_long pref,
n_long pref, /* signed and in network order */
u_short life,
struct interface *ifp)
{
@ -581,9 +604,9 @@ parse_ad(naddr from,
/* Convert preference to an unsigned value
* and later bias it by the metric of the interface.
*/
pref = ntohl(pref) ^ MIN_PreferenceLevel;
pref = UNSIGN_PREF(ntohl(pref));
if (pref == 0 || life == 0) {
if (pref == 0 || life < MinMaxAdvertiseInterval) {
pref = 0;
life = 0;
}
@ -782,9 +805,13 @@ send_adv(struct interface *ifp,
u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4;
u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3);
pref = ifp->int_rdisc_pref ^ MIN_PreferenceLevel;
pref = PREF(pref, ifp) ^ MIN_PreferenceLevel;
u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(pref);
/* Convert the configured preference to an unsigned value,
* bias it by the interface metric, and then send it as a
* signed, network byte order value.
*/
pref = UNSIGN_PREF(ifp->int_rdisc_pref);
u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp)));
u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr;
@ -1030,6 +1057,8 @@ read_d(void)
continue;
if (ifp->int_state & IS_NO_ADV_OUT)
continue;
if (stopint)
continue;
/* XXX
* We should handle messages from address 0.

View File

@ -1,4 +1,4 @@
.\" $NetBSD: routed.8,v 1.19 1998/04/29 09:49:14 fair Exp $
.\" $NetBSD: routed.8,v 1.20 1998/06/02 18:02:56 thorpej Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -42,7 +42,7 @@
.Nd network RIP and router discovery routing daemon
.Sh SYNOPSIS
.Nm
.Op Fl sqdghmpAt
.Op Fl sqdghmpAtv
.Op Fl T Ar tracefile
.Oo
.Fl F
@ -120,7 +120,7 @@ Advertised metrics reflect the metric associated with interface
so setting the metric on an interface
is an effective way to steer traffic.
.Pp
Responses do not contain routes with a first hop on the requesting
Responses do not include routes with a first hop on the requesting
network to implement in part
.Em split-horizon .
Requests from query programs
@ -193,25 +193,17 @@ The
is handled similarly.
When the daemon is supplying RIP routes, it also listens for
Router Discovery Solicitations and sends Advertisements.
When it is quiet and only listening to other RIP routers, it
When it is quiet and listening to other RIP routers, it
sends Solicitations and listens for Advertisements.
If it receives
a good Advertisement, it stops listening for broadcast or multicast
RIP responses.
a good Advertisement and it is not multi-homed,
it stops listening for broadcast or multicast RIP responses.
It tracks several advertising routers to speed recovery when the
currently chosen router dies.
If all discovered routers disappear,
the daemon resumes listening to RIP responses.
.Pp
While using Router Discovery (which happens by default when
the system has a single network interface and a Router Discovery 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.
It continues listen to RIP while using Router Discovery
if multi-homed to ensure all interfaces are used.
.Pp
The Router Discovery standard requires that advertisements
have a default "lifetime" of 30 minutes. That means should
@ -304,12 +296,6 @@ This option is required for conformance with RFC 1723.
However, it makes no sense and breaks using RIP as a discovery protocol
to ignore all RIPv2 packets that carry authentication when this machine
does not care about authentication.
.It Fl T Ar tracefile
increases the debugging level to at least 1 and
causes debugging information to be appended to the trace file.
Note that because of security concerns, it is wisest to not run
.Nm
routinely with tracing directed to a file.
.It Fl t
increases the debugging level, which causes more information to be logged
on the tracefile specified with
@ -323,6 +309,14 @@ or
signals or with the
.Xr rtquery 8
command.
.It Fl T Ar tracefile
increases the debugging level to at least 1 and
causes debugging information to be appended to the trace file.
Note that because of security concerns, it is wisest to not run
.Nm routed
routinely with tracing directed to a file.
.It Fl v
displays and logs the version of daemon.
.It Fl F Ar net[/mask][,metric]
minimize routes in transmissions via interfaces with addresses that match
.Em net/mask ,
@ -402,6 +396,8 @@ One can list all RIP routers reachable on the ATM network in
.Pa /etc/gateways
with a series of
"host" lines.
Note that it is usually desirable to use RIPv2 in such situations
to avoid generating lists of inferred host routes.
.Pp
Gateways marked
.Em external
@ -419,7 +415,8 @@ to the same destination.
The
.Pa /etc/gateways
file is comprised of a series of lines, each in
one of the following formats or consist of parameters described below:
one of the following two formats or consist of parameters described later.
Blank lines and lines starting with '#' are comments.
.Pp
.Bd -ragged
.Cm net
@ -489,6 +486,15 @@ or whether the gateway is
.Cm external
to the scope of the RIP protocol.
.Pp
As can be seen when debugging is turned on with
.Fl t ,
such lines create psuedo-interfaces.
To set parameters for remote or external interfaces,
a line starting with
.Cm if=alias(Hname) ,
.Cm if=remote(Hname) ,
etc. should be used.
.Pp
Lines that start with neither "net" nor "host" must consist of one
or more of the following parameter settings, separated by commas or
blanks:
@ -505,14 +511,19 @@ with mask
and the supplied metric (default 1).
This is useful for filling "holes" in CIDR allocations.
This parameter must appear by itself on a line.
The network number must specify a full, 32-bit value, as in 192.0.2.0
instead of 192.0.2.
.Pp
Do not use this feature unless necessary. It is dangerous.
.It Cm passwd Ns \&= Ns Ar XXX
specifies a RIPv2 password that will be included on all RIPv2
responses sent and checked on all RIPv2 responses received.
The password must not contain any blanks, tab characters, commas
or '#' characters.
.It Cm passwd Ns \&= Ns Ar XXX1[|KeyID[start|stop]]
.It Cm ripv1_mask Ns \&= Ns Ar nname/mask1,mask2
specifies that netmask of the network of which
.Cm nname/mask1\f1
is
a subnet should be
.Cm mask2 .
For example \f2ripv1_mask=192.0.2.16/28,27\f1 marks 192.0.2.16/28
as a subnet of 192.0.2.0/28 instead of 192.0.2.0/24.
.It Cm passwd Ns \&= Ns Ar XXX[|KeyID[start|stop]]
specifies a RIPv2 cleartext password that will be included on
all RIPv2 responses sent, and checked on all RIPv2 responses received.
Any blanks, tab characters, commas, or '#', '|', or NULL characters in the
@ -537,7 +548,7 @@ be valid within 24 hours, or that was valid within 24 hours.
To protect the secrets, the passwd settings are valid only in the
.Em /etc/gateways
file and only when that file is readable only by UID 0.
.It Cm md5_passwd Ns \&= Ns Ar XXX1|KeyID[start|stop]
.It Cm md5_passwd Ns \&= Ns Ar XXX|KeyID[start|stop]
specifes a RIPv2 MD5 password.
Except that a
.Cm KeyID
@ -563,6 +574,8 @@ or
causes
.Nm
to act as a client router discovery daemon, not advertising.
.It Cm no_rip_mcast
causes RIPv2 packets to be broadcast instead of multicast.
.It Cm no_ripv1_in
causes RIPv1 received responses to be ignored.
.It Cm no_ripv2_in
@ -593,8 +606,12 @@ which by default only listen to Router Discovery messages
specifies that Router Discovery packets should be broadcast instead of
multicast.
.It Cm rdisc_pref Ns \&= Ns Ar N
sets the preference in Router Discovery Advertisements to the integer
sets the preference in Router Discovery Advertisements to the optionally
signed integer
.Ar N .
The default preference is 0.
Default routes with smaller or more negative preferences are preferred by
clients.
.It Cm rdisc_interval Ns \&= Ns Ar N
sets the nominal interval with which Router Discovery Advertisements
are transmitted to N seconds and their lifetime to 3*N.
@ -612,15 +629,17 @@ Unless modified with
.Cm fake_default ,
the default route is broadcast with a metric of 14.
That serves as a "poor man's router discovery" protocol.
.It Cm trust_gateway Ns \&= Ns Ar rname
.It Cm trust_gateway Ns \&= Ns Ar rname[|net1/mask1|net2/mask2|...]
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.
keywords to be accepted, and packets from other routers to be ignored.
If networks are specified, then routes to other networks will be ignored
from that router.
.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.
Otherwise, ICMP Redirect messages are overridden.
.El
.Pp
.Sh FILES

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtquery.c,v 1.7 1998/06/02 10:48:49 kleink Exp $ */
/* $NetBSD: rtquery.c,v 1.8 1998/06/02 18:02:56 thorpej Exp $ */
/*-
* Copyright (c) 1982, 1986, 1993
@ -41,7 +41,7 @@ char copyright[] =
static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: rtquery.c,v 1.7 1998/06/02 10:48:49 kleink Exp $");
__RCSID("$NetBSD: rtquery.c,v 1.8 1998/06/02 18:02:56 thorpej Exp $");
#endif
#include <sys/param.h>
@ -110,6 +110,8 @@ u_long keyid;
struct timeval sent; /* when query sent */
static char *default_argv[2] = {"localhost", 0};
static void rip_input(struct sockaddr_in*, int);
static int out(char *);
static void trace_loop(char *argv[]) __attribute((__noreturn__));
@ -254,7 +256,7 @@ main(int argc,
}
argv += optind;
argc -= optind;
if ((not_trace && trace) || argc == 0) {
if (not_trace && trace) {
usage: fprintf(stderr, "%s: [-np1] [-r tgt_rt] [-w wtime]"
" [-a type=passwd] host1 [host2 ...]\n"
"or\t-t {on=filename|more|off|dump}"
@ -262,6 +264,10 @@ usage: fprintf(stderr, "%s: [-np1] [-r tgt_rt] [-w wtime]"
pgmname);
exit(1);
}
if (argc == 0) {
argc = 1;
argv = default_argv;
}
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: table.c,v 1.6 1997/09/16 08:37:15 mrg Exp $ */
/* $NetBSD: table.c,v 1.7 1998/06/02 18:02:56 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -37,13 +37,13 @@
static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: table.c,v 1.6 1997/09/16 08:37:15 mrg Exp $");
__RCSID("$NetBSD: table.c,v 1.7 1998/06/02 18:02:56 thorpej Exp $");
#endif
#include "defs.h"
static struct rt_spare *rts_better(struct rt_entry *);
static struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0};
static struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0,0};
void set_need_flash(void);
#ifdef _HAVE_SIN_LEN
@ -126,6 +126,10 @@ ag_out(struct ag_info *ag,
naddr bit;
/* Forget it if this route should not be output for split-horizon. */
if (ag->ag_state & AGS_SPLIT_HZ)
return;
/* If we output both the even and odd twins, then the immediate parent,
* if it is present, is redundant, unless the parent manages to
* aggregate into something coarser.
@ -151,12 +155,14 @@ ag_out(struct ag_info *ag,
*/
if (ag->ag_state & AGS_REDUN0) {
if (ag->ag_state & AGS_REDUN1)
return;
return; /* quit if fully redundant */
/* make it finer if it is half-redundant */
bit = (-ag->ag_mask) >> 1;
ag->ag_dst_h |= bit;
ag->ag_mask |= bit;
} else if (ag->ag_state & AGS_REDUN1) {
/* make it finer if it is half-redundant */
bit = (-ag->ag_mask) >> 1;
ag->ag_mask |= bit;
}
@ -243,6 +249,8 @@ ag_flush(naddr lim_dst_h, /* flush routes to here */
/* If the coarse route has a good enough
* metric, it suppresses the target.
* If the suppressed target was redundant,
* then mark the suppressor redundant.
*/
if (ag_cors->ag_pref <= ag->ag_pref) {
if (ag_cors->ag_seqno > ag->ag_seqno)
@ -340,6 +348,9 @@ ag_check(naddr dst,
|| (ag_cors->ag_state & AGS_CORS_GATE))) {
if (ag_cors->ag_seqno > ag->ag_seqno)
ag_cors->ag_seqno = ag->ag_seqno;
/* If the suppressed target was redundant,
* then mark the suppressor redundant.
*/
if (AG_IS_REDUN(ag->ag_state)
&& ag_cors->ag_mask==ag->ag_mask<<1) {
if (ag_cors->ag_dst_h == dst)
@ -382,11 +393,11 @@ ag_check(naddr dst,
* Routes are encountered in lexical order, so a
* route is never promoted until the parent route is
* already present. So we know that the new route is
* a promoted pair and the route already in the slot
* is the explicit route.
* a promoted (or aggregated) pair and the route
* already in the slot is the explicit route.
*
* Prefer the best route if their metrics differ,
* or the promoted one if not, following a sort
* or the aggregated one if not, following a sort
* of longest-match rule.
*/
if (pref <= ag->ag_pref) {
@ -406,9 +417,13 @@ ag_check(naddr dst,
if (ag->ag_seqno > seqno)
ag->ag_seqno = seqno;
/* some bits are set if they are set on either route */
ag->ag_state |= (state & (AGS_PROMOTE_EITHER
| AGS_REDUN0 | AGS_REDUN1));
/* Some bits are set if they are set on either route,
* except when the route is for an interface.
*/
if (!(ag->ag_state & AGS_IF))
ag->ag_state |= (state & (AGS_AGGREGATE_EITHER
| AGS_REDUN0
| AGS_REDUN1));
return;
}
@ -416,12 +431,12 @@ ag_check(naddr dst,
* be suppressed, it may be possible to combine them or
* worthwhile to promote one.
*
* Note that any route that can be promoted is always
* Any route that can be promoted is always
* marked to be eligible to be suppressed.
*/
if (!((state & AGS_PROMOTE)
if (!((state & AGS_AGGREGATE)
&& (ag->ag_state & AGS_SUPPRESS))
&& !((ag->ag_state & AGS_PROMOTE)
&& !((ag->ag_state & AGS_AGGREGATE)
&& (state & AGS_SUPPRESS)))
break;
@ -433,13 +448,13 @@ ag_check(naddr dst,
|| AG_IS_REDUN(state)
|| (ag->ag_gate == gate
&& ag->ag_pref == pref
&& (state & ag->ag_state & AGS_PROMOTE) != 0)) {
&& (state & ag->ag_state & AGS_AGGREGATE) != 0)) {
/* We have both the even and odd pairs.
* Since the routes are encountered in order,
* the route in the slot must be the even twin.
*
* Combine and promote the pair of routes.
* Combine and promote (aggregate) the pair of routes.
*/
if (seqno > ag->ag_seqno)
seqno = ag->ag_seqno;
@ -449,7 +464,7 @@ ag_check(naddr dst,
state |= AGS_REDUN0;
else
state &= ~AGS_REDUN0;
state |= (ag->ag_state & AGS_PROMOTE_EITHER);
state |= (ag->ag_state & AGS_AGGREGATE_EITHER);
if (ag->ag_tag != tag)
tag = 0;
if (ag->ag_nhop != nhop)
@ -461,7 +476,7 @@ ag_check(naddr dst,
ag_del(ag);
} else if (ag->ag_pref >= pref
&& (ag->ag_state & AGS_PROMOTE)) {
&& (ag->ag_state & AGS_AGGREGATE)) {
/* If we cannot combine the pair, maybe the route
* with the worse metric can be promoted.
*
@ -482,11 +497,17 @@ ag_check(naddr dst,
ag->ag_tag = tag;
tag = x;
/* The promoted route is even-redundant only if the
* even twin was fully redundant. It is not
* odd-redundant because the odd-twin will still be
* in the table.
*/
x = ag->ag_state;
if (!AG_IS_REDUN(x))
x &= ~AGS_REDUN0;
x &= ~AGS_REDUN1;
ag->ag_state = state;
state = x;
if (!AG_IS_REDUN(state))
state &= ~AGS_REDUN0;
x = ag->ag_metric;
ag->ag_metric = metric;
@ -496,24 +517,30 @@ ag_check(naddr dst,
ag->ag_pref = pref;
pref = x;
/* take the newest sequence number */
if (seqno >= ag->ag_seqno)
seqno = ag->ag_seqno;
else
ag->ag_seqno = seqno;
} else {
if (!(state & AGS_PROMOTE))
if (!(state & AGS_AGGREGATE))
break; /* cannot promote either twin */
/* promote the new, odd twin by shaving its
/* Promote the new, odd twin by shaving its
* mask and address.
* The promoted route is odd-redundant only if the
* odd twin was fully redundant. It is not
* even-redundant because the even twin is still in
* the table.
*/
if (!AG_IS_REDUN(state))
state &= ~AGS_REDUN1;
state &= ~AGS_REDUN0;
if (seqno > ag->ag_seqno)
seqno = ag->ag_seqno;
else
ag->ag_seqno = seqno;
if (!AG_IS_REDUN(state))
state &= ~AGS_REDUN1;
}
mask <<= 1;
@ -678,7 +705,7 @@ again:
w.w_rtm.rtm_flags = flags;
w.w_rtm.rtm_seq = ++rt_sock_seqno;
w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
if (metric != 0) {
if (metric != 0 || action == RTM_CHANGE) {
w.w_rtm.rtm_rmx.rmx_hopcount = metric;
w.w_rtm.rtm_inits |= RTV_HOPCOUNT;
}
@ -716,7 +743,7 @@ again:
}
return;
}
msglog("write(rt_sock)" PAT ": ", ARGS, strerror(errno));
msglog("write(rt_sock)" PAT ": %s", ARGS, strerror(errno));
return;
} else if (cc != w.w_rtm.rtm_msglen) {
msglog("write(rt_sock) wrote %d instead of %d for" PAT,
@ -725,7 +752,7 @@ again:
}
#endif
if (TRACEKERNEL)
trace_kernel("write kernel" PAT, ARGS);
trace_misc("write kernel" PAT, ARGS);
#undef PAT
#undef ARGS
}
@ -741,14 +768,15 @@ static struct khash {
short k_metric;
u_short k_state;
#define KS_NEW 0x001
#define KS_DELETE 0x002
#define KS_DELETE 0x002 /* need to delete the route */
#define KS_ADD 0x004 /* add to the kernel */
#define KS_CHANGE 0x008 /* tell kernel to change the route */
#define KS_DEL_ADD 0x010 /* delete & add to change the kernel */
#define KS_STATIC 0x020 /* Static flag in kernel */
#define KS_GATEWAY 0x040 /* G flag in kernel */
#define KS_DYNAMIC 0x080 /* result of redirect */
#define KS_DELETED 0x100 /* already deleted */
#define KS_DELETED 0x100 /* already deleted from kernel */
#define KS_CHECK 0x200
time_t k_keep;
#define K_KEEP_LIM 30
time_t k_redirect_time; /* when redirected route 1st seen */
@ -779,7 +807,7 @@ kern_add(naddr dst, naddr mask)
if (k != 0)
return k;
k = (struct khash *)malloc(sizeof(*k));
k = (struct khash *)rtmalloc(sizeof(*k), "kern_add");
memset(k, 0, sizeof(*k));
k->k_dst = dst;
@ -800,22 +828,24 @@ kern_check_static(struct khash *k,
struct interface *ifp)
{
struct rt_entry *rt;
naddr int_addr;
struct rt_spare new;
if (k->k_metric == 0)
return;
int_addr = (ifp != 0) ? ifp->int_addr : loopaddr;
bzero(&new, sizeof(new));
new.rts_ifp = ifp;
new.rts_gate = k->k_gate;
new.rts_router = (ifp != 0) ? ifp->int_addr : loopaddr;
new.rts_metric = k->k_metric;
new.rts_time = now.tv_sec;
rt = rtget(k->k_dst, k->k_mask);
if (rt != 0) {
if (!(rt->rt_state & RS_STATIC))
rtchange(rt, rt->rt_state | RS_STATIC,
k->k_gate, int_addr,
k->k_metric, 0, ifp, now.tv_sec, 0);
rtchange(rt, rt->rt_state | RS_STATIC, &new, 0);
} else {
rtadd(k->k_dst, k->k_mask, k->k_gate, int_addr,
k->k_metric, 0, RS_STATIC, ifp);
rtadd(k->k_dst, k->k_mask, RS_STATIC, &new);
}
}
@ -871,23 +901,29 @@ rtm_add(struct rt_msghdr *rtm,
return;
}
if (INFO_GATE(info) == 0
|| INFO_GATE(info)->sa_family != AF_INET) {
msglog("ignore %s without gateway",
rtm_type_name(rtm->rtm_type));
return;
}
k = kern_add(S_ADDR(INFO_DST(info)), mask);
if (k->k_state & KS_NEW)
k->k_keep = now.tv_sec+keep;
k->k_gate = S_ADDR(INFO_GATE(info));
k->k_metric = rtm->rtm_rmx.rmx_hopcount;
if (k->k_metric < 0)
k->k_metric = 0;
else if (k->k_metric > HOPCNT_INFINITY)
k->k_metric = HOPCNT_INFINITY;
k->k_state &= ~(KS_DELETED | KS_GATEWAY | KS_STATIC | KS_NEW);
if (INFO_GATE(info) == 0) {
trace_act("note %s without gateway",
rtm_type_name(rtm->rtm_type));
k->k_metric = HOPCNT_INFINITY;
} else if (INFO_GATE(info)->sa_family != AF_INET) {
trace_act("note %s with gateway AF=%d",
rtm_type_name(rtm->rtm_type),
INFO_GATE(info)->sa_family);
k->k_metric = HOPCNT_INFINITY;
} else {
k->k_gate = S_ADDR(INFO_GATE(info));
k->k_metric = rtm->rtm_rmx.rmx_hopcount;
if (k->k_metric < 0)
k->k_metric = 0;
else if (k->k_metric > HOPCNT_INFINITY-1)
k->k_metric = HOPCNT_INFINITY-1;
}
k->k_state &= ~(KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD
| KS_DELETED | KS_GATEWAY | KS_STATIC
| KS_NEW | KS_CHECK);
if (rtm->rtm_flags & RTF_GATEWAY)
k->k_state |= KS_GATEWAY;
if (rtm->rtm_flags & RTF_STATIC)
@ -961,44 +997,104 @@ rtm_lose(struct rt_msghdr *rtm,
return;
}
if (!supplier)
if (rdisc_ok)
rdisc_age(S_ADDR(INFO_GATE(info)));
age(S_ADDR(INFO_GATE(info)));
}
/* Make the gateway slot of an info structure point to something
* useful. If it is not already useful, but it specifies an interface,
* then fill in the sockaddr_in provided and point it there.
*/
static int
get_info_gate(struct sockaddr **sap,
struct sockaddr_in *sin)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)*sap;
struct interface *ifp;
if (sdl == 0)
return 0;
if ((sdl)->sdl_family == AF_INET)
return 1;
if ((sdl)->sdl_family != AF_LINK)
return 0;
ifp = ifwithindex(sdl->sdl_index, 1);
if (ifp == 0)
return 0;
sin->sin_addr.s_addr = ifp->int_addr;
#ifdef _HAVE_SA_LEN
sin->sin_len = sizeof(*sin);
#endif
sin->sin_family = AF_INET;
*sap = (struct sockaddr*)sin;
return 1;
}
/* Clean the kernel table by copying it to the daemon image.
* Eventually the daemon will delete any extra routes.
*/
void
flush_kern(void)
{
static char *sysctl_buf;
static size_t sysctl_buf_size = 0;
size_t needed;
int mib[6];
char *buf, *next, *lim;
char *next, *lim;
struct rt_msghdr *rtm;
struct interface *ifp;
static struct sockaddr_in gate_sa;
struct sockaddr_in gate_sin;
struct rt_addrinfo info;
int i;
struct khash *k;
for (i = 0; i < KHASH_SIZE; i++) {
for (k = khash_bins[i]; k != 0; k = k->k_next) {
k->k_state |= KS_CHECK;
}
}
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[4] = NET_RT_DUMP;
mib[5] = 0; /* no flags */
if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) {
DBGERR(1,"RT_DUMP-sysctl-estimate");
return;
for (;;) {
if ((needed = sysctl_buf_size) != 0) {
if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0)
break;
if (errno != ENOMEM && errno != EFAULT)
BADERR(1,"flush_kern: sysctl(RT_DUMP)");
free(sysctl_buf);
needed = 0;
}
if (sysctl(mib, 6, 0, &needed, 0, 0) < 0)
BADERR(1,"flush_kern: sysctl(RT_DUMP) estimate");
/* Kludge around the habit of some systems, such as
* BSD/OS 3.1, to not admit how many routes are in the
* kernel, or at least to be quite wrong.
*/
needed += 50*(sizeof(*rtm)+5*sizeof(struct sockaddr));
sysctl_buf = rtmalloc(sysctl_buf_size = needed,
"flush_kern sysctl(RT_DUMP)");
}
buf = malloc(needed);
if (sysctl(mib, 6, buf, &needed, 0, 0) < 0)
BADERR(1,"RT_DUMP");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
lim = sysctl_buf + needed;
for (next = sysctl_buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_msglen == 0) {
msglog("zero length kernel route at "
" %#x in buffer %#x before %#x",
rtm, sysctl_buf, lim);
break;
}
rt_xaddrs(&info,
(struct sockaddr *)(rtm+1),
@ -1015,32 +1111,14 @@ flush_kern(void)
if (rtm->rtm_flags & RTF_LLINFO)
continue;
if (INFO_GATE(&info) == 0)
continue;
if (INFO_GATE(&info)->sa_family != AF_INET) {
if (INFO_GATE(&info)->sa_family != AF_LINK)
continue;
ifp = ifwithindex(((struct sockaddr_dl *)
INFO_GATE(&info))->sdl_index, 0);
if (ifp == 0)
continue;
if ((ifp->int_if_flags & IFF_POINTOPOINT)
|| S_ADDR(INFO_DST(&info)) == ifp->int_addr)
gate_sa.sin_addr.s_addr = ifp->int_addr;
else
gate_sa.sin_addr.s_addr = htonl(ifp->int_net);
#ifdef _HAVE_SA_LEN
gate_sa.sin_len = sizeof(gate_sa);
#endif
gate_sa.sin_family = AF_INET;
INFO_GATE(&info) = (struct sockaddr *)&gate_sa;
}
/* ignore multicast addresses
*/
if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info)))))
continue;
if (!get_info_gate(&INFO_GATE(&info), &gate_sin))
continue;
/* Note static routes and interface routes, and also
* preload the image of the kernel table so that
* we can later clean it, as well as avoid making
@ -1050,7 +1128,17 @@ flush_kern(void)
*/
rtm_add(rtm,&info,MIN_WAITTIME);
}
free(buf);
for (i = 0; i < KHASH_SIZE; i++) {
for (k = khash_bins[i]; k != 0; k = k->k_next) {
if (k->k_state & KS_CHECK) {
msglog("%s --> %s disappeared from kernel",
addrname(k->k_dst, k->k_mask, 0),
naddr_ntoa(k->k_gate));
del_static(k->k_dst, k->k_mask, k->k_gate, 1);
}
}
}
}
@ -1061,7 +1149,8 @@ read_rt(void)
{
long cc;
struct interface *ifp;
naddr mask;
struct sockaddr_in gate_sin;
naddr mask, gate;
union {
struct {
struct rt_msghdr rtm;
@ -1106,7 +1195,7 @@ read_rt(void)
m.r.rtm.rtm_type != RTM_DELADDR);
if (ifp == 0)
trace_act("note %s with flags %#x"
" for interface index #%d",
" for unknown interface index #%d",
rtm_type_name(m.r.rtm.rtm_type),
m.ifm.ifm_flags,
m.ifm.ifm_index);
@ -1125,7 +1214,7 @@ read_rt(void)
if (ifinit_timer.tv_sec-now.tv_sec>=CHECK_BAD_INTERVAL
|| ifp == 0
|| ((ifp->int_if_flags ^ m.ifm.ifm_flags)
& IFF_UP_RUNNING) != 0)
& IFF_UP) != 0)
ifinit_timer.tv_sec = now.tv_sec;
continue;
}
@ -1162,11 +1251,18 @@ read_rt(void)
trace_act("ignore multicast %s", str);
continue;
}
if (m.r.rtm.rtm_flags & RTF_LLINFO) {
trace_act("ignore ARP %s", str);
continue;
}
if (INFO_GATE(&info) != 0
&& INFO_GATE(&info)->sa_family == AF_INET)
strp += sprintf(strp, " --> %s",
saddr_ntoa(INFO_GATE(&info)));
if (get_info_gate(&INFO_GATE(&info), &gate_sin)) {
gate = S_ADDR(INFO_GATE(&info));
strp += sprintf(strp, " --> %s", naddr_ntoa(gate));
} else {
gate = 0;
}
if (INFO_AUTHOR(&info) != 0)
strp += sprintf(strp, " by authority of %s",
@ -1186,12 +1282,14 @@ read_rt(void)
break;
case RTM_DELETE:
if (m.r.rtm.rtm_errno != 0) {
if (m.r.rtm.rtm_errno != 0
&& m.r.rtm.rtm_errno != ESRCH) {
trace_act("ignore %s with \"%s\" error",
str, strerror(m.r.rtm.rtm_errno));
} else {
trace_act("%s", str);
del_static(S_ADDR(INFO_DST(&info)), mask, 1);
del_static(S_ADDR(INFO_DST(&info)), mask,
gate, 1);
}
break;
@ -1244,12 +1342,20 @@ kern_out(struct ag_info *ag)
/* modify existing kernel entry if necessary */
if (k->k_gate != ag->ag_gate
|| k->k_metric != ag->ag_metric) {
/* Must delete bad interface routes etc. to change them. */
if (k->k_metric == HOPCNT_INFINITY)
k->k_state |= KS_DEL_ADD;
k->k_gate = ag->ag_gate;
k->k_metric = ag->ag_metric;
k->k_state |= KS_CHANGE;
}
if (k->k_state & KS_DYNAMIC) {
/* If the daemon thinks the route should exist, forget
* about any redirections.
* If the daemon thinks the route should exist, eventually
* override manual intervention by the operator.
*/
if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) {
k->k_state &= ~KS_DYNAMIC;
k->k_state |= (KS_ADD | KS_DEL_ADD);
}
@ -1291,15 +1397,33 @@ walk_kern(struct radix_node *rn, struct walkarg *argp)
return 0;
if (!(RT->rt_state & RS_IF)) {
ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE);
/* This is an ordinary route, not for an interface.
*/
/* aggregate, ordinary good routes without regard to
* their metric
*/
pref = 1;
ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE);
/* Do not install host routes directly to hosts, to avoid
* interfering with ARP entries in the kernel table.
*/
if (RT_ISHOST(RT)
&& ntohl(RT->rt_dst) == RT->rt_gate)
return 0;
} else {
/* Do not install routes for "external" remote interfaces.
/* This is an interface route.
* Do not install routes for "external" remote interfaces.
*/
if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL))
return 0;
ags |= AGS_IF;
/* Interfaces should override received routes.
*/
pref = 0;
ags |= (AGS_IF | AGS_CORS_GATE);
/* If it is not an interface, or an alias for an interface,
* it must be a "gateway."
@ -1309,19 +1433,23 @@ walk_kern(struct radix_node *rn, struct walkarg *argp)
*/
if (RT->rt_ifp == 0
|| (RT->rt_ifp->int_state & IS_REMOTE))
ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE);
ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE);
}
if (RT->rt_state & RS_RDISC)
/* If RIP is off and IRDP is on, let the route to the discovered
* route suppress any RIP routes. Eventually the RIP routes
* will time-out and be deleted. This reaches the steady-state
* quicker.
*/
if ((RT->rt_state & RS_RDISC) && rip_sock < 0)
ags |= AGS_CORS_GATE;
/* aggregate good routes without regard to their metric */
pref = 1;
metric = RT->rt_metric;
if (metric == HOPCNT_INFINITY) {
/* if the route is dead, so try hard to aggregate. */
pref = HOPCNT_INFINITY;
ags |= (AGS_FINE_GATE | AGS_SUPPRESS);
ags &= ~(AGS_IF | AGS_CORS_GATE);
}
ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0,
@ -1358,7 +1486,9 @@ fix_kern(void)
/* check hold on routes deleted by the operator */
if (k->k_keep > now.tv_sec) {
/* ensure we check when the hold is over */
LIM_SEC(need_kern, k->k_keep);
/* mark for the next cycle */
k->k_state |= KS_DELETE;
pk = &k->k_next;
continue;
@ -1406,6 +1536,7 @@ fix_kern(void)
void
del_static(naddr dst,
naddr mask,
naddr gate,
int gone)
{
struct khash *k;
@ -1419,8 +1550,8 @@ del_static(naddr dst,
* and add a replacement.
*/
k = kern_find(dst, mask, 0);
if (k != 0) {
k->k_state &= ~(KS_STATIC | KS_DYNAMIC);
if (k != 0 && (gate == 0 || k->k_gate == gate)) {
k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK);
k->k_state |= KS_DELETE;
if (gone) {
k->k_state |= KS_DELETED;
@ -1547,12 +1678,8 @@ rtfind(naddr dst)
void
rtadd(naddr dst,
naddr mask,
naddr gate, /* forward packets here */
naddr router, /* on the authority of this router */
int metric,
u_short tag,
u_int state, /* rs_state for the entry */
struct interface *ifp)
u_int state, /* rt_state for the entry */
struct rt_spare *new)
{
struct rt_entry *rt;
naddr smask;
@ -1579,13 +1706,9 @@ rtadd(naddr dst,
masktrim(&mask_sock);
rt->rt_mask = mask;
rt->rt_state = state;
rt->rt_gate = gate;
rt->rt_router = router;
rt->rt_spares[0] = *new;
rt->rt_time = now.tv_sec;
rt->rt_metric = metric;
rt->rt_poison_metric = HOPCNT_INFINITY;
rt->rt_tag = tag;
rt->rt_ifp = ifp;
rt->rt_seqno = update_seqno;
if (++total_routes == MAX_ROUTES)
@ -1609,29 +1732,24 @@ rtadd(naddr dst,
void
rtchange(struct rt_entry *rt,
u_int state, /* new state bits */
naddr gate, /* now forward packets here */
naddr router, /* on the authority of this router */
int metric, /* new metric */
u_short tag,
struct interface *ifp,
time_t new_time,
struct rt_spare *new,
char *label)
{
if (rt->rt_metric != metric) {
if (rt->rt_metric != new->rts_metric) {
/* Fix the kernel immediately if it seems the route
* has gone bad, since there may be a working route that
* aggregates this route.
*/
if (metric == HOPCNT_INFINITY) {
if (new->rts_metric == HOPCNT_INFINITY) {
need_kern.tv_sec = now.tv_sec;
if (new_time >= now.tv_sec - EXPIRE_TIME)
new_time = now.tv_sec - EXPIRE_TIME;
if (new->rts_time >= now.tv_sec - EXPIRE_TIME)
new->rts_time = now.tv_sec - EXPIRE_TIME;
}
rt->rt_seqno = update_seqno;
set_need_flash();
}
if (rt->rt_gate != gate) {
if (rt->rt_gate != new->rts_gate) {
need_kern.tv_sec = now.tv_sec;
rt->rt_seqno = update_seqno;
set_need_flash();
@ -1641,21 +1759,15 @@ rtchange(struct rt_entry *rt,
/* Keep various things from deciding ageless routes are stale.
*/
if (!AGE_RT(state, ifp))
new_time = now.tv_sec;
if (!AGE_RT(state, new->rts_ifp))
new->rts_time = now.tv_sec;
if (TRACEACTIONS)
trace_change(rt, state, gate, router, metric, tag, ifp,
new_time,
trace_change(rt, state, new,
label ? label : "Chg ");
rt->rt_state = state;
rt->rt_gate = gate;
rt->rt_router = router;
rt->rt_metric = metric;
rt->rt_tag = tag;
rt->rt_ifp = ifp;
rt->rt_time = new_time;
rt->rt_spares[0] = *new;
}
@ -1704,9 +1816,7 @@ rtswitch(struct rt_entry *rt,
swap = rt->rt_spares[0];
(void)sprintf(label, "Use #%d", (int)(rts - rt->rt_spares));
rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC),
rts->rts_gate, rts->rts_router, rts->rts_metric,
rts->rts_tag, rts->rts_ifp, rts->rts_time, label);
rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), rts, label);
if (swap.rts_metric == HOPCNT_INFINITY) {
*rts = rts_empty;
} else {
@ -1747,7 +1857,7 @@ void
rts_delete(struct rt_entry *rt,
struct rt_spare *rts)
{
trace_upslot(rt, rts, 0, 0, 0, HOPCNT_INFINITY, 0, 0);
trace_upslot(rt, rts, &rts_empty);
*rts = rts_empty;
}
@ -1757,11 +1867,12 @@ rts_delete(struct rt_entry *rt,
void
rtbad(struct rt_entry *rt)
{
/* Poison the route */
rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC),
rt->rt_gate, rt->rt_router, HOPCNT_INFINITY, rt->rt_tag,
0, rt->rt_time, 0);
struct rt_spare new;
/* Poison the route */
new = rt->rt_spares[0];
new.rts_metric = HOPCNT_INFINITY;
rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), &new, 0);
rtswitch(rt, 0);
}
@ -1826,10 +1937,10 @@ rtbad_sub(struct rt_entry *rt)
}
if (ifp1 != 0 || (state & RS_NET_SYN)) {
rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN | RS_LOCAL))
| state),
rt->rt_gate, rt->rt_router, rt->rt_metric,
rt->rt_tag, ifp1, rt->rt_time, 0);
struct rt_spare new = rt->rt_spares[0];
new.rts_ifp = ifp1;
rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state),
&new, 0);
} else {
rtbad(rt);
}
@ -1924,7 +2035,8 @@ walk_age(struct radix_node *rn, struct walkarg *argp)
/* trash the spare routes when they go bad */
if (rts->rts_metric < HOPCNT_INFINITY
&& now_garbage > rts->rts_time)
&& now_garbage > rts->rts_time
&& i != NUM_SPARES)
rts_delete(RT, rts);
}
@ -1943,10 +2055,11 @@ walk_age(struct radix_node *rn, struct walkarg *argp)
}
/* Start poisoning a bad route before deleting it. */
if (now.tv_sec - RT->rt_time > EXPIRE_TIME)
rtchange(RT, RT->rt_state, RT->rt_gate, RT->rt_router,
HOPCNT_INFINITY, RT->rt_tag, RT->rt_ifp,
RT->rt_time, 0);
if (now.tv_sec - RT->rt_time > EXPIRE_TIME) {
struct rt_spare new = RT->rt_spares[0];
new.rts_metric = HOPCNT_INFINITY;
rtchange(RT, RT->rt_state, &new, 0);
}
return 0;
}
@ -1975,6 +2088,7 @@ age(naddr bad_gate)
/* ignore unreachable remote interfaces */
if (!check_remote(ifp))
continue;
/* Restore remote interface that has become reachable
*/
if (ifp->int_state & IS_BROKE)
@ -2004,6 +2118,11 @@ age(naddr bad_gate)
age_bad_gate = bad_gate;
(void)rn_walktree(rhead, walk_age, 0);
/* delete old redirected routes to keep the kernel table small
* and prevent blackholes
*/
del_redirects(bad_gate, now.tv_sec-STALE_TIME);
/* Update the kernel routing table. */
fix_kern();

View File

@ -1,4 +1,4 @@
/* $NetBSD: trace.c,v 1.20 1997/10/19 18:23:55 mycroft Exp $ */
/* $NetBSD: trace.c,v 1.21 1998/06/02 18:02:56 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -37,7 +37,7 @@
static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
#elif defined(__NetBSD__)
#include <sys/cdefs.h>
__RCSID("$NetBSD: trace.c,v 1.20 1997/10/19 18:23:55 mycroft Exp $");
__RCSID("$NetBSD: trace.c,v 1.21 1998/06/02 18:02:56 thorpej Exp $");
#endif
#define RIPCMDS
@ -193,8 +193,8 @@ tmsg(char *p, ...)
}
static void
trace_close(void)
void
trace_close(int zap_stdio)
{
int fd;
@ -202,14 +202,17 @@ trace_close(void)
fflush(stdout);
fflush(stderr);
if (ftrace != 0 && file_trace) {
if (ftrace != 0 && zap_stdio) {
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);
if (isatty(STDIN_FILENO))
(void)dup2(fd, STDIN_FILENO);
if (isatty(STDOUT_FILENO))
(void)dup2(fd, STDOUT_FILENO);
if (isatty(STDERR_FILENO))
(void)dup2(fd, STDERR_FILENO);
(void)close(fd);
}
lastlog_time.tv_sec = 0;
@ -239,7 +242,7 @@ trace_off(char *p, ...)
vfprintf(ftrace, p, args);
(void)fputc('\n',ftrace);
}
trace_close();
trace_close(file_trace);
new_tracelevel = tracelevel = 0;
}
@ -361,8 +364,7 @@ set_tracefile(char *filename,
tmsg("switch to trace file %s", fn);
file_trace = 1;
trace_close();
trace_close(file_trace = 1);
if (fn != savetracename)
strncpy(savetracename, fn, sizeof(savetracename)-1);
@ -597,6 +599,9 @@ print_rts(struct rt_spare *rts,
int force_tag, /* -1=suppress, 0=default, 1=display */
int force_time) /* 0=suppress, 1=display */
{
int i;
if (force_metric >= 0)
(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
if (force_ifp >= 0)
@ -610,8 +615,13 @@ print_rts(struct rt_spare *rts,
(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)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
if (rts->rts_de_ag != 0) {
for (i = 1; (1 << i) <= rts->rts_de_ag; i++)
continue;
(void)fprintf(ftrace, "de_ag=%d ", i);
}
}
@ -644,78 +654,69 @@ trace_if(char *act,
void
trace_upslot(struct rt_entry *rt,
struct rt_spare *rts,
naddr gate,
naddr router,
struct interface *ifp,
int metric,
u_short tag,
time_t new_time)
struct rt_spare *new)
{
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)
if (rts->rts_gate == new->rts_gate
&& rts->rts_router == new->rts_router
&& rts->rts_metric == new->rts_metric
&& rts->rts_tag == new->rts_tag
&& rts->rts_de_ag == new->rts_de_ag)
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 (gate == 0) {
if (new->rts_gate == 0) {
(void)fprintf(ftrace, "Del #%d %-35s ",
(int)(rts - rt->rt_spares),
rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
print_rts(&new, 0,0,0,0,
rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp));
print_rts(rts, 0,0,0,0,
(rts != rt->rt_spares
|| AGE_RT(rt->rt_state,new->rts_ifp)));
} else if (rts->rts_gate != RIP_DEFAULT) {
(void)fprintf(ftrace, "Chg #%d %-35s ",
(int)(rts - rt->rt_spares),
rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
print_rts(rts, 0,0,
rts->rts_gate != gate,
rts->rts_tag != tag,
rts->rts_gate != new->rts_gate,
rts->rts_tag != new->rts_tag,
rts != rt->rt_spares || AGE_RT(rt->rt_state,
rt->rt_ifp));
(void)fprintf(ftrace, "\n %19s%-16s ", "",
gate != rts->rts_gate ? naddr_ntoa(gate) : "");
print_rts(&new,
-(metric == rts->rts_metric),
-(ifp == rts->rts_ifp),
(new->rts_gate != rts->rts_gate
? naddr_ntoa(new->rts_gate) : ""));
print_rts(new,
-(new->rts_metric == rts->rts_metric),
-(new->rts_ifp == rts->rts_ifp),
0,
rts->rts_tag != tag,
new_time != rts->rts_time && (rts != rt->rt_spares
|| AGE_RT(rt->rt_state,
ifp)));
rts->rts_tag != new->rts_tag,
(new->rts_time != rts->rts_time
&& (rts != rt->rt_spares
|| AGE_RT(rt->rt_state, new->rts_ifp))));
} else {
(void)fprintf(ftrace, "Add #%d %-35s ",
(int)(rts - rt->rt_spares),
rtname(rt->rt_dst, rt->rt_mask, gate));
print_rts(&new, 0,0,0,0,
rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp));
rtname(rt->rt_dst, rt->rt_mask, new->rts_gate));
print_rts(new, 0,0,0,0,
(rts != rt->rt_spares
|| AGE_RT(rt->rt_state,new->rts_ifp)));
}
(void)fputc('\n',ftrace);
}
/* talk about a change made to the kernel table
/* miscellaneous message checked by the caller
*/
void
trace_kernel(char *p, ...)
trace_misc(char *p, ...)
{
va_list args;
if (!TRACEKERNEL || ftrace == 0)
if (ftrace == 0)
return;
lastlog();
@ -762,31 +763,19 @@ trace_pkt(char *p, ...)
void
trace_change(struct rt_entry *rt,
u_int state,
naddr gate, /* forward packets here */
naddr router, /* on the authority of this router */
int metric,
u_short tag,
struct interface *ifp,
time_t new_time,
struct rt_spare *new,
char *label)
{
struct rt_spare new;
if (ftrace == 0)
return;
if (rt->rt_metric == metric
&& rt->rt_gate == gate
&& rt->rt_router == router
if (rt->rt_metric == new->rts_metric
&& rt->rt_gate == new->rts_gate
&& rt->rt_router == new->rts_router
&& rt->rt_state == state
&& rt->rt_tag == tag)
&& rt->rt_tag == new->rts_tag
&& rt->rt_de_ag == new->rts_de_ag)
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 ",
@ -798,13 +787,15 @@ trace_change(struct rt_entry *rt,
(void)fprintf(ftrace, "\n%*s %19s%-16s ",
(int)strlen(label), "", "",
rt->rt_gate != gate ? naddr_ntoa(gate) : "");
print_rts(&new,
-(metric == rt->rt_metric),
-(ifp == rt->rt_ifp),
(rt->rt_gate != new->rts_gate
? naddr_ntoa(new->rts_gate) : ""));
print_rts(new,
-(new->rts_metric == rt->rt_metric),
-(new->rts_ifp == rt->rt_ifp),
0,
rt->rt_tag != tag,
rt->rt_time != new_time && AGE_RT(rt->rt_state,ifp));
rt->rt_tag != new->rts_tag,
(rt->rt_time != new->rts_time
&& AGE_RT(rt->rt_state,new->rts_ifp)));
if (rt->rt_state != state)
trace_bits(rs_bits, state, 1);
(void)fputc('\n',ftrace);