diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -51,6 +51,18 @@ # xargs -n1 | sort | uniq -d; # done +# 20251030: Remove RIP and RIPng. +OLD_FILES+=sbin/routed +OLD_FILES+=sbin/rtquery +OLD_FILES+=usr/sbin/route6d +OLD_FILES+=usr/sbin/rip6query +OLD_FILES+=etc/rc.d/routed +OLD_FILES+=etc/rc.d/route6d +OLD_FILES+=usr/share/man/man8/rip6query.8.gz +OLD_FILES+=usr/share/man/man8/route6d.8.gz +OLD_FILES+=usr/share/man/man8/routed.8.gz +OLD_FILES+=usr/share/man/man8/rtquery.8.gz + # 20251028: Remove hifn(4) OLD_FILES+=share/man/man4/hifn.4 diff --git a/UPDATING b/UPDATING --- a/UPDATING +++ b/UPDATING @@ -27,6 +27,15 @@ world, or to merely disable the most expensive debugging functionality at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20251030: + The deprecated RIP routing daemons routed(8) and route6d(8), and their + associated utilities and rc.d scripts, have been removed. Users who + require route(6)d may use the net/freebsd-routed port instead, or + consider switching to another RIP implementation such as net/bird3 + or net/frr10. + + pkgbase users should remove the now-orphaned FreeBSD-rip package. + 20251025: flua(1) has moved to the new FreeBSD-flua package. If you use flua, you may want to install this package if it's not otherwise installed diff --git a/libexec/rc/netstart b/libexec/rc/netstart --- a/libexec/rc/netstart +++ b/libexec/rc/netstart @@ -44,8 +44,6 @@ /etc/rc.d/ppp ${_start} /etc/rc.d/ipfw ${_start} /etc/rc.d/routing ${_start} -/etc/rc.d/route6d ${_start} -/etc/rc.d/routed ${_start} /etc/rc.d/rtsold ${_start} /etc/rc.d/nisdomain ${_start} diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf --- a/libexec/rc/rc.conf +++ b/libexec/rc/rc.conf @@ -457,9 +457,6 @@ static_ndp_pairs="" # Set to static NDP list (or leave empty). static_routes="" # Set to static route list (or leave empty). gateway_enable="NO" # Set to YES if this host will be a gateway. -routed_enable="NO" # Set to YES to enable a routing daemon. -routed_program="/sbin/routed" # Name of routing daemon to use if enabled. -routed_flags="-q" # Flags for routing daemon. arpproxy_all="NO" # replaces obsolete kernel option ARP_PROXYALL. forward_sourceroute="NO" # do source routing (only if gateway_enable is set to "YES") accept_sourceroute="NO" # accept source routed packets to us @@ -530,13 +527,6 @@ ipv6_privacy="NO" # Use privacy address on RA-receiving IFs # (RFC 4941) -route6d_enable="NO" # Set to YES to enable an IPv6 routing daemon. -route6d_program="/usr/sbin/route6d" # Name of IPv6 routing daemon. -route6d_flags="" # Flags to IPv6 routing daemon. -#route6d_flags="-l" # Example for route6d with only IPv6 site local - # addrs. -#route6d_flags="-q" # If you want to run a routing daemon on an end - # node, you should stop advertisement. #ipv6_network_interfaces="em0 em1" # Examples for router # or static configuration for end node. # Choose correct prefix value. diff --git a/libexec/rc/rc.d/Makefile b/libexec/rc/rc.d/Makefile --- a/libexec/rc/rc.d/Makefile +++ b/libexec/rc/rc.d/Makefile @@ -364,18 +364,6 @@ tlsservd .endif -.if ${MK_INET6} != "no" || ${MK_ROUTED} != "no" -CONFGROUPS+= RIP -RIPPACKAGE= rip - -.if ${MK_INET6} != "no" -RIP+= route6d -.endif -.if ${MK_ROUTED} != "no" -RIP+= routed -.endif -.endif - .for fg in ${CONFGROUPS} ${CONFGROUPS.yes} ${fg}MODE?= ${BINMODE} ${fg}PACKAGE?= rc diff --git a/libexec/rc/rc.d/NETWORKING b/libexec/rc/rc.d/NETWORKING --- a/libexec/rc/rc.d/NETWORKING +++ b/libexec/rc/rc.d/NETWORKING @@ -4,7 +4,7 @@ # PROVIDE: NETWORKING NETWORK # REQUIRE: netif netwait netoptions routing ppp ipfw stf -# REQUIRE: defaultroute route6d resolv bridge +# REQUIRE: defaultroute resolv bridge # REQUIRE: static_arp static_ndp # This is a dummy dependency, for services which require networking diff --git a/libexec/rc/rc.d/route6d b/libexec/rc/rc.d/route6d deleted file mode 100755 --- a/libexec/rc/rc.d/route6d +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# -# - -# PROVIDE: route6d -# REQUIRE: netif routing -# KEYWORD: nojailvnet - -. /etc/rc.subr - -name="route6d" -desc="RIP6 routing daemon" -rcvar="route6d_enable" - -: ${route6d_svcj_options:="net_basic"} - -set_rcvar_obsolete ipv6_router_enable route6d_enable -set_rcvar_obsolete ipv6_router route6d_program -set_rcvar_obsolete ipv6_router_flags route6d_flags - -load_rc_config $name -run_rc_command "$1" diff --git a/libexec/rc/rc.d/routed b/libexec/rc/rc.d/routed deleted file mode 100755 --- a/libexec/rc/rc.d/routed +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -# -# - -# PROVIDE: routed dynamicrouting -# REQUIRE: netif routing -# BEFORE: NETWORKING -# KEYWORD: nojailvnet - -. /etc/rc.subr - -name="routed" -desc="Network RIP and router discovery routing daemon" -rcvar="routed_enable" - -: ${routed_svcj_options:="net_basic"} - -set_rcvar_obsolete router_enable routed_enable -set_rcvar_obsolete router routed_program -set_rcvar_obsolete router_flags routed_flags - -load_rc_config $name -run_rc_command "$1" diff --git a/release/packages/ucl/rip-all.ucl b/release/packages/ucl/rip-all.ucl deleted file mode 100644 --- a/release/packages/ucl/rip-all.ucl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-License-Identifier: ISC - * - * Copyright (c) 2025 Lexi Winter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -comment = "RIP routing protocol" - -desc = < diff --git a/sbin/routed/Makefile.depend b/sbin/routed/Makefile.depend deleted file mode 100644 --- a/sbin/routed/Makefile.depend +++ /dev/null @@ -1,18 +0,0 @@ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/arpa \ - include/protocols \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libmd \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/sbin/routed/Makefile.inc b/sbin/routed/Makefile.inc deleted file mode 100644 --- a/sbin/routed/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -PACKAGE= rip - -.include "../Makefile.inc" diff --git a/sbin/routed/defs.h b/sbin/routed/defs.h deleted file mode 100644 --- a/sbin/routed/defs.h +++ /dev/null @@ -1,602 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - - -/* 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 vestigial 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "radix.h" -#define UNUSED __attribute__((unused)) -#define PATTRIB(f,l) __attribute__((format (printf,f,l))) -#include -#include -#include -#include -#include -#define RIPVERSION RIPv2 -#include - -#ifndef __COPYRIGHT -#define __COPYRIGHT(_s) static const char copyright[] UNUSED = _s -#endif - -/* 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. - */ -#define naddr u_long -#define _HAVE_SA_LEN -#define _HAVE_SIN_LEN - -#define DAY (24*60*60) -#define NEVER DAY /* a long time */ -#define EPOCH NEVER /* bias time by this to avoid <0 */ - -/* Scan the kernel regularly to see if any interfaces have appeared or been - * 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))) - -/* Metric used for fake default routes. It ought to be 15, but when - * processing advertised routes, previous versions of `routed` added - * to the received metric and discarded the route if the total was 16 - * or larger. - */ -#define FAKE_METRIC (HOPCNT_INFINITY-2) - - -/* Router Discovery parameters */ -#define INADDR_ALLROUTERS_GROUP 0xe0000002 /* 224.0.0.2 */ -#define MaxMaxAdvertiseInterval 1800 -#define MinMaxAdvertiseInterval 4 -#define DefMaxAdvertiseInterval 600 -#define MIN_PreferenceLevel 0x80000000 - -#define MAX_INITIAL_ADVERT_INTERVAL 16 -#define MAX_INITIAL_ADVERTS 3 - -#define MAX_SOLICITATION_DELAY 1 -#define SOLICITATION_INTERVAL 3 -#define MAX_SOLICITATIONS 3 - - -/* Bloated packet size for systems that simply add authentication to - * full-sized packets - */ -#define OVER_MAXPACKETSIZE (MAXPACKETSIZE+sizeof(struct netinfo)*2) -/* typical packet buffers */ -union pkt_buf { - char packet[OVER_MAXPACKETSIZE*2]; - struct rip rip; -}; - -#define GNAME_LEN 64 /* assumed=64 in parms.c */ -/* bigger than IFNAMSIZ, with room for "external()" or "remote()" */ -#define IF_NAME_LEN (GNAME_LEN+15) - -/* No more routes than this, to protect ourself in case something goes - * whacko and starts broadcasting zillions of bogus routes. - */ -#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 */ - 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 */ - u_int rts_de_ag; /* de-aggregation level */ -#define NUM_SPARES 4 - } rt_spares[NUM_SPARES]; - u_int rt_seqno; /* when last changed */ - char rt_poison_metric; /* to notice maximum recently */ - time_t rt_poison_time; /* advertised metric */ -}; -#define rt_dst rt_dst_sock.sin_addr.s_addr -#define rt_ifp rt_spares[0].rts_ifp -#define rt_gate rt_spares[0].rts_gate -#define rt_router rt_spares[0].rts_router -#define rt_metric rt_spares[0].rts_metric -#define rt_tag rt_spares[0].rts_tag -#define rt_time rt_spares[0].rts_time -#define rt_de_ag rt_spares[0].rts_de_ag - -#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_state,ifp) (0 == ((rt_state) & (RS_MHOME | RS_STATIC \ - | RS_NET_SYN | RS_RDISC)) \ - && (!((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 { - LIST_ENTRY(interface) int_list; - LIST_ENTRY(interface) remote_list; - struct interface *int_ahash, **int_ahash_prev; - struct interface *int_bhash, **int_bhash_prev; - struct interface *int_nhash, **int_nhash_prev; - char int_name[IF_NAME_LEN+1]; - u_short int_index; - naddr int_addr; /* address on this host (net order) */ - naddr int_brdaddr; /* broadcast address (n) */ - 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; /* some bits copied from kernel */ - u_int int_state; - time_t int_act_time; /* last thought healthy */ - time_t int_query_time; - u_short int_transitions; /* times gone up-down */ - char int_metric; - u_char int_d_metric; /* for faked default route */ - u_char int_adj_inmetric; /* adjust advertised metrics */ - u_char int_adj_outmetric; /* instead of interface metric */ - struct int_data { - u_int ipackets; /* previous network stats */ - u_int ierrors; - u_int opackets; - u_int oerrors; - time_t ts; /* timestamp on network stats */ - } int_data; -# define MAX_AUTH_KEYS 5 - struct auth { /* authentication info */ - u_int16_t type; - u_char key[RIP_AUTH_PW_LEN]; - u_char keyid; - time_t start, end; - } int_auth[MAX_AUTH_KEYS]; - /* router discovery parameters */ - int int_rdisc_pref; /* signed preference to advertise */ - int int_rdisc_int; /* MaxAdvertiseInterval */ - int int_rdisc_cnt; - struct timeval int_rdisc_timer; -}; - -/* bits in int_state */ -#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_DISTRUST 0x0000100 /* ignore untrusted routers */ -#define IS_REDIRECT_OK 0x0000200 /* accept ICMP redirects */ -#define IS_BROKE 0x0000400 /* seems to be broken */ -#define IS_SICK 0x0000800 /* seems to be broken */ -#define IS_DUP 0x0001000 /* has a duplicate address */ -#define IS_NEED_NET_SYN 0x0002000 /* need RS_NET_SYN route */ -#define IS_NO_AG 0x0004000 /* do not aggregate subnets */ -#define IS_NO_SUPER_AG 0x0008000 /* do not aggregate networks */ -#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_RIP_MCAST 0x0100000 /* broadcast RIPv2 */ -#define IS_NO_ADV_IN 0x0200000 /* do not listen to advertisements */ -#define IS_NO_SOL_OUT 0x0400000 /* send no solicitations */ -#define IS_SOL_OUT 0x0800000 /* send solicitations */ -#define GROUP_IS_SOL_OUT (IS_SOL_OUT | IS_NO_SOL_OUT) -#define IS_NO_ADV_OUT 0x1000000 /* do not advertise rdisc */ -#define IS_ADV_OUT 0x2000000 /* advertise rdisc */ -#define GROUP_IS_ADV_OUT (IS_NO_ADV_OUT | IS_ADV_OUT) -#define IS_BCAST_RDISC 0x4000000 /* broadcast instead of multicast */ -#define IS_NO_RDISC (IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT) -#define IS_PM_RDISC 0x8000000 /* poor-man's router discovery */ - -#define iff_up(f) ((f) & IFF_UP) - -LIST_HEAD(ifhead, interface); - -/* 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 coarser mask */ -#define AGS_AGGREGATE 0x002 /* synthesize combined routes */ -#define AGS_REDUN0 0x004 /* redundant, finer routes output */ -#define AGS_REDUN1 0x008 -#define AG_IS_REDUN(state) (((state) & (AGS_REDUN0 | AGS_REDUN1)) \ - == (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 netmasks */ -#define AGS_SPLIT_HZ 0x200 /* suppress for split horizon */ - - /* some bits are set if they are set on either route */ -#define AGS_AGGREGATE_EITHER (AGS_RIPV2 | AGS_GATEWAY | \ - AGS_SUPPRESS | AGS_CORS_GATE) -}; - - -/* parameters for interfaces */ -struct parm { - struct parm *parm_next; - char parm_name[IF_NAME_LEN+1]; - naddr parm_net; - naddr parm_mask; - - u_char parm_d_metric; - u_char parm_adj_inmetric; - char parm_adj_outmetric; - u_int parm_int_state; - int parm_rdisc_pref; /* signed IRDP preference */ - int parm_rdisc_int; /* IRDP advertising interval */ - struct auth parm_auth[MAX_AUTH_KEYS]; -}; - -/* authority for internal networks */ -extern struct intnet { - struct intnet *intnet_next; - naddr intnet_addr; /* network byte order */ - naddr intnet_mask; - char intnet_metric; -} *intnets; - -/* defined RIPv1 netmasks */ -extern struct r1net { - struct r1net *r1net_next; - naddr r1net_net; /* host order */ - naddr r1net_match; - naddr r1net_mask; -} *r1nets; - -/* trusted routers */ -extern struct tgate { - struct tgate *tgate_next; - naddr tgate_addr; -#define MAX_TGATE_NETS 32 - struct tgate_net { - naddr net; /* host order */ - naddr mask; - } tgate_nets[MAX_TGATE_NETS]; -} *tgates; - -enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST, - NO_OUT_MULTICAST, NO_OUT_RIPV2}; - -/* common output buffers */ -extern struct ws_buf { - struct rip *buf; - struct netinfo *n; - struct netinfo *base; - struct netinfo *lim; - enum output_type type; -} v12buf; - -extern pid_t mypid; -extern naddr myaddr; /* main address of this system */ - -extern int stopint; /* !=0 to stop */ - -extern int rip_sock; /* RIP socket */ -extern const 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 supplier; /* process should supply updates */ -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 advertising it */ -extern int auth_ok; /* 1=ignore auth if we do not care */ -extern int insecure; /* Reply to special queries or not */ - -extern struct timeval clk; /* system clock's idea of time */ -extern struct timeval epoch; /* system clock when started */ -extern struct timeval now; /* current idea of time */ -extern time_t now_stale; -extern time_t now_expire; -extern time_t now_garbage; - -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 ifhead ifnet; /* all interfaces */ -extern struct ifhead remote_if; /* remote interfaces */ -extern int have_ripv1_out; /* have a RIPv1 interface */ -extern int need_flash; /* flash update needed */ -extern struct timeval need_kern; /* need to update kernel table */ -extern u_int update_seqno; /* a route has changed */ - -extern int tracelevel, new_tracelevel; -#define MAX_TRACELEVEL 4 -#define TRACEKERNEL (tracelevel >= 4) /* log kernel changes */ -#define TRACECONTENTS (tracelevel >= 3) /* display packet contents */ -#define TRACEPACKETS (tracelevel >= 2) /* note packets */ -#define TRACEACTIONS (tracelevel != 0) -extern FILE *ftrace; /* output trace file */ -extern char inittracename[PATH_MAX]; - -extern struct radix_node_head *rhead; - - - -void fix_sock(int, const char *); -void fix_select(void); -void rip_off(void); -void rip_on(struct interface *); - -void bufinit(void); -int output(enum output_type, struct sockaddr_in *, - struct interface *, struct rip *, int); -void clr_ws_buf(struct ws_buf *, struct auth *); -void rip_query(void); -void rip_bcast(int); -void supply(struct sockaddr_in *, struct interface *, - enum output_type, int, int, int); - -void msglog(const char *, ...) PATTRIB(1,2); -struct msg_limit { - time_t reuse; - struct msg_sub { - naddr addr; - time_t until; -# define MSG_SUBJECT_N 8 - } subs[MSG_SUBJECT_N]; -}; -void msglim(struct msg_limit *, naddr, - const char *, ...) PATTRIB(3,4); -#define LOGERR(msg) msglog(msg ": %s", strerror(errno)) -void logbad(int, const char *, ...) PATTRIB(2,3); -#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 -char *naddr_ntoa(naddr); -const char *saddr_ntoa(struct sockaddr *); - -void *rtmalloc(size_t, const char *); -void timevaladd(struct timeval *, struct timeval *); -void intvl_random(struct timeval *, u_long, u_long); -int getnet(char *, naddr *, naddr *); -int gethost(char *, naddr *); -void gwkludge(void); -const char *parse_parms(char *, int); -const char *check_parms(struct parm *); -void get_parms(struct interface *); - -void lastlog(void); -void trace_close(int); -void set_tracefile(const char *, const char *, int); -void tracelevel_msg(const char *, int); -void trace_off(const char*, ...) PATTRIB(1,2); -void set_tracelevel(void); -void trace_flush(void); -void trace_misc(const char *, ...) PATTRIB(1,2); -void trace_act(const char *, ...) PATTRIB(1,2); -void trace_pkt(const char *, ...) PATTRIB(1,2); -void trace_add_del(const char *, struct rt_entry *); -void trace_change(struct rt_entry *, u_int, struct rt_spare *, - const char *); -void trace_if(const char *, struct interface *); -void trace_upslot(struct rt_entry *, struct rt_spare *, - struct rt_spare *); -void trace_rip(const char*, const char*, struct sockaddr_in *, - struct interface *, struct rip *, int); -char *addrname(naddr, naddr, int); -char *rtname(naddr, naddr, naddr); - -void rdisc_age(naddr); -void set_rdisc_mg(struct interface *, int); -void set_supplier(void); -void if_bad_rdisc(struct interface *); -void if_ok_rdisc(struct interface *); -void read_rip(int, struct interface *); -void read_rt(void); -void read_d(void); -void rdisc_adv(void); -void rdisc_sol(void); - -void sigtrace_on(int); -void sigtrace_off(int); - -void flush_kern(void); -void age(naddr); - -void ag_flush(naddr, naddr, void (*)(struct ag_info *)); -void ag_check(naddr, naddr, naddr, naddr, char, char, u_int, - u_short, u_short, void (*)(struct ag_info *)); -void del_static(naddr, naddr, naddr, int); -void del_redirects(naddr, time_t); -struct rt_entry *rtget(naddr, naddr); -struct rt_entry *rtfind(naddr); -void rtinit(void); -void rtadd(naddr, naddr, u_int, struct rt_spare *); -void rtchange(struct rt_entry *, u_int, struct rt_spare *, char *); -void rtdelete(struct rt_entry *); -void rts_delete(struct rt_entry *, struct rt_spare *); -void rtbad_sub(struct rt_entry *); -void rtswitch(struct rt_entry *, struct rt_spare *); - -#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_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); - -naddr std_mask(naddr); -naddr ripv1_mask_net(naddr, struct interface *); -naddr ripv1_mask_host(naddr,struct interface *); -#define on_net(a,net,mask) (((ntohl(a) ^ (net)) & (mask)) == 0) -int check_dst(naddr); -struct interface *check_dup(naddr, naddr, naddr, int); -int check_remote(struct interface *); -void ifinit(void); -int walk_bad(struct radix_node *, struct walkarg *); -int if_ok(struct interface *, const char *); -void if_sick(struct interface *); -void if_link(struct interface *); -struct interface *ifwithaddr(naddr addr, int bcast, int remote); -struct interface *ifwithindex(u_short, int); -struct interface *iflookup(naddr); - -struct auth *find_auth(struct interface *); -void end_md5_auth(struct ws_buf *, struct auth *); - -#include diff --git a/sbin/routed/if.c b/sbin/routed/if.c deleted file mode 100644 --- a/sbin/routed/if.c +++ /dev/null @@ -1,1362 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include - -#include "defs.h" -#include "pathnames.h" -struct ifhead ifnet = LIST_HEAD_INITIALIZER(ifnet); /* all interfaces */ -struct ifhead remote_if = LIST_HEAD_INITIALIZER(remote_if); /* remote interfaces */ - -/* hash table for all interfaces, big enough to tolerate ridiculous - * numbers of IP aliases. Crazy numbers of aliases such as 7000 - * still will not do well, but not just in looking up interfaces - * by name or address. - */ -#define AHASH_LEN 211 /* must be prime */ -#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN] -static struct interface *ahash_tbl[AHASH_LEN]; - -#define BHASH_LEN 211 /* must be prime */ -#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN] -static struct interface *bhash_tbl[BHASH_LEN]; - - -/* hash for physical interface names. - * Assume there are never more 100 or 200 real interfaces, and that - * aliases are put on the end of the hash chains. - */ -#define NHASH_LEN 97 -static struct interface *nhash_tbl[NHASH_LEN]; - -int tot_interfaces; /* # of remote and local interfaces */ -int rip_interfaces; /* # of interfaces doing RIP */ -static int foundloopback; /* valid flag for loopaddr */ -naddr loopaddr; /* our address on loopback */ -static struct rt_spare loop_rts; - -struct timeval ifinit_timer; -static struct timeval last_ifinit; -#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ - && last_ifinit.tv_usec == now.tv_usec \ - && timercmp(&ifinit_timer, &now, >)) - -int have_ripv1_out; /* have a RIPv1 interface */ -static int have_ripv1_in; - - -static void if_bad(struct interface *); -static int addrouteforif(struct interface *); - -static struct interface** -nhash(char *p) -{ - u_int i; - - for (i = 0; *p != '\0'; p++) { - i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); - i ^= *p; - } - return &nhash_tbl[i % NHASH_LEN]; -} - - -/* Link a new interface into the lists and hash tables. - */ -void -if_link(struct interface *ifp) -{ - struct interface **hifp; - - LIST_INSERT_HEAD(&ifnet, ifp, int_list); - - hifp = AHASH(ifp->int_addr); - ifp->int_ahash_prev = hifp; - if ((ifp->int_ahash = *hifp) != NULL) - (*hifp)->int_ahash_prev = &ifp->int_ahash; - *hifp = ifp; - - if (ifp->int_if_flags & IFF_BROADCAST) { - hifp = BHASH(ifp->int_brdaddr); - ifp->int_bhash_prev = hifp; - if ((ifp->int_bhash = *hifp) != NULL) - (*hifp)->int_bhash_prev = &ifp->int_bhash; - *hifp = ifp; - } - - if (ifp->int_state & IS_REMOTE) - LIST_INSERT_HEAD(&remote_if, ifp, remote_list); - - hifp = nhash(ifp->int_name); - if (ifp->int_state & IS_ALIAS) { - /* put aliases on the end of the hash chain */ - while (*hifp != NULL) - hifp = &(*hifp)->int_nhash; - } - ifp->int_nhash_prev = hifp; - if ((ifp->int_nhash = *hifp) != NULL) - (*hifp)->int_nhash_prev = &ifp->int_nhash; - *hifp = ifp; -} - - -/* 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 = NULL; - - remote = (remote == 0) ? IS_REMOTE : 0; - - for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { - if (ifp->int_addr != addr) - continue; - if ((ifp->int_state & remote) != 0) - continue; - if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) - return ifp; - possible = ifp; - } - - if (possible || !bcast) - return possible; - - for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { - if (ifp->int_brdaddr != addr) - continue; - if ((ifp->int_state & remote) != 0) - continue; - if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) - return ifp; - possible = ifp; - } - - return possible; -} - - -/* find the interface with a name - */ -static struct interface * -ifwithname(char *name, /* "ec0" or whatever */ - naddr addr) /* 0 or network address */ -{ - struct interface *ifp; - - for (;;) { - for (ifp = *nhash(name); ifp != NULL; ifp = ifp->int_nhash) { - /* If the network address is not specified, - * ignore any alias interfaces. Otherwise, look - * for the interface with the target name and address. - */ - if (!strcmp(ifp->int_name, name) - && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) - || (ifp->int_addr == addr))) - return ifp; - } - - /* If there is no known interface, maybe there is a - * new interface. So just once look for new interfaces. - */ - if (IF_RESCAN_DELAY()) - return 0; - ifinit(); - } -} - - -struct interface * -ifwithindex(u_short ifindex, - int rescan_ok) -{ - struct interface *ifp; - - for (;;) { - LIST_FOREACH(ifp, &ifnet, int_list) { - if (ifp->int_index == ifindex) - return ifp; - } - - /* If there is no known interface, maybe there is a - * new interface. So just once look for new interfaces. - */ - if (!rescan_ok - || IF_RESCAN_DELAY()) - return 0; - ifinit(); - } -} - - -/* Find an interface from which the specified address - * should have come from. Used for figuring out which - * interface a packet came in on. - */ -struct interface * -iflookup(naddr addr) -{ - struct interface *ifp, *maybe; - int once = 0; - - maybe = NULL; - for (;;) { - LIST_FOREACH(ifp, &ifnet, int_list) { - if (ifp->int_if_flags & IFF_POINTOPOINT) { - /* finished with a match */ - if (ifp->int_dstaddr == addr) - return ifp; - - } else { - /* finished with an exact match */ - if (ifp->int_addr == addr) - return ifp; - - /* Look for the longest approximate match. - */ - if (on_net(addr, ifp->int_net, ifp->int_mask) - && (maybe == NULL - || ifp->int_mask > maybe->int_mask)) - maybe = ifp; - } - } - - if (maybe != NULL || once || IF_RESCAN_DELAY()) - return maybe; - once = 1; - - /* If there is no known interface, maybe there is a - * new interface. So just once look for new interfaces. - */ - ifinit(); - } -} - - -/* Return the classical netmask for an IP address. - */ -naddr /* host byte order */ -std_mask(naddr addr) /* network byte order */ -{ - addr = 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 */ -{ - struct r1net *r1p; - naddr mask = 0; - - if (addr == 0) /* default always has 0 mask */ - return mask; - - if (ifp != NULL && ifp->int_ripv1_mask != HOST_MASK) { - /* If the target network is that of the associated interface - * on which it arrived, then use the netmask of the interface. - */ - 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. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) - && ifp->int_ripv1_mask > mask - && ifp->int_ripv1_mask != HOST_MASK) - mask = ifp->int_ripv1_mask; - } - - } - - /* check special definitions */ - if (mask == 0) { - for (r1p = r1nets; r1p != NULL; r1p = r1p->r1net_next) { - if (on_net(addr, r1p->r1net_net, r1p->r1net_match) - && r1p->r1net_mask > mask) - mask = r1p->r1net_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 an IP address looks reasonable as a destination. - */ -int /* 0=bad */ -check_dst(naddr addr) -{ - 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)); -} - - -/* See a new interface duplicates an existing interface. - */ -struct interface * -check_dup(naddr addr, /* IP address, so network byte order */ - naddr dstaddr, /* ditto */ - naddr mask, /* mask, so host byte order */ - int if_flags) -{ - struct interface *ifp; - - LIST_FOREACH(ifp, &ifnet, int_list) { - if (ifp->int_mask != mask) - continue; - - if (!iff_up(ifp->int_if_flags)) - continue; - - /* The local address can only be shared with a point-to-point - * link. - */ - if ((!(ifp->int_state & IS_REMOTE) || !(if_flags & IS_REMOTE)) - && ifp->int_addr == addr - && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) - return ifp; - - if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) - return ifp; - } - return 0; -} - - -/* See that a remote gateway is reachable. - * Note that the answer can change as real interfaces come and go. - */ -int /* 0=bad */ -check_remote(struct interface *ifp) -{ - struct rt_entry *rt; - - /* do not worry about other kinds */ - if (!(ifp->int_state & IS_REMOTE)) - return 1; - - rt = rtfind(ifp->int_addr); - if (rt != NULL - && rt->rt_ifp != 0 - &&on_net(ifp->int_addr, - rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) - return 1; - - /* the gateway cannot be reached directly from one of our - * interfaces - */ - if (!(ifp->int_state & IS_BROKE)) { - msglog("unreachable gateway %s in "_PATH_GATEWAYS, - naddr_ntoa(ifp->int_addr)); - if_bad(ifp); - } - return 0; -} - - -/* Delete an interface. - */ -static void -ifdel(struct interface *ifp) -{ - struct interface *ifp1; - - - trace_if("Del", ifp); - - ifp->int_state |= IS_BROKE; - - LIST_REMOVE(ifp, int_list); - *ifp->int_ahash_prev = ifp->int_ahash; - if (ifp->int_ahash != 0) - ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; - *ifp->int_nhash_prev = ifp->int_nhash; - if (ifp->int_nhash != 0) - ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev; - if (ifp->int_if_flags & IFF_BROADCAST) { - *ifp->int_bhash_prev = ifp->int_bhash; - if (ifp->int_bhash != 0) - ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; - } - if (ifp->int_state & IS_REMOTE) - LIST_REMOVE(ifp, remote_list); - - if (!(ifp->int_state & IS_ALIAS)) { - /* delete aliases when the main interface dies - */ - LIST_FOREACH(ifp1, &ifnet, int_list) { - if (ifp1 != ifp - && !strcmp(ifp->int_name, ifp1->int_name)) - ifdel(ifp1); - } - - if ((ifp->int_if_flags & IFF_MULTICAST) && rip_sock >= 0) { - struct group_req gr; - struct sockaddr_in *sin; - - memset(&gr, 0, sizeof(gr)); - gr.gr_interface = ifp->int_index; - sin = (struct sockaddr_in *)&gr.gr_group; - sin->sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - if (setsockopt(rip_sock, IPPROTO_IP, MCAST_LEAVE_GROUP, - &gr, sizeof(gr)) < 0 - && errno != EADDRNOTAVAIL - && !TRACEACTIONS) - LOGERR("setsockopt(MCAST_LEAVE_GROUP RIP)"); - if (rip_sock_mcast == ifp) - rip_sock_mcast = NULL; - } - 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; - ifp->int_act_time = NEVER; - trace_if("Chg", ifp); - - LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); - } -} - - -/* Mark an interface dead. - */ -static 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_act_time = NEVER; - ifp->int_query_time = NEVER; - ifp->int_data.ts = now.tv_sec; - - trace_if("Chg", ifp); - - if (!(ifp->int_state & IS_ALIAS)) { - LIST_FOREACH(ifp1, &ifnet, int_list) { - 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, - const 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", - type, - ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); - ifp->int_state &= ~IS_SICK; - } - return 0; - } - - msglog("%sinterface %s to %s restored", - type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); - ifp->int_state &= ~(IS_BROKE | IS_SICK); - ifp->int_data.ts = 0; - - if (!(ifp->int_state & IS_ALIAS)) { - LIST_FOREACH(ifp1, &ifnet, int_list) { - if (ifp1 != ifp - && !strcmp(ifp->int_name, ifp1->int_name)) - if_ok(ifp1, type); - } - if_ok_rdisc(ifp); - } - - if (ifp->int_state & IS_REMOTE) { - if (!addrouteforif(ifp)) - return 0; - } - 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 - - memset(info, 0, sizeof(*info)); - info->rti_addrs = addrs; - for (i = 0; i < RTAX_MAX && sa < lim; i++) { - if ((addrs & (1 << i)) == 0) - continue; - info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; - sa = (struct sockaddr *)((char*)(sa) + SA_SIZE(sa)); - } -} - - -/* 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 struct ifa_msghdr *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_NOADDR 0x002 -# define COMP_BADADDR 0x004 -# define COMP_NODST 0x008 -# define COMP_NOBADR 0x010 -# define COMP_NOMASK 0x020 -# define COMP_DUP 0x040 -# define COMP_BAD_METRIC 0x080 -# define COMP_NETMASK 0x100 - - struct interface ifs, ifs0, *ifp, *ifp1; - struct rt_entry *rt; - size_t needed; - int mib[6]; - struct if_msghdr *ifm; - void *ifam_lim; - struct ifa_msghdr *ifam, *ifam2; - int in, ierr, out, oerr; - struct intnet *intnetp; - struct rt_addrinfo info; -#ifdef SIOCGIFMETRIC - struct ifreq ifr; -#endif - - - last_ifinit = now; - ifinit_timer.tv_sec = now.tv_sec + (supplier - ? CHECK_ACT_INTERVAL - : CHECK_QUIET_INTERVAL); - - /* mark all interfaces so we can get rid of those that disappear */ - LIST_FOREACH(ifp, &ifnet, int_list) - 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; - /* retry if the table grew */ - if (errno != ENOMEM && errno != EFAULT) - BADERR(1, "ifinit: sysctl(RT_IFLIST)"); - free(sysctl_buf); - needed = 0; - } - if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) - BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); - sysctl_buf = rtmalloc(sysctl_buf_size = needed, - "ifinit sysctl"); - } - - /* XXX: thanks to malloc(3), alignment can be presumed OK */ - ifam_lim = (char *)sysctl_buf + needed; - for (ifam = sysctl_buf; (void *)ifam < ifam_lim; ifam = ifam2) { - - ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); - -#ifdef RTM_OIFINFO - if (ifam->ifam_type == RTM_OIFINFO) - continue; /* just ignore compat message */ -#endif - if (ifam->ifam_type == RTM_IFINFO) { - struct sockaddr_dl *sdl; - - ifm = (struct if_msghdr *)ifam; - /* make prototype structure for the IP aliases - */ - memset(&ifs0, 0, 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_query_time = NEVER; - ifs0.int_act_time = now.tv_sec; - ifs0.int_data.ts = now.tv_sec; - ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; - 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; - sdl = (struct sockaddr_dl *)(ifm + 1); - sdl->sdl_data[sdl->sdl_nlen] = 0; - strncpy(ifs0.int_name, sdl->sdl_data, - MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); - continue; - } - if (ifam->ifam_type != RTM_NEWADDR) { - logbad(1,"ifinit: out of sync"); - continue; - } - rt_xaddrs(&info, (struct sockaddr *)(ifam+1), - (struct sockaddr *)ifam2, - ifam->ifam_addrs); - - /* Prepare for the next address of this interface, which - * will be an alias. - * Do not output RIP or Router-Discovery packets via aliases. - */ - memcpy(&ifs, &ifs0, sizeof(ifs)); - ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); - - if (INFO_IFA(&info) == 0) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOADDR)) - msglog("%s has no address", - ifs.int_name); - complaints |= COMP_NOADDR; - } - continue; - } - if (INFO_IFA(&info)->sa_family != AF_INET) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOT_INET)) - trace_act("%s: not AF_INET", - ifs.int_name); - complaints |= COMP_NOT_INET; - } - continue; - } - - ifs.int_addr = S_ADDR(INFO_IFA(&info)); - - if (ntohl(ifs.int_addr)>>24 == 0 - || ntohl(ifs.int_addr)>>24 == 0xff) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_BADADDR)) - msglog("%s has a bad address", - ifs.int_name); - complaints |= COMP_BADADDR; - } - continue; - } - - if (ifs.int_if_flags & IFF_LOOPBACK) { - ifs.int_state |= IS_NO_RIP | IS_NO_RDISC; - if (ifs.int_addr == htonl(INADDR_LOOPBACK)) - ifs.int_state |= IS_PASSIVE; - ifs.int_dstaddr = ifs.int_addr; - ifs.int_mask = HOST_MASK; - ifs.int_ripv1_mask = HOST_MASK; - ifs.int_std_mask = std_mask(ifs.int_dstaddr); - ifs.int_net = ntohl(ifs.int_dstaddr); - if (!foundloopback) { - foundloopback = 1; - loopaddr = ifs.int_addr; - loop_rts.rts_gate = loopaddr; - loop_rts.rts_router = loopaddr; - } - - } else if (ifs.int_if_flags & IFF_POINTOPOINT) { - if (INFO_BRD(&info) == 0 - || INFO_BRD(&info)->sa_family != AF_INET) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NODST)) - msglog("%s has a bad" - " destination address", - ifs.int_name); - complaints |= COMP_NODST; - } - continue; - } - ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); - if (ntohl(ifs.int_dstaddr)>>24 == 0 - || ntohl(ifs.int_dstaddr)>>24 == 0xff) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NODST)) - msglog("%s has a bad" - " destination address", - ifs.int_name); - complaints |= COMP_NODST; - } - continue; - } - ifs.int_mask = HOST_MASK; - ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); - ifs.int_std_mask = std_mask(ifs.int_dstaddr); - ifs.int_net = ntohl(ifs.int_dstaddr); - - } else { - if (INFO_MASK(&info) == 0) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints & COMP_NOMASK)) - msglog("%s has no netmask", - ifs.int_name); - complaints |= COMP_NOMASK; - } - continue; - } - ifs.int_dstaddr = ifs.int_addr; - ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); - ifs.int_ripv1_mask = ifs.int_mask; - ifs.int_std_mask = std_mask(ifs.int_addr); - ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; - if (ifs.int_mask != ifs.int_std_mask) - ifs.int_state |= IS_SUBNET; - - if (ifs.int_if_flags & IFF_BROADCAST) { - if (INFO_BRD(&info) == 0) { - if (iff_up(ifs.int_if_flags)) { - if (!(prev_complaints - & COMP_NOBADR)) - msglog("%s has" - "no broadcast address", - ifs.int_name); - complaints |= COMP_NOBADR; - } - continue; - } - ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); - } - } - ifs.int_std_net = ifs.int_net & ifs.int_std_mask; - ifs.int_std_addr = htonl(ifs.int_std_net); - - /* 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, ifs.int_name, 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_up(ifs.int_if_flags)) { - complaints |= COMP_BAD_METRIC; - msglog("%s has a metric of %d", - ifs.int_name, 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(ifs.int_name, ((ifs.int_state & IS_ALIAS) - ? ifs.int_addr - : 0)); - if (ifp != NULL) { - 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", - ifp->int_name); - ifdel(ifp); - ifp = NULL; - } - } - - if (ifp != NULL) { - /* 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_up(ifs.int_if_flags)) { - if (iff_up(ifp->int_if_flags)) { - msglog("interface %s to %s turned off", - ifp->int_name, - naddr_ntoa(ifp->int_dstaddr)); - if_bad(ifp); - ifp->int_if_flags &= ~IFF_UP; - } else if (now.tv_sec>(ifp->int_data.ts - + CHECK_BAD_INTERVAL)) { - trace_act("interface %s has been off" - " %jd seconds; forget it", - ifp->int_name, - (intmax_t)now.tv_sec - - ifp->int_data.ts); - ifdel(ifp); - ifp = NULL; - } - continue; - } - /* or that were off and are now ok */ - if (!iff_up(ifp->int_if_flags)) { - ifp->int_if_flags |= IFF_UP; - (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; - /* 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 judgment 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", - ifp->int_name, - naddr_ntoa(ifp->int_dstaddr), - in, ierr, out, oerr); - if_sick(ifp); - continue; - } - if (!(ifp->int_state & IS_BROKE)) { - msglog("interface %s to %s broken:" - " in=%d ierr=%d out=%d oerr=%d", - ifp->int_name, - naddr_ntoa(ifp->int_dstaddr), - 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_up(ifs.int_if_flags)) - continue; - - /* If it duplicates an existing interface, - * complain about it, mark the other one - * duplicated, and forget this one. - */ - ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, - ifs.int_if_flags); - if (ifp != NULL) { - /* Ignore duplicates of itself, caused by having - * IP aliases on the same network. - */ - if (!strcmp(ifp->int_name, ifs.int_name)) - continue; - - if (!(prev_complaints & COMP_DUP)) { - complaints |= COMP_DUP; - msglog("%s (%s%s%s) is duplicated by" - " %s (%s%s%s)", - ifs.int_name, - addrname(ifs.int_addr,ifs.int_mask,1), - ((ifs.int_if_flags & IFF_POINTOPOINT) - ? "-->" : ""), - ((ifs.int_if_flags & IFF_POINTOPOINT) - ? naddr_ntoa(ifs.int_dstaddr) : ""), - ifp->int_name, - addrname(ifp->int_addr,ifp->int_mask,1), - ((ifp->int_if_flags & IFF_POINTOPOINT) - ? "-->" : ""), - ((ifp->int_if_flags & IFF_POINTOPOINT) - ? naddr_ntoa(ifp->int_dstaddr) : "")); - } - ifp->int_state |= IS_DUP; - continue; - } - - if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST | IFF_LOOPBACK))) { - trace_act("%s is neither broadcast, point-to-point," - " nor loopback", - ifs.int_name); - if (!(ifs.int_state & IFF_MULTICAST)) - ifs.int_state |= IS_NO_RDISC; - } - - - /* It is new and ok. Add it to the list of interfaces - */ - ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); - memcpy(ifp, &ifs, sizeof(*ifp)); - get_parms(ifp); - if_link(ifp); - trace_if("Add", ifp); - - /* Notice likely bad netmask. - */ - if (!(prev_complaints & COMP_NETMASK) - && !(ifp->int_if_flags & IFF_POINTOPOINT) - && ifp->int_addr != RIP_DEFAULT) { - LIST_FOREACH(ifp1, &ifnet, int_list) { - if (ifp1->int_mask == ifp->int_mask) - continue; - if (ifp1->int_if_flags & IFF_POINTOPOINT) - continue; - if (ifp1->int_dstaddr == RIP_DEFAULT) - continue; - /* ignore aliases on the right network */ - if (!strcmp(ifp->int_name, ifp1->int_name)) - continue; - if (on_net(ifp->int_dstaddr, - ifp1->int_net, ifp1->int_mask) - || on_net(ifp1->int_dstaddr, - ifp->int_net, ifp->int_mask)) { - msglog("possible netmask problem" - " between %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; - } - } - } - - if (!(ifp->int_state & IS_ALIAS)) { - /* Count the # of directly connected networks. - */ - if (!(ifp->int_if_flags & IFF_LOOPBACK)) - tot_interfaces++; - if (!IS_RIP_OFF(ifp->int_state)) - rip_interfaces++; - - /* turn on router discovery and RIP If needed */ - if_ok_rdisc(ifp); - rip_on(ifp); - } - } - - /* If we are multi-homed and have at least two interfaces - * 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 && ifp) - || (tot_interfaces > 1 - && mhome - && (ifp = ifwithaddr(myaddr, 0, 0)) != NULL - && foundloopback)) { - advertise_mhome = 1; - rt = rtget(myaddr, HOST_MASK); - if (rt != NULL) { - if (rt->rt_ifp != ifp - || rt->rt_router != loopaddr) { - rtdelete(rt); - rt = NULL; - } else { - loop_rts.rts_ifp = ifp; - loop_rts.rts_metric = 0; - loop_rts.rts_time = rt->rt_time; - rtchange(rt, rt->rt_state | RS_MHOME, - &loop_rts, 0); - } - } - if (rt == NULL) { - loop_rts.rts_ifp = ifp; - loop_rts.rts_metric = 0; - rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); - } - } - - LIST_FOREACH_SAFE(ifp, &ifnet, int_list, ifp1) { - /* Forget any interfaces that have disappeared. - */ - if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { - trace_act("interface %s has disappeared", - 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_state & IS_NO_RIPV1_OUT) && supplier) - have_ripv1_out = 1; - if (!(ifp->int_state & IS_NO_RIPV1_IN)) - have_ripv1_in = 1; - } - - LIST_FOREACH(ifp, &ifnet, int_list) { - /* 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. - */ - if (!addrouteforif(ifp)) - continue; - - /* 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, 0); - rt = rtget(ifp->int_addr, HOST_MASK); - if (rt != NULL && rt->rt_router != loopaddr) { - rtdelete(rt); - rt = NULL; - } - if (rt != NULL) { - if (!(rt->rt_state & RS_LOCAL) - || rt->rt_metric > ifp->int_metric) { - ifp1 = ifp; - } else { - ifp1 = rt->rt_ifp; - } - loop_rts.rts_ifp = ifp1; - loop_rts.rts_metric = 0; - loop_rts.rts_time = rt->rt_time; - rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) - | (RS_IF|RS_LOCAL)), - &loop_rts, 0); - } else { - loop_rts.rts_ifp = ifp; - loop_rts.rts_metric = 0; - rtadd(ifp->int_addr, HOST_MASK, - (RS_IF | RS_LOCAL), &loop_rts); - } - } - } - - /* add the authority routes */ - for (intnetp = intnets; intnetp != NULL; - intnetp = intnetp->intnet_next) { - rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); - if (rt != NULL - && !(rt->rt_state & RS_NO_NET_SYN) - && !(rt->rt_state & RS_NET_INT)) { - rtdelete(rt); - rt = NULL; - } - if (rt == NULL) { - loop_rts.rts_ifp = NULL; - loop_rts.rts_metric = intnetp->intnet_metric-1; - rtadd(intnetp->intnet_addr, intnetp->intnet_mask, - RS_NET_SYN | RS_NET_INT, &loop_rts); - } - } - - prev_complaints = complaints; -} - - -static void -check_net_syn(struct interface *ifp) -{ - struct rt_entry *rt; - static struct rt_spare new; - - - /* Turn on the need to automatically synthesize a network route - * 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 != NULL - && 0 == (rt->rt_state & RS_NO_NET_SYN) - && (!(rt->rt_state & RS_NET_SYN) - || rt->rt_metric > ifp->int_metric)) { - rtdelete(rt); - rt = NULL; - } - if (rt == NULL) { - new.rts_ifp = ifp; - new.rts_gate = ifp->int_addr; - new.rts_router = ifp->int_addr; - new.rts_metric = ifp->int_metric; - rtadd(ifp->int_std_addr, ifp->int_std_mask, - RS_NET_SYN, &new); - } - - } else { - ifp->int_state &= ~IS_NEED_NET_SYN; - - rt = rtget(ifp->int_std_addr, - ifp->int_std_mask); - if (rt != NULL - && (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. - */ -static int /* 0=bad interface */ -addrouteforif(struct interface *ifp) -{ - struct rt_entry *rt; - static struct rt_spare new; - naddr dst; - - - /* skip sick interfaces - */ - if (ifp->int_state & IS_BROKE) - return 0; - - /* 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); - - dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) - ? ifp->int_dstaddr - : htonl(ifp->int_net)); - - new.rts_ifp = ifp; - new.rts_router = ifp->int_addr; - new.rts_gate = ifp->int_addr; - new.rts_metric = ifp->int_metric; - new.rts_time = now.tv_sec; - - /* If we are going to send packets to the gateway, - * it must be reachable using our physical interfaces - */ - if ((ifp->int_state & IS_REMOTE) - && !(ifp->int_state & IS_EXTERNAL) - && !check_remote(ifp)) - return 0; - - /* We are finished if the correct main interface route exists. - * The right route must be for the right interface, not synthesized - * from a subnet, be a "gateway" or not as appropriate, and so forth. - */ - del_static(dst, ifp->int_mask, 0, 0); - rt = rtget(dst, ifp->int_mask); - if (rt != NULL) { - 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 = NULL; - } else { - rtchange(rt, ((rt->rt_state | RS_IF) - & ~(RS_NET_SYN | RS_LOCAL)), - &new, 0); - } - } - if (rt == NULL) { - if (ifp->int_transitions++ > 0) - trace_act("re-install interface %s", - ifp->int_name); - - rtadd(dst, ifp->int_mask, RS_IF, &new); - } - - return 1; -} diff --git a/sbin/routed/input.c b/sbin/routed/input.c deleted file mode 100644 --- a/sbin/routed/input.c +++ /dev/null @@ -1,1025 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include "defs.h" -static void input(struct sockaddr_in *, struct interface *, struct interface *, - struct rip *, int); -static void input_route(naddr, naddr, struct rt_spare *, struct netinfo *); -static int ck_passwd(struct interface *, struct rip *, void *, - naddr, struct msg_limit *); - - -/* process RIP input - */ -void -read_rip(int sock, - struct interface *sifp) -{ - struct sockaddr_in from; - struct interface *aifp; - socklen_t fromlen; - int cc; -#ifdef USE_PASSIFNAME - static struct msg_limit bad_name; - struct { - char ifname[IFNAMSIZ]; - union pkt_buf pbuf; - } inbuf; -#else - struct { - union pkt_buf pbuf; - } inbuf; -#endif - - - for (;;) { - 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", - (int)fromlen); - - /* aifp is the "authenticated" interface via which the packet - * arrived. In fact, it is only the interface on which - * the packet should have arrived based on is source - * address. - * sifp is interface associated with the socket through which - * the packet was received. - */ -#ifdef USE_PASSIFNAME - if ((cc -= sizeof(inbuf.ifname)) < 0) - logbad(0,"missing USE_PASSIFNAME; only %d bytes", - cc+sizeof(inbuf.ifname)); - - /* check the remote interfaces first */ - LIST_FOREACH(aifp, &remote_if, remote_list) { - if (aifp->int_addr == from.sin_addr.s_addr) - break; - } - if (aifp == NULL) { - aifp = ifwithname(inbuf.ifname, 0); - if (aifp == NULL) { - msglim(&bad_name, from.sin_addr.s_addr, - "impossible interface name %.*s", - IFNAMSIZ, inbuf.ifname); - } else if (((aifp->int_if_flags & IFF_POINTOPOINT) - && aifp->int_dstaddr!=from.sin_addr.s_addr) - || (!(aifp->int_if_flags & IFF_POINTOPOINT) - && !on_net(from.sin_addr.s_addr, - aifp->int_net, - aifp->int_mask))) { - /* If it came via the wrong interface, do not - * trust it. - */ - aifp = NULL; - } - } -#else - aifp = iflookup(from.sin_addr.s_addr); -#endif - if (sifp == NULL) - sifp = aifp; - - input(&from, sifp, aifp, &inbuf.pbuf.rip, cc); - } -} - - -/* Process a RIP packet - */ -static void -input(struct sockaddr_in *from, /* received from this IP address */ - struct interface *sifp, /* interface of incoming socket */ - struct interface *aifp, /* "authenticated" interface */ - struct rip *rip, - int cc) -{ -# define FROM_NADDR from->sin_addr.s_addr - static struct msg_limit use_auth, bad_len, bad_mask; - static struct msg_limit unk_router, bad_router, bad_nhop; - - struct rt_entry *rt; - struct rt_spare new; - struct netinfo *n, *lim; - struct interface *ifp1; - naddr gate, mask, v1_mask, dst, ddst_h = 0; - struct auth *ap; - struct tgate *tg = NULL; - struct tgate_net *tn; - int i, j; - - /* Notice when we hear from a remote gateway - */ - if (aifp != NULL - && (aifp->int_state & IS_REMOTE)) - aifp->int_act_time = now.tv_sec; - - trace_rip("Recv", "from", from, sifp, rip, cc); - - if (sifp == NULL) { - trace_pkt(" discard a request from an indirect router" - " (possibly an attack)"); - return; - } - - if (rip->rip_vers == 0) { - msglim(&bad_router, FROM_NADDR, - "RIP version 0, cmd %d, packet received from %s", - rip->rip_cmd, naddr_ntoa(FROM_NADDR)); - return; - } else if (rip->rip_vers > RIPv2) { - rip->rip_vers = RIPv2; - } - if (cc > (int)OVER_MAXPACKETSIZE) { - msglim(&bad_router, FROM_NADDR, - "packet at least %d bytes too long received from %s", - cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR)); - return; - } - - n = rip->rip_nets; - lim = (struct netinfo *)((char*)rip + cc); - - /* Notice authentication. - * As required by section 4.2 in RFC 1723, discard authenticated - * RIPv2 messages, but only if configured for that silliness. - * - * RIPv2 authentication is lame. Why authenticate queries? - * Why should a RIPv2 implementation with authentication disabled - * not be able to listen to RIPv2 packets with authentication, while - * RIPv1 systems will listen? Crazy! - */ - if (!auth_ok - && rip->rip_vers == RIPv2 - && n < lim && n->n_family == RIP_AF_AUTH) { - msglim(&use_auth, FROM_NADDR, - "RIPv2 message with authentication from %s discarded", - naddr_ntoa(FROM_NADDR)); - return; - } - - switch (rip->rip_cmd) { - case RIPCMD_REQUEST: - /* For mere requests, be a little sloppy about the source - */ - if (aifp == NULL) - aifp = sifp; - - /* Are we talking to ourself or a remote gateway? - */ - ifp1 = ifwithaddr(FROM_NADDR, 0, 1); - if (ifp1) { - if (ifp1->int_state & IS_REMOTE) { - /* remote gateway */ - aifp = ifp1; - if (check_remote(aifp)) { - aifp->int_act_time = now.tv_sec; - (void)if_ok(aifp, "remote "); - } - } else if (from->sin_port == htons(RIP_PORT)) { - trace_pkt(" discard our own RIP request"); - return; - } - } - - /* did the request come from a router? - */ - if (from->sin_port == htons(RIP_PORT)) { - /* yes, ignore the request if RIP is off so that - * the router does not depend on us. - */ - if (rip_sock < 0 - || (aifp != NULL - && IS_RIP_OUT_OFF(aifp->int_state))) { - trace_pkt(" discard request while RIP off"); - return; - } - } - - /* According to RFC 1723, we should ignore unauthenticated - * 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? When RIP - * is still the most common router-discovery protocol - * and so hosts need to send queries that will be answered? - * What about `rtquery`? - * Maybe on firewalls you'd care, but not enough to - * give up the diagnostic facilities of remote probing. - */ - - if (n >= lim) { - msglim(&bad_len, FROM_NADDR, "empty request from %s", - naddr_ntoa(FROM_NADDR)); - return; - } - if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - msglim(&bad_len, FROM_NADDR, - "request of bad length (%d) from %s", - cc, naddr_ntoa(FROM_NADDR)); - } - - if (rip->rip_vers == RIPv2 - && (aifp == NULL || (aifp->int_state & IS_NO_RIPV1_OUT))) { - v12buf.buf->rip_vers = RIPv2; - /* If we have a secret but it is a cleartext secret, - * do not disclose our secret unless the other guy - * already knows it. - */ - ap = find_auth(aifp); - if (ap != NULL && ap->type == RIP_AUTH_PW - && n->n_family == RIP_AF_AUTH - && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth)) - ap = NULL; - } else { - v12buf.buf->rip_vers = RIPv1; - ap = NULL; - } - clr_ws_buf(&v12buf, ap); - - do { - 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). - */ - if (n->n_family == RIP_AF_UNSPEC - && n->n_metric == HOPCNT_INFINITY) { - /* Answer a query from a utility program - * with all we know. - */ - if (aifp == NULL) { - trace_pkt("ignore remote query"); - return; - } - if (from->sin_port != htons(RIP_PORT)) { - /* - * insecure: query from non-router node - * > 1: allow from distant node - * > 0: allow from neighbor node - * == 0: deny - */ - if ((aifp != NULL && insecure > 0) || - (aifp == NULL && insecure > 1)) - supply(from, aifp, OUT_QUERY, 0, - rip->rip_vers, - ap != NULL); - else - trace_pkt("Warning: " - "possible attack detected"); - return; - } - - /* A router trying to prime its tables. - * Filter the answer 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 as a router. - */ - if (aifp == NULL) { - trace_pkt("ignore distant router"); - return; - } - if (!supplier - || IS_RIP_OFF(aifp->int_state)) { - trace_pkt("ignore; not supplying"); - return; - } - - /* Do not answer a RIPv1 router if - * we are sending RIPv2. But do offer - * poor man's router discovery. - */ - if ((aifp->int_state & IS_NO_RIPV1_OUT) - && rip->rip_vers == RIPv1) { - if (!(aifp->int_state & IS_PM_RDISC)) { - trace_pkt("ignore; sending RIPv2"); - return; - } - - v12buf.n->n_family = RIP_AF_INET; - v12buf.n->n_dst = RIP_DEFAULT; - i = aifp->int_d_metric; - if (NULL != (rt = rtget(RIP_DEFAULT, 0))) { - j = (rt->rt_metric - +aifp->int_metric - +aifp->int_adj_outmetric - +1); - if (i > j) - i = j; - } - v12buf.n->n_metric = htonl(i); - v12buf.n++; - break; - } - - /* Respond with RIPv1 instead of RIPv2 if - * that is what we are broadcasting on the - * interface to keep the remote router from - * getting the wrong initial idea of the - * routes we send. - */ - supply(from, aifp, OUT_UNICAST, 0, - (aifp->int_state & IS_NO_RIPV1_OUT) - ? RIPv2 : RIPv1, - ap != NULL); - return; - } - - /* Ignore authentication */ - if (n->n_family == RIP_AF_AUTH) - continue; - - if (n->n_family != RIP_AF_INET) { - msglim(&bad_router, FROM_NADDR, - "request from %s for unsupported" - " (af %d) %s", - naddr_ntoa(FROM_NADDR), - ntohs(n->n_family), - naddr_ntoa(n->n_dst)); - return; - } - - /* We are being asked about a specific destination. - */ - dst = n->n_dst; - if (!check_dst(dst)) { - msglim(&bad_router, FROM_NADDR, - "bad queried destination %s from %s", - naddr_ntoa(dst), - naddr_ntoa(FROM_NADDR)); - return; - } - - /* decide what mask was intended */ - if (rip->rip_vers == RIPv1 - || 0 == (mask = ntohl(n->n_mask)) - || 0 != (ntohl(dst) & ~mask)) - mask = ripv1_mask_host(dst, aifp); - - /* try to find the answer */ - rt = rtget(dst, mask); - if (!rt && dst != RIP_DEFAULT) - rt = rtfind(n->n_dst); - - if (v12buf.buf->rip_vers != RIPv1) - v12buf.n->n_mask = mask; - if (rt == NULL) { - /* we do not have the answer */ - v12buf.n->n_metric = HOPCNT_INFINITY; - } else { - /* we have the answer, so compute the - * right metric and next hop. - */ - v12buf.n->n_family = RIP_AF_INET; - v12buf.n->n_dst = dst; - j = rt->rt_metric+1; - if (!aifp) - ++j; - else - j += (aifp->int_metric - + aifp->int_adj_outmetric); - if (j < HOPCNT_INFINITY) - v12buf.n->n_metric = j; - else - v12buf.n->n_metric = HOPCNT_INFINITY; - if (v12buf.buf->rip_vers != RIPv1) { - v12buf.n->n_tag = rt->rt_tag; - v12buf.n->n_mask = mask; - if (aifp != NULL - && on_net(rt->rt_gate, - aifp->int_net, - aifp->int_mask) - && rt->rt_gate != aifp->int_addr) - v12buf.n->n_nhop = rt->rt_gate; - } - } - v12buf.n->n_metric = htonl(v12buf.n->n_metric); - - /* Stop paying attention if we fill the output buffer. - */ - if (++v12buf.n >= v12buf.lim) - break; - } while (++n < lim); - - /* Send the answer about specific routes. - */ - if (ap != NULL && ap->type == RIP_AUTH_MD5) - end_md5_auth(&v12buf, ap); - - if (from->sin_port != htons(RIP_PORT)) { - /* query */ - (void)output(OUT_QUERY, from, aifp, - v12buf.buf, - ((char *)v12buf.n - (char*)v12buf.buf)); - } else if (supplier) { - (void)output(OUT_UNICAST, from, aifp, - v12buf.buf, - ((char *)v12buf.n - (char*)v12buf.buf)); - } else { - /* Only answer a router if we are a supplier - * to keep an unwary host that is just starting - * from picking us an a router. - */ - ; - } - return; - - case RIPCMD_TRACEON: - case RIPCMD_TRACEOFF: - /* Notice that trace messages are turned off for all possible - * abuse if _PATH_TRACE is undefined in pathnames.h. - * Notice also that because of the way the trace file is - * handled in trace.c, no abuse is plausible even if - * _PATH_TRACE_ is defined. - * - * First 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 (aifp == NULL) { - msglog("trace command from unknown router %s", - naddr_ntoa(FROM_NADDR)); - return; - } - if (rip->rip_cmd == RIPCMD_TRACEON) { - rip->rip_tracefile[cc-4] = '\0'; - set_tracefile((char*)rip->rip_tracefile, - "trace command: %s\n", 0); - } else { - trace_off("tracing turned off by %s", - naddr_ntoa(FROM_NADDR)); - } - return; - - case RIPCMD_RESPONSE: - if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - msglim(&bad_len, FROM_NADDR, - "response of bad length (%d) from %s", - cc, naddr_ntoa(FROM_NADDR)); - } - - /* verify message came from a router */ - if (from->sin_port != ntohs(RIP_PORT)) { - msglim(&bad_router, FROM_NADDR, - " discard RIP response from unknown port" - " %d on %s", - ntohs(from->sin_port), naddr_ntoa(FROM_NADDR)); - return; - } - - if (rip_sock < 0) { - trace_pkt(" discard response while RIP off"); - return; - } - - /* Are we talking to ourself or a remote gateway? - */ - ifp1 = ifwithaddr(FROM_NADDR, 0, 1); - if (ifp1) { - if (ifp1->int_state & IS_REMOTE) { - /* remote gateway */ - aifp = ifp1; - if (check_remote(aifp)) { - aifp->int_act_time = now.tv_sec; - (void)if_ok(aifp, "remote "); - } - } else { - trace_pkt(" discard our own RIP response"); - return; - } - } - - /* Accept routing packets from routers directly connected - * via broadcast or point-to-point networks, and from - * those listed in /etc/gateways. - */ - if (aifp == NULL) { - msglim(&unk_router, FROM_NADDR, - " discard response from %s" - " via unexpected interface", - naddr_ntoa(FROM_NADDR)); - return; - } - if (IS_RIP_IN_OFF(aifp->int_state)) { - trace_pkt(" discard RIPv%d response" - " via disabled interface %s", - rip->rip_vers, aifp->int_name); - return; - } - - if (n >= lim) { - msglim(&bad_len, FROM_NADDR, "empty response from %s", - naddr_ntoa(FROM_NADDR)); - return; - } - - if (((aifp->int_state & IS_NO_RIPV1_IN) - && rip->rip_vers == RIPv1) - || ((aifp->int_state & IS_NO_RIPV2_IN) - && rip->rip_vers != RIPv1)) { - trace_pkt(" discard RIPv%d response", - rip->rip_vers); - return; - } - - /* Ignore routes via dead interface. - */ - if (aifp->int_state & IS_BROKE) { - trace_pkt("discard response via broken interface %s", - aifp->int_name); - return; - } - - /* If the interface cares, ignore bad routers. - * Trace but do not log this problem, because where it - * happens, it happens frequently. - */ - if (aifp->int_state & IS_DISTRUST) { - tg = tgates; - while (tg->tgate_addr != FROM_NADDR) { - tg = tg->tgate_next; - if (tg == NULL) { - trace_pkt(" discard RIP response" - " from untrusted router %s", - naddr_ntoa(FROM_NADDR)); - return; - } - } - } - - /* Authenticate the packet if we have a secret. - * If we do not have any secrets, ignore the error in - * RFC 1723 and accept it regardless. - */ - if (aifp->int_auth[0].type != RIP_AUTH_NONE - && rip->rip_vers != RIPv1 - && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth)) - return; - - do { - if (n->n_family == RIP_AF_AUTH) - continue; - - n->n_metric = ntohl(n->n_metric); - dst = n->n_dst; - if (n->n_family != RIP_AF_INET - && (n->n_family != RIP_AF_UNSPEC - || dst != RIP_DEFAULT)) { - msglim(&bad_router, FROM_NADDR, - "route from %s to unsupported" - " address family=%d destination=%s", - naddr_ntoa(FROM_NADDR), - n->n_family, - naddr_ntoa(dst)); - continue; - } - if (!check_dst(dst)) { - msglim(&bad_router, FROM_NADDR, - "bad destination %s from %s", - naddr_ntoa(dst), - naddr_ntoa(FROM_NADDR)); - return; - } - if (n->n_metric == 0 - || n->n_metric > HOPCNT_INFINITY) { - msglim(&bad_router, FROM_NADDR, - "bad metric %d from %s" - " for destination %s", - n->n_metric, - naddr_ntoa(FROM_NADDR), - naddr_ntoa(dst)); - return; - } - - /* Notice the next-hop. - */ - gate = FROM_NADDR; - if (n->n_nhop != 0) { - if (rip->rip_vers == RIPv1) { - n->n_nhop = 0; - } else { - /* Use it only if it is valid. */ - if (on_net(n->n_nhop, - aifp->int_net, aifp->int_mask) - && check_dst(n->n_nhop)) { - gate = n->n_nhop; - } else { - msglim(&bad_nhop, FROM_NADDR, - "router %s to %s" - " has bad next hop %s", - naddr_ntoa(FROM_NADDR), - naddr_ntoa(dst), - naddr_ntoa(n->n_nhop)); - n->n_nhop = 0; - } - } - } - - if (rip->rip_vers == RIPv1 - || 0 == (mask = ntohl(n->n_mask))) { - mask = ripv1_mask_host(dst,aifp); - } else if ((ntohl(dst) & ~mask) != 0) { - msglim(&bad_mask, FROM_NADDR, - "router %s sent bad netmask" - " %#lx with %s", - naddr_ntoa(FROM_NADDR), - (u_long)mask, - naddr_ntoa(dst)); - continue; - } - if (rip->rip_vers == RIPv1) - n->n_tag = 0; - - /* Adjust metric according to incoming interface.. - */ - n->n_metric += (aifp->int_metric - + aifp->int_adj_inmetric); - if (n->n_metric > HOPCNT_INFINITY) - n->n_metric = HOPCNT_INFINITY; - - /* Should we trust this route from this router? */ - if (tg && (tn = tg->tgate_nets)->mask != 0) { - for (i = 0; i < MAX_TGATE_NETS; i++, tn++) { - if (on_net(dst, tn->net, tn->mask) - && tn->mask <= mask) - break; - } - if (i >= MAX_TGATE_NETS || tn->mask == 0) { - trace_pkt(" ignored unauthorized %s", - addrname(dst,mask,0)); - continue; - } - } - - /* Recognize and ignore a default route we faked - * which is being sent back to us by a machine with - * broken split-horizon. - * Be a little more paranoid than that, and reject - * default routes with the same metric we advertised. - */ - if (aifp->int_d_metric != 0 - && dst == RIP_DEFAULT - && (int)n->n_metric >= aifp->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 - && (((rt = rtget(dst,mask)) == NULL - || !(rt->rt_state & RS_NET_SYN))) - && (v1_mask = ripv1_mask_net(dst,0)) > mask) { - ddst_h = v1_mask & -v1_mask; - i = (v1_mask & ~mask)/ddst_h; - if (i >= 511) { - /* Punt if we would have to generate - * an unreasonable number of routes. - */ - if (TRACECONTENTS) - trace_misc("accept %s-->%s as 1" - " instead of %d routes", - addrname(dst,mask,0), - naddr_ntoa(FROM_NADDR), - i+1); - i = 0; - } else { - mask = v1_mask; - } - } else { - i = 0; - } - - new.rts_gate = gate; - new.rts_router = FROM_NADDR; - new.rts_metric = n->n_metric; - new.rts_tag = n->n_tag; - new.rts_time = now.tv_sec; - new.rts_ifp = aifp; - new.rts_de_ag = i; - j = 0; - for (;;) { - input_route(dst, mask, &new, n); - if (++j > i) - break; - dst = htonl(ntohl(dst) + ddst_h); - } - } while (++n < lim); - break; - } -#undef FROM_NADDR -} - - -/* Process a single input route. - */ -static void -input_route(naddr dst, /* network order */ - naddr mask, - struct rt_spare *new, - struct netinfo *n) -{ - int i; - struct rt_entry *rt; - struct rt_spare *rts, *rts0; - struct interface *ifp1; - - - /* 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 != NULL - && (!(ifp1->int_state & IS_BROKE) - || (ifp1->int_state & IS_PASSIVE))) - 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 == NULL) { - /* Ignore unknown routes being poisoned. - */ - if (new->rts_metric == HOPCNT_INFINITY) - return; - - /* Ignore the route if it points to us */ - if (n->n_nhop != 0 - && ifwithaddr(n->n_nhop, 1, 0) != NULL) - return; - - /* If something has not gone crazy and tried to fill - * our memory, accept the new route. - */ - if (total_routes < MAX_ROUTES) - rtadd(dst, mask, 0, new); - 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 never - * aggregating 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 == new->rts_router) - 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 a route from the router already in the table. - */ - - /* If the new route is a route broken down from an - * aggregated route, and if the previous route is either - * not a broken down route or was broken down from a finer - * netmask, and if the previous route is current, - * then forget this one. - */ - if (new->rts_de_ag > rts->rts_de_ag - && now_stale <= rts->rts_time) - return; - - /* Keep poisoned routes around only long enough to pass - * the poison on. Use a new timestamp for good routes. - */ - if (rts->rts_metric == HOPCNT_INFINITY - && new->rts_metric == HOPCNT_INFINITY) - new->rts_time = rts->rts_time; - - /* If this is an update for the router we currently prefer, - * then note it. - */ - if (i == NUM_SPARES) { - rtchange(rt, rt->rt_state, new, 0); - /* If the route got worse, check for something better. - */ - if (new->rts_metric > rts->rts_metric) - rtswitch(rt, 0); - return; - } - - /* This is an update for a spare route. - * Finished if the route is unchanged. - */ - if (rts->rts_gate == new->rts_gate - && rts->rts_metric == new->rts_metric - && rts->rts_tag == new->rts_tag) { - trace_upslot(rt, rts, new); - *rts = *new; - return; - } - /* Forget it if it has gone bad. - */ - if (new->rts_metric == HOPCNT_INFINITY) { - rts_delete(rt, rts); - return; - } - - } else { - /* The update is for a route we know about, - * but not from a familiar router. - * - * Ignore the route if it points to us. - */ - if (n->n_nhop != 0 - && NULL != ifwithaddr(n->n_nhop, 1, 0)) - return; - - /* the loop above set rts0=worst spare */ - rts = rts0; - - /* Save the route as a spare only if it has - * a better metric than our worst spare. - * This also ignores poisoned routes (those - * received with metric HOPCNT_INFINITY). - */ - if (new->rts_metric >= rts->rts_metric) - return; - } - - trace_upslot(rt, rts, new); - *rts = *new; - - /* try to switch to a better route */ - rtswitch(rt, rts); -} - - -static int /* 0 if bad */ -ck_passwd(struct interface *aifp, - struct rip *rip, - void *lim, - naddr from, - struct msg_limit *use_authp) -{ -# define NA (rip->rip_auths) - struct netauth *na2; - struct auth *ap; - MD5_CTX md5_ctx; - u_char hash[RIP_AUTH_PW_LEN]; - int i, len; - - assert(aifp != NULL); - if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) { - msglim(use_authp, from, "missing password from %s", - naddr_ntoa(from)); - return 0; - } - - /* accept any current (+/- 24 hours) password - */ - for (ap = aifp->int_auth, i = 0; i < MAX_AUTH_KEYS; i++, ap++) { - if (ap->type != NA->a_type - || (u_long)ap->start > (u_long)clk.tv_sec+DAY - || (u_long)ap->end+DAY < (u_long)clk.tv_sec) - continue; - - if (NA->a_type == RIP_AUTH_PW) { - if (!memcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN)) - return 1; - - } else { - /* accept MD5 secret with the right key ID - */ - if (NA->au.a_md5.md5_keyid != ap->keyid) - continue; - - len = ntohs(NA->au.a_md5.md5_pkt_len); - if ((len-sizeof(*rip)) % sizeof(*NA) != 0 - || len != (char *)lim-(char*)rip-(int)sizeof(*NA)) { - msglim(use_authp, from, - "wrong MD5 RIPv2 packet length of %d" - " instead of %d from %s", - len, (int)((char *)lim-(char *)rip - -sizeof(*NA)), - naddr_ntoa(from)); - return 0; - } - na2 = (struct netauth *)((char *)rip+len); - - /* Given a good hash value, these are not security - * problems so be generous and accept the routes, - * after complaining. - */ - if (TRACEPACKETS) { - if (NA->au.a_md5.md5_auth_len - != RIP_AUTH_MD5_HASH_LEN) - msglim(use_authp, from, - "unknown MD5 RIPv2 auth len %#x" - " instead of %#x from %s", - NA->au.a_md5.md5_auth_len, - (unsigned)RIP_AUTH_MD5_HASH_LEN, - naddr_ntoa(from)); - if (na2->a_family != RIP_AF_AUTH) - msglim(use_authp, from, - "unknown MD5 RIPv2 family %#x" - " instead of %#x from %s", - na2->a_family, RIP_AF_AUTH, - naddr_ntoa(from)); - if (na2->a_type != ntohs(1)) - msglim(use_authp, from, - "MD5 RIPv2 hash has %#x" - " instead of %#x from %s", - na2->a_type, ntohs(1), - naddr_ntoa(from)); - } - - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)rip, - len + RIP_AUTH_MD5_HASH_XTRA); - MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN); - MD5Final(hash, &md5_ctx); - if (!memcmp(hash, na2->au.au_pw, sizeof(hash))) - return 1; - } - } - - msglim(use_authp, from, "bad password from %s", - naddr_ntoa(from)); - return 0; -#undef NA -} diff --git a/sbin/routed/main.c b/sbin/routed/main.c deleted file mode 100644 --- a/sbin/routed/main.c +++ /dev/null @@ -1,940 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include "defs.h" -#include "pathnames.h" -#include -#include -#include - -pid_t mypid; - -naddr myaddr; /* system address */ -static char myname[MAXHOSTNAMELEN+1]; - -static int verbose; - -int supplier; /* supply or broadcast updates */ -int supplier_set; -static int ipforwarding = 1; /* kernel forwarding on */ - -static int default_gateway; /* 1=advertise default */ -static int background = 1; -int ridhosts; /* 1=reduce host routes */ -int mhome; /* 1=want multi-homed host route */ -int advertise_mhome; /* 1=must continue advertising it */ -int auth_ok = 1; /* 1=ignore auth if we do not care */ -int insecure; /* Reply to special queries or not */ - -struct timeval epoch; /* when started */ -struct timeval clk; -static struct timeval prev_clk; -static int usec_fudge; -struct timeval now; /* current idea of time */ -time_t now_stale; -time_t now_expire; -time_t now_garbage; - -static struct timeval next_bcast; /* next general broadcast */ -struct timeval no_flash = { /* inhibit flash update */ - EPOCH+SUPPLY_INTERVAL, 0 -}; - -static struct timeval flush_kern_timer; - -static fd_set fdbits; -static int sock_max; -int rip_sock = -1; /* RIP socket */ -const 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 *); -static void sigalrm(int s UNUSED); -static void sigterm(int sig); - -int -main(int argc, - char *argv[]) -{ - int n, mib[4], off; - size_t len; - char *p, *q; - const char *cp; - struct timeval wtime, t2; - time_t dt; - fd_set ibits; - naddr p_net, p_mask; - struct interface *ifp; - struct parm parm; - char *tracename = 0; - - - /* Some shells are badly broken and send SIGHUP to backgrounded - * processes. - */ - signal(SIGHUP, SIG_IGN); - - openlog("routed", LOG_PID, LOG_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_expire = EPOCH - EXPIRE_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, "isqdghmAtvT:F:P:")) != -1) { - switch (n) { - case 'i': - insecure++; - break; - case 's': - supplier = 1; - supplier_set = 1; - break; - - case 'q': - supplier = 0; - supplier_set = 1; - break; - - case 'd': - background = 0; - break; - - case 'g': - memset(&parm, 0, sizeof(parm)); - parm.parm_d_metric = 1; - cp = check_parms(&parm); - if (cp != 0) - msglog("bad -g: %s", cp); - 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 = FAKE_METRIC; - 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_net, &p_mask)) { - msglog("bad network; \"-F %s\"", - optarg); - break; - } - memset(&parm, 0, sizeof(parm)); - parm.parm_net = p_net; - parm.parm_mask = p_mask; - parm.parm_d_metric = n; - cp = check_parms(&parm); - if (cp != 0) - msglog("bad -F: %s", cp); - break; - - case 'P': - /* handle arbitrary parameters. - */ - q = strdup(optarg); - cp = parse_parms(q, 0); - if (cp != 0) - msglog("%s in \"-P %s\"", cp, optarg); - free(q); - break; - - case 'v': - /* display version */ - verbose++; - msglog("version 2.31"); - break; - - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (tracename == 0 && argc >= 1) { - tracename = *argv++; - argc--; - } - if (tracename != 0 && tracename[0] == '\0') - goto usage; - if (argc != 0) { -usage: - logbad(0, "usage: routed [-sqdghmAtv] [-T tracefile]" - " [-F net[,metric]] [-P parms]"); - } - if (geteuid() != 0) { - if (verbose) - exit(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; - } - } - - - signal(SIGALRM, sigalrm); - if (!background) - signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ - signal(SIGTERM, sigterm); - signal(SIGINT, sigterm); - signal(SIGUSR1, sigtrace_on); - signal(SIGUSR2, sigtrace_off); - - /* get into the background */ - if (background && daemon(0, 1) < 0) - BADERR(0,"daemon()"); - - mypid = getpid(); - - /* 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 (tracename != 0) { - strncpy(inittracename, tracename, sizeof(inittracename)-1); - set_tracefile(inittracename, "%s", -1); - } else { - tracelevel_msg("%s", -1); /* turn on tracing to stdio */ - } - - bufinit(); - - /* 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; - - /* Collect an initial view of the world by checking the interface - * configuration and the kludge file. - */ - gwkludge(); - ifinit(); - - /* Ask for routes */ - rip_query(); - rdisc_sol(); - - /* Now turn off stdio if not tracing */ - if (new_tracelevel == 0) - trace_close(background); - - /* Loop forever, listening and broadcasting. - */ - for (;;) { - prev_clk = clk; - gettimeofday(&clk, 0); - if (prev_clk.tv_sec == clk.tv_sec - && prev_clk.tv_usec == clk.tv_usec+usec_fudge) { - /* Much of `routed` depends on time always advancing. - * On systems that do not guarantee that gettimeofday() - * produces unique timestamps even if called within - * a single tick, use trickery like that in classic - * BSD kernels. - */ - clk.tv_usec += ++usec_fudge; - - } else { - usec_fudge = 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", (int)dt); - epoch.tv_sec += dt; - } - } - timevalsub(&now, &clk, &epoch); - now_stale = now.tv_sec - STALE_TIME; - now_expire = now.tv_sec - EXPIRE_TIME; - now_garbage = now.tv_sec - GARBAGE_TIME; - - /* deal with signals that should affect tracing */ - set_tracelevel(); - - if (stopint != 0) { - rip_bcast(0); - rdisc_adv(); - trace_off("exiting with signal %d", 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; - } - - /* Check the kernel table occasionally for mysteriously - * evaporated routes - */ - timevalsub(&t2, &flush_kern_timer, &now); - if (t2.tv_sec <= 0) { - flush_kern(); - flush_kern_timer.tv_sec = (now.tv_sec - + CHECK_QUIET_INTERVAL); - continue; - } - if (timercmp(&t2, &wtime, <)) - wtime = t2; - - /* If it is time, then broadcast our routes. - */ - if (supplier || advertise_mhome) { - 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 - * scheduled, 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 anniversary 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 in the correct 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--; - } - - LIST_FOREACH(ifp, &ifnet, int_list) { - if (n <= 0) - break; - if (ifp->int_rip_sock >= 0 - && FD_ISSET(ifp->int_rip_sock, &ibits)) { - read_rip(ifp->int_rip_sock, ifp); - n--; - } - } - } -} - - -/* ARGSUSED */ -static void -sigalrm(int s UNUSED) -{ - /* Historically, SIGALRM would cause the daemon to check for - * new and broken interfaces. - */ - ifinit_timer.tv_sec = now.tv_sec; - trace_act("SIGALRM"); -} - - -/* watch for fatal signals */ -static 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; - } - LIST_FOREACH(ifp, &ifnet, int_list) { - 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, - const 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)); -#ifdef USE_PASSIFNAME - on = 1; - if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0) - msglog("setsockopt(%s,SO_PASSIFNAME): %s", - name, strerror(errno)); -#endif - - if (rbuf >= MIN_SOCKBUF) { - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, - &rbuf, sizeof(rbuf)) < 0) - 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", 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 rsin; - unsigned char ttl; - int s; - - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - BADERR(1,"rip_sock = socket()"); - - memset(&rsin, 0, sizeof(rsin)); -#ifdef _HAVE_SIN_LEN - rsin.sin_len = sizeof(rsin); -#endif - rsin.sin_family = AF_INET; - rsin.sin_port = htons(RIP_PORT); - rsin.sin_addr.s_addr = addr; - if (bind(s, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) { - if (serious) - BADERR(errno != EADDRINUSE, "bind(rip_sock)"); - close(s); - 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; - naddr addr; - - - if (rip_sock >= 0 && !mhome) { - trace_act("turn off RIP"); - - (void)close(rip_sock); - rip_sock = -1; - - /* get non-broadcast sockets to listen to queries. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - if (ifp->int_state & IS_REMOTE) - continue; - if (ifp->int_rip_sock < 0) { - addr = ((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); - 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 group_req gr; - struct sockaddr_in *sin; - - if (!IS_RIP_IN_OFF(ifp->int_state) - && (ifp->int_if_flags & IFF_MULTICAST) - && !(ifp->int_state & IS_ALIAS)) { - memset(&gr, 0, sizeof(gr)); - gr.gr_interface = ifp->int_index; - sin = (struct sockaddr_in *)&gr.gr_group; - sin->sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - if (setsockopt(rip_sock, IPPROTO_IP, MCAST_JOIN_GROUP, - &gr, sizeof(gr)) < 0) - LOGERR("setsockopt(MCAST_JOIN_GROUP 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 != NULL) - rip_mcast_on(ifp); - return; - } - - /* If the main RIP socket is off and it makes sense to turn it on, - * then turn it on for all of the interfaces. - * It makes sense if either router discovery is off, or if - * router discover is on and at most one interface is doing RIP. - */ - if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { - trace_act("turn on RIP"); - - /* Close all of the query sockets so that we can open - * the main socket. SO_REUSEPORT is not a solution, - * since that would let two daemons bind to the broadcast - * socket. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - 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 = NULL; - - /* 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; - - LIST_FOREACH(ifp, &ifnet, int_list) { - ifp->int_query_time = NEVER; - rip_mcast_on(ifp); - } - ifinit_timer.tv_sec = now.tv_sec; - - } else if (ifp != NULL - && !(ifp->int_state & IS_REMOTE) - && ifp->int_rip_sock < 0) { - /* RIP is off, so ensure there are sockets on which - * to listen for queries. - */ - ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); - } - - fix_select(); -} - - -/* die if malloc(3) fails - */ -void * -rtmalloc(size_t size, - const char *msg) -{ - void *p = malloc(size); - if (p == NULL) - logbad(1,"malloc(%lu) failed in %s", (u_long)size, 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 + arc4random_uniform(1 + hi - lo))); - tp->tv_usec = arc4random_uniform(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; - } -} - - -/* put a message into the system log - */ -void -msglog(const char *p, ...) -{ - va_list args; - - trace_flush(); - - va_start(args, p); - vsyslog(LOG_ERR, p, args); - va_end(args); - if (ftrace != NULL) { - if (ftrace == stdout) - (void)fputs("routed: ", ftrace); - va_start(args, p); - (void)vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n', ftrace); - } -} - - -/* Put a message about a bad system into the system log if - * we have not complained about it recently. - * - * It is desirable to complain about all bad systems, but not too often. - * In the worst case, it is not practical to keep track of all bad systems. - * For example, there can be many systems with the wrong password. - */ -void -msglim(struct msg_limit *lim, naddr addr, const char *p, ...) -{ - va_list args; - int i; - struct msg_sub *ms1, *ms; - const char *p1; - - /* look for the oldest slot in the table - * or the slot for the bad router. - */ - ms = ms1 = lim->subs; - for (i = MSG_SUBJECT_N; ; i--, ms1++) { - if (i == 0) { - /* Reuse a slot at most once every 10 minutes. - */ - if (lim->reuse > now.tv_sec) { - ms = NULL; - } else { - ms = ms1; - lim->reuse = now.tv_sec + 10*60; - } - break; - } - if (ms->addr == addr) { - /* Repeat a complaint about a given system at - * most once an hour. - */ - if (ms->until > now.tv_sec) - ms = NULL; - break; - } - if (ms->until < ms1->until) - ms = ms1; - } - if (ms != NULL) { - ms->addr = addr; - ms->until = now.tv_sec + 60*60; /* 60 minutes */ - - trace_flush(); - for (p1 = p; *p1 == ' '; p1++) - continue; - va_start(args, p); - vsyslog(LOG_ERR, p1, args); - va_end(args); - } - - /* always display the message if tracing */ - if (ftrace != NULL) { - va_start(args, p); - (void)vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n', ftrace); - } -} - - -void -logbad(int dump, const char *p, ...) -{ - va_list args; - - trace_flush(); - - va_start(args, p); - vsyslog(LOG_ERR, p, args); - va_end(args); - (void)fputs("routed: ", stderr); - va_start(args, p); - (void)vfprintf(stderr, p, args); - va_end(args); - (void)fputs("; giving up\n",stderr); - (void)fflush(stderr); - - if (dump) - abort(); - exit(1); -} diff --git a/sbin/routed/output.c b/sbin/routed/output.c deleted file mode 100644 --- a/sbin/routed/output.c +++ /dev/null @@ -1,964 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include "defs.h" - -u_int update_seqno; - - -/* walk the tree of routes with this for output - */ -static 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 auth *a; - char metric; /* adjust metrics by interface */ - int npackets; - int gen_limit; - u_int state; -#define WS_ST_FLASH 0x001 /* send only changed routes */ -#define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ -#define WS_ST_AG 0x004 /* ok to aggregate subnets */ -#define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ -#define WS_ST_QUERY 0x010 /* responding to a query */ -#define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ -#define WS_ST_DEFAULT 0x040 /* faking a default */ -} ws; - -/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ -struct ws_buf v12buf; -static union pkt_buf ripv12_buf; - -/* Another for only RIPv2 listeners */ -static struct ws_buf v2buf; -static union pkt_buf rip_v2_buf; - - - -void -bufinit(void) -{ - ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE; - v12buf.buf = &ripv12_buf.rip; - v12buf.base = &v12buf.buf->rip_nets[0]; - - rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE; - rip_v2_buf.rip.rip_vers = RIPv2; - v2buf.buf = &rip_v2_buf.rip; - v2buf.base = &v2buf.buf->rip_nets[0]; -} - - -/* Send the contents of the global buffer via the non-multicast socket - */ -int /* <0 on failure */ -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 osin; - int flags; - const char *msg; - int res; - int soc; - int serrno; - - assert(ifp != NULL); - osin = *dst; - if (osin.sin_port == 0) - osin.sin_port = htons(RIP_PORT); -#ifdef _HAVE_SIN_LEN - if (osin.sin_len == 0) - osin.sin_len = sizeof(osin); -#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|IFF_MULTICAST)) == - IFF_POINTOPOINT) { - msg = "Send pt-to-pt"; - } else if (ifp->int_state & IS_DUP) { - trace_act("abort multicast output via %s" - " with duplicate address", - ifp->int_name); - return 0; - } else { - msg = "Send mcast"; - if (rip_sock_mcast != ifp) { - struct ip_mreqn mreqn; - - memset(&mreqn, 0, sizeof(struct ip_mreqn)); - mreqn.imr_ifindex = ifp->int_index; - if (0 > setsockopt(rip_sock, - IPPROTO_IP, - IP_MULTICAST_IF, - &mreqn, - sizeof(mreqn))) { - serrno = errno; - LOGERR("setsockopt(rip_sock, " - "IP_MULTICAST_IF)"); - errno = serrno; - ifp = NULL; - return -1; - } - rip_sock_mcast = ifp; - } - osin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - } - break; - - case NO_OUT_MULTICAST: - case NO_OUT_RIPV2: - default: -#ifdef DEBUG - abort(); -#endif - return -1; - } - - trace_rip(msg, "to", &osin, ifp, buf, size); - - res = sendto(soc, buf, size, flags, - (struct sockaddr *)&osin, sizeof(osin)); - if (res < 0 - && (ifp == NULL || !(ifp->int_state & IS_BROKE))) { - serrno = errno; - msglog("%s sendto(%s%s%s.%d): %s", msg, - ifp != NULL ? ifp->int_name : "", - ifp != NULL ? ", " : "", - inet_ntoa(osin.sin_addr), - ntohs(osin.sin_port), - strerror(errno)); - errno = serrno; - } - - return res; -} - - -/* Find the first key for a packet to send. - * Try for a key that is eligible and has not expired, but settle for - * the last key if they have all expired. - * If no key is ready yet, give up. - */ -struct auth * -find_auth(struct interface *ifp) -{ - struct auth *ap, *res; - int i; - - - if (ifp == NULL) - return 0; - - res = NULL; - ap = ifp->int_auth; - for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) { - /* stop looking after the last key */ - if (ap->type == RIP_AUTH_NONE) - break; - - /* ignore keys that are not ready yet */ - if ((u_long)ap->start > (u_long)clk.tv_sec) - continue; - - if ((u_long)ap->end < (u_long)clk.tv_sec) { - /* note best expired password as a fall-back */ - if (res == NULL || (u_long)ap->end > (u_long)res->end) - res = ap; - continue; - } - - /* note key with the best future */ - if (res == NULL || (u_long)res->end < (u_long)ap->end) - res = ap; - } - return res; -} - - -void -clr_ws_buf(struct ws_buf *wb, - struct auth *ap) -{ - struct netauth *na; - - wb->lim = wb->base + NETS_LEN; - wb->n = wb->base; - memset(wb->n, 0, NETS_LEN*sizeof(*wb->n)); - - /* (start to) install authentication if appropriate - */ - if (ap == NULL) - return; - - na = (struct netauth*)wb->n; - if (ap->type == RIP_AUTH_PW) { - na->a_family = RIP_AF_AUTH; - na->a_type = RIP_AUTH_PW; - memcpy(na->au.au_pw, ap->key, sizeof(na->au.au_pw)); - wb->n++; - - } else if (ap->type == RIP_AUTH_MD5) { - na->a_family = RIP_AF_AUTH; - na->a_type = RIP_AUTH_MD5; - na->au.a_md5.md5_keyid = ap->keyid; - na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; - na->au.a_md5.md5_seqno = htonl(clk.tv_sec); - wb->n++; - wb->lim--; /* make room for trailer */ - } -} - - -void -end_md5_auth(struct ws_buf *wb, - struct auth *ap) -{ - struct netauth *na, *na2; - MD5_CTX md5_ctx; - int len; - - - na = (struct netauth*)wb->base; - na2 = (struct netauth*)wb->n; - len = (char *)na2-(char *)wb->buf; - na2->a_family = RIP_AF_AUTH; - na2->a_type = htons(1); - na->au.a_md5.md5_pkt_len = htons(len); - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)wb->buf, len + RIP_AUTH_MD5_HASH_XTRA); - MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN); - MD5Final(na2->au.au_pw, &md5_ctx); - wb->n++; -} - - -/* Send the buffer - */ -static void -supply_write(struct ws_buf *wb) -{ - /* Output multicast only if legal. - * If we would multicast and it would be illegal, then discard the - * packet. - */ - switch (wb->type) { - case NO_OUT_MULTICAST: - trace_pkt("skip multicast to %s because impossible", - naddr_ntoa(ws.to.sin_addr.s_addr)); - break; - case NO_OUT_RIPV2: - break; - default: - if (ws.a != NULL && ws.a->type == RIP_AUTH_MD5) - end_md5_auth(wb,ws.a); - if (output(wb->type, &ws.to, ws.ifp, wb->buf, - ((char *)wb->n - (char*)wb->buf)) < 0 - && ws.ifp != NULL) - if_sick(ws.ifp); - ws.npackets++; - break; - } - - clr_ws_buf(wb,ws.a); -} - - -/* put an entry into the packet - */ -static void -supply_out(struct ag_info *ag) -{ - int i; - naddr mask, v1_mask, dst_h, ddst_h = 0; - 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; - - 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); - 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. - */ - if ((ws.state & WS_ST_RIP2_ALL) - || ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { - /* use the RIPv2-only buffer */ - wb = &v2buf; - - } else { - /* use the RIPv1-or-RIPv2 buffer */ - wb = &v12buf; - - /* 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. - */ - if (TRACECONTENTS) - trace_misc("sending %s-->%s as 1" - " instead of %d routes", - addrname(htonl(dst_h), mask, - 1), - naddr_ntoa(ws.to.sin_addr - .s_addr), - i+1); - i = 0; - - } else { - 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); - wb->n->n_metric = htonl(wb->n->n_metric); - /* Any non-zero bits in the supposedly unused RIPv1 fields - * cause the old `routed` to ignore the route. - * That means the mask and so forth cannot be sent - * in the hybrid RIPv1/RIPv2 mode. - */ - if (ws.state & WS_ST_RIP2_ALL) { - if (ag->ag_nhop != 0 - && ((ws.state & WS_ST_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; - 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 *argp UNUSED) -{ -#define RT ((struct rt_entry *)rn) - u_short ags; - char metric, pref; - naddr dst, nhop; - struct rt_spare *rts; - int i; - - - /* Do not advertise external remote interfaces or passive interfaces. - */ - if ((RT->rt_state & RS_IF) - && RT->rt_ifp != 0 - && (RT->rt_ifp->int_state & IS_PASSIVE) - && !(RT->rt_state & RS_MHOME)) - return 0; - - /* If being quiet about our ability to forward, then - * do not say anything unless responding to a query, - * except about our main interface. - */ - if (!supplier && !(ws.state & WS_ST_QUERY) - && !(RT->rt_state & RS_MHOME)) - 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 because 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. - * The final determination is made by supply_out(). - */ - if (!(RT->rt_state & RS_IF) - && RT->rt_gate != myaddr - && RT->rt_gate != loopaddr) - nhop = RT->rt_gate; - else - nhop = 0; - } - - metric = RT->rt_metric; - ags = 0; - - if (RT->rt_state & RS_MHOME) { - /* retain host route of multi-homed servers */ - ; - - } else if (RT_ISHOST(RT)) { - /* We should always suppress (into existing network routes) - * the host routes for the local end of our point-to-point - * links. - * If we are suppressing host routes in general, then do so. - * Avoid advertising host routes onto their own network, - * where they should be handled by proxy-ARP. - */ - if ((RT->rt_state & RS_LOCAL) - || ridhosts - || on_net(dst, ws.to_net, ws.to_mask)) - ags |= AGS_SUPPRESS; - - /* Aggregate stray host routes into network routes if allowed. - * We cannot aggregate host routes into small network routes - * without confusing RIPv1 listeners into thinking the - * network routes are host routes. - */ - if ((ws.state & WS_ST_AG) && (ws.state & WS_ST_RIP2_ALL)) - ags |= AGS_AGGREGATE; - - } else { - /* Always suppress network routes into other, existing - * network routes - */ - 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 ((ws.state & WS_ST_AG) - && ((RT->rt_state & RS_SUBNET) - || (ws.state & WS_ST_SUPER_AG))) - ags |= AGS_AGGREGATE; - } - - /* Do not send RIPv1 advertisements of subnets to other - * 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_AGGREGATE; - - - /* Do not send a route back to where it came from, except in - * response to a query. This is "split-horizon". That means not - * 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 - * suppress the fragmented routes and then itself be forgotten. - * - * Include the routes for both ends of point-to-point interfaces - * among those suppressed by split-horizon, since the other side - * should knows them as well as we do. - * - * Notice spare routes with the same metric that we are about to - * advertise, to split the horizon on redundant, inactive paths. - * - * Do not suppress advertisements of interface-related addresses on - * non-point-to-point interfaces. This ensures that we have something - * to say every 30 seconds to help detect broken Ethernets or - * other interfaces where one packet every 30 seconds costs nothing. - */ - if (ws.ifp != NULL - && !(ws.state & WS_ST_QUERY) - && (ws.state & WS_ST_TO_ON_NET) - && (!(RT->rt_state & RS_IF) - || ws.ifp->int_if_flags & IFF_POINTOPOINT)) { - for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) { - if (rts->rts_metric > metric - || rts->rts_ifp != ws.ifp) - continue; - - /* If we do not mark the route with AGS_SPLIT_HZ here, - * it will be poisoned-reverse, or advertised back - * toward its source with an infinite metric. - * If we have recently advertised the route with a - * better metric than we now have, then we should - * poison-reverse the route before suppressing it for - * split-horizon. - * - * In almost all cases, if there is no spare for the - * route then it is either old and dead or a brand - * new route. If it is brand new, there is no need - * for poison-reverse. If it is old and dead, it - * is already poisoned. - */ - if (RT->rt_poison_time < now_expire - || RT->rt_poison_metric >= metric - || RT->rt_spares[1].rts_gate == 0) { - ags |= AGS_SPLIT_HZ; - ags &= ~AGS_SUPPRESS; - } - metric = HOPCNT_INFINITY; - break; - } - } - - /* Keep track of the best metric with which the - * route has been advertised recently. - */ - if (RT->rt_poison_metric >= metric - || RT->rt_poison_time < now_expire) { - RT->rt_poison_time = now.tv_sec; - RT->rt_poison_metric = metric; - } - - /* Adjust the outgoing metric by the cost of the link. - * Avoid aggregation when a route is counting to infinity. - */ - pref = RT->rt_poison_metric + ws.metric; - metric += ws.metric; - - /* Do not advertise stable routes that will be ignored, - * unless we are answering a query. - * If the route recently was advertised with a metric that - * would have been less than infinity through this interface, - * we need to continue to advertise it in order to poison it. - */ - if (metric >= HOPCNT_INFINITY) { - if (!(ws.state & WS_ST_QUERY) - && (pref >= HOPCNT_INFINITY - || RT->rt_poison_time < now_garbage)) - return 0; - - metric = HOPCNT_INFINITY; - } - - 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 */ - int passwd_ok) /* OK to include cleartext password */ -{ - struct rt_entry *rt; - int def_metric; - - 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 != NULL) { - 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 ((ws.ifp = ifp) == NULL) { - ws.metric = 1; - } else { - /* Adjust the advertised metric by the outgoing interface - * metric. - */ - ws.metric = ifp->int_metric + 1 + ifp->int_adj_outmetric; - } - - ripv12_buf.rip.rip_vers = vers; - - switch (type) { - case OUT_MULTICAST: - if (ifp != NULL && ifp->int_if_flags & IFF_MULTICAST) - v2buf.type = OUT_MULTICAST; - else - v2buf.type = NO_OUT_MULTICAST; - v12buf.type = OUT_BROADCAST; - break; - - case OUT_QUERY: - ws.state |= WS_ST_QUERY; - /* FALLTHROUGH */ - case OUT_BROADCAST: - case OUT_UNICAST: - v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; - v12buf.type = type; - break; - - case NO_OUT_MULTICAST: - case NO_OUT_RIPV2: - break; /* no output */ - } - - if (vers == RIPv2) { - /* full RIPv2 only if cannot be heard by RIPv1 listeners */ - if (type != OUT_BROADCAST) - ws.state |= WS_ST_RIP2_ALL; - if ((ws.state & WS_ST_QUERY) - || !(ws.state & WS_ST_TO_ON_NET)) { - ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); - } else if (ifp == NULL || !(ifp->int_state & IS_NO_AG)) { - ws.state |= WS_ST_AG; - if (type != OUT_BROADCAST - && (ifp == NULL - || !(ifp->int_state & IS_NO_SUPER_AG))) - ws.state |= WS_ST_SUPER_AG; - } - } - - ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; - if (!passwd_ok && ws.a != NULL && ws.a->type == RIP_AUTH_PW) - ws.a = NULL; - clr_ws_buf(&v12buf,ws.a); - clr_ws_buf(&v2buf,ws.a); - - /* Fake a default route if asked and if there is not already - * a better, real default route. - */ - if (supplier && ifp && (def_metric = ifp->int_d_metric) != 0) { - if ((rt = rtget(RIP_DEFAULT, 0)) == NULL - || rt->rt_metric+ws.metric >= def_metric) { - ws.state |= WS_ST_DEFAULT; - ag_check(0, 0, 0, 0, def_metric, def_metric, - 0, 0, 0, supply_out); - } else { - def_metric = rt->rt_metric+ws.metric; - } - - /* If both RIPv2 and the poor-man's router discovery - * kludge are on, arrange to advertise an extra - * default route via RIPv1. - */ - if ((ws.state & WS_ST_RIP2_ALL) - && (ifp->int_state & IS_PM_RDISC)) { - ripv12_buf.rip.rip_vers = RIPv1; - v12buf.n->n_family = RIP_AF_INET; - v12buf.n->n_dst = htonl(RIP_DEFAULT); - v12buf.n->n_metric = htonl(def_metric); - v12buf.n++; - } - } - - (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 (v12buf.n != v12buf.base - && (v12buf.n > v12buf.base+1 - || v12buf.base->n_family != RIP_AF_AUTH)) - supply_write(&v12buf); - if (v2buf.n != v2buf.base - && (v2buf.n > v2buf.base+1 - || v2buf.base->n_family != RIP_AF_AUTH)) - supply_write(&v2buf); - - /* If we sent nothing and this is an answer to a query, send - * an empty buffer. - */ - if (ws.npackets == 0 - && (ws.state & WS_ST_QUERY)) - supply_write(&v12buf); -} - - -/* 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, 0, {0}, {0}}; -#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", - flash ? "dynamic update" : "all routes", - rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0); - - LIST_FOREACH(ifp, &ifnet, int_list) { - /* Skip interfaces not doing RIP. - * Do try broken interfaces to see if they have healed. - */ - if (IS_RIP_OUT_OFF(ifp->int_state)) - continue; - - /* skip turned off interfaces */ - if (!iff_up(ifp->int_if_flags)) - continue; - - vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; - - if (ifp->int_if_flags & IFF_BROADCAST) { - /* ordinary, hardware interface */ - dst.sin_addr.s_addr = ifp->int_brdaddr; - - if (vers == RIPv2 - && !(ifp->int_state & IS_NO_RIP_MCAST)) { - 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; - if (vers == RIPv2 && - ifp->int_if_flags & IFF_MULTICAST && - !(ifp->int_state & IS_NO_RIP_MCAST)) { - type = OUT_MULTICAST; - } else { - type = OUT_UNICAST; - } - - } else if (ifp->int_state & IS_REMOTE) { - /* remote interface */ - dst.sin_addr.s_addr = ifp->int_addr; - type = OUT_UNICAST; - - } else { - /* ATM, HIPPI, etc. */ - continue; - } - - supply(&dst, ifp, type, flash, vers, 1); - } - - 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, 0, {0}, {0}}; -#else - static struct sockaddr_in dst = {AF_INET}; -#endif - struct interface *ifp; - struct rip buf; - enum output_type type; - - - if (rip_sock < 0) - return; - - memset(&buf, 0, sizeof(buf)); - - LIST_FOREACH(ifp, &ifnet, int_list) { - /* Skip interfaces those already queried. - * Do not ask via interfaces through which we don't - * accept input. Do not ask via interfaces that cannot - * send RIP packets. - * Do try broken interfaces to see if they have healed. - */ - if (IS_RIP_IN_OFF(ifp->int_state) - || ifp->int_query_time != NEVER) - continue; - - /* skip turned off interfaces */ - if (!iff_up(ifp->int_if_flags)) - continue; - - buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1; - buf.rip_cmd = RIPCMD_REQUEST; - buf.rip_nets[0].n_family = RIP_AF_UNSPEC; - buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); - - /* Send a RIPv1 query only if allowed and if we will - * listen to RIPv1 routers. - */ - if ((ifp->int_state & IS_NO_RIPV1_OUT) - || (ifp->int_state & IS_NO_RIPV1_IN)) { - buf.rip_vers = RIPv2; - } else { - buf.rip_vers = RIPv1; - } - - if (ifp->int_if_flags & IFF_BROADCAST) { - /* ordinary, hardware interface */ - dst.sin_addr.s_addr = ifp->int_brdaddr; - - /* Broadcast RIPv1 queries and RIPv2 queries - * when the hardware cannot multicast. - */ - if (buf.rip_vers == RIPv2 - && (ifp->int_if_flags & IFF_MULTICAST) - && !(ifp->int_state & IS_NO_RIP_MCAST)) { - 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 if (ifp->int_state & IS_REMOTE) { - /* remote interface */ - dst.sin_addr.s_addr = ifp->int_addr; - type = OUT_UNICAST; - - } else { - /* ATM, HIPPI, etc. */ - continue; - } - - ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL; - if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0) - if_sick(ifp); - } -} diff --git a/sbin/routed/parms.c b/sbin/routed/parms.c deleted file mode 100644 --- a/sbin/routed/parms.c +++ /dev/null @@ -1,1034 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include "defs.h" -#include "pathnames.h" -#include - -static struct parm *parms; -struct intnet *intnets; -struct r1net *r1nets; -struct tgate *tgates; - - -/* use configured parameters - */ -void -get_parms(struct interface *ifp) -{ - static int warned_auth_in, warned_auth_out; - struct parm *parmp; - int i, num_passwds = 0; - - /* get all relevant parameters - */ - for (parmp = parms; parmp != NULL; parmp = parmp->parm_next) { - if (parmp->parm_name[0] == '\0' - || !strcmp(ifp->int_name, parmp->parm_name) - || (parmp->parm_name[0] == '\n' - && on_net(ifp->int_addr, - parmp->parm_net, parmp->parm_mask))) { - - /* This group of parameters is relevant, - * so get its settings - */ - ifp->int_state |= parmp->parm_int_state; - for (i = 0; i < MAX_AUTH_KEYS; i++) { - if (parmp->parm_auth[0].type == RIP_AUTH_NONE - || num_passwds >= MAX_AUTH_KEYS) - break; - memcpy(&ifp->int_auth[num_passwds++], - &parmp->parm_auth[i], - sizeof(ifp->int_auth[0])); - } - if (parmp->parm_rdisc_pref != 0) - ifp->int_rdisc_pref = parmp->parm_rdisc_pref; - if (parmp->parm_rdisc_int != 0) - ifp->int_rdisc_int = parmp->parm_rdisc_int; - if (parmp->parm_adj_inmetric != 0) - ifp->int_adj_inmetric = parmp->parm_adj_inmetric; - if (parmp->parm_adj_outmetric != 0) - ifp->int_adj_outmetric = parmp->parm_adj_outmetric; - } - } - - /* Set general defaults. - * - * Default poor-man's router discovery to a metric that will - * be heard by old versions of `routed`. They ignored received - * routes with metric 15. - */ - if ((ifp->int_state & IS_PM_RDISC) - && ifp->int_d_metric == 0) - ifp->int_d_metric = FAKE_METRIC; - - if (ifp->int_rdisc_int == 0) - ifp->int_rdisc_int = DefMaxAdvertiseInterval; - - if (!(ifp->int_if_flags & IFF_MULTICAST) - && !(ifp->int_state & IS_REMOTE)) - ifp->int_state |= IS_BCAST_RDISC; - - if (ifp->int_if_flags & IFF_POINTOPOINT) { - ifp->int_state |= IS_BCAST_RDISC; - /* By default, point-to-point links should be passive - * about router-discovery for the sake of demand-dialing. - */ - if (0 == (ifp->int_state & GROUP_IS_SOL_OUT)) - ifp->int_state |= IS_NO_SOL_OUT; - if (0 == (ifp->int_state & GROUP_IS_ADV_OUT)) - ifp->int_state |= IS_NO_ADV_OUT; - } - - if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE))) - ifp->int_state |= IS_NO_RDISC; - if (ifp->int_state & IS_PASSIVE) - ifp->int_state |= IS_NO_RIP; - - if (!IS_RIP_IN_OFF(ifp->int_state) - && ifp->int_auth[0].type != RIP_AUTH_NONE - && !(ifp->int_state & IS_NO_RIPV1_IN) - && !warned_auth_in) { - msglog("Warning: RIPv1 input via %s" - " will be accepted without authentication", - ifp->int_name); - warned_auth_in = 1; - } - if (!IS_RIP_OUT_OFF(ifp->int_state) - && ifp->int_auth[0].type != RIP_AUTH_NONE - && !(ifp->int_state & IS_NO_RIPV1_OUT)) { - if (!warned_auth_out) { - msglog("Warning: RIPv1 output via %s" - " will be sent without authentication", - ifp->int_name); - warned_auth_out = 1; - } - } -} - - -/* 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; - const char *cp; - char lbuf[200], net_host[5], dname[64+1+64+1]; - char gname[GNAME_LEN+1], qual[9]; - struct interface *ifp; - naddr dst, netmask, gate; - int metric, n, lnum; - struct stat sb; - u_int state; - const char *type; - - - fp = fopen(_PATH_GATEWAYS, "r"); - if (fp == NULL) - return; - - if (0 > fstat(fileno(fp), &sb)) { - msglog("could not stat() "_PATH_GATEWAYS); - (void)fclose(fp); - return; - } - - for (lnum = 1; ; lnum++) { - if (fgets(lbuf, sizeof(lbuf), fp) == NULL) - break; - lptr = lbuf; - while (*lptr == ' ') - lptr++; - p = lptr+strlen(lptr)-1; - while (*p == '\n' - || (*p == ' ' && (p == lptr+1 || *(p-1) != '\\'))) - *p-- = '\0'; - if (*lptr == '\0' /* ignore null and comment lines */ - || *lptr == '#') - continue; - - /* notice newfangled parameter lines - */ - if (strncasecmp("net", lptr, 3) - && strncasecmp("host", lptr, 4)) { - cp = parse_parms(lptr, - (sb.st_uid == 0 - && !(sb.st_mode&(S_IRWXG|S_IRWXO)))); - if (cp != NULL) - msglog("%s in line %d of "_PATH_GATEWAYS, - cp, lnum); - continue; - } - -/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */ - qual[0] = '\0'; - /* the '64' here must be GNAME_LEN */ - n = sscanf(lptr, "%4s %129[^ \t] gateway" - " %64[^ / \t] metric %u %8s\n", - net_host, dname, gname, &metric, qual); - if (n != 4 && n != 5) { - msglog("bad "_PATH_GATEWAYS" entry \"%s\"; %d values", - lptr, n); - continue; - } - if (metric >= HOPCNT_INFINITY) { - msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"", - lptr); - continue; - } - if (!strcasecmp(net_host, "host")) { - if (!gethost(dname, &dst)) { - msglog("bad host \"%s\" in "_PATH_GATEWAYS - " entry \"%s\"", dname, lptr); - continue; - } - netmask = HOST_MASK; - } else if (!strcasecmp(net_host, "net")) { - if (!getnet(dname, &dst, &netmask)) { - msglog("bad net \"%s\" in "_PATH_GATEWAYS - " entry \"%s\"", dname, lptr); - continue; - } - if (dst == RIP_DEFAULT) { - msglog("bad net \"%s\" in "_PATH_GATEWAYS - " entry \"%s\"--cannot be default", - dname, lptr); - continue; - } - /* Turn network # into IP address. */ - dst = htonl(dst); - } else { - msglog("bad \"%s\" in "_PATH_GATEWAYS - " entry \"%s\"", net_host, lptr); - continue; - } - - if (!gethost(gname, &gate)) { - msglog("bad gateway \"%s\" in "_PATH_GATEWAYS - " entry \"%s\"", gname, lptr); - continue; - } - - if (!strcasecmp(qual, type = "passive")) { - /* Passive entries are not placed in our tables, - * only the kernel's, so we don't copy all of the - * external routing information within a net. - * 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 (!strcasecmp(qual, type = "external")) { - /* External entries are handled by other means - * such as EGP, and are placed only in the daemon - * tables to prevent overriding them with something - * else. - */ - strcpy(qual,"external"); - state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL; - if (metric == 0) - metric = 1; - - } else if (!strcasecmp(qual, "active") - || 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 | IS_ALIAS; - type = "alias"; - } - - } else { - msglog("bad "_PATH_GATEWAYS" entry \"%s\";" - " unknown type %s", lptr, qual); - continue; - } - - if (0 != (state & (IS_PASSIVE | IS_REMOTE))) - state |= IS_NO_RDISC; - if (state & IS_PASSIVE) - state |= IS_NO_RIP; - - ifp = check_dup(gate,dst,netmask,state); - if (ifp != NULL) { - msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr); - continue; - } - - ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge()"); - memset(ifp, 0, sizeof(*ifp)); - - ifp->int_state = state; - if (netmask == HOST_MASK) - ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP; - else - ifp->int_if_flags = IFF_UP; - ifp->int_act_time = NEVER; - ifp->int_addr = gate; - ifp->int_dstaddr = dst; - ifp->int_mask = netmask; - ifp->int_ripv1_mask = netmask; - ifp->int_std_mask = std_mask(gate); - ifp->int_net = ntohl(dst); - ifp->int_std_net = ifp->int_net & ifp->int_std_mask; - ifp->int_std_addr = htonl(ifp->int_std_net); - ifp->int_metric = metric; - if (!(state & IS_EXTERNAL) - && ifp->int_mask != ifp->int_std_mask) - ifp->int_state |= IS_SUBNET; - (void)sprintf(ifp->int_name, "%s(%s)", type, gname); - ifp->int_index = -1; - - if_link(ifp); - } - - /* After all of the parameter lines have been read, - * apply them to any remote interfaces. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - get_parms(ifp); - - tot_interfaces++; - if (!IS_RIP_OFF(ifp->int_state)) - rip_interfaces++; - - trace_if("Add", ifp); - } - - (void)fclose(fp); -} - - -/* like strtok(), but honoring backslash and not changing the source string - */ -static int /* 0=ok, -1=bad */ -parse_quote(char **linep, /* look here */ - const char *delims, /* for these delimiters */ - char *delimp, /* 0 or put found delimiter here */ - char *buf, /* copy token to here */ - int lim) /* at most this many bytes */ -{ - char c = '\0', *pc; - const char *p; - - - pc = *linep; - if (*pc == '\0') - return -1; - - while (lim != 0) { - c = *pc++; - if (c == '\0') - break; - - if (c == '\\' && *pc != '\0') { - if ((c = *pc++) == 'n') { - c = '\n'; - } else if (c == 'r') { - c = '\r'; - } else if (c == 't') { - c = '\t'; - } else if (c == 'b') { - c = '\b'; - } else if (c >= '0' && c <= '7') { - c -= '0'; - if (*pc >= '0' && *pc <= '7') { - c = (c<<3)+(*pc++ - '0'); - if (*pc >= '0' && *pc <= '7') - c = (c<<3)+(*pc++ - '0'); - } - } - - } else { - for (p = delims; *p != '\0'; ++p) { - if (*p == c) - goto exit; - } - } - - *buf++ = c; - --lim; - } -exit: - if (lim == 0) - return -1; - - *buf = '\0'; /* terminate copy of token */ - if (delimp != NULL) - *delimp = c; /* return delimiter */ - *linep = pc-1; /* say where we ended */ - return 0; -} - - -/* Parse password timestamp - */ -static char * -parse_ts(time_t *tp, - char **valp, - char *val0, - char *delimp, - char *buf, - u_int bufsize) -{ - struct tm tm; - char *ptr; - - if (0 > parse_quote(valp, "| ,\n\r", delimp, - buf,bufsize) - || buf[bufsize-1] != '\0' - || buf[bufsize-2] != '\0') { - sprintf(buf,"bad timestamp %.25s", val0); - return buf; - } - strcat(buf,"\n"); - memset(&tm, 0, sizeof(tm)); - ptr = strptime(buf, "%y/%m/%d@%H:%M\n", &tm); - if (ptr == NULL || *ptr != '\0') { - sprintf(buf,"bad timestamp %.25s", val0); - return buf; - } - - if ((*tp = mktime(&tm)) == -1) { - sprintf(buf,"bad timestamp %.25s", val0); - return buf; - } - - return 0; -} - - -/* Get a password, key ID, and expiration date in the format - * passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min - */ -static const char * /* 0 or error message */ -get_passwd(char *tgt, - char *val, - struct parm *parmp, - u_int16_t type, - int safe) /* 1=from secure file */ -{ - static char buf[80]; - char *val0, *p, delim; - struct auth k, *ap, *ap2; - int i; - u_long l; - - assert(val != NULL); - if (!safe) - return "ignore unsafe password"; - - for (ap = parmp->parm_auth, i = 0; - ap->type != RIP_AUTH_NONE; i++, ap++) { - if (i >= MAX_AUTH_KEYS) - return "too many passwords"; - } - - memset(&k, 0, sizeof(k)); - k.type = type; - k.end = -1-DAY; - - val0 = val; - if (0 > parse_quote(&val, "| ,\n\r", &delim, - (char *)k.key, sizeof(k.key))) - return tgt; - - if (delim != '|') { - if (type == RIP_AUTH_MD5) - return "missing Keyid"; - } else { - val0 = ++val; - buf[sizeof(buf)-1] = '\0'; - if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf)) - || buf[sizeof(buf)-1] != '\0' - || (l = strtoul(buf,&p,0)) > 255 - || *p != '\0') { - sprintf(buf,"bad KeyID \"%.20s\"", val0); - return buf; - } - for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) { - if (ap2->keyid == l) { - sprintf(buf,"duplicate KeyID \"%.20s\"", val0); - return buf; - } - } - k.keyid = (int)l; - - if (delim == '|') { - val0 = ++val; - if (NULL != (p = parse_ts(&k.start,&val,val0,&delim, - buf,sizeof(buf)))) - return p; - if (delim != '|') - return "missing second timestamp"; - val0 = ++val; - if (NULL != (p = parse_ts(&k.end,&val,val0,&delim, - buf,sizeof(buf)))) - return p; - if ((u_long)k.start > (u_long)k.end) { - sprintf(buf,"out of order timestamp %.30s", - val0); - return buf; - } - } - } - if (delim != '\0') - return tgt; - - memmove(ap, &k, sizeof(*ap)); - return 0; -} - - -static const char * -bad_str(const char *estr) -{ - static char buf[100+8]; - - sprintf(buf, "bad \"%.100s\"", estr); - return buf; -} - - -/* Parse a set of parameters for an interface. - */ -const char * /* 0 or error message */ -parse_parms(char *line, - int safe) /* 1=from secure file */ -{ -#define PARS(str) (!strcasecmp(tgt, str)) -#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str))) -#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \ - parm.parm_int_state |= (b);} - struct parm parm; - struct intnet *intnetp; - struct r1net *r1netp; - struct tgate *tg; - naddr addr, mask; - char delim, *val0 = NULL, *tgt, *val, *p; - const char *msg; - char buf[BUFSIZ], buf2[BUFSIZ]; - int i; - - - /* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */ - if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1) - && *(val = &line[sizeof("subnet=")-1]) != '\0') { - if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))) - return bad_str(line); - intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp), - "parse_parms subnet"); - intnetp->intnet_metric = 1; - if (delim == ',') { - intnetp->intnet_metric = (int)strtol(val+1,&p,0); - if (*p != '\0' - || intnetp->intnet_metric <= 0 - || intnetp->intnet_metric >= HOPCNT_INFINITY) { - free(intnetp); - return bad_str(line); - } - } - if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask) - || intnetp->intnet_mask == HOST_MASK - || intnetp->intnet_addr == RIP_DEFAULT) { - free(intnetp); - return bad_str(line); - } - intnetp->intnet_addr = htonl(intnetp->intnet_addr); - intnetp->intnet_next = intnets; - intnets = intnetp; - return 0; - } - - /* "ripv1_mask=x.y.z.u/mask1,mask2" must be alone on the line. - * This requires that x.y.z.u/mask1 be considered a subnet of - * x.y.z.u/mask2, as if x.y.z.u/mask2 were a class-full network. - */ - if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1) - && *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') { - if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)) - || delim == '\0') - return bad_str(line); - if ((i = (int)strtol(val+1, &p, 0)) <= 0 - || i > 32 || *p != '\0') - return bad_str(line); - r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp), - "parse_parms ripv1_mask"); - r1netp->r1net_mask = HOST_MASK << (32-i); - if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match) - || r1netp->r1net_net == RIP_DEFAULT - || r1netp->r1net_mask > r1netp->r1net_match) { - free(r1netp); - return bad_str(line); - } - r1netp->r1net_next = r1nets; - r1nets = r1netp; - return 0; - } - - memset(&parm, 0, sizeof(parm)); - - for (;;) { - tgt = line + strspn(line, " ,\n\r"); - if (*tgt == '\0' || *tgt == '#') - break; - line = tgt+strcspn(tgt, "= #,\n\r"); - delim = *line; - if (delim == '=') { - val0 = ++line; - if (0 > parse_quote(&line, " #,\n\r",&delim, - buf,sizeof(buf))) - return bad_str(tgt); - } else { - val0 = NULL; - } - if (delim != '\0') { - for (;;) { - *line = '\0'; - if (delim == '#') - break; - ++line; - if (delim != ' ' - || (delim = *line) != ' ') - break; - } - } - - if (PARSEQ("if")) { - if (parm.parm_name[0] != '\0' - || strlen(buf) > IF_NAME_LEN) - return bad_str(tgt); - strcpy(parm.parm_name, buf); - - } else if (PARSEQ("addr")) { - /* This is a bad idea, because the address based - * sets of parameters cannot be checked for - * consistency with the interface name parameters. - * The parm_net stuff is needed to allow several - * -F settings. - */ - if (val0 == NULL || !getnet(val0, &addr, &mask) - || parm.parm_name[0] != '\0') - return bad_str(tgt); - parm.parm_net = addr; - parm.parm_mask = mask; - parm.parm_name[0] = '\n'; - - } else if (PARSEQ("passwd")) { - /* since cleartext passwords are so weak allow - * them anywhere - */ - if (val0 == NULL) - return bad_str("no passwd"); - msg = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1); - if (msg) { - *val0 = '\0'; - return bad_str(msg); - } - - } else if (PARSEQ("md5_passwd")) { - msg = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe); - if (msg) { - *val0 = '\0'; - return bad_str(msg); - } - - } else if (PARS("no_ag")) { - parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG); - - } else if (PARS("no_super_ag")) { - parm.parm_int_state |= IS_NO_SUPER_AG; - - } else if (PARS("no_rip_out")) { - parm.parm_int_state |= IS_NO_RIP_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("ripv2_out")) { - if (parm.parm_int_state & IS_NO_RIPV2_OUT) - return bad_str(tgt); - parm.parm_int_state |= IS_NO_RIPV1_OUT; - - } else if (PARS("ripv2")) { - if ((parm.parm_int_state & IS_NO_RIPV2_OUT) - || (parm.parm_int_state & IS_NO_RIPV2_IN)) - return bad_str(tgt); - parm.parm_int_state |= (IS_NO_RIPV1_IN - | IS_NO_RIPV1_OUT); - - } else if (PARS("no_rip")) { - CKF(IS_PM_RDISC, IS_NO_RIP); - - } else if (PARS("no_rip_mcast")) { - parm.parm_int_state |= IS_NO_RIP_MCAST; - - } else if (PARS("no_rdisc")) { - CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC); - - } else if (PARS("no_solicit")) { - CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT); - - } else if (PARS("send_solicit")) { - CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT); - - } else if (PARS("no_rdisc_adv")) { - CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT); - - } else if (PARS("rdisc_adv")) { - CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT); - - } else if (PARS("bcast_rdisc")) { - parm.parm_int_state |= IS_BCAST_RDISC; - - } else if (PARS("passive")) { - CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC); - parm.parm_int_state |= IS_NO_RIP | IS_PASSIVE; - - } else if (PARSEQ("rdisc_pref")) { - if (parm.parm_rdisc_pref != 0 - || (parm.parm_rdisc_pref = (int)strtol(buf,&p,0), - *p != '\0')) - return bad_str(tgt); - - } else if (PARS("pm_rdisc")) { - if (IS_RIP_OUT_OFF(parm.parm_int_state)) - return bad_str(tgt); - parm.parm_int_state |= IS_PM_RDISC; - - } else if (PARSEQ("rdisc_interval")) { - if (parm.parm_rdisc_int != 0 - || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0), - *p != '\0') - || parm.parm_rdisc_int < MinMaxAdvertiseInterval - || parm.parm_rdisc_int > MaxMaxAdvertiseInterval) - return bad_str(tgt); - - } else if (PARSEQ("fake_default")) { - if (parm.parm_d_metric != 0 - || IS_RIP_OUT_OFF(parm.parm_int_state) - || (i = strtoul(buf,&p,0), *p != '\0') - || i > HOPCNT_INFINITY-1) - return bad_str(tgt); - parm.parm_d_metric = i; - - } else if (PARSEQ("adj_inmetric")) { - if (parm.parm_adj_inmetric != 0 - || (i = strtoul(buf,&p,0), *p != '\0') - || i > HOPCNT_INFINITY-1) - return bad_str(tgt); - parm.parm_adj_inmetric = i; - - } else if (PARSEQ("adj_outmetric")) { - if (parm.parm_adj_outmetric != 0 - || (i = strtoul(buf,&p,0), *p != '\0') - || i > HOPCNT_INFINITY-1) - return bad_str(tgt); - parm.parm_adj_outmetric = i; - - } else if (PARSEQ("trust_gateway")) { - /* look for trust_gateway=x.y.z|net/mask|...) */ - p = buf; - if (0 > parse_quote(&p, "|", &delim, - buf2, sizeof(buf2)) - || !gethost(buf2,&addr)) - return bad_str(tgt); - tg = (struct tgate *)rtmalloc(sizeof(*tg), - "parse_parms" - "trust_gateway"); - memset(tg, 0, sizeof(*tg)); - tg->tgate_addr = addr; - i = 0; - /* The default is to trust all routes. */ - while (delim == '|') { - p++; - if (i >= MAX_TGATE_NETS - || 0 > parse_quote(&p, "|", &delim, - buf2, sizeof(buf2)) - || !getnet(buf2, &tg->tgate_nets[i].net, - &tg->tgate_nets[i].mask) - || tg->tgate_nets[i].net == RIP_DEFAULT - || tg->tgate_nets[i].mask == 0) { - free(tg); - return bad_str(tgt); - } - i++; - } - tg->tgate_next = tgates; - tgates = tg; - parm.parm_int_state |= IS_DISTRUST; - - } else if (PARS("redirect_ok")) { - parm.parm_int_state |= IS_REDIRECT_OK; - - } else { - return bad_str(tgt); /* error */ - } - } - - return check_parms(&parm); -#undef PARS -#undef PARSEQ -} - - -/* check for duplicate parameter specifications */ -const char * /* 0 or error message */ -check_parms(struct parm *new) -{ - struct parm *parmp, **parmpp; - int i, num_passwds; - - /* set implicit values - */ - if (new->parm_int_state & IS_NO_ADV_IN) - new->parm_int_state |= IS_NO_SOL_OUT; - if (new->parm_int_state & IS_NO_SOL_OUT) - new->parm_int_state |= IS_NO_ADV_IN; - - for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) { - if (new->parm_auth[i].type != RIP_AUTH_NONE) - num_passwds++; - } - - /* compare with existing sets of parameters - */ - for (parmpp = &parms; - (parmp = *parmpp) != NULL; - parmpp = &parmp->parm_next) { - if (strcmp(new->parm_name, parmp->parm_name)) - continue; - if (!on_net(htonl(parmp->parm_net), - new->parm_net, new->parm_mask) - && !on_net(htonl(new->parm_net), - parmp->parm_net, parmp->parm_mask)) - continue; - - for (i = 0; i < MAX_AUTH_KEYS; i++) { - if (parmp->parm_auth[i].type != RIP_AUTH_NONE) - num_passwds++; - } - if (num_passwds > MAX_AUTH_KEYS) - return "too many conflicting passwords"; - - if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT) - && 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT) - && 0 != ((new->parm_int_state ^ parmp->parm_int_state) - & GROUP_IS_SOL_OUT)) - || (0 != (new->parm_int_state & GROUP_IS_ADV_OUT) - && 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT) - && 0 != ((new->parm_int_state ^ parmp->parm_int_state) - & GROUP_IS_ADV_OUT)) - || (new->parm_rdisc_pref != 0 - && parmp->parm_rdisc_pref != 0 - && new->parm_rdisc_pref != parmp->parm_rdisc_pref) - || (new->parm_rdisc_int != 0 - && parmp->parm_rdisc_int != 0 - && new->parm_rdisc_int != parmp->parm_rdisc_int)) { - return ("conflicting, duplicate router discovery" - " parameters"); - - } - - if (new->parm_d_metric != 0 - && parmp->parm_d_metric != 0 - && new->parm_d_metric != parmp->parm_d_metric) { - return ("conflicting, duplicate poor man's router" - " discovery or fake default metric"); - } - - if (new->parm_adj_inmetric != 0 - && parmp->parm_adj_inmetric != 0 - && new->parm_adj_inmetric != parmp->parm_adj_inmetric) { - return ("conflicting interface input " - "metric adjustments"); - } - - if (new->parm_adj_outmetric != 0 - && parmp->parm_adj_outmetric != 0 - && new->parm_adj_outmetric != parmp->parm_adj_outmetric) { - return ("conflicting interface output " - "metric adjustments"); - } - } - - /* link new entry on the list so that when the entries are scanned, - * they affect the result in the order the operator specified. - */ - parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms"); - memcpy(parmp, new, sizeof(*parmp)); - *parmpp = parmp; - - return 0; -} - - -/* get a network number as a name or a number, with an optional "/xx" - * netmask. - */ -int /* 0=bad */ -getnet(char *name, - naddr *netp, /* network in host byte order */ - naddr *maskp) /* masks are always in host order */ -{ - int i; - struct netent *np; - naddr mask; /* in host byte order */ - struct in_addr in; /* a network and so host byte order */ - char hname[MAXHOSTNAMELEN+1]; - char *mname, *p; - - - /* Detect and separate "1.2.3.4/24" - */ - if (NULL != (mname = strrchr(name,'/'))) { - i = (int)(mname - name); - if (i > (int)sizeof(hname)-1) /* name too long */ - return 0; - memmove(hname, name, i); - hname[i] = '\0'; - mname++; - name = hname; - } - - np = getnetbyname(name); - if (np != NULL) { - in.s_addr = (naddr)np->n_net; - if (0 == (in.s_addr & 0xff000000)) - in.s_addr <<= 8; - if (0 == (in.s_addr & 0xff000000)) - in.s_addr <<= 8; - if (0 == (in.s_addr & 0xff000000)) - in.s_addr <<= 8; - } else if (inet_aton(name, &in) == 1) { - in.s_addr = ntohl(in.s_addr); - } else if (!mname && !strcasecmp(name,"default")) { - in.s_addr = RIP_DEFAULT; - } else { - return 0; - } - - if (!mname) { - /* we cannot use the interfaces here because we have not - * looked at them yet. - */ - mask = std_mask(htonl(in.s_addr)); - if ((~mask & in.s_addr) != 0) - mask = HOST_MASK; - } else { - mask = (naddr)strtoul(mname, &p, 0); - if (*p != '\0' || mask > 32) - return 0; - if (mask != 0) - mask = HOST_MASK << (32-mask); - } - - /* must have mask of 0 with default */ - if (mask != 0 && in.s_addr == RIP_DEFAULT) - return 0; - /* no host bits allowed in a network number */ - if ((~mask & in.s_addr) != 0) - return 0; - /* require non-zero network number */ - if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT) - return 0; - if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT) - return 0; - if (in.s_addr>>24 == 0xff) - return 0; - - *netp = 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) { - /* get a good number, but check that it makes some - * sense. - */ - if (ntohl(in.s_addr)>>24 == 0 - || ntohl(in.s_addr)>>24 == 0xff) - return 0; - *addrp = in.s_addr; - return 1; - } - - hp = gethostbyname(name); - if (hp) { - memcpy(addrp, hp->h_addr, sizeof(*addrp)); - return 1; - } - - return 0; -} diff --git a/sbin/routed/pathnames.h b/sbin/routed/pathnames.h deleted file mode 100644 --- a/sbin/routed/pathnames.h +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#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. However, if bad guys can write in the - * default value, /etc, you have far worse security problems than anything - * this might do. In other words, it makes no sense to turn this off. - * - * Leave this undefined, and only the trace file originally specified - * when routed was started, if any, will be appended to. - */ -#define _PATH_TRACE "/etc/routed.trace" diff --git a/sbin/routed/radix.h b/sbin/routed/radix.h deleted file mode 100644 --- a/sbin/routed/radix.h +++ /dev/null @@ -1,143 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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 __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. - */ - -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 */ -}; - -#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 \ - m = (struct radix_mask *)rtmalloc(sizeof(*(m)), "MKGet"); }\ - -#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 */ - (void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[]); - struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ - (void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[]); - struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ - (void *v, struct radix_node_head *head); - struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ - (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 Bcopy(a, b, n) memmove(((void *)(b)), ((void *)(a)), (size_t)(n)) -#define Bzero(p, n) memset((void *)(p), 0, (size_t)(n)); -#define Free(p) free((void *)p); - -void rn_init(void); -int rn_inithead(struct radix_node_head **head, int off); -int rn_walktree(struct radix_node_head *, - int (*)(struct radix_node *, struct walkarg *), - struct walkarg *); - -#endif /* __RADIX_H_ */ diff --git a/sbin/routed/radix.c b/sbin/routed/radix.c deleted file mode 100644 --- a/sbin/routed/radix.c +++ /dev/null @@ -1,886 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -/* - * Routines to build and maintain radix trees for routing lookups. - */ - -#include "defs.h" -#define log(x, msg) syslog(x, msg) -#define panic(s) {log(LOG_ERR,s); exit(1);} -#define min(a,b) (((a)<(b))?(a):(b)) - -int max_keylen; -static struct radix_mask *rn_mkfreelist; -static struct radix_node_head *mask_rnhead; -static char *addmask_key; -static const uint8_t normal_chars[] = - { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; -static char *rn_zeros, *rn_ones; - -#define rn_masktop (mask_rnhead->rnh_treetop) -#define Bcmp(a, b, l) (l == 0 ? 0 \ - : memcmp((caddr_t)(a), (caddr_t)(b), (size_t)l)) - -static int rn_satisfies_leaf(char *, struct radix_node *, int); -static struct radix_node *rn_addmask(void *n_arg, int search, int skip); -static struct radix_node *rn_addroute(void *v_arg, void *n_arg, - struct radix_node_head *head, struct radix_node treenodes[2]); -static struct radix_node *rn_match(void *v_arg, struct radix_node_head *head); - -/* - * 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 explicit mask and compare operation when testing whether - * a key satisfies a normal route, and also in remembering the unique leaf - * that governs a subtree. - */ - -static struct radix_node * -rn_search(void *v_arg, - struct radix_node *head) -{ - struct radix_node *x; - 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); -} - -static struct radix_node * -rn_search_m(void *v_arg, - struct radix_node *head, - void *m_arg) -{ - struct radix_node *x; - 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; -} - -static int -rn_refines(void* m_arg, void *n_arg) -{ - caddr_t m = m_arg, n = n_arg; - 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); -} - -static struct radix_node * -rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) -{ - struct radix_node *x; - caddr_t netmask = 0; - - if (m_arg) { - if ((x = rn_addmask(m_arg, 1, - head->rnh_treetop->rn_off)) == NULL) - 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_satisfies_leaf(char *trial, - struct radix_node *leaf, - int skip) -{ - char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; - char *cplim; - int length = min(*(u_char *)cp, *(u_char *)cp2); - - if (cp3 == NULL) - 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; -} - -static struct radix_node * -rn_match(void *v_arg, - struct radix_node_head *head) -{ - caddr_t v = v_arg; - struct radix_node *t = head->rnh_treetop, *x; - 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; - 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! - * Or 255.255.255.255 - * - * In this case, we have a complete match of the key. Unless - * the node is one of the roots, we are finished. - * If it is the zeros root, then take what we have, preferring - * any real data. - * If it is the ones root, then pretend the target key was followed - * by a byte of zeros. - */ - if (!(t->rn_flags & RNF_ROOT)) - return t; /* not a root */ - if (t->rn_dupedkey) { - t = t->rn_dupedkey; - return t; /* have some real data */ - } - if (*(cp-1) == 0) - return t; /* not the ones root */ - b = 0; /* fake a zero after 255.255.255.255 */ - goto on2; -on1: - test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */ - for (b = 7; (test >>= 1) > 0;) - b--; -on2: - 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_satisfies_leaf(v, t, matched_off)) { - return t; - } - } - t = saved_t; - /* start searching up the tree */ - do { - 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_satisfies_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 - -static struct radix_node * -rn_newpair(void *v, int b, struct radix_node nodes[2]) -{ - 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; -} - -static struct radix_node * -rn_insert(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); - struct radix_node *t = rn_search(v_arg, top); - caddr_t cp = v + head_off; - int b; - struct radix_node *tt; - - /* - * Find first bit at which v and t->rn_key differ - */ - { - caddr_t cp2 = t->rn_key + head_off; - int cmp_res; - caddr_t cplim = v + vlen; - - while (cp < cplim) - if (*cp2++ != *cp++) - goto on1; - /* handle adding 255.255.255.255 */ - if (!(t->rn_flags & RNF_ROOT) || *(cp2-1) == 0) { - *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; - } - { - 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 ((unsigned)b > (unsigned)x->rn_b); -#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); -} - -static struct radix_node * -rn_addmask(void *n_arg, int search, int skip) -{ - caddr_t netmask = (caddr_t)n_arg; - struct radix_node *x; - caddr_t cp, cplim; - 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 = NULL; - if (x || search) - return (x); - x = (struct radix_node *)rtmalloc(max_keylen + 2*sizeof(*x), - "rn_addmask"); - saved_x = x; - 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) -{ - 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(struct radix_node *tt, - struct radix_mask *next) -{ - struct radix_mask *m; - - MKGet(m); - if (m == NULL) { - 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; -} - -static struct radix_node * -rn_addroute(void *v_arg, - void *n_arg, - struct radix_node_head *head, - struct radix_node treenodes[2]) -{ - caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; - struct radix_node *t, *x = NULL, *tt; - struct radix_node *saved_tt, *top = head->rnh_treetop; - short b = 0, b_leaf = 0; - 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)) == NULL) - 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 = NULL; - } -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; -} - -static struct radix_node * -rn_delete(void *v_arg, - void *netmask_arg, - struct radix_node_head *head) -{ - 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 == NULL || - 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)) == NULL) - return (0); - netmask = x->rn_key; - while (tt->rn_mask != netmask) - if ((tt = tt->rn_dupedkey) == NULL) - return (0); - } - if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == NULL) - 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 == NULL) { - 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) - syslog(LOG_ERR, "%s 0x%lx at 0x%lx\n", - "rn_delete: Orphaned Mask", - (unsigned long)m, - (unsigned long)x); - } - } - /* - * 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(struct radix_node_head *h, - int (*f)(struct radix_node *, struct walkarg *), - struct walkarg *w) -{ - int error; - struct radix_node *base, *next; - 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(struct radix_node_head **head, int off) -{ - struct radix_node_head *rnh; - struct radix_node *t, *tt, *ttt; - if (*head) - return (1); - rnh = (struct radix_node_head *)rtmalloc(sizeof(*rnh), "rn_inithead"); - 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(void) -{ - char *cp, *cplim; - if (max_keylen == 0) { - printf("rn_init: radix functions require max_keylen be set\n"); - return; - } - rn_zeros = (char *)rtmalloc(3 * max_keylen, "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(&mask_rnhead, 0) == 0) - panic("rn_init 2"); -} - diff --git a/sbin/routed/rdisc.c b/sbin/routed/rdisc.c deleted file mode 100644 --- a/sbin/routed/rdisc.c +++ /dev/null @@ -1,1052 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#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 */ -static const struct interface *rdisc_sock_mcast; /* current multicast interface */ - -struct timeval rdisc_timer; -int rdisc_ok; /* using solicited route */ - - -#define MAX_ADS 16 /* at least one per interface */ -struct dr { /* accumulated advertisements */ - struct interface *dr_ifp; - naddr dr_gate; /* gateway */ - time_t dr_ts; /* when received */ - time_t dr_life; /* lifetime in host byte order */ - n_long dr_recv_pref; /* received but biased preference */ - n_long dr_pref; /* preference adjusted by metric */ -}; -static const struct dr *cur_drp; -static struct dr drs[MAX_ADS]; - -/* convert between signed, balanced around zero, - * and unsigned zero-based preferences */ -#define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) -#define UNSIGN_PREF(p) SIGN_PREF(p) -/* adjust unsigned preference by interface metric, - * without driving it to infinity */ -#define PREF(p, ifp) ((int)(p) <= ((ifp)->int_metric+(ifp)->int_adj_outmetric)\ - ? ((p) != 0 ? 1 : 0) \ - : (p) - ((ifp)->int_metric+(ifp)->int_adj_outmetric)) - -static void rdisc_sort(void); - - -/* dump an ICMP Router Discovery Advertisement Message - */ -static void -trace_rdisc(const 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 == NULL) - 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=%d", - naddr_ntoa(wp[0]), (int)ntohl(wp[1])); - wp += p->ad.icmp_ad_asize; - } - (void)fputc('\n',ftrace); - - } else { - trace_act("%s Router Solic. from %s to %s via %s value=%#x", - act, naddr_ntoa(from), naddr_ntoa(to), - ifp ? ifp->int_name : "?", - (int)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 group_req gr; - struct sockaddr_in *sin; - - assert(ifp != NULL); - - 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_ALL_HOSTS | IS_ALL_ROUTERS); - return; - } - - memset(&gr, 0, sizeof(gr)); - gr.gr_interface = ifp->int_index; - sin = (struct sockaddr_in *)&gr.gr_group; - sin->sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - - if (supplier - || (ifp->int_state & IS_NO_ADV_IN) - || !on) { - /* stop listening to advertisements - */ - if (ifp->int_state & IS_ALL_HOSTS) { - sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, - MCAST_LEAVE_GROUP, - &gr, sizeof(gr)) < 0) - LOGERR("MCAST_LEAVE_GROUP ALLHOSTS"); - ifp->int_state &= ~IS_ALL_HOSTS; - } - - } else if (!(ifp->int_state & IS_ALL_HOSTS)) { - /* start listening to advertisements - */ - sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, - &gr, sizeof(gr)) < 0) { - LOGERR("MCAST_JOIN_GROUP 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) { - sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, - MCAST_LEAVE_GROUP, - &gr, sizeof(gr)) < 0) - LOGERR("MCAST_LEAVE_GROUP ALLROUTERS"); - ifp->int_state &= ~IS_ALL_ROUTERS; - } - - } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { - /* start hearing solicitations - */ - sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, - &gr, sizeof(gr)) < 0) { - LOGERR("MCAST_JOIN_GROUP 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 supplying routes"); - - /* 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. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - 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 advertising, then do only that. */ - if (supplier) { - /* If switching from client to server, get rid of old - * default routes. - */ - if (cur_drp != NULL) - 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, solicit 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", - naddr_ntoa(drp->dr_gate), - drp->dr_ifp->int_name); - drp->dr_ts = sec; - } - break; - } - } - } - - rdisc_sol(); - rdisc_sort(); - - /* Delete old redirected routes to keep the kernel table small, - * and to prevent black holes. Check that the kernel table - * matches the daemon table (i.e. has the default route). - * But only if RIP is not running and we are not dealing with - * a bad gateway, since otherwise age() will be called. - */ - if (rip_sock < 0 && bad_gate == 0) - age(0); -} - - -/* 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_ts = 0; - drp->dr_life = 0; - } - - /* make a note to re-solicit, turn RIP on or off, etc. */ - rdisc_timer.tv_sec = 0; -} - - -/* 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; - naddr gate; - int i; - - - del_redirects(gate = 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) { - trace_act("discovered router %s via %s" - " is bad--have %d remaining", - naddr_ntoa(gate), ifp->int_name, i); - } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { - trace_act("last discovered router %s via %s" - " is bad--re-solicit", - naddr_ntoa(gate), ifp->int_name); - ifp->int_rdisc_cnt = 0; - ifp->int_rdisc_timer.tv_sec = 0; - rdisc_sol(); - } else { - trace_act("last discovered router %s via %s" - " is bad--wait to solicit", - naddr_ntoa(gate), ifp->int_name); - } -} - - -/* Find the best discovered route, - * and discard stale routers. - */ -static void -rdisc_sort(void) -{ - struct dr *drp, *new_drp; - struct rt_entry *rt; - struct rt_spare new; - struct interface *ifp; - u_int new_st = 0; - n_long new_pref = 0; - - - /* Find the best discovered route. - */ - new_drp = NULL; - 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 == NULL - || (!((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 == NULL) { - trace_act("turn off Router Discovery client"); - rdisc_ok = 0; - - if (rt != NULL - && (rt->rt_state & RS_RDISC)) { - new = rt->rt_spares[0]; - new.rts_metric = HOPCNT_INFINITY; - new.rts_time = now.tv_sec - GARBAGE_TIME; - rtchange(rt, rt->rt_state & ~RS_RDISC, - &new, 0); - rtswitch(rt, 0); - } - - } else { - if (cur_drp == NULL) { - trace_act("turn on Router Discovery client" - " using %s via %s", - naddr_ntoa(new_drp->dr_gate), - new_drp->dr_ifp->int_name); - rdisc_ok = 1; - - } else { - trace_act("switch Router Discovery from" - " %s via %s to %s via %s", - naddr_ntoa(cur_drp->dr_gate), - cur_drp->dr_ifp->int_name, - naddr_ntoa(new_drp->dr_gate), - new_drp->dr_ifp->int_name); - } - - memset(&new, 0, sizeof(new)); - new.rts_ifp = new_drp->dr_ifp; - new.rts_gate = new_drp->dr_gate; - new.rts_router = new_drp->dr_gate; - new.rts_metric = HOPCNT_INFINITY-1; - new.rts_time = now.tv_sec; - if (rt != NULL) { - rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); - } else { - rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); - } - } - - cur_drp = new_drp; - } - - /* turn RIP on or off */ - if (!rdisc_ok || rip_interfaces > 1) { - rip_on(0); - } else { - rip_off(); - } -} - - -/* handle a single address in an advertisement - */ -static void -parse_ad(naddr from, - naddr gate, - n_long pref, /* signed and in network order */ - u_short life, /* in host byte order */ - struct interface *ifp) -{ - static struct msg_limit bad_gate; - struct dr *drp, *new_drp; - - - if (gate == RIP_DEFAULT - || !check_dst(gate)) { - msglim(&bad_gate, from,"router %s advertising bad gateway %s", - naddr_ntoa(from), - naddr_ntoa(gate)); - return; - } - - /* ignore pointers to ourself and routes via unreachable networks - */ - if (ifwithaddr(gate, 1, 0) != NULL) { - trace_pkt(" discard Router Discovery Ad pointing at us"); - return; - } - if (!on_net(gate, ifp->int_net, ifp->int_mask)) { - trace_pkt(" discard Router Discovery Ad" - " toward unreachable net"); - return; - } - - /* Convert preference to an unsigned value - * and later bias it by the metric of the interface. - */ - pref = UNSIGN_PREF(ntohl(pref)); - - if (pref == 0 || life < MinMaxAdvertiseInterval) { - pref = 0; - life = 0; - } - - for (new_drp = NULL, 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 == NULL) { - /* 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 valuable 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 == NULL) - return; - - new_drp->dr_ifp = ifp; - new_drp->dr_gate = gate; - new_drp->dr_ts = now.tv_sec; - new_drp->dr_life = 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 rsin; - int flags; - const char *msg; - - - memset(&rsin, 0, sizeof(rsin)); - rsin.sin_addr.s_addr = dst; - rsin.sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - rsin.sin_len = sizeof(rsin); -#endif - flags = MSG_DONTROUTE; - - switch (type) { - case 0: /* unicast */ - default: - msg = "Send"; - break; - - case 1: /* broadcast */ - if (ifp->int_if_flags & IFF_POINTOPOINT) { - msg = "Send pt-to-pt"; - rsin.sin_addr.s_addr = ifp->int_dstaddr; - } else { - msg = "Send broadcast"; - rsin.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", - ifp->int_name); - return; - } - if (rdisc_sock_mcast != ifp) { - /* select the right interface. */ - struct ip_mreqn mreqn; - - memset(&mreqn, 0, sizeof(struct ip_mreqn)); - mreqn.imr_ifindex = ifp->int_index; - if (0 > setsockopt(rdisc_sock, - IPPROTO_IP, IP_MULTICAST_IF, - &mreqn, - sizeof(mreqn))) { - LOGERR("setsockopt(rdisc_sock," - "IP_MULTICAST_IF)"); - rdisc_sock_mcast = NULL; - return; - } - rdisc_sock_mcast = ifp; - } - flags = 0; - break; - } - - if (rdisc_sock < 0) - get_rdisc_sock(); - - trace_rdisc(msg, (ifp ? ifp->int_addr : 0), rsin.sin_addr.s_addr, ifp, - p, p_size); - - if (0 > sendto(rdisc_sock, p, p_size, flags, - (struct sockaddr *)&rsin, sizeof(rsin))) { - if (ifp == NULL || !(ifp->int_state & IS_BROKE)) - msglog("sendto(%s%s%s): %s", - ifp != NULL ? ifp->int_name : "", - ifp != NULL ? ", " : "", - inet_ntoa(rsin.sin_addr), - strerror(errno)); - if (ifp != NULL) - 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; - - - memset(&u, 0, 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); - - /* Convert the configured preference to an unsigned value, - * bias it by the interface metric, and then send it as a - * signed, network byte order value. - */ - pref = UNSIGN_PREF(ifp->int_rdisc_pref); - u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); - - u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; - - 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; - - if (!supplier) - return; - - rdisc_timer.tv_sec = now.tv_sec + NEVER; - - LIST_FOREACH(ifp, &ifnet, int_list) { - if (0 != (ifp->int_state & (IS_NO_ADV_OUT | 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; - - - if (supplier) - return; - - rdisc_timer.tv_sec = now.tv_sec + NEVER; - - LIST_FOREACH(ifp, &ifnet, int_list) { - if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) - || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) - continue; - - if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { - memset(&u, 0, 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(const char *act, - naddr from, - struct interface *ifp, - naddr to, - union ad_u *p, - u_int len) -{ - const char *type; - - - 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", - type, p->icmp.icmp_code, - naddr_ntoa(from), naddr_ntoa(to)); - return 0; - } - - trace_rdisc(act, from, to, ifp, p, len); - - if (ifp == NULL) - 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 struct msg_limit bad_asize, bad_len; -#ifdef USE_PASSIFNAME - static struct msg_limit bad_name; -#endif - struct sockaddr_in from; - int n, fromlen, cc, hlen; - struct { -#ifdef USE_PASSIFNAME - char ifname[IFNAMSIZ]; -#endif - union { - struct ip ip; - u_char b[512]; - } pkt; - } buf; - union ad_u *p; - n_long *wp; - struct interface *ifp; - - - for (;;) { - fromlen = sizeof(from); - cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 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); -#ifdef USE_PASSIFNAME - if ((cc -= sizeof(buf.ifname)) < 0) - logbad(0,"missing USE_PASSIFNAME; only %d bytes", - cc+sizeof(buf.ifname)); -#endif - - hlen = buf.pkt.ip.ip_hl << 2; - if (cc < hlen + ICMP_MINLEN) - continue; - p = (union ad_u *)&buf.pkt.b[hlen]; - cc -= hlen; - -#ifdef USE_PASSIFNAME - ifp = ifwithname(buf.ifname, 0); - if (ifp == NULL) - msglim(&bad_name, from.sin_addr.s_addr, - "impossible rdisc if_ name %.*s", - IFNAMSIZ, buf.ifname); -#else - /* If we could tell the interface on which a packet from - * address 0 arrived, we could deal with such solicitations. - */ - ifp = ((from.sin_addr.s_addr == 0) - ? 0 : iflookup(from.sin_addr.s_addr)); -#endif - ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, - buf.pkt.ip.ip_dst.s_addr, p, cc); - if (ifp == NULL) - continue; - if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { - trace_pkt(" " - "discard our own Router Discovery message"); - continue; - } - - switch (p->icmp.icmp_type) { - case ICMP_ROUTERADVERT: - if (p->ad.icmp_ad_asize*4 - < (int)sizeof(p->ad.icmp_ad_info[0])) { - msglim(&bad_asize, from.sin_addr.s_addr, - "intolerable rdisc address size=%d", - p->ad.icmp_ad_asize); - continue; - } - if (p->ad.icmp_ad_num == 0) { - trace_pkt(" empty?"); - continue; - } - if (cc != (int)(sizeof(p->ad) - - sizeof(p->ad.icmp_ad_info) - + (p->ad.icmp_ad_num - * sizeof(p->ad.icmp_ad_info[0])))) { - msglim(&bad_len, from.sin_addr.s_addr, - "rdisc length %d does not match ad_num" - " %d", cc, p->ad.icmp_ad_num); - continue; - } - if (supplier) - 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; - if (stopint) - 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/sbin/routed/routed.8 b/sbin/routed/routed.8 deleted file mode 100644 --- a/sbin/routed/routed.8 +++ /dev/null @@ -1,748 +0,0 @@ -.\" $Revision: 2.26 $ -.\" -.\" 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. 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. -.\" -.Dd May 20, 2025 -.Dt ROUTED 8 -.Os -.Sh NAME -.Nm routed , -.Nm rdisc -.Nd network RIP and router discovery routing daemon -.Sh DEPRECATION NOTICE -The -.Nm routed -and -.Nm rdisc -utilities are deprecated and will be removed in -.Fx 16.0 . -.Sh SYNOPSIS -.Nm -.Op Fl isqdghmpAtv -.Op Fl T Ar tracefile -.Oo -.Fl F -.Ar net Ns Op /mask Ns Op ,metric -.Oc -.Op Fl P Ar parms -.Sh DESCRIPTION -The -.Nm -utility is a daemon 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 -.Bx 4.3 -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 advertises 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 -hopcount -(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 Discovery 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"). -The advertised metric for a route reflects the metrics associated -with interfaces -(see -.Xr ifconfig 8 ) -though which it is received and sent, -so setting the metric on an interface -is an effective way to steer traffic. -See also -.Cm adj_inmetric -and -.Cm adj_outmetric -parameters below. -.Pp -Responses do not include 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 table is 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 ensure 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 , -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 1 ) , -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 listening to other RIP routers, it -sends Solicitations and listens for Advertisements. -If it receives -a good Advertisement and it is not multi-homed, -it stops listening for broadcast or multicast RIP responses. -It tracks several advertising routers to speed recovery when the -currently chosen router dies. -If all discovered routers disappear, -the daemon resumes listening to RIP responses. -It continues listening to RIP while using Router Discovery -if multi-homed to ensure all interfaces are used. -.Pp -The Router Discovery standard requires that advertisements -have a default "lifetime" of 30 minutes. -That means should -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. -On a host with more than one network interface, -this default route will be via only one of the interfaces. -Thus, multi-homed hosts running with -.Fl q -might need -.Cm no_rdisc -described below. -.Pp -See the -.Cm pm_rdisc -facility described below to support "legacy" systems -that can handle neither RIPv2 nor Router Discovery. -.Pp -By default, neither Router Discovery advertisements nor solicitations -are sent over point to point links (e.g.\& PPP). -The netmask associated with point-to-point links (such as SLIP -or PPP, with the IFF_POINTOPOINT flag) is used by -.Nm -to infer the netmask used by the remote system when RIPv1 is used. -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl i -allow -.Nm -to accept a RIP request from non-router node. -When specified once, -.Nm -replies to a route information query from neighbor nodes. -When specified twice, -it replies to a query from remote nodes in addition. -.Xr rtquery 8 -utility can be used to send a request. -.Pp -This feature is disabled by default because of a risk of reflection attack -though it is useful for debugging purpose. -.It Fl s -force -.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. -This is the default when only one interface is present. -With this explicit option, the daemon is always in "quiet-mode" for RIP -and does not supply routing information to other computers. -.It Fl d -do not run in the background. -This option is meant for interactive use. -.It Fl g -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 accidentally used to create chaos with a -routing loop than to solve problems. -.It Fl h -cause 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 -cause 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 -increase 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 -.Xr rtquery 8 -command. -.It Fl T Ar tracefile -increases the debugging level to at least 1 and -causes debugging information to be appended to the trace file. -Note that because of security concerns, it is wisest to not run -.Nm -routinely with tracing directed to a file. -.It Fl v -display and logs the version of daemon. -.It Fl F Ar net[/mask][,metric] -minimize routes in transmissions via interfaces with addresses that match -.Em net/mask , -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 -The -.Nm -utility 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 HIPPI or ATM network in -.Pa /etc/gateways -with a series of -"host" lines. -Note that it is usually desirable to use RIPv2 in such situations -to avoid generating lists of inferred host routes. -.Pp -Gateways marked -.Em external -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 necessary, -and that other routes to that destination should not be installed -by -.Nm . -Such entries are only required when both routers may learn of routes -to the same destination. -.Pp -The -.Pa /etc/gateways -file is comprised of a series of lines, each in -one of the following two formats or consist of parameters described later. -Blank lines and lines starting with '#' are comments. -.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 a method in -.Xr nsswitch.conf 5 -must be able to resolve it.) -.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. -.Pp -.Cm Host Ar hname -is equivalent to -.Cm net Ar 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 -As can be seen when debugging is turned on with -.Fl t , -such lines create pseudo-interfaces. -To set parameters for remote or external interfaces, -a line starting with -.Cm if=alias(Hname) , -.Cm if=remote(Hname) , -etc.\& should be used. -.Ss Parameters -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 indent -.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 Ns Oo / Ns Ar mask Oc Ns Op , Ns Ar 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. -The network number must specify a full, 32-bit value, as in 192.0.2.0 -instead of 192.0.2. -.Pp -Do not use this feature unless necessary. -It is dangerous. -.It Cm ripv1_mask Ns = Ns Ar nname Ns / Ns Ar mask1 , Ns Ar mask2 -specifies that netmask of the network of which -.Ar nname Ns / Ns Ar mask1 -is -a subnet should be -.Ar mask2 . -For example, -.Dq Li ripv1_mask=192.0.2.16/28,27 -marks 192.0.2.16/28 -as a subnet of 192.0.2.0/27 instead of 192.0.2.0/24. -It is better to turn on RIPv2 instead of using this facility, for example -with -.Cm ripv2_out . -.It Cm passwd Ns = Ns Ar XXX[|KeyID[start|stop]] -specifies a RIPv2 cleartext password that will be included on -all RIPv2 responses sent, and checked on all RIPv2 responses received. -Any blanks, tab characters, commas, or '#', '|', or NULL characters in the -password must be escaped with a backslash (\\). -The common escape sequences \\n, \\r, \\t, \\b, and \\xxx have their -usual meanings. -The -.Cm KeyID -must be unique but is ignored for cleartext passwords. -If present, -.Cm start -and -.Cm stop -are timestamps in the form year/month/day@hour:minute. -They specify when the password is valid. -The valid password with the most future is used on output packets, unless -all passwords have expired, in which case the password that expired most -recently is used, or unless no passwords are valid yet, in which case -no password is output. -Incoming packets can carry any password that is valid, will -be valid within the next 24 hours, or that was valid within the preceding -24 hours. -To protect the secrets, the passwd settings are valid only in the -.Pa /etc/gateways -file and only when that file is readable only by UID 0. -.It Cm md5_passwd Ns \&= Ns Ar XXX|KeyID[start|stop] -specifies a RIPv2 MD5 password. -Except that a -.Cm KeyID -is required, this keyword is similar to -.Cm passwd . -.It Cm no_ag -turns off aggregation of subnets in RIPv1 and RIPv2 responses. -.It Cm no_super_ag -turns off aggregation of networks into supernets in RIPv2 responses. -.It Cm passive -marks the interface to not be advertised in updates sent via other -interfaces, and turns off all RIP and router discovery through the interface. -.It Cm no_rip -disables all RIP processing on the specified interface. -If no interfaces are allowed to process RIP packets, -.Nm -acts purely as a router discovery daemon. -.Pp -Note that turning off RIP without explicitly turning on router -discovery advertisements with -.Cm rdisc_adv -or -.Fl s -causes -.Nm -to act as a client router discovery daemon, not advertising. -.It Cm no_rip_mcast -causes RIPv2 packets to be broadcast instead of multicast. -.It Cm no_rip_out -causes no RIP updates to be sent. -.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 on RIPv2 output and causes RIPv2 advertisements to be -multicast when possible. -.It Cm ripv2 -is equivalent to -.Cm no_ripv1_in -and -.Cm no_ripv1_out . -This enables RIPv2. -.It Cm no_rdisc -disables the Internet Router Discovery Protocol. -.It Cm no_solicit -disables the transmission of Router Discovery Solicitations. -.It Cm send_solicit -specifies that Router Discovery solicitations should be sent, -even on point-to-point links, -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 optionally -signed integer -.Ar N . -The default preference is 0. -Default routes with smaller or more negative preferences are preferred by -clients. -.It Cm rdisc_interval Ns \&= Ns Ar N -sets the nominal interval with which Router Discovery Advertisements -are transmitted to N seconds and their lifetime to 3*N. -.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 specified 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. -.It Cm adj_inmetric Ns \&= Ns Ar delta -adjusts the hop count or metric of received RIP routes by -.Ar delta . -The metric of every received RIP route is increased by the sum -of two values associated with the interface. -One is the adj_inmetric value and the other is the interface -metric set with -.Xr ifconfig 8 . -.It Cm adj_outmetric Ns \&= Ns Ar delta -adjusts the hop count or metric of advertised RIP routes by -.Ar delta . -The metric of every received RIP route is increased by the metric -associated with the interface by which it was received, or by 1 if -the interface does not have a non-zero metric. -The metric of the received route is then increased by the -adj_outmetric associated with the interface. -Every advertised route is increased by a total of four -values, -the metric set for the interface by which it was received with -.Xr ifconfig 8 , -the -.Cm adj_inmetric Ar delta -of the receiving interface, -the metric set for the interface by which it is transmitted with -.Xr ifconfig 8 , -and the -.Cm adj_outmetric Ar delta -of the transmitting interface. -.It Cm trust_gateway Ns \&= Ns Ar rname[|net1/mask1|net2/mask2|...] -causes RIP packets from router -.Ar rname -and other routers named in other -.Cm trust_gateway -keywords to be accepted, and packets from other routers to be ignored. -If networks are specified, then routes to other networks will be ignored -from that router. -.It Cm redirect_ok -allows the kernel to listen ICMP Redirect messages when the system is acting -as a router and forwarding packets. -Otherwise, ICMP Redirect messages are overridden and deleted when the -system is acting as a router. -.El -.Sh FILES -.Bl -tag -width /etc/gateways -compact -.It Pa /etc/gateways -for distant gateways -.El -.Sh SEE ALSO -.Xr icmp 4 , -.Xr udp 4 , -.Xr rtquery 8 -.Rs -.%T Internet Transport Protocols -.%R XSIS 028112 -.%Q Xerox System Integration Standard -.Re -.Sh HISTORY -The -.Nm -utility appeared in -.Bx 4.2 . -.\" LocalWords: loopback ICMP rtquery ifconfig multicasting Solicitations RIPv -.\" LocalWords: netstat rdisc -.Sh BUGS -It does not always detect unidirectional failures in network interfaces, -for example, when the output side fails. diff --git a/sbin/routed/rtquery/Makefile b/sbin/routed/rtquery/Makefile deleted file mode 100644 --- a/sbin/routed/rtquery/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Make `routed` tools for BSD/OS -# $Revision: 1.6 $ - -PACKAGE=runtime -PROG= rtquery -MAN= rtquery.8 -LIBADD= md -WARNS?= 3 -NO_WARRAY_BOUNDS= - -.include diff --git a/sbin/routed/rtquery/Makefile.depend b/sbin/routed/rtquery/Makefile.depend deleted file mode 100644 --- a/sbin/routed/rtquery/Makefile.depend +++ /dev/null @@ -1,18 +0,0 @@ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/arpa \ - include/protocols \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libmd \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/sbin/routed/rtquery/rtquery.8 b/sbin/routed/rtquery/rtquery.8 deleted file mode 100644 --- a/sbin/routed/rtquery/rtquery.8 +++ /dev/null @@ -1,135 +0,0 @@ -.\" $Revision: 2.27 $ -.\" -.Dd May 20, 2025 -.Dt RTQUERY 8 -.Os -.Sh NAME -.Nm rtquery -.Nd query routing daemons for their routing tables -.Sh DEPRECATION NOTICE -The -.Nm -utility is deprecated and will be removed in -.Fx 16.0 . -.Sh SYNOPSIS -.Nm -.Op Fl np1 -.Op Fl w Ar timeout -.Op Fl r Ar addr -.Op Fl a Ar secret -.Ar host ... -.Nm -.Op Fl t Ar op -.Ar host ... -.Sh DESCRIPTION -The -.Nm -utility is used to query a RIP network routing daemon, such as -.Xr routed 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 -The -.Nm -utility by default uses the -.Em request -command. -When the -.Fl p -option is specified, -.Nm -uses the -.Em poll -command, an -undocumented extension to the RIP protocol supported by -the commercial -.Nm gated -routing product. -When querying -.Nm gated , -the -.Em poll -command is preferred over the -.Em request -command because the response is not subject to Split Horizon and/or -Poisoned Reverse, and because some versions of -.Nm gated -do not answer the -.Em request -command. -The -.Xr routed 8 -utility does not answer the -.Em poll -command, but recognizes -.Em requests -coming from -.Nm -and so answers completely. -.Pp -The -.Nm -utility is also used to turn tracing on or off in -.Xr routed 8 . -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl n -displays only the numeric network and host numbers instead of both -numeric and symbolic. -.It Fl p -uses the -.Em poll -command to request full routing information from -.Nm gated . -This is an undocumented extension RIP protocol supported only by -.Nm gated . -.It Fl 1 -queries 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 -asks about the route to destination -.Em addr . -.It Fl a Ar passwd=XXX -.It Fl a Ar md5_passwd=XXX|KeyID -causes the query to be sent with the indicated cleartext or MD5 password. -.It Fl t Ar op -changes tracing, where -.Em op -is one of the following. -Requests from processes not running with UID 0 or on distant networks -are generally ignored by the daemon except for a message in the system log. -.Nm gated -is likely to ignore these debugging requests. -.El -.Bl -tag -width Ds -offset indent-two -.It Em on=tracefile -turns tracing on into the specified file. -That file must usually have been specified when the daemon was -started or be the same as a fixed name, often -.Pa /etc/routed.trace . -.It Em more -increases the debugging level. -.It Em off -turns off tracing. -.It Em dump -dumps the daemon's routing table to the current tracefile. -.El -.Sh SEE ALSO -.Xr routed 8 -.Rs -.%T Routing Information Protocol, RIPv1 -.%O RFC1058 -.Re -.Rs -.%T Routing Information Protocol, RIPv2 -.%O RFC1723 -.Re diff --git a/sbin/routed/rtquery/rtquery.c b/sbin/routed/rtquery/rtquery.c deleted file mode 100644 --- a/sbin/routed/rtquery/rtquery.c +++ /dev/null @@ -1,900 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include -#include -#include -#include -#include -#define RIPVERSION RIPv2 -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef sgi -#include -#include -#endif - -#define UNUSED __attribute__((unused)) -#ifndef sgi -#define _HAVE_SIN_LEN -#endif - -#ifdef __NetBSD__ -#include -#else -#define MD5_DIGEST_LEN 16 -typedef struct { - u_int32_t state[4]; /* state (ABCD) */ - u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ - unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; -extern void MD5Init(MD5_CTX*); -extern void MD5Update(MD5_CTX*, u_char*, u_int); -extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); -#endif - - -#define WTIME 15 /* Time to wait for all responses */ -#define STIME (250*1000) /* usec to wait for another response */ - -int soc; - -const char *pgmname; - -union { - struct rip rip; - char packet[MAXPACKETSIZE+MAXPATHLEN]; -} omsg_buf; -#define OMSG omsg_buf.rip -int omsg_len = sizeof(struct rip); - -union { - struct rip rip; - char packet[MAXPACKETSIZE+1024]; - } imsg_buf; -#define IMSG imsg_buf.rip - -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 */ -int trace, not_trace; /* send trace command or not */ -int auth_type = RIP_AUTH_NONE; -char passwd[RIP_AUTH_PW_LEN]; -u_long keyid; - -struct timeval sent; /* when query sent */ - -static char localhost_str[] = "localhost"; -static char *default_argv[] = {localhost_str, 0}; - -static void rip_input(struct sockaddr_in*, int); -static int out(const char *); -static void trace_loop(char *argv[]) __attribute((__noreturn__)); -static void query_loop(char *argv[], int) __attribute((__noreturn__)); -static int getnet(char *, struct netinfo *); -static u_int std_mask(u_int); -static int parse_quote(char **, const char *, char *, char *, int); -static void usage(void) __dead2; - - -int -main(int argc, - char *argv[]) -{ - int ch, bsize; - char *p, *options, *value, delim; - const char *result; - - OMSG.rip_nets[0].n_dst = RIP_DEFAULT; - OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; - OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); - - pgmname = argv[0]; - while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) - switch (ch) { - case 'n': - not_trace = 1; - nflag = 1; - break; - - case 'p': - not_trace = 1; - pflag = 1; - break; - - case '1': - ripv2 = 0; - break; - - case 'w': - not_trace = 1; - wtime = (int)strtoul(optarg, &p, 0); - if (*p != '\0' - || wtime <= 0) - usage(); - break; - - case 'r': - not_trace = 1; - if (rflag) - usage(); - rflag = getnet(optarg, &OMSG.rip_nets[0]); - if (!rflag) { - struct hostent *hp = gethostbyname(optarg); - if (hp == NULL) { - fprintf(stderr, "%s: %s:", - pgmname, optarg); - herror(0); - exit(1); - } - memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr, - sizeof(OMSG.rip_nets[0].n_dst)); - OMSG.rip_nets[0].n_family = RIP_AF_INET; - OMSG.rip_nets[0].n_mask = -1; - rflag = 1; - } - break; - - case 't': - trace = 1; - options = optarg; - while (*options != '\0') { - /* messy complications to make -W -Wall happy */ - static char on_str[] = "on"; - static char more_str[] = "more"; - static char off_str[] = "off"; - static char dump_str[] = "dump"; - static char *traceopts[] = { -# define TRACE_ON 0 - on_str, -# define TRACE_MORE 1 - more_str, -# define TRACE_OFF 2 - off_str, -# define TRACE_DUMP 3 - dump_str, - 0 - }; - result = ""; - switch (getsubopt(&options,traceopts,&value)) { - case TRACE_ON: - OMSG.rip_cmd = RIPCMD_TRACEON; - if (!value - || strlen(value) > MAXPATHLEN) - usage(); - result = value; - break; - case TRACE_MORE: - if (value) - usage(); - OMSG.rip_cmd = RIPCMD_TRACEON; - break; - case TRACE_OFF: - if (value) - usage(); - OMSG.rip_cmd = RIPCMD_TRACEOFF; - break; - case TRACE_DUMP: - if (value) - usage(); - OMSG.rip_cmd = RIPCMD_TRACEON; - result = "dump/../table"; - break; - default: - usage(); - } - strcpy((char*)OMSG.rip_tracefile, result); - omsg_len += strlen(result) - sizeof(OMSG.ripun); - } - break; - - case 'a': - not_trace = 1; - p = strchr(optarg,'='); - if (!p) - usage(); - *p++ = '\0'; - if (!strcasecmp("passwd",optarg)) - auth_type = RIP_AUTH_PW; - else if (!strcasecmp("md5_passwd",optarg)) - auth_type = RIP_AUTH_MD5; - else - usage(); - if (0 > parse_quote(&p,"|",&delim, - passwd, sizeof(passwd))) - usage(); - if (auth_type == RIP_AUTH_MD5 - && delim == '|') { - keyid = strtoul(p+1,&p,0); - if (keyid > 255 || *p != '\0') - usage(); - } else if (delim != '\0') { - usage(); - } - break; - - default: - usage(); - } - argv += optind; - argc -= optind; - if (not_trace && trace) - usage(); - if (argc == 0) { - argc = 1; - argv = default_argv; - } - - soc = socket(AF_INET, SOCK_DGRAM, 0); - if (soc < 0) { - perror("socket"); - exit(2); - } - - /* be prepared to receive a lot of routes */ - for (bsize = 127*1024; ; bsize -= 1024) { - if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF, - &bsize, sizeof(bsize)) == 0) - break; - if (bsize <= 4*1024) { - perror("setsockopt SO_RCVBUF"); - break; - } - } - - if (trace) - trace_loop(argv); - else - query_loop(argv, argc); - /* NOTREACHED */ - return 0; -} - - -static void -usage(void) -{ - fprintf(stderr, - "usage: rtquery [-np1] [-r tgt_rt] [-w wtime]" - " [-a type=passwd] host1 [host2 ...]\n" - "\trtquery -t {on=filename|more|off|dump}" - " host1 [host2 ...]\n"); - exit(1); -} - - -/* tell the target hosts about tracing - */ -static void -trace_loop(char *argv[]) -{ - struct sockaddr_in myaddr; - int res; - - if (geteuid() != 0) { - (void)fprintf(stderr, "-t requires UID 0\n"); - exit(1); - } - - if (ripv2) { - OMSG.rip_vers = RIPv2; - } else { - OMSG.rip_vers = RIPv1; - } - - memset(&myaddr, 0, sizeof(myaddr)); - myaddr.sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - myaddr.sin_len = sizeof(myaddr); -#endif - myaddr.sin_port = htons(IPPORT_RESERVED-1); - while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { - if (errno != EADDRINUSE - || myaddr.sin_port == 0) { - perror("bind"); - exit(2); - } - myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); - } - - res = 1; - while (*argv != NULL) { - if (out(*argv++) <= 0) - res = 0; - } - exit(res); -} - - -/* query all of the listed hosts - */ -static void -query_loop(char *argv[], int argc) -{ -# define NA0 (OMSG.rip_auths[0]) -# define NA2 (OMSG.rip_auths[2]) - struct seen { - struct seen *next; - struct in_addr addr; - } *seen, *sp; - int answered = 0; - int cc; - fd_set bits; - struct timeval now, delay; - struct sockaddr_in from; - int fromlen; - MD5_CTX md5_ctx; - - - OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; - if (ripv2) { - OMSG.rip_vers = RIPv2; - if (auth_type == RIP_AUTH_PW) { - OMSG.rip_nets[1] = OMSG.rip_nets[0]; - NA0.a_family = RIP_AF_AUTH; - NA0.a_type = RIP_AUTH_PW; - memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); - omsg_len += sizeof(OMSG.rip_nets[0]); - - } else if (auth_type == RIP_AUTH_MD5) { - OMSG.rip_nets[1] = OMSG.rip_nets[0]; - NA0.a_family = RIP_AF_AUTH; - NA0.a_type = RIP_AUTH_MD5; - NA0.au.a_md5.md5_keyid = (int8_t)keyid; - NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; - NA0.au.a_md5.md5_seqno = 0; - cc = (char *)&NA2-(char *)&OMSG; - NA0.au.a_md5.md5_pkt_len = htons(cc); - NA2.a_family = RIP_AF_AUTH; - NA2.a_type = htons(1); - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, - (u_char *)&OMSG, cc); - MD5Update(&md5_ctx, - (u_char *)passwd, RIP_AUTH_MD5_HASH_LEN); - MD5Final(NA2.au.au_pw, &md5_ctx); - omsg_len += 2*sizeof(OMSG.rip_nets[0]); - } - - } else { - OMSG.rip_vers = RIPv1; - OMSG.rip_nets[0].n_mask = 0; - } - - /* ask the first (valid) host */ - seen = NULL; - while (0 > out(*argv++)) { - if (*argv == NULL) - exit(1); - answered++; - } - - FD_ZERO(&bits); - for (;;) { - FD_SET(soc, &bits); - delay.tv_sec = 0; - delay.tv_usec = STIME; - cc = select(soc+1, &bits, 0,0, &delay); - if (cc > 0) { - fromlen = sizeof(from); - cc = recvfrom(soc, imsg_buf.packet, - sizeof(imsg_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 != NULL; sp = sp->next) { - if (sp->addr.s_addr == from.sin_addr.s_addr) - break; - } - if (sp == NULL) { - sp = malloc(sizeof(*sp)); - if (sp == NULL) { - fprintf(stderr, - "rtquery: malloc failed\n"); - exit(1); - } - 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 != NULL && out(*argv++) < 0) - 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 (sent.tv_sec + wtime <= now.tv_sec) - break; - } - - /* fail if there was no answer */ - exit (answered >= argc ? 0 : 1); -} - - -/* send to one host - */ -static int -out(const char *host) -{ - struct sockaddr_in router; - struct hostent *hp; - - if (gettimeofday(&sent, 0) < 0) { - perror("gettimeofday(sent)"); - return -1; - } - - memset(&router, 0, sizeof(router)); - router.sin_family = AF_INET; -#ifdef _HAVE_SIN_LEN - router.sin_len = sizeof(router); -#endif - if (!inet_aton(host, &router.sin_addr)) { - hp = gethostbyname(host); - if (hp == NULL) { - herror(host); - return -1; - } - memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr)); - } - router.sin_port = htons(RIP_PORT); - - if (sendto(soc, &omsg_buf, omsg_len, 0, - (struct sockaddr *)&router, sizeof(router)) < 0) { - perror(host); - return -1; - } - - return 0; -} - - -/* - * Convert string to printable characters - */ -static char * -qstring(u_char *s, int len) -{ - static char buf[8*20+1]; - char *p; - u_char *s2, c; - - - for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { - c = *s++; - if (c == '\0') { - for (s2 = s+1; s2 < &s[len]; s2++) { - if (*s2 != '\0') - break; - } - if (s2 >= &s[len]) - goto exit; - } - - if (c >= ' ' && c < 0x7f && c != '\\') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch (c) { - case '\\': - *p++ = '\\'; - break; - case '\n': - *p++= 'n'; - break; - case '\r': - *p++= 'r'; - break; - case '\t': - *p++ = 't'; - break; - case '\b': - *p++ = 'b'; - break; - default: - p += sprintf(p,"%o",c); - break; - } - } -exit: - *p = '\0'; - return buf; -} - - -/* - * Handle an incoming RIP packet. - */ -static void -rip_input(struct sockaddr_in *from, - int size) -{ - struct netinfo *n, *lim; - struct in_addr in; - const char *name; - char net_buf[80]; - u_char hash[RIP_AUTH_MD5_KEY_LEN]; - MD5_CTX md5_ctx; - u_char md5_authed = 0; - u_int mask, dmask; - char *sp; - int i; - struct hostent *hp; - struct netent *np; - struct netauth *na; - - - if (nflag) { - printf("%s:", inet_ntoa(from->sin_addr)); - } else { - hp = gethostbyaddr((char*)&from->sin_addr, - sizeof(struct in_addr), AF_INET); - if (hp == NULL) { - printf("%s:", - inet_ntoa(from->sin_addr)); - } else { - printf("%s (%s):", hp->h_name, - inet_ntoa(from->sin_addr)); - } - } - if (IMSG.rip_cmd != RIPCMD_RESPONSE) { - printf("\n unexpected response type %d\n", IMSG.rip_cmd); - return; - } - printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, - (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", - size); - if (size > MAXPACKETSIZE) { - if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) { - printf(" at least %d bytes too long\n", - size-MAXPACKETSIZE); - size = (int)sizeof(imsg_buf) - (int)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 = IMSG.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 (IMSG.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 - || mask == 0xffffffff)) { - hp = gethostbyaddr((char*)&in, - sizeof(in), - AF_INET); - if (hp != NULL) - name = hp->h_name; - } - } - - } else if (n->n_family == RIP_AF_AUTH) { - na = (struct netauth*)n; - if (na->a_type == RIP_AUTH_PW - && n == IMSG.rip_nets) { - (void)printf(" Password Authentication:" - " \"%s\"\n", - qstring(na->au.au_pw, - RIP_AUTH_PW_LEN)); - continue; - } - - if (na->a_type == RIP_AUTH_MD5 - && n == IMSG.rip_nets) { - (void)printf(" MD5 Auth" - " len=%d KeyID=%d" - " auth_len=%d" - " seqno=%#x" - " rsvd=%#x,%#x\n", - ntohs(na->au.a_md5.md5_pkt_len), - na->au.a_md5.md5_keyid, - na->au.a_md5.md5_auth_len, - (int)ntohl(na->au.a_md5.md5_seqno), - na->au.a_md5.rsvd[0], - na->au.a_md5.rsvd[1]); - md5_authed = 1; - continue; - } - (void)printf(" Authentication type %d: ", - ntohs(na->a_type)); - for (i = 0; i < (int)sizeof(na->au.au_pw); i++) - (void)printf("%02x ", na->au.au_pw[i]); - putc('\n', stdout); - if (md5_authed && n+1 > lim - && na->a_type == ntohs(1)) { - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)&IMSG, - (char *)na-(char *)&IMSG - +RIP_AUTH_MD5_HASH_XTRA); - MD5Update(&md5_ctx, (u_char *)passwd, - RIP_AUTH_MD5_KEY_LEN); - MD5Final(hash, &md5_ctx); - (void)printf(" %s hash\n", - memcmp(hash, na->au.au_pw, - sizeof(hash)) - ? "WRONG" : "correct"); - } - continue; - - } else { - (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", - ntohs(n->n_family), - (u_char)(n->n_dst >> 24), - (u_char)(n->n_dst >> 16), - (u_char)(n->n_dst >> 8), - (u_char)n->n_dst); - } - - (void)printf(" %-18s metric %2d %-10s", - net_buf, (int)ntohl(n->n_metric), name); - - if (n->n_nhop != 0) { - in.s_addr = n->n_nhop; - if (nflag) - hp = NULL; - else - hp = gethostbyaddr((char*)&in, sizeof(in), - AF_INET); - (void)printf(" nhop=%-15s%s", - (hp != NULL) ? hp->h_name : inet_ntoa(in), - (IMSG.rip_vers == RIPv1) ? " ?" : ""); - } - if (n->n_tag != 0) - (void)printf(" tag=%#x%s", n->n_tag, - (IMSG.rip_vers == RIPv1) ? " ?" : ""); - putc('\n', stdout); - } -} - - -/* Return the classical netmask for an IP address. - */ -static u_int -std_mask(u_int addr) /* in network order */ -{ - addr = 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; -} - - -/* 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 (NULL != (mname = strrchr(name,'/'))) { - i = (int)(mname - name); - if (i > (int)sizeof(hname)-1) /* name too long */ - return 0; - memmove(hname, name, i); - hname[i] = '\0'; - mname++; - name = hname; - } - - nentp = getnetbyname(name); - if (nentp != NULL) { - in.s_addr = nentp->n_net; - } else if (inet_aton(name, &in) == 1) { - in.s_addr = ntohl(in.s_addr); - } else { - return 0; - } - - if (mname == NULL) { - mask = std_mask(in.s_addr); - if ((~mask & in.s_addr) != 0) - mask = 0xffffffff; - } else { - mask = (u_int)strtoul(mname, &p, 0); - if (*p != '\0' || mask > 32) - return 0; - mask = 0xffffffff << (32-mask); - } - - rt->n_dst = htonl(in.s_addr); - rt->n_family = RIP_AF_INET; - rt->n_mask = htonl(mask); - return 1; -} - - -/* strtok(), but honoring backslash - */ -static int /* -1=bad */ -parse_quote(char **linep, - const char *delims, - char *delimp, - char *buf, - int lim) -{ - char c, *pc; - const char *p; - - - pc = *linep; - if (*pc == '\0') - return -1; - - for (;;) { - if (lim == 0) - return -1; - c = *pc++; - if (c == '\0') - break; - - if (c == '\\' && *pc != '\0') { - if ((c = *pc++) == 'n') { - c = '\n'; - } else if (c == 'r') { - c = '\r'; - } else if (c == 't') { - c = '\t'; - } else if (c == 'b') { - c = '\b'; - } else if (c >= '0' && c <= '7') { - c -= '0'; - if (*pc >= '0' && *pc <= '7') { - c = (c<<3)+(*pc++ - '0'); - if (*pc >= '0' && *pc <= '7') - c = (c<<3)+(*pc++ - '0'); - } - } - - } else { - for (p = delims; *p != '\0'; ++p) { - if (*p == c) - goto exit; - } - } - - *buf++ = c; - --lim; - } -exit: - if (delimp != NULL) - *delimp = c; - *linep = pc-1; - if (lim != 0) - *buf = '\0'; - return 0; -} diff --git a/sbin/routed/table.c b/sbin/routed/table.c deleted file mode 100644 --- a/sbin/routed/table.c +++ /dev/null @@ -1,2154 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#include "defs.h" -static struct rt_spare *rts_better(struct rt_entry *); -static struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0,0}; -static void set_need_flash(void); -#ifdef _HAVE_SIN_LEN -static void masktrim(struct sockaddr_in *ap); -#else -static void masktrim(struct sockaddr_in_new *ap); -#endif -static void rtbad(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, 0 -}; - -int stopint; - -int total_routes; - -/* zap any old routes through this gateway */ -static 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. - */ - -static 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 != NULL; cag = cag->ag_fine) \ - acnt++; \ - for (cag = ag_corsest; cag != NULL; 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; - - - /* Forget it if this route should not be output for split-horizon. */ - if (ag->ag_state & AGS_SPLIT_HZ) - return; - - /* If we output both the even and odd twins, then the immediate parent, - * if it is present, is redundant, unless the parent manages to - * aggregate into something coarser. - * 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 != NULL - && 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; /* quit if fully redundant */ - /* make it finer if it is half-redundant */ - bit = (-ag->ag_mask) >> 1; - ag->ag_dst_h |= bit; - ag->ag_mask |= bit; - - } else if (ag->ag_state & AGS_REDUN1) { - /* make it finer if it is half-redundant */ - bit = (-ag->ag_mask) >> 1; - ag->ag_mask |= bit; - } - out(ag); -} - - -static void -ag_del(struct ag_info *ag) -{ - CHECK_AG(); - - if (ag->ag_cors == NULL) - ag_corsest = ag->ag_fine; - else - ag->ag_cors->ag_fine = ag->ag_fine; - - if (ag->ag_fine == NULL) - 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 aggregation. - * 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 restrictive 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 != NULL && 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 == NULL) { - /* 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 the suppressed target was redundant, - * then mark the suppressor redundant. - */ - if (ag_cors->ag_pref <= ag->ag_pref) { - 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 new_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; - - dst = 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 = new_seqno; - out(&nc_ag); - return; - } - - /* Search for the right slot in the aggregation table. - */ - ag_cors = NULL; - ag = ag_corsest; - while (ag != NULL) { - 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 (e.g. with large hop counts) - * from preventing suppression of finer routes. - */ - if (ag_cors != NULL - && 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 the suppressed target was redundant, - * then mark the suppressor redundant. - */ - if (AG_IS_REDUN(ag->ag_state) - && ag_cors->ag_mask == ag->ag_mask<<1) { - if (ag_cors->ag_dst_h == dst) - 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 != NULL - && 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 (or aggregated) pair and the route - * already in the slot is the explicit route. - * - * Prefer the best route if their metrics differ, - * or the aggregated 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; - if (ag->ag_seqno < new_seqno) - ag->ag_seqno = new_seqno; - x = ag->ag_state; - ag->ag_state = state; - state = x; - } - - /* Some bits are set if they are set on either route, - * except when the route is for an interface. - */ - if (!(ag->ag_state & AGS_IF)) - ag->ag_state |= (state & (AGS_AGGREGATE_EITHER - | AGS_REDUN0 - | AGS_REDUN1)); - return; - } - - /* 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. - * - * Any route that can be promoted is always - * marked to be eligible to be suppressed. - */ - if (!((state & AGS_AGGREGATE) - && (ag->ag_state & AGS_SUPPRESS)) - && !((ag->ag_state & AGS_AGGREGATE) - && (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_AGGREGATE) != 0)) { - - /* We have both the even and odd pairs. - * Since the routes are encountered in order, - * the route in the slot must be the even twin. - * - * Combine and promote (aggregate) the pair of routes. - */ - if (new_seqno < ag->ag_seqno) - new_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_AGGREGATE_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_AGGREGATE)) { - /* 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; - - /* The promoted route is even-redundant only if the - * even twin was fully redundant. It is not - * odd-redundant because the odd-twin will still be - * in the table. - */ - x = ag->ag_state; - if (!AG_IS_REDUN(x)) - x &= ~AGS_REDUN0; - x &= ~AGS_REDUN1; - ag->ag_state = state; - state = x; - - x = ag->ag_metric; - ag->ag_metric = metric; - metric = x; - - x = ag->ag_pref; - ag->ag_pref = pref; - pref = x; - - /* take the newest sequence number */ - if (new_seqno <= ag->ag_seqno) - new_seqno = ag->ag_seqno; - else - ag->ag_seqno = new_seqno; - - } else { - if (!(state & AGS_AGGREGATE)) - break; /* cannot promote either twin */ - - /* Promote the new, odd twin by shaving its - * mask and address. - * The promoted route is odd-redundant only if the - * odd twin was fully redundant. It is not - * even-redundant because the even twin is still in - * the table. - */ - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN1; - state &= ~AGS_REDUN0; - if (new_seqno < ag->ag_seqno) - new_seqno = ag->ag_seqno; - else - ag->ag_seqno = new_seqno; - } - - mask <<= 1; - dst &= mask; - - if (ag_cors == NULL) { - 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 != NULL - && ag->ag_mask < mask) { - ag_cors = ag; - ag = ag->ag_fine; - } - - /* Empty the target slot - */ - if (ag != NULL && ag->ag_mask == mask) { - ag_flush(ag->ag_dst_h, ag->ag_mask, out); - ag = (ag_cors == NULL) ? ag_corsest : ag_cors->ag_fine; - } - -#ifdef DEBUG_AG - (void)fflush(stderr); - if (ag == NULL && ag_cors != ag_finest) - abort(); - if (ag_cors == NULL && ag != ag_corsest) - abort(); - if (ag != NULL && ag->ag_cors != ag_cors) - abort(); - if (ag_cors != NULL && 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 = new_seqno; - - nag->ag_fine = ag; - if (ag != NULL) - ag->ag_cors = nag; - else - ag_finest = nag; - nag->ag_cors = ag_cors; - if (ag_cors == NULL) - ag_corsest = nag; - else - ag_cors->ag_fine = nag; - CHECK_AG(); -} - -static const char * -rtm_type_name(u_char type) -{ - static const char * const 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", -#ifdef RTM_OIFINFO - "RTM_OIFINFO", -#endif - "RTM_IFINFO", - "RTM_NEWMADDR", - "RTM_DELMADDR" - }; -#define NEW_RTM_PAT "RTM type %#x" - static char name0[sizeof(NEW_RTM_PAT)+2]; - - - if (type > sizeof(rtm_types)/sizeof(rtm_types[0]) - || type == 0) { - snprintf(name0, sizeof(name0), NEW_RTM_PAT, type); - return name0; - } else { - return rtm_types[type-1]; - } -#undef NEW_RTM_PAT -} - - -/* 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 -{ - 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; -# define PAT " %-10s %s metric=%d flags=%#x" -# define ARGS rtm_type_name(action), rtname(dst,mask,gate), metric, flags - -again: - memset(&w, 0, 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 || action == RTM_CHANGE) { - 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 < 0) { - if (errno == ESRCH - && (action == RTM_CHANGE || action == RTM_DELETE)) { - trace_act("route disappeared before" PAT, ARGS); - if (action == RTM_CHANGE) { - action = RTM_ADD; - goto again; - } - return; - } - msglog("write(rt_sock)" PAT ": %s", ARGS, strerror(errno)); - return; - } else if (cc != w.w_rtm.rtm_msglen) { - msglog("write(rt_sock) wrote %ld instead of %d for" PAT, - cc, w.w_rtm.rtm_msglen, ARGS); - return; - } -#endif - if (TRACEKERNEL) - trace_misc("write kernel" PAT, ARGS); -#undef PAT -#undef ARGS -} - - -#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 /* need to delete the route */ -#define KS_ADD 0x004 /* add to the kernel */ -#define KS_CHANGE 0x008 /* tell kernel to change the route */ -#define KS_DEL_ADD 0x010 /* delete & add to change the kernel */ -#define KS_STATIC 0x020 /* Static flag in kernel */ -#define KS_GATEWAY 0x040 /* G flag in kernel */ -#define KS_DYNAMIC 0x080 /* result of redirect */ -#define KS_DELETED 0x100 /* already deleted from kernel */ -#define KS_CHECK 0x200 - time_t k_keep; -#define K_KEEP_LIM 30 - time_t k_redirect_time; /* when redirected route 1st seen */ -} *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) != NULL; pk = &k->k_next) { - if (k->k_dst == dst && k->k_mask == mask) - break; - } - if (ppk != NULL) - *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 != NULL) - return k; - - k = (struct khash *)rtmalloc(sizeof(*k), "kern_add"); - - memset(k, 0, 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; - struct rt_spare new; - - if (k->k_metric == 0) - return; - - memset(&new, 0, sizeof(new)); - new.rts_ifp = ifp; - new.rts_gate = k->k_gate; - new.rts_router = (ifp != NULL) ? ifp->int_addr : loopaddr; - new.rts_metric = k->k_metric; - new.rts_time = now.tv_sec; - - rt = rtget(k->k_dst, k->k_mask); - if (rt != NULL) { - if (!(rt->rt_state & RS_STATIC)) - rtchange(rt, rt->rt_state | RS_STATIC, &new, 0); - } else { - rtadd(k->k_dst, k->k_mask, RS_STATIC, &new); - } -} - - -/* operate on a kernel entry - */ -static void -kern_ioctl(struct khash *k, - int action, /* RTM_DELETE, etc */ - int flags) - -{ - switch (action) { - case RTM_DELETE: - k->k_state &= ~KS_DYNAMIC; - if (k->k_state & KS_DELETED) - return; - k->k_state |= KS_DELETED; - break; - case RTM_ADD: - k->k_state &= ~KS_DELETED; - break; - case RTM_CHANGE: - if (k->k_state & KS_DELETED) { - action = RTM_ADD; - k->k_state &= ~KS_DELETED; - } - break; - } - - rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_metric, flags); -} - - -/* add a route the kernel told us - */ -static void -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("ignore %s without mask", 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; - if (INFO_GATE(info) == 0) { - trace_act("note %s without gateway", - rtm_type_name(rtm->rtm_type)); - k->k_metric = HOPCNT_INFINITY; - } else if (INFO_GATE(info)->sa_family != AF_INET) { - trace_act("note %s with gateway AF=%d", - rtm_type_name(rtm->rtm_type), - INFO_GATE(info)->sa_family); - k->k_metric = HOPCNT_INFINITY; - } else { - k->k_gate = S_ADDR(INFO_GATE(info)); - k->k_metric = rtm->rtm_rmx.rmx_hopcount; - if (k->k_metric < 0) - k->k_metric = 0; - else if (k->k_metric > HOPCNT_INFINITY-1) - k->k_metric = HOPCNT_INFINITY-1; - } - k->k_state &= ~(KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD - | KS_DELETED | KS_GATEWAY | KS_STATIC - | KS_NEW | KS_CHECK); - if (rtm->rtm_flags & RTF_GATEWAY) - k->k_state |= KS_GATEWAY; - if (rtm->rtm_flags & RTF_STATIC) - k->k_state |= KS_STATIC; - - if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { - if (INFO_AUTHOR(info) != 0 - && INFO_AUTHOR(info)->sa_family == AF_INET) - ifp = iflookup(S_ADDR(INFO_AUTHOR(info))); - else - ifp = NULL; - if (supplier - && (ifp == NULL || !(ifp->int_state & IS_REDIRECT_OK))) { - /* Routers are not supposed to listen to redirects, - * so delete it if it came via an unknown interface - * or the interface does not have special permission. - */ - k->k_state &= ~KS_DYNAMIC; - k->k_state |= KS_DELETE; - LIM_SEC(need_kern, 0); - trace_act("mark for deletion redirected %s --> %s" - " via %s", - addrname(k->k_dst, k->k_mask, 0), - naddr_ntoa(k->k_gate), - ifp ? ifp->int_name : "unknown interface"); - } else { - k->k_state |= KS_DYNAMIC; - k->k_redirect_time = now.tv_sec; - trace_act("accept redirected %s --> %s via %s", - addrname(k->k_dst, k->k_mask, 0), - naddr_ntoa(k->k_gate), - ifp ? ifp->int_name : "unknown interface"); - } - return; - } - - /* 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 toward the gateway. - */ - ifp = iflookup(k->k_gate); - if (ifp == NULL) - 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) { - trace_act("ignore %s without gateway", - rtm_type_name(rtm->rtm_type)); - return; - } - - if (rdisc_ok) - rdisc_age(S_ADDR(INFO_GATE(info))); - age(S_ADDR(INFO_GATE(info))); -} - - -/* Make the gateway slot of an info structure point to something - * useful. If it is not already useful, but it specifies an interface, - * then fill in the sockaddr_in provided and point it there. - */ -static int -get_info_gate(struct sockaddr **sap, - struct sockaddr_in *rsin) -{ - struct sockaddr_dl *sdl = (struct sockaddr_dl *)*sap; - struct interface *ifp; - - if (sdl == NULL) - return 0; - if ((sdl)->sdl_family == AF_INET) - return 1; - if ((sdl)->sdl_family != AF_LINK) - return 0; - - ifp = ifwithindex(sdl->sdl_index, 1); - if (ifp == NULL) - return 0; - - rsin->sin_addr.s_addr = ifp->int_addr; -#ifdef _HAVE_SA_LEN - rsin->sin_len = sizeof(*rsin); -#endif - rsin->sin_family = AF_INET; - *sap = (struct sockaddr*)rsin; - - return 1; -} - - -/* Clean the kernel table by copying it to the daemon image. - * Eventually the daemon will delete any extra routes. - */ -void -flush_kern(void) -{ - static char *sysctl_buf; - static size_t sysctl_buf_size = 0; - size_t needed; - int mib[6]; - char *next, *lim; - struct rt_msghdr *rtm; - struct sockaddr_in gate_sin; - struct rt_addrinfo info; - int i; - struct khash *k; - - - for (i = 0; i < KHASH_SIZE; i++) { - for (k = khash_bins[i]; k != NULL; k = k->k_next) { - k->k_state |= KS_CHECK; - } - } - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ - mib[4] = NET_RT_DUMP; - mib[5] = 0; /* no flags */ - for (;;) { - if ((needed = sysctl_buf_size) != 0) { - if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) - break; - if (errno != ENOMEM && errno != EFAULT) - BADERR(1,"flush_kern: sysctl(RT_DUMP)"); - free(sysctl_buf); - needed = 0; - } - if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) - BADERR(1,"flush_kern: sysctl(RT_DUMP) estimate"); - /* Kludge around the habit of some systems, such as - * BSD/OS 3.1, to not admit how many routes are in the - * kernel, or at least to be quite wrong. - */ - needed += 50*(sizeof(*rtm)+5*sizeof(struct sockaddr)); - sysctl_buf = rtmalloc(sysctl_buf_size = needed, - "flush_kern sysctl(RT_DUMP)"); - } - - lim = sysctl_buf + needed; - for (next = sysctl_buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - if (rtm->rtm_msglen == 0) { - msglog("zero length kernel route at " - " %#lx in buffer %#lx before %#lx", - (u_long)rtm, (u_long)sysctl_buf, (u_long)lim); - break; - } - - 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; - -#if defined (RTF_LLINFO) - /* ignore ARP table entries on systems with a merged route - * and ARP table. - */ - if (rtm->rtm_flags & RTF_LLINFO) - continue; -#endif -#if defined(RTF_WASCLONED) && defined(__FreeBSD__) - /* ignore cloned routes - */ - if (rtm->rtm_flags & RTF_WASCLONED) - continue; -#endif - - /* ignore multicast addresses - */ - if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) - continue; - - if (!get_info_gate(&INFO_GATE(&info), &gate_sin)) - continue; - - /* Note static routes and interface routes, and also - * preload the image of the kernel table so that - * we can later clean it, as well as avoid making - * 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); - } - - for (i = 0; i < KHASH_SIZE; i++) { - for (k = khash_bins[i]; k != NULL; k = k->k_next) { - if (k->k_state & KS_CHECK) { - msglog("%s --> %s disappeared from kernel", - addrname(k->k_dst, k->k_mask, 0), - naddr_ntoa(k->k_gate)); - del_static(k->k_dst, k->k_mask, k->k_gate, 1); - } - } - } -} - - -/* Listen to announcements from the kernel - */ -void -read_rt(void) -{ - long cc; - struct interface *ifp; - struct sockaddr_in gate_sin; - naddr mask, gate; - 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, - m.r.rtm.rtm_type != RTM_DELADDR); - if (ifp == NULL) - trace_act("note %s with flags %#x" - " for unknown interface index #%d", - rtm_type_name(m.r.rtm.rtm_type), - m.ifm.ifm_flags, - m.ifm.ifm_index); - else - trace_act("note %s with flags %#x for %s", - 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 == NULL - || ((ifp->int_if_flags ^ m.ifm.ifm_flags) - & IFF_UP) != 0) - ifinit_timer.tv_sec = now.tv_sec; - continue; - } -#ifdef RTM_OIFINFO - if (m.r.rtm.rtm_type == RTM_OIFINFO) - continue; /* ignore compat message */ -#endif - - strlcpy(str, rtm_type_name(m.r.rtm.rtm_type), sizeof(str)); - strp = &str[strlen(str)]; - if (m.r.rtm.rtm_type <= RTM_CHANGE) - strp += sprintf(strp," from pid %d",m.r.rtm.rtm_pid); - - /* - * Only messages that use the struct rt_msghdr format are - * allowed beyond this point. - */ - if (m.r.rtm.rtm_type > RTM_RESOLVE) { - trace_act("ignore %s", str); - continue; - } - - 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", str); - continue; - } - - if (INFO_DST(&info)->sa_family != AF_INET) { - trace_act("ignore %s for AF %d", 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", str); - continue; - } - -#if defined(RTF_LLINFO) - if (m.r.rtm.rtm_flags & RTF_LLINFO) { - trace_act("ignore ARP %s", str); - continue; - } -#endif - -#if defined(RTF_WASCLONED) && defined(__FreeBSD__) - if (m.r.rtm.rtm_flags & RTF_WASCLONED) { - trace_act("ignore cloned %s", str); - continue; - } -#endif - - if (get_info_gate(&INFO_GATE(&info), &gate_sin)) { - gate = S_ADDR(INFO_GATE(&info)); - strp += sprintf(strp, " --> %s", naddr_ntoa(gate)); - } else { - gate = 0; - } - - if (INFO_AUTHOR(&info) != 0) - strp += sprintf(strp, " by authority of %s", - 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", - str, strerror(m.r.rtm.rtm_errno)); - } else { - trace_act("%s", str); - rtm_add(&m.r.rtm,&info,0); - } - break; - - case RTM_DELETE: - if (m.r.rtm.rtm_errno != 0 - && m.r.rtm.rtm_errno != ESRCH) { - trace_act("ignore %s with \"%s\" error", - str, strerror(m.r.rtm.rtm_errno)); - } else { - trace_act("%s", str); - del_static(S_ADDR(INFO_DST(&info)), mask, - gate, 1); - } - break; - - case RTM_LOSING: - trace_act("%s", str); - rtm_lose(&m.r.rtm,&info); - break; - - default: - trace_act("ignore %s", 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 == NULL) - 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) { - /* Must delete bad interface routes etc. to change them. */ - if (k->k_metric == HOPCNT_INFINITY) - k->k_state |= KS_DEL_ADD; - k->k_gate = ag->ag_gate; - k->k_metric = ag->ag_metric; - k->k_state |= KS_CHANGE; - } - - /* If the daemon thinks the route should exist, forget - * about any redirections. - * If the daemon thinks the route should exist, eventually - * override manual intervention by the operator. - */ - if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) { - k->k_state &= ~KS_DYNAMIC; - k->k_state |= (KS_ADD | KS_DEL_ADD); - } - - 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 *argp UNUSED) -{ -#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)) { - /* This is an ordinary route, not for an interface. - */ - - /* aggregate, ordinary good routes without regard to - * their metric - */ - pref = 1; - ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); - - /* Do not install host routes directly to hosts, to avoid - * interfering with ARP entries in the kernel table. - */ - if (RT_ISHOST(RT) - && ntohl(RT->rt_dst) == RT->rt_gate) - return 0; - - } else { - /* This is an interface route. - * Do not install routes for "external" remote interfaces. - */ - if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL)) - return 0; - - /* Interfaces should override received routes. - */ - pref = 0; - ags |= (AGS_IF | AGS_CORS_GATE); - - /* If it is not an interface, or an alias for an interface, - * it must be a "gateway." - * - * If it is a "remote" interface, it is also a "gateway" to - * the kernel if is not an alias. - */ - if (RT->rt_ifp == 0 - || (RT->rt_ifp->int_state & IS_REMOTE)) - ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); - } - - /* If RIP is off and IRDP is on, let the route to the discovered - * route suppress any RIP routes. Eventually the RIP routes - * will time-out and be deleted. This reaches the steady-state - * quicker. - */ - if ((RT->rt_state & RS_RDISC) && rip_sock < 0) - ags |= AGS_CORS_GATE; - - metric = RT->rt_metric; - if (metric == HOPCNT_INFINITY) { - /* if the route is dead, so try hard to aggregate. */ - pref = HOPCNT_INFINITY; - ags |= (AGS_FINE_GATE | AGS_SUPPRESS); - ags &= ~(AGS_IF | AGS_CORS_GATE); - } - - ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0, - 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; - 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) != NULL; ) { - /* 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) { - /* ensure we check when the hold is over */ - LIM_SEC(need_kern, k->k_keep); - /* mark for the next cycle */ - k->k_state |= KS_DELETE; - pk = &k->k_next; - continue; - } - - if ((k->k_state & KS_DELETE) - && !(k->k_state & KS_DYNAMIC)) { - kern_ioctl(k, RTM_DELETE, 0); - *pk = k->k_next; - free(k); - continue; - } - - if (k->k_state & KS_DEL_ADD) - kern_ioctl(k, RTM_DELETE, 0); - - if (k->k_state & KS_ADD) { - kern_ioctl(k, RTM_ADD, - ((0 != (k->k_state & (KS_GATEWAY - | KS_DYNAMIC))) - ? RTF_GATEWAY : 0)); - } else if (k->k_state & KS_CHANGE) { - kern_ioctl(k, RTM_CHANGE, - ((0 != (k->k_state & (KS_GATEWAY - | KS_DYNAMIC))) - ? RTF_GATEWAY : 0)); - } - k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); - - /* Mark this route to be deleted in the next cycle. - * This deletes routes that disappear from the - * 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, - naddr gate, - 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 != NULL && (gate == 0 || k->k_gate == gate)) { - k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK); - k->k_state |= KS_DELETE; - if (gone) { - k->k_state |= KS_DELETED; - k->k_keep = now.tv_sec + K_KEEP_LIM; - } - } - - rt = rtget(dst, mask); - if (rt != NULL && (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 != NULL; 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", - addrname(k->k_dst, k->k_mask, 0), - naddr_ntoa(k->k_gate)); - } - } -} - - -/* Start the daemon tables. - */ -extern int max_keylen; - -void -rtinit(void) -{ - int i; - struct ag_info *ag; - - /* Initialize the radix trees */ - max_keylen = sizeof(struct sockaddr_in); - rn_init(); - rn_inithead(&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, 0, {0}, {0}}; -static struct sockaddr_in mask_sock = {sizeof(mask_sock), AF_INET, 0, {0}, {0}}; -#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 - - -static 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 = htonl(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, - u_int state, /* rt_state for the entry */ - struct rt_spare *new) -{ - struct rt_entry *rt; - naddr smask; - int i; - struct rt_spare *rts; - - rt = (struct rt_entry *)rtmalloc(sizeof (*rt), "rtadd"); - memset(rt, 0, 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 = htonl(mask); - masktrim(&mask_sock); - rt->rt_mask = mask; - rt->rt_state = state; - rt->rt_spares[0] = *new; - rt->rt_time = now.tv_sec; - rt->rt_poison_metric = HOPCNT_INFINITY; - 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)) { - msglog("rnh_addaddr() failed for %s mask=%#lx", - naddr_ntoa(dst), (u_long)mask); - free(rt); - } -} - - -/* notice a changed route - */ -void -rtchange(struct rt_entry *rt, - u_int state, /* new state bits */ - struct rt_spare *new, - char *label) -{ - if (rt->rt_metric != new->rts_metric) { - /* Fix the kernel immediately if it seems the route - * has gone bad, since there may be a working route that - * aggregates this route. - */ - if (new->rts_metric == HOPCNT_INFINITY) { - need_kern.tv_sec = now.tv_sec; - if (new->rts_time >= now.tv_sec - EXPIRE_TIME) - new->rts_time = now.tv_sec - EXPIRE_TIME; - } - rt->rt_seqno = update_seqno; - set_need_flash(); - } - - if (rt->rt_gate != new->rts_gate) { - need_kern.tv_sec = now.tv_sec; - rt->rt_seqno = update_seqno; - set_need_flash(); - } - - state |= (rt->rt_state & RS_SUBNET); - - /* Keep various things from deciding ageless routes are stale. - */ - if (!AGE_RT(state, new->rts_ifp)) - new->rts_time = now.tv_sec; - - if (TRACEACTIONS) - trace_change(rt, state, new, - label ? label : "Chg "); - - rt->rt_state = state; - rt->rt_spares[0] = *new; -} - - -/* 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_MHOME | RS_STATIC | RS_RDISC - | RS_NET_SYN | RS_IF))) - return; - - /* find the best alternative among the spares */ - if (rts == NULL) - 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", (int)(rts - rt->rt_spares)); - rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), rts, label); - if (swap.rts_metric == HOPCNT_INFINITY) { - *rts = rts_empty; - } else { - *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 != NULL) { - 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 = htonl(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--; - } -} - - -void -rts_delete(struct rt_entry *rt, - struct rt_spare *rts) -{ - trace_upslot(rt, rts, &rts_empty); - *rts = rts_empty; -} - - -/* Get rid of a bad route, and try to switch to a replacement. - */ -static void -rtbad(struct rt_entry *rt) -{ - struct rt_spare new; - - /* Poison the route */ - new = rt->rt_spares[0]; - new.rts_metric = HOPCNT_INFINITY; - rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), &new, 0); - rtswitch(rt, 0); -} - - -/* 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 = NULL; - 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. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - /* 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) { - LIST_FOREACH(ifp, &ifnet, int_list) { - 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 != NULL; - 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 != NULL || (state & RS_NET_SYN)) { - struct rt_spare new = rt->rt_spares[0]; - new.rts_ifp = ifp1; - rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state), - &new, 0); - } else { - rtbad(rt); - } -} - - -/* Called while walking the table looking for sick interfaces - * or after a time change. - */ -/* ARGSUSED */ -int -walk_bad(struct radix_node *rn, - struct walkarg *argp UNUSED) -{ -#define RT ((struct rt_entry *)rn) - struct rt_spare *rts; - int i; - - - /* fix any spare routes through the interface - */ - rts = RT->rt_spares; - for (i = NUM_SPARES; i != 1; i--) { - rts++; - if (rts->rts_metric < HOPCNT_INFINITY - && (rts->rts_ifp == NULL - || (rts->rts_ifp->int_state & IS_BROKE))) - rts_delete(RT, rts); - } - - /* 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 *argp UNUSED) -{ -#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->rt_state, 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 - && i != NUM_SPARES) - rts_delete(RT, rts); - } - - - /* 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 publicly 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) { - struct rt_spare new = RT->rt_spares[0]; - new.rts_metric = HOPCNT_INFINITY; - rtchange(RT, RT->rt_state, &new, 0); - } - return 0; -} - - -/* Watch for dead routes and interfaces. - */ -void -age(naddr bad_gate) -{ - struct interface *ifp; - int need_query = 0; - - /* If not listening to RIP, there is no need to age the routes in - * the table. - */ - age_timer.tv_sec = (now.tv_sec - + ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL)); - - /* Check for dead IS_REMOTE interfaces by timing their - * transmissions. - */ - LIST_FOREACH(ifp, &ifnet, int_list) { - if (!(ifp->int_state & IS_REMOTE)) - continue; - - /* ignore unreachable remote interfaces */ - if (!check_remote(ifp)) - continue; - - /* Restore remote interface that has become reachable - */ - if (ifp->int_state & IS_BROKE) - if_ok(ifp, "remote "); - - if (ifp->int_act_time != NEVER - && now.tv_sec - ifp->int_act_time > EXPIRE_TIME) { - msglog("remote interface %s to %s timed out after" - " %ld:%ld", - ifp->int_name, - naddr_ntoa(ifp->int_dstaddr), - (long)(now.tv_sec - ifp->int_act_time)/60, - (long)(now.tv_sec - ifp->int_act_time)%60); - if_sick(ifp); - } - - /* If we have not heard from the other router - * recently, ask it. - */ - if (now.tv_sec >= ifp->int_query_time) { - ifp->int_query_time = NEVER; - need_query = 1; - } - } - - /* Age routes. */ - age_bad_gate = bad_gate; - (void)rn_walktree(rhead, walk_age, 0); - - /* delete old redirected routes to keep the kernel table small - * and prevent blackholes - */ - del_redirects(bad_gate, now.tv_sec-STALE_TIME); - - /* Update the kernel routing table. */ - fix_kern(); - - /* poke reticent remote gateways */ - if (need_query) - rip_query(); -} diff --git a/sbin/routed/trace.c b/sbin/routed/trace.c deleted file mode 100644 --- a/sbin/routed/trace.c +++ /dev/null @@ -1,1009 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * 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. 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. - */ - -#define RIPCMDS -#include "defs.h" -#include "pathnames.h" -#include -#include -#include - - -int tracelevel, new_tracelevel; -FILE *ftrace; /* output trace file */ -static const char *sigtrace_pat = "%s"; -static char savetracename[PATH_MAX]; -char inittracename[PATH_MAX]; -static int file_trace; /* 1=tracing to file, not stdout */ - -static void trace_dump(void); -static void tmsg(const char *, ...) PATTRIB(1,2); - - -/* convert string to printable characters - */ -static char * -qstring(u_char *s, int len) -{ - static char buf[8*20+1]; - char *p; - u_char *s2, c; - - - for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { - c = *s++; - if (c == '\0') { - for (s2 = s+1; s2 < &s[len]; s2++) { - if (*s2 != '\0') - break; - } - if (s2 >= &s[len]) - goto exit; - } - - if (c >= ' ' && c < 0x7f && c != '\\') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch (c) { - case '\\': - *p++ = '\\'; - break; - case '\n': - *p++= 'n'; - break; - case '\r': - *p++= 'r'; - break; - case '\t': - *p++ = 't'; - break; - case '\b': - *p++ = 'b'; - break; - default: - p += sprintf(p,"%o",c); - break; - } - } -exit: - *p = '\0'; - return buf; -} - - -/* convert IP address to a string, but not into a single buffer - */ -char * -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 -} - - -const char * -saddr_ntoa(struct sockaddr *sa) -{ - return (sa == NULL) ? "?" : naddr_ntoa(S_ADDR(sa)); -} - - -static char * -ts(time_t secs) { - static char s[20]; - - secs += epoch.tv_sec; - memcpy(s, ctime(&secs)+11, 8); - s[8] = '\0'; - 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. - */ -static struct timeval lastlog_time; - -void -lastlog(void) -{ - if (lastlog_time.tv_sec != now.tv_sec - || lastlog_time.tv_usec != now.tv_usec) { - (void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec)); - lastlog_time = now; - } -} - - -static void -tmsg(const char *p, ...) -{ - va_list args; - - if (ftrace != NULL) { - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n',ftrace); - fflush(ftrace); - } -} - - -void -trace_close(int zap_stdio) -{ - int fd; - - - fflush(stdout); - fflush(stderr); - - if (ftrace != NULL && zap_stdio) { - if (ftrace != stdout) - fclose(ftrace); - ftrace = NULL; - fd = open(_PATH_DEVNULL, O_RDWR); - if (fd < 0) - return; - if (isatty(STDIN_FILENO)) - (void)dup2(fd, STDIN_FILENO); - if (isatty(STDOUT_FILENO)) - (void)dup2(fd, STDOUT_FILENO); - if (isatty(STDERR_FILENO)) - (void)dup2(fd, STDERR_FILENO); - (void)close(fd); - } - lastlog_time.tv_sec = 0; -} - - -void -trace_flush(void) -{ - if (ftrace != NULL) { - fflush(ftrace); - if (ferror(ftrace)) - trace_off("tracing off: %s", strerror(ferror(ftrace))); - } -} - - -void -trace_off(const char *p, ...) -{ - va_list args; - - - if (ftrace != NULL) { - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n',ftrace); - } - trace_close(file_trace); - - new_tracelevel = tracelevel = 0; -} - - -/* log a change in tracing - */ -void -tracelevel_msg(const char *pat, - int dump) /* -1=no dump, 0=default, 1=force */ -{ - static const char * const off_msgs[MAX_TRACELEVEL] = { - "Tracing actions stopped", - "Tracing packets stopped", - "Tracing packet contents stopped", - "Tracing kernel changes stopped", - }; - static const char * const on_msgs[MAX_TRACELEVEL] = { - "Tracing actions started", - "Tracing packets started", - "Tracing packet contents started", - "Tracing kernel changes started", - }; - u_int old_tracelevel = tracelevel; - - - if (new_tracelevel < 0) - new_tracelevel = 0; - else if (new_tracelevel > MAX_TRACELEVEL) - new_tracelevel = MAX_TRACELEVEL; - - if (new_tracelevel < tracelevel) { - if (new_tracelevel <= 0) { - trace_off(pat, off_msgs[0]); - } else do { - tmsg(pat, off_msgs[tracelevel]); - } - while (--tracelevel != new_tracelevel); - - } else if (new_tracelevel > tracelevel) { - do { - tmsg(pat, on_msgs[tracelevel++]); - } while (tracelevel != new_tracelevel); - } - - if (dump > 0 - || (dump == 0 && old_tracelevel == 0 && tracelevel != 0)) - trace_dump(); -} - - -void -set_tracefile(const char *filename, - const char *pat, - int dump) /* -1=no dump, 0=default, 1=force */ -{ - struct stat stbuf; - FILE *n_ftrace; - const char *fn; - - - /* Allow a null filename to increase the level if the trace file - * is already open or if coming from a trusted source, such as - * a signal or the command line. - */ - if (filename == NULL || filename[0] == '\0') { - filename = NULL; - if (ftrace == NULL) { - if (inittracename[0] == '\0') { - msglog("missing trace file name"); - return; - } - fn = inittracename; - } else { - fn = NULL; - } - - } else if (!strcmp(filename,"dump/../table")) { - trace_dump(); - return; - - } else { - /* Allow the file specified with "-T file" to be reopened, - * but require all other names specified over the net to - * match the official path. The path can specify a directory - * in which the file is to be created. - */ - if (strcmp(filename, inittracename) -#ifdef _PATH_TRACE - && (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1) - || strstr(filename,"../") - || 0 > stat(_PATH_TRACE, &stbuf)) -#endif - ) { - msglog("wrong trace file \"%s\"", filename); - return; - } - - /* If the new tracefile exists, it must be a regular file. - */ - if (stat(filename, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode)) { - msglog("wrong type (%#x) of trace file \"%s\"", - stbuf.st_mode, filename); - return; - } - - fn = filename; - } - - if (fn != NULL) { - n_ftrace = fopen(fn, "a"); - if (n_ftrace == NULL) { - msglog("failed to open trace file \"%s\" %s", - fn, strerror(errno)); - if (fn == inittracename) - inittracename[0] = '\0'; - return; - } - - tmsg("switch to trace file %s", fn); - - trace_close(file_trace = 1); - - if (fn != savetracename) - strncpy(savetracename, fn, sizeof(savetracename)-1); - ftrace = n_ftrace; - - fflush(stdout); - fflush(stderr); - dup2(fileno(ftrace), STDOUT_FILENO); - dup2(fileno(ftrace), STDERR_FILENO); - } - - if (new_tracelevel == 0 || filename == NULL) - new_tracelevel++; - tracelevel_msg(pat, dump != 0 ? dump : (filename != NULL)); -} - - -/* ARGSUSED */ -void -sigtrace_on(int s UNUSED) -{ - new_tracelevel++; - sigtrace_pat = "SIGUSR1: %s"; -} - - -/* ARGSUSED */ -void -sigtrace_off(int s UNUSED) -{ - new_tracelevel--; - sigtrace_pat = "SIGUSR2: %s"; -} - - -/* Set tracing after a signal. - */ -void -set_tracelevel(void) -{ - if (new_tracelevel == tracelevel) - return; - - /* If tracing entirely off, and there was no tracefile specified - * on the command line, then leave it off. - */ - if (new_tracelevel > tracelevel && ftrace == NULL) { - if (savetracename[0] != '\0') { - set_tracefile(savetracename,sigtrace_pat,0); - } else if (inittracename[0] != '\0') { - set_tracefile(inittracename,sigtrace_pat,0); - } else { - new_tracelevel = 0; - return; - } - } else { - tracelevel_msg(sigtrace_pat, 0); - } -} - - -/* 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; - size_t l; - int i; - - strlcpy(bufs[bufno].str, naddr_ntoa(addr), sizeof(bufs[bufno].str)); - s = bufs[bufno].str; - l = sizeof(bufs[bufno].str); - 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 != NULL) { - if (c) - (void)putc(c, ftrace); - (void)fprintf(ftrace, tbl->bits_name, field); - c = '|'; - } - - if (c != '<' || force) - (void)fputs("> ", ftrace); -} - - -char * -rtname(naddr dst, - naddr mask, - naddr gate) -{ - static char buf[3*4+3+1+2+3 /* "xxx.xxx.xxx.xxx/xx-->" */ - +3*4+3+1]; /* "xxx.xxx.xxx.xxx" */ - int i; - - i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0)); - (void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), naddr_ntoa(gate)); - return buf; -} - - -static void -print_rts(struct rt_spare *rts, - int force_metric, /* -1=suppress, 0=default */ - int force_ifp, /* -1=suppress, 0=default */ - int force_router, /* -1=suppress, 0=default, 1=display */ - int force_tag, /* -1=suppress, 0=default, 1=display */ - int force_time) /* 0=suppress, 1=display */ -{ - int i; - - - if (force_metric >= 0) - (void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric); - if (force_ifp >= 0) - (void)fprintf(ftrace, "%s ", (rts->rts_ifp == NULL ? - "if?" : rts->rts_ifp->int_name)); - if (force_router > 0 - || (force_router == 0 && rts->rts_router != rts->rts_gate)) - (void)fprintf(ftrace, "router=%s ", - naddr_ntoa(rts->rts_router)); - if (force_time > 0) - (void)fprintf(ftrace, "%s ", ts(rts->rts_time)); - if (force_tag > 0 - || (force_tag == 0 && rts->rts_tag != 0)) - (void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag)); - if (rts->rts_de_ag != 0) { - for (i = 1; (u_int)(1 << i) <= rts->rts_de_ag; i++) - continue; - (void)fprintf(ftrace, "de_ag=%d ", i); - } - -} - - -void -trace_if(const char *act, - struct interface *ifp) -{ - if (!TRACEACTIONS || ftrace == NULL) - return; - - lastlog(); - (void)fprintf(ftrace, "%-3s interface %-4s ", act, ifp->int_name); - (void)fprintf(ftrace, "%-15s-->%-15s ", - naddr_ntoa(ifp->int_addr), - addrname(((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : htonl(ifp->int_net)), - ifp->int_mask, 1)); - if (ifp->int_metric != 0) - (void)fprintf(ftrace, "metric=%d ", ifp->int_metric); - if (ifp->int_adj_inmetric != 0) - (void)fprintf(ftrace, "adj_inmetric=%u ", - ifp->int_adj_inmetric); - if (ifp->int_adj_outmetric != 0) - (void)fprintf(ftrace, "adj_outmetric=%u ", - ifp->int_adj_outmetric); - if (!IS_RIP_OUT_OFF(ifp->int_state) - && ifp->int_d_metric != 0) - (void)fprintf(ftrace, "fake_default=%u ", ifp->int_d_metric); - trace_bits(if_bits, ifp->int_if_flags, 0); - trace_bits(is_bits, ifp->int_state, 0); - (void)fputc('\n',ftrace); -} - - -void -trace_upslot(struct rt_entry *rt, - struct rt_spare *rts, - struct rt_spare *new) -{ - if (!TRACEACTIONS || ftrace == NULL) - return; - - if (rts->rts_gate == new->rts_gate - && rts->rts_router == new->rts_router - && rts->rts_metric == new->rts_metric - && rts->rts_tag == new->rts_tag - && rts->rts_de_ag == new->rts_de_ag) - return; - - lastlog(); - if (new->rts_gate == 0) { - (void)fprintf(ftrace, "Del #%d %-35s ", - (int)(rts - rt->rt_spares), - rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); - print_rts(rts, 0,0,0,0, - (rts != rt->rt_spares - || AGE_RT(rt->rt_state,new->rts_ifp))); - - } else if (rts->rts_gate != RIP_DEFAULT) { - (void)fprintf(ftrace, "Chg #%d %-35s ", - (int)(rts - rt->rt_spares), - rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); - print_rts(rts, 0,0, - rts->rts_gate != new->rts_gate, - rts->rts_tag != new->rts_tag, - rts != rt->rt_spares || AGE_RT(rt->rt_state, - rt->rt_ifp)); - - (void)fprintf(ftrace, "\n %19s%-16s ", "", - (new->rts_gate != rts->rts_gate - ? naddr_ntoa(new->rts_gate) : "")); - print_rts(new, - -(new->rts_metric == rts->rts_metric), - -(new->rts_ifp == rts->rts_ifp), - 0, - rts->rts_tag != new->rts_tag, - (new->rts_time != rts->rts_time - && (rts != rt->rt_spares - || AGE_RT(rt->rt_state, new->rts_ifp)))); - - } else { - (void)fprintf(ftrace, "Add #%d %-35s ", - (int)(rts - rt->rt_spares), - rtname(rt->rt_dst, rt->rt_mask, new->rts_gate)); - print_rts(new, 0,0,0,0, - (rts != rt->rt_spares - || AGE_RT(rt->rt_state,new->rts_ifp))); - } - (void)fputc('\n',ftrace); -} - - -/* miscellaneous message checked by the caller - */ -void -trace_misc(const char *p, ...) -{ - va_list args; - - if (ftrace == NULL) - return; - - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n',ftrace); -} - - -/* display a message if tracing actions - */ -void -trace_act(const char *p, ...) -{ - va_list args; - - if (!TRACEACTIONS || ftrace == NULL) - return; - - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n',ftrace); -} - - -/* display a message if tracing packets - */ -void -trace_pkt(const char *p, ...) -{ - va_list args; - - if (!TRACEPACKETS || ftrace == NULL) - return; - - lastlog(); - va_start(args, p); - vfprintf(ftrace, p, args); - va_end(args); - (void)fputc('\n',ftrace); -} - - -void -trace_change(struct rt_entry *rt, - u_int state, - struct rt_spare *new, - const char *label) -{ - if (ftrace == NULL) - return; - - if (rt->rt_metric == new->rts_metric - && rt->rt_gate == new->rts_gate - && rt->rt_router == new->rts_router - && rt->rt_state == state - && rt->rt_tag == new->rts_tag - && rt->rt_de_ag == new->rts_de_ag) - return; - - lastlog(); - (void)fprintf(ftrace, "%s %-35s ", - label, - rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); - print_rts(rt->rt_spares, - 0,0,0,0, AGE_RT(rt->rt_state, rt->rt_ifp)); - trace_bits(rs_bits, rt->rt_state, rt->rt_state != state); - - (void)fprintf(ftrace, "\n%*s %19s%-16s ", - (int)strlen(label), "", "", - (rt->rt_gate != new->rts_gate - ? naddr_ntoa(new->rts_gate) : "")); - print_rts(new, - -(new->rts_metric == rt->rt_metric), - -(new->rts_ifp == rt->rt_ifp), - 0, - rt->rt_tag != new->rts_tag, - (rt->rt_time != new->rts_time - && AGE_RT(rt->rt_state,new->rts_ifp))); - if (rt->rt_state != state) - trace_bits(rs_bits, state, 1); - (void)fputc('\n',ftrace); -} - - -void -trace_add_del(const char * action, struct rt_entry *rt) -{ - if (ftrace == NULL) - return; - - lastlog(); - (void)fprintf(ftrace, "%s %-35s ", - action, - rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); - print_rts(rt->rt_spares, 0,0,0,0,AGE_RT(rt->rt_state,rt->rt_ifp)); - trace_bits(rs_bits, rt->rt_state, 0); - (void)fputc('\n',ftrace); -} - - -/* ARGSUSED */ -static int -walk_trace(struct radix_node *rn, - struct walkarg *w UNUSED) -{ -#define RT ((struct rt_entry *)rn) - struct rt_spare *rts; - int i; - - (void)fprintf(ftrace, " %-35s ", - rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate)); - print_rts(&RT->rt_spares[0], 0,0,0,0, AGE_RT(RT->rt_state, RT->rt_ifp)); - trace_bits(rs_bits, RT->rt_state, 0); - if (RT->rt_poison_time >= now_garbage - && RT->rt_poison_metric < RT->rt_metric) - (void)fprintf(ftrace, "pm=%d@%s", - RT->rt_poison_metric, ts(RT->rt_poison_time)); - - rts = &RT->rt_spares[1]; - for (i = 1; i < NUM_SPARES; i++, rts++) { - if (rts->rts_gate != RIP_DEFAULT) { - (void)fprintf(ftrace,"\n #%d%15s%-16s ", - i, "", naddr_ntoa(rts->rts_gate)); - print_rts(rts, 0,0,0,0,1); - } - } - (void)fputc('\n',ftrace); - - return 0; -} - - -static void -trace_dump(void) -{ - struct interface *ifp; - - if (ftrace == NULL) - return; - lastlog(); - - (void)fputs("current daemon state:\n", ftrace); - LIST_FOREACH(ifp, &ifnet, int_list) - trace_if("", ifp); - (void)rn_walktree(rhead, walk_trace, 0); -} - - -void -trace_rip(const char *dir1, const char *dir2, - struct sockaddr_in *who, - struct interface *ifp, - struct rip *msg, - int size) /* total size of message */ -{ - struct netinfo *n, *lim; -# define NA ((struct netauth*)n) - int i, seen_route; - - if (!TRACEPACKETS || ftrace == NULL) - 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; - - seen_route = 0; - switch (msg->rip_cmd) { - case RIPCMD_REQUEST: - case RIPCMD_RESPONSE: - n = msg->rip_nets; - lim = (struct netinfo *)((char*)msg + size); - for (; n < lim; n++) { - if (!seen_route - && n->n_family == RIP_AF_UNSPEC - && ntohl(n->n_metric) == HOPCNT_INFINITY - && msg->rip_cmd == RIPCMD_REQUEST - && (n+1 == lim - || (n+2 == lim - && (n+1)->n_family == RIP_AF_AUTH))) { - (void)fputs("\tQUERY ", ftrace); - if (n->n_dst != 0) - (void)fprintf(ftrace, "%s ", - 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) { - if (NA->a_type == RIP_AUTH_PW - && n == msg->rip_nets) { - (void)fprintf(ftrace, "\tPassword" - " Authentication:" - " \"%s\"\n", - qstring(NA->au.au_pw, - RIP_AUTH_PW_LEN)); - continue; - } - - if (NA->a_type == RIP_AUTH_MD5 - && n == msg->rip_nets) { - (void)fprintf(ftrace, - "\tMD5 Auth" - " pkt_len=%d KeyID=%u" - " auth_len=%d" - " seqno=%#x" - " rsvd=%#x,%#x\n", - ntohs(NA->au.a_md5.md5_pkt_len), - NA->au.a_md5.md5_keyid, - NA->au.a_md5.md5_auth_len, - (int)ntohl(NA->au.a_md5.md5_seqno), - (int)ntohs(NA->au.a_md5.rsvd[0]), - (int)ntohs(NA->au.a_md5.rsvd[1])); - continue; - } - (void)fprintf(ftrace, - "\tAuthentication type %d: ", - ntohs(NA->a_type)); - for (i = 0; - i < (int)sizeof(NA->au.au_pw); - i++) - (void)fprintf(ftrace, "%02x ", - NA->au.au_pw[i]); - (void)fputc('\n',ftrace); - continue; - } - - seen_route = 1; - if (n->n_family != RIP_AF_INET) { - (void)fprintf(ftrace, - "\t(af %d) %-18s mask=%#x ", - 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; - } -} diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5 --- a/share/man/man5/rc.conf.5 +++ b/share/man/man5/rc.conf.5 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 5, 2025 +.Dd October 30, 2025 .Dt RC.CONF 5 .Os .Sh NAME @@ -3061,52 +3061,6 @@ .Pq Vt bool The IPv6 equivalent of .Va gateway_enable . -.It Va routed_enable -.Pq Vt bool -If set to -.Dq Li YES , -run a routing daemon of some sort, based on the -settings of -.Va routed_program -and -.Va routed_flags . -.It Va route6d_enable -.Pq Vt bool -The IPv6 equivalent of -.Va routed_enable . -If set to -.Dq Li YES , -run a routing daemon of some sort, based on the -settings of -.Va route6d_program -and -.Va route6d_flags . -.It Va routed_program -.Pq Vt str -If -.Va routed_enable -is set to -.Dq Li YES , -this is the name of the routing daemon to use. -The default is -.Xr routed 8 . -.It Va route6d_program -.Pq Vt str -The IPv6 equivalent of -.Va routed_program . -The default is -.Xr route6d 8 . -.It Va routed_flags -.Pq Vt str -If -.Va routed_enable -is set to -.Dq Li YES , -these are the flags to pass to the routing daemon. -.It Va route6d_flags -.Pq Vt str -The IPv6 equivalent of -.Va routed_flags . .It Va rtadvd_enable .Pq Vt bool If set to @@ -5140,8 +5094,6 @@ .Xr rcorder 8 , .Xr rfcomm_pppd 8 , .Xr route 8 , -.Xr route6d 8 , -.Xr routed 8 , .Xr rpc.lockd 8 , .Xr rpc.statd 8 , .Xr rpc.tlsclntd 8 , diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -2500,8 +2500,6 @@ OLD_FILES+=usr/sbin/ip6addrctl OLD_FILES+=usr/sbin/mld6query OLD_FILES+=usr/sbin/ndp -OLD_FILES+=usr/sbin/rip6query -OLD_FILES+=usr/sbin/route6d OLD_FILES+=usr/sbin/rrenumd OLD_FILES+=usr/sbin/rtadvctl OLD_FILES+=usr/sbin/rtadvd @@ -2513,8 +2511,6 @@ OLD_FILES+=usr/share/man/man8/ip6addrctl.8.gz OLD_FILES+=usr/share/man/man8/mld6query.8.gz OLD_FILES+=usr/share/man/man8/ndp.8.gz -OLD_FILES+=usr/share/man/man8/rip6query.8.gz -OLD_FILES+=usr/share/man/man8/route6d.8.gz OLD_FILES+=usr/share/man/man8/rrenumd.8.gz OLD_FILES+=usr/share/man/man8/rtadvctl.8.gz OLD_FILES+=usr/share/man/man8/rtadvd.8.gz @@ -7114,16 +7110,6 @@ . endif .endif -.if ${MK_ROUTED} == no -OLD_FILES+=etc/rc.d/routed -OLD_FILES+=rescue/routed -OLD_FILES+=rescue/rtquery -OLD_FILES+=sbin/routed -OLD_FILES+=sbin/rtquery -OLD_FILES+=usr/share/man/man8/routed.8.gz -OLD_FILES+=usr/share/man/man8/rtquery.8.gz -.endif - .if ${MK_SENDMAIL} == no OLD_FILES+=etc/mtree/BSD.sendmail.dist OLD_FILES+=etc/newsyslog.conf.d/sendmail.conf diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -148,8 +148,6 @@ SUBDIR.${MK_INET6}+= ip6addrctl SUBDIR.${MK_INET6}+= mld6query SUBDIR.${MK_INET6}+= ndp -SUBDIR.${MK_INET6}+= rip6query -SUBDIR.${MK_INET6}+= route6d SUBDIR.${MK_INET6}+= rrenumd SUBDIR.${MK_INET6}+= rtadvctl SUBDIR.${MK_INET6}+= rtadvd diff --git a/usr.sbin/rip6query/Makefile b/usr.sbin/rip6query/Makefile deleted file mode 100644 --- a/usr.sbin/rip6query/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PACKAGE=rip -PROG= rip6query -MAN= rip6query.8 - -CFLAGS+= -I${.CURDIR:H}/route6d - -.include diff --git a/usr.sbin/rip6query/Makefile.depend b/usr.sbin/rip6query/Makefile.depend deleted file mode 100644 --- a/usr.sbin/rip6query/Makefile.depend +++ /dev/null @@ -1,16 +0,0 @@ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/arpa \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.sbin/rip6query/rip6query.8 b/usr.sbin/rip6query/rip6query.8 deleted file mode 100644 --- a/usr.sbin/rip6query/rip6query.8 +++ /dev/null @@ -1,69 +0,0 @@ -.\" $KAME: rip6query.8,v 1.4 2001/03/15 12:35:24 itojun Exp $ -.\" -.\" Copyright (C) 1998 and 1999 WIDE Project. -.\" 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. -.\" -.\" $Id: rip6query.8,v 1.2 2000/01/19 06:24:55 itojun Exp $ -.\" -.Dd May 20, 2025 -.Dt RIP6QUERY 8 -.Os -.Sh NAME -.Nm rip6query -.Nd RIPng debugging tool -.\" -.Sh DEPRECATION NOTICE -The -.Nm -utility is deprecated and will be removed in -.Fx 16.0 . -.\" -.Sh SYNOPSIS -.Nm -.Op Fl I Ar interface -.Ar destination -.\" -.Sh DESCRIPTION -The -.Nm -utility requests remote RIPng daemon on -.Ar destination -to dump RIPng routing information. -.Fl I -lets you specify outgoing -.Ar interface -for the query packet, -and is useful when link-local address is specified for -.Ar destination . -.\" -.Sh SEE ALSO -.Xr route6d 8 -.\" -.Sh HISTORY -The -.Nm -utility first appeared in WIDE Hydrangea IPv6 protocol stack kit. diff --git a/usr.sbin/rip6query/rip6query.c b/usr.sbin/rip6query/rip6query.c deleted file mode 100644 --- a/usr.sbin/rip6query/rip6query.c +++ /dev/null @@ -1,196 +0,0 @@ -/* $KAME: rip6query.c,v 1.11 2001/05/08 04:36:37 itojun Exp $ */ - -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "route6d.h" - -static int s; -static struct sockaddr_in6 sin6; -static struct rip6 *ripbuf; - -#define RIPSIZE(n) (sizeof(struct rip6) + (n-1) * sizeof(struct netinfo6)) - -int main(int, char **); -static void usage(void) __dead2; -static const char *sa_n2a(struct sockaddr *); -static const char *inet6_n2a(struct in6_addr *); - -int -main(int argc, char *argv[]) -{ - struct netinfo6 *np; - struct sockaddr_in6 fsock; - int i, n, len; - int c; - int ifidx = -1; - int error; - socklen_t flen; - char pbuf[10]; - struct addrinfo hints, *res; - - while ((c = getopt(argc, argv, "I:")) != -1) { - switch (c) { - case 'I': - ifidx = if_nametoindex(optarg); - if (ifidx == 0) { - errx(1, "invalid interface %s", optarg); - /*NOTREACHED*/ - } - break; - default: - usage(); - /*NOTREACHED*/ - } - } - argv += optind; - argc -= optind; - - if (argc != 1) { - usage(); - } - - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - err(1, "socket"); - /*NOTREACHED*/ - } - - /* getaddrinfo is preferred for addr@ifname syntax */ - snprintf(pbuf, sizeof(pbuf), "%d", RIP6_PORT); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; - error = getaddrinfo(argv[0], pbuf, &hints, &res); - if (error) { - errx(1, "%s: %s", argv[0], gai_strerror(error)); - /*NOTREACHED*/ - } - if (res->ai_next) { - errx(1, "%s: %s", argv[0], "resolved to multiple addrs"); - /*NOTREACHED*/ - } - if (sizeof(sin6) != res->ai_addrlen) { - errx(1, "%s: %s", argv[0], "invalid addrlen"); - /*NOTREACHED*/ - } - memcpy(&sin6, res->ai_addr, res->ai_addrlen); - if (ifidx >= 0) - sin6.sin6_scope_id = ifidx; - - if ((ripbuf = (struct rip6 *)malloc(BUFSIZ)) == NULL) { - err(1, "malloc"); - /*NOTREACHED*/ - } - ripbuf->rip6_cmd = RIP6_REQUEST; - ripbuf->rip6_vers = RIP6_VERSION; - ripbuf->rip6_res1[0] = 0; - ripbuf->rip6_res1[1] = 0; - np = ripbuf->rip6_nets; - bzero(&np->rip6_dest, sizeof(struct in6_addr)); - np->rip6_tag = 0; - np->rip6_plen = 0; - np->rip6_metric = HOPCNT_INFINITY6; - if (sendto(s, ripbuf, RIPSIZE(1), 0, (struct sockaddr *)&sin6, - sizeof(struct sockaddr_in6)) < 0) { - err(1, "send"); - /*NOTREACHED*/ - } - do { - flen = sizeof(fsock); - if ((len = recvfrom(s, ripbuf, BUFSIZ, 0, - (struct sockaddr *)&fsock, &flen)) < 0) { - err(1, "recvfrom"); - /*NOTREACHED*/ - } - printf("Response from %s len %d\n", - sa_n2a((struct sockaddr *)&fsock), len); - n = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / - sizeof(struct netinfo6); - np = ripbuf->rip6_nets; - for (i = 0; i < n; i++, np++) { - printf("\t%s/%d [%d]", inet6_n2a(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - if (np->rip6_tag) - printf(" tag=0x%x", ntohs(np->rip6_tag)); - printf("\n"); - } - } while (len == RIPSIZE(24)); - - return 0; -} - -static void -usage(void) -{ - fprintf(stderr, "usage: rip6query [-I iface] address\n"); - exit(1); -} - -/* getnameinfo() is preferred as we may be able to show ifindex as ifname */ -static const char * -sa_n2a(struct sockaddr *sa) -{ - static char buf[NI_MAXHOST]; - - if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), - NULL, 0, NI_NUMERICHOST) != 0) { - snprintf(buf, sizeof(buf), "%s", "(invalid)"); - } - return buf; -} - -static const char * -inet6_n2a(struct in6_addr *addr) -{ - static char buf[NI_MAXHOST]; - - return inet_ntop(AF_INET6, addr, buf, sizeof(buf)); -} diff --git a/usr.sbin/route6d/Makefile b/usr.sbin/route6d/Makefile deleted file mode 100644 --- a/usr.sbin/route6d/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -PACKAGE=rip -PROG= route6d -MAN= route6d.8 - -CFLAGS+= -DHAVE_POLL_H - -WARNS?= 1 - -.include diff --git a/usr.sbin/route6d/Makefile.depend b/usr.sbin/route6d/Makefile.depend deleted file mode 100644 --- a/usr.sbin/route6d/Makefile.depend +++ /dev/null @@ -1,16 +0,0 @@ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/arpa \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.sbin/route6d/misc/chkrt b/usr.sbin/route6d/misc/chkrt deleted file mode 100755 --- a/usr.sbin/route6d/misc/chkrt +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/perl -# -# -$dump="/var/tmp/route6d_dump"; -$pidfile="/var/run/route6d.pid"; - -system("rm -f $dump"); - -open(FD, "< $pidfile") || die "Can not open $pidfile"; -$_ = ; -chop; -close(FD); -system("kill -INT $_"); - -open(NS, "/usr/bin/netstat -r -n|") || die "Can not open netstat"; -while () { - chop; - next unless (/^3f/ || /^5f/); - @f = split(/\s+/); - $gw{$f[0]} = $f[1]; - $int{$f[0]} = $f[3]; -} -close(NS); - -$err=0; -sleep(2); -open(FD, "< $dump") || die "Can not open $dump"; -while () { - chop; - next unless (/^ 3f/ || /^ 5f/); - @f = split(/\s+/); - $dst = $f[1]; - $f[2] =~ /if\(\d:([a-z0-9]+)\)/; - $intf = $1; - $f[3] =~ /gw\(([a-z0-9:]+)\)/; - $gateway = $1; - $f[4] =~ /\[(\d+)\]/; - $metric = $1; - $f[5] =~ /age\((\d+)\)/; - $age = $1; - unless (defined($gw{$dst})) { - print "NOT FOUND: $dst $intf $gateway $metric $age\n"; - $err++; - next; - } - if ($gw{$dst} ne $gateway && $gw{$dst} !~ /link#\d+/) { - print "WRONG GW: $dst $intf $gateway $metric $age\n"; - print "kernel gw: $gw{$dst}\n"; - $err++; - next; - } - if ($int{$dst} ne $intf) { - print "WRONG IF: $dst $intf $gateway $metric $age\n"; - print "kernel if: $int{$dst}\n"; - $err++; - next; - } -} -close(FD); - -if ($err == 0) { - print "No error found\n"; -} diff --git a/usr.sbin/route6d/misc/cksum.c b/usr.sbin/route6d/misc/cksum.c deleted file mode 100644 --- a/usr.sbin/route6d/misc/cksum.c +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. - */ - -#include - -unsigned short buf[BUFSIZ]; - -main() -{ - int i; - unsigned short *p = buf, *q = &buf[4]; - unsigned long sum, sum2; - - while (scanf("%x", &i) != EOF) { - *p++ = i; printf("%d ", i); - } - printf("\n"); - - sum = buf[2] + (buf[3] >> 8) & 0xff; - while (q != p) - sum += (*q++ & 0xffff); - sum2 = (sum & 0xffff) + (sum >> 16) & 0xffff; - printf("%x, %x\n", sum, sum2); -} diff --git a/usr.sbin/route6d/route6d.h b/usr.sbin/route6d/route6d.h deleted file mode 100644 --- a/usr.sbin/route6d/route6d.h +++ /dev/null @@ -1,82 +0,0 @@ -/* $KAME: route6d.h,v 1.8 2003/05/28 09:11:13 itojun Exp $ */ - -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. - */ - -#define ROUTE6D_DUMP "/var/run/route6d_dump" -#define ROUTE6D_PID "/var/run/route6d.pid" - -#define RIP6_VERSION 1 - -#define RIP6_REQUEST 1 -#define RIP6_RESPONSE 2 - -#define IFC_CHANGED 1 - -struct netinfo6 { - struct in6_addr rip6_dest; - u_short rip6_tag; - u_char rip6_plen; - u_char rip6_metric; -}; - -struct rip6 { - u_char rip6_cmd; - u_char rip6_vers; - u_char rip6_res1[2]; - struct netinfo6 rip6_nets[1]; -}; - -#define HOPCNT_INFINITY6 16 -#define NEXTHOP_METRIC 0xff -#define RIP6_MAXMTU 1500 - -#define IFMINMTU 1280 - -#ifndef DEBUG -#define SUPPLY_INTERVAL6 30 -#define RIP_LIFETIME 180 -#define RIP_HOLDDOWN 120 -#define RIP_TRIG_INT6_MAX 5 -#define RIP_TRIG_INT6_MIN 1 -#else -/* only for debugging; can not wait for 30sec to appear a bug */ -#define SUPPLY_INTERVAL6 10 -#define RIP_LIFETIME 60 -#define RIP_HOLDDOWN 40 -#define RIP_TRIG_INT6_MAX 5 -#define RIP_TRIG_INT6_MIN 1 -#endif - -#define RIP6_PORT 521 -#define RIP6_DEST "ff02::9" - -#define LOOPBACK_IF "lo0" diff --git a/usr.sbin/route6d/route6d.8 b/usr.sbin/route6d/route6d.8 deleted file mode 100644 --- a/usr.sbin/route6d/route6d.8 +++ /dev/null @@ -1,300 +0,0 @@ -.\" $KAME: route6d.8,v 1.10 2000/11/24 11:57:18 itojun Exp $ -.\" -.\" Copyright (c) 1996 WIDE Project. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modifications, are permitted provided that the above copyright notice -.\" and this paragraph are duplicated in all such forms and that any -.\" documentation, advertising materials, and other materials related to -.\" such distribution and use acknowledge that the software was developed -.\" by the WIDE Project, Japan. The name of the Project may not be used to -.\" endorse or promote products derived from this software without -.\" specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' -.\" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT -.\" LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -.\" A PARTICULAR PURPOSE. -.\" -.Dd May 20, 2025 -.Dt ROUTE6D 8 -.Os -.Sh NAME -.Nm route6d -.Nd RIP6 Routing Daemon -.Sh DEPRECATION NOTICE -The -.Nm -utility is deprecated and will be removed in -.Fx 16.0 . -.Sh SYNOPSIS -.Nm -.Op Fl adDhlnqsS -.Bk -words -.Op Fl R Ar routelog -.Ek -.Bk -words -.Op Fl A Ar prefix/preflen,if1[,if2...\&] -.Ek -.Bk -words -.Op Fl L Ar prefix/preflen,if1[,if2...\&] -.Ek -.Bk -words -.Op Fl N Ar if1[,if2...\&] -.Ek -.Bk -words -.Op Fl O Ar prefix/preflen,if1[,if2...\&] -.Ek -.Bk -words -.Op Fl P Ar number -.Ek -.Bk -words -.Op Fl p Ar pidfile -.Ek -.Bk -words -.Op Fl Q Ar number -.Ek -.Bk -words -.Op Fl T Ar if1[,if2...\&] -.Ek -.Bk -words -.Op Fl t Ar tag -.Ek -.\" -.Sh DESCRIPTION -The -.Nm -utility is a routing daemon which supports RIP over IPv6. -.Pp -Options are: -.Bl -tag -width indent -.\" -.It Fl a -Enables aging of the statically defined routes. -With this option, any -statically defined routes will be removed unless corresponding updates -arrive as if the routes are received at the startup of -.Nm . -.\" -.It Fl R Ar routelog -This option makes the -.Nm -to log the route change (add/delete) to the file -.Ar routelog . -.\" -.It Fl A Ar prefix/preflen,if1[,if2...] -This option is used for aggregating routes. -.Ar prefix/preflen -specifies the prefix and the prefix length of the -aggregated route. -When advertising routes, -.Nm -filters specific routes covered by the aggregate, -and advertises the aggregated route -.Ar prefix/preflen , -to the interfaces specified in the comma-separated interface list, -.Ar if1[,if2...] . -The characters -.Qq Li * , -.Qq Li \&? , -and -.Qq Li \&[ -in the interface list will be interpreted as shell-style pattern. -The -.Nm -utility creates a static route to -.Ar prefix/preflen -with -.Dv RTF_REJECT -flag, into the kernel routing table. -.\" -.It Fl d -Enables output of debugging message. -This option also instructs -.Nm -to run in foreground mode -(does not become daemon). -.\" -.It Fl D -Enables extensive output of debugging message. -This option also instructs -.Nm -to run in foreground mode -(does not become daemon). -.\" -.It Fl h -Disables the split horizon processing. -.\" -.It Fl l -By default, -.Nm -will not exchange site local routes for safety reasons. -This is because semantics of site local address space is rather vague -(specification is still in being worked), -and there is no good way to define site local boundary. -With -.Fl l -option, -.Nm -will exchange site local routes as well. -It must not be used on site boundary routers, -since -.Fl l -option assumes that all interfaces are in the same site. -.\" -.It Fl L Ar prefix/preflen,if1[,if2...] -Filter incoming routes from interfaces -.Ar if1,[if2...] . -The -.Nm -utility will accept incoming routes that are in -.Ar prefix/preflen . -If multiple -.Fl L -options are specified, any routes that match one of the options is accepted. -.Li ::/0 -is treated specially as default route, not -.Do -any route that has longer prefix length than, or equal to 0 -.Dc . -If you would like to accept any route, specify no -.Fl L -option. -For example, with -.Do -.Fl L -.Li 2001:db8::/16,if1 -.Fl L -.Li ::/0,if1 -.Dc -.Nm -will accept default route and routes in 6bone test address, but no others. -.\" -.It Fl n -Do not update the kernel routing table. -.\" -.It Fl N Ar if1[,if2...] -Do not listen to, or advertise, route from/to interfaces specified by -.Ar if1,[if2...] . -.\" -.It Fl O Ar prefix/preflen,if1[,if2...] -Restrict route advertisement toward interfaces specified by -.Ar if1,[if2...] . -With this option -.Nm -will only advertise routes that matches -.Ar prefix/preflen . -.It Fl P Ar number -Specifies routes to be ignored in calculation of expiration timer. -The -.Ar number -must be -.Li 1 , -.Li 2 , -or -.Li 3 -and it means route flags of -.Li RTF_PROTO1 , -.Li RTF_PROTO2 , -or -.Li RTF_PROTO3 . -When -.Li 1 -is specified, routes with -.Li RTF_PROTO1 -will never expire. -.It Fl p Ar pidfile -Specifies an alternative file in which to store the process ID. -The default is -.Pa /var/run/route6d.pid . -.It Fl Q Ar number -Specifies flag which will be used for routes added by RIP protocol. -The default is -.Li 2 Pq Li RTF_PROTO2 . -.\" -.It Fl q -Makes -.Nm -in listen-only mode. -No advertisement is sent. -.\" -.It Fl s -Makes -.Nm -to advertise the statically defined routes which exist in the kernel routing -table when -.Nm -invoked. -Announcements obey the regular split horizon rule. -.\" -.It Fl S -This option is the same as -.Fl s -option except that no split horizon rule does apply. -.\" -.It Fl T Ar if1[,if2...] -Advertise only default route, toward -.Ar if1,[if2...] . -.\" -.It Fl t Ar tag -Attach route tag -.Ar tag -to originated route entries. -.Ar tag -can be decimal, octal prefixed by -.Li 0 , -or hexadecimal prefixed by -.Li 0x . -.\" -.El -.Pp -Upon receipt of signal -.Dv SIGINT -or -.Dv SIGUSR1 , -.Nm -will dump the current internal state into -.Pa /var/run/route6d_dump . -.\" -.Sh FILES -.Bl -tag -width /var/run/route6d_dump -compact -.It Pa /var/run/route6d_dump -dumps internal state on -.Dv SIGINT -or -.Dv SIGUSR1 -.El -.\" -.Sh SEE ALSO -.Rs -.%A G. Malkin -.%A R. Minnear -.%T RIPng for IPv6 -.%R RFC2080 -.%D January 1997 -.Re -.\" -.Sh NOTE -The -.Nm -utility uses IPv6 advanced API, -defined in RFC2292, -for communicating with peers using link-local addresses. -.Pp -Internally -.Nm -embeds interface identifier into bit 32 to 63 of link-local addresses -.Li ( fe80::xx -and -.Li ff02::xx ) -so they will be visible on internal state dump file -.Pq Pa /var/run/route6d_dump . -.Pp -Routing table manipulation differs from IPv6 implementation to implementation. -Currently -.Nm -obeys WIDE Hydrangea/KAME IPv6 kernel, -and will not be able to run on other platforms. -.Pp -Current -.Nm -does not reduce the rate of the triggered updates when consecutive updates -arrive. diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c deleted file mode 100644 --- a/usr.sbin/route6d/route6d.c +++ /dev/null @@ -1,3580 +0,0 @@ -/* $KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $ */ - -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_POLL_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "route6d.h" - -#define MAXFILTER 40 -#define RT_DUMP_MAXRETRY 15 - -#ifdef DEBUG -#define INIT_INTERVAL6 6 -#else -#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ -#endif - -/* alignment constraint for routing socket */ -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) - -struct ifc { /* Configuration of an interface */ - TAILQ_ENTRY(ifc) ifc_next; - - char ifc_name[IFNAMSIZ]; /* if name */ - int ifc_index; /* if index */ - int ifc_mtu; /* if mtu */ - int ifc_metric; /* if metric */ - u_int ifc_flags; /* flags */ - short ifc_cflags; /* IFC_XXX */ - struct in6_addr ifc_mylladdr; /* my link-local address */ - struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ - TAILQ_HEAD(, ifac) ifc_ifac_head; /* list of AF_INET6 addrs */ - TAILQ_HEAD(, iff) ifc_iff_head; /* list of filters */ - int ifc_joined; /* joined to ff02::9 */ -}; -static TAILQ_HEAD(, ifc) ifc_head = TAILQ_HEAD_INITIALIZER(ifc_head); - -struct ifac { /* Address associated to an interface */ - TAILQ_ENTRY(ifac) ifac_next; - - struct ifc *ifac_ifc; /* back pointer */ - struct in6_addr ifac_addr; /* address */ - struct in6_addr ifac_raddr; /* remote address, valid in p2p */ - int ifac_scope_id; /* scope id */ - int ifac_plen; /* prefix length */ -}; - -struct iff { /* Filters for an interface */ - TAILQ_ENTRY(iff) iff_next; - - int iff_type; - struct in6_addr iff_addr; - int iff_plen; -}; - -static struct ifc **index2ifc; -static unsigned int nindex2ifc; -static struct ifc *loopifcp = NULL; /* pointing to loopback */ -#ifdef HAVE_POLL_H -static struct pollfd set[2]; -#else -static fd_set *sockvecp; /* vector to select() for receiving */ -static fd_set *recvecp; -static int fdmasks; -static int maxfd; /* maximum fd for select() */ -#endif -static int rtsock; /* the routing socket */ -static int ripsock; /* socket to send/receive RIP datagram */ - -static struct rip6 *ripbuf; /* packet buffer for sending */ - -/* - * Maintain the routes in a linked list. When the number of the routes - * grows, somebody would like to introduce a hash based or a radix tree - * based structure. I believe the number of routes handled by RIP is - * limited and I don't have to manage a complex data structure, however. - * - * One of the major drawbacks of the linear linked list is the difficulty - * of representing the relationship between a couple of routes. This may - * be a significant problem when we have to support route aggregation with - * suppressing the specifics covered by the aggregate. - */ - -struct riprt { - TAILQ_ENTRY(riprt) rrt_next; /* next destination */ - - struct riprt *rrt_same; /* same destination - future use */ - struct netinfo6 rrt_info; /* network info */ - struct in6_addr rrt_gw; /* gateway */ - u_long rrt_flags; /* kernel routing table flags */ - u_long rrt_rflags; /* route6d routing table flags */ - time_t rrt_t; /* when the route validated */ - int rrt_index; /* ifindex from which this route got */ -}; -static TAILQ_HEAD(, riprt) riprt_head = TAILQ_HEAD_INITIALIZER(riprt_head); - -static int dflag = 0; /* debug flag */ -static int qflag = 0; /* quiet flag */ -static int nflag = 0; /* don't update kernel routing table */ -static int aflag = 0; /* age out even the statically defined routes */ -static int hflag = 0; /* don't split horizon */ -static int lflag = 0; /* exchange site local routes */ -static int Pflag = 0; /* don't age out routes with RTF_PROTO[123] */ -static int Qflag = RTF_PROTO2; /* set RTF_PROTO[123] flag to routes by RIPng */ -static int sflag = 0; /* announce static routes w/ split horizon */ -static int Sflag = 0; /* announce static routes to every interface */ -static unsigned long routetag = 0; /* route tag attached on originating case */ - -static char *filter[MAXFILTER]; -static int filtertype[MAXFILTER]; -static int nfilter = 0; - -static pid_t pid; - -static struct sockaddr_storage ripsin; - -static int interval = 1; -static time_t nextalarm = 0; -#if 0 -static time_t sup_trig_update = 0; -#endif - -static FILE *rtlog = NULL; - -static int logopened = 0; - -static int seq = 0; - -static volatile sig_atomic_t seenalrm; -static volatile sig_atomic_t seenquit; -static volatile sig_atomic_t seenusr1; - -#define RRTF_AGGREGATE 0x08000000 -#define RRTF_NOADVERTISE 0x10000000 -#define RRTF_NH_NOT_LLADDR 0x20000000 -#define RRTF_SENDANYWAY 0x40000000 -#define RRTF_CHANGED 0x80000000 - -static void sighandler(int); -static void ripalarm(void); -static void riprecv(void); -static void ripsend(struct ifc *, struct sockaddr_in6 *, int); -static int out_filter(struct riprt *, struct ifc *); -static void init(void); -static void ifconfig(void); -static int ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); -static void rtrecv(void); -static int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *, - const struct sockaddr_in6 *); -static int rt_deladdr(struct ifc *, const struct sockaddr_in6 *, - const struct sockaddr_in6 *); -static void filterconfig(void); -static int getifmtu(int); -static const char *rttypes(struct rt_msghdr *); -static const char *rtflags(struct rt_msghdr *); -static const char *ifflags(int); -static int ifrt(struct ifc *, int); -static void ifrt_p2p(struct ifc *, int); -static void applyplen(struct in6_addr *, int); -static void ifrtdump(int); -static void ifdump(int); -static void ifdump0(FILE *, const struct ifc *); -static void ifremove(int); -static void rtdump(int); -static void rt_entry(struct rt_msghdr *, int); -static void rtdexit(void); -static void riprequest(struct ifc *, struct netinfo6 *, int, - struct sockaddr_in6 *); -static void ripflush(struct ifc *, struct sockaddr_in6 *, int, struct netinfo6 *np); -static void sendrequest(struct ifc *); -static int sin6mask2len(const struct sockaddr_in6 *); -static int mask2len(const struct in6_addr *, int); -static int sendpacket(struct sockaddr_in6 *, int); -static int addroute(struct riprt *, const struct in6_addr *, struct ifc *); -static int delroute(struct netinfo6 *, struct in6_addr *); -#if 0 -static struct in6_addr *getroute(struct netinfo6 *, struct in6_addr *); -#endif -static void krtread(int); -static int tobeadv(struct riprt *, struct ifc *); -static char *allocopy(char *); -static char *hms(void); -static const char *inet6_n2p(const struct in6_addr *); -static struct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int); -static struct in6_addr *plen2mask(int); -static struct riprt *rtsearch(struct netinfo6 *); -static int ripinterval(int); -#if 0 -static time_t ripsuptrig(void); -#endif -static void fatal(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -static void trace(int, const char *, ...) - __attribute__((__format__(__printf__, 2, 3))); -static void tracet(int, const char *, ...) - __attribute__((__format__(__printf__, 2, 3))); -static struct ifc *ifc_find(char *); -static struct iff *iff_find(struct ifc *, int); -static void setindex2ifc(int, struct ifc *); - -#define MALLOC(type) ((type *)malloc(sizeof(type))) - -#define IFIL_TYPE_ANY 0x0 -#define IFIL_TYPE_A 'A' -#define IFIL_TYPE_N 'N' -#define IFIL_TYPE_T 'T' -#define IFIL_TYPE_O 'O' -#define IFIL_TYPE_L 'L' - -int -main(int argc, char *argv[]) -{ - int ch; - int error = 0; - unsigned long proto; - struct ifc *ifcp; - sigset_t mask, omask; - const char *pidfile = ROUTE6D_PID; - FILE *pidfh; - char *progname; - char *ep; - - progname = strrchr(*argv, '/'); - if (progname) - progname++; - else - progname = *argv; - - pid = getpid(); - while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnp:P:Q:qsS")) != -1) { - switch (ch) { - case 'A': - case 'N': - case 'O': - case 'T': - case 'L': - if (nfilter >= MAXFILTER) { - fatal("Exceeds MAXFILTER"); - /*NOTREACHED*/ - } - filtertype[nfilter] = ch; - filter[nfilter++] = allocopy(optarg); - break; - case 't': - ep = NULL; - routetag = strtoul(optarg, &ep, 0); - if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { - fatal("invalid route tag"); - /*NOTREACHED*/ - } - break; - case 'p': - pidfile = optarg; - break; - case 'P': - ep = NULL; - proto = strtoul(optarg, &ep, 0); - if (!ep || *ep != '\0' || 3 < proto) { - fatal("invalid P flag"); - /*NOTREACHED*/ - } - if (proto == 0) - Pflag = 0; - if (proto == 1) - Pflag |= RTF_PROTO1; - if (proto == 2) - Pflag |= RTF_PROTO2; - if (proto == 3) - Pflag |= RTF_PROTO3; - break; - case 'Q': - ep = NULL; - proto = strtoul(optarg, &ep, 0); - if (!ep || *ep != '\0' || 3 < proto) { - fatal("invalid Q flag"); - /*NOTREACHED*/ - } - if (proto == 0) - Qflag = 0; - if (proto == 1) - Qflag |= RTF_PROTO1; - if (proto == 2) - Qflag |= RTF_PROTO2; - if (proto == 3) - Qflag |= RTF_PROTO3; - break; - case 'R': - if ((rtlog = fopen(optarg, "w")) == NULL) { - fatal("Can not write to routelog"); - /*NOTREACHED*/ - } - break; -#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) - FLAG('a', aflag, 1); break; - FLAG('d', dflag, 1); break; - FLAG('D', dflag, 2); break; - FLAG('h', hflag, 1); break; - FLAG('l', lflag, 1); break; - FLAG('n', nflag, 1); break; - FLAG('q', qflag, 1); break; - FLAG('s', sflag, 1); break; - FLAG('S', Sflag, 1); break; -#undef FLAG - default: - fatal("Invalid option specified, terminating"); - /*NOTREACHED*/ - } - } - argc -= optind; - argv += optind; - if (argc > 0) { - fatal("bogus extra arguments"); - /*NOTREACHED*/ - } - - if (geteuid()) { - nflag = 1; - fprintf(stderr, "No kernel update is allowed\n"); - } - - if (dflag == 0) { - if (daemon(0, 0) < 0) { - fatal("daemon"); - /*NOTREACHED*/ - } - } - - openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); - logopened++; - - if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) - fatal("malloc"); - memset(ripbuf, 0, RIP6_MAXMTU); - ripbuf->rip6_cmd = RIP6_RESPONSE; - ripbuf->rip6_vers = RIP6_VERSION; - ripbuf->rip6_res1[0] = 0; - ripbuf->rip6_res1[1] = 0; - - init(); - ifconfig(); - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (ifcp->ifc_index < 0) { - fprintf(stderr, "No ifindex found at %s " - "(no link-local address?)\n", ifcp->ifc_name); - error++; - } - } - if (error) - exit(1); - if (loopifcp == NULL) { - fatal("No loopback found"); - /*NOTREACHED*/ - } - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - ifrt(ifcp, 0); - } - filterconfig(); - krtread(0); - if (dflag) - ifrtdump(0); - - pid = getpid(); - if ((pidfh = fopen(pidfile, "w")) != NULL) { - fprintf(pidfh, "%d\n", pid); - fclose(pidfh); - } - - if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { - fatal("malloc"); - /*NOTREACHED*/ - } - memset(ripbuf, 0, RIP6_MAXMTU); - ripbuf->rip6_cmd = RIP6_RESPONSE; - ripbuf->rip6_vers = RIP6_VERSION; - ripbuf->rip6_res1[0] = 0; - ripbuf->rip6_res1[1] = 0; - - if (signal(SIGALRM, sighandler) == SIG_ERR || - signal(SIGQUIT, sighandler) == SIG_ERR || - signal(SIGTERM, sighandler) == SIG_ERR || - signal(SIGUSR1, sighandler) == SIG_ERR || - signal(SIGHUP, sighandler) == SIG_ERR || - signal(SIGINT, sighandler) == SIG_ERR) { - fatal("signal"); - /*NOTREACHED*/ - } - /* - * To avoid rip packet congestion (not on a cable but in this - * process), wait for a moment to send the first RIP6_RESPONSE - * packets. - */ - alarm(ripinterval(INIT_INTERVAL6)); - - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (iff_find(ifcp, IFIL_TYPE_N) != NULL) - continue; - if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) - sendrequest(ifcp); - } - - syslog(LOG_INFO, "**** Started ****"); - sigemptyset(&mask); - sigaddset(&mask, SIGALRM); - while (1) { - if (seenalrm) { - ripalarm(); - seenalrm = 0; - continue; - } - if (seenquit) { - rtdexit(); - seenquit = 0; - continue; - } - if (seenusr1) { - ifrtdump(SIGUSR1); - seenusr1 = 0; - continue; - } - -#ifdef HAVE_POLL_H - switch (poll(set, 2, INFTIM)) -#else - memcpy(recvecp, sockvecp, fdmasks); - switch (select(maxfd + 1, recvecp, 0, 0, 0)) -#endif - { - case -1: - if (errno != EINTR) { - fatal("select"); - /*NOTREACHED*/ - } - continue; - case 0: - continue; - default: -#ifdef HAVE_POLL_H - if (set[0].revents & POLLIN) -#else - if (FD_ISSET(ripsock, recvecp)) -#endif - { - sigprocmask(SIG_BLOCK, &mask, &omask); - riprecv(); - sigprocmask(SIG_SETMASK, &omask, NULL); - } -#ifdef HAVE_POLL_H - if (set[1].revents & POLLIN) -#else - if (FD_ISSET(rtsock, recvecp)) -#endif - { - sigprocmask(SIG_BLOCK, &mask, &omask); - rtrecv(); - sigprocmask(SIG_SETMASK, &omask, NULL); - } - } - } -} - -static void -sighandler(int signo) -{ - - switch (signo) { - case SIGALRM: - seenalrm++; - break; - case SIGQUIT: - case SIGTERM: - seenquit++; - break; - case SIGUSR1: - case SIGHUP: - case SIGINT: - seenusr1++; - break; - } -} - -/* - * gracefully exits after resetting sockopts. - */ -/* ARGSUSED */ -static void -rtdexit(void) -{ - struct riprt *rrt; - - alarm(0); - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (rrt->rrt_rflags & RRTF_AGGREGATE) { - delroute(&rrt->rrt_info, &rrt->rrt_gw); - } - } - close(ripsock); - close(rtsock); - syslog(LOG_INFO, "**** Terminated ****"); - closelog(); - exit(1); -} - -/* - * Called periodically: - * 1. age out the learned route. remove it if necessary. - * 2. submit RIP6_RESPONSE packets. - * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have - * to invoke this function in every 1 or 5 or 10 seconds only to age the - * routes more precisely. - */ -/* ARGSUSED */ -static void -ripalarm(void) -{ - struct ifc *ifcp; - struct riprt *rrt, *rrt_tmp; - time_t t_lifetime, t_holddown; - - /* age the RIP routes */ - t_lifetime = time(NULL) - RIP_LIFETIME; - t_holddown = t_lifetime - RIP_HOLDDOWN; - TAILQ_FOREACH_SAFE(rrt, &riprt_head, rrt_next, rrt_tmp) { - if (rrt->rrt_t == 0) - continue; - else if (rrt->rrt_t < t_holddown) { - TAILQ_REMOVE(&riprt_head, rrt, rrt_next); - delroute(&rrt->rrt_info, &rrt->rrt_gw); - free(rrt); - } else if (rrt->rrt_t < t_lifetime) - rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; - } - /* Supply updates */ - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) - ripsend(ifcp, &ifcp->ifc_ripsin, 0); - } - alarm(ripinterval(SUPPLY_INTERVAL6)); -} - -static void -init(void) -{ - int error; - const int int0 = 0, int1 = 1, int255 = 255; - struct addrinfo hints, *res; - char port[NI_MAXSERV]; - - TAILQ_INIT(&ifc_head); - nindex2ifc = 0; /*initial guess*/ - index2ifc = NULL; - snprintf(port, sizeof(port), "%u", RIP6_PORT); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET6; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_PASSIVE; - error = getaddrinfo(NULL, port, &hints, &res); - if (error) { - fatal("%s", gai_strerror(error)); - /*NOTREACHED*/ - } - if (res->ai_next) { - fatal(":: resolved to multiple address"); - /*NOTREACHED*/ - } - - ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (ripsock < 0) { - fatal("rip socket"); - /*NOTREACHED*/ - } -#ifdef IPV6_V6ONLY - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, - &int1, sizeof(int1)) < 0) { - fatal("rip IPV6_V6ONLY"); - /*NOTREACHED*/ - } -#endif - if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { - fatal("rip bind"); - /*NOTREACHED*/ - } - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &int255, sizeof(int255)) < 0) { - fatal("rip IPV6_MULTICAST_HOPS"); - /*NOTREACHED*/ - } - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &int0, sizeof(int0)) < 0) { - fatal("rip IPV6_MULTICAST_LOOP"); - /*NOTREACHED*/ - } - -#ifdef IPV6_RECVPKTINFO - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &int1, sizeof(int1)) < 0) { - fatal("rip IPV6_RECVPKTINFO"); - /*NOTREACHED*/ - } -#else /* old adv. API */ - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, - &int1, sizeof(int1)) < 0) { - fatal("rip IPV6_PKTINFO"); - /*NOTREACHED*/ - } -#endif - -#ifdef IPV6_RECVPKTINFO - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, - &int1, sizeof(int1)) < 0) { - fatal("rip IPV6_RECVHOPLIMIT"); - /*NOTREACHED*/ - } -#else /* old adv. API */ - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT, - &int1, sizeof(int1)) < 0) { - fatal("rip IPV6_HOPLIMIT"); - /*NOTREACHED*/ - } -#endif - freeaddrinfo(res); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET6; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - error = getaddrinfo(RIP6_DEST, port, &hints, &res); - if (error) { - fatal("%s", gai_strerror(error)); - /*NOTREACHED*/ - } - if (res->ai_next) { - fatal("%s resolved to multiple address", RIP6_DEST); - /*NOTREACHED*/ - } - memcpy(&ripsin, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - -#ifdef HAVE_POLL_H - set[0].fd = ripsock; - set[0].events = POLLIN; -#else - maxfd = ripsock; -#endif - - if (nflag == 0) { - if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { - fatal("route socket"); - /*NOTREACHED*/ - } -#ifdef HAVE_POLL_H - set[1].fd = rtsock; - set[1].events = POLLIN; -#else - if (rtsock > maxfd) - maxfd = rtsock; -#endif - } else { -#ifdef HAVE_POLL_H - set[1].fd = -1; -#else - rtsock = -1; /*just for safety */ -#endif - } - -#ifndef HAVE_POLL_H - fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); - if ((sockvecp = malloc(fdmasks)) == NULL) { - fatal("malloc"); - /*NOTREACHED*/ - } - if ((recvecp = malloc(fdmasks)) == NULL) { - fatal("malloc"); - /*NOTREACHED*/ - } - memset(sockvecp, 0, fdmasks); - FD_SET(ripsock, sockvecp); - if (rtsock >= 0) - FD_SET(rtsock, sockvecp); -#endif -} - -#define RIPSIZE(n) \ - (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) - -/* - * ripflush flushes the rip datagram stored in the rip buffer - */ -static void -ripflush(struct ifc *ifcp, struct sockaddr_in6 *sin6, int nrt, struct netinfo6 *np) -{ - int i; - int error; - - if (ifcp) - tracet(1, "Send(%s): info(%d) to %s.%d\n", - ifcp->ifc_name, nrt, - inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); - else - tracet(1, "Send: info(%d) to %s.%d\n", - nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); - if (dflag >= 2) { - np = ripbuf->rip6_nets; - for (i = 0; i < nrt; i++, np++) { - if (np->rip6_metric == NEXTHOP_METRIC) { - if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) - trace(2, " NextHop reset"); - else { - trace(2, " NextHop %s", - inet6_n2p(&np->rip6_dest)); - } - } else { - trace(2, " %s/%d[%d]", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - } - if (np->rip6_tag) { - trace(2, " tag=0x%04x", - ntohs(np->rip6_tag) & 0xffff); - } - trace(2, "\n"); - } - } - error = sendpacket(sin6, RIPSIZE(nrt)); - if (error == EAFNOSUPPORT) { - /* Protocol not supported */ - if (ifcp != NULL) { - tracet(1, "Could not send info to %s (%s): " - "set IFF_UP to 0\n", - ifcp->ifc_name, - inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); - /* As if down for AF_INET6 */ - ifcp->ifc_flags &= ~IFF_UP; - } else { - tracet(1, "Could not send info to %s\n", - inet6_n2p(&sin6->sin6_addr)); - } - } -} - -/* - * Generate RIP6_RESPONSE packets and send them. - */ -static void -ripsend(struct ifc *ifcp, struct sockaddr_in6 *sin6, int flag) -{ - struct riprt *rrt; - struct in6_addr *nh; /* next hop */ - struct netinfo6 *np; - int maxrte; - int nrt; - - if (qflag) - return; - - if (ifcp == NULL) { - /* - * Request from non-link local address is not - * a regular route6d update. - */ - maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - - sizeof(struct udphdr) - - sizeof(struct rip6) + sizeof(struct netinfo6)) / - sizeof(struct netinfo6); - nh = NULL; - nrt = 0; - np = ripbuf->rip6_nets; - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (rrt->rrt_rflags & RRTF_NOADVERTISE) - continue; - /* Put the route to the buffer */ - *np = rrt->rrt_info; - np++; nrt++; - if (nrt == maxrte) { - ripflush(NULL, sin6, nrt, np); - nh = NULL; - nrt = 0; - np = ripbuf->rip6_nets; - } - } - if (nrt) /* Send last packet */ - ripflush(NULL, sin6, nrt, np); - return; - } - - if ((flag & RRTF_SENDANYWAY) == 0 && - (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) - return; - - /* -N: no use */ - if (iff_find(ifcp, IFIL_TYPE_N) != NULL) - return; - - /* -T: generate default route only */ - if (iff_find(ifcp, IFIL_TYPE_T) != NULL) { - struct netinfo6 rrt_info; - memset(&rrt_info, 0, sizeof(struct netinfo6)); - rrt_info.rip6_dest = in6addr_any; - rrt_info.rip6_plen = 0; - rrt_info.rip6_metric = 1; - rrt_info.rip6_metric += ifcp->ifc_metric; - rrt_info.rip6_tag = htons(routetag & 0xffff); - np = ripbuf->rip6_nets; - *np = rrt_info; - nrt = 1; - ripflush(ifcp, sin6, nrt, np); - return; - } - - maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - - sizeof(struct udphdr) - - sizeof(struct rip6) + sizeof(struct netinfo6)) / - sizeof(struct netinfo6); - - nrt = 0; np = ripbuf->rip6_nets; nh = NULL; - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (rrt->rrt_rflags & RRTF_NOADVERTISE) - continue; - - /* Need to check filter here */ - if (out_filter(rrt, ifcp) == 0) - continue; - - /* Check split horizon and other conditions */ - if (tobeadv(rrt, ifcp) == 0) - continue; - - /* Only considers the routes with flag if specified */ - if ((flag & RRTF_CHANGED) && - (rrt->rrt_rflags & RRTF_CHANGED) == 0) - continue; - - /* Check nexthop */ - if (rrt->rrt_index == ifcp->ifc_index && - !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && - (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { - if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { - if (nrt == maxrte - 2) { - ripflush(ifcp, sin6, nrt, np); - nh = NULL; - nrt = 0; - np = ripbuf->rip6_nets; - } - - np->rip6_dest = rrt->rrt_gw; - np->rip6_plen = 0; - np->rip6_tag = 0; - np->rip6_metric = NEXTHOP_METRIC; - nh = &rrt->rrt_gw; - np++; nrt++; - } - } else if (nh && (rrt->rrt_index != ifcp->ifc_index || - !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || - rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { - /* Reset nexthop */ - if (nrt == maxrte - 2) { - ripflush(ifcp, sin6, nrt, np); - nh = NULL; - nrt = 0; - np = ripbuf->rip6_nets; - } - memset(np, 0, sizeof(struct netinfo6)); - np->rip6_metric = NEXTHOP_METRIC; - nh = NULL; - np++; nrt++; - } - - /* Put the route to the buffer */ - *np = rrt->rrt_info; - np++; nrt++; - if (nrt == maxrte) { - ripflush(ifcp, sin6, nrt, np); - nh = NULL; - nrt = 0; - np = ripbuf->rip6_nets; - } - } - if (nrt) /* Send last packet */ - ripflush(ifcp, sin6, nrt, np); -} - -/* - * outbound filter logic, per-route/interface. - */ -static int -out_filter(struct riprt *rrt, struct ifc *ifcp) -{ - struct iff *iffp; - struct in6_addr ia; - int ok; - - /* - * -A: filter out less specific routes, if we have aggregated - * route configured. - */ - TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { - if (iffp->iff_type != 'A') - continue; - if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) - continue; - ia = rrt->rrt_info.rip6_dest; - applyplen(&ia, iffp->iff_plen); - if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) - return 0; - } - - /* - * if it is an aggregated route, advertise it only to the - * interfaces specified on -A. - */ - if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { - ok = 0; - TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { - if (iffp->iff_type != 'A') - continue; - if (rrt->rrt_info.rip6_plen == iffp->iff_plen && - IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, - &iffp->iff_addr)) { - ok = 1; - break; - } - } - if (!ok) - return 0; - } - - /* - * -O: advertise only if prefix matches the configured prefix. - */ - if (iff_find(ifcp, IFIL_TYPE_O) != NULL) { - ok = 0; - TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { - if (iffp->iff_type != 'O') - continue; - if (rrt->rrt_info.rip6_plen < iffp->iff_plen) - continue; - ia = rrt->rrt_info.rip6_dest; - applyplen(&ia, iffp->iff_plen); - if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { - ok = 1; - break; - } - } - if (!ok) - return 0; - } - - /* the prefix should be advertised */ - return 1; -} - -/* - * Determine if the route is to be advertised on the specified interface. - * It checks options specified in the arguments and the split horizon rule. - */ -static int -tobeadv(struct riprt *rrt, struct ifc *ifcp) -{ - - /* Special care for static routes */ - if (rrt->rrt_flags & RTF_STATIC) { - /* XXX don't advertise reject/blackhole routes */ - if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) - return 0; - - if (Sflag) /* Yes, advertise it anyway */ - return 1; - if (sflag && rrt->rrt_index != ifcp->ifc_index) - return 1; - return 0; - } - /* Regular split horizon */ - if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) - return 0; - return 1; -} - -/* - * Send a rip packet actually. - */ -static int -sendpacket(struct sockaddr_in6 *sin6, int len) -{ - struct msghdr m; - struct cmsghdr *cm; - struct iovec iov[2]; - struct in6_pktinfo *pi; - u_char cmsgbuf[256]; - int idx; - struct sockaddr_in6 sincopy; - - /* do not overwrite the given sin */ - sincopy = *sin6; - sin6 = &sincopy; - - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || - IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) - idx = sin6->sin6_scope_id; - else - idx = 0; - - m.msg_name = (caddr_t)sin6; - m.msg_namelen = sizeof(*sin6); - iov[0].iov_base = (caddr_t)ripbuf; - iov[0].iov_len = len; - m.msg_iov = iov; - m.msg_iovlen = 1; - m.msg_flags = 0; - if (!idx) { - m.msg_control = NULL; - m.msg_controllen = 0; - } else { - memset(cmsgbuf, 0, sizeof(cmsgbuf)); - cm = (struct cmsghdr *)(void *)cmsgbuf; - m.msg_control = (caddr_t)cm; - m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - - cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - cm->cmsg_level = IPPROTO_IPV6; - cm->cmsg_type = IPV6_PKTINFO; - pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm); - memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ - pi->ipi6_ifindex = idx; - } - - if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { - trace(1, "sendmsg: %s\n", strerror(errno)); - return errno; - } - - return 0; -} - -/* - * Receive and process RIP packets. Update the routes/kernel forwarding - * table if necessary. - */ -static void -riprecv(void) -{ - struct ifc *ifcp, *ic; - struct sockaddr_in6 fsock; - struct in6_addr nh; /* next hop */ - struct rip6 *rp; - struct netinfo6 *np, *nq; - struct riprt *rrt; - ssize_t len, nn; - unsigned int need_trigger, idx; - char buf[4 * RIP6_MAXMTU]; - time_t t; - struct msghdr m; - struct cmsghdr *cm; - struct iovec iov[2]; - u_char cmsgbuf[256]; - struct in6_pktinfo *pi = NULL; - int *hlimp = NULL; - struct iff *iffp; - struct in6_addr ia; - int ok; - time_t t_half_lifetime; - - need_trigger = 0; - - m.msg_name = (caddr_t)&fsock; - m.msg_namelen = sizeof(fsock); - iov[0].iov_base = (caddr_t)buf; - iov[0].iov_len = sizeof(buf); - m.msg_iov = iov; - m.msg_iovlen = 1; - cm = (struct cmsghdr *)(void *)cmsgbuf; - m.msg_control = (caddr_t)cm; - m.msg_controllen = sizeof(cmsgbuf); - m.msg_flags = 0; - if ((len = recvmsg(ripsock, &m, 0)) < 0) { - fatal("recvmsg"); - /*NOTREACHED*/ - } - idx = 0; - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); - cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { - if (cm->cmsg_level != IPPROTO_IPV6) - continue; - switch (cm->cmsg_type) { - case IPV6_PKTINFO: - if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) { - trace(1, - "invalid cmsg length for IPV6_PKTINFO\n"); - return; - } - pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm); - idx = pi->ipi6_ifindex; - break; - case IPV6_HOPLIMIT: - if (cm->cmsg_len != CMSG_LEN(sizeof(int))) { - trace(1, - "invalid cmsg length for IPV6_HOPLIMIT\n"); - return; - } - hlimp = (int *)(void *)CMSG_DATA(cm); - break; - } - } - - if ((size_t)len < sizeof(struct rip6)) { - trace(1, "Packet too short\n"); - return; - } - - if (pi == NULL || hlimp == NULL) { - /* - * This can happen when the kernel failed to allocate memory - * for the ancillary data. Although we might be able to handle - * some cases without this info, those are minor and not so - * important, so it's better to discard the packet for safer - * operation. - */ - trace(1, "IPv6 packet information cannot be retrieved\n"); - return; - } - - nh = fsock.sin6_addr; - nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / - sizeof(struct netinfo6); - rp = (struct rip6 *)(void *)buf; - np = rp->rip6_nets; - - if (rp->rip6_vers != RIP6_VERSION) { - trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); - return; - } - if (rp->rip6_cmd == RIP6_REQUEST) { - if (idx && idx < nindex2ifc) { - ifcp = index2ifc[idx]; - riprequest(ifcp, np, nn, &fsock); - } else { - riprequest(NULL, np, nn, &fsock); - } - return; - } - - if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { - trace(1, "Response from non-ll addr: %s\n", - inet6_n2p(&fsock.sin6_addr)); - return; /* Ignore packets from non-link-local addr */ - } - if (ntohs(fsock.sin6_port) != RIP6_PORT) { - trace(1, "Response from non-rip port from %s\n", - inet6_n2p(&fsock.sin6_addr)); - return; - } - if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) { - trace(1, - "Response packet with a smaller hop limit (%d) from %s\n", - *hlimp, inet6_n2p(&fsock.sin6_addr)); - return; - } - /* - * Further validation: since this program does not send off-link - * requests, an incoming response must always come from an on-link - * node. Although this is normally ensured by the source address - * check above, it may not 100% be safe because there are router - * implementations that (invalidly) allow a packet with a link-local - * source address to be forwarded to a different link. - * So we also check whether the destination address is a link-local - * address or the hop limit is 255. Note that RFC2080 does not require - * the specific hop limit for a unicast response, so we cannot assume - * the limitation. - */ - if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) { - trace(1, - "Response packet possibly from an off-link node: " - "from %s to %s hlim=%d\n", - inet6_n2p(&fsock.sin6_addr), - inet6_n2p(&pi->ipi6_addr), *hlimp); - return; - } - - idx = fsock.sin6_scope_id; - ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; - if (!ifcp) { - trace(1, "Packets to unknown interface index %d\n", idx); - return; /* Ignore it */ - } - if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) - return; /* The packet is from me; ignore */ - if (rp->rip6_cmd != RIP6_RESPONSE) { - trace(1, "Invalid command %d\n", rp->rip6_cmd); - return; - } - - /* -N: no use */ - if (iff_find(ifcp, IFIL_TYPE_N) != NULL) - return; - - tracet(1, "Recv(%s): from %s.%d info(%zd)\n", - ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); - - t = time(NULL); - t_half_lifetime = t - (RIP_LIFETIME/2); - for (; nn; nn--, np++) { - if (np->rip6_metric == NEXTHOP_METRIC) { - /* modify neighbor address */ - if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { - nh = np->rip6_dest; - trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); - } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { - nh = fsock.sin6_addr; - trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); - } else { - nh = fsock.sin6_addr; - trace(1, "\tInvalid Nexthop: %s\n", - inet6_n2p(&np->rip6_dest)); - } - continue; - } - if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { - trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - continue; - } - if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { - trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - continue; - } - if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { - trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - continue; - } - /* may need to pass sitelocal prefix in some case, however*/ - if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { - trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - continue; - } - trace(2, "\tnetinfo6: %s/%d [%d]", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, np->rip6_metric); - if (np->rip6_tag) - trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); - if (dflag >= 2) { - ia = np->rip6_dest; - applyplen(&ia, np->rip6_plen); - if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) - trace(2, " [junk outside prefix]"); - } - - /* - * -L: listen only if the prefix matches the configuration - */ - ok = 1; /* if there's no L filter, it is ok */ - TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { - if (iffp->iff_type != IFIL_TYPE_L) - continue; - ok = 0; - if (np->rip6_plen < iffp->iff_plen) - continue; - /* special rule: ::/0 means default, not "in /0" */ - if (iffp->iff_plen == 0 && np->rip6_plen > 0) - continue; - ia = np->rip6_dest; - applyplen(&ia, iffp->iff_plen); - if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { - ok = 1; - break; - } - } - if (!ok) { - trace(2, " (filtered)\n"); - continue; - } - - trace(2, "\n"); - np->rip6_metric++; - np->rip6_metric += ifcp->ifc_metric; - if (np->rip6_metric > HOPCNT_INFINITY6) - np->rip6_metric = HOPCNT_INFINITY6; - - applyplen(&np->rip6_dest, np->rip6_plen); - if ((rrt = rtsearch(np)) != NULL) { - if (rrt->rrt_t == 0) - continue; /* Intf route has priority */ - nq = &rrt->rrt_info; - if (nq->rip6_metric > np->rip6_metric) { - if (rrt->rrt_index == ifcp->ifc_index && - IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { - /* Small metric from the same gateway */ - nq->rip6_metric = np->rip6_metric; - } else { - /* Better route found */ - rrt->rrt_index = ifcp->ifc_index; - /* Update routing table */ - delroute(nq, &rrt->rrt_gw); - rrt->rrt_gw = nh; - *nq = *np; - addroute(rrt, &nh, ifcp); - } - rrt->rrt_rflags |= RRTF_CHANGED; - rrt->rrt_t = t; - need_trigger = 1; - } else if (nq->rip6_metric < np->rip6_metric && - rrt->rrt_index == ifcp->ifc_index && - IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { - /* Got worse route from same gw */ - nq->rip6_metric = np->rip6_metric; - rrt->rrt_t = t; - rrt->rrt_rflags |= RRTF_CHANGED; - need_trigger = 1; - } else if (nq->rip6_metric == np->rip6_metric && - np->rip6_metric < HOPCNT_INFINITY6) { - if (rrt->rrt_index == ifcp->ifc_index && - IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { - /* same metric, same route from same gw */ - rrt->rrt_t = t; - } else if (rrt->rrt_t < t_half_lifetime) { - /* Better route found */ - rrt->rrt_index = ifcp->ifc_index; - /* Update routing table */ - delroute(nq, &rrt->rrt_gw); - rrt->rrt_gw = nh; - *nq = *np; - addroute(rrt, &nh, ifcp); - rrt->rrt_rflags |= RRTF_CHANGED; - rrt->rrt_t = t; - } - } - /* - * if nq->rip6_metric == HOPCNT_INFINITY6 then - * do not update age value. Do nothing. - */ - } else if (np->rip6_metric < HOPCNT_INFINITY6) { - /* Got a new valid route */ - if ((rrt = MALLOC(struct riprt)) == NULL) { - fatal("malloc: struct riprt"); - /*NOTREACHED*/ - } - memset(rrt, 0, sizeof(*rrt)); - nq = &rrt->rrt_info; - - rrt->rrt_same = NULL; - rrt->rrt_index = ifcp->ifc_index; - rrt->rrt_flags = RTF_UP|RTF_GATEWAY; - rrt->rrt_gw = nh; - *nq = *np; - applyplen(&nq->rip6_dest, nq->rip6_plen); - if (nq->rip6_plen == sizeof(struct in6_addr) * 8) - rrt->rrt_flags |= RTF_HOST; - - /* Update routing table */ - addroute(rrt, &nh, ifcp); - rrt->rrt_rflags |= RRTF_CHANGED; - need_trigger = 1; - rrt->rrt_t = t; - - /* Put the route to the list */ - TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); - } - } - /* XXX need to care the interval between triggered updates */ - if (need_trigger) { - if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { - TAILQ_FOREACH(ic, &ifc_head, ifc_next) { - if (ifcp->ifc_index == ic->ifc_index) - continue; - if (ic->ifc_flags & IFF_UP) - ripsend(ic, &ic->ifc_ripsin, - RRTF_CHANGED); - } - } - /* Reset the flag */ - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - rrt->rrt_rflags &= ~RRTF_CHANGED; - } - } -} - -/* - * Send all routes request packet to the specified interface. - */ -static void -sendrequest(struct ifc *ifcp) -{ - struct netinfo6 *np; - int error; - - if (ifcp->ifc_flags & IFF_LOOPBACK) - return; - ripbuf->rip6_cmd = RIP6_REQUEST; - np = ripbuf->rip6_nets; - memset(np, 0, sizeof(struct netinfo6)); - np->rip6_metric = HOPCNT_INFINITY6; - tracet(1, "Send rtdump Request to %s (%s)\n", - ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); - error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); - if (error == EAFNOSUPPORT) { - /* Protocol not supported */ - tracet(1, "Could not send rtdump Request to %s (%s): " - "set IFF_UP to 0\n", - ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); - ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ - } - ripbuf->rip6_cmd = RIP6_RESPONSE; -} - -/* - * Process a RIP6_REQUEST packet. - */ -static void -riprequest(struct ifc *ifcp, - struct netinfo6 *np, - int nn, - struct sockaddr_in6 *sin6) -{ - int i; - struct riprt *rrt; - - if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && - np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { - /* Specific response, don't split-horizon */ - trace(1, "\tRIP Request\n"); - for (i = 0; i < nn; i++, np++) { - rrt = rtsearch(np); - if (rrt) - np->rip6_metric = rrt->rrt_info.rip6_metric; - else - np->rip6_metric = HOPCNT_INFINITY6; - } - (void)sendpacket(sin6, RIPSIZE(nn)); - return; - } - /* Whole routing table dump */ - trace(1, "\tRIP Request -- whole routing table\n"); - ripsend(ifcp, sin6, RRTF_SENDANYWAY); -} - -/* - * Get information of each interface. - */ -static void -ifconfig(void) -{ - struct ifaddrs *ifap, *ifa; - struct ifc *ifcp; - struct ipv6_mreq mreq; - int s; - - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - fatal("socket"); - /*NOTREACHED*/ - } - - if (getifaddrs(&ifap) != 0) { - fatal("getifaddrs"); - /*NOTREACHED*/ - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - ifcp = ifc_find(ifa->ifa_name); - /* we are interested in multicast-capable interfaces */ - if ((ifa->ifa_flags & IFF_MULTICAST) == 0) - continue; - if (!ifcp) { - /* new interface */ - if ((ifcp = MALLOC(struct ifc)) == NULL) { - fatal("malloc: struct ifc"); - /*NOTREACHED*/ - } - memset(ifcp, 0, sizeof(*ifcp)); - - ifcp->ifc_index = -1; - strlcpy(ifcp->ifc_name, ifa->ifa_name, - sizeof(ifcp->ifc_name)); - TAILQ_INIT(&ifcp->ifc_ifac_head); - TAILQ_INIT(&ifcp->ifc_iff_head); - ifcp->ifc_flags = ifa->ifa_flags; - TAILQ_INSERT_HEAD(&ifc_head, ifcp, ifc_next); - trace(1, "newif %s <%s>\n", ifcp->ifc_name, - ifflags(ifcp->ifc_flags)); - if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) - loopifcp = ifcp; - } else { - /* update flag, this may be up again */ - if (ifcp->ifc_flags != ifa->ifa_flags) { - trace(1, "%s: <%s> -> ", ifcp->ifc_name, - ifflags(ifcp->ifc_flags)); - trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); - ifcp->ifc_cflags |= IFC_CHANGED; - } - ifcp->ifc_flags = ifa->ifa_flags; - } - if (ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s) < 0) { - /* maybe temporary failure */ - continue; - } - if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP - && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { - mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; - mreq.ipv6mr_interface = ifcp->ifc_index; - if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq, sizeof(mreq)) < 0) { - fatal("IPV6_JOIN_GROUP"); - /*NOTREACHED*/ - } - trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); - ifcp->ifc_joined++; - } - } - close(s); - freeifaddrs(ifap); -} - -static int -ifconfig1(const char *name, - const struct sockaddr *sa, - struct ifc *ifcp, - int s) -{ - struct in6_ifreq ifr; - const struct sockaddr_in6 *sin6; - struct ifac *ifac; - int plen; - char buf[BUFSIZ]; - - sin6 = (const struct sockaddr_in6 *)(const void *)sa; - if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) - return (-1); - ifr.ifr_addr = *sin6; - strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { - syslog(LOG_INFO, "ioctl: SIOCGIFNETMASK_IN6"); - return (-1); - } - plen = sin6mask2len(&ifr.ifr_addr); - if ((ifac = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { - /* same interface found */ - /* need check if something changed */ - /* XXX not yet implemented */ - return (-1); - } - /* - * New address is found - */ - if ((ifac = MALLOC(struct ifac)) == NULL) { - fatal("malloc: struct ifac"); - /*NOTREACHED*/ - } - memset(ifac, 0, sizeof(*ifac)); - - ifac->ifac_ifc = ifcp; - ifac->ifac_addr = sin6->sin6_addr; - ifac->ifac_plen = plen; - ifac->ifac_scope_id = sin6->sin6_scope_id; - if (ifcp->ifc_flags & IFF_POINTOPOINT) { - ifr.ifr_addr = *sin6; - if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { - fatal("ioctl: SIOCGIFDSTADDR_IN6"); - /*NOTREACHED*/ - } - ifac->ifac_raddr = ifr.ifr_dstaddr.sin6_addr; - inet_ntop(AF_INET6, (void *)&ifac->ifac_raddr, buf, - sizeof(buf)); - trace(1, "found address %s/%d -- %s\n", - inet6_n2p(&ifac->ifac_addr), ifac->ifac_plen, buf); - } else { - trace(1, "found address %s/%d\n", - inet6_n2p(&ifac->ifac_addr), ifac->ifac_plen); - } - if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifac->ifac_addr)) { - ifcp->ifc_mylladdr = ifac->ifac_addr; - ifcp->ifc_index = ifac->ifac_scope_id; - memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); - ifcp->ifc_ripsin.sin6_scope_id = ifcp->ifc_index; - setindex2ifc(ifcp->ifc_index, ifcp); - ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); - if (ifcp->ifc_mtu > RIP6_MAXMTU) - ifcp->ifc_mtu = RIP6_MAXMTU; - if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { - fatal("ioctl: SIOCGIFMETRIC"); - /*NOTREACHED*/ - } - ifcp->ifc_metric = ifr.ifr_metric; - trace(1, "\tindex: %d, mtu: %d, metric: %d\n", - ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); - } else - ifcp->ifc_cflags |= IFC_CHANGED; - - TAILQ_INSERT_HEAD(&ifcp->ifc_ifac_head, ifac, ifac_next); - - return 0; -} - -static void -ifremove(int ifindex) -{ - struct ifc *ifcp; - struct riprt *rrt; - - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (ifcp->ifc_index == ifindex) - break; - } - if (ifcp == NULL) - return; - - tracet(1, "ifremove: %s is departed.\n", ifcp->ifc_name); - TAILQ_REMOVE(&ifc_head, ifcp, ifc_next); - - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (rrt->rrt_index == ifcp->ifc_index && - rrt->rrt_rflags & RRTF_AGGREGATE) - delroute(&rrt->rrt_info, &rrt->rrt_gw); - } - free(ifcp); -} - -/* - * Receive and process routing messages. - * Update interface information as necessary. - */ -static void -rtrecv(void) -{ - char buf[BUFSIZ]; - char *p, *q = NULL; - struct rt_msghdr *rtm; - struct ifa_msghdr *ifam; - struct if_msghdr *ifm; - struct if_announcemsghdr *ifan; - int len; - struct ifc *ifcp, *ic; - int iface = 0, rtable = 0; - struct sockaddr_in6 *rta[RTAX_MAX]; - struct sockaddr_in6 mask; - int i, addrs = 0; - struct riprt *rrt; - - if ((len = read(rtsock, buf, sizeof(buf))) < 0) { - perror("read from rtsock"); - exit(1); - } - if (len == 0) - return; -#if 0 - if (len < sizeof(*rtm)) { - trace(1, "short read from rtsock: %d (should be > %lu)\n", - len, (u_long)sizeof(*rtm)); - return; - } -#endif - if (dflag >= 2) { - fprintf(stderr, "rtmsg:\n"); - for (i = 0; i < len; i++) { - fprintf(stderr, "%02x ", buf[i] & 0xff); - if (i % 16 == 15) fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); - } - - for (p = buf; p - buf < len; p += - ((struct rt_msghdr *)(void *)p)->rtm_msglen) { - if (((struct rt_msghdr *)(void *)p)->rtm_version != RTM_VERSION) - continue; - - /* safety against bogus message */ - if (((struct rt_msghdr *)(void *)p)->rtm_msglen <= 0) { - trace(1, "bogus rtmsg: length=%d\n", - ((struct rt_msghdr *)(void *)p)->rtm_msglen); - break; - } - rtm = NULL; - ifam = NULL; - ifm = NULL; - switch (((struct rt_msghdr *)(void *)p)->rtm_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - ifam = (struct ifa_msghdr *)(void *)p; - addrs = ifam->ifam_addrs; - q = (char *)(ifam + 1); - break; - case RTM_IFINFO: - ifm = (struct if_msghdr *)(void *)p; - addrs = ifm->ifm_addrs; - q = (char *)(ifm + 1); - break; - case RTM_IFANNOUNCE: - ifan = (struct if_announcemsghdr *)(void *)p; - switch (ifan->ifan_what) { - case IFAN_ARRIVAL: - iface++; - break; - case IFAN_DEPARTURE: - ifremove(ifan->ifan_index); - iface++; - break; - } - break; - default: - rtm = (struct rt_msghdr *)(void *)p; - if (rtm->rtm_version != RTM_VERSION) { - trace(1, "unexpected rtmsg version %d " - "(should be %d)\n", - rtm->rtm_version, RTM_VERSION); - continue; - } - /* - * Only messages that use the struct rt_msghdr - * format are allowed beyond this point. - */ - if (rtm->rtm_type > RTM_RESOLVE) { - trace(1, "rtmsg type %d ignored\n", - rtm->rtm_type); - continue; - } - addrs = rtm->rtm_addrs; - q = (char *)(rtm + 1); - if (rtm->rtm_pid == pid) { -#if 0 - trace(1, "rtmsg looped back to me, ignored\n"); -#endif - continue; - } - break; - } - memset(&rta, 0, sizeof(rta)); - for (i = 0; i < RTAX_MAX; i++) { - if (addrs & (1 << i)) { - rta[i] = (struct sockaddr_in6 *)(void *)q; - q += ROUNDUP(rta[i]->sin6_len); - } - } - - trace(1, "rtsock: %s (addrs=%x)\n", - rttypes((struct rt_msghdr *)(void *)p), addrs); - if (dflag >= 2) { - for (i = 0; - i < ((struct rt_msghdr *)(void *)p)->rtm_msglen; - i++) { - fprintf(stderr, "%02x ", p[i] & 0xff); - if (i % 16 == 15) fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); - } - - /* - * Easy ones first. - * - * We may be able to optimize by using ifm->ifm_index or - * ifam->ifam_index. For simplicity we don't do that here. - */ - switch (((struct rt_msghdr *)(void *)p)->rtm_type) { - case RTM_NEWADDR: - case RTM_IFINFO: - iface++; - continue; - case RTM_ADD: - rtable++; - continue; - case RTM_LOSING: - case RTM_MISS: - case RTM_GET: - case RTM_LOCK: - /* nothing to be done here */ - trace(1, "\tnothing to be done, ignored\n"); - continue; - } - -#if 0 - if (rta[RTAX_DST] == NULL) { - trace(1, "\tno destination, ignored\n"); - continue; - } - if (rta[RTAX_DST]->sin6_family != AF_INET6) { - trace(1, "\taf mismatch, ignored\n"); - continue; - } - if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { - trace(1, "\tlinklocal destination, ignored\n"); - continue; - } - if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { - trace(1, "\tloopback destination, ignored\n"); - continue; /* Loopback */ - } - if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { - trace(1, "\tmulticast destination, ignored\n"); - continue; - } -#endif - - /* hard ones */ - switch (((struct rt_msghdr *)(void *)p)->rtm_type) { - case RTM_NEWADDR: - case RTM_IFINFO: - case RTM_ADD: - case RTM_LOSING: - case RTM_MISS: - case RTM_GET: - case RTM_LOCK: - /* should already be handled */ - fatal("rtrecv: never reach here"); - /*NOTREACHED*/ - case RTM_DELETE: - if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { - trace(1, "\tsome of dst/gw/netamsk are " - "unavailable, ignored\n"); - break; - } - if ((rtm->rtm_flags & RTF_HOST) != 0) { - mask.sin6_len = sizeof(mask); - memset(&mask.sin6_addr, 0xff, - sizeof(mask.sin6_addr)); - rta[RTAX_NETMASK] = &mask; - } else if (!rta[RTAX_NETMASK]) { - trace(1, "\tsome of dst/gw/netamsk are " - "unavailable, ignored\n"); - break; - } - if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], - rta[RTAX_NETMASK]) == 0) { - rtable++; /*just to be sure*/ - } - break; - case RTM_CHANGE: - case RTM_REDIRECT: - trace(1, "\tnot supported yet, ignored\n"); - break; - case RTM_DELADDR: - if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { - trace(1, "\tno netmask or ifa given, ignored\n"); - break; - } - if (ifam->ifam_index < nindex2ifc) - ifcp = index2ifc[ifam->ifam_index]; - else - ifcp = NULL; - if (!ifcp) { - trace(1, "\tinvalid ifam_index %d, ignored\n", - ifam->ifam_index); - break; - } - if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) - iface++; - break; - } - - } - - if (iface) { - trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); - ifconfig(); - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (ifcp->ifc_cflags & IFC_CHANGED) { - if (ifrt(ifcp, 1)) { - TAILQ_FOREACH(ic, &ifc_head, ifc_next) { - if (ifcp->ifc_index == ic->ifc_index) - continue; - if (ic->ifc_flags & IFF_UP) - ripsend(ic, &ic->ifc_ripsin, - RRTF_CHANGED); - } - /* Reset the flag */ - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - rrt->rrt_rflags &= ~RRTF_CHANGED; - } - } - ifcp->ifc_cflags &= ~IFC_CHANGED; - } - } - } - if (rtable) { - trace(1, "rtsock: read routing table again\n"); - krtread(1); - } -} - -/* - * remove specified route from the internal routing table. - */ -static int -rt_del(const struct sockaddr_in6 *sdst, - const struct sockaddr_in6 *sgw, - const struct sockaddr_in6 *smask) -{ - const struct in6_addr *dst = NULL; - const struct in6_addr *gw = NULL; - int prefix; - struct netinfo6 ni6; - struct riprt *rrt = NULL; - time_t t_lifetime; - - if (sdst->sin6_family != AF_INET6) { - trace(1, "\tother AF, ignored\n"); - return -1; - } - if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) - || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) - || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { - trace(1, "\taddress %s not interesting, ignored\n", - inet6_n2p(&sdst->sin6_addr)); - return -1; - } - dst = &sdst->sin6_addr; - if (sgw->sin6_family == AF_INET6) { - /* easy case */ - gw = &sgw->sin6_addr; - prefix = sin6mask2len(smask); - } else if (sgw->sin6_family == AF_LINK) { - /* - * Interface route... a hard case. We need to get the prefix - * length from the kernel, but we now are parsing rtmsg. - * We'll purge matching routes from my list, then get the - * fresh list. - */ - struct riprt *longest; - trace(1, "\t%s is an interface route, guessing prefixlen\n", - inet6_n2p(dst)); - longest = NULL; - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, - &sdst->sin6_addr) - && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { - if (!longest - || longest->rrt_info.rip6_plen < - rrt->rrt_info.rip6_plen) { - longest = rrt; - } - } - } - rrt = longest; - if (!rrt) { - trace(1, "\tno matching interface route found\n"); - return -1; - } - gw = &in6addr_loopback; - prefix = rrt->rrt_info.rip6_plen; - } else { - trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); - return -1; - } - - trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); - trace(1, "gw %s\n", inet6_n2p(gw)); - t_lifetime = time(NULL) - RIP_LIFETIME; - /* age route for interface address */ - memset(&ni6, 0, sizeof(ni6)); - ni6.rip6_dest = *dst; - ni6.rip6_plen = prefix; - applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ - trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), - ni6.rip6_plen); - if (!rrt && (rrt = rtsearch(&ni6)) == NULL) { - trace(1, "\tno route found\n"); - return -1; - } -#if 0 - if ((rrt->rrt_flags & RTF_STATIC) == 0) { - trace(1, "\tyou can delete static routes only\n"); - } else -#endif - if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { - trace(1, "\tgw mismatch: %s <-> ", - inet6_n2p(&rrt->rrt_gw)); - trace(1, "%s\n", inet6_n2p(gw)); - } else { - trace(1, "\troute found, age it\n"); - if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { - rrt->rrt_t = t_lifetime; - rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; - } - } - return 0; -} - -/* - * remove specified address from internal interface/routing table. - */ -static int -rt_deladdr(struct ifc *ifcp, - const struct sockaddr_in6 *sifa, - const struct sockaddr_in6 *smask) -{ - const struct in6_addr *addr = NULL; - int prefix; - struct ifac *ifac = NULL; - struct netinfo6 ni6; - struct riprt *rrt = NULL; - time_t t_lifetime; - int updated = 0; - - if (sifa->sin6_family != AF_INET6) { - trace(1, "\tother AF, ignored\n"); - return -1; - } - addr = &sifa->sin6_addr; - prefix = sin6mask2len(smask); - - trace(1, "\tdeleting %s/%d from %s\n", - inet6_n2p(addr), prefix, ifcp->ifc_name); - ifac = ifa_match(ifcp, addr, prefix); - if (!ifac) { - trace(1, "\tno matching ifa found for %s/%d on %s\n", - inet6_n2p(addr), prefix, ifcp->ifc_name); - return -1; - } - if (ifac->ifac_ifc != ifcp) { - trace(1, "\taddress table corrupt: back pointer does not match " - "(%s != %s)\n", - ifcp->ifc_name, ifac->ifac_ifc->ifc_name); - return -1; - } - TAILQ_REMOVE(&ifcp->ifc_ifac_head, ifac, ifac_next); - t_lifetime = time(NULL) - RIP_LIFETIME; - /* age route for interface address */ - memset(&ni6, 0, sizeof(ni6)); - ni6.rip6_dest = ifac->ifac_addr; - ni6.rip6_plen = ifac->ifac_plen; - applyplen(&ni6.rip6_dest, ni6.rip6_plen); - trace(1, "\tfind interface route %s/%d on %d\n", - inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); - if ((rrt = rtsearch(&ni6)) != NULL) { - struct in6_addr none; - memset(&none, 0, sizeof(none)); - if (rrt->rrt_index == ifcp->ifc_index && - (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || - IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { - trace(1, "\troute found, age it\n"); - if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { - rrt->rrt_t = t_lifetime; - rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; - } - updated++; - } else { - trace(1, "\tnon-interface route found: %s/%d on %d\n", - inet6_n2p(&rrt->rrt_info.rip6_dest), - rrt->rrt_info.rip6_plen, - rrt->rrt_index); - } - } else - trace(1, "\tno interface route found\n"); - /* age route for p2p destination */ - if (ifcp->ifc_flags & IFF_POINTOPOINT) { - memset(&ni6, 0, sizeof(ni6)); - ni6.rip6_dest = ifac->ifac_raddr; - ni6.rip6_plen = 128; - applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ - trace(1, "\tfind p2p route %s/%d on %d\n", - inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, - ifcp->ifc_index); - if ((rrt = rtsearch(&ni6)) != NULL) { - if (rrt->rrt_index == ifcp->ifc_index && - IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, - &ifac->ifac_addr)) { - trace(1, "\troute found, age it\n"); - if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { - rrt->rrt_t = t_lifetime; - rrt->rrt_info.rip6_metric = - HOPCNT_INFINITY6; - updated++; - } - } else { - trace(1, "\tnon-p2p route found: %s/%d on %d\n", - inet6_n2p(&rrt->rrt_info.rip6_dest), - rrt->rrt_info.rip6_plen, - rrt->rrt_index); - } - } else - trace(1, "\tno p2p route found\n"); - } - free(ifac); - - return ((updated) ? 0 : -1); -} - -/* - * Get each interface address and put those interface routes to the route - * list. - */ -static int -ifrt(struct ifc *ifcp, int again) -{ - struct ifac *ifac; - struct riprt *rrt = NULL, *search_rrt, *loop_rrt; - struct netinfo6 *np; - time_t t_lifetime; - int need_trigger = 0; - -#if 0 - if (ifcp->ifc_flags & IFF_LOOPBACK) - return 0; /* ignore loopback */ -#endif - - if (ifcp->ifc_flags & IFF_POINTOPOINT) { - ifrt_p2p(ifcp, again); - return 0; - } - - TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { - if (IN6_IS_ADDR_LINKLOCAL(&ifac->ifac_addr)) { -#if 0 - trace(1, "route: %s on %s: " - "skip linklocal interface address\n", - inet6_n2p(&ifac->ifac_addr), ifcp->ifc_name); -#endif - continue; - } - if (IN6_IS_ADDR_UNSPECIFIED(&ifac->ifac_addr)) { -#if 0 - trace(1, "route: %s: skip unspec interface address\n", - ifcp->ifc_name); -#endif - continue; - } - if (IN6_IS_ADDR_LOOPBACK(&ifac->ifac_addr)) { -#if 0 - trace(1, "route: %s: skip loopback address\n", - ifcp->ifc_name); -#endif - continue; - } - if (ifcp->ifc_flags & IFF_UP) { - if ((rrt = MALLOC(struct riprt)) == NULL) - fatal("malloc: struct riprt"); - memset(rrt, 0, sizeof(*rrt)); - rrt->rrt_same = NULL; - rrt->rrt_index = ifcp->ifc_index; - rrt->rrt_t = 0; /* don't age */ - rrt->rrt_info.rip6_dest = ifac->ifac_addr; - rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); - rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; - rrt->rrt_info.rip6_plen = ifac->ifac_plen; - rrt->rrt_flags = RTF_HOST; - rrt->rrt_rflags |= RRTF_CHANGED; - applyplen(&rrt->rrt_info.rip6_dest, ifac->ifac_plen); - memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); - rrt->rrt_gw = ifac->ifac_addr; - np = &rrt->rrt_info; - search_rrt = rtsearch(np); - if (search_rrt != NULL) { - if (search_rrt->rrt_info.rip6_metric <= - rrt->rrt_info.rip6_metric) { - /* Already have better route */ - if (!again) { - trace(1, "route: %s/%d: " - "already registered (%s)\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - ifcp->ifc_name); - } - goto next; - } - - TAILQ_REMOVE(&riprt_head, search_rrt, rrt_next); - delroute(&search_rrt->rrt_info, - &search_rrt->rrt_gw); - free(search_rrt); - } - /* Attach the route to the list */ - trace(1, "route: %s/%d: register route (%s)\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - ifcp->ifc_name); - TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); - addroute(rrt, &rrt->rrt_gw, ifcp); - rrt = NULL; - sendrequest(ifcp); - ripsend(ifcp, &ifcp->ifc_ripsin, 0); - need_trigger = 1; - } else { - TAILQ_FOREACH(loop_rrt, &riprt_head, rrt_next) { - if (loop_rrt->rrt_index == ifcp->ifc_index) { - t_lifetime = time(NULL) - RIP_LIFETIME; - if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { - loop_rrt->rrt_t = t_lifetime; - loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; - loop_rrt->rrt_rflags |= RRTF_CHANGED; - need_trigger = 1; - } - } - } - } - next: - if (rrt) - free(rrt); - } - return need_trigger; -} - -/* - * there are couple of p2p interface routing models. "behavior" lets - * you pick one. it looks that gated behavior fits best with BSDs, - * since BSD kernels do not look at prefix length on p2p interfaces. - */ -static void -ifrt_p2p(struct ifc *ifcp, int again) -{ - struct ifac *ifac; - struct riprt *rrt, *orrt; - struct netinfo6 *np; - struct in6_addr addr, dest; - int advert, ignore, i; -#define P2PADVERT_NETWORK 1 -#define P2PADVERT_ADDR 2 -#define P2PADVERT_DEST 4 -#define P2PADVERT_MAX 4 - const enum { CISCO, GATED, ROUTE6D } behavior = GATED; - const char *category = ""; - const char *noadv; - - TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { - addr = ifac->ifac_addr; - dest = ifac->ifac_raddr; - applyplen(&addr, ifac->ifac_plen); - applyplen(&dest, ifac->ifac_plen); - advert = ignore = 0; - switch (behavior) { - case CISCO: - /* - * honor addr/plen, just like normal shared medium - * interface. this may cause trouble if you reuse - * addr/plen on other interfaces. - * - * advertise addr/plen. - */ - advert |= P2PADVERT_NETWORK; - break; - case GATED: - /* - * prefixlen on p2p interface is meaningless. - * advertise addr/128 and dest/128. - * - * do not install network route to route6d routing - * table (if we do, it would prevent route installation - * for other p2p interface that shares addr/plen). - * - * XXX what should we do if dest is ::? it will not - * get announced anyways (see following filter), - * but we need to think. - */ - advert |= P2PADVERT_ADDR; - advert |= P2PADVERT_DEST; - ignore |= P2PADVERT_NETWORK; - break; - case ROUTE6D: - /* - * just for testing. actually the code is redundant - * given the current p2p interface address assignment - * rule for kame kernel. - * - * intent: - * A/n -> announce A/n - * A B/n, A and B share prefix -> A/n (= B/n) - * A B/n, do not share prefix -> A/128 and B/128 - * actually, A/64 and A B/128 are the only cases - * permitted by the kernel: - * A/64 -> A/64 - * A B/128 -> A/128 and B/128 - */ - if (!IN6_IS_ADDR_UNSPECIFIED(&ifac->ifac_raddr)) { - if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) - advert |= P2PADVERT_NETWORK; - else { - advert |= P2PADVERT_ADDR; - advert |= P2PADVERT_DEST; - ignore |= P2PADVERT_NETWORK; - } - } else - advert |= P2PADVERT_NETWORK; - break; - } - - for (i = 1; i <= P2PADVERT_MAX; i *= 2) { - if ((ignore & i) != 0) - continue; - if ((rrt = MALLOC(struct riprt)) == NULL) { - fatal("malloc: struct riprt"); - /*NOTREACHED*/ - } - memset(rrt, 0, sizeof(*rrt)); - rrt->rrt_same = NULL; - rrt->rrt_index = ifcp->ifc_index; - rrt->rrt_t = 0; /* don't age */ - switch (i) { - case P2PADVERT_NETWORK: - rrt->rrt_info.rip6_dest = ifac->ifac_addr; - rrt->rrt_info.rip6_plen = ifac->ifac_plen; - applyplen(&rrt->rrt_info.rip6_dest, - ifac->ifac_plen); - category = "network"; - break; - case P2PADVERT_ADDR: - rrt->rrt_info.rip6_dest = ifac->ifac_addr; - rrt->rrt_info.rip6_plen = 128; - rrt->rrt_gw = in6addr_loopback; - category = "addr"; - break; - case P2PADVERT_DEST: - rrt->rrt_info.rip6_dest = ifac->ifac_raddr; - rrt->rrt_info.rip6_plen = 128; - rrt->rrt_gw = ifac->ifac_addr; - category = "dest"; - break; - } - if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || - IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { -#if 0 - trace(1, "route: %s: skip unspec/linklocal " - "(%s on %s)\n", category, ifcp->ifc_name); -#endif - free(rrt); - continue; - } - if ((advert & i) == 0) { - rrt->rrt_rflags |= RRTF_NOADVERTISE; - noadv = ", NO-ADV"; - } else - noadv = ""; - rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); - rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; - np = &rrt->rrt_info; - orrt = rtsearch(np); - if (!orrt) { - /* Attach the route to the list */ - trace(1, "route: %s/%d: register route " - "(%s on %s%s)\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - category, ifcp->ifc_name, noadv); - TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); - } else if (rrt->rrt_index != orrt->rrt_index || - rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { - /* replace route */ - TAILQ_INSERT_BEFORE(orrt, rrt, rrt_next); - TAILQ_REMOVE(&riprt_head, orrt, rrt_next); - free(orrt); - - trace(1, "route: %s/%d: update (%s on %s%s)\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - category, ifcp->ifc_name, noadv); - } else { - /* Already found */ - if (!again) { - trace(1, "route: %s/%d: " - "already registered (%s on %s%s)\n", - inet6_n2p(&np->rip6_dest), - np->rip6_plen, category, - ifcp->ifc_name, noadv); - } - free(rrt); - } - } - } -#undef P2PADVERT_NETWORK -#undef P2PADVERT_ADDR -#undef P2PADVERT_DEST -#undef P2PADVERT_MAX -} - -static int -getifmtu(int ifindex) -{ - int mib[6]; - char *buf; - size_t msize; - struct if_msghdr *ifm; - int mtu; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET6; - mib[4] = NET_RT_IFLIST; - mib[5] = ifindex; - if (sysctl(mib, nitems(mib), NULL, &msize, NULL, 0) < 0) { - fatal("sysctl estimate NET_RT_IFLIST"); - /*NOTREACHED*/ - } - if ((buf = malloc(msize)) == NULL) { - fatal("malloc"); - /*NOTREACHED*/ - } - if (sysctl(mib, nitems(mib), buf, &msize, NULL, 0) < 0) { - fatal("sysctl NET_RT_IFLIST"); - /*NOTREACHED*/ - } - ifm = (struct if_msghdr *)(void *)buf; - mtu = ifm->ifm_data.ifi_mtu; - if (ifindex != ifm->ifm_index) { - fatal("ifindex does not match with ifm_index"); - /*NOTREACHED*/ - } - free(buf); - return mtu; -} - -static const char * -rttypes(struct rt_msghdr *rtm) -{ -#define RTTYPE(s, f) \ -do { \ - if (rtm->rtm_type == (f)) \ - return (s); \ -} while (0) - RTTYPE("ADD", RTM_ADD); - RTTYPE("DELETE", RTM_DELETE); - RTTYPE("CHANGE", RTM_CHANGE); - RTTYPE("GET", RTM_GET); - RTTYPE("LOSING", RTM_LOSING); - RTTYPE("REDIRECT", RTM_REDIRECT); - RTTYPE("MISS", RTM_MISS); - RTTYPE("LOCK", RTM_LOCK); - RTTYPE("NEWADDR", RTM_NEWADDR); - RTTYPE("DELADDR", RTM_DELADDR); - RTTYPE("IFINFO", RTM_IFINFO); -#ifdef RTM_OIFINFO - RTTYPE("OIFINFO", RTM_OIFINFO); -#endif -#ifdef RTM_IFANNOUNCE - RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); -#endif -#ifdef RTM_NEWMADDR - RTTYPE("NEWMADDR", RTM_NEWMADDR); -#endif -#ifdef RTM_DELMADDR - RTTYPE("DELMADDR", RTM_DELMADDR); -#endif -#undef RTTYPE - return NULL; -} - -static const char * -rtflags(struct rt_msghdr *rtm) -{ - static char buf[BUFSIZ]; - - /* - * letter conflict should be okay. painful when *BSD diverges... - */ - strlcpy(buf, "", sizeof(buf)); -#define RTFLAG(s, f) \ -do { \ - if (rtm->rtm_flags & (f)) \ - strlcat(buf, (s), sizeof(buf)); \ -} while (0) - RTFLAG("U", RTF_UP); - RTFLAG("G", RTF_GATEWAY); - RTFLAG("H", RTF_HOST); - RTFLAG("R", RTF_REJECT); - RTFLAG("D", RTF_DYNAMIC); - RTFLAG("M", RTF_MODIFIED); - RTFLAG("d", RTF_DONE); -#ifdef RTF_MASK - RTFLAG("m", RTF_MASK); -#endif -#ifdef RTF_CLONED - RTFLAG("c", RTF_CLONED); -#endif - RTFLAG("X", RTF_XRESOLVE); -#ifdef RTF_LLINFO - RTFLAG("L", RTF_LLINFO); -#endif - RTFLAG("S", RTF_STATIC); - RTFLAG("B", RTF_BLACKHOLE); -#ifdef RTF_PROTO3 - RTFLAG("3", RTF_PROTO3); -#endif - RTFLAG("2", RTF_PROTO2); - RTFLAG("1", RTF_PROTO1); -#ifdef RTF_BROADCAST - RTFLAG("b", RTF_BROADCAST); -#endif -#ifdef RTF_DEFAULT - RTFLAG("d", RTF_DEFAULT); -#endif -#ifdef RTF_ISAROUTER - RTFLAG("r", RTF_ISAROUTER); -#endif -#ifdef RTF_TUNNEL - RTFLAG("T", RTF_TUNNEL); -#endif -#ifdef RTF_AUTH - RTFLAG("A", RTF_AUTH); -#endif -#ifdef RTF_CRYPT - RTFLAG("E", RTF_CRYPT); -#endif -#undef RTFLAG - return buf; -} - -static const char * -ifflags(int flags) -{ - static char buf[BUFSIZ]; - - strlcpy(buf, "", sizeof(buf)); -#define IFFLAG(s, f) \ -do { \ - if (flags & (f)) { \ - if (buf[0]) \ - strlcat(buf, ",", sizeof(buf)); \ - strlcat(buf, (s), sizeof(buf)); \ - } \ -} while (0) - IFFLAG("UP", IFF_UP); - IFFLAG("BROADCAST", IFF_BROADCAST); - IFFLAG("DEBUG", IFF_DEBUG); - IFFLAG("LOOPBACK", IFF_LOOPBACK); - IFFLAG("POINTOPOINT", IFF_POINTOPOINT); -#ifdef IFF_NOTRAILERS - IFFLAG("NOTRAILERS", IFF_NOTRAILERS); -#endif - IFFLAG("RUNNING", IFF_RUNNING); - IFFLAG("NOARP", IFF_NOARP); - IFFLAG("PROMISC", IFF_PROMISC); - IFFLAG("ALLMULTI", IFF_ALLMULTI); - IFFLAG("OACTIVE", IFF_OACTIVE); - IFFLAG("SIMPLEX", IFF_SIMPLEX); - IFFLAG("LINK0", IFF_LINK0); - IFFLAG("LINK1", IFF_LINK1); - IFFLAG("LINK2", IFF_LINK2); - IFFLAG("MULTICAST", IFF_MULTICAST); -#undef IFFLAG - return buf; -} - -static void -krtread(int again) -{ - int mib[6]; - size_t msize; - char *buf, *p, *lim; - struct rt_msghdr *rtm; - int retry; - const char *errmsg; - - retry = 0; - buf = NULL; - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET6; /* Address family */ - mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ - mib[5] = 0; /* No flags */ - do { - if (retry) - sleep(1); - retry++; - errmsg = NULL; - if (buf) { - free(buf); - buf = NULL; - } - if (sysctl(mib, nitems(mib), NULL, &msize, NULL, 0) < 0) { - errmsg = "sysctl estimate"; - continue; - } - if ((buf = malloc(msize)) == NULL) { - errmsg = "malloc"; - continue; - } - if (sysctl(mib, nitems(mib), buf, &msize, NULL, 0) < 0) { - errmsg = "sysctl NET_RT_DUMP"; - continue; - } - } while (retry < RT_DUMP_MAXRETRY && errmsg != NULL); - if (errmsg) { - fatal("%s (with %d retries, msize=%lu)", errmsg, retry, - (u_long)msize); - /*NOTREACHED*/ - } else if (1 < retry) - syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); - - lim = buf + msize; - for (p = buf; p < lim; p += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)p; - rt_entry(rtm, again); - } - free(buf); -} - -static void -rt_entry(struct rt_msghdr *rtm, int again) -{ - struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; - struct sockaddr_in6 *sin6_genmask, *sin6_ifp; - char *rtmp, *ifname = NULL; - struct riprt *rrt, *orrt; - struct netinfo6 *np; - int ifindex; - - sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; - if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & - (RTF_XRESOLVE|RTF_BLACKHOLE)) { - return; /* not interested in the link route */ - } - /* do not look at cloned routes */ -#ifdef RTF_WASCLONED - if (rtm->rtm_flags & RTF_WASCLONED) - return; -#endif -#ifdef RTF_CLONED - if (rtm->rtm_flags & RTF_CLONED) - return; -#endif - /* XXX: Ignore connected routes. */ - if (!(rtm->rtm_flags & (RTF_GATEWAY|RTF_HOST|RTF_STATIC))) - return; - /* - * do not look at dynamic routes. - * netbsd/openbsd cloned routes have UGHD. - */ - if (rtm->rtm_flags & RTF_DYNAMIC) - return; - rtmp = (char *)(rtm + 1); - /* Destination */ - if ((rtm->rtm_addrs & RTA_DST) == 0) - return; /* ignore routes without destination address */ - sin6_dst = (struct sockaddr_in6 *)(void *)rtmp; - rtmp += ROUNDUP(sin6_dst->sin6_len); - if (rtm->rtm_addrs & RTA_GATEWAY) { - sin6_gw = (struct sockaddr_in6 *)(void *)rtmp; - rtmp += ROUNDUP(sin6_gw->sin6_len); - } - if (rtm->rtm_addrs & RTA_NETMASK) { - sin6_mask = (struct sockaddr_in6 *)(void *)rtmp; - rtmp += ROUNDUP(sin6_mask->sin6_len); - } - if (rtm->rtm_addrs & RTA_GENMASK) { - sin6_genmask = (struct sockaddr_in6 *)(void *)rtmp; - rtmp += ROUNDUP(sin6_genmask->sin6_len); - } - if (rtm->rtm_addrs & RTA_IFP) { - sin6_ifp = (struct sockaddr_in6 *)(void *)rtmp; - rtmp += ROUNDUP(sin6_ifp->sin6_len); - } - - /* Destination */ - if (sin6_dst->sin6_family != AF_INET6) - return; - if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) - return; /* Link-local */ - if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) - return; /* Loopback */ - if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) - return; - - if ((rrt = MALLOC(struct riprt)) == NULL) { - fatal("malloc: struct riprt"); - /*NOTREACHED*/ - } - memset(rrt, 0, sizeof(*rrt)); - np = &rrt->rrt_info; - rrt->rrt_same = NULL; - rrt->rrt_t = time(NULL); - if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) - rrt->rrt_t = 0; /* Don't age static routes */ - if (rtm->rtm_flags & Pflag) - rrt->rrt_t = 0; /* Don't age PROTO[123] routes */ - if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) - rrt->rrt_t = 0; /* Don't age non-gateway host routes */ - np->rip6_tag = 0; - np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; - if (np->rip6_metric < 1) - np->rip6_metric = 1; - rrt->rrt_flags = rtm->rtm_flags; - np->rip6_dest = sin6_dst->sin6_addr; - - /* Mask or plen */ - if (rtm->rtm_flags & RTF_HOST) - np->rip6_plen = 128; /* Host route */ - else if (sin6_mask) - np->rip6_plen = sin6mask2len(sin6_mask); - else - np->rip6_plen = 0; - - orrt = rtsearch(np); - if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { - /* Already found */ - if (!again) { - trace(1, "route: %s/%d flags %s: already registered\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - rtflags(rtm)); - } - free(rrt); - return; - } - /* Gateway */ - if (!sin6_gw) - memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); - else { - if (sin6_gw->sin6_family == AF_INET6) - rrt->rrt_gw = sin6_gw->sin6_addr; - else if (sin6_gw->sin6_family == AF_LINK) { - /* XXX in case ppp link? */ - rrt->rrt_gw = in6addr_loopback; - } else - memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); - } - trace(1, "route: %s/%d flags %s", - inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); - trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); - - /* Interface */ - ifindex = rtm->rtm_index; - if ((unsigned int)ifindex < nindex2ifc && index2ifc[ifindex]) - ifname = index2ifc[ifindex]->ifc_name; - else { - trace(1, " not configured\n"); - free(rrt); - return; - } - trace(1, " if %s sock %d", ifname, ifindex); - rrt->rrt_index = ifindex; - - trace(1, "\n"); - - /* Check gateway */ - if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && - !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) && - (rrt->rrt_flags & RTF_LOCAL) == 0) { - trace(0, "***** Gateway %s is not a link-local address.\n", - inet6_n2p(&rrt->rrt_gw)); - trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", - inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); - rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; - } - - /* Put it to the route list */ - if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { - /* replace route list */ - TAILQ_INSERT_BEFORE(orrt, rrt, rrt_next); - TAILQ_REMOVE(&riprt_head, orrt, rrt_next); - - trace(1, "route: %s/%d flags %s: replace new route\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - rtflags(rtm)); - free(orrt); - } else - TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); -} - -static int -addroute(struct riprt *rrt, - const struct in6_addr *gw, - struct ifc *ifcp) -{ - struct netinfo6 *np; - u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; - struct rt_msghdr *rtm; - struct sockaddr_in6 *sin6; - int len; - - np = &rrt->rrt_info; - inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); - inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); - tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, - np->rip6_metric - 1, buf2); - if (rtlog) - fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), - inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, - np->rip6_metric - 1, buf2); - if (nflag) - return 0; - - memset(buf, 0, sizeof(buf)); - rtm = (struct rt_msghdr *)(void *)buf; - rtm->rtm_type = RTM_ADD; - rtm->rtm_version = RTM_VERSION; - rtm->rtm_seq = ++seq; - rtm->rtm_pid = pid; - rtm->rtm_flags = rrt->rrt_flags; - rtm->rtm_flags |= Qflag; - rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; - rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; - rtm->rtm_inits = RTV_HOPCOUNT; - sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; - /* Destination */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = np->rip6_dest; - sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); - /* Gateway */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = *gw; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - sin6->sin6_scope_id = ifcp->ifc_index; - sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); - /* Netmask */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = *(plen2mask(np->rip6_plen)); - sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); - - len = (char *)sin6 - (char *)buf; - rtm->rtm_msglen = len; - if (write(rtsock, buf, len) > 0) - return 0; - - if (errno == EEXIST) { - trace(0, "ADD: Route already exists %s/%d gw %s\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); - if (rtlog) - fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); - } else { - trace(0, "Can not write to rtsock (addroute): %s\n", - strerror(errno)); - if (rtlog) - fprintf(rtlog, "\tCan not write to rtsock: %s\n", - strerror(errno)); - } - return -1; -} - -static int -delroute(struct netinfo6 *np, struct in6_addr *gw) -{ - u_char buf[BUFSIZ], buf2[BUFSIZ]; - struct rt_msghdr *rtm; - struct sockaddr_in6 *sin6; - int len; - - inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); - tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), - np->rip6_plen, buf2); - if (rtlog) - fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", - hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); - if (nflag) - return 0; - - memset(buf, 0, sizeof(buf)); - rtm = (struct rt_msghdr *)(void *)buf; - rtm->rtm_type = RTM_DELETE; - rtm->rtm_version = RTM_VERSION; - rtm->rtm_seq = ++seq; - rtm->rtm_pid = pid; - rtm->rtm_flags = RTF_UP | RTF_GATEWAY; - rtm->rtm_flags |= Qflag; - if (np->rip6_plen == sizeof(struct in6_addr) * 8) - rtm->rtm_flags |= RTF_HOST; - rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; - sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; - /* Destination */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = np->rip6_dest; - sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); - /* Gateway */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = *gw; - sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); - /* Netmask */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = *(plen2mask(np->rip6_plen)); - sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); - - len = (char *)sin6 - (char *)buf; - rtm->rtm_msglen = len; - if (write(rtsock, buf, len) >= 0) - return 0; - - if (errno == ESRCH) { - trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); - if (rtlog) - fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); - } else { - trace(0, "Can not write to rtsock (delroute): %s\n", - strerror(errno)); - if (rtlog) - fprintf(rtlog, "\tCan not write to rtsock: %s\n", - strerror(errno)); - } - return -1; -} - -#if 0 -static struct in6_addr * -getroute(struct netinfo6 *np, struct in6_addr *gw) -{ - u_char buf[BUFSIZ]; - int myseq; - int len; - struct rt_msghdr *rtm; - struct sockaddr_in6 *sin6; - - rtm = (struct rt_msghdr *)(void *)buf; - len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); - memset(rtm, 0, len); - rtm->rtm_type = RTM_GET; - rtm->rtm_version = RTM_VERSION; - myseq = ++seq; - rtm->rtm_seq = myseq; - rtm->rtm_addrs = RTA_DST; - rtm->rtm_msglen = len; - sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = np->rip6_dest; - if (write(rtsock, buf, len) < 0) { - if (errno == ESRCH) /* No such route found */ - return NULL; - perror("write to rtsock"); - exit(1); - } - do { - if ((len = read(rtsock, buf, sizeof(buf))) < 0) { - perror("read from rtsock"); - exit(1); - } - rtm = (struct rt_msghdr *)(void *)buf; - } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != myseq || - rtm->rtm_pid != pid); - sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; - if (rtm->rtm_addrs & RTA_DST) { - sin6 = (struct sockaddr_in6 *)(void *) - ((char *)sin6 + ROUNDUP(sin6->sin6_len)); - } - if (rtm->rtm_addrs & RTA_GATEWAY) { - *gw = sin6->sin6_addr; - return gw; - } - return NULL; -} -#endif - -static const char * -inet6_n2p(const struct in6_addr *p) -{ - static char buf[BUFSIZ]; - - return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); -} - -static void -ifrtdump(int sig) -{ - - ifdump(sig); - rtdump(sig); -} - -static void -ifdump(int sig) -{ - struct ifc *ifcp; - FILE *dump; - int nifc = 0; - - if (sig == 0) - dump = stderr; - else - if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) - dump = stderr; - - fprintf(dump, "%s: Interface Table Dump\n", hms()); - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) - nifc++; - fprintf(dump, " Number of interfaces: %d\n", nifc); - - fprintf(dump, " advertising interfaces:\n"); - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if ((ifcp->ifc_flags & IFF_UP) == 0) - continue; - if (iff_find(ifcp, IFIL_TYPE_N) != NULL) - continue; - ifdump0(dump, ifcp); - } - fprintf(dump, "\n"); - fprintf(dump, " non-advertising interfaces:\n"); - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if ((ifcp->ifc_flags & IFF_UP) && - (iff_find(ifcp, IFIL_TYPE_N) == NULL)) - continue; - ifdump0(dump, ifcp); - } - fprintf(dump, "\n"); - if (dump != stderr) - fclose(dump); -} - -static void -ifdump0(FILE *dump, const struct ifc *ifcp) -{ - struct ifac *ifac; - struct iff *iffp; - char buf[BUFSIZ]; - const char *ft; - int addr; - - fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", - ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), - inet6_n2p(&ifcp->ifc_mylladdr), - ifcp->ifc_mtu, ifcp->ifc_metric); - TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { - if (ifcp->ifc_flags & IFF_POINTOPOINT) { - inet_ntop(AF_INET6, (void *)&ifac->ifac_raddr, - buf, sizeof(buf)); - fprintf(dump, "\t%s/%d -- %s\n", - inet6_n2p(&ifac->ifac_addr), - ifac->ifac_plen, buf); - } else { - fprintf(dump, "\t%s/%d\n", - inet6_n2p(&ifac->ifac_addr), - ifac->ifac_plen); - } - } - - fprintf(dump, "\tFilter:\n"); - TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { - addr = 0; - switch (iffp->iff_type) { - case IFIL_TYPE_A: - ft = "Aggregate"; addr++; break; - case IFIL_TYPE_N: - ft = "No-use"; break; - case IFIL_TYPE_O: - ft = "Advertise-only"; addr++; break; - case IFIL_TYPE_T: - ft = "Default-only"; break; - case IFIL_TYPE_L: - ft = "Listen-only"; addr++; break; - default: - snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); - ft = buf; - addr++; - break; - } - fprintf(dump, "\t\t%s", ft); - if (addr) - fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), - iffp->iff_plen); - fprintf(dump, "\n"); - } - fprintf(dump, "\n"); -} - -static void -rtdump(int sig) -{ - struct riprt *rrt; - char buf[BUFSIZ]; - FILE *dump; - time_t t, age; - - if (sig == 0) - dump = stderr; - else - if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) - dump = stderr; - - t = time(NULL); - fprintf(dump, "\n%s: Routing Table Dump\n", hms()); - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (rrt->rrt_t == 0) - age = 0; - else - age = t - rrt->rrt_t; - inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, - buf, sizeof(buf)); - fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", - buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, - index2ifc[rrt->rrt_index]->ifc_name, - inet6_n2p(&rrt->rrt_gw), - rrt->rrt_info.rip6_metric, (long)age); - if (rrt->rrt_info.rip6_tag) { - fprintf(dump, " tag(0x%04x)", - ntohs(rrt->rrt_info.rip6_tag) & 0xffff); - } - if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) - fprintf(dump, " NOT-LL"); - if (rrt->rrt_rflags & RRTF_NOADVERTISE) - fprintf(dump, " NO-ADV"); - fprintf(dump, "\n"); - } - fprintf(dump, "\n"); - if (dump != stderr) - fclose(dump); -} - -/* - * Parse the -A (and -O) options and put corresponding filter object to the - * specified interface structures. Each of the -A/O option has the following - * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) - * -O 5f09:c400::/32,ef0,ef1 (only when match) - */ -static void -filterconfig(void) -{ - int i; - char *p, *ap, *iflp, *ifname, *ep; - struct iff iff, *iffp; - struct ifc *ifcp; - struct riprt *rrt; -#if 0 - struct in6_addr gw; -#endif - u_long plen; - - for (i = 0; i < nfilter; i++) { - ap = filter[i]; - iflp = NULL; - iffp = ⇔ - memset(iffp, 0, sizeof(*iffp)); - if (filtertype[i] == 'N' || filtertype[i] == 'T') { - iflp = ap; - goto ifonly; - } - if ((p = strchr(ap, ',')) != NULL) { - *p++ = '\0'; - iflp = p; - } - if ((p = strchr(ap, '/')) == NULL) { - fatal("no prefixlen specified for '%s'", ap); - /*NOTREACHED*/ - } - *p++ = '\0'; - if (inet_pton(AF_INET6, ap, &iffp->iff_addr) != 1) { - fatal("invalid prefix specified for '%s'", ap); - /*NOTREACHED*/ - } - errno = 0; - ep = NULL; - plen = strtoul(p, &ep, 10); - if (errno || !*p || *ep || plen > sizeof(iffp->iff_addr) * 8) { - fatal("invalid prefix length specified for '%s'", ap); - /*NOTREACHED*/ - } - iffp->iff_plen = plen; - applyplen(&iffp->iff_addr, iffp->iff_plen); -ifonly: - iffp->iff_type = filtertype[i]; - if (iflp == NULL || *iflp == '\0') { - fatal("no interface specified for '%s'", ap); - /*NOTREACHED*/ - } - /* parse the interface listing portion */ - while (iflp) { - ifname = iflp; - if ((iflp = strchr(iflp, ',')) != NULL) - *iflp++ = '\0'; - - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (fnmatch(ifname, ifcp->ifc_name, 0) != 0) - continue; - - iffp = malloc(sizeof(*iffp)); - if (iffp == NULL) { - fatal("malloc of iff"); - /*NOTREACHED*/ - } - memcpy(iffp, &iff, sizeof(*iffp)); -#if 0 - syslog(LOG_INFO, "Add filter: type %d, ifname %s.", iffp->iff_type, ifname); -#endif - TAILQ_INSERT_HEAD(&ifcp->ifc_iff_head, iffp, iff_next); - } - } - - /* - * -A: aggregate configuration. - */ - if (filtertype[i] != IFIL_TYPE_A) - continue; - /* put the aggregate to the kernel routing table */ - rrt = (struct riprt *)malloc(sizeof(struct riprt)); - if (rrt == NULL) { - fatal("malloc: rrt"); - /*NOTREACHED*/ - } - memset(rrt, 0, sizeof(struct riprt)); - rrt->rrt_info.rip6_dest = iff.iff_addr; - rrt->rrt_info.rip6_plen = iff.iff_plen; - rrt->rrt_info.rip6_metric = 1; - rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); - rrt->rrt_gw = in6addr_loopback; - rrt->rrt_flags = RTF_UP | RTF_REJECT; - rrt->rrt_rflags = RRTF_AGGREGATE; - rrt->rrt_t = 0; - rrt->rrt_index = loopifcp->ifc_index; -#if 0 - if (getroute(&rrt->rrt_info, &gw)) { -#if 0 - /* - * When the address has already been registered in the - * kernel routing table, it should be removed - */ - delroute(&rrt->rrt_info, &gw); -#else - /* it is safer behavior */ - errno = EINVAL; - fatal("%s/%u already in routing table, " - "cannot aggregate", - inet6_n2p(&rrt->rrt_info.rip6_dest), - rrt->rrt_info.rip6_plen); - /*NOTREACHED*/ -#endif - } -#endif - /* Put the route to the list */ - TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); - trace(1, "Aggregate: %s/%d for %s\n", - inet6_n2p(&iff.iff_addr), iff.iff_plen, - loopifcp->ifc_name); - /* Add this route to the kernel */ - if (nflag) /* do not modify kernel routing table */ - continue; - addroute(rrt, &in6addr_loopback, loopifcp); - } -} - -/***************** utility functions *****************/ - -/* - * Returns a pointer to ifac whose address and prefix length matches - * with the address and prefix length specified in the arguments. - */ -static struct ifac * -ifa_match(const struct ifc *ifcp, - const struct in6_addr *ia, - int plen) -{ - struct ifac *ifac; - - TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { - if (IN6_ARE_ADDR_EQUAL(&ifac->ifac_addr, ia) && - ifac->ifac_plen == plen) - break; - } - - return (ifac); -} - -/* - * Return a pointer to riprt structure whose address and prefix length - * matches with the address and prefix length found in the argument. - * Note: This is not a rtalloc(). Therefore exact match is necessary. - */ -static struct riprt * -rtsearch(struct netinfo6 *np) -{ - struct riprt *rrt; - - TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { - if (rrt->rrt_info.rip6_plen == np->rip6_plen && - IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, - &np->rip6_dest)) - break; - } - - return (rrt); -} - -static int -sin6mask2len(const struct sockaddr_in6 *sin6) -{ - - return mask2len(&sin6->sin6_addr, - sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); -} - -static int -mask2len(const struct in6_addr *addr, int lenlim) -{ - int i = 0, j; - const u_char *p = (const u_char *)addr; - - for (j = 0; j < lenlim; j++, p++) { - if (*p != 0xff) - break; - i += 8; - } - if (j < lenlim) { - switch (*p) { -#define MASKLEN(m, l) case m: do { i += l; break; } while (0) - MASKLEN(0xfe, 7); break; - MASKLEN(0xfc, 6); break; - MASKLEN(0xf8, 5); break; - MASKLEN(0xf0, 4); break; - MASKLEN(0xe0, 3); break; - MASKLEN(0xc0, 2); break; - MASKLEN(0x80, 1); break; -#undef MASKLEN - } - } - return i; -} - -static const u_char plent[8] = { - 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe -}; - -static void -applyplen(struct in6_addr *ia, int plen) -{ - u_char *p; - int i; - - p = ia->s6_addr; - for (i = 0; i < 16; i++) { - if (plen <= 0) - *p = 0; - else if (plen < 8) - *p &= plent[plen]; - p++, plen -= 8; - } -} - -static const int pl2m[9] = { - 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff -}; - -static struct in6_addr * -plen2mask(int n) -{ - static struct in6_addr ia; - u_char *p; - int i; - - memset(&ia, 0, sizeof(struct in6_addr)); - p = (u_char *)&ia; - for (i = 0; i < 16; i++, p++, n -= 8) { - if (n >= 8) { - *p = 0xff; - continue; - } - *p = pl2m[n]; - break; - } - return &ia; -} - -static char * -allocopy(char *p) -{ - int len = strlen(p) + 1; - char *q = (char *)malloc(len); - - if (!q) { - fatal("malloc"); - /*NOTREACHED*/ - } - - strlcpy(q, p, len); - return q; -} - -static char * -hms(void) -{ - static char buf[BUFSIZ]; - time_t t; - struct tm *tm; - - t = time(NULL); - if ((tm = localtime(&t)) == 0) { - fatal("localtime"); - /*NOTREACHED*/ - } - snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, - tm->tm_sec); - return buf; -} - -#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ - -static int -ripinterval(int timer) -{ - double r = rand(); - - interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); - nextalarm = time(NULL) + interval; - return interval; -} - -#if 0 -static time_t -ripsuptrig(void) -{ - time_t t; - - double r = rand(); - t = (int)(RIP_TRIG_INT6_MIN + - (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); - sup_trig_update = time(NULL) + t; - return t; -} -#endif - -static void -fatal(const char *fmt, ...) -{ - va_list ap; - char buf[1024]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - perror(buf); - if (errno) - syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); - else - syslog(LOG_ERR, "%s", buf); - rtdexit(); -} - -static void -tracet(int level, const char *fmt, ...) -{ - va_list ap; - - if (level <= dflag) { - va_start(ap, fmt); - fprintf(stderr, "%s: ", hms()); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - if (dflag) { - va_start(ap, fmt); - if (level > 0) - vsyslog(LOG_DEBUG, fmt, ap); - else - vsyslog(LOG_WARNING, fmt, ap); - va_end(ap); - } -} - -static void -trace(int level, const char *fmt, ...) -{ - va_list ap; - - if (level <= dflag) { - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - if (dflag) { - va_start(ap, fmt); - if (level > 0) - vsyslog(LOG_DEBUG, fmt, ap); - else - vsyslog(LOG_WARNING, fmt, ap); - va_end(ap); - } -} - -static struct ifc * -ifc_find(char *name) -{ - struct ifc *ifcp; - - TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { - if (strcmp(name, ifcp->ifc_name) == 0) - break; - } - return (ifcp); -} - -static struct iff * -iff_find(struct ifc *ifcp, int type) -{ - struct iff *iffp; - - TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { - if (type == IFIL_TYPE_ANY || - type == iffp->iff_type) - break; - } - - return (iffp); -} - -static void -setindex2ifc(int idx, struct ifc *ifcp) -{ - int n, nsize; - struct ifc **p; - - if (!index2ifc) { - nindex2ifc = 5; /*initial guess*/ - index2ifc = (struct ifc **) - malloc(sizeof(*index2ifc) * nindex2ifc); - if (index2ifc == NULL) { - fatal("malloc"); - /*NOTREACHED*/ - } - memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); - } - n = nindex2ifc; - for (nsize = nindex2ifc; nsize <= idx; nsize *= 2) - ; - if (n != nsize) { - p = (struct ifc **)realloc(index2ifc, - sizeof(*index2ifc) * nsize); - if (p == NULL) { - fatal("realloc"); - /*NOTREACHED*/ - } - memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); - index2ifc = p; - nindex2ifc = nsize; - } - index2ifc[idx] = ifcp; -}