Page MenuHomeFreeBSD

D53484.1790285313.diff
No OneTemporary

Size
475 KB
Referenced Files
None
Subscribers
None

D53484.1790285313.diff

This file is larger than 256 KB, so syntax highlighting was skipped.
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 <ivy@FreeBSD.org>
- *
- * 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 = <<EOD
-routed(8) and route6d(8) allow the host to participate in a RIP (IPv4) or
-RIPng (IPv6) routing domain, exchanging routing information with other RIP
-routers.
-
-RIP and RIPng support is deprecated and will be removed in FreeBSD 16.0.
-EOD
-
-annotations {
- set = "optional,optional-jail"
-}
diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile
--- a/rescue/rescue/Makefile
+++ b/rescue/rescue/Makefile
@@ -127,10 +127,6 @@
CRUNCH_LIBS_pfctl+= ${LIBPFCTL} ${LIBNV}
.endif
-.if ${MK_ROUTED} != "no"
-CRUNCH_PROGS_sbin+= routed rtquery
-.endif
-
.if ${MK_ZFS} != "no"
CRUNCH_PROGS_sbin+= bectl
CRUNCH_PROGS_sbin+= zfs
@@ -186,7 +182,6 @@
CRUNCH_ALIAS_bsdlabel= disklabel
.endif
-CRUNCH_SRCDIR_rtquery= ${SRCTOP}/sbin/routed/rtquery
CRUNCH_SRCDIR_ipf= ${SRCTOP}/sbin/ipf/ipf
.if ${MK_ZFS} != "no"
CRUNCH_SRCDIR_zfs= ${SRCTOP}/cddl/sbin/zfs
diff --git a/sbin/Makefile b/sbin/Makefile
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -81,7 +81,6 @@
SUBDIR.${MK_PF}+= pflogd
SUBDIR.${MK_PF}+= pflowctl
SUBDIR.${MK_QUOTAS}+= quotacheck
-SUBDIR.${MK_ROUTED}+= routed
SUBDIR.${MK_VERIEXEC}+= veriexec
SUBDIR.${MK_ZFS}+= bectl
SUBDIR.${MK_ZFS}+= zfsbootcfg
diff --git a/sbin/routed/Makefile b/sbin/routed/Makefile
deleted file mode 100644
--- a/sbin/routed/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Make `routed` for FreeBSD
-
-PACKAGE=rip
-PROG= routed
-MAN= routed.8
-SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
-WARNS?= 3
-LIBADD= md
-
-SUBDIR= rtquery
-
-.include <bsd.prog.mk>
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 <dirdeps.mk>
-
-.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 <assert.h>
-#include <stdio.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <time.h>
-#include <sys/cdefs.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/sysctl.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include "radix.h"
-#define UNUSED __attribute__((unused))
-#define PATTRIB(f,l) __attribute__((format (printf,f,l)))
-#include <net/if.h>
-#include <net/route.h>
-#include <net/if_dl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#define RIPVERSION RIPv2
-#include <protocols/routed.h>
-
-#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 <md5.h>
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 <stdint.h>
-
-#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 <signal.h>
-#include <fcntl.h>
-#include <sys/file.h>
-
-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 <sys/stat.h>
-
-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 <paths.h>
-
-#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 <sys/cdefs.h>
-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 <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-/* 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 <bsd.prog.mk>
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 <dirdeps.mk>
-
-.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 <sys/param.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#define RIPVERSION RIPv2
-#include <protocols/routed.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef sgi
-#include <strings.h>
-#include <bstring.h>
-#endif
-
-#define UNUSED __attribute__((unused))
-#ifndef sgi
-#define _HAVE_SIN_LEN
-#endif
-
-#ifdef __NetBSD__
-#include <md5.h>
-#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<<i)&mask) == 0);
- i++)
- continue;
- (void)sprintf(sp, "/%d",32-i);
- } else {
- (void)sprintf(sp," (mask %#x)", mask);
- }
- }
-
- if (!nflag) {
- if (mask == 0) {
- mask = std_mask(in.s_addr);
- if ((ntohl(in.s_addr) & ~mask) != 0)
- mask = 0;
- }
- /* Without a netmask, do not worry about
- * whether the destination is a host or a
- * network. Try both and use the first name
- * we get.
- *
- * If we have a netmask we can make a
- * good guess.
- */
- if ((in.s_addr & ~mask) == 0) {
- np = getnetbyaddr((long)in.s_addr,
- AF_INET);
- if (np != NULL)
- name = np->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 <sys/stat.h>
-#include <sys/signal.h>
-#include <fcntl.h>
-
-
-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<<i) & mask) == 0; i++)
- continue;
- (void)snprintf(sp, s + l - sp, "/%d", 32-i);
-
- } else {
- (void)snprintf(sp, s + l - sp, " (mask %#x)",
- (u_int)mask);
- }
- }
-
- return s;
-#undef NUM_BUFS
-}
-
-
-/* display a bit-field
- */
-struct bits {
- u_int bits_mask;
- u_int bits_clear;
- const char *bits_name;
-};
-
-static const struct bits if_bits[] = {
- { IFF_LOOPBACK, 0, "LOOPBACK" },
- { IFF_POINTOPOINT, 0, "PT-TO-PT" },
- { 0, 0, 0}
-};
-
-static const struct bits is_bits[] = {
- { IS_ALIAS, 0, "ALIAS" },
- { IS_SUBNET, 0, "" },
- { IS_REMOTE, (IS_NO_RDISC
- | IS_BCAST_RDISC), "REMOTE" },
- { IS_PASSIVE, (IS_NO_RDISC
- | IS_NO_RIP
- | IS_NO_SUPER_AG
- | IS_PM_RDISC
- | IS_NO_AG), "PASSIVE" },
- { IS_EXTERNAL, 0, "EXTERNAL" },
- { IS_CHECKED, 0, "" },
- { IS_ALL_HOSTS, 0, "" },
- { IS_ALL_ROUTERS, 0, "" },
- { IS_DISTRUST, 0, "DISTRUST" },
- { IS_BROKE, IS_SICK, "BROKEN" },
- { IS_SICK, 0, "SICK" },
- { IS_DUP, 0, "DUPLICATE" },
- { IS_REDIRECT_OK, 0, "REDIRECT_OK" },
- { IS_NEED_NET_SYN, 0, "" },
- { IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
- { IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
- { (IS_NO_RIPV1_IN
- | IS_NO_RIPV2_IN
- | IS_NO_RIPV1_OUT
- | IS_NO_RIPV2_OUT), 0, "NO_RIP" },
- { (IS_NO_RIPV1_IN
- | IS_NO_RIPV1_OUT), 0, "RIPV2" },
- { IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" },
- { IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" },
- { IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" },
- { IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" },
- { (IS_NO_ADV_IN
- | IS_NO_SOL_OUT
- | IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" },
- { IS_NO_SOL_OUT, 0, "NO_SOLICIT" },
- { IS_SOL_OUT, 0, "SEND_SOLICIT" },
- { IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" },
- { IS_ADV_OUT, 0, "RDISC_ADV" },
- { IS_BCAST_RDISC, 0, "BCAST_RDISC" },
- { IS_PM_RDISC, 0, "" },
- { 0, 0, "%#x"}
-};
-
-static const struct bits rs_bits[] = {
- { RS_IF, 0, "IF" },
- { RS_NET_INT, RS_NET_SYN, "NET_INT" },
- { RS_NET_SYN, 0, "NET_SYN" },
- { RS_SUBNET, 0, "" },
- { RS_LOCAL, 0, "LOCAL" },
- { RS_MHOME, 0, "MHOME" },
- { RS_STATIC, 0, "STATIC" },
- { RS_RDISC, 0, "RDISC" },
- { 0, 0, "%#x"}
-};
-
-
-static void
-trace_bits(const struct bits *tbl,
- u_int field,
- int force)
-{
- u_int b;
- char c;
-
- if (force) {
- (void)putc('<', ftrace);
- c = 0;
- } else {
- c = '<';
- }
-
- while (field != 0
- && (b = tbl->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 <bsd.prog.mk>
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 <dirdeps.mk>
-
-.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 <stdio.h>
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <signal.h>
-#include <errno.h>
-#include <err.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/in_var.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#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 <bsd.prog.mk>
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 <dirdeps.mk>
-
-.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";
-$_ = <FD>;
-chop;
-close(FD);
-system("kill -INT $_");
-
-open(NS, "/usr/bin/netstat -r -n|") || die "Can not open netstat";
-while (<NS>) {
- 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 (<FD>) {
- 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 <stdio.h>
-
-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 <sys/param.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <sys/uio.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <net/route.h>
-#include <netinet/in.h>
-#include <netinet/in_var.h>
-#include <netinet/ip6.h>
-#include <netinet/udp.h>
-#include <err.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <ifaddrs.h>
-#include <netdb.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#include <signal.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#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 = &iff;
- 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;
-}

File Metadata

Mime Type
text/plain
Expires
Thu, Sep 24, 9:28 PM (17 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29905272
Default Alt Text
D53484.1790285313.diff (475 KB)

Event Timeline