diff --git a/usr.sbin/routed/Makefile b/usr.sbin/routed/Makefile deleted file mode 100644 index b17fd70ab04b..000000000000 --- a/usr.sbin/routed/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# From: @(#)Makefile 8.1 (Berkeley) 6/19/93 -# $Id$ - -PROG= routed -SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c -MAN8= routed.8 -SUBDIR= rtquery -#COPTS= -g -DDEBUG -Wall - -.include diff --git a/usr.sbin/routed/Makefile.inc b/usr.sbin/routed/Makefile.inc deleted file mode 100644 index 10fa13f1ed80..000000000000 --- a/usr.sbin/routed/Makefile.inc +++ /dev/null @@ -1 +0,0 @@ -.include "../../Makefile.inc" diff --git a/usr.sbin/routed/defs.h b/usr.sbin/routed/defs.h deleted file mode 100644 index 05c2403c7470..000000000000 --- a/usr.sbin/routed/defs.h +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)defs.h 8.1 (Berkeley) 6/5/93 - * $Id: defs.h,v 1.4 1996/07/22 21:12:14 wollman Exp $ - */ - -#ifndef __NetBSD__ -#ident "$Revision: 1.1.3.3 $" -#endif - -/* Definitions for RIPv2 routing process. - * - * This code is based on the 4.4BSD `routed` daemon, with extensions to - * support: - * RIPv2, including variable length subnet masks. - * Router Discovery - * aggregate routes in the kernel tables. - * aggregate advertised routes. - * maintain spare routes for faster selection of another gateway - * when the current gateway dies. - * timers on routes with second granularity so that selection - * of a new route does not wait 30-60 seconds. - * tolerance of static routes. - * tell the kernel hop counts - * do not advertise if ipforwarding=0 - * - * The vestigual support for other protocols has been removed. There - * is no likelihood that IETF RIPv1 or RIPv2 will ever be used with - * other protocols. The result is far smaller, faster, cleaner, and - * perhaps understandable. - * - * The accumulation of special flags and kludges added over the many - * years have been simplified and integrated. - */ - -#include -#include -#include -#include -#include -#include -#ifdef sgi -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef sgi -#include -#else -#include "radix.h" -#endif -#include -#include -#include -#include -#include -#define RIPVERSION RIPv2 -#include - - -/* Type of an IP address. - * Some systems do not like to pass structures, so do not use in_addr. - * Some systems think a long has 64 bits, which would be a gross waste. - * So define it here so it can be changed for the target system. - * It should be defined somewhere netinet/in.h, but it is not. - */ -#ifdef sgi -#define naddr __uint32_t -#else -#ifdef __NetBSD__ -#define naddr u_int32_t -#else -#define naddr u_long -#endif -#define _HAVE_SA_LEN -#define _HAVE_SIN_LEN -#endif - -/* Turn on if IP_DROP_MEMBERSHIP and IP_ADD_MEMBERSHIP do not look at - * the dstaddr of point-to-point interfaces. - */ -/* #define MCAST_PPP_BUG */ - -#define NEVER (24*60*60) /* a long time */ -#define EPOCH NEVER /* bias time by this to avoid <0 */ - -/* Scan the kernel regularly to see if any interfaces have appeared or been - * turned off. These must be less than STALE_TIME. - */ -#define CHECK_BAD_INTERVAL 5 /* when an interface is known bad */ -#define CHECK_ACT_INTERVAL 30 /* when advertising */ -#define CHECK_QUIET_INTERVAL 300 /* when not */ - -#define LIM_SEC(s,l) ((s).tv_sec = MIN((s).tv_sec, (l))) - - -/* Router Discovery parameters */ -#ifndef sgi -#define INADDR_ALLROUTERS_GROUP 0xe0000002 /* 224.0.0.2 */ -#endif -#define MaxMaxAdvertiseInterval 1800 -#define MinMaxAdvertiseInterval 4 -#define DefMaxAdvertiseInterval 600 -#define DEF_PreferenceLevel 0 -#define MIN_PreferenceLevel 0x80000000 - -#define MAX_INITIAL_ADVERT_INTERVAL 16 -#define MAX_INITIAL_ADVERTS 3 -#define MAX_RESPONSE_DELAY 2 - -#define MAX_SOLICITATION_DELAY 1 -#define SOLICITATION_INTERVAL 3 -#define MAX_SOLICITATIONS 3 - - -/* typical packet buffers */ -union pkt_buf { - char packet[MAXPACKETSIZE+1]; - struct rip rip; -}; - - -/* no more routes than this, to protect ourself in case something goes - * whacko and starts broadcast zillions of bogus routes. - */ -#define MAX_ROUTES (128*1024) -extern int total_routes; - -/* Main, daemon routing table structure - */ -struct rt_entry { - struct radix_node rt_nodes[2]; /* radix tree glue */ - u_int rt_state; -# define RS_IF 0x001 /* for network interface */ -# define RS_NET_INT 0x002 /* authority route */ -# define RS_NET_SYN 0x004 /* fake net route for subnet */ -# define RS_NO_NET_SYN (RS_LOCAL | RS_LOCAL | RS_IF) -# define RS_SUBNET 0x008 /* subnet route from any source */ -# define RS_LOCAL 0x010 /* loopback for pt-to-pt */ -# define RS_MHOME 0x020 /* from -m */ -# define RS_STATIC 0x040 /* from the kernel */ -# define RS_RDISC 0x080 /* from router discovery */ -# define RS_PERMANENT (RS_MHOME | RS_STATIC | RS_NET_SYN | RS_RDISC) - struct sockaddr_in rt_dst_sock; - naddr rt_mask; - struct rt_spare { - struct interface *rts_ifp; - naddr rts_gate; /* forward packets here */ - naddr rts_router; /* on the authority of this router */ - char rts_metric; - u_short rts_tag; - time_t rts_time; /* timer to junk stale routes */ -#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 HOST_MASK 0xffffffff -#define RT_ISHOST(rt) ((rt)->rt_mask == HOST_MASK) - -/* age all routes that - * are not from -g, -m, or static routes from the kernel - * not unbroken interface routes - * but not broken interfaces - * nor non-passive, remote interfaces that are not aliases - * (i.e. remote & metric=0) - */ -#define AGE_RT(rt,ifp) (0 == ((rt)->rt_state & RS_PERMANENT) \ - && (!((rt)->rt_state & RS_IF) \ - || (ifp) == 0 \ - || (((ifp)->int_state & IS_REMOTE) \ - && !((ifp)->int_state & IS_PASSIVE)))) - -/* true if A is better than B - * Better if - * - A is not a poisoned route - * - and A is not stale - * - and A has a shorter path - * - or is the router speaking for itself - * - or the current route is equal but stale - * - or it is a host route advertised by a system for itself - */ -#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \ - && now_stale <= (A)->rts_time \ - && ((A)->rts_metric < (B)->rts_metric \ - || ((A)->rts_gate == (A)->rts_router \ - && (B)->rts_gate != (B)->rts_router) \ - || ((A)->rts_metric == (B)->rts_metric \ - && now_stale > (B)->rts_time) \ - || (RT_ISHOST(rt) \ - && (rt)->rt_dst == (A)->rts_router \ - && (A)->rts_metric == (B)->rts_metric))) - - -/* An "interface" is similar to a kernel ifnet structure, except it also - * handles "logical" or "IS_REMOTE" interfaces (remote gateways). - */ -struct interface { - struct interface *int_next, *int_prev; - char int_name[IFNAMSIZ+15+1]; /* big enough for IS_REMOTE */ - u_short int_index; - naddr int_addr; /* address on this host (net order) */ - naddr int_brdaddr; /* broadcast address (n) */ - naddr int_dstaddr; /* other end of pt-to-pt link (n) */ - naddr int_net; /* working network # (host order)*/ - naddr int_mask; /* working net mask (host order) */ - naddr int_ripv1_mask; /* for inferring a mask (n) */ - naddr int_std_addr; /* class A/B/C address (n) */ - naddr int_std_net; /* class A/B/C network (h) */ - naddr int_std_mask; /* class A/B/C netmask (h) */ - int int_rip_sock; /* for queries */ - int int_if_flags; /* copied from kernel */ - u_int int_state; - time_t int_act_time; /* last thought healthy */ - u_short int_transitions; /* times gone up-down */ - char int_metric; - char int_d_metric; /* for faked default route */ - struct int_data { - u_int ipackets; /* previous network stats */ - u_int ierrors; - u_int opackets; - u_int oerrors; -#ifdef sgi - u_int odrops; -#endif - time_t ts; /* timestamp on network stats */ - } int_data; - char int_passwd[RIP_AUTH_PW_LEN]; /* RIPv2 password */ - int int_rdisc_pref; /* advertised rdisc preference */ - int int_rdisc_int; /* MaxAdvertiseInterval */ - int int_rdisc_cnt; - struct timeval int_rdisc_timer; -}; - -#define IS_ALIAS 0x0000001 /* interface alias */ -#define IS_SUBNET 0x0000002 /* interface on subnetted network */ -#define IS_REMOTE 0x0000004 /* interface is not on this machine */ -#define IS_PASSIVE 0x0000008 /* remote and does not do RIP */ -#define IS_EXTERNAL 0x0000010 /* handled by EGP or something */ -#define IS_CHECKED 0x0000020 /* still exists */ -#define IS_ALL_HOSTS 0x0000040 /* in INADDR_ALLHOSTS_GROUP */ -#define IS_ALL_ROUTERS 0x0000080 /* in INADDR_ALLROUTERS_GROUP */ -#define IS_RIP_QUERIED 0x0000100 /* query broadcast */ -#define IS_BROKE 0x0000200 /* seems to be broken */ -#define IS_SICK 0x0000400 /* seems to be broken */ -#define IS_DUP 0x0000800 /* has a duplicate address */ -#define IS_ACTIVE 0x0001000 /* heard from it at least once */ -#define IS_NEED_NET_SYN 0x0002000 /* need RS_NET_SYN route */ -#define IS_NO_AG 0x0004000 /* do not aggregate subnets */ -#define IS_NO_SUPER_AG 0x0008000 /* do not aggregate networks */ -#define IS_NO_RIPV1_IN 0x0010000 /* no RIPv1 input at all */ -#define IS_NO_RIPV2_IN 0x0020000 /* no RIPv2 input at all */ -#define IS_NO_RIP_IN (IS_NO_RIPV1_IN | IS_NO_RIPV2_IN) -#define IS_RIP_IN_OFF(s) (((s) & IS_NO_RIP_IN) == IS_NO_RIP_IN) -#define IS_NO_RIPV1_OUT 0x0040000 /* no RIPv1 output at all */ -#define IS_NO_RIPV2_OUT 0x0080000 /* no RIPv2 output at all */ -#define IS_NO_RIP_OUT (IS_NO_RIPV1_OUT | IS_NO_RIPV2_OUT) -#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_RDISC (IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT) -#define IS_PM_RDISC 0x4000000 /* 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) - - -/* Information for aggregating routes */ -#define NUM_AG_SLOTS 32 -struct ag_info { - struct ag_info *ag_fine; /* slot with finer netmask */ - struct ag_info *ag_cors; /* more coarse netmask */ - naddr ag_dst_h; /* destination in host byte order */ - naddr ag_mask; - naddr ag_gate; - naddr ag_nhop; - char ag_metric; /* metric to be advertised */ - char ag_pref; /* aggregate based on this */ - u_int ag_seqno; - 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_REDUN0 0x004 /* redundant, finer routes output */ -#define AGS_REDUN1 0x008 -#define AG_IS_REDUN(state) (((state) & (AGS_REDUN0 | AGS_REDUN1)) \ - == (AGS_REDUN0 | AGS_REDUN1)) -#define AGS_GATEWAY 0x010 /* tell kernel RTF_GATEWAY */ -#define AGS_IF 0x020 /* for an interface */ -#define AGS_RIPV2 0x040 /* send only as RIPv2 */ -#define AGS_FINE_GATE 0x080 /* ignore differing ag_gate when this - * has the finer netmask */ -#define AGS_CORS_GATE 0x100 /* ignore differing gate when this - * has the coarser netmaks */ -#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) -}; - - -/* parameters for interfaces */ -extern struct parm { - struct parm *parm_next; - char parm_name[IFNAMSIZ+1]; - naddr parm_addr_h; - naddr parm_mask; - - char parm_d_metric; - u_int parm_int_state; - int parm_rdisc_pref; - int parm_rdisc_int; - char parm_passwd[RIP_AUTH_PW_LEN+1]; -} *parms; - -/* authority for internal networks */ -extern struct intnet { - struct intnet *intnet_next; - naddr intnet_addr; - naddr intnet_mask; - char intnet_metric; -} *intnets; - - - -extern pid_t mypid; -extern naddr myaddr; /* main address of this system */ - -extern int stopint; /* !=0 to stop */ - -extern int sock_max; -extern int rip_sock; /* RIP socket */ -extern struct interface *rip_sock_mcast; /* current multicast interface */ -extern int rt_sock; /* routing socket */ -extern int rt_sock_seqno; -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 ridhosts; /* 1=reduce host routes */ -extern int mhome; /* 1=want multi-homed host route */ -extern int advertise_mhome; /* 1=must continue adverising it */ -extern int auth_ok; /* 1=ignore auth if we do not care */ - -extern struct timeval epoch; /* when started */ -extern struct timeval now; /* current idea of time */ -extern time_t now_stale; -extern time_t now_garbage; - -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 struct timeval ifinit_timer; /* time to check interfaces */ - -extern naddr loopaddr; /* our address on loopback */ -extern int tot_interfaces; /* # of remote and local interfaces */ -extern int rip_interfaces; /* # of interfaces doing RIP */ -extern struct interface *ifnet; /* all interfaces */ -extern int have_ripv1_out; /* have a RIPv1 interface */ -extern int have_ripv1_in; -extern int need_flash; /* flash update needed */ -extern struct timeval need_kern; /* need to update kernel table */ -extern int update_seqno; /* a route has changed */ - -extern u_int tracelevel, new_tracelevel; -#define MAX_TRACELEVEL 3 -#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */ -#define TRACEPACKETS (tracelevel >= 2) /* note packets */ -#define TRACEACTIONS (tracelevel != 0) -extern FILE *ftrace; /* output trace file */ - -extern struct radix_node_head *rhead; - - -#ifdef sgi -/* Fix conflicts */ -#define dup2(x,y) BSDdup2(x,y) -#endif /* sgi */ - -extern void fix_sock(int, char *); -extern void fix_select(void); -extern void rip_off(void); -extern void rip_on(struct interface *); - -enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST, - NO_OUT_MULTICAST, NO_OUT_RIPV2}; -extern int output(enum output_type, struct sockaddr_in *, - struct interface *, struct rip *, int); -extern void rip_query(void); -extern void rip_bcast(int); -extern void supply(struct sockaddr_in *, struct interface *, - enum output_type, int, int); - -extern void msglog(char *, ...); -#define LOGERR(msg) msglog(msg ": %s", strerror(errno)) -extern void logbad(int, char *, ...); -#define BADERR(dump,msg) logbad(dump,msg ": %s", strerror(errno)) -#ifdef DEBUG -#define DBGERR(dump,msg) BADERR(dump,msg) -#else -#define DBGERR(dump,msg) LOGERR(msg) -#endif -extern char *naddr_ntoa(naddr); -extern char *saddr_ntoa(struct sockaddr *); - -extern void *rtmalloc(size_t, char *); -extern void timevaladd(struct timeval *, struct timeval *); -extern void intvl_random(struct timeval *, u_long, u_long); -extern int getnet(char *, naddr *, naddr *); -extern int gethost(char *, naddr *); -extern void gwkludge(void); -extern char *parse_parms(char *); -extern char *check_parms(struct parm *); -extern void get_parms(struct interface *); - -extern void lastlog(void); -extern void trace_on(char *, int); -extern void trace_off(char*, ...); -extern void trace_flush(void); -extern void set_tracelevel(void); -extern void 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_if(char *, struct interface *); -extern void trace_upslot(struct rt_entry *, struct rt_spare *, - naddr, naddr, - struct interface *, int, u_short, time_t); -extern void trace_rip(char*, char*, struct sockaddr_in *, - struct interface *, struct rip *, int); -extern char *addrname(naddr, naddr, int); - -extern void rdisc_age(naddr); -extern void set_rdisc_mg(struct interface *, int); -extern void set_supplier(void); -extern void if_bad_rdisc(struct interface *); -extern void if_ok_rdisc(struct interface *); -extern void read_rip(int, struct interface *); -extern void read_rt(void); -extern void read_d(void); -extern void rdisc_adv(void); -extern void rdisc_sol(void); - -extern void sigalrm(int); -extern void sigterm(int); - -extern void sigtrace_on(int); -extern void sigtrace_off(int); - -extern void flush_kern(void); -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_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 rtdelete(struct rt_entry *); -extern void rtbad_sub(struct rt_entry *); -extern void rtswitch(struct rt_entry *, struct rt_spare *); -extern void rtbad(struct rt_entry *); - - -#define S_ADDR(x) (((struct sockaddr_in *)(x))->sin_addr.s_addr) -#define INFO_DST(I) ((I)->rti_info[RTAX_DST]) -#define INFO_GATE(I) ((I)->rti_info[RTAX_GATEWAY]) -#define INFO_MASK(I) ((I)->rti_info[RTAX_NETMASK]) -#define INFO_IFA(I) ((I)->rti_info[RTAX_IFA]) -#define INFO_IFP(I) ((I)->rti_info[RTAX_IFP]) -#define INFO_AUTHOR(I) ((I)->rti_info[RTAX_AUTHOR]) -#define INFO_BRD(I) ((I)->rti_info[RTAX_BRD]) -void rt_xaddrs(struct rt_addrinfo *, struct sockaddr *, struct sockaddr *, - int); - -extern naddr std_mask(naddr); -extern naddr ripv1_mask_net(naddr, struct interface *); -extern naddr ripv1_mask_host(naddr,struct interface *); -#define on_net(a,net,mask) (((ntohl(a) ^ (net)) & (mask)) == 0) -extern int check_dst(naddr); -extern void addrouteforif(register struct interface *); -extern void ifinit(void); -extern int walk_bad(struct radix_node *, struct walkarg *); -extern int if_ok(struct interface *, char *); -extern void if_sick(struct interface *); -extern void if_bad(struct interface *); -extern struct interface *ifwithaddr(naddr, int, int); -extern struct interface *ifwithname(char *, naddr); -extern struct interface *ifwithindex(u_short); -extern struct interface *iflookup(naddr); diff --git a/usr.sbin/routed/if.c b/usr.sbin/routed/if.c deleted file mode 100644 index 71b4ad59c760..000000000000 --- a/usr.sbin/routed/if.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#include "defs.h" -#include "pathnames.h" - -struct interface *ifnet; /* all interfaces */ -int tot_interfaces; /* # of remote and local interfaces */ -int rip_interfaces; /* # of interfaces doing RIP */ -int foundloopback; /* valid flag for loopaddr */ -naddr loopaddr; /* our address on loopback */ - -struct timeval ifinit_timer; - -int have_ripv1_out; /* have a RIPv1 interface */ -int have_ripv1_in; - - -/* Find the interface with an address - */ -struct interface * -ifwithaddr(naddr addr, - int bcast, /* notice IFF_BROADCAST address */ - int remote) /* include IS_REMOTE interfaces */ -{ - struct interface *ifp, *possible = 0; - - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - if (ifp->int_addr == addr - || ((ifp->int_if_flags & IFF_BROADCAST) - && ifp->int_brdaddr == addr - && bcast)) { - if ((ifp->int_state & IS_REMOTE) && !remote) - continue; - - if (!(ifp->int_state & IS_BROKE) - && !(ifp->int_state & IS_PASSIVE)) - return ifp; - - possible = ifp; - } - } - - return possible; -} - - -/* find the interface with a name - */ -struct interface * -ifwithname(char *name, /* "ec0" or whatever */ - naddr addr) /* 0 or network address */ -{ - struct interface *ifp; - - - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { - if (!strcmp(ifp->int_name, name) - && (ifp->int_addr == addr - || (addr == 0 && !(ifp->int_state & IS_ALIAS)))) - return ifp; - } - return 0; -} - - -struct interface * -ifwithindex(u_short index) -{ - struct interface *ifp; - - - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { - if (ifp->int_index == index) - return ifp; - } - return 0; -} - - -/* Find an interface from which the specified address - * should have come from. Used for figuring out which - * interface a packet came in on -- for tracing. - */ -struct interface * -iflookup(naddr addr) -{ - struct interface *ifp, *maybe; - - maybe = 0; - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - if (ifp->int_if_flags & IFF_POINTOPOINT) { - if (ifp->int_dstaddr == addr) - /* finished with a match */ - return ifp; - - } else { - /* finished with an exact match */ - if (ifp->int_addr == addr) - return ifp; - if ((ifp->int_if_flags & IFF_BROADCAST) - && ifp->int_brdaddr == addr) - return ifp; - - /* Look for the longest approximate match. - */ - if (on_net(addr, ifp->int_net, ifp->int_mask) - && (maybe == 0 - || ifp->int_mask > maybe->int_mask)) - maybe = ifp; - } - } - - return maybe; -} - - -/* Return the classical netmask for an IP address. - */ -naddr -std_mask(naddr addr) /* in network order */ -{ - NTOHL(addr); /* was a host, not a network */ - - if (addr == 0) /* default route has mask 0 */ - return 0; - if (IN_CLASSA(addr)) - return IN_CLASSA_NET; - if (IN_CLASSB(addr)) - return IN_CLASSB_NET; - return IN_CLASSC_NET; -} - - -/* Find the netmask that would be inferred by RIPv1 listeners - * on the given interface for a given network. - * If no interface is specified, look for the best fitting interface. - */ -naddr -ripv1_mask_net(naddr addr, /* in network byte order */ - struct interface *ifp) /* as seen on this interface */ -{ - naddr mask = 0; - - if (addr == 0) /* default always has 0 mask */ - return mask; - - if (ifp != 0) { - /* If the target network is that of the associated interface - * on which it arrived, then use the netmask of the interface. - */ - if (on_net(addr, ifp->int_net, ifp->int_std_mask)) - mask = ifp->int_ripv1_mask; - - } else { - /* Examine all interfaces, and if it the target seems - * to have the same network number of an interface, use the - * netmask of that interface. If there is more than one - * such interface, prefer the interface with the longest - * match. - */ - 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) - mask = ifp->int_ripv1_mask; - } - } - - /* Otherwise, make the classic A/B/C guess. - */ - if (mask == 0) - mask = std_mask(addr); - - return mask; -} - - -naddr -ripv1_mask_host(naddr addr, /* in network byte order */ - struct interface *ifp) /* as seen on this interface */ -{ - naddr mask = ripv1_mask_net(addr, ifp); - - - /* If the computed netmask does not mask the address, - * then assume it is a host address - */ - if ((ntohl(addr) & ~mask) != 0) - mask = HOST_MASK; - return mask; -} - - -/* See if a IP address looks reasonable as a destination - */ -int /* 0=bad */ -check_dst(naddr addr) -{ - NTOHL(addr); - - if (IN_CLASSA(addr)) { - if (addr == 0) - return 1; /* default */ - - addr >>= IN_CLASSA_NSHIFT; - return (addr != 0 && addr != IN_LOOPBACKNET); - } - - return (IN_CLASSB(addr) || IN_CLASSC(addr)); -} - - -/* Delete an interface. - */ -static void -ifdel(struct interface *ifp) -{ - struct ip_mreq m; - struct interface *ifp1; - - - trace_if("Del", ifp); - - ifp->int_state |= IS_BROKE; - - /* unlink the interface - */ - if (rip_sock_mcast == ifp) - rip_sock_mcast = 0; - if (ifp->int_next != 0) - ifp->int_next->int_prev = ifp->int_prev; - if (ifp->int_prev != 0) - ifp->int_prev->int_next = ifp->int_next; - else - ifnet = ifp->int_next; - - if (!(ifp->int_state & IS_ALIAS)) { - /* delete aliases - */ - for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { - if (ifp1 != ifp - && !strcmp(ifp->int_name, ifp1->int_name)) - ifdel(ifp1); - } - - if ((ifp->int_if_flags & IFF_MULTICAST) -#ifdef MCAST_PPP_BUG - && !(ifp->int_if_flags & IFF_POINTOPOINT) -#endif - && rip_sock >= 0) { - m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); - m.imr_interface.s_addr = ((ifp->int_if_flags - & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); - if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, - &m, sizeof(m)) < 0 - && errno != EADDRNOTAVAIL - && !TRACEACTIONS) - LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); - } - if (ifp->int_rip_sock >= 0) { - (void)close(ifp->int_rip_sock); - ifp->int_rip_sock = -1; - fix_select(); - } - - tot_interfaces--; - if (!IS_RIP_OFF(ifp->int_state)) - 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. - */ - (void)rn_walktree(rhead, walk_bad, 0); - - set_rdisc_mg(ifp, 0); - if_bad_rdisc(ifp); - } - - free(ifp); -} - - -/* Mark an interface ill. - */ -void -if_sick(struct interface *ifp) -{ - if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { - ifp->int_state |= IS_SICK; - trace_if("Chg", ifp); - - LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); - } -} - - -/* Mark an interface dead. - */ -void -if_bad(struct interface *ifp) -{ - struct interface *ifp1; - - - if (ifp->int_state & IS_BROKE) - return; - - LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); - - ifp->int_state |= (IS_BROKE | IS_SICK); - ifp->int_state &= ~(IS_RIP_QUERIED | IS_ACTIVE); - ifp->int_data.ts = 0; - - trace_if("Chg", ifp); - - if (!(ifp->int_state & IS_ALIAS)) { - for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { - if (ifp1 != ifp - && !strcmp(ifp->int_name, ifp1->int_name)) - if_bad(ifp1); - } - (void)rn_walktree(rhead, walk_bad, 0); - if_bad_rdisc(ifp); - } -} - - -/* Mark an interface alive - */ -int /* 1=it was dead */ -if_ok(struct interface *ifp, - char *type) -{ - struct interface *ifp1; - - - if (!(ifp->int_state & IS_BROKE)) { - if (ifp->int_state & IS_SICK) { - trace_act("%sinterface %s to %s working better\n", - type, - ifp->int_name, naddr_ntoa(ifp->int_addr)); - ifp->int_state &= ~IS_SICK; - } - return 0; - } - - msglog("%sinterface %s to %s restored", - type, ifp->int_name, naddr_ntoa(ifp->int_addr)); - ifp->int_state &= ~(IS_BROKE | IS_SICK); - ifp->int_data.ts = 0; - - if (!(ifp->int_state & IS_ALIAS)) { - for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { - if (ifp1 != ifp - && !strcmp(ifp->int_name, ifp1->int_name)) - if_ok(ifp1, type); - } - if_ok_rdisc(ifp); - } - return 1; -} - - -/* disassemble routing message - */ -void -rt_xaddrs(struct rt_addrinfo *info, - struct sockaddr *sa, - struct sockaddr *lim, - int addrs) -{ - int i; -#ifdef _HAVE_SA_LEN - static struct sockaddr sa_zero; -#endif -#ifdef sgi -#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ - : sizeof(__uint64_t)) -#else -#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ - : sizeof(long)) -#endif - - - bzero(info, sizeof(*info)); - info->rti_addrs = addrs; - for (i = 0; i < RTAX_MAX && sa < lim; i++) { - if ((addrs & (1 << i)) == 0) - continue; -#ifdef _HAVE_SA_LEN - info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; - sa = (struct sockaddr *)((char*)(sa) - + ROUNDUP(sa->sa_len)); -#else - info->rti_info[i] = sa; - sa = (struct sockaddr *)((char*)(sa) - + ROUNDUP(_FAKE_SA_LEN_DST(sa))); -#endif - } -} - - -/* Find the network interfaces which have configured themselves. - * This must be done regularly, if only for extra addresses - * that come and go on interfaces. - */ -void -ifinit(void) -{ - static char *sysctl_buf; - static size_t sysctl_buf_size = 0; - uint complaints = 0; - static u_int prev_complaints = 0; -# define COMP_NOT_INET 0x001 -# define COMP_WIERD 0x002 -# define COMP_NOADDR 0x004 -# define COMP_NODST 0x008 -# define COMP_NOBADR 0x010 -# define COMP_NOMASK 0x020 -# define COMP_DUP 0x040 -# define COMP_BAD_METRIC 0x080 -# define COMP_NETMASK 0x100 - - struct interface ifs, ifs0, *ifp, *ifp1; - struct rt_entry *rt; - size_t needed; - int mib[6]; - struct if_msghdr *ifm; - struct ifa_msghdr *ifam, *ifam_lim, *ifam2; - struct sockaddr_dl *sdl; - int in, ierr, out, oerr; - struct intnet *intnetp; - struct rt_addrinfo info; -#ifdef SIOCGIFMETRIC - struct ifreq ifr; -#endif - - - ifinit_timer.tv_sec = now.tv_sec + (supplier - ? CHECK_ACT_INTERVAL - : CHECK_QUIET_INTERVAL); - - /* mark all interfaces so we can get rid of thost that disappear */ - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) - ifp->int_state &= ~(IS_CHECKED | IS_DUP); - - /* Fetch the interface list, without too many system calls - * since we do it repeatedly. - */ - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET; - mib[4] = NET_RT_IFLIST; - mib[5] = 0; - 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, "ifinit: get interface table"); - 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"); - } - - ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); - for (ifam = (struct ifa_msghdr *)sysctl_buf; - ifam < ifam_lim; - ifam = ifam2) { - - ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); - - if (ifam->ifam_type == RTM_IFINFO) { - ifm = (struct if_msghdr *)ifam; - /* make prototype structure for the IP aliases - */ - bzero(&ifs0, sizeof(ifs0)); - ifs0.int_rip_sock = -1; - ifs0.int_index = ifm->ifm_index; - ifs0.int_if_flags = ifm->ifm_flags; - ifs0.int_state = IS_CHECKED; - ifs0.int_act_time = now.tv_sec; - ifs0.int_data.ts = now.tv_sec; - ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; - ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; - ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; - ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; -#ifdef sgi - ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; -#endif - sdl = (struct sockaddr_dl *)(ifm + 1); - sdl->sdl_data[sdl->sdl_nlen] = 0; - continue; - } - if (ifam->ifam_type != RTM_NEWADDR) { - logbad(1,"ifinit: out of sync"); - continue; - } - - rt_xaddrs(&info, (struct sockaddr *)(ifam+1), - (struct sockaddr *)ifam2, - ifam->ifam_addrs); - - if (INFO_IFA(&info) == 0) { - if (iff_alive(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOADDR)) - msglog("%s has a bad address", - sdl->sdl_data); - complaints |= COMP_NOADDR; - } - continue; - } - if (INFO_IFA(&info)->sa_family != AF_INET) { - if (iff_alive(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOT_INET)) - trace_act("%s: not AF_INET\n", - sdl->sdl_data); - complaints |= COMP_NOT_INET; - } - continue; - } - - bcopy(&ifs0, &ifs, sizeof(ifs0)); - ifs0.int_state |= IS_ALIAS; /* next will be an alias */ - - ifs.int_addr = S_ADDR(INFO_IFA(&info)); - - if (ifs.int_if_flags & IFF_BROADCAST) { - if (INFO_MASK(&info) == 0) { - if (iff_alive(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOMASK)) - msglog("%s has no netmask", - sdl->sdl_data); - complaints |= COMP_NOMASK; - } - continue; - } - ifs.int_dstaddr = ifs.int_addr; - ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); - ifs.int_ripv1_mask = ifs.int_mask; - ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; - ifs.int_std_mask = std_mask(ifs.int_addr); - if (ifs.int_mask != ifs.int_std_mask) - ifs.int_state |= IS_SUBNET; - - if (INFO_BRD(&info) == 0) { - if (iff_alive(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOBADR)) - msglog("%s has no" - " broadcast address", - sdl->sdl_data); - complaints |= COMP_NOBADR; - } - continue; - } - ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); - - } 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 (!(prev_complaints & COMP_NODST)) - msglog("%s has a bad" - " destination address", - sdl->sdl_data); - complaints |= COMP_NODST; - } - continue; - } - ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); - ifs.int_mask = HOST_MASK; - ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); - ifs.int_net = ntohl(ifs.int_dstaddr); - ifs.int_std_mask = std_mask(ifs.int_dstaddr); - - } else if (ifs.int_if_flags & IFF_LOOPBACK) { - ifs.int_state |= IS_PASSIVE | IS_NO_RIP; - ifs.int_dstaddr = ifs.int_addr; - ifs.int_mask = HOST_MASK; - ifs.int_ripv1_mask = HOST_MASK; - ifs.int_net = ntohl(ifs.int_dstaddr); - ifs.int_std_mask = std_mask(ifs.int_dstaddr); - if (!foundloopback) { - foundloopback = 1; - loopaddr = ifs.int_addr; - } - - } else { - if (!(prev_complaints & COMP_WIERD)) - trace_act("%s is neither broadcast" - " nor point-to-point nor loopback", - sdl->sdl_data); - complaints |= COMP_WIERD; - continue; - } - ifs.int_std_net = ifs.int_net & ifs.int_std_mask; - ifs.int_std_addr = htonl(ifs.int_std_net); - - /* Use a minimum metric of one. Treat the interface metric - * (default 0) as an increment to the hop count of one. - * - * The metric obtained from the routing socket dump of - * interface addresses is wrong. It is not set by the - * SIOCSIFMETRIC ioctl. - */ -#ifdef SIOCGIFMETRIC - strncpy(ifr.ifr_name, sdl->sdl_data, sizeof(ifr.ifr_name)); - if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { - DBGERR(1, "ioctl(SIOCGIFMETRIC)"); - ifs.int_metric = 0; - } else { - ifs.int_metric = ifr.ifr_metric; - } -#else - ifs.int_metric = ifam->ifam_metric; -#endif - if (ifs.int_metric > HOPCNT_INFINITY) { - ifs.int_metric = 0; - if (!(prev_complaints & COMP_BAD_METRIC) - && iff_alive(ifs.int_if_flags)) { - complaints |= COMP_BAD_METRIC; - msglog("%s has a metric of %d", - sdl->sdl_data, ifs.int_metric); - } - } - - /* See if this is a familiar interface. - * If so, stop worrying about it if it is the same. - * Start it over if it now is to somewhere else, as happens - * frequently with PPP and SLIP. - */ - ifp = ifwithname(sdl->sdl_data, ((ifs.int_state & IS_ALIAS) - ? ifs.int_addr - : 0)); - if (ifp != 0) { - ifp->int_state |= IS_CHECKED; - - if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) - & (IFF_BROADCAST - | IFF_LOOPBACK - | IFF_POINTOPOINT - | IFF_MULTICAST)) - || 0 != ((ifp->int_state ^ ifs.int_state) - & IS_ALIAS) - || ifp->int_addr != ifs.int_addr - || ifp->int_brdaddr != ifs.int_brdaddr - || ifp->int_dstaddr != ifs.int_dstaddr - || ifp->int_mask != ifs.int_mask - || ifp->int_metric != ifs.int_metric) { - /* Forget old information about - * a changed interface. - */ - trace_act("interface %s has changed\n", - ifp->int_name); - ifdel(ifp); - ifp = 0; - } - } - - if (ifp != 0) { - /* The primary representative of an alias worries - * about how things are working. - */ - if (ifp->int_state & IS_ALIAS) - continue; - - /* note interfaces that have been turned off - */ - if (!iff_alive(ifs.int_if_flags)) { - if (iff_alive(ifp->int_if_flags)) { - msglog("interface %s to %s turned off", - ifp->int_name, - naddr_ntoa(ifp->int_addr)); - if_bad(ifp); - ifp->int_if_flags &= ~IFF_UP_RUNNING; - } - continue; - } - /* or that were off and are now ok */ - if (!iff_alive(ifp->int_if_flags)) { - ifp->int_if_flags |= IFF_UP_RUNNING; - (void)if_ok(ifp, ""); - } - - /* If it has been long enough, - * see if the interface is broken. - */ - if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) - continue; - - in = ifs.int_data.ipackets - ifp->int_data.ipackets; - ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; - out = ifs.int_data.opackets - ifp->int_data.opackets; - oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; -#ifdef sgi - /* Through at least IRIX 6.2, PPP and SLIP - * count packets dropped by the filters. - * But FDDI rings stuck non-operational count - * dropped packets as they wait for improvement. - */ - if (!(ifp->int_if_flags & IFF_POINTOPOINT)) - oerr += (ifs.int_data.odrops - - ifp->int_data.odrops); -#endif - /* If the interface just awoke, restart the counters. - */ - if (ifp->int_data.ts == 0) { - ifp->int_data = ifs.int_data; - continue; - } - ifp->int_data = ifs.int_data; - - /* Withhold judgement when the short error - * counters wrap or the interface is reset. - */ - if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { - LIM_SEC(ifinit_timer, - now.tv_sec+CHECK_BAD_INTERVAL); - continue; - } - - /* Withhold judgement when there is no traffic - */ - if (in == 0 && out == 0 && ierr == 0 && oerr == 0) - continue; - - /* It is bad if input or output is not working. - * Require presistent problems before marking it dead. - */ - if ((in <= ierr && ierr > 0) - || (out <= oerr && oerr > 0)) { - if (!(ifp->int_state & IS_SICK)) { - trace_act("interface %s to %s" - " sick: in=%d ierr=%d" - " out=%d oerr=%d\n", - ifp->int_name, - naddr_ntoa(ifp->int_addr), - in, ierr, out, oerr); - if_sick(ifp); - continue; - } - if (!(ifp->int_state & IS_BROKE)) { - msglog("interface %s to %s bad:" - " in=%d ierr=%d out=%d oerr=%d", - ifp->int_name, - naddr_ntoa(ifp->int_addr), - in, ierr, out, oerr); - if_bad(ifp); - } - continue; - } - - /* otherwise, it is active and healthy - */ - ifp->int_act_time = now.tv_sec; - (void)if_ok(ifp, ""); - continue; - } - - /* This is a new interface. - * If it is dead, forget it. - */ - if (!iff_alive(ifs.int_if_flags)) - continue; - - /* See if it duplicates an existing interface. - */ - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { - if (ifp->int_mask != ifs.int_mask) - continue; - if (((ifp->int_addr != ifs.int_addr - && ifs.int_mask != HOST_MASK) - || (ifp->int_dstaddr != ifs.int_dstaddr - && ifs.int_mask == HOST_MASK))) - continue; - if (!iff_alive(ifp->int_if_flags)) - continue; - /* Let one of our real interfaces be marked - * passive. - */ - if ((ifp->int_state & IS_PASSIVE) - && !(ifp->int_state & IS_EXTERNAL)) - continue; - - /* It does duplicate an existing interface, - * so complain about it, mark the other one - * duplicated, and for get this one. - */ - if (!(prev_complaints & COMP_DUP)) { - complaints |= COMP_DUP; - msglog("%s is duplicated by %s at %s", - sdl->sdl_data, ifp->int_name, - naddr_ntoa(ifp->int_addr)); - } - ifp->int_state |= IS_DUP; - break; - } - if (ifp != 0) - continue; - - /* It is new and ok. So make it real - */ - strncpy(ifs.int_name, sdl->sdl_data, - MIN(sizeof(ifs.int_name)-1, sdl->sdl_nlen)); - get_parms(&ifs); - - /* Add it to the list of interfaces - */ - ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit"); - bcopy(&ifs, ifp, sizeof(*ifp)); - if (ifnet != 0) { - ifp->int_next = ifnet; - ifnet->int_prev = ifp; - } - ifnet = ifp; - trace_if("Add", ifp); - - /* Notice likely bad netmask. - */ - if (!(prev_complaints & COMP_NETMASK) - && !(ifp->int_if_flags & IFF_POINTOPOINT)) { - for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { - if (ifp1->int_mask == ifp->int_mask) - continue; - if (ifp1->int_if_flags & IFF_POINTOPOINT) - continue; - if (on_net(ifp->int_addr, - ifp1->int_net, ifp1->int_mask) - || on_net(ifp1->int_addr, - ifp->int_net, ifp->int_mask)) { - msglog("possible netmask problem" - " betwen %s:%s and %s:%s", - ifp->int_name, - addrname(htonl(ifp->int_net), - ifp->int_mask, 1), - ifp1->int_name, - addrname(htonl(ifp1->int_net), - ifp1->int_mask, 1)); - complaints |= COMP_NETMASK; - } - } - } - - /* Count the # of directly connected networks. - */ - if (!(ifp->int_state & IS_ALIAS)) { - if (!(ifp->int_if_flags & IFF_LOOPBACK)) - tot_interfaces++; - if (!IS_RIP_OFF(ifp->int_state)) - rip_interfaces++; - } - - if_ok_rdisc(ifp); - rip_on(ifp); - } - - /* If we are multi-homed and have at least one interface - * listening to RIP, then output by default. - */ - if (!supplier_set && rip_interfaces > 1) - set_supplier(); - - /* If we are multi-homed, optionally advertise a route to - * our main address. - */ - if (advertise_mhome - || (tot_interfaces > 1 - && mhome - && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 - && foundloopback)) { - advertise_mhome = 1; - rt = rtget(myaddr, HOST_MASK); - if (rt != 0) { - if (rt->rt_ifp != ifp - || rt->rt_router != loopaddr) { - rtdelete(rt); - rt = 0; - } else { - rtchange(rt, rt->rt_state | RS_MHOME, - loopaddr, loopaddr, - 0, 0, ifp, rt->rt_time, 0); - } - } - if (rt == 0) - rtadd(myaddr, HOST_MASK, loopaddr, loopaddr, - 0, 0, RS_MHOME, ifp); - } - - for (ifp = ifnet; ifp != 0; ifp = ifp1) { - ifp1 = ifp->int_next; /* because we may delete it */ - - /* Forget any interfaces that have disappeared. - */ - if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { - trace_act("interface %s has disappeared\n", - ifp->int_name); - ifdel(ifp); - continue; - } - - if ((ifp->int_state & IS_BROKE) - && !(ifp->int_state & IS_PASSIVE)) - LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); - - /* If we ever have a RIPv1 interface, assume we always will. - * It might come back if it ever goes away. - */ - if (!(ifp->int_if_flags & IFF_LOOPBACK)) { - if (!(ifp->int_state & IS_NO_RIPV1_OUT)) - have_ripv1_out = 1; - if (!(ifp->int_state & IS_NO_RIPV1_IN)) - have_ripv1_in = 1; - } - } - - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - /* Ensure there is always a network route for interfaces, - * after any dead interfaces have been deleted, which - * might affect routes for point-to-point links. - */ - addrouteforif(ifp); - - /* Add routes to the local end of point-to-point interfaces - * using loopback. - */ - if ((ifp->int_if_flags & IFF_POINTOPOINT) - && !(ifp->int_state & IS_REMOTE) - && foundloopback) { - /* Delete any routes to the network address through - * foreign routers. Remove even static routes. - */ - del_static(ifp->int_addr, HOST_MASK, 0); - rt = rtget(ifp->int_addr, HOST_MASK); - if (rt != 0 && rt->rt_router != loopaddr) { - rtdelete(rt); - rt = 0; - } - if (rt != 0) { - if (!(rt->rt_state & RS_LOCAL) - || rt->rt_metric > ifp->int_metric) { - ifp1 = ifp; - } 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); - } else { - rtadd(ifp->int_addr, HOST_MASK, - loopaddr, loopaddr, - 0, 0, (RS_IF | RS_LOCAL), ifp); - } - } - } - - /* add the authority routes */ - for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { - rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); - if (rt != 0 - && !(rt->rt_state & RS_NO_NET_SYN) - && !(rt->rt_state & RS_NET_INT)) { - rtdelete(rt); - rt = 0; - } - if (rt == 0) - rtadd(intnetp->intnet_addr, intnetp->intnet_mask, - loopaddr, loopaddr, intnetp->intnet_metric-1, - 0, RS_NET_SYN | RS_NET_INT, 0); - } - - prev_complaints = complaints; -} - - -static void -check_net_syn(struct interface *ifp) -{ - struct rt_entry *rt; - - - /* Turn on the need to automatically synthesize a network route - * for this interface only if we are running RIPv1 on some other - * interface that is on a different class-A,B,or C network. - */ - if (have_ripv1_out || have_ripv1_in) { - ifp->int_state |= IS_NEED_NET_SYN; - rt = rtget(ifp->int_std_addr, ifp->int_std_mask); - if (rt != 0 - && 0 == (rt->rt_state & RS_NO_NET_SYN) - && (!(rt->rt_state & RS_NET_SYN) - || rt->rt_metric > ifp->int_metric)) { - rtdelete(rt); - rt = 0; - } - if (rt == 0) - rtadd(ifp->int_std_addr, ifp->int_std_mask, - ifp->int_addr, ifp->int_addr, - ifp->int_metric, 0, RS_NET_SYN, ifp); - - } else { - ifp->int_state &= ~IS_NEED_NET_SYN; - - rt = rtget(ifp->int_std_addr, - ifp->int_std_mask); - if (rt != 0 - && (rt->rt_state & RS_NET_SYN) - && rt->rt_ifp == ifp) - rtbad_sub(rt); - } -} - - -/* Add route for interface if not currently installed. - * Create route to other end if a point-to-point link, - * otherwise a route to this (sub)network. - */ -void -addrouteforif(struct interface *ifp) -{ - struct rt_entry *rt; - naddr dst, gate; - - - /* skip sick interfaces - */ - if (ifp->int_state & IS_BROKE) - return; - - /* If the interface on a subnet, then install a RIPv1 route to - * the network as well (unless it is sick). - */ - if (ifp->int_state & IS_SUBNET) - check_net_syn(ifp); - - if (ifp->int_state & IS_REMOTE) { - dst = ifp->int_addr; - gate = ifp->int_dstaddr; - /* If we are going to send packets to the gateway, - * it must be reachable using our physical interfaces - */ - if (!(ifp->int_state && IS_EXTERNAL) - && !rtfind(ifp->int_dstaddr) - && ifp->int_transitions == 0) { - msglog("unreachable gateway %s in " - _PATH_GATEWAYS" entry %s", - naddr_ntoa(gate), ifp->int_name); - return; - } - - } else { - dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT - | IFF_LOOPBACK)) - ? ifp->int_dstaddr - : htonl(ifp->int_net)); - gate = ifp->int_addr; - } - - /* We are finished if the correct main interface route exists. - * 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); - rt = rtget(dst, ifp->int_mask); - if (rt != 0) { - if ((rt->rt_ifp != ifp - || rt->rt_router != ifp->int_addr) - && (!(ifp->int_state & IS_DUP) - || rt->rt_ifp == 0 - || (rt->rt_ifp->int_state & IS_BROKE))) { - rtdelete(rt); - rt = 0; - } 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); - } - } - if (rt == 0) { - if (ifp->int_transitions++ > 0) - trace_act("re-install interface %s\n", - ifp->int_name); - - rtadd(dst, ifp->int_mask, gate, gate, - ifp->int_metric, 0, RS_IF, ifp); - } -} diff --git a/usr.sbin/routed/input.c b/usr.sbin/routed/input.c deleted file mode 100644 index 7df5988e822a..000000000000 --- a/usr.sbin/routed/input.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#include "defs.h" - -static void input(struct sockaddr_in *, struct interface*, struct rip *, int); -static void input_route(struct interface *, naddr, - naddr, naddr, naddr, struct netinfo *); - - -/* process RIP input - */ -void -read_rip(int sock, - struct interface *ifp) -{ - struct sockaddr_in from; - int fromlen, cc; - union pkt_buf inbuf; - - - for (;;) { - fromlen = sizeof(from); - cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0, - (struct sockaddr*)&from, &fromlen); - if (cc <= 0) { - if (cc < 0 && errno != EWOULDBLOCK) - LOGERR("recvfrom(rip)"); - break; - } - if (fromlen != sizeof(struct sockaddr_in)) - logbad(1,"impossible recvfrom(rip) fromlen=%d", - fromlen); - - input(&from, - (ifp != 0) ? ifp : iflookup(from.sin_addr.s_addr), - &inbuf.rip, cc); - } -} - - -/* Process a RIP packet - */ -static void -input(struct sockaddr_in *from, /* received from this IP address */ - struct interface *ifp, - struct rip *rip, - int size) -{ -# define FROM_NADDR from->sin_addr.s_addr - static naddr use_auth, bad_len, bad_mask; - static naddr unk_router, bad_router, bad_nhop; - - struct rt_entry *rt; - struct netinfo *n, *lim; - struct interface *ifp1; - naddr gate, mask, v1_mask, dst, ddst_h; - int i; - - - if (ifp != 0) - ifp->int_state |= IS_ACTIVE; - - trace_rip("Recv", "from", from, ifp, rip, size); - - if (rip->rip_vers == 0) { - if (from->sin_addr.s_addr != bad_router) - msglog("RIP version 0, cmd %d, packet received" - " from %s", - rip->rip_cmd, naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; - return; - } - if (size > MAXPACKETSIZE) { - if (from->sin_addr.s_addr != bad_router) - msglog("packet at least %d bytes too long received" - " from %s", - size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; - return; - } - - n = rip->rip_nets; - lim = (struct netinfo *)((char*)rip + size); - - /* Notice authentication. - * As required by section 4.2 in RFC 1723, discard authenticated - * RIPv2 messages, but only if configured for that silliness. - * - * RIPv2 authentication is lame, since snooping on the wire makes - * its simple passwords evident. Also, why authenticate queries? - * Why should a RIPv2 implementation with authentication disabled - * not be able to listen to RIPv2 packets with authenication, while - * RIPv1 systems will listen? Crazy! - */ - if (!auth_ok - && rip->rip_vers >= RIPv2 - && n < lim && n->n_family == RIP_AF_AUTH) { - if (from->sin_addr.s_addr != use_auth) - msglog("RIPv2 message with authentication" - " from %s discarded", - naddr_ntoa(FROM_NADDR)); - use_auth = from->sin_addr.s_addr; - trace_pkt("discard authenticated RIPv2 message\n"); - return; - } - - switch (rip->rip_cmd) { - case RIPCMD_REQUEST: - /* did the request come from a router? - */ - if (from->sin_port == htons(RIP_PORT)) { - /* yes, ignore it if RIP is off so that it does not - * depend on us. - */ - if (rip_sock < 0) { - trace_pkt("ignore request while RIP off\n"); - return; - } - - /* Ignore the request if we talking to ourself - * (and not a remote gateway). - */ - if (ifwithaddr(FROM_NADDR, 0, 0) != 0) { - trace_pkt("discard our own RIP request\n"); - return; - } - } - - /* According to RFC 1723, we should ignore unathenticated - * queries. That is too silly to bother with. Sheesh! - * Are forwarding tables supposed to be secret? When - * a bad guy can infer them with test traffic? - * Maybe on firewalls you'd care, but not enough to - * give up the diagnostic facilities of remote probing. - */ - - if (n >= lim - || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - if (from->sin_addr.s_addr != bad_len) - msglog("request of bad length (%d) from %s", - size, naddr_ntoa(FROM_NADDR)); - bad_len = from->sin_addr.s_addr; - } - for (; n < lim; n++) { - n->n_metric = ntohl(n->n_metric); - - /* A single entry with family RIP_AF_UNSPEC and - * metric HOPCNT_INFINITY means "all routes". - * We respond to routers only if we are acting - * as a supplier, or to anyone other than a router - * (i.e. a query). - * - * Answer a query from a stray program with all - * we know. Filter the answer to a query from a - * router in the about same way broadcasts are - * filtered. - * - * Only answer a router if we are a supplier - * to keep an unwary host that is just starting - * from picking us an a router. - */ - if (n->n_family == RIP_AF_UNSPEC - && n->n_metric == HOPCNT_INFINITY - && n == rip->rip_nets - && n+1 == lim) { - if (from->sin_port != htons(RIP_PORT)) { - /* query from `rtquery` or similar - */ - supply(from, ifp, - OUT_QUERY, 0, rip->rip_vers); - } else if (supplier) { - /* a router trying to prime its - * tables. - */ - supply(from, ifp, - OUT_UNICAST, 0, rip->rip_vers); - } - return; - } - - if (n->n_family != RIP_AF_INET) { - if (from->sin_addr.s_addr != bad_router) - msglog("request from %s" - " for unsupported (af %d) %s", - naddr_ntoa(FROM_NADDR), - ntohs(n->n_family), - naddr_ntoa(n->n_dst)); - bad_router = from->sin_addr.s_addr; - return; - } - - dst = n->n_dst; - if (!check_dst(dst)) { - if (from->sin_addr.s_addr != bad_router) - msglog("bad queried destination" - " %s from %s", - naddr_ntoa(dst), - naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; - return; - } - - if (rip->rip_vers == RIPv1 - || 0 == (mask = ntohl(n->n_mask)) - || 0 != (ntohl(dst) & ~mask)) - mask = ripv1_mask_host(dst,ifp); - - rt = rtget(dst, mask); - if (!rt && dst != RIP_DEFAULT) - rt = rtfind(n->n_dst); - - n->n_tag = 0; - n->n_nhop = 0; - if (rip->rip_vers == RIPv1) { - n->n_mask = 0; - } else { - n->n_mask = mask; - } - if (rt == 0) { - n->n_metric = HOPCNT_INFINITY; - } else { - n->n_metric = rt->rt_metric+1; - n->n_metric += (ifp!=0) ? ifp->int_metric : 1; - if (n->n_metric > HOPCNT_INFINITY) - n->n_metric = HOPCNT_INFINITY; - if (rip->rip_vers != RIPv1) { - n->n_tag = rt->rt_tag; - if (ifp != 0 - && on_net(rt->rt_gate, - ifp->int_net, - ifp->int_mask) - && rt->rt_gate != ifp->int_addr) - n->n_nhop = rt->rt_gate; - } - } - HTONL(n->n_metric); - } - /* Answer about specific routes. - * Only answer a router if we are a supplier - * to keep an unwary host that is just starting - * from picking us an a router. - */ - rip->rip_cmd = RIPCMD_RESPONSE; - rip->rip_res1 = 0; - if (rip->rip_vers != RIPv1) - rip->rip_vers = RIPv2; - if (from->sin_port != htons(RIP_PORT)) { - /* query */ - (void)output(OUT_QUERY, from, ifp, rip, size); - } else if (supplier) { - (void)output(OUT_UNICAST, from, ifp, rip, size); - } - return; - - case RIPCMD_TRACEON: - case RIPCMD_TRACEOFF: - /* verify message came from a privileged port */ - if (ntohs(from->sin_port) > IPPORT_RESERVED) { - msglog("trace command from untrusted port on %s", - naddr_ntoa(FROM_NADDR)); - return; - } - if (ifp == 0) { - msglog("trace command from unknown router %s", - naddr_ntoa(FROM_NADDR)); - return; - } - if (rip->rip_cmd == RIPCMD_TRACEON) { - rip->rip_tracefile[size-4] = '\0'; - trace_on((char*)rip->rip_tracefile, 0); - } else { - trace_off("tracing turned off by %s\n", - naddr_ntoa(FROM_NADDR)); - } - return; - - case RIPCMD_RESPONSE: - if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - if (from->sin_addr.s_addr != bad_len) - msglog("response of bad length (%d) from %s", - size, naddr_ntoa(FROM_NADDR)); - bad_len = from->sin_addr.s_addr; - } - - /* verify message came from a router */ - if (from->sin_port != ntohs(RIP_PORT)) { - trace_pkt("discard RIP response from unknown port\n"); - return; - } - - if (rip_sock < 0) { - trace_pkt("discard response while RIP off\n"); - return; - } - - /* Are we talking to ourself or a remote gateway? - */ - ifp1 = ifwithaddr(FROM_NADDR, 0, 1); - if (ifp1) { - if (ifp1->int_state & IS_REMOTE) { - if (ifp1->int_state & IS_PASSIVE) { - msglog("bogus input from %s on" - " supposedly passive %s", - naddr_ntoa(FROM_NADDR), - ifp1->int_name); - } else { - ifp1->int_act_time = now.tv_sec; - if (if_ok(ifp1, "remote ")) - addrouteforif(ifp1); - } - } else { - trace_pkt("discard our own RIP response\n"); - } - return; - } - - /* Check the router from which message originated. We accept - * routing packets from routers directly connected via - * broadcast or point-to-point networks, and from - * those listed in /etc/gateways. - */ - if (!ifp) { - if (from->sin_addr.s_addr != unk_router) - msglog("packet from unknown router %s" - " or via unidentified interface", - naddr_ntoa(FROM_NADDR)); - unk_router = from->sin_addr.s_addr; - return; - } - if (ifp->int_state & IS_PASSIVE) { - trace_act("packet from %s via passive interface %s\n", - naddr_ntoa(FROM_NADDR), - ifp->int_name); - return; - } - - /* Check required version - */ - if (((ifp->int_state & IS_NO_RIPV1_IN) - && rip->rip_vers == RIPv1) - || ((ifp->int_state & IS_NO_RIPV2_IN) - && rip->rip_vers != RIPv1)) { - trace_pkt("discard RIPv%d response\n", - rip->rip_vers); - return; - } - - /* Ignore routes via dead interface. - */ - if (ifp->int_state & IS_BROKE) { - trace_pkt("discard response via broken interface %s\n", - ifp->int_name); - return; - } - - /* Authenticate the packet if we have a secret. - */ - if (ifp->int_passwd[0] != '\0') { - if (n >= lim - || n->n_family != RIP_AF_AUTH - || ((struct netauth*)n)->a_type != RIP_AUTH_PW) { - if (from->sin_addr.s_addr != use_auth) - msglog("missing password from %s", - naddr_ntoa(FROM_NADDR)); - use_auth = from->sin_addr.s_addr; - return; - - } else if (0 != bcmp(((struct netauth*)n)->au.au_pw, - ifp->int_passwd, - sizeof(ifp->int_passwd))) { - if (from->sin_addr.s_addr != use_auth) - msglog("bad password from %s", - naddr_ntoa(FROM_NADDR)); - use_auth = from->sin_addr.s_addr; - return; - } - } - - for (; n < lim; n++) { - if (n->n_family == RIP_AF_AUTH) - continue; - - NTOHL(n->n_metric); - dst = n->n_dst; - if (n->n_family != RIP_AF_INET - && (n->n_family != RIP_AF_UNSPEC - || dst != RIP_DEFAULT)) { - if (from->sin_addr.s_addr != bad_router) - msglog("route from %s to unsupported" - " address family %d," - " destination %s", - naddr_ntoa(FROM_NADDR), - n->n_family, - naddr_ntoa(dst)); - bad_router = from->sin_addr.s_addr; - continue; - } - if (!check_dst(dst)) { - if (from->sin_addr.s_addr != bad_router) - msglog("bad destination %s from %s", - naddr_ntoa(dst), - naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; - return; - } - if (n->n_metric == 0 - || n->n_metric > HOPCNT_INFINITY) { - if (from->sin_addr.s_addr != bad_router) - msglog("bad metric %d from %s" - " for destination %s", - n->n_metric, - naddr_ntoa(FROM_NADDR), - naddr_ntoa(dst)); - bad_router = from->sin_addr.s_addr; - return; - } - - /* Notice the next-hop. - */ - gate = from->sin_addr.s_addr; - if (n->n_nhop != 0 - && rip->rip_vers == RIPv2) { - /* Ignore the route if it points to us */ - if (0 != ifwithaddr(n->n_nhop, 1, 0)) - continue; - - /* Use it only if it is valid. */ - if (on_net(n->n_nhop, - ifp->int_net, ifp->int_mask) - && check_dst(n->n_nhop)) { - gate = n->n_nhop; - } else { - if (bad_nhop != from->sin_addr.s_addr) - msglog("router %s to %s has" - " bad next hop %s", - naddr_ntoa(FROM_NADDR), - naddr_ntoa(dst), - naddr_ntoa(n->n_nhop)); - bad_nhop = from->sin_addr.s_addr; - } - } - - if (rip->rip_vers == RIPv1 - || 0 == (mask = ntohl(n->n_mask))) { - mask = ripv1_mask_host(dst,ifp); - } else if ((ntohl(dst) & ~mask) != 0) { - if (bad_mask != from->sin_addr.s_addr) { - msglog("router %s sent bad netmask" - " %#x with %s", - naddr_ntoa(FROM_NADDR), - mask, - naddr_ntoa(dst)); - bad_mask = from->sin_addr.s_addr; - } - continue; - } - if (rip->rip_vers == RIPv1) - n->n_tag = 0; - - /* Adjust metric according to incoming interface.. - */ - n->n_metric += ifp->int_metric; - if (n->n_metric > HOPCNT_INFINITY) - n->n_metric = HOPCNT_INFINITY; - - /* Recognize and ignore a default route we faked - * which is being sent back to us by a machine with - * broken split-horizon. - * Be a little more paranoid than that, and reject - * default routes with the same metric we advertised. - */ - if (ifp->int_d_metric != 0 - && dst == RIP_DEFAULT - && n->n_metric >= ifp->int_d_metric) - continue; - - /* We can receive aggregated RIPv2 routes that must - * be broken down before they are transmitted by - * RIPv1 via an interface on a subnet. - * We might also receive the same routes aggregated - * via other RIPv2 interfaces. - * This could cause duplicate routes to be sent on - * the RIPv1 interfaces. "Longest matching variable - * length netmasks" lets RIPv2 listeners understand, - * but breaking down the aggregated routes for RIPv1 - * listeners can produce duplicate routes. - * - * Breaking down aggregated routes here bloats - * the daemon table, but does not hurt the kernel - * table, since routes are always aggregated for - * the kernel. - * - * Notice that this does not break down network - * routes corresponding to subnets. This is part - * of the defense against RS_NET_SYN. - */ - if (have_ripv1_out - && (v1_mask = ripv1_mask_net(dst,0)) > mask - && (((rt = rtget(dst,mask)) == 0 - || !(rt->rt_state & RS_NET_SYN)))) { - ddst_h = v1_mask & -v1_mask; - i = (v1_mask & ~mask)/ddst_h; - if (i >= 511) { - /* 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 - i = 0; - } else { - mask = v1_mask; - } - } else { - i = 0; - } - - for (;;) { - input_route(ifp, FROM_NADDR, - dst, mask, gate, n); - if (i-- == 0) - break; - dst = htonl(ntohl(dst) + ddst_h); - } - } - break; - } -} - - -/* Process a single input route. - */ -static void -input_route(struct interface *ifp, - naddr from, - naddr dst, - naddr mask, - naddr gate, - 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. - * Sometimes network routes arrive over a point-to-point link for - * the network containing the address(es) of the link. - * - * If our interface is broken, switch to using the other guy. - */ - ifp1 = ifwithaddr(dst, 1, 1); - if (ifp1 != 0 - && !(ifp1->int_state & IS_BROKE)) - return; - - /* Look for the route in our table. - */ - rt = rtget(dst, mask); - - /* Consider adding the route if we do not already have it. - */ - if (rt == 0) { - /* Ignore unknown routes being poisoned. - */ - if (n->n_metric == HOPCNT_INFINITY) - return; - - if (total_routes < MAX_ROUTES) - rtadd(dst, mask, gate, from, n->n_metric, - n->n_tag, 0, ifp); - return; - } - - /* We already know about the route. Consider this update. - * - * If (rt->rt_state & RS_NET_SYN), then this route - * is the same as a network route we have inferred - * for subnets we know, in order to tell RIPv1 routers - * about the subnets. - * - * It is impossible to tell if the route is coming - * from a distant RIPv2 router with the standard - * netmask because that router knows about the entire - * network, or if it is a round-about echo of a - * synthetic, RIPv1 network route of our own. - * The worst is that both kinds of routes might be - * received, and the bad one might have the smaller - * metric. Partly solve this problem by faking the - * RIPv1 route with a metric that reflects the most - * distant part of the subnet. Also never - * aggregate into such a route. Also keep it - * around as long as the interface exists. - */ - - rts0 = rt->rt_spares; - for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) { - if (rts->rts_router == from) - break; - /* Note the worst slot to reuse, - * other than the current slot. - */ - if (rts0 == rt->rt_spares - || BETTER_LINK(rt, rts0, rts)) - rts0 = rts; - } - if (i != 0) { - /* Found the router - */ - int old_metric = rts->rts_metric; - - /* Keep poisoned routes around only long enough to pass - * the poison on. Get a new timestamp for good routes. - */ - new_time =((old_metric == HOPCNT_INFINITY) - ? rts->rts_time - : now.tv_sec); - - /* 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); - /* If the route got worse, check for something better. - */ - if (n->n_metric > old_metric) - rtswitch(rt, 0); - return; - } - - /* This is an update for a spare route. - * Finished if the route is unchanged. - */ - if (rts->rts_gate == gate - && old_metric == n->n_metric - && rts->rts_tag == n->n_tag) { - rts->rts_time = new_time; - return; - } - - } else { - /* The update is for a route we know about, - * but not from a familiar router. - */ - rts = rts0; - - /* Save the route as a spare only if it has - * a better metric than our worst spare. - * This also ignores poisoned routes (those - * received with metric HOPCNT_INFINITY). - */ - if (n->n_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; - - /* try to switch to a better route */ - rtswitch(rt, rts); -} diff --git a/usr.sbin/routed/main.c b/usr.sbin/routed/main.c deleted file mode 100644 index b96fe71b38ec..000000000000 --- a/usr.sbin/routed/main.c +++ /dev/null @@ -1,824 +0,0 @@ -/* - * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -char copyright[] = -"@(#) Copyright (c) 1983, 1988, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#include "defs.h" -#include "pathnames.h" -#ifdef sgi -#include "math.h" -#endif -#include -#include -#include - -pid_t mypid; - -naddr myaddr; /* system address */ -char myname[MAXHOSTNAMELEN+1]; - -int supplier; /* supply or broadcast updates */ -int supplier_set; -int ipforwarding = 1; /* kernel forwarding on */ - -int default_gateway; /* 1=advertise default */ -int background = 1; -int ridhosts; /* 1=reduce host routes */ -int mhome; /* 1=want multi-homed host route */ -int advertise_mhome; /* 1=must continue adverising it */ -int auth_ok = 1; /* 1=ignore auth if we do not care */ - -struct timeval epoch; /* when started */ -struct timeval clk, prev_clk; -struct timeval now; /* current idea of time */ -time_t now_stale; -time_t now_garbage; - -struct timeval next_bcast; /* next general broadcast */ -struct timeval no_flash = {EPOCH+SUPPLY_INTERVAL}; /* inhibit flash update */ - -fd_set fdbits; -int sock_max; -int rip_sock = -1; /* RIP socket */ -struct interface *rip_sock_mcast; /* current multicast interface */ -int rt_sock; /* routing socket */ -int rt_sock_seqno; - - -static int get_rip_sock(naddr, int); -static void timevalsub(struct timeval *, struct timeval *, struct timeval *); - -int -main(int argc, - char *argv[]) -{ - int n, mib[4], off; - size_t len; - char *p, *q; - struct timeval wtime, t2; - time_t dt; - fd_set ibits; - naddr p_addr, p_mask; - struct interface *ifp; - struct parm parm; - char *tracename = 0; - - - openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); - ftrace = stdout; - - gettimeofday(&clk, 0); - prev_clk = clk; - epoch = clk; - epoch.tv_sec -= EPOCH; - now.tv_sec = EPOCH; - now_stale = EPOCH - STALE_TIME; - now_garbage = EPOCH - GARBAGE_TIME; - wtime.tv_sec = 0; - - (void)gethostname(myname, sizeof(myname)-1); - (void)gethost(myname, &myaddr); - - while ((n = getopt(argc, argv, "sqdghmAtT:F:P:")) != EOF) { - switch (n) { - case 's': - supplier = 1; - supplier_set = 1; - break; - - case 'q': - supplier = 0; - supplier_set = 1; - break; - - case 'd': - background = 0; - break; - - case 'g': - bzero(&parm, sizeof(parm)); - parm.parm_d_metric = 1; - p = check_parms(&parm); - if (p != 0) - msglog("bad -g: %s", p); - else - default_gateway = 1; - break; - - case 'h': /* suppress extra host routes */ - ridhosts = 1; - break; - - case 'm': /* advertise host route */ - mhome = 1; /* on multi-homed hosts */ - break; - - case 'A': - /* Ignore authentication if we do not care. - * Crazy as it is, that is what RFC 1723 requires. - */ - auth_ok = 0; - break; - - case 't': - new_tracelevel++; - break; - - case 'T': - tracename = optarg; - break; - - case 'F': /* minimal routes for SLIP */ - n = HOPCNT_INFINITY-2; - p = strchr(optarg,','); - if (p && *p != '\0') { - n = (int)strtoul(p+1, &q, 0); - if (*q == '\0' - && n <= HOPCNT_INFINITY-1 - && n >= 1) - *p = '\0'; - } - if (!getnet(optarg, &p_addr, &p_mask)) { - msglog("bad network; \"-F %s\"", - optarg); - break; - } - bzero(&parm, sizeof(parm)); - parm.parm_addr_h = ntohl(p_addr); - parm.parm_mask = p_mask; - parm.parm_d_metric = n; - p = check_parms(&parm); - if (p != 0) - msglog("bad -F: %s", p); - break; - - case 'P': - /* handle arbirary, (usually) per-interface - * parameters. - */ - p = parse_parms(optarg); - if (p != 0) - msglog("bad \"%s\" in \"%s\"", - p, optarg); - break; - - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (tracename == 0 && argc >= 1) { - tracename = *argv++; - argc--; - } - if (argc != 0) { -usage: - logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]" - " [-F net[,metric]] [-P parms]"); - } - if (geteuid() != 0) - logbad(0, "requires UID 0"); - - mib[0] = CTL_NET; - mib[1] = PF_INET; - mib[2] = IPPROTO_IP; - mib[3] = IPCTL_FORWARDING; - len = sizeof(ipforwarding); - if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) - LOGERR("sysctl(IPCTL_FORWARDING)"); - - if (!ipforwarding) { - if (supplier) - msglog("-s incompatible with ipforwarding=0"); - if (default_gateway) { - msglog("-g incompatible with ipforwarding=0"); - default_gateway = 0; - } - supplier = 0; - supplier_set = 1; - } - if (default_gateway) { - if (supplier_set && !supplier) { - msglog("-g and -q incompatible"); - } else { - supplier = 1; - supplier_set = 1; - } - } - - - /* get into the background */ - if (background) { -#ifdef sgi - if (0 > _daemonize(_DF_NOCHDIR, - new_tracelevel == 0 ? -1 : STDOUT_FILENO, - new_tracelevel == 0 ? -1 : STDERR_FILENO, - -1)) - BADERR(0, "_daemonize()"); -#else - if (daemon(1, 1) < 0) - BADERR(0,"daemon()"); -#endif - } - - mypid = getpid(); - srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid)); - - /* prepare socket connected to the kernel. - */ - rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); - if (rt_sock < 0) - BADERR(1,"rt_sock = socket()"); - if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) - logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); - off = 0; - if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, - &off,sizeof(off)) < 0) - LOGERR("setsockopt(SO_USELOOPBACK,0)"); - - fix_select(); - - - if (background && new_tracelevel == 0) - ftrace = 0; - if (tracename != 0) { - trace_on(tracename, 1); - if (new_tracelevel == 0) /* use stdout if file is bad */ - new_tracelevel = 1; - } - set_tracelevel(); - - /* initialize radix tree */ - rtinit(); - - /* Pick a random part of the second for our output to minimize - * collisions. - * - * Start broadcasting after hearing from other routers, and - * at a random time so a bunch of systems do not get synchronized - * after a power failure. - */ - intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); - age_timer.tv_usec = next_bcast.tv_usec; - age_timer.tv_sec = EPOCH+MIN_WAITTIME; - rdisc_timer = next_bcast; - ifinit_timer.tv_usec = next_bcast.tv_usec; - - signal(SIGALRM, sigalrm); - signal(SIGHUP, sigterm); - signal(SIGTERM, sigterm); - signal(SIGINT, sigterm); - signal(SIGUSR1, sigtrace_on); - signal(SIGUSR2, sigtrace_off); - - /* Collect an initial view of the world by checking the interface - * configuration and the kludge file. - */ - gwkludge(); - ifinit(); - flush_kern(); - - /* Ask for routes */ - rip_query(); - if (!supplier) - rdisc_sol(); - - /* Loop forever, listening and broadcasting. - */ - for (;;) { - prev_clk = clk; - gettimeofday(&clk, 0); - timevalsub(&t2, &clk, &prev_clk); - if (t2.tv_sec < 0 - || t2.tv_sec > wtime.tv_sec + 5) { - /* Deal with time changes before other housekeeping to - * keep everything straight. - */ - dt = t2.tv_sec; - if (dt > 0) - dt -= wtime.tv_sec; - trace_act("time changed by %d sec\n", dt); - epoch.tv_sec += dt; - } - timevalsub(&now, &clk, &epoch); - now_stale = now.tv_sec - STALE_TIME; - now_garbage = now.tv_sec - GARBAGE_TIME; - - /* deal with interrupts that should affect tracing */ - set_tracelevel(); - - if (stopint != 0) { - if (supplier) { - rip_bcast(0); - rdisc_adv(); - } - trace_off("exiting with signal %d\n", stopint); - exit(stopint | 128); - } - - /* look for new or dead interfaces */ - timevalsub(&wtime, &ifinit_timer, &now); - if (wtime.tv_sec <= 0) { - wtime.tv_sec = 0; - ifinit(); - rip_query(); - continue; - } - - /* If it is time, then broadcast our routes. - */ - if (supplier || advertise_mhome) { - timevalsub(&t2, &next_bcast, &now); - if (t2.tv_sec <= 0) { - /* Synchronize the aging and broadcast - * timers to minimize awakenings - */ - age(0); - - rip_bcast(0); - - /* It is desirable to send routing updates - * regularly. So schedule the next update - * 30 seconds after the previous one was - * secheduled, instead of 30 seconds after - * the previous update was finished. - * Even if we just started after discovering - * a 2nd interface or were otherwise delayed, - * pick a 30-second aniversary of the - * original broadcast time. - */ - n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; - next_bcast.tv_sec += n*SUPPLY_INTERVAL; - - continue; - } - - if (timercmp(&t2, &wtime, <)) - wtime = t2; - } - - /* If we need a flash update, either do it now or - * set the delay to end when it is time. - * - * If we are within MIN_WAITTIME seconds of a full update, - * do not bother. - */ - if (need_flash - && supplier - && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { - /* accurate to the millisecond */ - if (!timercmp(&no_flash, &now, >)) - rip_bcast(1); - timevalsub(&t2, &no_flash, &now); - if (timercmp(&t2, &wtime, <)) - wtime = t2; - } - - /* trigger the main aging timer. - */ - timevalsub(&t2, &age_timer, &now); - if (t2.tv_sec <= 0) { - age(0); - continue; - } - if (timercmp(&t2, &wtime, <)) - wtime = t2; - - /* update the kernel routing table - */ - timevalsub(&t2, &need_kern, &now); - if (t2.tv_sec <= 0) { - age(0); - continue; - } - if (timercmp(&t2, &wtime, <)) - wtime = t2; - - /* take care of router discovery, - * but do it to the millisecond - */ - if (!timercmp(&rdisc_timer, &now, >)) { - rdisc_age(0); - continue; - } - timevalsub(&t2, &rdisc_timer, &now); - if (timercmp(&t2, &wtime, <)) - wtime = t2; - - - /* wait for input or a timer to expire. - */ - trace_flush(); - ibits = fdbits; - n = select(sock_max, &ibits, 0, 0, &wtime); - if (n <= 0) { - if (n < 0 && errno != EINTR && errno != EAGAIN) - BADERR(1,"select"); - continue; - } - - if (FD_ISSET(rt_sock, &ibits)) { - read_rt(); - n--; - } - if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { - read_d(); - n--; - } - if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { - read_rip(rip_sock, 0); - n--; - } - - for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) { - if (ifp->int_rip_sock >= 0 - && FD_ISSET(ifp->int_rip_sock, &ibits)) { - read_rip(ifp->int_rip_sock, ifp); - n--; - } - } - } -} - - -/* ARGSUSED */ -void -sigalrm(int sig) -{ - /* Historically, SIGALRM would cause the daemon to check for - * new and broken interfaces. - */ - ifinit_timer.tv_sec = now.tv_sec; - trace_act("SIGALRM\n"); -} - - -/* watch for fatal signals */ -void -sigterm(int sig) -{ - stopint = sig; - (void)signal(sig, SIG_DFL); /* catch it only once */ -} - - -void -fix_select(void) -{ - struct interface *ifp; - - - FD_ZERO(&fdbits); - sock_max = 0; - - FD_SET(rt_sock, &fdbits); - if (sock_max <= rt_sock) - sock_max = rt_sock+1; - if (rip_sock >= 0) { - FD_SET(rip_sock, &fdbits); - if (sock_max <= rip_sock) - sock_max = rip_sock+1; - } - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { - if (ifp->int_rip_sock >= 0) { - FD_SET(ifp->int_rip_sock, &fdbits); - if (sock_max <= ifp->int_rip_sock) - sock_max = ifp->int_rip_sock+1; - } - } - if (rdisc_sock >= 0) { - FD_SET(rdisc_sock, &fdbits); - if (sock_max <= rdisc_sock) - sock_max = rdisc_sock+1; - } -} - - -void -fix_sock(int sock, - char *name) -{ - int on; -#define MIN_SOCKBUF (4*1024) - static int rbuf; - - if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) - logbad(1, "fcntl(%s) O_NONBLOCK: %s", - name, strerror(errno)); - on = 1; - if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, - &on,sizeof(on)) < 0) - msglog("setsockopt(%s,SO_BROADCAST): %s", - name, strerror(errno)); - if (rbuf >= MIN_SOCKBUF) { - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, - &rbuf, sizeof(rbuf)) < 0) - msglog("setsockopt(%s,SO_RCVBUF=%d): %s", - name, rbuf, strerror(errno)); - } else { - for (rbuf = 60*1024; ; rbuf -= 4096) { - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, - &rbuf, sizeof(rbuf)) == 0) { - trace_act("RCVBUF=%d\n", rbuf); - break; - } - if (rbuf < MIN_SOCKBUF) { - msglog("setsockopt(%s,SO_RCVBUF = %d): %s", - name, rbuf, strerror(errno)); - break; - } - } - } -} - - -/* get a rip socket - */ -static int /* <0 or file descriptor */ -get_rip_sock(naddr addr, - int serious) /* 1=failure to bind is serious */ -{ - struct sockaddr_in sin; - unsigned char ttl; - int s; - - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - BADERR(1,"rip_sock = socket()"); - - bzero(&sin,sizeof(sin)); -#ifdef _HAVE_SIN_LEN - sin.sin_len = sizeof(sin); -#endif - 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 (serious) - BADERR(errno != EADDRINUSE, "bind(rip_sock)"); - return -1; - } - fix_sock(s,"rip_sock"); - - ttl = 1; - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, - &ttl, sizeof(ttl)) < 0) - DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)"); - - return s; -} - - -/* turn off main RIP socket */ -void -rip_off(void) -{ - struct interface *ifp; - register naddr addr; - - - if (rip_sock >= 0 && !mhome) { - trace_act("turn off RIP\n"); - - (void)close(rip_sock); - rip_sock = -1; - - /* get non-broadcast sockets to listen to queries. - */ - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - if (ifp->int_rip_sock < 0 - && !(ifp->int_state & IS_ALIAS)) { - addr = ((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); - ifp->int_rip_sock = get_rip_sock(addr, 0); - } - } - - fix_select(); - - age(0); - } -} - - -/* turn on RIP multicast input via an interface - */ -static void -rip_mcast_on(struct interface *ifp) -{ - struct ip_mreq m; - - if (!IS_RIP_IN_OFF(ifp->int_state) - && (ifp->int_if_flags & IFF_MULTICAST) -#ifdef MCAST_PPP_BUG - && !(ifp->int_if_flags & IFF_POINTOPOINT) -#endif - && !(ifp->int_state & IS_ALIAS)) { - m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); - m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); - if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP, - &m, sizeof(m)) < 0) - LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)"); - } -} - - -/* Prepare socket used for RIP. - */ -void -rip_on(struct interface *ifp) -{ - /* If the main RIP socket is already alive, only start receiving - * multicasts for this interface. - */ - if (rip_sock >= 0) { - if (ifp != 0) - rip_mcast_on(ifp); - return; - } - - /* If the main RIP socket is off, and it makes sense to turn it on, - * turn it on for all of the interfaces. - */ - if (rip_interfaces > 0 && !rdisc_ok) { - trace_act("turn on RIP\n"); - - /* Close all of the query sockets so that we can open - * the main socket. SO_REUSEPORT is not a solution, - * since that would let two daemons bind to the broadcast - * socket. - */ - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - if (ifp->int_rip_sock >= 0) { - (void)close(ifp->int_rip_sock); - ifp->int_rip_sock = -1; - } - } - - rip_sock = get_rip_sock(INADDR_ANY, 1); - rip_sock_mcast = 0; - - /* Do not advertise anything until we have heard something - */ - if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) - next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; - - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - if (!IS_RIP_IN_OFF(ifp->int_state)) - ifp->int_state &= ~IS_RIP_QUERIED; - rip_mcast_on(ifp); - } - - ifinit_timer.tv_sec = now.tv_sec; - - fix_select(); - - } else if (ifp != 0 - && ifp->int_rip_sock < 0 - && !(ifp->int_state & IS_ALIAS)) { - /* RIP is off, so ensure there are sockets on which - * to listen for queries. - */ - ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); - - fix_select(); - } -} - - -/* die if malloc(3) fails - */ -void * -rtmalloc(size_t size, - char *msg) -{ - void *p = malloc(size); - if (p == 0) - logbad(1,"malloc() failed in %s", msg); - return p; -} - - -/* get a random instant in an interval - */ -void -intvl_random(struct timeval *tp, /* put value here */ - u_long lo, /* value is after this second */ - u_long hi) /* and before this */ -{ - tp->tv_sec = (time_t)(hi == lo - ? lo - : (lo + random() % ((hi - lo)))); - tp->tv_usec = random() % 1000000; -} - - -void -timevaladd(struct timeval *t1, - struct timeval *t2) -{ - - t1->tv_sec += t2->tv_sec; - if ((t1->tv_usec += t2->tv_usec) > 1000000) { - t1->tv_sec++; - t1->tv_usec -= 1000000; - } -} - - -/* t1 = t2 - t3 - */ -static void -timevalsub(struct timeval *t1, - struct timeval *t2, - struct timeval *t3) -{ - t1->tv_sec = t2->tv_sec - t3->tv_sec; - if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { - t1->tv_sec--; - t1->tv_usec += 1000000; - } -} - - -void -msglog(char *p, ...) -{ - va_list args; - - trace_flush(); - - va_start(args, p); - vsyslog(LOG_ERR, p, args); - - if (ftrace != 0) { - if (ftrace == stdout) - (void)fputs("routed: ", ftrace); - (void)vfprintf(ftrace, p, args); - (void)fputc('\n', ftrace); - } -} - - -void -logbad(int dump, char *p, ...) -{ - va_list args; - - trace_flush(); - - va_start(args, p); - vsyslog(LOG_ERR, p, args); - - (void)fputs("routed: ", stderr); - (void)vfprintf(stderr, p, args); - (void)fputs("; giving up\n",stderr); - (void)fflush(stderr); - - if (dump) - abort(); - exit(1); -} diff --git a/usr.sbin/routed/output.c b/usr.sbin/routed/output.c deleted file mode 100644 index 5f646d890a8d..000000000000 --- a/usr.sbin/routed/output.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#include "defs.h" - - -int update_seqno; - - -/* walk the tree of routes with this for output - */ -struct { - struct sockaddr_in to; - naddr to_mask; - naddr to_net; - naddr to_std_mask; - naddr to_std_net; - struct interface *ifp; /* usually output interface */ - struct ws_buf { /* info for each buffer */ - struct rip *buf; - struct netinfo *n; - struct netinfo *base; - struct netinfo *lim; - enum output_type type; - } v12, v2; - char metric; /* adjust metrics by interface */ - int npackets; - int gen_limit; - u_int state; -#define WS_ST_FLASH 0x001 /* send only changed routes */ -#define WS_ST_RIP2_SAFE 0x002 /* send RIPv2 safe for RIPv1 */ -#define WS_ST_RIP2_ALL 0x004 /* send full featured RIPv2 */ -#define WS_ST_AG 0x008 /* ok to aggregate subnets */ -#define WS_ST_SUPER_AG 0x010 /* ok to aggregate networks */ -#define WS_ST_SUB_AG 0x020 /* aggregate subnets in odd case */ -#define WS_ST_QUERY 0x040 /* responding to a query */ -#define WS_ST_TO_ON_NET 0x080 /* sending onto one of our nets */ -#define WS_ST_DEFAULT 0x100 /* faking a default */ -#define WS_ST_PM_RDISC 0x200 /* poor-man's router discovery */ -} ws; - -/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ -union pkt_buf ripv12_buf; - -/* Another for only RIPv2 listeners */ -union pkt_buf rip_v2_buf; - - - -/* Send the contents of the global buffer via the non-multicast socket - */ -int /* <0 on failure */ -output(enum output_type type, - struct sockaddr_in *dst, /* send to here */ - struct interface *ifp, - struct rip *buf, - int size) /* this many bytes */ -{ - struct sockaddr_in sin; - int flags; - char *msg; - int res; - naddr tgt_mcast; - int soc; - int serrno; - - sin = *dst; - if (sin.sin_port == 0) - sin.sin_port = htons(RIP_PORT); -#ifdef _HAVE_SIN_LEN - if (sin.sin_len == 0) - sin.sin_len = sizeof(sin); -#endif - - soc = rip_sock; - flags = 0; - - switch (type) { - case OUT_QUERY: - msg = "Answer Query"; - if (soc < 0) - soc = ifp->int_rip_sock; - break; - case OUT_UNICAST: - msg = "Send"; - if (soc < 0) - soc = ifp->int_rip_sock; - flags = MSG_DONTROUTE; - break; - case OUT_BROADCAST: - if (ifp->int_if_flags & IFF_POINTOPOINT) { - msg = "Send"; - } else { - msg = "Send bcast"; - } - flags = MSG_DONTROUTE; - break; - case OUT_MULTICAST: - if (ifp->int_if_flags & IFF_POINTOPOINT) { - msg = "Send pt-to-pt"; - } else if (ifp->int_state & IS_DUP) { - trace_act("abort multicast output via %s" - " with duplicate address\n", - ifp->int_name); - return 0; - } else { - msg = "Send mcast"; - if (rip_sock_mcast != ifp) { -#ifdef MCAST_PPP_BUG - /* Do not specifiy the primary interface - * explicitly if we have the multicast - * point-to-point kernel bug, since the - * kernel will do the wrong thing if the - * local address of a point-to-point link - * is the same as the address of an ordinary - * interface. - */ - if (ifp->int_addr == myaddr) { - tgt_mcast = 0; - } else -#endif - tgt_mcast = ifp->int_addr; - if (0 > setsockopt(rip_sock, - IPPROTO_IP, IP_MULTICAST_IF, - &tgt_mcast, - sizeof(tgt_mcast))) { - serrno = errno; - LOGERR("setsockopt(rip_sock," - "IP_MULTICAST_IF)"); - errno = serrno; - ifp = 0; - return -1; - } - rip_sock_mcast = ifp; - } - sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - } - - case NO_OUT_MULTICAST: - case NO_OUT_RIPV2: - break; - } - - trace_rip(msg, "to", &sin, ifp, buf, size); - - res = sendto(soc, buf, size, flags, - (struct sockaddr *)&sin, sizeof(sin)); - if (res < 0 - && (ifp == 0 || !(ifp->int_state & IS_BROKE))) { - serrno = errno; - msglog("%s sendto(%s%s%s.%d): %s", msg, - ifp != 0 ? ifp->int_name : "", - ifp != 0 ? ", " : "", - inet_ntoa(sin.sin_addr), - ntohs(sin.sin_port), - strerror(errno)); - errno = serrno; - } - - return res; -} - - -/* install authentication if appropriate - */ -static void -set_auth(struct ws_buf *w) -{ - if (ws.ifp != 0 - && ws.ifp->int_passwd[0] != '\0' - && (ws.state & WS_ST_RIP2_SAFE)) { - w->n->n_family = RIP_AF_AUTH; - ((struct netauth*)w->n)->a_type = RIP_AUTH_PW; - bcopy(ws.ifp->int_passwd, ((struct netauth*)w->n)->au.au_pw, - sizeof(((struct netauth*)w->n)->au.au_pw)); - w->n++; - } -} - - -/* Send the buffer - */ -static void -supply_write(struct ws_buf *wb) -{ - /* Output multicast only if legal. - * If we would multcast and it would be illegal, then discard the - * packet. - */ - switch (wb->type) { - case NO_OUT_MULTICAST: - trace_pkt("skip multicast to %s because impossible\n", - naddr_ntoa(ws.to.sin_addr.s_addr)); - break; - case NO_OUT_RIPV2: - break; - default: - if (output(wb->type, &ws.to, ws.ifp, wb->buf, - ((char *)wb->n - (char*)wb->buf)) < 0 - && ws.ifp != 0) - if_sick(ws.ifp); - ws.npackets++; - break; - } - - bzero(wb->n = wb->base, sizeof(*wb->n)*NETS_LEN); - if (wb->buf->rip_vers == RIPv2) - set_auth(wb); -} - - -/* put an entry into the packet - */ -static void -supply_out(struct ag_info *ag) -{ - int i; - naddr mask, v1_mask, s_mask, dst_h, ddst_h; - struct ws_buf *wb; - - - /* Skip this route if doing a flash update and it and the routes - * it aggregates have not changed recently. - */ - if (ag->ag_seqno < update_seqno - && (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), - (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0); - s_mask = std_mask(htonl(dst_h)); - i = 0; - - /* If we are sending RIPv2 packets that cannot (or must not) be - * heard by RIPv1 listeners, do not worry about sub- or supernets. - * Subnets (from other networks) can only be sent via multicast. - * A pair of subnet routes might have been promoted so that they - * are legal to send by RIPv1. - * If RIPv1 is off, use the multicast buffer, unless this is the - * fake default route and it is acting as a poor-man's router- - * discovery mechanism. - */ - if (((ws.state & WS_ST_RIP2_ALL) - && (dst_h != RIP_DEFAULT || !(ws.state & WS_ST_PM_RDISC))) - || ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { - /* use the RIPv2-only buffer */ - wb = &ws.v2; - - } else { - /* use the RIPv1-or-RIPv2 buffer */ - wb = &ws.v12; - - /* Convert supernet route into corresponding set of network - * routes for RIPv1, but leave non-contiguous netmasks - * to ag_check(). - */ - if (v1_mask > mask - && mask + (mask & -mask) == 0) { - ddst_h = v1_mask & -v1_mask; - i = (v1_mask & ~mask)/ddst_h; - - if (i > ws.gen_limit) { - /* 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 - i = 0; - - } else { - mask = v1_mask; - ws.gen_limit -= i; - } - } - } - - do { - wb->n->n_family = RIP_AF_INET; - wb->n->n_dst = htonl(dst_h); - /* If the route is from router-discovery or we are - * shutting down, admit only a bad metric. - */ - wb->n->n_metric = ((stopint || ag->ag_metric < 1) - ? HOPCNT_INFINITY - : ag->ag_metric); - HTONL(wb->n->n_metric); - if (wb->buf->rip_vers == RIPv2) { - if (ag->ag_nhop != 0 - && (ws.state & WS_ST_RIP2_SAFE) - && ((ws.state & WS_ST_QUERY) - || (ag->ag_nhop != ws.ifp->int_addr - && on_net(ag->ag_nhop, - ws.ifp->int_net, - ws.ifp->int_mask)))) - wb->n->n_nhop = ag->ag_nhop; - if ((ws.state & WS_ST_RIP2_ALL) - || mask != s_mask) - wb->n->n_mask = htonl(mask); - wb->n->n_tag = ag->ag_tag; - } - dst_h += ddst_h; - - if (++wb->n >= wb->lim) - supply_write(wb); - } while (i-- != 0); -} - - -/* supply one route from the table - */ -/* ARGSUSED */ -static int -walk_supply(struct radix_node *rn, - struct walkarg *w) -{ -#define RT ((struct rt_entry *)rn) - u_short ags = 0; - char metric, pref; - naddr dst, nhop; - - - /* Do not advertise the loopback interface - * or external remote interfaces - */ - if (RT->rt_ifp != 0 - && ((RT->rt_ifp->int_if_flags & IFF_LOOPBACK) - || (RT->rt_ifp->int_state & IS_EXTERNAL)) - && !(RT->rt_state & RS_MHOME)) - return 0; - - /* If being quiet about our ability to forward, then - * do not say anything unless responding to a query. - */ - if (!supplier && !(ws.state & WS_ST_QUERY)) - return 0; - - dst = RT->rt_dst; - - /* do not collide with the fake default route */ - if (dst == RIP_DEFAULT - && (ws.state & WS_ST_DEFAULT)) - return 0; - - if (RT->rt_state & RS_NET_SYN) { - if (RT->rt_state & RS_NET_INT) { - /* Do not send manual synthetic network routes - * into the subnet. - */ - if (on_net(ws.to.sin_addr.s_addr, - ntohl(dst), RT->rt_mask)) - return 0; - - } else { - /* Do not send automatic synthetic network routes - * if they are not needed becaus no RIPv1 listeners - * can hear them. - */ - if (ws.state & WS_ST_RIP2_ALL) - return 0; - - /* Do not send automatic synthetic network routes to - * the real subnet. - */ - if (on_net(ws.to.sin_addr.s_addr, - ntohl(dst), RT->rt_mask)) - return 0; - } - nhop = 0; - - } else { - /* 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. - */ - if (!(RT->rt_state & RS_IF) - && RT->rt_gate != myaddr - && RT->rt_gate != loopaddr) - nhop = RT->rt_gate; - else - nhop = 0; - } - - /* Adjust the outgoing metric by the cost of the link. - */ - pref = metric = RT->rt_metric + ws.metric; - if (pref < HOPCNT_INFINITY) { - /* Keep track of the best metric with which the - * route has been advertised recently. - */ - if (RT->rt_poison_metric >= metric - || RT->rt_poison_time <= now_garbage) { - RT->rt_poison_time = now.tv_sec; - RT->rt_poison_metric = RT->rt_metric; - } - - } else { - /* Do not advertise stable routes that will be ignored, - * unless they are being held down and poisoned. If the - * route recently was advertised with a metric that would - * have been less than infinity through this interface, we - * need to continue to advertise it in order to poison it. - */ - pref = RT->rt_poison_metric + ws.metric; - if (pref >= HOPCNT_INFINITY) - return 0; - - metric = HOPCNT_INFINITY; - } - - if (RT->rt_state & RS_MHOME) { - /* retain host route of multi-homed servers */ - ; - - } else if (RT_ISHOST(RT)) { - /* We should always aggregate 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; - - } else if (ws.state & WS_ST_AG) { - /* Aggregate network routes, if we are allowed. - */ - ags |= AGS_SUPPRESS; - - /* Generate supernets if allowed. - * If we can be heard by RIPv1 systems, we will - * 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; - - } - - /* Do not send RIPv1 advertisements of subnets to other - * networks. If possible, multicast them by RIPv2. - */ - 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; - } - - /* Do not send a route back to where it came from, except in - * response to a query. This is "split-horizon". That means not - * advertising back to the same network and so via the same interface. - * - * 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. - * - * Include the routes for both ends of point-to-point interfaces - * since the other side presumably knows them as well as we do. - */ - if (RT->rt_ifp == ws.ifp && ws.ifp != 0 - && !(ws.state & WS_ST_QUERY) - && (ws.state & WS_ST_TO_ON_NET) - && (!(RT->rt_state & RS_IF) - || ws.ifp->int_if_flags & IFF_POINTOPOINT)) { - ags |= AGS_SPLIT_HZ; - ags &= ~(AGS_PROMOTE | AGS_SUPPRESS); - } - - ag_check(dst, RT->rt_mask, 0, nhop, metric, pref, - RT->rt_seqno, RT->rt_tag, ags, supply_out); - return 0; -#undef RT -} - - -/* Supply dst with the contents of the routing tables. - * If this won't fit in one packet, chop it up into several. - */ -void -supply(struct sockaddr_in *dst, - struct interface *ifp, /* output interface */ - enum output_type type, - int flash, /* 1=flash update */ - int vers) /* RIP version */ -{ - static int init = 1; - struct rt_entry *rt; - - - ws.state = 0; - ws.gen_limit = 1024; - - ws.to = *dst; - ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); - ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; - - if (ifp != 0) { - ws.to_mask = ifp->int_mask; - ws.to_net = ifp->int_net; - if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask)) - ws.state |= WS_ST_TO_ON_NET; - - } else { - ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0); - ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; - rt = rtfind(dst->sin_addr.s_addr); - if (rt) - ifp = rt->rt_ifp; - } - - 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; - } else { - /* Adjust the advertised metric by the outgoing interface - * metric. - */ - ws.metric = ifp->int_metric+1; - } - - if (init) { - init = 0; - - bzero(&ripv12_buf, sizeof(ripv12_buf)); - ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE; - ws.v12.buf = &ripv12_buf.rip; - ws.v12.base = &ws.v12.buf->rip_nets[0]; - ws.v12.lim = ws.v12.base + NETS_LEN; - - bzero(&rip_v2_buf, sizeof(rip_v2_buf)); - rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE; - rip_v2_buf.rip.rip_vers = RIPv2; - ws.v2.buf = &rip_v2_buf.rip; - ws.v2.base = &ws.v2.buf->rip_nets[0]; - ws.v2.lim = ws.v2.base + NETS_LEN; - } - ripv12_buf.rip.rip_vers = vers; - - ws.v12.n = ws.v12.base; - set_auth(&ws.v12); - ws.v2.n = ws.v2.base; - set_auth(&ws.v2); - - switch (type) { - case OUT_BROADCAST: - ws.v2.type = ((ws.ifp != 0 - && (ws.ifp->int_if_flags & IFF_MULTICAST)) - ? OUT_MULTICAST - : NO_OUT_MULTICAST); - ws.v12.type = OUT_BROADCAST; - break; - case OUT_MULTICAST: - ws.v2.type = ((ws.ifp != 0 - && (ws.ifp->int_if_flags & IFF_MULTICAST)) - ? OUT_MULTICAST - : NO_OUT_MULTICAST); - ws.v12.type = OUT_BROADCAST; - break; - case OUT_UNICAST: - case OUT_QUERY: - ws.v2.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; - ws.v12.type = type; - break; - default: - ws.v2.type = type; - ws.v12.type = type; - break; - } - - if (vers == RIPv2) { - /* if asked to send RIPv2, send at least that which can - * be safely heard by RIPv1 listeners. - */ - ws.state |= WS_ST_RIP2_SAFE; - - /* full RIPv2 only if cannot be heard by RIPv1 listeners */ - if (type != OUT_BROADCAST) - ws.state |= WS_ST_RIP2_ALL; - if (!(ws.state & WS_ST_TO_ON_NET)) { - ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); - } else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) { - ws.state |= WS_ST_AG; - if (type != OUT_BROADCAST - && (ws.ifp == 0 - || !(ws.ifp->int_state & IS_NO_SUPER_AG))) - ws.state |= WS_ST_SUPER_AG; - } - - } else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) { - ws.state |= WS_ST_SUB_AG; - } - - if (supplier) { - /* Fake a default route if asked, and if there is not - * a better, real default route. - */ - if (ifp->int_d_metric != 0 - && (0 == (rt = rtget(RIP_DEFAULT, 0)) - || rt->rt_metric+ws.metric >= ifp->int_d_metric)) { - ws.state |= WS_ST_DEFAULT; - ag_check(0, 0, 0, 0, - ifp->int_d_metric,ifp->int_d_metric, - 0, 0, 0, supply_out); - } - if ((ws.state & WS_ST_RIP2_ALL) - && (ifp->int_state & IS_PM_RDISC)) { - ws.state |= WS_ST_PM_RDISC; - ripv12_buf.rip.rip_vers = RIPv1; - } - } - - (void)rn_walktree(rhead, walk_supply, 0); - ag_flush(0,0,supply_out); - - /* Flush the packet buffers, provided they are not empty and - * do not contain only the password. - */ - if (ws.v12.n != ws.v12.base - && (ws.v12.n > ws.v12.base+1 - || ws.v12.n->n_family != RIP_AF_AUTH)) - supply_write(&ws.v12); - if (ws.v2.n != ws.v2.base - && (ws.v2.n > ws.v2.base+1 - || ws.v2.n->n_family != RIP_AF_AUTH)) - supply_write(&ws.v2); - - /* If we sent nothing and this is an answer to a query, send - * an empty buffer. - */ - if (ws.npackets == 0 - && (ws.state & WS_ST_QUERY)) - supply_write(&ws.v12); -} - - -/* send all of the routing table or just do a flash update - */ -void -rip_bcast(int flash) -{ -#ifdef _HAVE_SIN_LEN - static struct sockaddr_in dst = {sizeof(dst), AF_INET}; -#else - static struct sockaddr_in dst = {AF_INET}; -#endif - struct interface *ifp; - enum output_type type; - int vers; - struct timeval rtime; - - - need_flash = 0; - intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); - no_flash = rtime; - timevaladd(&no_flash, &now); - - if (rip_sock < 0) - return; - - trace_act("send %s and inhibit dynamic updates for %.3f sec\n", - flash ? "dynamic update" : "all routes", - rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0); - - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - /* skip interfaces not doing RIP, those already queried, - * and aliases. Do try broken interfaces to see - * if they have healed. - */ - if (0 != (ifp->int_state & (IS_PASSIVE | IS_ALIAS))) - continue; - - /* skip turned off interfaces */ - if (!iff_alive(ifp->int_if_flags)) - continue; - - /* default to RIPv1 output */ - if (ifp->int_state & IS_NO_RIPV1_OUT) { - /* Say nothing if this interface is turned off */ - if (ifp->int_state & IS_NO_RIPV2_OUT) - continue; - vers = RIPv2; - } else { - vers = RIPv1; - } - - 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. - */ - if (vers == RIPv2 - && (ifp->int_state & IS_NO_RIPV1_OUT)) { - type = OUT_MULTICAST; - } else { - type = OUT_BROADCAST; - } - - } else if (ifp->int_if_flags & IFF_POINTOPOINT) { - /* point-to-point hardware interface */ - dst.sin_addr.s_addr = ifp->int_dstaddr; - type = OUT_UNICAST; - - } else { - /* remote interface */ - dst.sin_addr.s_addr = ifp->int_addr; - type = OUT_UNICAST; - } - - supply(&dst, ifp, type, flash, vers); - } - - update_seqno++; /* all routes are up to date */ -} - - -/* Ask for routes - * Do it only once to an interface, and not even after the interface - * was broken and recovered. - */ -void -rip_query(void) -{ -#ifdef _HAVE_SIN_LEN - static struct sockaddr_in dst = {sizeof(dst), AF_INET}; -#else - static struct sockaddr_in dst = {AF_INET}; -#endif - struct interface *ifp; - struct rip buf; - enum output_type type; - - - if (rip_sock < 0) - return; - - bzero(&buf, sizeof(buf)); - - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - /* skip interfaces not doing RIP, those already queried, - * and aliases. Do try broken interfaces to see - * if they have healed. - */ - if (0 != (ifp->int_state & (IS_RIP_QUERIED - | IS_PASSIVE | IS_ALIAS))) - continue; - - /* skip turned off interfaces */ - if (!iff_alive(ifp->int_if_flags)) - continue; - - /* default to RIPv1 output */ - if (ifp->int_state & IS_NO_RIPV2_OUT) { - /* Say nothing if this interface is turned off */ - if (ifp->int_state & IS_NO_RIPV1_OUT) - continue; - buf.rip_vers = RIPv1; - } else { - buf.rip_vers = RIPv2; - } - - buf.rip_cmd = RIPCMD_REQUEST; - buf.rip_nets[0].n_family = RIP_AF_UNSPEC; - buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); - - 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. - */ - if (buf.rip_vers == RIPv2 - && (ifp->int_state & IS_NO_RIPV1_OUT)) { - type = OUT_MULTICAST; - } else { - type = OUT_BROADCAST; - } - - } else if (ifp->int_if_flags & IFF_POINTOPOINT) { - /* point-to-point hardware interface */ - dst.sin_addr.s_addr = ifp->int_dstaddr; - type = OUT_UNICAST; - - } else { - /* remote interface */ - dst.sin_addr.s_addr = ifp->int_addr; - type = OUT_UNICAST; - } - - ifp->int_state |= IS_RIP_QUERIED; - if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0) - if_sick(ifp); - } -} diff --git a/usr.sbin/routed/parms.c b/usr.sbin/routed/parms.c deleted file mode 100644 index 1fc0b857b58a..000000000000 --- a/usr.sbin/routed/parms.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; -#endif /* not lint */ - -#ident "$Revision: 1.1 $" - -#include "defs.h" -#include "pathnames.h" - - -struct parm *parms; -struct intnet *intnets; - - -/* parse a set of parameters for an interface - */ -char * /* error message */ -parse_parms(char *line) -{ -#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt))) -#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str)))) -#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \ - parm.parm_int_state |= (b);} -#define DELIMS " ,\t\n" - struct parm parm, *parmp; - struct intnet *intnetp; - char *tok, *tgt, *p; - - - /* "subnet=x.y.z.u/mask" must be alone on the line */ - if (!strncasecmp("subnet=",line,7)) { - intnetp = (struct intnet*)malloc(sizeof(*intnetp)); - if (!getnet(&line[7], &intnetp->intnet_addr, - &intnetp->intnet_mask)) { - free(intnetp); - return line; - } - HTONL(intnetp->intnet_addr); - intnetp->intnet_next = intnets; - intnets = intnetp; - return 0; - } - - bzero(&parm, sizeof(parm)); - - tgt = "null"; - for (tok = strtok(line, DELIMS); - tok != 0 && tok[0] != '\0'; - tgt = 0, tok = strtok(0,DELIMS)) { - if (PARSE("if")) { - if (parm.parm_name[0] != '\0' - || tok[3] == '\0' - || strlen(tok) > IFNAMSIZ+3) - break; - strcpy(parm.parm_name, tok+3); - - } else if (PARSE("passwd")) { - if (tok[7] == '\0' - || strlen(tok) > RIP_AUTH_PW_LEN+7) - break; - strcpy(parm.parm_passwd, tok+7); - - } else if (PARS("no_ag")) { - parm.parm_int_state |= IS_NO_AG; - - } else if (PARS("no_super_ag")) { - parm.parm_int_state |= IS_NO_SUPER_AG; - - } else if (PARS("no_rip")) { - parm.parm_int_state |= (IS_NO_RIPV1_IN - | IS_NO_RIPV2_IN - | IS_NO_RIPV1_OUT - | IS_NO_RIPV2_OUT); - - } else if (PARS("no_ripv1_in")) { - parm.parm_int_state |= IS_NO_RIPV1_IN; - - } else if (PARS("no_ripv2_in")) { - parm.parm_int_state |= IS_NO_RIPV2_IN; - - } else if (PARS("no_ripv2_out")) { - parm.parm_int_state |= IS_NO_RIPV2_OUT; - - } else if (PARS("ripv2_out")) { - if (parm.parm_int_state & IS_NO_RIPV2_OUT) - break; - parm.parm_int_state |= IS_NO_RIPV1_OUT; - - } else if (PARS("no_rdisc")) { - CKF((GROUP_IS_SOL|GROUP_IS_ADV), - IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT); - - } else if (PARS("no_solicit")) { - CKF(GROUP_IS_SOL, IS_NO_SOL_OUT); - - } else if (PARS("send_solicit")) { - CKF(GROUP_IS_SOL, IS_SOL_OUT); - - } else if (PARS("no_rdisc_adv")) { - CKF(GROUP_IS_ADV, IS_NO_ADV_OUT); - - } else if (PARS("rdisc_adv")) { - CKF(GROUP_IS_ADV, IS_ADV_OUT); - - } else if (PARS("bcast_rdisc")) { - parm.parm_int_state |= IS_BCAST_RDISC; - - } else if (PARSE("rdisc_pref")) { - if (parm.parm_rdisc_pref != 0 - || tok[11] == '\0' - || (parm.parm_rdisc_pref = (int)strtol(&tok[11], - &p,0), - *p != '\0')) - break; - - } else if (PARSE("rdisc_interval")) { - if (parm.parm_rdisc_int != 0 - || tok[15] == '\0' - || (parm.parm_rdisc_int = (int)strtol(&tok[15], - &p,0), - *p != '\0') - || parm.parm_rdisc_int < MinMaxAdvertiseInterval - || parm.parm_rdisc_int > MaxMaxAdvertiseInterval) - break; - - } else if (PARSE("fake_default")) { - if (parm.parm_d_metric != 0 - || tok[13] == '\0' - || (parm.parm_d_metric=(int)strtol(&tok[13],&p,0), - *p != '\0') - || parm.parm_d_metric >= HOPCNT_INFINITY-2) - break; - - } else { - tgt = tok; - break; - } - } - if (tgt != 0) - return tgt; - - if (parm.parm_int_state & IS_NO_ADV_IN) - parm.parm_int_state |= IS_NO_SOL_OUT; - - /* check for duplicate specification */ - for (parmp = parms; parmp != 0; parmp = parmp->parm_next) { - if (strcmp(parm.parm_name, parmp->parm_name)) - continue; - if (parmp->parm_a_h != (parm.parm_a_h & parmp->parm_m) - && parm.parm_a_h != (parmp->parm_a_h & parm.parm_m)) - continue; - - if (strcmp(parmp->parm_passwd, parm.parm_passwd) - || (0 != (parm.parm_int_state & GROUP_IS_SOL) - && 0 != (parmp->parm_int_state & GROUP_IS_SOL) - && 0 != ((parm.parm_int_state ^ parmp->parm_int_state) - && GROUP_IS_SOL)) - || (0 != (parm.parm_int_state & GROUP_IS_ADV) - && 0 != (parmp->parm_int_state & GROUP_IS_ADV) - && 0 != ((parm.parm_int_state ^ parmp->parm_int_state) - && GROUP_IS_ADV)) - || (parm.parm_rdisc_pref != 0 - && parmp->parm_rdisc_pref != 0 - && parm.parm_rdisc_pref != parmp->parm_rdisc_pref) - || (parm.parm_rdisc_int != 0 - && parmp->parm_rdisc_int != 0 - && parm.parm_rdisc_int != parmp->parm_rdisc_int) - || (parm.parm_d_metric != 0 - && parmp->parm_d_metric != 0 - && parm.parm_d_metric != parmp->parm_d_metric)) - return "duplicate"; - } - - parmp = (struct parm*)malloc(sizeof(*parmp)); - bcopy(&parm, parmp, sizeof(*parmp)); - parmp->parm_next = parms; - parms = parmp; - - return 0; -#undef DELIMS -#undef PARS -#undef PARSE -} - - -/* use configured parameters - */ -void -get_parms(struct interface *ifp) -{ - struct parm *parmp; - - for (parmp = parms; parmp != 0; parmp = parmp->parm_next) { - if ((parmp->parm_a_h == (ntohl(ifp->int_addr) - & parmp->parm_m) - && parmp->parm_name[0] == '\0') - || (parmp->parm_name[0] != '\0' - && !strcmp(ifp->int_name, parmp->parm_name))) { - ifp->int_state |= parmp->parm_int_state; - bcopy(parmp->parm_passwd, ifp->int_passwd, - sizeof(ifp->int_passwd)); - ifp->int_rdisc_pref = parmp->parm_rdisc_pref; - ifp->int_rdisc_int = parmp->parm_rdisc_int; - ifp->int_d_metric = parmp->parm_d_metric; - } - } - - if ((ifp->int_state & IS_NO_RIP_IN) == IS_NO_RIP_IN) - ifp->int_state |= IS_NO_RIP_OUT; - - if (ifp->int_rdisc_int == 0) - ifp->int_rdisc_int = DefMaxAdvertiseInterval; - - if ((ifp->int_state & IS_PASSIVE) - || (ifp->int_state & IS_REMOTE)) - ifp->int_state |= IS_NO_ADV_IN|IS_NO_SOL_OUT|IS_NO_ADV_OUT; - - - if (!(ifp->int_state & IS_PASSIVE)) { - if (!(ifp->int_if_flags & IFF_MULTICAST) - && !(ifp->int_if_flags & IFF_POINTOPOINT)) - ifp->int_state |= IS_NO_RIPV2_OUT; - } - - if (!(ifp->int_if_flags & IFF_MULTICAST)) - ifp->int_state |= IS_BCAST_RDISC; - - if (ifp->int_if_flags & IFF_POINTOPOINT) { - ifp->int_state |= IS_BCAST_RDISC; - /* point-to-point links should be passive for the sake - * of demand-dialing - */ - if (0 == (ifp->int_state & GROUP_IS_SOL)) - ifp->int_state |= IS_NO_SOL_OUT; - if (0 == (ifp->int_state & GROUP_IS_ADV)) - ifp->int_state |= IS_NO_ADV_OUT; - } -} - - -/* Read a list of gateways from /etc/gateways and add them to our tables. - * - * This file contains a list of "remote" gateways. That is usually - * a gateway which we cannot immediately determine if it is present or - * not as we can do for those provided by directly connected hardware. - * - * If a gateway is marked "passive" in the file, then we assume it - * does not understand RIP and assume it is always present. Those - * not marked passive are treated as if they were directly connected - * and assumed to be broken if they do not send us advertisements. - * All remote interfaces are added to our list, and those not marked - * passive are sent routing updates. - * - * A passive interface can also be local, hardware interface exempt - * from RIP. - */ -void -gwkludge(void) -{ - FILE *fp; - char *p, *lptr; - char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9]; - struct interface *ifp; - naddr dst, netmask, gate; - int metric, n; - u_int state; - char *type; - struct parm *parmp; - - - fp = fopen(_PATH_GATEWAYS, "r"); - if (fp == 0) - return; - - for (;;) { - if (0 == fgets(lbuf, sizeof(lbuf)-1, fp)) - break; - lptr = lbuf; - while (*lptr == ' ') - lptr++; - if (*lptr == '\n' /* ignore null and comment lines */ - || *lptr == '#') - continue; - - /* notice parameter lines */ - if (strncasecmp("net", lptr, 3) - && strncasecmp("host", lptr, 4)) { - p = parse_parms(lptr); - if (p != 0) - msglog("bad \"%s\" in "_PATH_GATEWAYS - " entry %s", lptr, p); - continue; - } - -/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */ - n = sscanf(lptr, "%4s %129[^ ] gateway" - " %64[^ / ] metric %d %8s\n", - net_host, dname, gname, &metric, qual); - if (n != 5) { - msglog("bad "_PATH_GATEWAYS" entry %s", lptr); - continue; - } - if (metric < 0 || metric >= HOPCNT_INFINITY) { - msglog("bad metric in "_PATH_GATEWAYS" entry %s", - lptr); - continue; - } - if (!strcmp(net_host, "host")) { - if (!gethost(dname, &dst)) { - msglog("bad host %s in "_PATH_GATEWAYS - " entry %s", dname, lptr); - continue; - } - netmask = HOST_MASK; - } else if (!strcmp(net_host, "net")) { - if (!getnet(dname, &dst, &netmask)) { - msglog("bad net %s in "_PATH_GATEWAYS - " entry %s", dname, lptr); - continue; - } - HTONL(dst); - } else { - msglog("bad \"%s\" in "_PATH_GATEWAYS - " entry %s", lptr); - continue; - } - - if (!gethost(gname, &gate)) { - msglog("bad gateway %s in "_PATH_GATEWAYS - " entry %s", gname, lptr); - continue; - } - - if (strcmp(qual, type = "passive") == 0) { - /* Passive entries are not placed in our tables, - * only the kernel's, so we don't copy all of the - * external routing information within a net. - * Internal machines should use the default - * route to a suitable gateway (like us). - */ - state = IS_REMOTE | IS_PASSIVE; - if (metric == 0) - metric = 1; - - } else if (strcmp(qual, type = "external") == 0) { - /* External entries are handled by other means - * such as EGP, and are placed only in the daemon - * tables to prevent overriding them with something - * else. - */ - state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL; - if (metric == 0) - metric = 1; - - } else if (qual[0] == '\0') { - if (metric != 0) { - /* Entries that are neither "passive" nor - * "external" are "remote" and must behave - * like physical interfaces. If they are not - * heard from regularly, they are deleted. - */ - state = IS_REMOTE; - type = "remote"; - } else { - /* "remote" entries with a metric of 0 - * are aliases for our own interfaces - */ - state = IS_REMOTE | IS_PASSIVE; - type = "alias"; - } - - } else { - msglog("bad "_PATH_GATEWAYS" entry %s", lptr); - continue; - } - - if (!(state & IS_EXTERNAL)) { - /* If we are going to send packets to the gateway, - * it must be reachable using our physical interfaces - */ - if (!rtfind(gate)) { - msglog("unreachable gateway %s in " - _PATH_GATEWAYS" entry %s", - gname, lptr); - continue; - } - - /* Remember to advertise the corresponding logical - * network. - */ - if (netmask != std_mask(dst)) - state |= IS_SUBNET; - } - - parmp = (struct parm*)malloc(sizeof(*parmp)); - bzero(parmp, sizeof(*parmp)); - parmp->parm_next = parms; - parms = parmp; - parmp->parm_a_h = ntohl(dst); - parmp->parm_m = -1; - parmp->parm_d_metric = 0; - parmp->parm_int_state = state; - - /* See if this new interface duplicates an existing - * interface. - */ - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { - if (ifp->int_addr == dst - && ifp->int_mask == netmask) - break; - } - if (ifp != 0) { - /* Let one of our real interfaces be marked passive. - */ - if ((state & IS_PASSIVE) && !(state & IS_EXTERNAL)) { - ifp->int_state |= state; - } else { - msglog("%s is duplicated in "_PATH_GATEWAYS - " by %s", - ifp->int_name, lptr); - } - continue; - } - - tot_interfaces++; - - ifp = (struct interface *)malloc(sizeof(*ifp)); - bzero(ifp, sizeof(*ifp)); - if (ifnet != 0) { - ifp->int_next = ifnet; - ifnet->int_prev = ifp; - } - ifnet = ifp; - - ifp->int_state = state; - ifp->int_net = ntohl(dst) & netmask; - ifp->int_mask = netmask; - if (netmask == HOST_MASK) - ifp->int_if_flags |= IFF_POINTOPOINT; - ifp->int_dstaddr = dst; - ifp->int_addr = gate; - ifp->int_metric = metric; - (void)sprintf(ifp->int_name, "%s-%s", type, naddr_ntoa(dst)); - ifp->int_index = -1; - - get_parms(ifp); - - if (TRACEACTIONS) - trace_if("Add", ifp); - } -} - - -/* get a network number as a name or a number, with an optional "/xx" - * netmask. - */ -int /* 0=bad */ -getnet(char *name, - naddr *addr_hp, - naddr *maskp) -{ - int i; - struct netent *nentp; - naddr mask; - struct in_addr in; - char hname[MAXHOSTNAMELEN+1]; - char *mname, *p; - - - /* Detect and separate "1.2.3.4/24" - */ - if (0 != (mname = rindex(name,'/'))) { - i = (int)(mname - name); - if (i > sizeof(hname)-1) /* name too long */ - return 0; - bcopy(name, hname, i); - hname[i] = '\0'; - mname++; - name = hname; - } - - nentp = getnetbyname(name); - if (nentp != 0) { - in.s_addr = (naddr)nentp->n_net; - } else if (inet_aton(name, &in) == 1) { - NTOHL(in.s_addr); - } else { - return 0; - } - - if (mname == 0) { - mask = std_mask(in.s_addr); - } else { - mask = (naddr)strtoul(mname, &p, 0); - if (*p != '\0' || mask > 32) - return 0; - mask = HOST_MASK << (32-mask); - } - - *addr_hp = in.s_addr; - *maskp = mask; - return 1; -} - - -int /* 0=bad */ -gethost(char *name, - naddr *addrp) -{ - struct hostent *hp; - struct in_addr in; - - - /* Try for a number first, even in IRIX where gethostbyname() - * is smart. This avoids hitting the name server which - * might be sick because routing is. - */ - if (inet_aton(name, &in) == 1) { - *addrp = in.s_addr; - return 1; - } - - hp = gethostbyname(name); - if (hp) { - bcopy(hp->h_addr, addrp, sizeof(*addrp)); - return 1; - } - - return 0; -} diff --git a/usr.sbin/routed/pathnames.h b/usr.sbin/routed/pathnames.h deleted file mode 100644 index e9e6c48c6392..000000000000 --- a/usr.sbin/routed/pathnames.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/5/93 - * - * $NetBSD$ - */ - -#include - -#define _PATH_GATEWAYS "/etc/gateways" - -/* All remotely requested trace files must either start with this prefix - * or be the same as the tracefile specified when the daemon was started. - * If this is a directory, routed will create log files in it. That - * might be a security problem. - */ -#define _PATH_TRACE "/tmp/routed.log" diff --git a/usr.sbin/routed/radix.c b/usr.sbin/routed/radix.c deleted file mode 100644 index 7552e0832a50..000000000000 --- a/usr.sbin/routed/radix.c +++ /dev/null @@ -1,894 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)radix.c 8.4 (Berkeley) 11/2/94 - */ - -/* - * Routines to build and maintain radix trees for routing lookups. - */ -#include -#include -#include -#include -#include -#include -#define min(a,b) (((a)<(b))?(a):(b)) -#define log(x, msg) syslog(x, msg) -#define panic(s) {log(LOG_ERR,s); exit(1);} - - -int max_keylen; -struct radix_mask *rn_mkfreelist; -struct radix_node_head *mask_rnhead; -static char *addmask_key; -static char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, -1}; -static char *rn_zeros, *rn_ones; - -#define rn_masktop (mask_rnhead->rnh_treetop) -#undef Bcmp -#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) - -static int rn_satsifies_leaf(char *, struct radix_node *, int); - -/* - * The data structure for the keys is a radix tree with one way - * branching removed. The index rn_b at an internal node n represents a bit - * position to be tested. The tree is arranged so that all descendants - * of a node n have keys whose bits all agree up to position rn_b - 1. - * (We say the index of n is rn_b.) - * - * There is at least one descendant which has a one bit at position rn_b, - * and at least one with a zero there. - * - * A route is determined by a pair of key and mask. We require that the - * bit-wise logical and of the key and mask to be the key. - * We define the index of a route to associated with the mask to be - * the first bit number in the mask where 0 occurs (with bit number 0 - * representing the highest order bit). - * - * We say a mask is normal if every bit is 0, past the index of the mask. - * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b, - * and m is a normal mask, then the route applies to every descendant of n. - * If the index(m) < rn_b, this implies the trailing last few bits of k - * before bit b are all 0, (and hence consequently true of every descendant - * of n), so the route applies to all descendants of the node as well. - * - * Similar logic shows that a non-normal mask m such that - * index(m) <= index(n) could potentially apply to many children of n. - * Thus, for each non-host route, we attach its mask to a list at an internal - * node as high in the tree as we can go. - * - * The present version of the code makes use of normal routes in short- - * circuiting an explict mask and compare operation when testing whether - * a key satisfies a normal route, and also in remembering the unique leaf - * that governs a subtree. - */ - -struct radix_node * -rn_search(v_arg, head) - void *v_arg; - struct radix_node *head; -{ - register struct radix_node *x; - register caddr_t v; - - for (x = head, v = v_arg; x->rn_b >= 0;) { - if (x->rn_bmask & v[x->rn_off]) - x = x->rn_r; - else - x = x->rn_l; - } - return (x); -} - -struct radix_node * -rn_search_m(v_arg, head, m_arg) - struct radix_node *head; - void *v_arg, *m_arg; -{ - register struct radix_node *x; - register caddr_t v = v_arg, m = m_arg; - - for (x = head; x->rn_b >= 0;) { - if ((x->rn_bmask & m[x->rn_off]) && - (x->rn_bmask & v[x->rn_off])) - x = x->rn_r; - else - x = x->rn_l; - } - return x; -} - -int -rn_refines(m_arg, n_arg) - void *m_arg, *n_arg; -{ - register caddr_t m = m_arg, n = n_arg; - register caddr_t lim, lim2 = lim = n + *(u_char *)n; - int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); - int masks_are_equal = 1; - - if (longer > 0) - lim -= longer; - while (n < lim) { - if (*n & ~(*m)) - return 0; - if (*n++ != *m++) - masks_are_equal = 0; - } - while (n < lim2) - if (*n++) - return 0; - if (masks_are_equal && (longer < 0)) - for (lim2 = m - longer; m < lim2; ) - if (*m++) - return 1; - return (!masks_are_equal); -} - -struct radix_node * -rn_lookup(v_arg, m_arg, head) - void *v_arg, *m_arg; - struct radix_node_head *head; -{ - register struct radix_node *x; - caddr_t netmask = 0; - - if (m_arg) { - if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) - return (0); - netmask = x->rn_key; - } - x = rn_match(v_arg, head); - if (x && netmask) { - while (x && x->rn_mask != netmask) - x = x->rn_dupedkey; - } - return x; -} - -static int -rn_satsifies_leaf(char *trial, - register struct radix_node *leaf, - int skip) -{ - register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; - char *cplim; - int length = min(*(u_char *)cp, *(u_char *)cp2); - - if (cp3 == 0) - cp3 = rn_ones; - else - length = min(length, *(u_char *)cp3); - cplim = cp + length; cp3 += skip; cp2 += skip; - for (cp += skip; cp < cplim; cp++, cp2++, cp3++) - if ((*cp ^ *cp2) & *cp3) - return 0; - return 1; -} - -struct radix_node * -rn_match(v_arg, head) - void *v_arg; - struct radix_node_head *head; -{ - caddr_t v = v_arg; - register struct radix_node *t = head->rnh_treetop, *x; - register caddr_t cp = v, cp2; - caddr_t cplim; - struct radix_node *saved_t, *top = t; - int off = t->rn_off, vlen = *(u_char *)cp, matched_off; - register int test, b, rn_b; - - /* - * Open code rn_search(v, top) to avoid overhead of extra - * subroutine call. - */ - for (; t->rn_b >= 0; ) { - if (t->rn_bmask & cp[t->rn_off]) - t = t->rn_r; - else - t = t->rn_l; - } - /* - * See if we match exactly as a host destination - * or at least learn how many bits match, for normal mask finesse. - * - * It doesn't hurt us to limit how many bytes to check - * to the length of the mask, since if it matches we had a genuine - * match and the leaf we have is the most specific one anyway; - * if it didn't match with a shorter length it would fail - * with a long one. This wins big for class B&C netmasks which - * are probably the most common case... - */ - if (t->rn_mask) - vlen = *(u_char *)t->rn_mask; - cp += off; cp2 = t->rn_key + off; cplim = v + vlen; - for (; cp < cplim; cp++, cp2++) - if (*cp != *cp2) - goto on1; - /* - * This extra grot is in case we are explicitly asked - * to look up the default. Ugh! - */ - if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey) - t = t->rn_dupedkey; - return t; -on1: - test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */ - for (b = 7; (test >>= 1) > 0;) - b--; - matched_off = cp - v; - b += matched_off << 3; - rn_b = -1 - b; - /* - * If there is a host route in a duped-key chain, it will be first. - */ - if ((saved_t = t)->rn_mask == 0) - t = t->rn_dupedkey; - for (; t; t = t->rn_dupedkey) - /* - * Even if we don't match exactly as a host, - * we may match if the leaf we wound up at is - * a route to a net. - */ - if (t->rn_flags & RNF_NORMAL) { - if (rn_b <= t->rn_b) - return t; - } else if (rn_satsifies_leaf(v, t, matched_off)) - return t; - t = saved_t; - /* start searching up the tree */ - do { - register struct radix_mask *m; - t = t->rn_p; - if (m = t->rn_mklist) { - /* - * If non-contiguous masks ever become important - * we can restore the masking and open coding of - * the search and satisfaction test and put the - * calculation of "off" back before the "do". - */ - do { - if (m->rm_flags & RNF_NORMAL) { - if (rn_b <= m->rm_b) - return (m->rm_leaf); - } else { - off = min(t->rn_off, matched_off); - x = rn_search_m(v, t, m->rm_mask); - while (x && x->rn_mask != m->rm_mask) - x = x->rn_dupedkey; - if (x && rn_satsifies_leaf(v, x, off)) - return x; - } - } while (m = m->rm_mklist); - } - } while (t != top); - return 0; -} - -#ifdef RN_DEBUG -int rn_nodenum; -struct radix_node *rn_clist; -int rn_saveinfo; -int rn_debug = 1; -#endif - -struct radix_node * -rn_newpair(v, b, nodes) - void *v; - int b; - struct radix_node nodes[2]; -{ - register struct radix_node *tt = nodes, *t = tt + 1; - t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7); - t->rn_l = tt; t->rn_off = b >> 3; - tt->rn_b = -1; tt->rn_key = (caddr_t)v; tt->rn_p = t; - tt->rn_flags = t->rn_flags = RNF_ACTIVE; -#ifdef RN_DEBUG - tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; - tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt; -#endif - return t; -} - -struct radix_node * -rn_insert(v_arg, head, dupentry, nodes) - void *v_arg; - struct radix_node_head *head; - int *dupentry; - struct radix_node nodes[2]; -{ - caddr_t v = v_arg; - struct radix_node *top = head->rnh_treetop; - int head_off = top->rn_off, vlen = (int)*((u_char *)v); - register struct radix_node *t = rn_search(v_arg, top); - register caddr_t cp = v + head_off; - register int b; - struct radix_node *tt; - /* - * Find first bit at which v and t->rn_key differ - */ - { - register caddr_t cp2 = t->rn_key + head_off; - register int cmp_res; - caddr_t cplim = v + vlen; - - while (cp < cplim) - if (*cp2++ != *cp++) - goto on1; - *dupentry = 1; - return t; -on1: - *dupentry = 0; - cmp_res = (cp[-1] ^ cp2[-1]) & 0xff; - for (b = (cp - v) << 3; cmp_res; b--) - cmp_res >>= 1; - } - { - register struct radix_node *p, *x = top; - cp = v; - do { - p = x; - if (cp[x->rn_off] & x->rn_bmask) - x = x->rn_r; - else x = x->rn_l; - } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */ -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p); -#endif - t = rn_newpair(v_arg, b, nodes); tt = t->rn_l; - if ((cp[p->rn_off] & p->rn_bmask) == 0) - p->rn_l = t; - else - p->rn_r = t; - x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */ - if ((cp[t->rn_off] & t->rn_bmask) == 0) { - t->rn_r = x; - } else { - t->rn_r = tt; t->rn_l = x; - } -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p); -#endif - } - return (tt); -} - -struct radix_node * -rn_addmask(n_arg, search, skip) - int search, skip; - void *n_arg; -{ - caddr_t netmask = (caddr_t)n_arg; - register struct radix_node *x; - register caddr_t cp, cplim; - register int b = 0, mlen, j; - int maskduplicated, m0, isnormal; - struct radix_node *saved_x; - static int last_zeroed = 0; - - if ((mlen = *(u_char *)netmask) > max_keylen) - mlen = max_keylen; - if (skip == 0) - skip = 1; - if (mlen <= skip) - return (mask_rnhead->rnh_nodes); - if (skip > 1) - Bcopy(rn_ones + 1, addmask_key + 1, skip - 1); - if ((m0 = mlen) > skip) - Bcopy(netmask + skip, addmask_key + skip, mlen - skip); - /* - * Trim trailing zeroes. - */ - for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;) - cp--; - mlen = cp - addmask_key; - if (mlen <= skip) { - if (m0 >= last_zeroed) - last_zeroed = mlen; - return (mask_rnhead->rnh_nodes); - } - if (m0 < last_zeroed) - Bzero(addmask_key + m0, last_zeroed - m0); - *addmask_key = last_zeroed = mlen; - x = rn_search(addmask_key, rn_masktop); - if (Bcmp(addmask_key, x->rn_key, mlen) != 0) - x = 0; - if (x || search) - return (x); - R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x)); - if ((saved_x = x) == 0) - return (0); - Bzero(x, max_keylen + 2 * sizeof (*x)); - netmask = cp = (caddr_t)(x + 2); - Bcopy(addmask_key, cp, mlen); - x = rn_insert(cp, mask_rnhead, &maskduplicated, x); - if (maskduplicated) { - log(LOG_ERR, "rn_addmask: mask impossibly already in tree"); - Free(saved_x); - return (x); - } - /* - * Calculate index of mask, and check for normalcy. - */ - cplim = netmask + mlen; isnormal = 1; - for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;) - cp++; - if (cp != cplim) { - for (j = 0x80; (j & *cp) != 0; j >>= 1) - b++; - if (*cp != normal_chars[b] || cp != (cplim - 1)) - isnormal = 0; - } - b += (cp - netmask) << 3; - x->rn_b = -1 - b; - if (isnormal) - x->rn_flags |= RNF_NORMAL; - return (x); -} - -static int /* XXX: arbitrary ordering for non-contiguous masks */ -rn_lexobetter(void *m_arg, void *n_arg) -{ - register u_char *mp = m_arg, *np = n_arg, *lim; - - if (*mp > *np) - return 1; /* not really, but need to check longer one first */ - if (*mp == *np) - for (lim = mp + *mp; mp < lim;) - if (*mp++ > *np++) - return 1; - return 0; -} - -static struct radix_mask * -rn_new_radix_mask(register struct radix_node *tt, - register struct radix_mask *next) -{ - register struct radix_mask *m; - - MKGet(m); - if (m == 0) { - log(LOG_ERR, "Mask for route not entered\n"); - return (0); - } - Bzero(m, sizeof *m); - m->rm_b = tt->rn_b; - m->rm_flags = tt->rn_flags; - if (tt->rn_flags & RNF_NORMAL) - m->rm_leaf = tt; - else - m->rm_mask = tt->rn_mask; - m->rm_mklist = next; - tt->rn_mklist = m; - return m; -} - -struct radix_node * -rn_addroute(v_arg, n_arg, head, treenodes) - void *v_arg, *n_arg; - struct radix_node_head *head; - struct radix_node treenodes[2]; -{ - caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; - register struct radix_node *t, *x, *tt; - struct radix_node *saved_tt, *top = head->rnh_treetop; - short b = 0, b_leaf; - int keyduplicated; - caddr_t mmask; - struct radix_mask *m, **mp; - - /* - * In dealing with non-contiguous masks, there may be - * many different routes which have the same mask. - * We will find it useful to have a unique pointer to - * the mask to speed avoiding duplicate references at - * nodes and possibly save time in calculating indices. - */ - if (netmask) { - if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0) - return (0); - b_leaf = x->rn_b; - b = -1 - x->rn_b; - netmask = x->rn_key; - } - /* - * Deal with duplicated keys: attach node to previous instance - */ - saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes); - if (keyduplicated) { - for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) { - if (tt->rn_mask == netmask) - return (0); - if (netmask == 0 || - (tt->rn_mask && - ((b_leaf < tt->rn_b) || /* index(netmask) > node */ - rn_refines(netmask, tt->rn_mask) || - rn_lexobetter(netmask, tt->rn_mask)))) - break; - } - /* - * If the mask is not duplicated, we wouldn't - * find it among possible duplicate key entries - * anyway, so the above test doesn't hurt. - * - * We sort the masks for a duplicated key the same way as - * in a masklist -- most specific to least specific. - * This may require the unfortunate nuisance of relocating - * the head of the list. - */ - if (tt == saved_tt) { - struct radix_node *xx = x; - /* link in at head of list */ - (tt = treenodes)->rn_dupedkey = t; - tt->rn_flags = t->rn_flags; - tt->rn_p = x = t->rn_p; - if (x->rn_l == t) x->rn_l = tt; else x->rn_r = tt; - saved_tt = tt; x = xx; - } else { - (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; - t->rn_dupedkey = tt; - } -#ifdef RN_DEBUG - t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; - tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt; -#endif - tt->rn_key = (caddr_t) v; - tt->rn_b = -1; - tt->rn_flags = RNF_ACTIVE; - } - /* - * Put mask in tree. - */ - if (netmask) { - tt->rn_mask = netmask; - tt->rn_b = x->rn_b; - tt->rn_flags |= x->rn_flags & RNF_NORMAL; - } - t = saved_tt->rn_p; - if (keyduplicated) - goto on2; - b_leaf = -1 - t->rn_b; - if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r; - /* Promote general routes from below */ - if (x->rn_b < 0) { - for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) - if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) { - if (*mp = m = rn_new_radix_mask(x, 0)) - mp = &m->rm_mklist; - } - } else if (x->rn_mklist) { - /* - * Skip over masks whose index is > that of new node - */ - for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist) - if (m->rm_b >= b_leaf) - break; - t->rn_mklist = m; *mp = 0; - } -on2: - /* Add new route to highest possible ancestor's list */ - if ((netmask == 0) || (b > t->rn_b )) - return tt; /* can't lift at all */ - b_leaf = tt->rn_b; - do { - x = t; - t = t->rn_p; - } while (b <= t->rn_b && x != top); - /* - * Search through routes associated with node to - * insert new route according to index. - * Need same criteria as when sorting dupedkeys to avoid - * double loop on deletion. - */ - for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist) { - if (m->rm_b < b_leaf) - continue; - if (m->rm_b > b_leaf) - break; - if (m->rm_flags & RNF_NORMAL) { - mmask = m->rm_leaf->rn_mask; - if (tt->rn_flags & RNF_NORMAL) { - log(LOG_ERR, - "Non-unique normal route, mask not entered"); - return tt; - } - } else - mmask = m->rm_mask; - if (mmask == netmask) { - m->rm_refs++; - tt->rn_mklist = m; - return tt; - } - if (rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask)) - break; - } - *mp = rn_new_radix_mask(tt, *mp); - return tt; -} - -struct radix_node * -rn_delete(v_arg, netmask_arg, head) - void *v_arg, *netmask_arg; - struct radix_node_head *head; -{ - register struct radix_node *t, *p, *x, *tt; - struct radix_mask *m, *saved_m, **mp; - struct radix_node *dupedkey, *saved_tt, *top; - caddr_t v, netmask; - int b, head_off, vlen; - - v = v_arg; - netmask = netmask_arg; - x = head->rnh_treetop; - tt = rn_search(v, x); - head_off = x->rn_off; - vlen = *(u_char *)v; - saved_tt = tt; - top = x; - if (tt == 0 || - Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off)) - return (0); - /* - * Delete our route from mask lists. - */ - if (netmask) { - if ((x = rn_addmask(netmask, 1, head_off)) == 0) - return (0); - netmask = x->rn_key; - while (tt->rn_mask != netmask) - if ((tt = tt->rn_dupedkey) == 0) - return (0); - } - if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0) - goto on1; - if (tt->rn_flags & RNF_NORMAL) { - if (m->rm_leaf != tt || m->rm_refs > 0) { - log(LOG_ERR, "rn_delete: inconsistent annotation\n"); - return 0; /* dangling ref could cause disaster */ - } - } else { - if (m->rm_mask != tt->rn_mask) { - log(LOG_ERR, "rn_delete: inconsistent annotation\n"); - goto on1; - } - if (--m->rm_refs >= 0) - goto on1; - } - b = -1 - tt->rn_b; - t = saved_tt->rn_p; - if (b > t->rn_b) - goto on1; /* Wasn't lifted at all */ - do { - x = t; - t = t->rn_p; - } while (b <= t->rn_b && x != top); - for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist) - if (m == saved_m) { - *mp = m->rm_mklist; - MKFree(m); - break; - } - if (m == 0) { - log(LOG_ERR, "rn_delete: couldn't find our annotation\n"); - if (tt->rn_flags & RNF_NORMAL) - return (0); /* Dangling ref to us */ - } -on1: - /* - * Eliminate us from tree - */ - if (tt->rn_flags & RNF_ROOT) - return (0); -#ifdef RN_DEBUG - /* Get us out of the creation list */ - for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {} - if (t) t->rn_ybro = tt->rn_ybro; -#endif - t = tt->rn_p; - if (dupedkey = saved_tt->rn_dupedkey) { - if (tt == saved_tt) { - x = dupedkey; x->rn_p = t; - if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x; - } else { - for (x = p = saved_tt; p && p->rn_dupedkey != tt;) - p = p->rn_dupedkey; - if (p) p->rn_dupedkey = tt->rn_dupedkey; - else log(LOG_ERR, "rn_delete: couldn't find us\n"); - } - t = tt + 1; - if (t->rn_flags & RNF_ACTIVE) { -#ifndef RN_DEBUG - *++x = *t; p = t->rn_p; -#else - b = t->rn_info; *++x = *t; t->rn_info = b; p = t->rn_p; -#endif - if (p->rn_l == t) p->rn_l = x; else p->rn_r = x; - x->rn_l->rn_p = x; x->rn_r->rn_p = x; - } - goto out; - } - if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l; - p = t->rn_p; - if (p->rn_r == t) p->rn_r = x; else p->rn_l = x; - x->rn_p = p; - /* - * Demote routes attached to us. - */ - if (t->rn_mklist) { - if (x->rn_b >= 0) { - for (mp = &x->rn_mklist; m = *mp;) - mp = &m->rm_mklist; - *mp = t->rn_mklist; - } else { - /* If there are any key,mask pairs in a sibling - duped-key chain, some subset will appear sorted - in the same order attached to our mklist */ - for (m = t->rn_mklist; m && x; x = x->rn_dupedkey) - if (m == x->rn_mklist) { - struct radix_mask *mm = m->rm_mklist; - x->rn_mklist = 0; - if (--(m->rm_refs) < 0) - MKFree(m); - m = mm; - } - if (m) -#ifdef _KERNEL - printf("%s %x at %x\n", - "rn_delete: Orphaned Mask", m, x); -#else - syslog(LOG_ERR, "%s %x at %x\n", - "rn_delete: Orphaned Mask", m, x); -#endif - } - } - /* - * We may be holding an active internal node in the tree. - */ - x = tt + 1; - if (t != x) { -#ifndef RN_DEBUG - *t = *x; -#else - b = t->rn_info; *t = *x; t->rn_info = b; -#endif - t->rn_l->rn_p = t; t->rn_r->rn_p = t; - p = x->rn_p; - if (p->rn_l == x) p->rn_l = t; else p->rn_r = t; - } -out: - tt->rn_flags &= ~RNF_ACTIVE; - tt[1].rn_flags &= ~RNF_ACTIVE; - return (tt); -} - -int -rn_walktree(h, f, w) - struct radix_node_head *h; - register int (*f)(); - void *w; -{ - int error; - struct radix_node *base, *next; - register struct radix_node *rn = h->rnh_treetop; - /* - * This gets complicated because we may delete the node - * while applying the function f to it, so we need to calculate - * the successor node in advance. - */ - /* First time through node, go left */ - while (rn->rn_b >= 0) - rn = rn->rn_l; - for (;;) { - base = rn; - /* If at right child go back up, otherwise, go right */ - while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0) - rn = rn->rn_p; - /* Find the next *leaf* since next node might vanish, too */ - for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) - rn = rn->rn_l; - next = rn; - /* Process leaves */ - while (rn = base) { - base = rn->rn_dupedkey; - if (!(rn->rn_flags & RNF_ROOT) && (error = (*f)(rn, w))) - return (error); - } - rn = next; - if (rn->rn_flags & RNF_ROOT) - return (0); - } - /* NOTREACHED */ -} - -int -rn_inithead(head, off) - void **head; - int off; -{ - register struct radix_node_head *rnh; - register struct radix_node *t, *tt, *ttt; - if (*head) - return (1); - R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh)); - if (rnh == 0) - return (0); - Bzero(rnh, sizeof (*rnh)); - *head = rnh; - t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); - ttt = rnh->rnh_nodes + 2; - t->rn_r = ttt; - t->rn_p = t; - tt = t->rn_l; - tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; - tt->rn_b = -1 - off; - *ttt = *tt; - ttt->rn_key = rn_ones; - rnh->rnh_addaddr = rn_addroute; - rnh->rnh_deladdr = rn_delete; - rnh->rnh_matchaddr = rn_match; - rnh->rnh_lookup = rn_lookup; - rnh->rnh_walktree = rn_walktree; - rnh->rnh_treetop = t; - return (1); -} - -void -rn_init() -{ - char *cp, *cplim; -#ifdef KERNEL - struct domain *dom; - - for (dom = domains; dom; dom = dom->dom_next) - if (dom->dom_maxrtkey > max_keylen) - max_keylen = dom->dom_maxrtkey; -#endif - if (max_keylen == 0) { - printf("rn_init: radix functions require max_keylen be set\n"); - return; - } - R_Malloc(rn_zeros, char *, 3 * max_keylen); - if (rn_zeros == NULL) - panic("rn_init"); - Bzero(rn_zeros, 3 * max_keylen); - rn_ones = cp = rn_zeros + max_keylen; - addmask_key = cplim = rn_ones + max_keylen; - while (cp < cplim) - *cp++ = -1; - if (rn_inithead((void **)&mask_rnhead, 0) == 0) - panic("rn_init 2"); -} diff --git a/usr.sbin/routed/radix.h b/usr.sbin/routed/radix.h deleted file mode 100644 index fddf02ead7a6..000000000000 --- a/usr.sbin/routed/radix.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)radix.h 8.2 (Berkeley) 10/31/94 - */ - -#ifndef __RADIX_H_ -#define __RADIX_H_ - -#include -struct walkarg; - -/* - * Radix search tree node layout. - */ - -struct radix_node { - struct radix_mask *rn_mklist; /* list of masks contained in subtree */ - struct radix_node *rn_p; /* parent */ - short rn_b; /* bit offset; -1-index(netmask) */ - char rn_bmask; /* node: mask for bit test*/ - u_char rn_flags; /* enumerated next */ -#define RNF_NORMAL 1 /* leaf contains normal route */ -#define RNF_ROOT 2 /* leaf is root leaf for tree */ -#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */ - union { - struct { /* leaf only data: */ - caddr_t rn_Key; /* object of search */ - caddr_t rn_Mask; /* netmask, if present */ - struct radix_node *rn_Dupedkey; - } rn_leaf; - struct { /* node only data: */ - int rn_Off; /* where to start compare */ - struct radix_node *rn_L;/* progeny */ - struct radix_node *rn_R;/* progeny */ - }rn_node; - } rn_u; -#ifdef RN_DEBUG - int rn_info; - struct radix_node *rn_twin; - struct radix_node *rn_ybro; -#endif -}; - -#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey -#define rn_key rn_u.rn_leaf.rn_Key -#define rn_mask rn_u.rn_leaf.rn_Mask -#define rn_off rn_u.rn_node.rn_Off -#define rn_l rn_u.rn_node.rn_L -#define rn_r rn_u.rn_node.rn_R - -/* - * Annotations to tree concerning potential routes applying to subtrees. - */ - -extern struct radix_mask { - short rm_b; /* bit offset; -1-index(netmask) */ - char rm_unused; /* cf. rn_bmask */ - u_char rm_flags; /* cf. rn_flags */ - struct radix_mask *rm_mklist; /* more masks to try */ - union { - caddr_t rmu_mask; /* the mask */ - struct radix_node *rmu_leaf; /* for normal routes */ - } rm_rmu; - int rm_refs; /* # of references to this struct */ -} *rn_mkfreelist; - -#define rm_mask rm_rmu.rmu_mask -#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ - -#define MKGet(m) {\ - if (rn_mkfreelist) {\ - m = rn_mkfreelist; \ - rn_mkfreelist = (m)->rm_mklist; \ - } else \ - R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\ - -#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);} - -struct radix_node_head { - struct radix_node *rnh_treetop; - int rnh_addrsize; /* permit, but not require fixed keys */ - int rnh_pktsize; /* permit, but not require fixed keys */ - struct radix_node *(*rnh_addaddr) /* add based on sockaddr */ - __P((void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[])); - struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ - __P((void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[])); - struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ - __P((void *v, void *mask, struct radix_node_head *head)); - struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ - __P((void *v, void *mask, struct radix_node_head *head)); - struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ - __P((void *v, struct radix_node_head *head)); - struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ - __P((void *v, void *mask, struct radix_node_head *head)); - struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ - __P((void *v, struct radix_node_head *head)); - int (*rnh_walktree) /* traverse tree */ - (struct radix_node_head *head, - int (*f)(struct radix_node *, struct walkarg *), - struct walkarg *w); - struct radix_node rnh_nodes[3]; /* empty tree for common case */ -}; - - -#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n)) -#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n)) -#define Bzero(p, n) bzero((char *)(p), (int)(n)); -#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n))) -#define Free(p) free((char *)p); - -void rn_init __P((void)); -int rn_inithead __P((void **, int)); -int rn_refines __P((void *, void *)); -int rn_walktree __P((struct radix_node_head *, - int (*)__P((struct radix_node *, struct walkarg*)), - struct walkarg*)); -struct radix_node - *rn_addmask __P((void *, int, int)), - *rn_addroute __P((void *, void *, struct radix_node_head *, - struct radix_node [2])), - *rn_delete __P((void *, void *, struct radix_node_head *)), - *rn_insert __P((void *, struct radix_node_head *, int *, - struct radix_node [2])), - *rn_match __P((void *, struct radix_node_head *)), - *rn_newpair __P((void *, int, struct radix_node[2])), - *rn_search __P((void *, struct radix_node *)), - *rn_search_m __P((void *, struct radix_node *, void *)); - -#endif /* __RADIX_H_ */ diff --git a/usr.sbin/routed/rdisc.c b/usr.sbin/routed/rdisc.c deleted file mode 100644 index 489da110615b..000000000000 --- a/usr.sbin/routed/rdisc.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * Copyright (c) 1995 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#include "defs.h" -#include -#include -#include - -/* router advertisement ICMP packet */ -struct icmp_ad { - u_int8_t icmp_type; /* type of message */ - u_int8_t icmp_code; /* type sub code */ - u_int16_t icmp_cksum; /* ones complement cksum of struct */ - u_int8_t icmp_ad_num; /* # of following router addresses */ - u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ - u_int16_t icmp_ad_life; /* seconds of validity */ - struct icmp_ad_info { - n_long icmp_ad_addr; - n_long icmp_ad_pref; - } icmp_ad_info[1]; -}; - -/* router solicitation ICMP packet */ -struct icmp_so { - u_int8_t icmp_type; /* type of message */ - u_int8_t icmp_code; /* type sub code */ - u_int16_t icmp_cksum; /* ones complement cksum of struct */ - n_long icmp_so_rsvd; -}; - -union ad_u { - struct icmp icmp; - struct icmp_ad ad; - struct icmp_so so; -}; - - -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 */ - - -#define MAX_ADS 5 -struct dr { /* accumulated advertisements */ - struct interface *dr_ifp; - naddr dr_gate; /* gateway */ - time_t dr_ts; /* when received */ - time_t dr_life; /* lifetime */ - n_long dr_recv_pref; /* received but biased preference */ - n_long dr_pref; /* preference adjusted by metric */ -} *cur_drp, drs[MAX_ADS]; - -/* adjust 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)) - -static void rdisc_sort(void); - - -/* dump an ICMP Router Discovery Advertisement Message - */ -static void -trace_rdisc(char *act, - naddr from, - naddr to, - struct interface *ifp, - union ad_u *p, - u_int len) -{ - int i; - n_long *wp, *lim; - - - if (!TRACEPACKETS || ftrace == 0) - return; - - lastlog(); - - if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { - (void)fprintf(ftrace, "%s Router Ad" - " from %s to %s via %s life=%d\n", - act, naddr_ntoa(from), naddr_ntoa(to), - ifp ? ifp->int_name : "?", - ntohs(p->ad.icmp_ad_life)); - if (!TRACECONTENTS) - return; - - wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; - lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; - for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { - (void)fprintf(ftrace, "\t%s preference=%#x", - naddr_ntoa(wp[0]), (int)ntohl(wp[1])); - wp += p->ad.icmp_ad_asize; - } - (void)fputc('\n',ftrace); - - } else { - trace_act("%s Router Solic. from %s to %s via %s" - " value=%#x\n", - act, naddr_ntoa(from), naddr_ntoa(to), - ifp ? ifp->int_name : "?", - ntohl(p->so.icmp_so_rsvd)); - } -} - -/* prepare Router Discovery socket. - */ -static void -get_rdisc_sock(void) -{ - if (rdisc_sock < 0) { - rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (rdisc_sock < 0) - BADERR(1,"rdisc_sock = socket()"); - fix_sock(rdisc_sock,"rdisc_sock"); - fix_select(); - } -} - - -/* Pick multicast group for router-discovery socket - */ -void -set_rdisc_mg(struct interface *ifp, - int on) { /* 0=turn it off */ - struct ip_mreq m; - - if (rdisc_sock < 0) { - /* Create the raw socket so that we can hear at least - * broadcast router discovery packets. - */ - if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC - || !on) - return; - get_rdisc_sock(); - } - - if (!(ifp->int_if_flags & IFF_MULTICAST) - || (ifp->int_state & IS_ALIAS)) { - ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); - return; - } - -#ifdef MCAST_PPP_BUG - if (ifp->int_if_flags & IFF_POINTOPOINT) - return; -#endif - bzero(&m, sizeof(m)); - m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); - if (supplier - || (ifp->int_state & IS_NO_ADV_IN) - || !on) { - /* stop listening to advertisements - */ - if (ifp->int_state & IS_ALL_HOSTS) { - m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, - IP_DROP_MEMBERSHIP, - &m, sizeof(m)) < 0) - LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); - ifp->int_state &= ~IS_ALL_HOSTS; - } - - } else if (!(ifp->int_state & IS_ALL_HOSTS)) { - /* start listening to advertisements - */ - m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &m, sizeof(m)) < 0) { - LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); - } else { - ifp->int_state |= IS_ALL_HOSTS; - } - } - - if (!supplier - || (ifp->int_state & IS_NO_ADV_OUT) - || !on) { - /* stop listening to solicitations - */ - if (ifp->int_state & IS_ALL_ROUTERS) { - m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, - IP_DROP_MEMBERSHIP, - &m, sizeof(m)) < 0) - LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); - ifp->int_state &= ~IS_ALL_ROUTERS; - } - - } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { - /* start hearing solicitations - */ - m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &m, sizeof(m)) < 0) { - LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); - } else { - ifp->int_state |= IS_ALL_ROUTERS; - } - } -} - - -/* start supplying routes - */ -void -set_supplier(void) -{ - struct interface *ifp; - struct dr *drp; - - if (supplier_set) - return; - - trace_act("start suppying routes\n"); - - /* Forget discovered routes. - */ - for (drp = drs; drp < &drs[MAX_ADS]; drp++) { - drp->dr_recv_pref = 0; - drp->dr_life = 0; - } - rdisc_age(0); - - supplier_set = 1; - supplier = 1; - - /* Do not start advertising until we have heard some RIP routes */ - LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); - - /* Switch router discovery multicast groups from soliciting - * to advertising. - */ - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - if (ifp->int_state & IS_BROKE) - continue; - ifp->int_rdisc_cnt = 0; - ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; - ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; - set_rdisc_mg(ifp, 1); - } - - /* get rid of any redirects */ - del_redirects(0,0); -} - - -/* age discovered routes and find the best one - */ -void -rdisc_age(naddr bad_gate) -{ - time_t sec; - struct dr *drp; - - - /* If only adverising, then do only that. */ - if (supplier) { - /* if switching from client to server, get rid of old - * default routes. - */ - if (cur_drp != 0) - rdisc_sort(); - rdisc_adv(); - return; - } - - /* If we are being told about a bad router, - * then age the discovered default route, and if there is - * no alternative, solicite a replacement. - */ - if (bad_gate != 0) { - /* Look for the bad discovered default route. - * Age it and note its interface. - */ - for (drp = drs; drp < &drs[MAX_ADS]; drp++) { - if (drp->dr_ts == 0) - continue; - - /* When we find the bad router, then age the route - * to at most SUPPLY_INTERVAL. - * This is contrary to RFC 1256, but defends against - * black holes. - */ - if (drp->dr_gate == bad_gate) { - sec = (now.tv_sec - drp->dr_life - + SUPPLY_INTERVAL); - if (drp->dr_ts > sec) { - trace_act("age 0.0.0.0 --> %s" - " via %s\n", - naddr_ntoa(drp->dr_gate), - drp->dr_ifp->int_name); - drp->dr_ts = sec; - } - break; - } - } - } - - /* 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(); -} - - -/* Zap all routes discovered via an interface that has gone bad - * This should only be called when !(ifp->int_state & IS_ALIAS) - */ -void -if_bad_rdisc(struct interface *ifp) -{ - struct dr *drp; - - for (drp = drs; drp < &drs[MAX_ADS]; drp++) { - if (drp->dr_ifp != ifp) - continue; - drp->dr_recv_pref = 0; - drp->dr_life = 0; - } - - rdisc_sort(); -} - - -/* mark an interface ok for router discovering. - */ -void -if_ok_rdisc(struct interface *ifp) -{ - set_rdisc_mg(ifp, 1); - - ifp->int_rdisc_cnt = 0; - ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier - ? MIN_WAITTIME - : MAX_SOLICITATION_DELAY); - if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) - rdisc_timer = ifp->int_rdisc_timer; -} - - -/* get rid of a dead discovered router - */ -static void -del_rdisc(struct dr *drp) -{ - struct interface *ifp; - int i; - - - del_redirects(drp->dr_gate, 0); - drp->dr_ts = 0; - drp->dr_life = 0; - - - /* Count the other discovered routes on the interface. - */ - i = 0; - ifp = drp->dr_ifp; - for (drp = drs; drp < &drs[MAX_ADS]; drp++) { - if (drp->dr_ts != 0 - && drp->dr_ifp == ifp) - i++; - } - - /* If that was the last good discovered router on the interface, - * 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\n", ifp->int_name); - ifp->int_rdisc_cnt = 0; - ifp->int_rdisc_timer.tv_sec = 0; - rdisc_sol(); - } -} - - -/* Find the best discovered route, - * and discard stale routers. - */ -static void -rdisc_sort(void) -{ - struct dr *drp, *new_drp; - struct rt_entry *rt; - struct interface *ifp; - u_int new_st; - n_long new_pref; - - - /* Find the best discovered route. - */ - new_drp = 0; - for (drp = drs; drp < &drs[MAX_ADS]; drp++) { - if (drp->dr_ts == 0) - continue; - ifp = drp->dr_ifp; - - /* Get rid of expired discovered routers. - */ - if (drp->dr_ts + drp->dr_life <= now.tv_sec) { - del_rdisc(drp); - continue; - } - - LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); - - /* Update preference with possibly changed interface - * metric. - */ - drp->dr_pref = PREF(drp->dr_recv_pref, ifp); - - /* Prefer the current route to prevent thrashing. - * Prefer shorter lifetimes to speed the detection of - * bad routers. - * Avoid sick interfaces. - */ - if (new_drp == 0 - || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) - && (new_pref < drp->dr_pref - || (new_pref == drp->dr_pref - && (drp == cur_drp - || (new_drp != cur_drp - && new_drp->dr_life > drp->dr_life))))) - || ((new_st & IS_SICK) - && !(drp->dr_ifp->int_state & IS_SICK))) { - new_drp = drp; - new_st = drp->dr_ifp->int_state; - new_pref = drp->dr_pref; - } - } - - /* switch to a better default route - */ - if (new_drp != cur_drp) { - rt = rtget(RIP_DEFAULT, 0); - - /* Stop using discovered routes if they are all bad - */ - if (new_drp == 0) { - trace_act("turn off Router Discovery client\n"); - rdisc_ok = 0; - - if (rt != 0 - && (rt->rt_state & RS_RDISC)) { - 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); - 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\n", - naddr_ntoa(new_drp->dr_gate), - new_drp->dr_ifp->int_name); - - rdisc_ok = 1; - - } else { - trace_act("switch Router Discovery from" - " %s via %s to %s via %s\n", - naddr_ntoa(cur_drp->dr_gate), - cur_drp->dr_ifp->int_name, - naddr_ntoa(new_drp->dr_gate), - new_drp->dr_ifp->int_name); - } - - 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); - } else { - rtadd(RIP_DEFAULT, 0, - new_drp->dr_gate, new_drp->dr_gate, - 0, 0, RS_RDISC, new_drp->dr_ifp); - } - - /* Now turn off RIP and delete RIP routes, - * which might otherwise include the default - * we just modified. - */ - rip_off(); - } - - cur_drp = new_drp; - } -} - - -/* handle a single address in an advertisement - */ -static void -parse_ad(naddr from, - naddr gate, - n_long pref, - u_short life, - struct interface *ifp) -{ - static naddr bad_gate; - struct dr *drp, *new_drp; - - - if (gate == RIP_DEFAULT - || !check_dst(gate)) { - if (bad_gate != from) { - msglog("router %s advertising bad gateway %s", - naddr_ntoa(from), - naddr_ntoa(gate)); - bad_gate = from; - } - return; - } - - /* ignore pointers to ourself and routes via unreachable networks - */ - if (ifwithaddr(gate, 1, 0) != 0) { - trace_pkt("\tdiscard Router Discovery Ad pointing at us\n"); - return; - } - if (!on_net(gate, ifp->int_net, ifp->int_mask)) { - trace_pkt("\tdiscard Router Discovery Ad" - " toward unreachable net\n"); - return; - } - - /* Convert preference to an unsigned value - * and later bias it by the metric of the interface. - */ - pref = ntohl(pref) ^ MIN_PreferenceLevel; - - if (pref == 0 || life == 0) { - pref = 0; - life = 0; - } - - for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) { - /* accept new info for a familiar entry - */ - if (drp->dr_gate == gate) { - new_drp = drp; - break; - } - - if (life == 0) - continue; /* do not worry about dead ads */ - - if (drp->dr_ts == 0) { - new_drp = drp; /* use unused entry */ - - } else if (new_drp == 0) { - /* look for an entry worse than the new one to - * reuse. - */ - if ((!(ifp->int_state & IS_SICK) - && (drp->dr_ifp->int_state & IS_SICK)) - || (pref > drp->dr_pref - && !((ifp->int_state ^ drp->dr_ifp->int_state) - & IS_SICK))) - new_drp = drp; - - } else if (new_drp->dr_ts != 0) { - /* look for the least valueable entry to reuse - */ - if ((!(new_drp->dr_ifp->int_state & IS_SICK) - && (drp->dr_ifp->int_state & IS_SICK)) - || (new_drp->dr_pref > drp->dr_pref - && !((new_drp->dr_ifp->int_state - ^ drp->dr_ifp->int_state) - & IS_SICK))) - new_drp = drp; - } - } - - /* forget it if all of the current entries are better */ - if (new_drp == 0) - return; - - new_drp->dr_ifp = ifp; - new_drp->dr_gate = gate; - new_drp->dr_ts = now.tv_sec; - new_drp->dr_life = ntohs(life); - new_drp->dr_recv_pref = pref; - /* bias functional preference by metric of the interface */ - new_drp->dr_pref = PREF(pref,ifp); - - /* after hearing a good advertisement, stop asking - */ - if (!(ifp->int_state & IS_SICK)) - ifp->int_rdisc_cnt = MAX_SOLICITATIONS; -} - - -/* Compute the IP checksum - * This assumes the packet is less than 32K long. - */ -static u_short -in_cksum(u_short *p, - u_int len) -{ - u_int sum = 0; - int nwords = len >> 1; - - while (nwords-- != 0) - sum += *p++; - - if (len & 1) - sum += *(u_char *)p; - - /* end-around-carry */ - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return (~sum); -} - - -/* Send a router discovery advertisement or solicitation ICMP packet. - */ -static void -send_rdisc(union ad_u *p, - int p_size, - struct interface *ifp, - naddr dst, /* 0 or unicast destination */ - int type) /* 0=unicast, 1=bcast, 2=mcast */ -{ - struct sockaddr_in sin; - int flags; - char *msg; - naddr tgt_mcast; - - - bzero(&sin, sizeof(sin)); - sin.sin_addr.s_addr = dst; - sin.sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - sin.sin_len = sizeof(sin); -#endif - flags = MSG_DONTROUTE; - - switch (type) { - case 0: /* unicast */ - msg = "Send"; - break; - - case 1: /* broadcast */ - if (ifp->int_if_flags & IFF_POINTOPOINT) { - msg = "Send pt-to-pt"; - sin.sin_addr.s_addr = ifp->int_dstaddr; - } else { - msg = "Send broadcast"; - sin.sin_addr.s_addr = ifp->int_brdaddr; - } - break; - - case 2: /* multicast */ - msg = "Send multicast"; - if (ifp->int_state & IS_DUP) { - trace_act("abort multicast output via %s" - " with duplicate address\n", - ifp->int_name); - return; - } - if (rdisc_sock_mcast != ifp) { - /* select the right interface. */ -#ifdef MCAST_PPP_BUG - /* Do not specifiy the primary interface explicitly - * if we have the multicast point-to-point kernel - * bug, since the kernel will do the wrong thing - * if the local address of a point-to-point link - * is the same as the address of an ordinary - * interface. - */ - if (ifp->int_addr == myaddr) { - tgt_mcast = 0; - } else -#endif - tgt_mcast = ifp->int_addr; - if (0 > setsockopt(rdisc_sock, - IPPROTO_IP, IP_MULTICAST_IF, - &tgt_mcast, sizeof(tgt_mcast))) { - LOGERR("setsockopt(rdisc_sock," - "IP_MULTICAST_IF)"); - rdisc_sock_mcast = 0; - return; - } - rdisc_sock_mcast = ifp; - } - flags = 0; - break; - } - - if (rdisc_sock < 0) - get_rdisc_sock(); - - trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, - p, p_size); - - if (0 > sendto(rdisc_sock, p, p_size, flags, - (struct sockaddr *)&sin, sizeof(sin))) { - if (ifp == 0 || !(ifp->int_state & IS_BROKE)) - msglog("sendto(%s%s%s): %s", - ifp != 0 ? ifp->int_name : "", - ifp != 0 ? ", " : "", - inet_ntoa(sin.sin_addr), - strerror(errno)); - if (ifp != 0) - if_sick(ifp); - } -} - - -/* Send an advertisement - */ -static void -send_adv(struct interface *ifp, - naddr dst, /* 0 or unicast destination */ - int type) /* 0=unicast, 1=bcast, 2=mcast */ -{ - union ad_u u; - n_long pref; - - - bzero(&u,sizeof(u.ad)); - - u.ad.icmp_type = ICMP_ROUTERADVERT; - u.ad.icmp_ad_num = 1; - 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); - - u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; - - u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); - - send_rdisc(&u, sizeof(u.ad), ifp, dst, type); -} - - -/* Advertise for Router Discovery - */ -void -rdisc_adv(void) -{ - struct interface *ifp; - - - rdisc_timer.tv_sec = now.tv_sec + NEVER; - - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - if (0 != (ifp->int_state & (IS_NO_ADV_OUT - | IS_PASSIVE - | IS_ALIAS - | IS_BROKE))) - continue; - - if (!timercmp(&ifp->int_rdisc_timer, &now, >) - || stopint) { - send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), - (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); - ifp->int_rdisc_cnt++; - - intvl_random(&ifp->int_rdisc_timer, - (ifp->int_rdisc_int*3)/4, - ifp->int_rdisc_int); - if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS - && (ifp->int_rdisc_timer.tv_sec - > MAX_INITIAL_ADVERT_INTERVAL)) { - ifp->int_rdisc_timer.tv_sec - = MAX_INITIAL_ADVERT_INTERVAL; - } - timevaladd(&ifp->int_rdisc_timer, &now); - } - - if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) - rdisc_timer = ifp->int_rdisc_timer; - } -} - - -/* Solicit for Router Discovery - */ -void -rdisc_sol(void) -{ - struct interface *ifp; - union ad_u u; - - - rdisc_timer.tv_sec = now.tv_sec + NEVER; - - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - if (0 != (ifp->int_state & (IS_NO_SOL_OUT - | IS_PASSIVE - | IS_ALIAS - | IS_BROKE)) - || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) - continue; - - if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { - bzero(&u,sizeof(u.so)); - u.so.icmp_type = ICMP_ROUTERSOLICIT; - u.so.icmp_cksum = in_cksum((u_short*)&u.so, - sizeof(u.so)); - send_rdisc(&u, sizeof(u.so), ifp, - htonl(INADDR_ALLROUTERS_GROUP), - ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); - - if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) - continue; - - ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; - ifp->int_rdisc_timer.tv_usec = 0; - timevaladd(&ifp->int_rdisc_timer, &now); - } - - if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) - rdisc_timer = ifp->int_rdisc_timer; - } -} - - -/* check the IP header of a possible Router Discovery ICMP packet */ -static struct interface * /* 0 if bad */ -ck_icmp(char *act, - naddr from, - naddr to, - union ad_u *p, - u_int len) -{ - struct interface *ifp; - char *type; - - - /* If we could tell the interface on which a packet from address 0 - * arrived, we could deal with such solicitations. - */ - - ifp = ((from == 0) ? 0 : iflookup(from)); - - if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { - type = "advertisement"; - } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { - type = "solicitation"; - } else { - return 0; - } - - if (p->icmp.icmp_code != 0) { - trace_pkt("unrecognized ICMP Router" - " %s code=%d from %s to %s\n", - type, p->icmp.icmp_code, - naddr_ntoa(from), naddr_ntoa(to)); - return 0; - } - - trace_rdisc(act, from, to, ifp, p, len); - - if (ifp == 0) - trace_pkt("unknown interface for router-discovery %s" - " from %s to %s", - type, naddr_ntoa(from), naddr_ntoa(to)); - - return ifp; -} - - -/* read packets from the router discovery socket - */ -void -read_d(void) -{ - static naddr bad_asize, bad_len; - struct sockaddr_in from; - int n, fromlen, cc, hlen; - union { - struct ip ip; - u_short s[512/2]; - u_char b[512]; - } pkt; - union ad_u *p; - n_long *wp; - struct interface *ifp; - - - for (;;) { - fromlen = sizeof(from); - cc = recvfrom(rdisc_sock, &pkt, sizeof(pkt), 0, - (struct sockaddr*)&from, - &fromlen); - if (cc <= 0) { - if (cc < 0 && errno != EWOULDBLOCK) - LOGERR("recvfrom(rdisc_sock)"); - break; - } - if (fromlen != sizeof(struct sockaddr_in)) - logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", - fromlen); - - hlen = pkt.ip.ip_hl << 2; - if (cc < hlen + ICMP_MINLEN) - continue; - p = (union ad_u *)&pkt.b[hlen]; - cc -= hlen; - - ifp = ck_icmp("Recv", - from.sin_addr.s_addr, pkt.ip.ip_dst.s_addr, - p, cc); - if (ifp == 0) - continue; - if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { - trace_pkt("\tdiscard our own Router Discovery msg\n"); - continue; - } - - switch (p->icmp.icmp_type) { - case ICMP_ROUTERADVERT: - if (p->ad.icmp_ad_asize*4 - < sizeof(p->ad.icmp_ad_info[0])) { - if (bad_asize != from.sin_addr.s_addr) { - msglog("intolerable rdisc address" - " size=%d", - p->ad.icmp_ad_asize); - bad_asize = from.sin_addr.s_addr; - } - continue; - } - if (p->ad.icmp_ad_num == 0) { - trace_pkt("\tempty?\n"); - continue; - } - if (cc != (sizeof(p->ad) - sizeof(p->ad.icmp_ad_info) - + (p->ad.icmp_ad_num - * sizeof(p->ad.icmp_ad_info[0])))) { - if (bad_len != from.sin_addr.s_addr) { - msglog("rdisc length %d does not" - " match ad_num %d", - cc, p->ad.icmp_ad_num); - bad_len = from.sin_addr.s_addr; - } - continue; - } - if (supplier) - continue; - if (ifp->int_state & IS_NO_ADV_IN) - continue; - - wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; - for (n = 0; n < p->ad.icmp_ad_num; n++) { - parse_ad(from.sin_addr.s_addr, - wp[0], wp[1], - ntohs(p->ad.icmp_ad_life), - ifp); - wp += p->ad.icmp_ad_asize; - } - break; - - - case ICMP_ROUTERSOLICIT: - if (!supplier) - continue; - if (ifp->int_state & IS_NO_ADV_OUT) - continue; - - /* XXX - * We should handle messages from address 0. - */ - - /* Respond with a point-to-point advertisement */ - send_adv(ifp, from.sin_addr.s_addr, 0); - break; - } - } - - rdisc_sort(); -} diff --git a/usr.sbin/routed/routed.8 b/usr.sbin/routed/routed.8 deleted file mode 100644 index c4fe5166b109..000000000000 --- a/usr.sbin/routed/routed.8 +++ /dev/null @@ -1,602 +0,0 @@ -.\" Copyright (c) 1983, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)routed.8 8.2 (Berkeley) 12/11/93 -.\" -.Dd June 1, 1996 -.Dt ROUTED 8 -.Os BSD 4.4 -.Sh NAME -.Nm routed -.Nd network RIP and router discovery routing daemon -.Sh SYNOPSIS -.Nm -.Op Fl sqdghmAt -.Op Fl T Ar tracefile -.Oo -.Fl F -.Ar net Ns Op /mask Ns Op ,metric -.Oc -.OP Fl P Ar parms -.Sh DESCRIPTION -.Nm Routed -is a dameon invoked at boot time to manage the network -routing tables. -It uses Routing Information Protocol, RIPv1 (RFC\ 1058), -RIPv2 (RFC\ 1723), -and Internet Router Discovery Protocol (RFC 1256) -to maintain the kernel routing table. -The RIPv1 protocol is based on the reference 4.3BSD daemon. -.Pp -It listens on the -.Xr udp 4 -socket for the -.Xr route 8 -service (see -.Xr services 5 ) -for Routing Information Protocol packets. -It also sends and receives multicast Router Discovery ICMP messages. -If the host is a router, -.Nm -periodically supplies copies -of its routing tables to any directly connected hosts and networks. -It also advertise or solicits default routes using Router Discovery -ICMP messages. -.Pp -When started (or when a network interface is later turned on), -.Nm -uses an AF_ROUTE address family facility to find those -directly connected interfaces configured into the -system and marked "up". -It adds necessary routes for the interfaces -to the kernel routing table. -Soon after being first started, and provided there is at least one -interface on which RIP has not been disabled, -.Nm -deletes all pre-existing -non-static routes in kernel table. -Static routes in the kernel table are preserved and -included in RIP responses if they have a valid RIP metric -(see -.Xr route 8 ). -.Pp -If more than one interface is present (not counting the loopback interface), -it is assumed that the host should forward packets among the -connected networks. -After transmitting a RIP -.Em request -and -Router Discovery Advertisements or Solicitations on a new interface, -the daemon enters a loop, listening for -RIP request and response and Router Discover packets from other hosts. -.Pp -When a -.Em request -packet is received, -.Nm -formulates a reply based on the information maintained in its -internal tables. -The -.Em response -packet generated contains a list of known routes, each marked -with a "hop count" metric (a count of 16 or greater is -considered "infinite"). -Advertised metrics reflect the metric associated with interface -(see -.Xr ifconfig 8 ), -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 -network to implement in part -.Em split-horizon . -Requests from query programs -such as -.Xr rtquery 8 -are answered with the complete table. -.Pp -The routing table maintained by the daemon -includes space for several gateways for each destination -to speed recovery from a failing router. -RIP -.Em response -packets received are used to update the routing tables provided they are -from one of the several currently recognized gateways or -advertise a better metric than at least one of the existing -gateways. -.Pp -When an update is applied, -.Nm -records the change in its own tables and updates the kernel routing table -if the best route to the destination changes. -The change in the kernel routing tableis reflected in the next batch of -.Em response -packets sent. -If the next response is not scheduled for a while, a -.Em flash update -response containing only recently changed routes is sent. -.Pp -In addition to processing incoming packets, -.Nm -also periodically checks the routing table entries. -If an entry has not been updated for 3 minutes, the entry's metric -is set to infinity and marked for deletion. -Deletions are delayed until the route has been advertised with -an infinite metric to insure the invalidation -is propagated throughout the local internet. -This is a form of -.Em poison reverse . -.Pp -Routes in the kernel table that are added or changed as a result -of ICMP Redirect messages are deleted after a while to minimize -.Em black-holes . -When a TCP connection suffers a timeout, -the kernel tells -.Nm routed , -which deletes all redirected routes -through the gateway involved, advances the age of all RIP routes through -the gateway to allow an alternate to be chosen, and advances of the -age of any relevant Router Discovery Protocol default routes. -.Pp -Hosts acting as internetwork routers gratuitously supply their -routing tables every 30 seconds to all directly connected hosts -and networks. -These RIP responses are sent to the broadcast address on nets that support -broadcasting, -to the destination address on point-to-point links, and to the router's -own address on other networks. -If RIPv2 is enabled, multicast packets are sent on interfaces that -support multicasting. -.Pp -If no response is received on a remote interface, if there are errors -while sending responses, -or if there are more errors than input or output (see -.Xr netstat 8 ), -then the cable or some other part of the interface is assumed to be -disconnected or broken, and routes are adjusted appropriately. -.Pp -The -.Em Internet Router Discovery Protocol -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 -sends Solicitations and listens for Advertisements. -If it receives -a good Advertisement, 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 Discover Advertisement -is received), there is a single default route and a variable number of -redirected host routes in the kernel table. -.Pp -The Router Discover standard requires that advertisements -have a default "lifetime" of 30 minutes. That means should -something happen, a client can be without a good route for -30 minutes. It is a good idea to reduce the default to 45 -seconds using -.Fl P Cm rdisc_interval=45 -on the command line or -.Cm rdisc_interval=45 -in the -.Pa /etc/gateways -file. -.Pp -While using Router Discovery (which happens by default when -the system has a single network interface and a Router Discover Advertisement -is received), there is a single default route and a variable number of -redirected host routes in the kernel table. -.Pp -See the -.Cm pm_rdisc -facility described below to support "legacy" systems -that can handle neither RIPv2 nor Router Discovery. -.Pp -By default, neither Router Discovery advertisements nor solicications -are sent over point to point links (e.g. PPP). - -.Pp -Options supported by -.Nm routed : -.Bl -tag -width Ds -.It Fl s -this option forces -.Nm -to supply routing information. -This is the default if multiple network interfaces are present on which -RIP or Router Discovery have not been disabled, and if the kernel switch -ipforwarding=1. -.It Fl q -is the opposite of the -.Fl s -option. -.It Fl d -Do not run in the background. -This option is meant for interactive use. -.It Fl g -This flag is used on internetwork routers to offer a route -to the "default" destination. -It is equivalent to -.Fl F -.Cm 0/0,1 -and is present mostly for historical reasons. -A better choice is -.Fl P Cm pm_rdisc -on the command line or -.CM pm_rdisc in the -.Pa /etc/gateways -file. -since a larger metric -will be used, reducing the spread of the potentially dangerous -default route. -This is typically used on a gateway to the Internet, -or on a gateway that uses another routing protocol whose routes -are not reported to other local routers. -Notice that because a metric of 1 is used, this feature is -dangerous. It is more commonly accidently used to create chaos with routing -loop than to solve problems. -.It Fl h -This causes host or point-to-point routes to not be advertised, -provided there is a network route going the same direction. -That is a limited kind of aggregation. -This option is useful on gateways to ethernets that have other gateway -machines connected with point-to-point links such as SLIP. -.It Fl m -This causes the machine to advertise a host or point-to-point route to -its primary interface. -It is useful on multi-homed machines such as NFS servers. -This option should not be used except when the cost of -the host routes it generates is justified by the popularity of -the server. -It is effective only when the machine is supplying -routing information, because there is more than one interface. -The -.Fl m -option overrides the -.Fl q -option to the limited extent of advertising the host route. -.It Fl A -do not ignore RIPv2 authentication if we do not care about RIPv2 -authentication. -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. -.It Fl t -increases the debugging level, which causes more information to be logged -on the tracefile specified with -.Fl T -or standard out. -The debugging level can be increased or decreased -with the -.Em SIGUSR1 -or -.Em SIGUSR2 -signals or with the -.Cm rtquery -command. -.It Fl F Ar net[/mask][,metric] -minimize routes in transmissions via interfaces with addresses that match -.Em net/mask , -and synthesizes a default route to this machine with the -.Em metric . -The intent is to reduce RIP traffic on slow, point-to-point links -such as PPP links by replacing many large UDP packets of RIP information -with a single, small packet containing a "fake" default route. -If -.Em metric -is absent, a value of 14 is assumed to limit -the spread of the "fake" default route. - -This is a dangerous feature that when used carelessly can cause routing -loops. -Notice also that more than one interface can match the specified network -number and mask. -See also -.Fl g . -.It Fl P Ar parms -is equivalent to adding the parameter -line -.Em parms -to the -.Pa /etc/gateways -file. -.El -.Pp -Any other argument supplied is interpreted as the name -of a file in which the actions of -.Nm -should be logged. -It is better to use -.Fl T -instead of -appending the name of the trace file to the command. -.Pp -.Nm -also supports the notion of -"distant" -.Em passive -or -.Em active -gateways. -When -.Nm -is started, it reads the file -.Pa /etc/gateways -to find such distant gateways which may not be located using -only information from a routing socket, to discover if some -of the local gateways are -.Em passive , -and to obtain other parameters. -Gateways specified in this manner should be marked passive -if they are not expected to exchange routing information, -while gateways marked active -should be willing to exchange RIP packets. -Routes through -.Em passive -gateways are installed in the -kernel's routing tables once upon startup and are not included in -transmitted RIP responses. -.Pp -Distant active gateways are treated like network interfaces. -RIP responses are sent -to the distant -.Em active -gateway. -If no responses are received, the associated route is deleted from -the kernel table and RIP responses advertised via other interfaces. -If the distant gateway resumes sending RIP responses, the associated -route is restored. -.Pp -Such gateways can be useful on media that do not support broadcasts -or multicasts but otherwise act like classic shared media like -Ethernets such as some ATM networks. -One can list all RIP routers reachable on the ATM network in -.Pa /etc/gateways -with a series of -"host" lines. -.Pp -Gateways marked -.Em external -are also passive, but are not placed in the kernel -routing table nor are they included in routing updates. -The function of external entries is to indicate -that another routing process -will install such a route if ncessary, -and that alternate routes to that destination should not be installed -by -.Nm routed . -Such entries are only required when both routers may learn of routes -to the same destination. -.Pp -The -.Em /etc/gateways -file is comprised of a series of lines, each in -one of the following formats or consist of parameters described below: -.Pp -.Bd -ragged -.Cm net -.Ar Nname[/mask] -.Cm gateway -.Ar Gname -.Cm metric -.Ar value -.Pf < Cm passive No \&| -.Cm active No \&| -.Cm extern Ns > -.Ed -.Bd -ragged -.Cm host -.Ar Hname -.Cm gateway -.Ar Gname -.Cm metric -.Ar value -.Pf < Cm passive No \&| -.Cm active No \&| -.Cm extern Ns > -.Ed -.Pp -.Ar Nname -or -.Ar Hname -is the name of the destination network or host. -It may be a symbolic network name or an Internet address -specified in "dot" notation (see -.Xr inet 3 ). -(If it is a name, then it must either be defined in -.Pa /etc/networks -or -.Pa /etc/hosts , -or -.Xr named 8 , -must have been started before -.Xr routed Ns .) -.Pp -.Ar mask -is an optional number between 1 and 32 indicating the netmask associated -with -.Ar Nname . -.Pp -.Ar Gname -is the name or address of the gateway to which RIP responses should -be forwarded. -.Pp -.Ar Value -is the hop count to the destination host or network. -.Ar " host hname " -is equivalent to -.Ar " net nname/32 ". -.Pp -One of the keywords -.Cm passive , -.Cm active -or -.Cm external -must be present to indicate whether the gateway should be treated as -.Cm passive -or -.Cm active -(as described above), -or whether the gateway is -.Cm external -to the scope of the RIP protocol. -.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: -.Bl -tag -width Ds -.It Cm if Ns \&= Ns Ar ifname -indicates that the other parameters on the line apply to the interface -name -.Ar ifname . -.It Cm subnet Ns \&= Ns Ar nname[/mask][,metric] -advertises a route to network -.AR nname -with mask -.AR 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. -.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 no_ag -turns off aggregation of subnets in RIPv1 and RIPv2 responses. -.It Cm no_super_ag -turns off aggregation of networks into supernets in RIPv2 responses. -.It Cm passive -is equivalent -.Cm no_rip Cm no_rdisc . -.It Cm no_rip -disables all RIP processing on the specified interface. -If no interfaces are allowed to process RIP packets, -.Nm -acts purely as a router discovery daemon. -.Cm No_rip -is equivalent to -.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out . - -Note that turning off RIP without explicitly turning on router -discovery advertisements with -.Cm rdisc_adv -or -.Fl s -causes -.Nm routed -to act as a client router discovery daemon, not adveritising. -.It Cm no_ripv1_in -causes RIPv1 received responses to be ignored. -.It Cm no_ripv2_in -causes RIPv2 received responses to be ignored. -.It Cm ripv2_out -turns off RIPv1 output and causes RIPv2 advertisements to be -multicast when possible. -.It Cm no_rdisc -disables the Internet Router Discovery Protocol. -.It Cm no_solicit -disables the tranmission of Router Discovery Solicitations. -.It Cm send_solicit -specifies that Router Discovery solicitations should be sent, -even on point-to-point links, -which by default only listen to Router Discovery messages. -.It Cm no_rdisc_adv -disables the transmission of Router Discovery Advertisements -.It Cm rdisc_adv -specifies that Router Discovery advertisements should be sent, -even on point-to-point links, -which by default only listen to Router Discovery messages -.It Cm bcast_rdisc -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 -.Ar N . -.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. -.It Cm fake_default Ns \&= Ns Ar metric -has an identical effect to -.Fl F Ar net[/mask][,metric] -with the network and mask coming from the sepcified interface. -.It Cm pm_rdisc -is similar to -.Cm fake_default . -When RIPv2 routes are multicast, so that RIPv1 listeners cannot -receive them, this feature causes a RIPv1 default route to be -broadcast to RIPv1 listeners. -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. -.El -.Pp -Note that the netmask associated with point-to-point links (such as SLIP -or PPP, with the IFF_POINTOPOINT flag) is used by -.Nm routed -to infer the netmask used by the remote system when RIPv1 is used. -.Pp -.Sh FILES -.Bl -tag -width /etc/gateways -compact -.It Pa /etc/gateways -for distant gateways -.El -.Sh SEE ALSO -.Xr gated 8 , -.Xr udp 4 , -.Xr icmp 4 , -.Xr htable 8 , -.Xr rtquery 8 . -.Rs -.%T Internet Transport Protocols -.%R XSIS 028112 -.%Q Xerox System Integration Standard -.Re -.Sh BUGS -It does not always detect unidirectional failures in network interfaces -(e.g., when the output side fails). -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.2 . diff --git a/usr.sbin/routed/rtquery/Makefile b/usr.sbin/routed/rtquery/Makefile deleted file mode 100644 index e748e739bc9c..000000000000 --- a/usr.sbin/routed/rtquery/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# From: @(#)Makefile 8.1 (Berkeley) 6/5/93 -# $Id$ - -PROG= rtquery -MAN8= rtquery.8 -#COPTS= -g -DDEBUG -Wall - -.include diff --git a/usr.sbin/routed/rtquery/rtquery.8 b/usr.sbin/routed/rtquery/rtquery.8 deleted file mode 100644 index 3c59efd66443..000000000000 --- a/usr.sbin/routed/rtquery/rtquery.8 +++ /dev/null @@ -1,79 +0,0 @@ -.Dd April 9, 1996 -.Dt RTQUERY 8 -.Os BSD 4.4 -.Sh NAME -.Nm rtquery -.Nd query routing daemons for their routing tables -.Sh SYNOPSIS -.Nm -.Op Fl np1 -.Op Fl 1 Ar timeout -.Op Fl r Ar addr -.Ar host ... -.Sh DESCRIPTION -.Nm Rtquery -is used to query a network routing daemon, -.Xr routed 8 -or -.Xr gated 8 , -for its routing table by sending a -.Em request -or -.Em poll -command. The routing information in any routing -.Em response -packets returned is displayed numerically and symbolically. -.Pp -.Em Rtquery -by default uses the -.Em request -command. -When the -.B \-p -option is specified, -.Nm rtquery -uses the -.Em poll -command, which is an -undocumented extension to the RIP specification supported by -.IR gated (1M). -When querying -.IR gated (1M), -the -.I poll -command is preferred over the -.I request -command because the response is not subject to Split Horizon and/or -Poisioned Reverse. -.Pp -Options supported by -.Nm rtquery : -.Bl -tag -width Ds -.It Fl n -Normally network and host numbers are displayed both symbolically -and numerically. -The -.Fl n -option displays only the numeric network and host numbers. -.It Fl p -Uses the -.Em poll -command to request full routing information from -.Xr gated 8 , -This is an undocumented extension supported only by -.Xr gated 8 . -.It Fl 1 -query using RIP version 1 instead of RIP version 2. -.It Fl w Ar timeout -changes the delay for an answer from each host. -By default, each host is given 15 seconds to respond. -.It Fl r Ar addr -ask about the route to destination -.Em parms -.Sh SEE ALSO -.Xr routed 8, -.Xr gated 8, -.br -RFC\ 1058 - Routing Information Protocol, RIPv1 -.br -RFC\ 1723 - Routing Information Protocol, RIPv2 diff --git a/usr.sbin/routed/rtquery/rtquery.c b/usr.sbin/routed/rtquery/rtquery.c deleted file mode 100644 index 97899c970983..000000000000 --- a/usr.sbin/routed/rtquery/rtquery.c +++ /dev/null @@ -1,516 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1982, 1986, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93"; -#endif /* not lint */ - -#include -#include -#include -#include -#include -#define RIPVERSION RIPv2 -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef sgi -#include -#include -#endif - -#ifndef sgi -#define _HAVE_SIN_LEN -#endif - -#define WTIME 15 /* Time to wait for all responses */ -#define STIME (250*1000) /* usec to wait for another response */ - -int s; - -char *pgmname; - -union pkt_buf { - char packet[MAXPACKETSIZE+4096]; - struct rip rip; -} msg_buf; -#define MSG msg_buf.rip -#define MSG_LIM ((struct rip*)(&msg_buf.packet[MAXPACKETSIZE \ - - sizeof(struct netinfo)])) - -int nflag; /* numbers, no names */ -int pflag; /* play the `gated` game */ -int ripv2 = 1; /* use RIP version 2 */ -int wtime = WTIME; -int rflag; /* 1=ask about a particular route */ - -struct timeval start; /* when query sent */ - -static void rip_input(struct sockaddr_in*, int); -static int query(char *, struct netinfo *); -static int getnet(char *, struct netinfo *); -static u_int std_mask(u_int); - - -int -main(int argc, - char *argv[]) -{ - char *p; - struct seen { - struct seen *next; - struct in_addr addr; - } *seen, *sp; - int answered = 0; - int ch, cc, bsize; - fd_set bits; - struct timeval now, delay; - struct sockaddr_in from; - int fromlen; - struct netinfo rt; - - - bzero(&rt, sizeof(rt)); - - pgmname = argv[0]; - while ((ch = getopt(argc, argv, "np1w:r:")) != EOF) - switch (ch) { - case 'n': - nflag = 1; - break; - case 'p': - pflag = 1; - break; - case '1': - ripv2 = 0; - break; - case 'w': - wtime = (int)strtoul(optarg, &p, 0); - if (*p != '\0' - || wtime <= 0) - goto usage; - break; - case 'r': - if (rflag) - goto usage; - rflag = getnet(optarg, &rt); - break; - case '?': - default: - goto usage; - } - argv += optind; - argc -= optind; - if (argc == 0) { -usage: printf("usage: query [-np1v] [-w wtime] host1 [host2 ...]\n"); - exit(1); - } - - if (!rflag) { - rt.n_dst = RIP_DEFAULT; - rt.n_family = RIP_AF_UNSPEC; - rt.n_metric = htonl(HOPCNT_INFINITY); - } - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket"); - exit(2); - } - for (bsize = 127*1024; ; bsize -= 1024) { - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, - &bsize, sizeof(bsize)) == 0) - break; - if (bsize <= 4*1024) { - perror("setsockopt SO_RCVBUF"); - break; - } - } - - /* ask the first host */ - seen = 0; - while (0 > query(*argv++, &rt) && *argv != 0) - answered++; - - FD_ZERO(&bits); - for (;;) { - FD_SET(s, &bits); - delay.tv_sec = 0; - delay.tv_usec = STIME; - cc = select(s+1, &bits, 0,0, &delay); - if (cc > 0) { - fromlen = sizeof(from); - cc = recvfrom(s, msg_buf.packet, - sizeof(msg_buf.packet), 0, - (struct sockaddr *)&from, &fromlen); - if (cc < 0) { - perror("recvfrom"); - exit(1); - } - /* count the distinct responding hosts. - * You cannot match responding hosts with - * addresses to which queries were transmitted, - * because a router might respond with a - * different source address. - */ - for (sp = seen; sp != 0; sp = sp->next) { - if (sp->addr.s_addr == from.sin_addr.s_addr) - break; - } - if (sp == 0) { - sp = malloc(sizeof(*sp)); - sp->addr = from.sin_addr; - sp->next = seen; - seen = sp; - answered++; - } - - rip_input(&from, cc); - continue; - } - - if (cc < 0) { - if ( errno == EINTR) - continue; - perror("select"); - exit(1); - } - - /* After a pause in responses, probe another host. - * This reduces the intermingling of answers. - */ - while (*argv != 0 && 0 > query(*argv++, &rt)) - answered++; - - /* continue until no more packets arrive - * or we have heard from all hosts - */ - if (answered >= argc) - break; - - /* or until we have waited a long time - */ - if (gettimeofday(&now, 0) < 0) { - perror("gettimeofday(now)"); - exit(1); - } - if (start.tv_sec + wtime <= now.tv_sec) - break; - } - - /* fail if there was no answer */ - exit (answered >= argc ? 0 : 1); - /* NOTREACHED */ -} - - -/* - * Poll one host. - */ -static int -query(char *host, - struct netinfo *rt) -{ - struct sockaddr_in router; - struct hostent *hp; - - if (gettimeofday(&start, 0) < 0) { - perror("gettimeofday(start)"); - return -1; - } - - bzero(&router, sizeof(router)); - router.sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - router.sin_len = sizeof(router); -#endif - router.sin_addr.s_addr = inet_addr(host); - if (router.sin_addr.s_addr == -1) { - hp = gethostbyname(host); - if (hp == 0) { - fprintf(stderr,"%s: %s:", pgmname, host); - herror(0); - return -1; - } - bcopy(hp->h_addr, &router.sin_addr, hp->h_length); - } - - router.sin_port = htons(RIP_PORT); - - MSG.rip_cmd = (pflag)? RIPCMD_POLL : RIPCMD_REQUEST; - MSG.rip_nets[0] = *rt; - if (ripv2) { - MSG.rip_vers = RIPv2; - } else { - MSG.rip_vers = RIPv1; - MSG.rip_nets[0].n_mask = 0; - } - - if (sendto(s, msg_buf.packet, sizeof(struct rip), 0, - (struct sockaddr *)&router, sizeof(router)) < 0) { - perror(host); - return -1; - } - - return 0; -} - - -/* - * Handle an incoming RIP packet. - */ -static void -rip_input(struct sockaddr_in *from, - int size) -{ - struct netinfo *n, *lim; - struct in_addr in; - char *name; - char net_buf[80]; - u_int mask, dmask; - char *sp; - int i; - struct hostent *hp; - struct netent *np; - struct netauth *a; - - - if (nflag) { - printf("%s:", inet_ntoa(from->sin_addr)); - } else { - hp = gethostbyaddr((char*)&from->sin_addr, - sizeof(struct in_addr), AF_INET); - if (hp == 0) { - printf("%s:", - inet_ntoa(from->sin_addr)); - } else { - printf("%s (%s):", hp->h_name, - inet_ntoa(from->sin_addr)); - } - } - if (MSG.rip_cmd != RIPCMD_RESPONSE) { - printf("\n unexpected response type %d\n", MSG.rip_cmd); - return; - } - printf(" RIPv%d%s %d bytes\n", MSG.rip_vers, - (MSG.rip_vers != RIPv1 && MSG.rip_vers != RIPv2) ? " ?" : "", - size); - if (size > MAXPACKETSIZE) { - if (size > sizeof(msg_buf) - sizeof(*n)) { - printf(" at least %d bytes too long\n", - size-MAXPACKETSIZE); - size = sizeof(msg_buf) - sizeof(*n); - } else { - printf(" %d bytes too long\n", - size-MAXPACKETSIZE); - } - } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - printf(" response of bad length=%d\n", size); - } - - n = MSG.rip_nets; - lim = (struct netinfo *)((char*)n + size) - 1; - for (; n <= lim; n++) { - name = ""; - if (n->n_family == RIP_AF_INET) { - in.s_addr = n->n_dst; - (void)strcpy(net_buf, inet_ntoa(in)); - - mask = ntohl(n->n_mask); - dmask = mask & -mask; - if (mask != 0) { - sp = &net_buf[strlen(net_buf)]; - if (MSG.rip_vers == RIPv1) { - (void)sprintf(sp," mask=%#x ? ",mask); - mask = 0; - } else if (mask + dmask == 0) { - for (i = 0; - (i != 32 - && ((1<n_name; - else if (in.s_addr == 0) - name = "default"; - } - if (name[0] == '\0' - && (in.s_addr & ~mask) != 0) { - hp = gethostbyaddr((char*)&in, - sizeof(in), - AF_INET); - if (hp != 0) - name = hp->h_name; - } - } - - } else if (n->n_family == RIP_AF_AUTH) { - a = (struct netauth*)n; - (void)printf(" authentication type %d: ", - a->a_type); - for (i = 0; i < sizeof(a->au.au_pw); i++) - (void)printf("%02x ", a->au.au_pw[i]); - putc('\n', stdout); - continue; - - } else { - (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", - n->n_family, - (char)(n->n_dst >> 24), - (char)(n->n_dst >> 16), - (char)(n->n_dst >> 8), - (char)n->n_dst); - } - - (void)printf(" %-18s metric %2d %8s", - net_buf, ntohl(n->n_metric), name); - - if (n->n_nhop != 0) { - in.s_addr = n->n_nhop; - if (nflag) - hp = 0; - else - hp = gethostbyaddr((char*)&in, sizeof(in), - AF_INET); - (void)printf(" nhop=%-15s%s", - (hp != 0) ? hp->h_name : inet_ntoa(in), - (MSG.rip_vers == RIPv1) ? " ?" : ""); - } - if (n->n_tag != 0) - (void)printf(" tag=%#x%s", n->n_tag, - (MSG.rip_vers == RIPv1) ? " ?" : ""); - putc('\n', stdout); - } -} - - -/* Return the classical netmask for an IP address. - */ -static u_int -std_mask(u_int addr) -{ - NTOHL(addr); - - if (addr == 0) - return 0; - if (IN_CLASSA(addr)) - return IN_CLASSA_NET; - if (IN_CLASSB(addr)) - return IN_CLASSB_NET; - return IN_CLASSC_NET; -} - - -/* get a network number as a name or a number, with an optional "/xx" - * netmask. - */ -static int /* 0=bad */ -getnet(char *name, - struct netinfo *rt) -{ - int i; - struct netent *nentp; - u_int mask; - struct in_addr in; - char hname[MAXHOSTNAMELEN+1]; - char *mname, *p; - - - /* Detect and separate "1.2.3.4/24" - */ - if (0 != (mname = rindex(name,'/'))) { - i = (int)(mname - name); - if (i > sizeof(hname)-1) /* name too long */ - return 0; - bcopy(name, hname, i); - hname[i] = '\0'; - mname++; - name = hname; - } - - nentp = getnetbyname(name); - if (nentp != 0) { - in.s_addr = nentp->n_net; - } else if (inet_aton(name, &in) == 1) { - NTOHL(in.s_addr); - } else { - return 0; - } - - if (mname == 0) { - mask = std_mask(in.s_addr); - } else { - mask = (u_int)strtoul(mname, &p, 0); - if (*p != '\0' || mask > 32) - return 0; - mask = 0xffffffff << (32-mask); - } - - rt->n_dst = in.s_addr; - rt->n_family = AF_INET; - rt->n_mask = htonl(mask); - return 1; -} diff --git a/usr.sbin/routed/table.c b/usr.sbin/routed/table.c deleted file mode 100644 index aa7510c251f1..000000000000 --- a/usr.sbin/routed/table.c +++ /dev/null @@ -1,1961 +0,0 @@ -/* - * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#include "defs.h" - -static struct rt_spare *rts_better(struct rt_entry *); - -struct radix_node_head *rhead; /* root of the radix tree */ - -int need_flash = 1; /* flash update needed - * start =1 to suppress the 1st - */ - -struct timeval age_timer; /* next check of old routes */ -struct timeval need_kern = { /* need to update kernel table */ - EPOCH+MIN_WAITTIME-1 -}; - -int stopint; - -int total_routes; - -naddr age_bad_gate; - - -/* It is desirable to "aggregate" routes, to combine differing routes of - * the same metric and next hop into a common route with a smaller netmask - * or to suppress redundant routes, routes that add no information to - * routes with smaller netmasks. - * - * A route is redundant if and only if any and all routes with smaller - * but matching netmasks and nets are the same. Since routes are - * kept sorted in the radix tree, redundant routes always come second. - * - * There are two kinds of aggregations. First, two routes of the same bit - * mask and differing only in the least significant bit of the network - * number can be combined into a single route with a coarser mask. - * - * Second, a route can be suppressed in favor of another route with a more - * coarse mask provided no incompatible routes with intermediate masks - * are present. The second kind of aggregation involves suppressing routes. - * A route must not be suppressed if an incompatible route exists with - * an intermediate mask, since the suppressed route would be covered - * by the intermediate. - * - * This code relies on the radix tree walk encountering routes - * sorted first by address, with the smallest address first. - */ - -struct ag_info ag_slots[NUM_AG_SLOTS], *ag_avail, *ag_corsest, *ag_finest; - -/* #define DEBUG_AG */ -#ifdef DEBUG_AG -#define CHECK_AG() {int acnt = 0; struct ag_info *cag; \ - for (cag = ag_avail; cag != 0; cag = cag->ag_fine) \ - acnt++; \ - for (cag = ag_corsest; cag != 0; cag = cag->ag_fine) \ - acnt++; \ - if (acnt != NUM_AG_SLOTS) { \ - (void)fflush(stderr); \ - abort(); \ - } \ -} -#else -#define CHECK_AG() -#endif - - -/* Output the contents of an aggregation table slot. - * This function must always be immediately followed with the deletion - * of the target slot. - */ -static void -ag_out(struct ag_info *ag, - void (*out)(struct ag_info *)) -{ - struct ag_info *ag_cors; - naddr bit; - - - /* 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. - * On successive calls, this code detects the even and odd twins, - * and marks the parent. - * - * Note that the order in which the radix tree code emits routes - * ensures that the twins are seen before the parent is emitted. - */ - ag_cors = ag->ag_cors; - if (ag_cors != 0 - && ag_cors->ag_mask == ag->ag_mask<<1 - && ag_cors->ag_dst_h == (ag->ag_dst_h & ag_cors->ag_mask)) { - ag_cors->ag_state |= ((ag_cors->ag_dst_h == ag->ag_dst_h) - ? AGS_REDUN0 - : AGS_REDUN1); - } - - /* Skip it if this route is itself redundant. - * - * It is ok to change the contents of the slot here, since it is - * always deleted next. - */ - if (ag->ag_state & AGS_REDUN0) { - if (ag->ag_state & AGS_REDUN1) - return; - bit = (-ag->ag_mask) >> 1; - ag->ag_dst_h |= bit; - ag->ag_mask |= bit; - - } else if (ag->ag_state & AGS_REDUN1) { - bit = (-ag->ag_mask) >> 1; - ag->ag_mask |= bit; - } - out(ag); -} - - -static void -ag_del(struct ag_info *ag) -{ - CHECK_AG(); - - if (ag->ag_cors == 0) - ag_corsest = ag->ag_fine; - else - ag->ag_cors->ag_fine = ag->ag_fine; - - if (ag->ag_fine == 0) - ag_finest = ag->ag_cors; - else - ag->ag_fine->ag_cors = ag->ag_cors; - - ag->ag_fine = ag_avail; - ag_avail = ag; - - CHECK_AG(); -} - - -/* Flush routes waiting for aggretation. - * This must not suppress a route unless it is known that among all - * routes with coarser masks that match it, the one with the longest - * mask is appropriate. This is ensured by scanning the routes - * in lexical order, and with the most restritive mask first - * among routes to the same destination. - */ -void -ag_flush(naddr lim_dst_h, /* flush routes to here */ - naddr lim_mask, /* matching this mask */ - void (*out)(struct ag_info *)) -{ - struct ag_info *ag, *ag_cors; - naddr dst_h; - - - for (ag = ag_finest; - ag != 0 && ag->ag_mask >= lim_mask; - ag = ag_cors) { - ag_cors = ag->ag_cors; - - /* work on only the specified routes */ - dst_h = ag->ag_dst_h; - if ((dst_h & lim_mask) != lim_dst_h) - continue; - - if (!(ag->ag_state & AGS_SUPPRESS)) - ag_out(ag, out); - - else for ( ; ; ag_cors = ag_cors->ag_cors) { - /* Look for a route that can suppress the - * current route */ - if (ag_cors == 0) { - /* failed, so output it and look for - * another route to work on - */ - ag_out(ag, out); - break; - } - - if ((dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h) { - /* We found a route with a coarser mask that - * aggregates the current target. - * - * If it has a different next hop, it - * cannot replace the target, so output - * the target. - */ - if (ag->ag_gate != ag_cors->ag_gate - && !(ag->ag_state & AGS_FINE_GATE) - && !(ag_cors->ag_state & AGS_CORS_GATE)) { - ag_out(ag, out); - break; - } - - /* If the coarse route has a good enough - * metric, it suppresses the target. - */ - if (ag_cors->ag_pref <= ag->ag_pref) { - if (ag_cors->ag_seqno > ag->ag_seqno) - ag_cors->ag_seqno = ag->ag_seqno; - if (AG_IS_REDUN(ag->ag_state) - && ag_cors->ag_mask==ag->ag_mask<<1) { - if (ag_cors->ag_dst_h == dst_h) - ag_cors->ag_state |= AGS_REDUN0; - else - ag_cors->ag_state |= AGS_REDUN1; - } - if (ag->ag_tag != ag_cors->ag_tag) - ag_cors->ag_tag = 0; - if (ag->ag_nhop != ag_cors->ag_nhop) - ag_cors->ag_nhop = 0; - break; - } - } - } - - /* That route has either been output or suppressed */ - ag_cors = ag->ag_cors; - ag_del(ag); - } - - CHECK_AG(); -} - - -/* Try to aggregate a route with previous routes. - */ -void -ag_check(naddr dst, - naddr mask, - naddr gate, - naddr nhop, - char metric, - char pref, - u_int seqno, - u_short tag, - u_short state, - void (*out)(struct ag_info *)) /* output using this */ -{ - struct ag_info *ag, *nag, *ag_cors; - naddr xaddr; - int x; - - NTOHL(dst); - - /* Punt non-contiguous subnet masks. - * - * (X & -X) contains a single bit if and only if X is a power of 2. - * (X + (X & -X)) == 0 if and only if X is a power of 2. - */ - if ((mask & -mask) + mask != 0) { - struct ag_info nc_ag; - - nc_ag.ag_dst_h = dst; - nc_ag.ag_mask = mask; - nc_ag.ag_gate = gate; - nc_ag.ag_nhop = nhop; - nc_ag.ag_metric = metric; - nc_ag.ag_pref = pref; - nc_ag.ag_tag = tag; - nc_ag.ag_state = state; - nc_ag.ag_seqno = seqno; - out(&nc_ag); - return; - } - - /* Search for the right slot in the aggregation table. - */ - ag_cors = 0; - ag = ag_corsest; - while (ag != 0) { - if (ag->ag_mask >= mask) - break; - - /* Suppress old routes (i.e. combine with compatible routes - * with coarser masks) as we look for the right slot in the - * aggregation table for the new route. - * A route to an address less than the current destination - * will not be affected by the current route or any route - * seen hereafter. That means it is safe to suppress it. - * This check keeps poor routes (eg. with large hop counts) - * from preventing suppresion of finer routes. - */ - if (ag_cors != 0 - && ag->ag_dst_h < dst - && (ag->ag_state & AGS_SUPPRESS) - && ag_cors->ag_pref <= ag->ag_pref - && (ag->ag_dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h - && (ag_cors->ag_gate == ag->ag_gate - || (ag->ag_state & AGS_FINE_GATE) - || (ag_cors->ag_state & AGS_CORS_GATE))) { - if (ag_cors->ag_seqno > ag->ag_seqno) - ag_cors->ag_seqno = ag->ag_seqno; - if (AG_IS_REDUN(ag->ag_state) - && ag_cors->ag_mask==ag->ag_mask<<1) { - if (ag_cors->ag_dst_h == dst) - ag_cors->ag_state |= AGS_REDUN0; - else - ag_cors->ag_state |= AGS_REDUN1; - } - if (ag->ag_tag != ag_cors->ag_tag) - ag_cors->ag_tag = 0; - if (ag->ag_nhop != ag_cors->ag_nhop) - ag_cors->ag_nhop = 0; - ag_del(ag); - CHECK_AG(); - } else { - ag_cors = ag; - } - ag = ag_cors->ag_fine; - } - - /* If we find the even/odd twin of the new route, and if the - * masks and so forth are equal, we can aggregate them. - * We can probably promote one of the pair. - * - * Since the routes are encountered in lexical order, - * the new route must be odd. However, the second or later - * times around this loop, it could be the even twin promoted - * from the even/odd pair of twins of the finer route. - */ - while (ag != 0 - && ag->ag_mask == mask - && ((ag->ag_dst_h ^ dst) & (mask<<1)) == 0) { - - /* Here we know the target route and the route in the current - * slot have the same netmasks and differ by at most the - * last bit. They are either for the same destination, or - * for an even/odd pair of destinations. - */ - if (ag->ag_dst_h == dst) { - /* We have two routes to the same destination. - * 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. - * - * Prefer the best route if their metrics differ, - * or the promoted one if not, following a sort - * of longest-match rule. - */ - if (pref <= ag->ag_pref) { - ag->ag_gate = gate; - ag->ag_nhop = nhop; - ag->ag_tag = tag; - ag->ag_metric = metric; - ag->ag_pref = pref; - x = ag->ag_state; - ag->ag_state = state; - state = x; - } - - /* The sequence number controls flash updating, - * and should be the smaller of the two. - */ - 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)); - return; - } - - /* If one of the routes can be promoted and the other can - * be suppressed, it may be possible to combine them or - * worthwhile to promote one. - * - * Note that any route that can be promoted is always - * marked to be eligible to be suppressed. - */ - if (!((state & AGS_PROMOTE) - && (ag->ag_state & AGS_SUPPRESS)) - && !((ag->ag_state & AGS_PROMOTE) - && (state & AGS_SUPPRESS))) - break; - - /* A pair of even/odd twin routes can be combined - * if either is redundant, or if they are via the - * same gateway and have the same metric. - */ - if (AG_IS_REDUN(ag->ag_state) - || AG_IS_REDUN(state) - || (ag->ag_gate == gate - && ag->ag_pref == pref - && (state & ag->ag_state & AGS_PROMOTE) != 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. - */ - if (seqno > ag->ag_seqno) - seqno = ag->ag_seqno; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN1; - if (AG_IS_REDUN(ag->ag_state)) - state |= AGS_REDUN0; - else - state &= ~AGS_REDUN0; - state |= (ag->ag_state & AGS_PROMOTE_EITHER); - if (ag->ag_tag != tag) - tag = 0; - if (ag->ag_nhop != nhop) - nhop = 0; - - /* Get rid of the even twin that was already - * in the slot. - */ - ag_del(ag); - - } else if (ag->ag_pref >= pref - && (ag->ag_state & AGS_PROMOTE)) { - /* If we cannot combine the pair, maybe the route - * with the worse metric can be promoted. - * - * Promote the old, even twin, by giving its slot - * in the table to the new, odd twin. - */ - ag->ag_dst_h = dst; - - xaddr = ag->ag_gate; - ag->ag_gate = gate; - gate = xaddr; - - xaddr = ag->ag_nhop; - ag->ag_nhop = nhop; - nhop = xaddr; - - x = ag->ag_tag; - ag->ag_tag = tag; - tag = x; - - x = ag->ag_state; - ag->ag_state = state; - state = x; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN0; - - x = ag->ag_metric; - ag->ag_metric = metric; - metric = x; - - x = ag->ag_pref; - ag->ag_pref = pref; - pref = x; - - if (seqno >= ag->ag_seqno) - seqno = ag->ag_seqno; - else - ag->ag_seqno = seqno; - - } else { - if (!(state & AGS_PROMOTE)) - break; /* cannot promote either twin */ - - /* promote the new, odd twin by shaving its - * mask and address. - */ - if (seqno > ag->ag_seqno) - seqno = ag->ag_seqno; - else - ag->ag_seqno = seqno; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN1; - } - - mask <<= 1; - dst &= mask; - - if (ag_cors == 0) { - ag = ag_corsest; - break; - } - ag = ag_cors; - ag_cors = ag->ag_cors; - } - - /* When we can no longer promote and combine routes, - * flush the old route in the target slot. Also flush - * any finer routes that we know will never be aggregated by - * the new route. - * - * In case we moved toward coarser masks, - * get back where we belong - */ - if (ag != 0 - && ag->ag_mask < mask) { - ag_cors = ag; - ag = ag->ag_fine; - } - - /* Empty the target slot - */ - if (ag != 0 && ag->ag_mask == mask) { - ag_flush(ag->ag_dst_h, ag->ag_mask, out); - ag = (ag_cors == 0) ? ag_corsest : ag_cors->ag_fine; - } - -#ifdef DEBUG_AG - (void)fflush(stderr); - if (ag == 0 && ag_cors != ag_finest) - abort(); - if (ag_cors == 0 && ag != ag_corsest) - abort(); - if (ag != 0 && ag->ag_cors != ag_cors) - abort(); - if (ag_cors != 0 && ag_cors->ag_fine != ag) - abort(); - CHECK_AG(); -#endif - - /* Save the new route on the end of the table. - */ - nag = ag_avail; - ag_avail = nag->ag_fine; - - nag->ag_dst_h = dst; - nag->ag_mask = mask; - nag->ag_gate = gate; - nag->ag_nhop = nhop; - nag->ag_metric = metric; - nag->ag_pref = pref; - nag->ag_tag = tag; - nag->ag_state = state; - nag->ag_seqno = seqno; - - nag->ag_fine = ag; - if (ag != 0) - ag->ag_cors = nag; - else - ag_finest = nag; - nag->ag_cors = ag_cors; - if (ag_cors == 0) - ag_corsest = nag; - else - ag_cors->ag_fine = nag; - CHECK_AG(); -} - - -static char * -rtm_type_name(u_char type) -{ - static char *rtm_types[] = { - "RTM_ADD", - "RTM_DELETE", - "RTM_CHANGE", - "RTM_GET", - "RTM_LOSING", - "RTM_REDIRECT", - "RTM_MISS", - "RTM_LOCK", - "RTM_OLDADD", - "RTM_OLDDEL", - "RTM_RESOLVE", - "RTM_NEWADDR", - "RTM_DELADDR", - "RTM_IFINFO" - }; - static char name0[10]; - - - if (type > sizeof(rtm_types)/sizeof(rtm_types[0]) - || type == 0) { - sprintf(name0, "RTM type %#x", type); - return name0; - } else { - return rtm_types[type-1]; - } -} - - -/* Trim a mask in a sockaddr - * Produce a length of 0 for an address of 0. - * Otherwise produce the index of the first zero byte. - */ -void -#ifdef _HAVE_SIN_LEN -masktrim(struct sockaddr_in *ap) -#else -masktrim(struct sockaddr_in_new *ap) -#endif -{ - register char *cp; - - if (ap->sin_addr.s_addr == 0) { - ap->sin_len = 0; - return; - } - cp = (char *)(&ap->sin_addr.s_addr+1); - while (*--cp == 0) - continue; - ap->sin_len = cp - (char*)ap + 1; -} - - -/* Tell the kernel to add, delete or change a route - */ -static void -rtioctl(int action, /* RTM_DELETE, etc */ - naddr dst, - naddr gate, - naddr mask, - int metric, - int flags) -{ - struct { - struct rt_msghdr w_rtm; - struct sockaddr_in w_dst; - struct sockaddr_in w_gate; -#ifdef _HAVE_SA_LEN - struct sockaddr_in w_mask; -#else - struct sockaddr_in_new w_mask; -#endif - } w; - long cc; - -again: - bzero(&w, sizeof(w)); - w.w_rtm.rtm_msglen = sizeof(w); - w.w_rtm.rtm_version = RTM_VERSION; - w.w_rtm.rtm_type = action; - 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) { - w.w_rtm.rtm_rmx.rmx_hopcount = metric; - w.w_rtm.rtm_inits |= RTV_HOPCOUNT; - } - w.w_dst.sin_family = AF_INET; - w.w_dst.sin_addr.s_addr = dst; - w.w_gate.sin_family = AF_INET; - w.w_gate.sin_addr.s_addr = gate; -#ifdef _HAVE_SA_LEN - w.w_dst.sin_len = sizeof(w.w_dst); - w.w_gate.sin_len = sizeof(w.w_gate); -#endif - if (mask == HOST_MASK) { - w.w_rtm.rtm_flags |= RTF_HOST; - w.w_rtm.rtm_msglen -= sizeof(w.w_mask); - } else { - w.w_rtm.rtm_addrs |= RTA_NETMASK; - w.w_mask.sin_addr.s_addr = htonl(mask); -#ifdef _HAVE_SA_LEN - masktrim(&w.w_mask); - if (w.w_mask.sin_len == 0) - w.w_mask.sin_len = sizeof(long); - w.w_rtm.rtm_msglen -= (sizeof(w.w_mask) - w.w_mask.sin_len); -#endif - } -#ifndef NO_INSTALL - cc = write(rt_sock, &w, w.w_rtm.rtm_msglen); - if (cc == w.w_rtm.rtm_msglen) - return; - if (cc < 0) { - if (errno == ESRCH - && (action == RTM_CHANGE || action == RTM_DELETE)) { - trace_act("route to %s disappeared before %s\n", - addrname(dst, mask, 0), - rtm_type_name(action)); - if (action == RTM_CHANGE) { - action = RTM_ADD; - goto again; - } - return; - } - msglog("write(rt_sock) %s %s --> %s: %s", - rtm_type_name(action), - addrname(dst, mask, 0), naddr_ntoa(gate), - strerror(errno)); - } else { - msglog("write(rt_sock) wrote %d instead of %d", - cc, w.w_rtm.rtm_msglen); - } -#endif -} - - -#define KHASH_SIZE 71 /* should be prime */ -#define KHASH(a,m) khash_bins[((a) ^ (m)) % KHASH_SIZE] -static struct khash { - struct khash *k_next; - naddr k_dst; - naddr k_mask; - naddr k_gate; - short k_metric; - u_short k_state; -#define KS_NEW 0x001 -#define KS_DELETE 0x002 -#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 */ - time_t k_keep; -#define K_KEEP_LIM 30 - time_t k_redirect_time; -} *khash_bins[KHASH_SIZE]; - - -static struct khash* -kern_find(naddr dst, naddr mask, struct khash ***ppk) -{ - struct khash *k, **pk; - - for (pk = &KHASH(dst,mask); (k = *pk) != 0; pk = &k->k_next) { - if (k->k_dst == dst && k->k_mask == mask) - break; - } - if (ppk != 0) - *ppk = pk; - return k; -} - - -static struct khash* -kern_add(naddr dst, naddr mask) -{ - struct khash *k, **pk; - - k = kern_find(dst, mask, &pk); - if (k != 0) - return k; - - k = (struct khash *)malloc(sizeof(*k)); - - bzero(k, sizeof(*k)); - k->k_dst = dst; - k->k_mask = mask; - k->k_state = KS_NEW; - k->k_keep = now.tv_sec; - *pk = k; - - return k; -} - - -/* If a kernel route has a non-zero metric, check that it is still in the - * daemon table, and not deleted by interfaces coming and going. - */ -static void -kern_check_static(struct khash *k, - struct interface *ifp) -{ - struct rt_entry *rt; - naddr int_addr; - - if (k->k_metric == 0) - return; - - int_addr = (ifp != 0) ? ifp->int_addr : loopaddr; - - 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); - } else { - rtadd(k->k_dst, k->k_mask, k->k_gate, int_addr, - k->k_metric, 0, RS_STATIC, ifp); - } -} - - -/* add a route the kernel told us - */ -static void -rtm_add(struct rt_msghdr *rtm, - struct rt_addrinfo *info, - time_t keep) -{ - struct khash *k; - struct interface *ifp; - naddr mask; - - - if (rtm->rtm_flags & RTF_HOST) { - mask = HOST_MASK; - } else if (INFO_MASK(info) != 0) { - mask = ntohl(S_ADDR(INFO_MASK(info))); - } else { - msglog("punt %s without mask", - rtm_type_name(rtm->rtm_type)); - return; - } - - if (INFO_GATE(info) == 0 - || INFO_GATE(info)->sa_family != AF_INET) { - msglog("punt %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 (rtm->rtm_flags & RTF_GATEWAY) - k->k_state |= KS_GATEWAY; - if (rtm->rtm_flags & RTF_STATIC) - k->k_state |= KS_STATIC; - if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { - if (supplier) { - /* Routers are not supposed to listen to redirects, - * so delete it. - */ - k->k_state &= ~KS_DYNAMIC; - k->k_state |= KS_DELETE; - trace_act("mark redirected %s --> %s for deletion" - " since this is a router\n", - addrname(k->k_dst, k->k_mask, 0), - naddr_ntoa(k->k_gate)); - } else { - k->k_state |= KS_DYNAMIC; - k->k_redirect_time = now.tv_sec; - } - } - - /* If it is not a static route, quit until the next comparison - * between the kernel and daemon tables, when it will be deleted. - */ - if (!(k->k_state & KS_STATIC)) { - k->k_state |= KS_DELETE; - LIM_SEC(need_kern, k->k_keep); - return; - } - - /* Put static routes with real metrics into the daemon table so - * they can be advertised. - * - * Find the interface concerned - */ - ifp = iflookup(k->k_gate); - if (ifp == 0) { - /* if there is no known interface, - * maybe there is a new interface - */ - ifinit(); - ifp = iflookup(k->k_gate); - if (ifp == 0) - msglog("static route %s --> %s impossibly lacks ifp", - addrname(S_ADDR(INFO_DST(info)), mask, 0), - naddr_ntoa(k->k_gate)); - } - - kern_check_static(k, ifp); -} - - -/* deal with packet loss - */ -static void -rtm_lose(struct rt_msghdr *rtm, - struct rt_addrinfo *info) -{ - if (INFO_GATE(info) == 0 - || INFO_GATE(info)->sa_family != AF_INET) { - msglog("punt %s without gateway", - rtm_type_name(rtm->rtm_type)); - return; - } - - if (!supplier) - rdisc_age(S_ADDR(INFO_GATE(info))); - - age(S_ADDR(INFO_GATE(info))); -} - - -/* Clean the kernel table by copying it to the daemon image. - * Eventually the daemon will delete any extra routes. - */ -void -flush_kern(void) -{ - size_t needed; - int mib[6]; - char *buf, *next, *lim; - struct rt_msghdr *rtm; - struct interface *ifp; - static struct sockaddr_in gate_sa; - struct rt_addrinfo info; - - - 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; - } - 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) { - rtm = (struct rt_msghdr *)next; - - rt_xaddrs(&info, - (struct sockaddr *)(rtm+1), - (struct sockaddr *)(next + rtm->rtm_msglen), - rtm->rtm_addrs); - - if (INFO_DST(&info) == 0 - || INFO_DST(&info)->sa_family != AF_INET) - continue; - - /* ignore ARP table entries on systems with a merged route - * and ARP table. - */ - 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); - 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; - - /* 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 - * unneeded changes. Keep the old kernel routes for a - * few seconds to allow a RIP or router-discovery - * response to be heard. - */ - rtm_add(rtm,&info,MIN_WAITTIME); - } - free(buf); -} - - -/* Listen to announcements from the kernel - */ -void -read_rt(void) -{ - long cc; - struct interface *ifp; - naddr mask; - union { - struct { - struct rt_msghdr rtm; - struct sockaddr addrs[RTAX_MAX]; - } r; - struct if_msghdr ifm; - } m; - char str[100], *strp; - struct rt_addrinfo info; - - - for (;;) { - cc = read(rt_sock, &m, sizeof(m)); - if (cc <= 0) { - if (cc < 0 && errno != EWOULDBLOCK) - LOGERR("read(rt_sock)"); - return; - } - - if (m.r.rtm.rtm_version != RTM_VERSION) { - msglog("bogus routing message version %d", - m.r.rtm.rtm_version); - continue; - } - - /* Ignore our own results. - */ - if (m.r.rtm.rtm_type <= RTM_CHANGE - && m.r.rtm.rtm_pid == mypid) { - static int complained = 0; - if (!complained) { - msglog("receiving our own change messages"); - complained = 1; - } - continue; - } - - if (m.r.rtm.rtm_type == RTM_IFINFO - || m.r.rtm.rtm_type == RTM_NEWADDR - || m.r.rtm.rtm_type == RTM_DELADDR) { - ifp = ifwithindex(m.ifm.ifm_index); - if (ifp == 0) - trace_act("note %s with flags %#x" - " for index #%d\n", - rtm_type_name(m.r.rtm.rtm_type), - m.ifm.ifm_flags, - m.ifm.ifm_index); - else - trace_act("note %s with flags %#x for %s\n", - rtm_type_name(m.r.rtm.rtm_type), - m.ifm.ifm_flags, - ifp->int_name); - - /* After being informed of a change to an interface, - * check them all now if the check would otherwise - * be a long time from now, if the interface is - * not known, or if the interface has been turned - * off or on. - */ - 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) - ifinit_timer.tv_sec = now.tv_sec; - continue; - } - - strcpy(str, rtm_type_name(m.r.rtm.rtm_type)); - strp = &str[strlen(str)]; - if (m.r.rtm.rtm_type <= RTM_CHANGE) - strp += sprintf(strp," from pid %d",m.r.rtm.rtm_pid); - - rt_xaddrs(&info, m.r.addrs, &m.r.addrs[RTAX_MAX], - m.r.rtm.rtm_addrs); - - if (INFO_DST(&info) == 0) { - trace_act("ignore %s without dst\n", str); - continue; - } - - if (INFO_DST(&info)->sa_family != AF_INET) { - trace_act("ignore %s for AF %d\n", str, - INFO_DST(&info)->sa_family); - continue; - } - - mask = ((INFO_MASK(&info) != 0) - ? ntohl(S_ADDR(INFO_MASK(&info))) - : (m.r.rtm.rtm_flags & RTF_HOST) - ? HOST_MASK - : std_mask(S_ADDR(INFO_DST(&info)))); - - strp += sprintf(strp, ": %s", - addrname(S_ADDR(INFO_DST(&info)), mask, 0)); - - if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) { - trace_act("ignore multicast %s\n", str); - continue; - } - - if (INFO_GATE(&info) != 0 - && INFO_GATE(&info)->sa_family == AF_INET) - strp += sprintf(strp, " --> %s", - saddr_ntoa(INFO_GATE(&info))); - - if (INFO_AUTHOR(&info) != 0) - strp += sprintf(strp, " by authority of %s", - saddr_ntoa(INFO_AUTHOR(&info))); - - switch (m.r.rtm.rtm_type) { - case RTM_ADD: - case RTM_CHANGE: - case RTM_REDIRECT: - if (m.r.rtm.rtm_errno != 0) { - trace_act("ignore %s with \"%s\" error\n", - str, strerror(m.r.rtm.rtm_errno)); - } else { - trace_act("%s\n", str); - rtm_add(&m.r.rtm,&info,0); - } - break; - - case RTM_DELETE: - if (m.r.rtm.rtm_errno != 0) { - trace_act("ignore %s with \"%s\" error\n", - str, strerror(m.r.rtm.rtm_errno)); - } else { - trace_act("%s\n", str); - del_static(S_ADDR(INFO_DST(&info)), mask, 1); - } - break; - - case RTM_LOSING: - trace_act("%s\n", str); - rtm_lose(&m.r.rtm,&info); - break; - - default: - trace_act("ignore %s\n", str); - break; - } - } -} - - -/* after aggregating, note routes that belong in the kernel - */ -static void -kern_out(struct ag_info *ag) -{ - struct khash *k; - - - /* Do not install bad routes if they are not already present. - * This includes routes that had RS_NET_SYN for interfaces that - * recently died. - */ - if (ag->ag_metric == HOPCNT_INFINITY) { - k = kern_find(htonl(ag->ag_dst_h), ag->ag_mask, 0); - if (k == 0) - return; - } else { - k = kern_add(htonl(ag->ag_dst_h), ag->ag_mask); - } - - if (k->k_state & KS_NEW) { - /* will need to add new entry to the kernel table */ - k->k_state = KS_ADD; - if (ag->ag_state & AGS_GATEWAY) - k->k_state |= KS_GATEWAY; - k->k_gate = ag->ag_gate; - k->k_metric = ag->ag_metric; - return; - } - - if (k->k_state & KS_STATIC) - return; - - /* modify existing kernel entry if necessary */ - if (k->k_gate != ag->ag_gate - || k->k_metric != ag->ag_metric) { - k->k_gate = ag->ag_gate; - k->k_metric = ag->ag_metric; - k->k_state |= KS_CHANGE; - } - - if (k->k_state & KS_DYNAMIC) { - k->k_state &= ~KS_DYNAMIC; - k->k_state |= (KS_ADD | KS_DEL_ADD); - } - - if ((k->k_state & KS_GATEWAY) - && !(ag->ag_state & AGS_GATEWAY)) { - k->k_state &= ~KS_GATEWAY; - k->k_state |= (KS_ADD | KS_DEL_ADD); - } else if (!(k->k_state & KS_GATEWAY) - && (ag->ag_state & AGS_GATEWAY)) { - k->k_state |= KS_GATEWAY; - k->k_state |= (KS_ADD | KS_DEL_ADD); - } - - /* Deleting-and-adding is necessary to change aspects of a route. - * Just delete instead of deleting and then adding a bad route. - * Otherwise, we want to keep the route in the kernel. - */ - if (k->k_metric == HOPCNT_INFINITY - && (k->k_state & KS_DEL_ADD)) - k->k_state |= KS_DELETE; - else - k->k_state &= ~KS_DELETE; -#undef RT -} - - -/* ARGSUSED */ -static int -walk_kern(struct radix_node *rn, - struct walkarg *w) -{ -#define RT ((struct rt_entry *)rn) - char metric, pref; - u_int ags = 0; - - - /* Do not install synthetic routes */ - if (RT->rt_state & RS_NET_SYN) - return 0; - - if (!(RT->rt_state & RS_IF)) { - ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE); - - } else { - /* 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; - - /* If it is not an interface, or an alias for an interface, - * it must be a "gateway." - * - * If it is a "remote" interface, it is also a "gateway" to - * the kernel if is not a alias. - */ - if (RT->rt_ifp == 0 - || ((RT->rt_ifp->int_state & IS_REMOTE) - && RT->rt_ifp->int_metric == 0)) - ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE); - } - - if (RT->rt_state & RS_RDISC) - 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); - } - - ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0, - metric,pref, 0, 0, ags, kern_out); - return 0; -#undef RT -} - - -/* Update the kernel table to match the daemon table. - */ -static void -fix_kern(void) -{ - int i, flags; - struct khash *k, **pk; - - - need_kern = age_timer; - - /* Walk daemon table, updating the copy of the kernel table. - */ - (void)rn_walktree(rhead, walk_kern, 0); - ag_flush(0,0,kern_out); - - for (i = 0; i < KHASH_SIZE; i++) { - for (pk = &khash_bins[i]; (k = *pk) != 0; ) { - /* Do not touch static routes */ - if (k->k_state & KS_STATIC) { - kern_check_static(k,0); - pk = &k->k_next; - continue; - } - - /* check hold on routes deleted by the operator */ - if (k->k_keep > now.tv_sec) { - LIM_SEC(need_kern, k->k_keep); - k->k_state |= KS_DELETE; - pk = &k->k_next; - continue; - } - - if ((k->k_state & (KS_DELETE | KS_DYNAMIC)) - == KS_DELETE) { - if (!(k->k_state & KS_DELETED)) - rtioctl(RTM_DELETE, - k->k_dst, k->k_gate, k->k_mask, - 0, 0); - *pk = k->k_next; - free(k); - continue; - } - - if (0 != (k->k_state&(KS_ADD|KS_CHANGE|KS_DEL_ADD))) { - if (k->k_state & KS_DEL_ADD) { - rtioctl(RTM_DELETE, - k->k_dst,k->k_gate,k->k_mask, - 0, 0); - k->k_state &= ~KS_DYNAMIC; - } - - flags = 0; - if (0 != (k->k_state&(KS_GATEWAY|KS_DYNAMIC))) - flags |= RTF_GATEWAY; - - if (k->k_state & KS_ADD) { - rtioctl(RTM_ADD, - k->k_dst, k->k_gate, k->k_mask, - k->k_metric, flags); - } else if (k->k_state & KS_CHANGE) { - rtioctl(RTM_CHANGE, - k->k_dst,k->k_gate,k->k_mask, - k->k_metric, flags); - } - k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); - } - - /* Mark this route to be deleted in the next cycle. - * This deletes routes that disappear from the - * daemon table, since the normal aging code - * will clear the bit for routes that have not - * disappeared from the daemon table. - */ - k->k_state |= KS_DELETE; - pk = &k->k_next; - } - } -} - - -/* Delete a static route in the image of the kernel table. - */ -void -del_static(naddr dst, - naddr mask, - int gone) -{ - struct khash *k; - struct rt_entry *rt; - - /* Just mark it in the table to be deleted next time the kernel - * table is updated. - * If it has already been deleted, mark it as such, and set its - * keep-timer so that it will not be deleted again for a while. - * This lets the operator delete a route added by the daemon - * and add a replacement. - */ - k = kern_find(dst, mask, 0); - if (k != 0) { - k->k_state &= ~(KS_STATIC | KS_DYNAMIC); - k->k_state |= KS_DELETE; - if (gone) { - k->k_state |= KS_DELETED; - k->k_keep = now.tv_sec + K_KEEP_LIM; - } - } - - rt = rtget(dst, mask); - if (rt != 0 && (rt->rt_state & RS_STATIC)) - rtbad(rt); -} - - -/* Delete all routes generated from ICMP Redirects that use a given gateway, - * as well as old redirected routes. - */ -void -del_redirects(naddr bad_gate, - time_t old) -{ - int i; - struct khash *k; - - - for (i = 0; i < KHASH_SIZE; i++) { - for (k = khash_bins[i]; k != 0; k = k->k_next) { - if (!(k->k_state & KS_DYNAMIC) - || (k->k_state & KS_STATIC)) - continue; - - if (k->k_gate != bad_gate - && k->k_redirect_time > old - && !supplier) - continue; - - k->k_state |= KS_DELETE; - k->k_state &= ~KS_DYNAMIC; - need_kern.tv_sec = now.tv_sec; - trace_act("mark redirected %s --> %s for deletion\n", - addrname(k->k_dst, k->k_mask, 0), - naddr_ntoa(k->k_gate)); - } - } -} - - -/* Start the daemon tables. - */ -void -rtinit(void) -{ - extern int max_keylen; - int i; - struct ag_info *ag; - - /* Initialize the radix trees */ - max_keylen = sizeof(struct sockaddr_in); - rn_init(); - rn_inithead((void**)&rhead, 32); - - /* mark all of the slots in the table free */ - ag_avail = ag_slots; - for (ag = ag_slots, i = 1; i < NUM_AG_SLOTS; i++) { - ag->ag_fine = ag+1; - ag++; - } -} - - -#ifdef _HAVE_SIN_LEN -static struct sockaddr_in dst_sock = {sizeof(dst_sock), AF_INET}; -static struct sockaddr_in mask_sock = {sizeof(mask_sock), AF_INET}; -#else -static struct sockaddr_in_new dst_sock = {_SIN_ADDR_SIZE, AF_INET}; -static struct sockaddr_in_new mask_sock = {_SIN_ADDR_SIZE, AF_INET}; -#endif - - -void -set_need_flash(void) -{ - if (!need_flash) { - need_flash = 1; - /* Do not send the flash update immediately. Wait a little - * while to hear from other routers. - */ - no_flash.tv_sec = now.tv_sec + MIN_WAITTIME; - } -} - - -/* Get a particular routing table entry - */ -struct rt_entry * -rtget(naddr dst, naddr mask) -{ - struct rt_entry *rt; - - dst_sock.sin_addr.s_addr = dst; - mask_sock.sin_addr.s_addr = mask; - masktrim(&mask_sock); - rt = (struct rt_entry *)rhead->rnh_lookup(&dst_sock,&mask_sock,rhead); - if (!rt - || rt->rt_dst != dst - || rt->rt_mask != mask) - return 0; - - return rt; -} - - -/* Find a route to dst as the kernel would. - */ -struct rt_entry * -rtfind(naddr dst) -{ - dst_sock.sin_addr.s_addr = dst; - return (struct rt_entry *)rhead->rnh_matchaddr(&dst_sock, rhead); -} - - -/* add a route to the table - */ -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) -{ - struct rt_entry *rt; - naddr smask; - int i; - struct rt_spare *rts; - - rt = (struct rt_entry *)rtmalloc(sizeof (*rt), "rtadd"); - bzero(rt, sizeof(*rt)); - for (rts = rt->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) - rts->rts_metric = HOPCNT_INFINITY; - - rt->rt_nodes->rn_key = (caddr_t)&rt->rt_dst_sock; - rt->rt_dst = dst; - rt->rt_dst_sock.sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - rt->rt_dst_sock.sin_len = dst_sock.sin_len; -#endif - if (mask != HOST_MASK) { - smask = std_mask(dst); - if ((smask & ~mask) == 0 && mask > smask) - state |= RS_SUBNET; - } - mask_sock.sin_addr.s_addr = mask; - masktrim(&mask_sock); - rt->rt_mask = mask; - rt->rt_state = state; - rt->rt_gate = gate; - rt->rt_router = router; - 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) - msglog("have maximum (%d) routes", total_routes); - if (TRACEACTIONS) - trace_add_del("Add", rt); - - need_kern.tv_sec = now.tv_sec; - set_need_flash(); - - if (0 == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock, - rhead, rt->rt_nodes)) { -/* - * This will happen if RIP1 and RIP2 routeds talk to one another and - * there are variable subnets. This is only good for filling up your - * syslog. -jkh - */ -#if 0 - msglog("rnh_addaddr() failed for %s mask=%#x", - naddr_ntoa(dst), mask); -#endif - } -} - - -/* notice a changed route - */ -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, - char *label) -{ - if (rt->rt_metric != 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) - need_kern.tv_sec = now.tv_sec; - rt->rt_seqno = update_seqno; - set_need_flash(); - } - - if (rt->rt_gate != gate) { - need_kern.tv_sec = now.tv_sec; - rt->rt_seqno = update_seqno; - set_need_flash(); - } - - state |= (rt->rt_state & RS_SUBNET); - - if (TRACEACTIONS) - trace_change(rt, state, gate, router, metric, tag, ifp, - new_time, - 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; -} - - -/* check for a better route among the spares - */ -static struct rt_spare * -rts_better(struct rt_entry *rt) -{ - struct rt_spare *rts, *rts1; - int i; - - /* find the best alternative among the spares */ - rts = rt->rt_spares+1; - for (i = NUM_SPARES, rts1 = rts+1; i > 2; i--, rts1++) { - if (BETTER_LINK(rt,rts1,rts)) - rts = rts1; - } - - return rts; -} - - -/* switch to a backup route - */ -void -rtswitch(struct rt_entry *rt, - struct rt_spare *rts) -{ - struct rt_spare swap; - char label[10]; - - - /* Do not change permanent routes */ - if (0 != (rt->rt_state & RS_PERMANENT)) - return; - - /* Do not discard synthetic routes until they go bad */ - if ((rt->rt_state & RS_NET_SYN) - && rt->rt_metric < HOPCNT_INFINITY) - return; - - /* find the best alternative among the spares */ - if (rts == 0) - rts = rts_better(rt); - - /* Do not bother if it is not worthwhile. - */ - if (!BETTER_LINK(rt, rts, rt->rt_spares)) - return; - - swap = rt->rt_spares[0]; - (void)sprintf(label, "Use #%d", 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); - *rts = swap; -} - - -void -rtdelete(struct rt_entry *rt) -{ - struct khash *k; - - - if (TRACEACTIONS) - trace_add_del("Del", rt); - - k = kern_find(rt->rt_dst, rt->rt_mask, 0); - if (k != 0) { - k->k_state |= KS_DELETE; - need_kern.tv_sec = now.tv_sec; - } - - dst_sock.sin_addr.s_addr = rt->rt_dst; - mask_sock.sin_addr.s_addr = rt->rt_mask; - masktrim(&mask_sock); - if (rt != (struct rt_entry *)rhead->rnh_deladdr(&dst_sock, &mask_sock, - rhead)) { - msglog("rnh_deladdr() failed"); - } else { - free(rt); - total_routes--; - } -} - - -/* Get rid of a bad route, and try to switch to a replacement. - */ -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); - - rtswitch(rt, 0); -} - - -/* Junk a RS_NET_SYN or RS_LOCAL route, - * unless it is needed by another interface. - */ -void -rtbad_sub(struct rt_entry *rt) -{ - struct interface *ifp, *ifp1; - struct intnet *intnetp; - u_int state; - - - ifp1 = 0; - state = 0; - - if (rt->rt_state & RS_LOCAL) { - /* Is this the route through loopback for the interface? - * If so, see if it is used by any other interfaces, such - * as a point-to-point interface with the same local address. - */ - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - /* Retain it if another interface needs it. - */ - if (ifp->int_addr == rt->rt_ifp->int_addr) { - state |= RS_LOCAL; - ifp1 = ifp; - break; - } - } - - } - - if (!(state & RS_LOCAL)) { - /* Retain RIPv1 logical network route if there is another - * interface that justifies it. - */ - if (rt->rt_state & RS_NET_SYN) { - for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { - if ((ifp->int_state & IS_NEED_NET_SYN) - && rt->rt_mask == ifp->int_std_mask - && rt->rt_dst == ifp->int_std_addr) { - state |= RS_NET_SYN; - ifp1 = ifp; - break; - } - } - } - - /* or if there is an authority route that needs it. */ - for (intnetp = intnets; - intnetp != 0; - intnetp = intnetp->intnet_next) { - if (intnetp->intnet_addr == rt->rt_dst - && intnetp->intnet_mask == rt->rt_mask) { - state |= (RS_NET_SYN | RS_NET_INT); - break; - } - } - } - - 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); - } else { - rtbad(rt); - } -} - - -/* Called while walking the table looking for sick interfaces - * or after a time change. - */ -/* ARGSUSED */ -int -walk_bad(struct radix_node *rn, - struct walkarg *w) -{ -#define RT ((struct rt_entry *)rn) - struct rt_spare *rts; - int i; - time_t new_time; - - - /* fix any spare routes through the interface - */ - rts = RT->rt_spares; - for (i = NUM_SPARES; i != 1; i--) { - rts++; - - if (rts->rts_ifp != 0 - && (rts->rts_ifp->int_state & IS_BROKE)) { - new_time = rts->rts_time; - if (new_time >= now_garbage) - new_time = now_garbage-1; - trace_upslot(RT, rts, rts->rts_gate, - rts->rts_router, 0, - HOPCNT_INFINITY, rts->rts_tag, - new_time); - rts->rts_ifp = 0; - rts->rts_metric = HOPCNT_INFINITY; - rts->rts_time = new_time; - } - } - - /* Deal with the main route - */ - /* finished if it has been handled before or if its interface is ok - */ - if (RT->rt_ifp == 0 || !(RT->rt_ifp->int_state & IS_BROKE)) - return 0; - - /* Bad routes for other than interfaces are easy. - */ - if (0 == (RT->rt_state & (RS_IF | RS_NET_SYN | RS_LOCAL))) { - rtbad(RT); - return 0; - } - - rtbad_sub(RT); - return 0; -#undef RT -} - - -/* Check the age of an individual route. - */ -/* ARGSUSED */ -static int -walk_age(struct radix_node *rn, - struct walkarg *w) -{ -#define RT ((struct rt_entry *)rn) - struct interface *ifp; - struct rt_spare *rts; - int i; - - - /* age all of the spare routes, including the primary route - * currently in use - */ - rts = RT->rt_spares; - for (i = NUM_SPARES; i != 0; i--, rts++) { - - ifp = rts->rts_ifp; - if (i == NUM_SPARES) { - if (!AGE_RT(RT, ifp)) { - /* Keep various things from deciding ageless - * routes are stale */ - rts->rts_time = now.tv_sec; - continue; - } - - /* forget RIP routes after RIP has been turned off. - */ - if (rip_sock < 0) { - rtdelete(RT); - return 0; - } - } - - /* age failing routes - */ - if (age_bad_gate == rts->rts_gate - && rts->rts_time >= now_stale) { - rts->rts_time -= SUPPLY_INTERVAL; - } - - /* trash the spare routes when they go bad */ - if (rts->rts_metric < HOPCNT_INFINITY - && now_garbage > rts->rts_time) { - trace_upslot(RT, rts, rts->rts_gate, - rts->rts_router, rts->rts_ifp, - HOPCNT_INFINITY, rts->rts_tag, - rts->rts_time); - rts->rts_metric = HOPCNT_INFINITY; - } - } - - - /* finished if the active route is still fresh */ - if (now_stale <= RT->rt_time) - return 0; - - /* try to switch to an alternative */ - rtswitch(RT, 0); - - /* Delete a dead route after it has been publically mourned. */ - if (now_garbage > RT->rt_time) { - rtdelete(RT); - return 0; - } - - /* 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); - return 0; -} - - -/* Watch for dead routes and interfaces. - */ -void -age(naddr bad_gate) -{ - struct interface *ifp; - - - age_timer.tv_sec = now.tv_sec + (rip_sock < 0 - ? NEVER - : SUPPLY_INTERVAL); - - for (ifp = ifnet; ifp; ifp = ifp->int_next) { - /* Check for dead IS_REMOTE interfaces by timing their - * transmissions. - */ - if ((ifp->int_state & IS_REMOTE) - && !(ifp->int_state & IS_PASSIVE) - && (ifp->int_state & IS_ACTIVE)) { - LIM_SEC(age_timer, now.tv_sec+SUPPLY_INTERVAL); - - if (now.tv_sec - ifp->int_act_time > EXPIRE_TIME - && !(ifp->int_state & IS_BROKE)) { - msglog("remote interface %s to %s timed out" - "--turned off", - ifp->int_name, - naddr_ntoa(ifp->int_addr)); - if_bad(ifp); - } - } - } - - /* Age routes. */ - age_bad_gate = bad_gate; - (void)rn_walktree(rhead, walk_age, 0); - - /* Update the kernel routing table. */ - fix_kern(); -} diff --git a/usr.sbin/routed/trace.c b/usr.sbin/routed/trace.c deleted file mode 100644 index f38b393abb88..000000000000 --- a/usr.sbin/routed/trace.c +++ /dev/null @@ -1,800 +0,0 @@ -/* - * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.1.3.3 $" - -#define RIPCMDS -#include "defs.h" -#include "pathnames.h" -#include -#include -#include - - -#ifdef sgi -/* use *stat64 for files on large filesystems */ -#define stat stat64 -#endif - -#define NRECORDS 50 /* size of circular trace buffer */ - -u_int tracelevel, new_tracelevel; -FILE *ftrace = stdout; /* output trace file */ -static char *tracelevel_pat = "%s\n"; - -char savetracename[MAXPATHLEN+1]; - - -/* convert IP address to a string, but not into a single buffer - */ -char * -naddr_ntoa(naddr a) -{ -#define NUM_BUFS 4 - static int bufno; - static struct { - char str[16]; /* xxx.xxx.xxx.xxx\0 */ - } bufs[NUM_BUFS]; - char *s; - struct in_addr addr; - - addr.s_addr = a; - s = strcpy(bufs[bufno].str, inet_ntoa(addr)); - bufno = (bufno+1) % NUM_BUFS; - return s; -#undef NUM_BUFS -} - - -char * -saddr_ntoa(struct sockaddr *sa) -{ - return (sa == 0) ? "?" : naddr_ntoa(S_ADDR(sa)); -} - - -static char * -ts(time_t secs) { - static char s[20]; - - secs += epoch.tv_sec; -#ifdef sgi - (void)cftime(s, "%T", &secs); -#else - bcopy(ctime(&secs)+11, s, 8); - s[8] = '\0'; -#endif - return s; -} - - -/* On each event, display a time stamp. - * This assumes that 'now' is update once for each event, and - * that at least now.tv_usec changes. - */ -void -lastlog(void) -{ - static struct timeval last; - - if (last.tv_sec != now.tv_sec - || last.tv_usec != now.tv_usec) { - (void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec)); - last = now; - } -} - - -static void -tmsg(char *p, ...) -{ - va_list args; - - if (ftrace != 0) { - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - fflush(ftrace); - } -} - - -static void -trace_close(void) -{ - int fd; - - - fflush(stdout); - fflush(stderr); - - if (ftrace != 0 - && savetracename[0] != '\0') { - fd = open(_PATH_DEVNULL, O_RDWR); - (void)dup2(fd, STDOUT_FILENO); - (void)dup2(fd, STDERR_FILENO); - (void)close(fd); - fclose(ftrace); - ftrace = 0; - } -} - - -void -trace_flush(void) -{ - if (ftrace != 0) { - fflush(ftrace); - if (ferror(ftrace)) - trace_off("tracing off: ", strerror(ferror(ftrace))); - } -} - - -void -trace_off(char *p, ...) -{ - va_list args; - - - if (ftrace != 0) { - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - fflush(ftrace); - } - trace_close(); - - new_tracelevel = tracelevel = 0; -} - - -void -trace_on(char *filename, - int trusted) -{ - struct stat stbuf; - FILE *n_ftrace; - - - /* Given a null filename when tracing is already on, increase the - * debugging level and re-open the file in case it has been unlinked. - */ - if (filename[0] == '\0') { - if (tracelevel != 0) { - new_tracelevel++; - tracelevel_pat = "trace command: %s\n"; - } else if (savetracename[0] == '\0') { - msglog("missing trace file name"); - return; - } - filename = savetracename; - - } else if (stat(filename, &stbuf) >= 0) { - if (!trusted) { - msglog("trace file \"%s\" already exists"); - return; - } - if ((stbuf.st_mode & S_IFMT) != S_IFREG) { - msglog("wrong type (%#x) of trace file \"%s\"", - stbuf.st_mode, filename); - return; - } - - if (!trusted - && strcmp(filename, savetracename) - && strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) { - msglog("wrong directory for trace file: \"%s\"", - filename); - return; - } - } - - n_ftrace = fopen(filename, "a"); - if (n_ftrace == 0) { - msglog("failed to open trace file \"%s\" %s", - filename, strerror(errno)); - return; - } - - tmsg("switch to trace file %s\n", filename); - trace_close(); - if (filename != savetracename) - strncpy(savetracename, filename, sizeof(savetracename)-1); - ftrace = n_ftrace; - - fflush(stdout); - fflush(stderr); - dup2(fileno(ftrace), STDOUT_FILENO); - dup2(fileno(ftrace), STDERR_FILENO); - - if (new_tracelevel == 0) - new_tracelevel = 1; - set_tracelevel(); -} - - -/* ARGSUSED */ -void -sigtrace_on(int s) -{ - new_tracelevel++; - tracelevel_pat = "SIGUSR1: %s\n"; -} - - -/* ARGSUSED */ -void -sigtrace_off(int s) -{ - new_tracelevel--; - tracelevel_pat = "SIGUSR2: %s\n"; -} - - -/* Move to next higher level of tracing when -t option processed or - * SIGUSR1 is received. Successive levels are: - * actions - * actions + packets - * actions + packets + contents - */ -void -set_tracelevel(void) -{ - static char *off_msgs[MAX_TRACELEVEL] = { - "Tracing actions stopped", - "Tracing packets stopped", - "Tracing packet contents stopped", - }; - static char *on_msgs[MAX_TRACELEVEL] = { - "Tracing actions started", - "Tracing packets started", - "Tracing packet contents started", - }; - - - if (new_tracelevel > MAX_TRACELEVEL) { - new_tracelevel = MAX_TRACELEVEL; - if (new_tracelevel == tracelevel) { - tmsg(tracelevel_pat, on_msgs[tracelevel-1]); - return; - } - } - while (new_tracelevel != tracelevel) { - if (new_tracelevel < tracelevel) { - if (--tracelevel == 0) - trace_off(tracelevel_pat, off_msgs[0]); - else - tmsg(tracelevel_pat, off_msgs[tracelevel]); - } else { - if (ftrace == 0) { - if (savetracename[0] != '\0') - trace_on(savetracename, 1); - else - ftrace = stdout; - } - tmsg(tracelevel_pat, on_msgs[tracelevel++]); - } - } - tracelevel_pat = "%s\n"; -} - - -/* display an address - */ -char * -addrname(naddr addr, /* in network byte order */ - naddr mask, - int force) /* 0=show mask if nonstandard, */ -{ /* 1=always show mask, 2=never */ -#define NUM_BUFS 4 - static int bufno; - static struct { - char str[15+20]; - } bufs[NUM_BUFS]; - char *s, *sp; - naddr dmask; - int i; - - s = strcpy(bufs[bufno].str, naddr_ntoa(addr)); - bufno = (bufno+1) % NUM_BUFS; - - if (force == 1 || (force == 0 && mask != std_mask(addr))) { - sp = &s[strlen(s)]; - - dmask = mask & -mask; - if (mask + dmask == 0) { - for (i = 0; i != 32 && ((1<bits_mask) != 0) { - if ((b & field) == b) { - if (tbl->bits_name[0] != '\0') { - if (c) - (void)putc(c, ftrace); - (void)fprintf(ftrace, "%s", tbl->bits_name); - c = '|'; - } - if (0 == (field &= ~(b | tbl->bits_clear))) - break; - } - tbl++; - } - if (field != 0 && tbl->bits_name != 0) { - if (c) - (void)putc(c, ftrace); - (void)fprintf(ftrace, tbl->bits_name, field); - c = '|'; - } - - if (c != '<' || force) - (void)fputs("> ", ftrace); -} - - -static char * -trace_pair(naddr dst, - naddr mask, - char *gate) -{ - static char buf[3*4+3+1+2+3 /* "xxx.xxx.xxx.xxx/xx-->" */ - +3*4+3+1]; /* "xxx.xxx.xxx.xxx" */ - int i; - - i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0)); - (void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), gate); - return buf; -} - - -void -trace_if(char *act, - struct interface *ifp) -{ - if (!TRACEACTIONS || ftrace == 0) - return; - - lastlog(); - (void)fprintf(ftrace, "%s interface %-4s ", act, ifp->int_name); - (void)fprintf(ftrace, "%-15s-->%-15s ", - naddr_ntoa(ifp->int_addr), - addrname(htonl((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_net), - ifp->int_mask, 1)); - if (ifp->int_metric != 0) - (void)fprintf(ftrace, "metric=%d ", ifp->int_metric); - trace_bits(if_bits, ifp->int_if_flags, 0); - trace_bits(is_bits, ifp->int_state, 0); - (void)fputc('\n',ftrace); -} - - -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) -{ - if (!TRACEACTIONS || ftrace == 0) - return; - if (rts->rts_gate == gate - && rts->rts_router == router - && rts->rts_metric == metric - && rts->rts_tag == tag) - return; - - lastlog(); - if (rts->rts_gate != RIP_DEFAULT) { - (void)fprintf(ftrace, "Chg #%d %-35s ", - rts - rt->rt_spares, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(rts->rts_gate))); - if (rts->rts_gate != rts->rts_gate) - (void)fprintf(ftrace, "router=%s ", - naddr_ntoa(rts->rts_gate)); - if (rts->rts_tag != 0) - (void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag)); - (void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric); - if (rts->rts_ifp != 0) - (void)fprintf(ftrace, "%s ", - rts->rts_ifp->int_name); - (void)fprintf(ftrace, "%s\n", ts(rts->rts_time)); - - (void)fprintf(ftrace, " %19s%-16s ", - "", - gate != rts->rts_gate ? naddr_ntoa(gate) : ""); - if (gate != router) - (void)fprintf(ftrace,"router=%s ",naddr_ntoa(router)); - if (tag != rts->rts_tag) - (void)fprintf(ftrace, "tag=%#x ", ntohs(tag)); - if (metric != rts->rts_metric) - (void)fprintf(ftrace, "metric=%-2d ", metric); - if (ifp != rts->rts_ifp && ifp != 0 ) - (void)fprintf(ftrace, "%s ", ifp->int_name); - (void)fprintf(ftrace, "%s\n", - new_time != rts->rts_time ? ts(new_time) : ""); - - } else { - (void)fprintf(ftrace, "Add #%d %-35s ", - rts - rt->rt_spares, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(gate))); - if (gate != router) - (void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate)); - if (tag != 0) - (void)fprintf(ftrace, "tag=%#x ", ntohs(tag)); - (void)fprintf(ftrace, "metric=%-2d ", metric); - if (ifp != 0) - (void)fprintf(ftrace, "%s ", ifp->int_name); - (void)fprintf(ftrace, "%s\n", ts(new_time)); - } -} - - -/* display a message if tracing actions - */ -void -trace_act(char *p, ...) -{ - va_list args; - - if (!TRACEACTIONS || ftrace == 0) - return; - - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); -} - - -/* display a message if tracing packets - */ -void -trace_pkt(char *p, ...) -{ - va_list args; - - if (!TRACEPACKETS || ftrace == 0) - return; - - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); -} - - -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, - char *label) -{ - if (ftrace == 0) - return; - - if (rt->rt_metric == metric - && rt->rt_gate == gate - && rt->rt_router == router - && rt->rt_state == state - && rt->rt_tag == tag) - return; - - lastlog(); - (void)fprintf(ftrace, "%s %-35s metric=%-2d ", - label, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(rt->rt_gate)), - rt->rt_metric); - if (rt->rt_router != rt->rt_gate) - (void)fprintf(ftrace, "router=%s ", - naddr_ntoa(rt->rt_router)); - if (rt->rt_tag != 0) - (void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag)); - trace_bits(rs_bits, rt->rt_state, rt->rt_state != state); - (void)fprintf(ftrace, "%s ", - rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name); - (void)fprintf(ftrace, "%s\n", - AGE_RT(rt, rt->rt_ifp) ? ts(rt->rt_time) : ""); - - (void)fprintf(ftrace, "%*s %19s%-16s ", - strlen(label), "", "", - rt->rt_gate != gate ? naddr_ntoa(gate) : ""); - if (rt->rt_metric != metric) - (void)fprintf(ftrace, "metric=%-2d ", metric); - if (router != gate) - (void)fprintf(ftrace, "router=%s ", naddr_ntoa(router)); - if (rt->rt_tag != tag) - (void)fprintf(ftrace, "tag=%#x ", ntohs(tag)); - if (rt->rt_state != state) - trace_bits(rs_bits, state, 1); - if (rt->rt_ifp != ifp) - (void)fprintf(ftrace, "%s ", - ifp != 0 ? ifp->int_name : "?"); - (void)fprintf(ftrace, "%s\n", - ((rt->rt_time == new_time || !AGE_RT(rt, ifp)) - ? "" : ts(new_time))); -} - - -void -trace_add_del(char * action, struct rt_entry *rt) -{ - u_int state = rt->rt_state; - - if (ftrace == 0) - return; - - lastlog(); - (void)fprintf(ftrace, "%s %-35s metric=%-2d ", - action, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(rt->rt_gate)), - rt->rt_metric); - if (rt->rt_router != rt->rt_gate) - (void)fprintf(ftrace, "router=%s ", - naddr_ntoa(rt->rt_router)); - if (rt->rt_tag != 0) - (void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag)); - trace_bits(rs_bits, state, 0); - (void)fprintf(ftrace, "%s ", - rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?"); - (void)fprintf(ftrace, "%s\n", ts(rt->rt_time)); -} - - -void -trace_rip(char *dir1, char *dir2, - struct sockaddr_in *who, - struct interface *ifp, - struct rip *msg, - int size) /* total size of message */ -{ - struct netinfo *n, *lim; - struct netauth *a; - int i; - - if (!TRACEPACKETS || ftrace == 0) - return; - - lastlog(); - if (msg->rip_cmd >= RIPCMD_MAX - || msg->rip_vers == 0) { - (void)fprintf(ftrace, "%s bad RIPv%d cmd=%d %s" - " %s.%d size=%d\n", - dir1, msg->rip_vers, msg->rip_cmd, dir2, - naddr_ntoa(who->sin_addr.s_addr), - ntohs(who->sin_port), - size); - return; - } - - (void)fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n", - dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2, - naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port), - ifp ? " via " : "", ifp ? ifp->int_name : ""); - if (!TRACECONTENTS) - return; - - switch (msg->rip_cmd) { - case RIPCMD_REQUEST: - case RIPCMD_RESPONSE: - n = msg->rip_nets; - lim = (struct netinfo *)((char*)msg + size); - for (; n < lim; n++) { - if (n->n_family == RIP_AF_UNSPEC - && ntohl(n->n_metric) == HOPCNT_INFINITY - && n+1 == lim - && n == msg->rip_nets - && msg->rip_cmd == RIPCMD_REQUEST) { - (void)fputs("\tQUERY ", ftrace); - if (n->n_dst != 0) - (void)fprintf(ftrace, "%s ", - naddr_ntoa(n->n_dst)); - if (n->n_mask != 0) - (void)fprintf(ftrace, "mask=%#x ", - (u_int)ntohl(n->n_mask)); - if (n->n_nhop != 0) - (void)fprintf(ftrace, " nhop=%s ", - naddr_ntoa(n->n_nhop)); - if (n->n_tag != 0) - (void)fprintf(ftrace, "tag=%#x", - ntohs(n->n_tag)); - (void)fputc('\n',ftrace); - continue; - } - - if (n->n_family == RIP_AF_AUTH) { - a = (struct netauth*)n; - (void)fprintf(ftrace, - "\tAuthentication type %d: ", - ntohs(a->a_type)); - for (i = 0; - i < sizeof(a->au.au_pw); - i++) - (void)fprintf(ftrace, "%02x ", - a->au.au_pw[i]); - (void)fputc('\n',ftrace); - continue; - } - - if (n->n_family != RIP_AF_INET) { - (void)fprintf(ftrace, - "\t(af %d) %-18s mask=%#x", - ntohs(n->n_family), - naddr_ntoa(n->n_dst), - (u_int)ntohl(n->n_mask)); - } else if (msg->rip_vers == RIPv1) { - (void)fprintf(ftrace, "\t%-18s ", - addrname(n->n_dst, - ntohl(n->n_mask), - n->n_mask==0 ? 2 : 1)); - } else { - (void)fprintf(ftrace, "\t%-18s ", - addrname(n->n_dst, - ntohl(n->n_mask), - n->n_mask==0 ? 2 : 0)); - } - (void)fprintf(ftrace, "metric=%-2d ", - (u_int)ntohl(n->n_metric)); - if (n->n_nhop != 0) - (void)fprintf(ftrace, " nhop=%s ", - naddr_ntoa(n->n_nhop)); - if (n->n_tag != 0) - (void)fprintf(ftrace, "tag=%#x", - ntohs(n->n_tag)); - (void)fputc('\n',ftrace); - } - if (size != (char *)n - (char *)msg) - (void)fprintf(ftrace, "truncated record, len %d\n", - size); - break; - - case RIPCMD_TRACEON: - fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile); - break; - - case RIPCMD_TRACEOFF: - break; - } -}