Remove rtsol(8) and rtsold(8) as their functionality is in dhcpcd(8).
Remove rtsol(8) from rc.d/network. Add -w seconds command to ifconfig to wait for N seconds for until DAD has finished on all addresses. Use ifconfig -w in rc.d/network instead of a forced sleep. As discussed on tech-net@
This commit is contained in:
parent
e8cd4b633c
commit
c6314d6139
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: mi,v 1.1088 2014/08/22 10:51:38 apb Exp $
|
||||
# $NetBSD: mi,v 1.1089 2014/09/11 13:10:03 roy Exp $
|
||||
#
|
||||
# Note: Don't delete entries from here - mark them as "obsolete" instead,
|
||||
# unless otherwise stated below.
|
||||
|
@ -359,7 +359,7 @@
|
|||
./sbin/route base-netutil-root
|
||||
./sbin/routed base-router-root
|
||||
./sbin/rrestore base-netutil-root
|
||||
./sbin/rtsol base-netutil-root use_inet6
|
||||
./sbin/rtsol base-obsolete obsolete
|
||||
./sbin/rump.cgdconfig base-sysutil-root crypto,rump
|
||||
./sbin/rump.ifconfig base-netutil-root rump
|
||||
./sbin/rump.modload base-sysutil-root rump
|
||||
|
@ -1631,7 +1631,7 @@
|
|||
./usr/sbin/rpcbind base-rpcbind-bin
|
||||
./usr/sbin/rtadvd base-router-bin use_inet6
|
||||
./usr/sbin/rtquery base-netutil-bin
|
||||
./usr/sbin/rtsold base-netutil-bin inet6
|
||||
./usr/sbin/rtsold base-obsolete obsolete
|
||||
./usr/sbin/rump.envstat base-sysutil-bin rump
|
||||
./usr/sbin/rump.powerd base-sysutil-bin rump
|
||||
./usr/sbin/rump.traceroute base-netutil-bin rump
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# LIST OF CHANGES FROM LAST RELEASE: <$Revision: 1.1978 $>
|
||||
# LIST OF CHANGES FROM LAST RELEASE: <$Revision: 1.1979 $>
|
||||
#
|
||||
#
|
||||
# [Note: This file does not mention every change made to the NetBSD source tree.
|
||||
|
@ -46,3 +46,5 @@ Changes from NetBSD 7.0 to NetBSD 8.0:
|
|||
awinrtc(4): Add support for AllWinner A10/A20 real-time clock.
|
||||
[jmcneill 20140907]
|
||||
awinmmc(4): Use DMA for MMC transfers. [jmcneill 20140908]
|
||||
rtsol(8): Removed in favour of dhcpcd. [roy 20140911]
|
||||
rtsold(8): Removed in favour of dhcpcd. [roy 20140911]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: rc.conf,v 1.123 2014/07/22 17:11:09 wiz Exp $
|
||||
# $NetBSD: rc.conf,v 1.124 2014/09/11 13:10:03 roy Exp $
|
||||
#
|
||||
# /etc/defaults/rc.conf --
|
||||
# default configuration of /etc/rc.conf
|
||||
|
@ -253,7 +253,6 @@ routed=NO routed_flags="-q"
|
|||
gated=NO
|
||||
mrouted=NO mrouted_flags=""
|
||||
route6d=NO route6d_flags=""
|
||||
rtsold=NO rtsold_flags="-a" # for ip6mode=autohost only
|
||||
ldpd=NO
|
||||
|
||||
# Daemons used to boot other hosts over a network.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# $NetBSD: network,v 1.66 2014/04/29 09:58:18 uebayasi Exp $
|
||||
# $NetBSD: network,v 1.67 2014/09/11 13:10:03 roy Exp $
|
||||
#
|
||||
|
||||
# PROVIDE: network
|
||||
|
@ -432,33 +432,26 @@ network_start_defaultroute6()
|
|||
network_start_ipv6_autoconf()
|
||||
{
|
||||
# IPv6 interface autoconfiguration.
|
||||
#
|
||||
# wait till DAD is completed. always invoke it in case
|
||||
# if are configured manually by ifconfig
|
||||
#
|
||||
echo 'Waiting for DAD completion for' \
|
||||
'statically configured addresses...'
|
||||
dadcount=$(/sbin/sysctl -n net.inet6.ip6.dad_count 2>/dev/null)
|
||||
sleep $dadcount
|
||||
sleep 1
|
||||
|
||||
if checkyesno rtsol; then
|
||||
if [ "$ip6mode" = "autohost" ]; then
|
||||
echo 'Sending router solicitation...'
|
||||
/sbin/rtsol $rtsol_flags
|
||||
else
|
||||
echo
|
||||
warn \
|
||||
"ip6mode must be set to 'autohost' to use rtsol."
|
||||
dadcount=$(/sbin/sysctl -n net.inet6.ip6.dad_count 2>/dev/null)
|
||||
if [ -n "$dadcount" -a "$dadcount" != 0 ]; then
|
||||
# wait till DAD is completed
|
||||
echo 'Waiting for DAD to complete for' \
|
||||
'statically configured addresses...'
|
||||
# Add 1 for MAX_RTR_SOLICITATION_DELAY and another
|
||||
# to give time for the last DAD packet to respond and
|
||||
# a few more for luck.
|
||||
waitsecs=$((dadcount + 4))
|
||||
/sbin/ifconfig -w $waitsecs
|
||||
fi
|
||||
|
||||
# wait till DAD is completed, for global addresses
|
||||
# configured by router advert message.
|
||||
#
|
||||
echo 'Waiting for DAD completion for' \
|
||||
'addresses configured by router advert message...'
|
||||
sleep $dadcount
|
||||
sleep 1
|
||||
# dhcpcd will ensure DAD completes before forking
|
||||
if checkyesno rtsol && !checkyesno dhcpcd; then
|
||||
if [ "$ip6mode" = "autohost" ]; then
|
||||
echo
|
||||
warn "rtsol has been removed, " \
|
||||
"please configure dhcpcd in its place."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# $NetBSD: rtsold,v 1.7 2006/10/07 21:41:41 rpaulo Exp $
|
||||
#
|
||||
|
||||
# PROVIDE: rtsold
|
||||
# REQUIRE: network mountcritlocal
|
||||
# BEFORE: NETWORKING
|
||||
|
||||
$_rc_subr_loaded . /etc/rc.subr
|
||||
|
||||
name="rtsold"
|
||||
rcvar=$name
|
||||
command="/usr/sbin/${name}"
|
||||
start_precmd="rtsold_precmd"
|
||||
|
||||
rtsold_precmd()
|
||||
{
|
||||
if [ "$ip6mode" != "autohost" ]; then
|
||||
warn "\$ip6mode must be set to 'autohost' to use ${name}."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
load_rc_config $name
|
||||
run_rc_command "$1"
|
|
@ -1,4 +1,3 @@
|
|||
# $NetBSD: list.inet6,v 1.1 2005/01/10 02:58:59 lukem Exp $
|
||||
# $NetBSD: list.inet6,v 1.2 2014/09/11 13:10:03 roy Exp $
|
||||
|
||||
PROG ping6
|
||||
PROG rtsol
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile,v 1.126 2013/12/25 22:04:52 christos Exp $
|
||||
# $NetBSD: Makefile,v 1.127 2014/09/11 13:10:03 roy Exp $
|
||||
# @(#)Makefile 8.5 (Berkeley) 3/31/94
|
||||
|
||||
# Not ported: XNSrouted enpload scsiformat startslip
|
||||
|
@ -55,7 +55,7 @@ SUBDIR+= cgdconfig
|
|||
.endif
|
||||
|
||||
.if (${USE_INET6} != "no")
|
||||
SUBDIR+= ping6 rtsol
|
||||
SUBDIR+= ping6
|
||||
.endif
|
||||
|
||||
.if (${MKISCSI} != "no")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: ifconfig.8,v 1.106 2014/01/07 20:25:24 degroote Exp $
|
||||
.\" $NetBSD: ifconfig.8,v 1.107 2014/09/11 13:10:04 roy Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
|
@ -59,6 +59,9 @@
|
|||
.Fl s
|
||||
.Ar interface
|
||||
.Nm
|
||||
.Fl w
|
||||
.Ar secs
|
||||
.Nm
|
||||
.Fl C
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
|
@ -860,6 +863,17 @@ flag except that it zeros the interface input and output statistics
|
|||
after printing them.
|
||||
.Pp
|
||||
The
|
||||
.Fl w
|
||||
flag may be used to wait
|
||||
.Ar seconds
|
||||
seconds for the
|
||||
.Cm tentative
|
||||
flag to be removed from all addresses.
|
||||
0 seconds means to wait indefinitely until all addresses no longer have the
|
||||
.Cm tentative
|
||||
flag.
|
||||
.Pp
|
||||
The
|
||||
.Fl N
|
||||
flag is just the opposite of the
|
||||
.Fl n
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ifconfig.c,v 1.231 2013/10/19 00:35:30 christos Exp $ */
|
||||
/* $NetBSD: ifconfig.c,v 1.232 2014/09/11 13:10:04 roy Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
|
||||
|
@ -63,7 +63,7 @@
|
|||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1983, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
__RCSID("$NetBSD: ifconfig.c,v 1.231 2013/10/19 00:35:30 christos Exp $");
|
||||
__RCSID("$NetBSD: ifconfig.c,v 1.232 2014/09/11 13:10:04 roy Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -102,10 +102,13 @@ __RCSID("$NetBSD: ifconfig.c,v 1.231 2013/10/19 00:35:30 christos Exp $");
|
|||
#include "env.h"
|
||||
#include "prog_ops.h"
|
||||
|
||||
static bool bflag, dflag, hflag, sflag, uflag;
|
||||
bool lflag, Nflag, vflag, zflag;
|
||||
#define WAIT_DAD 10000000 /* nanoseconds between each poll, 10ms */
|
||||
|
||||
static char gflags[10 + 26 * 2 + 1] = "AabCdhlNsuvz";
|
||||
static bool bflag, dflag, hflag, sflag, uflag, wflag;
|
||||
bool lflag, Nflag, vflag, zflag;
|
||||
static long wflag_secs;
|
||||
|
||||
static char gflags[10 + 26 * 2 + 1] = "AabCdhlNsuvw:z";
|
||||
bool gflagset[10 + 26 * 2];
|
||||
|
||||
static int carrier(prop_dictionary_t);
|
||||
|
@ -115,6 +118,7 @@ static int flag_index(int);
|
|||
static void init_afs(void);
|
||||
static int list_cloners(prop_dictionary_t, prop_dictionary_t);
|
||||
static int media_status_exec(prop_dictionary_t, prop_dictionary_t);
|
||||
static int wait_dad_exec(prop_dictionary_t, prop_dictionary_t);
|
||||
static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t);
|
||||
static int notrailers(prop_dictionary_t, prop_dictionary_t);
|
||||
static void printall(const char *, prop_dictionary_t);
|
||||
|
@ -223,6 +227,9 @@ static struct kwinst familykw[24];
|
|||
struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners",
|
||||
list_cloners, "none");
|
||||
|
||||
struct pterm wait_dad = PTERM_INITIALIZER(&wait_dad, "wait DAD", wait_dad_exec,
|
||||
"none");
|
||||
|
||||
struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec,
|
||||
"none");
|
||||
|
||||
|
@ -505,6 +512,70 @@ no_cmds_exec(prop_dictionary_t env, prop_dictionary_t oenv)
|
|||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
wait_dad_exec(prop_dictionary_t env, prop_dictionary_t oenv)
|
||||
{
|
||||
#ifdef INET6
|
||||
bool waiting;
|
||||
struct ifaddrs *ifaddrs, *ifa;
|
||||
struct in6_ifreq ifr6;
|
||||
int s;
|
||||
const struct timespec ts = { .tv_sec = 0, .tv_nsec = WAIT_DAD };
|
||||
const struct timespec add = { .tv_sec = wflag_secs, .tv_nsec = 0};
|
||||
struct timespec now, end;
|
||||
|
||||
if (wflag_secs) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
|
||||
err(EXIT_FAILURE, "clock_gettime");
|
||||
timespecadd(&now, &add, &end);
|
||||
}
|
||||
|
||||
if (getifaddrs(&ifaddrs) == -1)
|
||||
err(EXIT_FAILURE, "getifaddrs");
|
||||
|
||||
for (;;) {
|
||||
waiting = false;
|
||||
for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == NULL)
|
||||
continue;
|
||||
switch (ifa->ifa_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
strncpy(ifr6.ifr_name,
|
||||
ifa->ifa_name, sizeof(ifr6.ifr_name));
|
||||
ifr6.ifr_addr =
|
||||
*(struct sockaddr_in6 *)ifa->ifa_addr;
|
||||
if ((s = getsock(AF_INET6)) == -1)
|
||||
err(EXIT_FAILURE,
|
||||
"%s: getsock", __func__);
|
||||
if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == -1)
|
||||
err(EXIT_FAILURE, "SIOCGIFAFLAG_IN6");
|
||||
if (ifr6.ifr_ifru.ifru_flags6 &
|
||||
IN6_IFF_TENTATIVE)
|
||||
{
|
||||
waiting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (waiting)
|
||||
break;
|
||||
}
|
||||
if (!waiting)
|
||||
break;
|
||||
nanosleep(&ts, NULL);
|
||||
if (wflag_secs) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
|
||||
err(EXIT_FAILURE, "clock_gettime");
|
||||
if (timespeccmp(&now, &end, >))
|
||||
errx(EXIT_FAILURE, "timed out");
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddrs);
|
||||
#endif
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
media_status_exec(prop_dictionary_t env, prop_dictionary_t oenv)
|
||||
{
|
||||
|
@ -549,6 +620,7 @@ main(int argc, char **argv)
|
|||
int ch, narg = 0, rc;
|
||||
prop_dictionary_t env, oenv;
|
||||
const char *ifname;
|
||||
char *end;
|
||||
|
||||
memset(match, 0, sizeof(match));
|
||||
|
||||
|
@ -605,6 +677,14 @@ main(int argc, char **argv)
|
|||
vflag = true;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
wflag = true;
|
||||
wflag_secs = strtol(optarg, &end, 10);
|
||||
if ((end != NULL && *end != '\0') ||
|
||||
wflag_secs < 0 || wflag_secs >= INT32_MAX)
|
||||
errx(EXIT_FAILURE, "%s: not a number", optarg);
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
zflag = true;
|
||||
break;
|
||||
|
@ -636,6 +716,9 @@ main(int argc, char **argv)
|
|||
start != &opt_family_only.pb_parser)
|
||||
start = &iface_only.pif_parser;
|
||||
break;
|
||||
case 'w':
|
||||
start = &wait_dad.pt_parser;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -644,19 +727,23 @@ main(int argc, char **argv)
|
|||
argv += optind;
|
||||
|
||||
/*
|
||||
* -l means "list all interfaces", and is mutally exclusive with
|
||||
* -l means "list all interfaces", and is mutually exclusive with
|
||||
* all other flags/commands.
|
||||
*
|
||||
* -C means "list all names of cloners", and it mutually exclusive
|
||||
* with all other flags/commands.
|
||||
*
|
||||
* -a means "print status of all interfaces".
|
||||
*
|
||||
* -w means "spin until DAD completes for all addreseses", and is
|
||||
* mutually exclusivewith all other flags/commands.
|
||||
*/
|
||||
if ((lflag || Cflag) && (aflag || get_flag('m') || vflag || zflag))
|
||||
if ((lflag || Cflag || wflag) &&
|
||||
(aflag || get_flag('m') || vflag || zflag))
|
||||
usage();
|
||||
if ((lflag || Cflag) && get_flag('L'))
|
||||
if ((lflag || Cflag || wflag) && get_flag('L'))
|
||||
usage();
|
||||
if (lflag && Cflag)
|
||||
if ((lflag && Cflag) || (lflag & wflag) || (Cflag && wflag))
|
||||
usage();
|
||||
|
||||
nmatch = __arraycount(match);
|
||||
|
@ -1399,10 +1486,11 @@ usage(void)
|
|||
" %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n"
|
||||
" %s -l [-b] [-d] [-s] [-u]\n"
|
||||
" %s -C\n"
|
||||
" %s -w n\n"
|
||||
" %s interface create\n"
|
||||
" %s interface destroy\n",
|
||||
progname, flag_is_registered(gflags, 'm') ? "[-m] " : "",
|
||||
progname, progname, progname, progname);
|
||||
progname, progname, progname, progname, progname);
|
||||
|
||||
prop_object_release((prop_object_t)env);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# $NetBSD: Makefile,v 1.13 2004/01/03 01:40:31 itojun Exp $
|
||||
|
||||
NOMAN= # defined
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= rtsol
|
||||
SRCS= rtsold.c rtsol.c if.c probe.c rtsock.c
|
||||
|
||||
CPPFLAGS+=-DSMALL -DUSE_RTSOCK
|
||||
|
||||
#MAN= rtsold.8
|
||||
|
||||
.PATH: ${NETBSDSRCDIR}/usr.sbin/rtsold
|
||||
|
||||
LDADD+= -lutil
|
||||
DPADD+= ${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# $NetBSD: postinstall,v 1.179 2014/08/12 09:12:18 apb Exp $
|
||||
# $NetBSD: postinstall,v 1.180 2014/09/11 13:10:04 roy Exp $
|
||||
#
|
||||
# Copyright (c) 2002-2008 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
|
@ -1332,7 +1332,7 @@ do_rc()
|
|||
quota \
|
||||
racoon rpcbind raidframe raidframeparity random_seed rarpd \
|
||||
rbootd rndctl root route6d routed rtadvd rtclocaltime \
|
||||
rtsold rwho \
|
||||
rwho \
|
||||
savecore screenblank securelevel sshd \
|
||||
staticroute swap1 swap2 sysctl sysdb syslogd \
|
||||
timed tpctl ttys \
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
# $NetBSD: Makefile,v 1.15 2014/03/18 00:16:49 christos Exp $
|
||||
|
||||
WARNS?=6
|
||||
USE_FORT?= yes # network client (local server)
|
||||
|
||||
PROG= rtsold
|
||||
SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
|
||||
|
||||
CPPFLAGS+=-DUSE_RTSOCK
|
||||
# $NetBSD: Makefile,v 1.16 2014/09/11 13:10:04 roy Exp $
|
||||
|
||||
MAN= rtsold.8
|
||||
MLINKS= rtsold.8 rtsol.8
|
||||
|
||||
LDADD+= -lutil
|
||||
DPADD+= ${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
/* $NetBSD: dump.c,v 1.10 2014/03/18 00:16:49 christos Exp $ */
|
||||
/* $KAME: dump.c,v 1.10 2002/05/31 10:10:03 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "rtsold.h"
|
||||
|
||||
static FILE *fp;
|
||||
|
||||
static void dump_interface_status(void);
|
||||
static const char *sec2str(time_t);
|
||||
static const char *ifstatstr[] = {
|
||||
"IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE"
|
||||
};
|
||||
|
||||
static void
|
||||
dump_interface_status(void)
|
||||
{
|
||||
struct ifinfo *ifinfo;
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
|
||||
fprintf(fp, "Interface %s\n", ifinfo->ifname);
|
||||
fprintf(fp, " probe interval: ");
|
||||
if (ifinfo->probeinterval) {
|
||||
fprintf(fp, "%d\n", ifinfo->probeinterval);
|
||||
fprintf(fp, " probe timer: %d\n", ifinfo->probetimer);
|
||||
} else {
|
||||
fprintf(fp, "infinity\n");
|
||||
fprintf(fp, " no probe timer\n");
|
||||
}
|
||||
fprintf(fp, " interface status: %s\n",
|
||||
ifinfo->active > 0 ? "active" : "inactive");
|
||||
fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]);
|
||||
fprintf(fp, " carrier detection: %s\n",
|
||||
ifinfo->mediareqok ? "available" : "unavailable");
|
||||
fprintf(fp, " probes: %d, dadcount = %d\n",
|
||||
ifinfo->probes, ifinfo->dadcount);
|
||||
if (ifinfo->timer.tv_sec == tm_max.tv_sec &&
|
||||
ifinfo->timer.tv_usec == tm_max.tv_usec)
|
||||
fprintf(fp, " no timer\n");
|
||||
else {
|
||||
fprintf(fp, " timer: interval=%d:%d, expire=%s\n",
|
||||
(int)ifinfo->timer.tv_sec,
|
||||
(int)ifinfo->timer.tv_usec,
|
||||
(ifinfo->expire.tv_sec < now.tv_sec) ? "expired"
|
||||
: sec2str(ifinfo->expire.tv_sec - now.tv_sec));
|
||||
}
|
||||
fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rtsold_dump_file(const char *dumpfile)
|
||||
{
|
||||
if ((fp = fopen(dumpfile, "w")) == NULL) {
|
||||
warnmsg(LOG_WARNING, __func__, "open a dump file(%s): %s",
|
||||
dumpfile, strerror(errno));
|
||||
return;
|
||||
}
|
||||
dump_interface_status();
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static const char *
|
||||
sec2str(time_t total)
|
||||
{
|
||||
static char result[256];
|
||||
int days, hours, mins, secs;
|
||||
int first = 1;
|
||||
char *p = result;
|
||||
char *ep = &result[sizeof(result)];
|
||||
int n;
|
||||
|
||||
days = (int)(total / 3600 / 24);
|
||||
hours = (int)((total / 3600) % 24);
|
||||
mins = (int)((total / 60) % 60);
|
||||
secs = (int)(total % 60);
|
||||
|
||||
if (days) {
|
||||
first = 0;
|
||||
n = snprintf(p, (size_t)(ep - p), "%dd", days);
|
||||
if (n < 0 || n >= ep - p)
|
||||
return "?";
|
||||
p += n;
|
||||
}
|
||||
if (!first || hours) {
|
||||
first = 0;
|
||||
n = snprintf(p, (size_t)(ep - p), "%dh", hours);
|
||||
if (n < 0 || n >= ep - p)
|
||||
return "?";
|
||||
p += n;
|
||||
}
|
||||
if (!first || mins) {
|
||||
first = 0;
|
||||
n = snprintf(p, (size_t)(ep - p), "%dm", mins);
|
||||
if (n < 0 || n >= ep - p)
|
||||
return "?";
|
||||
p += n;
|
||||
}
|
||||
snprintf(p, (size_t)(ep - p), "%ds", secs);
|
||||
return result;
|
||||
}
|
|
@ -1,366 +0,0 @@
|
|||
/* $NetBSD: if.c,v 1.16 2014/03/18 00:16:49 christos Exp $ */
|
||||
/* $KAME: if.c,v 1.18 2002/05/31 10:10:03 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* 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/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_ether.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include <netinet6/in6_var.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include "rtsold.h"
|
||||
|
||||
static int ifsock;
|
||||
|
||||
static int get_llflag(const char *);
|
||||
static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
|
||||
|
||||
int
|
||||
ifinit(void)
|
||||
{
|
||||
ifsock = rssock;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
interface_up(char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int llflag;
|
||||
|
||||
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
|
||||
if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (!(ifr.ifr_flags & IFF_UP)) {
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
if (ioctl(ifsock, SIOCSIFFLAGS, &ifr) < 0)
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"ioctl(SIOCSIFFLAGS): %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name);
|
||||
|
||||
llflag = get_llflag(name);
|
||||
if (llflag < 0) {
|
||||
warnmsg(LOG_WARNING, __func__,
|
||||
"get_llflag() failed, anyway I'll try");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(llflag & IN6_IFF_NOTREADY)) {
|
||||
warnmsg(LOG_DEBUG, __func__, "%s is ready", name);
|
||||
return 0;
|
||||
} else {
|
||||
if (llflag & IN6_IFF_TENTATIVE) {
|
||||
warnmsg(LOG_DEBUG, __func__, "%s is tentative",
|
||||
name);
|
||||
return IFS_TENTATIVE;
|
||||
}
|
||||
if (llflag & IN6_IFF_DUPLICATED)
|
||||
warnmsg(LOG_DEBUG, __func__, "%s is duplicated",
|
||||
name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
interface_status(struct ifinfo *ifinfo)
|
||||
{
|
||||
char *ifname = ifinfo->ifname;
|
||||
struct ifreq ifr;
|
||||
struct ifmediareq ifmr;
|
||||
|
||||
/* get interface flags */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s",
|
||||
ifname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* if one of UP and RUNNING flags is dropped,
|
||||
* the interface is not active.
|
||||
*/
|
||||
if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
|
||||
goto inactive;
|
||||
}
|
||||
|
||||
/* Next, check carrier on the interface, if possible */
|
||||
if (!ifinfo->mediareqok)
|
||||
goto active;
|
||||
memset(&ifmr, 0, sizeof(ifmr));
|
||||
strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
|
||||
|
||||
if (ioctl(ifsock, SIOCGIFMEDIA, &ifmr) < 0) {
|
||||
if (errno != EINVAL) {
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"ioctl(SIOCGIFMEDIA) on %s: %s",
|
||||
ifname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* EINVAL simply means that the interface does not support
|
||||
* the SIOCGIFMEDIA ioctl. We regard it alive.
|
||||
*/
|
||||
ifinfo->mediareqok = 0;
|
||||
goto active;
|
||||
}
|
||||
|
||||
if (ifmr.ifm_status & IFM_AVALID) {
|
||||
switch (ifmr.ifm_active & IFM_NMASK) {
|
||||
case IFM_ETHER:
|
||||
if (ifmr.ifm_status & IFM_ACTIVE)
|
||||
goto active;
|
||||
else
|
||||
goto inactive;
|
||||
break;
|
||||
default:
|
||||
goto inactive;
|
||||
}
|
||||
}
|
||||
|
||||
inactive:
|
||||
return 0;
|
||||
|
||||
active:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define ROUNDUP(a, size) \
|
||||
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
|
||||
|
||||
#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
|
||||
((char *)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
|
||||
sizeof(u_long)) : sizeof(u_long)))
|
||||
#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
|
||||
|
||||
size_t
|
||||
lladdropt_length(struct sockaddr_dl *sdl)
|
||||
{
|
||||
switch (sdl->sdl_type) {
|
||||
case IFT_ETHER:
|
||||
#ifdef IFT_IEEE80211
|
||||
case IFT_IEEE80211:
|
||||
#endif
|
||||
return ROUNDUP8(ETHER_ADDR_LEN + 2);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
|
||||
{
|
||||
char *addr;
|
||||
|
||||
ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
|
||||
|
||||
switch (sdl->sdl_type) {
|
||||
case IFT_ETHER:
|
||||
#ifdef IFT_IEEE80211
|
||||
case IFT_IEEE80211:
|
||||
#endif
|
||||
ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
|
||||
addr = (char *)(ndopt + 1);
|
||||
memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
|
||||
break;
|
||||
default:
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"unsupported link type(%d)", sdl->sdl_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_dl *
|
||||
if_nametosdl(char *name)
|
||||
{
|
||||
int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
|
||||
char *buf, *next, *lim;
|
||||
size_t len;
|
||||
struct if_msghdr *ifm;
|
||||
struct sockaddr *sa, *rti_info[RTAX_MAX];
|
||||
struct sockaddr_dl *sdl = NULL, *ret_sdl;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
|
||||
return NULL;
|
||||
if ((buf = malloc(len)) == NULL)
|
||||
return NULL;
|
||||
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lim = buf + len;
|
||||
for (next = buf; next < lim; next += ifm->ifm_msglen) {
|
||||
ifm = (struct if_msghdr *)next;
|
||||
if (ifm->ifm_type == RTM_IFINFO) {
|
||||
sa = (struct sockaddr *)(ifm + 1);
|
||||
get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
|
||||
if ((sa = rti_info[RTAX_IFP]) != NULL) {
|
||||
if (sa->sa_family == AF_LINK) {
|
||||
sdl = (struct sockaddr_dl *)sa;
|
||||
if (strlen(name) != sdl->sdl_nlen)
|
||||
continue; /* not same len */
|
||||
if (strncmp(&sdl->sdl_data[0],
|
||||
name,
|
||||
sdl->sdl_nlen) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next == lim || sdl == NULL) {
|
||||
/* search failed */
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret_sdl, sdl, sdl->sdl_len);
|
||||
|
||||
free(buf);
|
||||
return(ret_sdl);
|
||||
}
|
||||
|
||||
int
|
||||
getinet6sysctl(int code)
|
||||
{
|
||||
int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
|
||||
int value;
|
||||
size_t size;
|
||||
|
||||
mib[3] = code;
|
||||
size = sizeof(value);
|
||||
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
|
||||
return -1;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
/* get ia6_flags for link-local addr on if. returns -1 on error. */
|
||||
static int
|
||||
get_llflag(const char *name)
|
||||
{
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
struct in6_ifreq ifr6;
|
||||
struct sockaddr_in6 *sin6;
|
||||
int s;
|
||||
|
||||
if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (getifaddrs(&ifap) != 0) {
|
||||
warnmsg(LOG_ERR, __func__, "getifaddrs: %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
||||
if (strlen(ifa->ifa_name) != strlen(name) ||
|
||||
strncmp(ifa->ifa_name, name, strlen(name)) != 0)
|
||||
continue;
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
|
||||
continue;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
|
||||
memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len);
|
||||
if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
close(s);
|
||||
return ifr6.ifr_ifru.ifru_flags6;
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RTAX_MAX; i++) {
|
||||
if (addrs & (1 << i)) {
|
||||
rti_info[i] = sa;
|
||||
NEXT_SA(sa);
|
||||
} else
|
||||
rti_info[i] = NULL;
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
/* $NetBSD: probe.c,v 1.12 2014/03/18 00:16:49 christos Exp $ */
|
||||
/* $KAME: probe.c,v 1.15 2002/05/31 21:22:08 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 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/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet6/nd6.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rtsold.h"
|
||||
|
||||
static struct msghdr sndmhdr;
|
||||
static struct iovec sndiov[2];
|
||||
static int probesock;
|
||||
static void sendprobe(struct in6_addr *, struct ifinfo *);
|
||||
|
||||
int
|
||||
probe_init(void)
|
||||
{
|
||||
size_t scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
|
||||
CMSG_SPACE(sizeof(int));
|
||||
static u_char *sndcmsgbuf = NULL;
|
||||
|
||||
if (sndcmsgbuf == NULL &&
|
||||
(sndcmsgbuf = malloc(scmsglen)) == NULL) {
|
||||
warnmsg(LOG_ERR, __func__, "malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make the socket send-only */
|
||||
if (shutdown(probesock, 0)) {
|
||||
warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialize msghdr for sending packets */
|
||||
sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
sndmhdr.msg_iov = sndiov;
|
||||
sndmhdr.msg_iovlen = 1;
|
||||
sndmhdr.msg_control = sndcmsgbuf;
|
||||
sndmhdr.msg_controllen = (socklen_t)scmsglen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe if each router in the default router list is still alive.
|
||||
*/
|
||||
void
|
||||
defrouter_probe(struct ifinfo *ifinfo)
|
||||
{
|
||||
char ntopbuf[INET6_ADDRSTRLEN];
|
||||
struct in6_drlist dr;
|
||||
int s, i;
|
||||
int ifindex = ifinfo->sdl->sdl_index;
|
||||
|
||||
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
memset(&dr, 0, sizeof(dr));
|
||||
strlcpy(dr.ifname, "lo0", sizeof dr.ifname); /* dummy interface */
|
||||
if (ioctl(s, SIOCGDRLST_IN6, &dr) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "ioctl(SIOCGDRLST_IN6): %s",
|
||||
strerror(errno));
|
||||
goto closeandend;
|
||||
}
|
||||
|
||||
for (i = 0; i < PRLSTSIZ && dr.defrouter[i].if_index; i++) {
|
||||
if (ifindex && dr.defrouter[i].if_index == ifindex) {
|
||||
/* sanity check */
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"default router list contains a "
|
||||
"non-link-local address(%s)",
|
||||
inet_ntop(AF_INET6,
|
||||
&dr.defrouter[i].rtaddr,
|
||||
ntopbuf, INET6_ADDRSTRLEN));
|
||||
continue; /* ignore the address */
|
||||
}
|
||||
sendprobe(&dr.defrouter[i].rtaddr, ifinfo);
|
||||
}
|
||||
}
|
||||
|
||||
closeandend:
|
||||
close(s);
|
||||
}
|
||||
|
||||
static void
|
||||
sendprobe(struct in6_addr *addr, struct ifinfo *ifinfo)
|
||||
{
|
||||
char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
|
||||
struct sockaddr_in6 sa6_probe;
|
||||
struct in6_pktinfo *pi;
|
||||
struct cmsghdr *cm;
|
||||
u_int32_t ifindex = ifinfo->sdl->sdl_index;
|
||||
int hoplimit = 1;
|
||||
|
||||
memset(&sa6_probe, 0, sizeof(sa6_probe));
|
||||
sa6_probe.sin6_family = AF_INET6;
|
||||
sa6_probe.sin6_len = sizeof(sa6_probe);
|
||||
sa6_probe.sin6_addr = *addr;
|
||||
sa6_probe.sin6_scope_id = ifinfo->linkid;
|
||||
|
||||
sndmhdr.msg_name = &sa6_probe;
|
||||
sndmhdr.msg_iov[0].iov_base = NULL;
|
||||
sndmhdr.msg_iov[0].iov_len = 0;
|
||||
|
||||
cm = CMSG_FIRSTHDR(&sndmhdr);
|
||||
/* specify the outgoing interface */
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_PKTINFO;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
|
||||
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
|
||||
pi->ipi6_ifindex = ifindex;
|
||||
|
||||
/* specify the hop limit of the packet for safety */
|
||||
cm = CMSG_NXTHDR(&sndmhdr, cm);
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_HOPLIMIT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
|
||||
|
||||
warnmsg(LOG_DEBUG, __func__, "probe a router %s on %s",
|
||||
inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN),
|
||||
if_indextoname(ifindex, ifnamebuf));
|
||||
|
||||
if (sendmsg(probesock, &sndmhdr, 0))
|
||||
warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
|
||||
if_indextoname(ifindex, ifnamebuf), strerror(errno));
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/* $NetBSD: rtsock.c,v 1.7 2014/03/18 00:16:49 christos Exp $ */
|
||||
/* $KAME: rtsock.c,v 1.4 2001/09/19 06:59:41 sakane Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 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/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include "rtsold.h"
|
||||
|
||||
#define ROUNDUP(a, size) \
|
||||
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
|
||||
|
||||
#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
|
||||
((char *)(ap) + \
|
||||
((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) \
|
||||
: sizeof(u_long)))
|
||||
|
||||
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
|
||||
static int rtsock_input_ifannounce(int, struct rt_msghdr *, char *);
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
u_char type;
|
||||
size_t minlen;
|
||||
int (*func) __P((int, struct rt_msghdr *, char *));
|
||||
} rtsock_dispatch[] = {
|
||||
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
|
||||
{ RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr),
|
||||
rtsock_input_ifannounce },
|
||||
#endif
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
int
|
||||
rtsock_open(void)
|
||||
{
|
||||
|
||||
return socket(PF_ROUTE, SOCK_RAW, 0);
|
||||
}
|
||||
|
||||
int
|
||||
rtsock_input(int s)
|
||||
{
|
||||
ssize_t n;
|
||||
char msg[2048];
|
||||
char *lim, *next;
|
||||
struct rt_msghdr *rtm;
|
||||
int idx;
|
||||
size_t len;
|
||||
int ret = 0;
|
||||
const size_t lenlim =
|
||||
offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen);
|
||||
|
||||
n = read(s, msg, sizeof(msg));
|
||||
|
||||
lim = msg + n;
|
||||
for (next = msg; next < lim; next += len) {
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
if (lim - next < (intptr_t)lenlim)
|
||||
break;
|
||||
len = rtm->rtm_msglen;
|
||||
if (len < lenlim)
|
||||
break;
|
||||
|
||||
if (dflag > 1) {
|
||||
warnmsg(LOG_INFO, __func__,
|
||||
"rtmsg type %d, len=%lu", rtm->rtm_type,
|
||||
(u_long)len);
|
||||
}
|
||||
|
||||
for (idx = 0; rtsock_dispatch[idx].func; idx++) {
|
||||
if (rtm->rtm_type != rtsock_dispatch[idx].type)
|
||||
continue;
|
||||
if (rtm->rtm_msglen < rtsock_dispatch[idx].minlen) {
|
||||
warnmsg(LOG_INFO, __func__,
|
||||
"rtmsg type %d too short!", rtm->rtm_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = (*rtsock_dispatch[idx].func)(s, rtm, lim);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
|
||||
static int
|
||||
rtsock_input_ifannounce(int s, struct rt_msghdr *rtm, char *lim)
|
||||
{
|
||||
struct if_announcemsghdr *ifan;
|
||||
struct ifinfo *ifinfo;
|
||||
|
||||
ifan = (struct if_announcemsghdr *)rtm;
|
||||
if ((char *)(ifan + 1) > lim)
|
||||
return -1;
|
||||
|
||||
switch (ifan->ifan_what) {
|
||||
case IFAN_ARRIVAL:
|
||||
/*
|
||||
* XXX for NetBSD 1.5, interface index will monotonically be
|
||||
* increased as new pcmcia card gets inserted.
|
||||
* we may be able to do a name-based interface match,
|
||||
* and call ifreconfig() to enable the interface again.
|
||||
*/
|
||||
warnmsg(LOG_INFO, __func__,
|
||||
"interface %s inserted", ifan->ifan_name);
|
||||
break;
|
||||
case IFAN_DEPARTURE:
|
||||
warnmsg(LOG_WARNING, __func__,
|
||||
"interface %s removed", ifan->ifan_name);
|
||||
ifinfo = find_ifinfo(ifan->ifan_index);
|
||||
if (ifinfo) {
|
||||
if (dflag > 1) {
|
||||
warnmsg(LOG_INFO, __func__,
|
||||
"bring interface %s to DOWN state",
|
||||
ifan->ifan_name);
|
||||
}
|
||||
ifinfo->state = IFS_DOWN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,346 +0,0 @@
|
|||
/* $NetBSD: rtsol.c,v 1.16 2014/03/18 00:16:49 christos Exp $ */
|
||||
/* $KAME: rtsol.c,v 1.15 2002/05/31 10:10:03 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* 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/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include "rtsold.h"
|
||||
|
||||
#define ALLROUTER "ff02::2"
|
||||
|
||||
static struct msghdr rcvmhdr;
|
||||
static struct msghdr sndmhdr;
|
||||
static struct iovec rcviov[2];
|
||||
static struct iovec sndiov[2];
|
||||
static struct sockaddr_in6 from;
|
||||
|
||||
int rssock;
|
||||
|
||||
static struct sockaddr_in6 sin6_allrouters = {
|
||||
.sin6_len = sizeof(sin6_allrouters),
|
||||
.sin6_family = AF_INET6
|
||||
};
|
||||
|
||||
int
|
||||
sockopen(void)
|
||||
{
|
||||
static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL;
|
||||
size_t rcvcmsglen, sndcmsglen;
|
||||
int on;
|
||||
static u_char answer[1500];
|
||||
struct icmp6_filter filt;
|
||||
|
||||
sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
|
||||
CMSG_SPACE(sizeof(int));
|
||||
if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"malloc for receive msghdr failed");
|
||||
return -1;
|
||||
}
|
||||
if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"malloc for send msghdr failed");
|
||||
return -1;
|
||||
}
|
||||
memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6));
|
||||
sin6_allrouters.sin6_family = AF_INET6;
|
||||
sin6_allrouters.sin6_len = sizeof(sin6_allrouters);
|
||||
if (inet_pton(AF_INET6, ALLROUTER,
|
||||
&sin6_allrouters.sin6_addr.s6_addr) != 1) {
|
||||
warnmsg(LOG_ERR, __func__, "inet_pton failed for %s",
|
||||
ALLROUTER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* specify to tell receiving interface */
|
||||
on = 1;
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
|
||||
sizeof(on)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#else /* old adv. API */
|
||||
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
|
||||
sizeof(on)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "IPV6_PKTINFO: %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
on = 1;
|
||||
/* specify to tell value of hoplimit field of received IP6 hdr */
|
||||
#ifdef IPV6_RECVHOPLIMIT
|
||||
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
|
||||
sizeof(on)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#else /* old adv. API */
|
||||
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
|
||||
sizeof(on)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "IPV6_HOPLIMIT: %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* specfiy to accept only router advertisements on the socket */
|
||||
ICMP6_FILTER_SETBLOCKALL(&filt);
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
|
||||
if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
|
||||
sizeof(filt)) == -1) {
|
||||
warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialize msghdr for receiving packets */
|
||||
rcviov[0].iov_base = answer;
|
||||
rcviov[0].iov_len = sizeof(answer);
|
||||
rcvmhdr.msg_name = &from;
|
||||
rcvmhdr.msg_namelen = sizeof(from);
|
||||
rcvmhdr.msg_iov = rcviov;
|
||||
rcvmhdr.msg_iovlen = 1;
|
||||
rcvmhdr.msg_control = rcvcmsgbuf;
|
||||
rcvmhdr.msg_controllen = (socklen_t)rcvcmsglen;
|
||||
|
||||
/* initialize msghdr for sending packets */
|
||||
sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
sndmhdr.msg_iov = sndiov;
|
||||
sndmhdr.msg_iovlen = 1;
|
||||
sndmhdr.msg_control = sndcmsgbuf;
|
||||
sndmhdr.msg_controllen = (socklen_t)sndcmsglen;
|
||||
|
||||
return rssock;
|
||||
}
|
||||
|
||||
void
|
||||
sendpacket(struct ifinfo *ifinfo)
|
||||
{
|
||||
struct in6_pktinfo *pi;
|
||||
struct cmsghdr *cm;
|
||||
int hoplimit = 255;
|
||||
ssize_t i;
|
||||
struct sockaddr_in6 dst;
|
||||
|
||||
dst = sin6_allrouters;
|
||||
dst.sin6_scope_id = ifinfo->linkid;
|
||||
|
||||
sndmhdr.msg_name = &dst;
|
||||
sndmhdr.msg_iov[0].iov_base = ifinfo->rs_data;
|
||||
sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen;
|
||||
|
||||
cm = CMSG_FIRSTHDR(&sndmhdr);
|
||||
/* specify the outgoing interface */
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_PKTINFO;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
|
||||
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
|
||||
pi->ipi6_ifindex = ifinfo->sdl->sdl_index;
|
||||
|
||||
/* specify the hop limit of the packet */
|
||||
cm = CMSG_NXTHDR(&sndmhdr, cm);
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_HOPLIMIT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
|
||||
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"send RS on %s, whose state is %d",
|
||||
ifinfo->ifname, ifinfo->state);
|
||||
|
||||
i = sendmsg(rssock, &sndmhdr, 0);
|
||||
|
||||
if (i < 0 || (size_t)i != ifinfo->rs_datalen) {
|
||||
/*
|
||||
* ENETDOWN is not so serious, especially when using several
|
||||
* network cards on a mobile node. We ignore it.
|
||||
*/
|
||||
if (errno != ENETDOWN || dflag > 0)
|
||||
warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
|
||||
ifinfo->ifname, strerror(errno));
|
||||
}
|
||||
|
||||
/* update counter */
|
||||
ifinfo->probes++;
|
||||
}
|
||||
|
||||
void
|
||||
rtsol_input(int s)
|
||||
{
|
||||
char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
|
||||
int *hlimp = NULL;
|
||||
ssize_t i;
|
||||
size_t ifindex = 0;
|
||||
struct in6_pktinfo *pi = NULL;
|
||||
struct ifinfo *ifi = NULL;
|
||||
struct icmp6_hdr *icp;
|
||||
struct cmsghdr *cm;
|
||||
|
||||
/* get message */
|
||||
if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/* extract optional information via Advanced API */
|
||||
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); cm;
|
||||
cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
|
||||
if (cm->cmsg_level == IPPROTO_IPV6 &&
|
||||
cm->cmsg_type == IPV6_PKTINFO &&
|
||||
cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
|
||||
pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
|
||||
ifindex = pi->ipi6_ifindex;
|
||||
}
|
||||
if (cm->cmsg_level == IPPROTO_IPV6 &&
|
||||
cm->cmsg_type == IPV6_HOPLIMIT &&
|
||||
cm->cmsg_len == CMSG_LEN(sizeof(int)))
|
||||
hlimp = (int *)CMSG_DATA(cm);
|
||||
}
|
||||
|
||||
if (ifindex == 0) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to get receiving interface");
|
||||
return;
|
||||
}
|
||||
if (hlimp == NULL) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to get receiving hop limit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (i < (ssize_t)sizeof(struct nd_router_advert)) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"packet size(%zd) is too short", i);
|
||||
return;
|
||||
}
|
||||
|
||||
icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
|
||||
|
||||
if (icp->icmp6_type != ND_ROUTER_ADVERT) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"invalid icmp type(%d) from %s on %s", icp->icmp6_type,
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
|
||||
INET6_ADDRSTRLEN),
|
||||
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
|
||||
return;
|
||||
}
|
||||
|
||||
if (icp->icmp6_code != 0) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"invalid icmp code(%d) from %s on %s", icp->icmp6_code,
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
|
||||
INET6_ADDRSTRLEN),
|
||||
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
|
||||
return;
|
||||
}
|
||||
|
||||
if (*hlimp != 255) {
|
||||
warnmsg(LOG_NOTICE, __func__,
|
||||
"invalid RA with hop limit(%d) from %s on %s",
|
||||
*hlimp,
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
|
||||
INET6_ADDRSTRLEN),
|
||||
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
|
||||
warnmsg(LOG_NOTICE, __func__,
|
||||
"invalid RA with non link-local source from %s on %s",
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
|
||||
INET6_ADDRSTRLEN),
|
||||
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
|
||||
return;
|
||||
}
|
||||
|
||||
/* xxx: more validation? */
|
||||
|
||||
if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) {
|
||||
warnmsg(LOG_NOTICE, __func__,
|
||||
"received RA from %s on an unexpected IF(%s)",
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
|
||||
INET6_ADDRSTRLEN),
|
||||
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
|
||||
return;
|
||||
}
|
||||
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"received RA from %s on %s, state is %d",
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN),
|
||||
ifi->ifname, ifi->state);
|
||||
|
||||
ifi->racnt++;
|
||||
|
||||
switch (ifi->state) {
|
||||
case IFS_IDLE: /* should be ignored */
|
||||
case IFS_DELAY: /* right? */
|
||||
break;
|
||||
case IFS_PROBE:
|
||||
ifi->state = IFS_IDLE;
|
||||
ifi->probes = 0;
|
||||
rtsol_timer_update(ifi);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: rtsold.8,v 1.33 2013/05/26 17:25:53 wiz Exp $
|
||||
.\" $NetBSD: rtsold.8,v 1.34 2014/09/11 13:10:04 roy Exp $
|
||||
.\" $KAME: rtsold.8,v 1.17 2001/07/09 22:30:37 itojun Exp $
|
||||
.\"
|
||||
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
|
@ -28,7 +28,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd May 24, 2013
|
||||
.Dd September 9, 2014
|
||||
.Dt RTSOLD 8
|
||||
.Os
|
||||
.\"
|
||||
|
@ -36,184 +36,9 @@
|
|||
.Nm rtsold
|
||||
.Nd router solicitation daemon
|
||||
.\"
|
||||
.Sh SYNOPSIS
|
||||
.Nm rtsold
|
||||
.Op Fl 1Ddfm
|
||||
.Ar interface ...
|
||||
.Nm rtsold
|
||||
.Op Fl 1Ddfm
|
||||
.Fl a
|
||||
.Nm rtsol
|
||||
.Op Fl Dd
|
||||
.Ar interface ...
|
||||
.Nm rtsol
|
||||
.Op Fl Dd
|
||||
.Fl a
|
||||
.\"
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the daemon program to send ICMPv6 Router Solicitation messages
|
||||
on the specified interfaces.
|
||||
If a node (re)attaches to a link,
|
||||
.Nm
|
||||
sends some Router Solicitations on the link destined to the link-local scope
|
||||
all-routers multicast address to discover new routers
|
||||
and to get non link-local addresses.
|
||||
.Pp
|
||||
.Nm
|
||||
should be used on IPv6 hosts
|
||||
.Pq non-router nodes
|
||||
only.
|
||||
.Pp
|
||||
If you invoke the program as
|
||||
.Nm rtsol ,
|
||||
it will transmit probes from the specified
|
||||
.Ar interface ,
|
||||
without becoming a daemon.
|
||||
In other words,
|
||||
and
|
||||
.Nm rtsol
|
||||
behaves as
|
||||
.Dq rtsold -f1 interface ... .
|
||||
.Pp
|
||||
Specifically,
|
||||
.Nm
|
||||
sends at most 3 Router Solicitations on an interface
|
||||
after one of the following events:
|
||||
.Bl -bullet
|
||||
.It
|
||||
Just after invocation of the
|
||||
.Nm
|
||||
daemon.
|
||||
.It
|
||||
The interface is up after a temporary interface failure.
|
||||
.Nm
|
||||
detects such failures by periodically probing to see if the status
|
||||
of the interface is active or not.
|
||||
Note that some network cards and drivers do not allow the extraction
|
||||
of link state.
|
||||
In such cases,
|
||||
.Nm
|
||||
cannot detect the change of the interface status.
|
||||
.It
|
||||
Every 60 seconds if the
|
||||
.Fl m
|
||||
option is specified and the
|
||||
.Nm
|
||||
daemon cannot get the interface status.
|
||||
This feature does not conform to the IPv6 neighbor discovery
|
||||
specification, but is provided for mobile stations.
|
||||
The default interval for router advertisements,
|
||||
which is approximately 10 minutes,
|
||||
is slightly long for mobile stations.
|
||||
This feature is provided
|
||||
for such stations so that they can find new routers as soon as possible
|
||||
when they attach to another link.
|
||||
.El
|
||||
.Pp
|
||||
Once
|
||||
.Nm
|
||||
has sent a Router Solicitation, and has received a valid Router Advertisement,
|
||||
it refrains from sending additional solicitations on that interface, until
|
||||
the next time one of the above events occurs.
|
||||
.Pp
|
||||
When sending a Router Solicitation on an interface,
|
||||
.Nm
|
||||
includes a Source Link-layer address option if the interface
|
||||
has a link-layer address.
|
||||
.Pp
|
||||
Upon receipt of signal
|
||||
.Dv SIGUSR1 ,
|
||||
.Nm
|
||||
will dump the current internal state into
|
||||
.Pa /var/run/rtsold.dump .
|
||||
Also note that
|
||||
.Nm
|
||||
will not be able to update the kernel routing tables unless
|
||||
.Xr sysctl 8
|
||||
reports that
|
||||
net.inet6.ip6.accept_rtadv=1.
|
||||
.\"
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl 1
|
||||
Perform only one probe.
|
||||
Transmit Router Solicitation packets until at least one valid Router
|
||||
Advertisement packet has arrived on each
|
||||
.Ar interface ,
|
||||
then exit.
|
||||
.It Fl a
|
||||
Autoprobe outgoing interfaces.
|
||||
.Nm
|
||||
will try to find a non-loopback, non-point-to-point, IPv6-capable interfaces,
|
||||
and send router solicitation messages on all of them.
|
||||
.It Fl D
|
||||
Enable more debugging (than that offered by the
|
||||
.Fl d
|
||||
option) including the printing of internal timer information.
|
||||
.It Fl d
|
||||
Enable debugging.
|
||||
.It Fl f
|
||||
This option prevents
|
||||
.Nm
|
||||
from becoming a daemon (foreground mode).
|
||||
Warning messages are generated to standard error
|
||||
instead of
|
||||
.Xr syslog 3 .
|
||||
.It Fl m
|
||||
Enable mobility support.
|
||||
If this option is specified,
|
||||
.Nm
|
||||
sends probing packets to default routers that have advertised Router
|
||||
Advertisements
|
||||
when the node (re)attaches to an interface.
|
||||
Moreover, if the option is specified,
|
||||
.Nm
|
||||
periodically sends Router Solicitation on an interface that does not support
|
||||
the
|
||||
.Dv SIOCGIFMEDIA
|
||||
ioctl.
|
||||
.El
|
||||
.\"
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std rtsold
|
||||
.\"
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/run/rtsold.dumpXX -compact
|
||||
.It Pa /var/run/rtsold.pid
|
||||
The PID of the currently running
|
||||
.Nm rtsold .
|
||||
.It Pa /var/run/rtsold.dump
|
||||
Internal state dump file.
|
||||
.El
|
||||
.\"
|
||||
.Sh SEE ALSO
|
||||
.Xr rtadvd 8 ,
|
||||
.Xr sysctl 8
|
||||
.\"
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command is based on the
|
||||
.Nm rtsol
|
||||
command, which first appeared in the WIDE/KAME IPv6 protocol stack kit.
|
||||
.Nm rtsol
|
||||
is now integrated into
|
||||
.Nm .
|
||||
.\"
|
||||
.Sh BUGS
|
||||
In some operating systems, when a PCMCIA network card is removed
|
||||
and reinserted, the corresponding interface index is changed.
|
||||
However,
|
||||
.Nm
|
||||
assumes such changes will not occur, and always uses the index that
|
||||
it got at invocation.
|
||||
As a result,
|
||||
.Nm
|
||||
may not work if you reinsert a network card.
|
||||
In such a case,
|
||||
.Nm
|
||||
should be killed and restarted.
|
||||
.Pp
|
||||
You may see kernel error messages if you try to autoconfigure a host with
|
||||
multiple interfaces.
|
||||
have been removed from NetBSD as their functionality is now included in
|
||||
.Xr dhcpcd 8 .
|
||||
|
|
|
@ -1,749 +0,0 @@
|
|||
/* $NetBSD: rtsold.c,v 1.42 2014/03/25 21:07:59 joerg Exp $ */
|
||||
/* $KAME: rtsold.c,v 1.77 2004/01/03 01:35:13 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* 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/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <util.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "rtsold.h"
|
||||
|
||||
struct ifinfo *iflist;
|
||||
struct timeval tm_max = {0x7fffffff, 0x7fffffff};
|
||||
static int log_upto = 999;
|
||||
static int fflag = 0;
|
||||
static int isdaemon = 0;
|
||||
|
||||
int aflag = 0;
|
||||
int dflag = 0;
|
||||
|
||||
/* protocol constatns */
|
||||
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
|
||||
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
|
||||
#define MAX_RTR_SOLICITATIONS 3 /* times */
|
||||
|
||||
/*
|
||||
* implementation dependent constants in seconds
|
||||
* XXX: should be configurable
|
||||
*/
|
||||
#define PROBE_INTERVAL 60
|
||||
|
||||
/* static variables and functions */
|
||||
static int mobile_node = 0;
|
||||
#ifndef SMALL
|
||||
static int do_dump;
|
||||
static const char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static int ifreconfig(char *);
|
||||
#endif
|
||||
static int make_packet(struct ifinfo *);
|
||||
static struct timeval *rtsol_check_timer(void);
|
||||
|
||||
#ifndef SMALL
|
||||
static void rtsold_set_dump_file(int);
|
||||
#endif
|
||||
__dead static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int s, ch, once = 0;
|
||||
struct timeval *timeout;
|
||||
const char *ident;
|
||||
const char *opts;
|
||||
struct pollfd set[2];
|
||||
#ifdef USE_RTSOCK
|
||||
int rtsock;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialization
|
||||
*/
|
||||
ident = getprogname();
|
||||
isdaemon = ident[strlen(ident) - 1] == 'd';
|
||||
|
||||
/* get option */
|
||||
if (!isdaemon) {
|
||||
fflag = 1;
|
||||
once = 1;
|
||||
opts = "adD";
|
||||
} else
|
||||
opts = "adDfm1";
|
||||
|
||||
while ((ch = getopt(argc, argv, opts)) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'D':
|
||||
dflag = 2;
|
||||
break;
|
||||
case 'f':
|
||||
fflag = 1;
|
||||
break;
|
||||
case 'm':
|
||||
mobile_node = 1;
|
||||
break;
|
||||
case '1':
|
||||
once = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if ((!aflag && argc == 0) || (aflag && argc != 0)) {
|
||||
usage();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* set log level */
|
||||
if (dflag == 0)
|
||||
log_upto = LOG_NOTICE;
|
||||
if (!fflag) {
|
||||
openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
|
||||
if (log_upto >= 0)
|
||||
setlogmask(LOG_UPTO(log_upto));
|
||||
}
|
||||
|
||||
/* warn if accept_rtadv is down */
|
||||
if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
|
||||
warnx("kernel is configured not to accept RAs");
|
||||
/* warn if forwarding is up */
|
||||
if (getinet6sysctl(IPV6CTL_FORWARDING))
|
||||
warnx("kernel is configured as a router, not a host");
|
||||
|
||||
#ifndef SMALL
|
||||
/* initialization to dump internal status to a file */
|
||||
signal(SIGUSR1, rtsold_set_dump_file);
|
||||
#endif
|
||||
|
||||
if (!fflag)
|
||||
daemon(0, 0); /* act as a daemon */
|
||||
|
||||
/*
|
||||
* Open a socket for sending RS and receiving RA.
|
||||
* This should be done before calling ifinit(), since the function
|
||||
* uses the socket.
|
||||
*/
|
||||
if ((s = sockopen()) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "failed to open a socket");
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
set[0].fd = s;
|
||||
set[0].events = POLLIN;
|
||||
|
||||
set[1].fd = -1;
|
||||
|
||||
#ifdef USE_RTSOCK
|
||||
if ((rtsock = rtsock_open()) < 0) {
|
||||
warnmsg(LOG_ERR, __func__, "failed to open a socket");
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
set[1].fd = rtsock;
|
||||
set[1].events = POLLIN;
|
||||
#endif
|
||||
|
||||
/* configuration per interface */
|
||||
if (ifinit()) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to initilizatoin interfaces");
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
if (aflag)
|
||||
argv = autoifprobe();
|
||||
while (argv && *argv) {
|
||||
if (ifconfig(*argv)) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to initialize %s", *argv);
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
|
||||
/* setup for probing default routers */
|
||||
if (probe_init()) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to setup for probing routers");
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* dump the current pid */
|
||||
if (!once) {
|
||||
if (pidfile(NULL) < 0) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to open a pid log file: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) { /* main loop */
|
||||
int e;
|
||||
|
||||
#ifndef SMALL
|
||||
if (do_dump) { /* SIGUSR1 */
|
||||
do_dump = 0;
|
||||
rtsold_dump_file(dumpfilename);
|
||||
}
|
||||
#endif
|
||||
|
||||
timeout = rtsol_check_timer();
|
||||
|
||||
if (once) {
|
||||
struct ifinfo *ifi;
|
||||
|
||||
/* if we have no timeout, we are done (or failed) */
|
||||
if (timeout == NULL)
|
||||
break;
|
||||
|
||||
/* if all interfaces have got RA packet, we are done */
|
||||
for (ifi = iflist; ifi; ifi = ifi->next) {
|
||||
if (ifi->state != IFS_DOWN && ifi->racnt == 0)
|
||||
break;
|
||||
}
|
||||
if (ifi == NULL)
|
||||
break;
|
||||
}
|
||||
e = poll(set, 2, (int)(timeout ?
|
||||
(timeout->tv_sec * 1000 + timeout->tv_usec / 1000) :
|
||||
INFTIM));
|
||||
if (e < 1) {
|
||||
if (e < 0 && errno != EINTR) {
|
||||
warnmsg(LOG_ERR, __func__, "poll: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* packet reception */
|
||||
#ifdef USE_RTSOCK
|
||||
if (set[1].revents & POLLIN)
|
||||
rtsock_input(rtsock);
|
||||
#endif
|
||||
if (set[0].revents & POLLIN)
|
||||
rtsol_input(s);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ifconfig(char *ifname)
|
||||
{
|
||||
struct ifinfo *ifinfo;
|
||||
struct sockaddr_dl *sdl;
|
||||
int flags;
|
||||
|
||||
if ((sdl = if_nametosdl(ifname)) == NULL) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"failed to get link layer information for %s", ifname);
|
||||
return -1;
|
||||
}
|
||||
if (find_ifinfo(sdl->sdl_index)) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"interface %s was already configured", ifname);
|
||||
free(sdl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
|
||||
warnmsg(LOG_ERR, __func__, "memory allocation failed");
|
||||
free(sdl);
|
||||
return -1;
|
||||
}
|
||||
memset(ifinfo, 0, sizeof(*ifinfo));
|
||||
ifinfo->sdl = sdl;
|
||||
|
||||
strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
|
||||
|
||||
/* construct a router solicitation message */
|
||||
if (make_packet(ifinfo))
|
||||
goto bad;
|
||||
|
||||
/* set link ID of this interface. */
|
||||
#ifdef HAVE_SCOPELIB
|
||||
if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid))
|
||||
goto bad;
|
||||
#else
|
||||
/* XXX: assume interface IDs as link IDs */
|
||||
ifinfo->linkid = ifinfo->sdl->sdl_index;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* check if the interface is available.
|
||||
* also check if SIOCGIFMEDIA ioctl is OK on the interface.
|
||||
*/
|
||||
ifinfo->mediareqok = 1;
|
||||
ifinfo->active = interface_status(ifinfo);
|
||||
if (!ifinfo->mediareqok) {
|
||||
/*
|
||||
* probe routers periodically even if the link status
|
||||
* does not change.
|
||||
*/
|
||||
ifinfo->probeinterval = PROBE_INTERVAL;
|
||||
}
|
||||
|
||||
/* activate interface: interface_up returns 0 on success */
|
||||
flags = interface_up(ifinfo->ifname);
|
||||
if (flags == 0)
|
||||
ifinfo->state = IFS_DELAY;
|
||||
else if (flags == IFS_TENTATIVE)
|
||||
ifinfo->state = IFS_TENTATIVE;
|
||||
else
|
||||
ifinfo->state = IFS_DOWN;
|
||||
|
||||
rtsol_timer_update(ifinfo);
|
||||
|
||||
/* link into chain */
|
||||
if (iflist)
|
||||
ifinfo->next = iflist;
|
||||
iflist = ifinfo;
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
free(ifinfo->sdl);
|
||||
free(ifinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
iflist_init(void)
|
||||
{
|
||||
struct ifinfo *ifi, *next;
|
||||
|
||||
for (ifi = iflist; ifi; ifi = next) {
|
||||
next = ifi->next;
|
||||
if (ifi->sdl)
|
||||
free(ifi->sdl);
|
||||
if (ifi->rs_data)
|
||||
free(ifi->rs_data);
|
||||
free(ifi);
|
||||
iflist = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
ifreconfig(char *ifname)
|
||||
{
|
||||
struct ifinfo *ifi, *prev;
|
||||
int rv;
|
||||
|
||||
prev = NULL;
|
||||
for (ifi = iflist; ifi; ifi = ifi->next) {
|
||||
if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
|
||||
break;
|
||||
prev = ifi;
|
||||
}
|
||||
prev->next = ifi->next;
|
||||
|
||||
rv = ifconfig(ifname);
|
||||
|
||||
/* reclaim it after ifconfig() in case ifname is pointer inside ifi */
|
||||
if (ifi->rs_data)
|
||||
free(ifi->rs_data);
|
||||
free(ifi->sdl);
|
||||
free(ifi);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ifinfo *
|
||||
find_ifinfo(size_t ifindex)
|
||||
{
|
||||
struct ifinfo *ifi;
|
||||
|
||||
for (ifi = iflist; ifi; ifi = ifi->next)
|
||||
if (ifi->sdl->sdl_index == ifindex)
|
||||
return ifi;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
make_packet(struct ifinfo *ifinfo)
|
||||
{
|
||||
size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen;
|
||||
struct nd_router_solicit *rs;
|
||||
u_char *buf;
|
||||
|
||||
if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
|
||||
warnmsg(LOG_INFO, __func__,
|
||||
"link-layer address option has null length"
|
||||
" on %s. Treat as not included.", ifinfo->ifname);
|
||||
}
|
||||
packlen += lladdroptlen;
|
||||
ifinfo->rs_datalen = packlen;
|
||||
|
||||
/* allocate buffer */
|
||||
if ((buf = malloc(packlen)) == NULL) {
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"memory allocation failed for %s", ifinfo->ifname);
|
||||
return -1;
|
||||
}
|
||||
ifinfo->rs_data = buf;
|
||||
|
||||
/* fill in the message */
|
||||
rs = (struct nd_router_solicit *)buf;
|
||||
rs->nd_rs_type = ND_ROUTER_SOLICIT;
|
||||
rs->nd_rs_code = 0;
|
||||
rs->nd_rs_cksum = 0;
|
||||
rs->nd_rs_reserved = 0;
|
||||
buf += sizeof(*rs);
|
||||
|
||||
/* fill in source link-layer address option */
|
||||
if (lladdroptlen)
|
||||
lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct timeval *
|
||||
rtsol_check_timer(void)
|
||||
{
|
||||
static struct timeval returnval;
|
||||
struct timeval now, rtsol_timer;
|
||||
struct ifinfo *ifinfo;
|
||||
int flags;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
rtsol_timer = tm_max;
|
||||
|
||||
for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
|
||||
if (timercmp(&ifinfo->expire, &now, <=)) {
|
||||
if (dflag > 1)
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"timer expiration on %s, "
|
||||
"state = %d", ifinfo->ifname,
|
||||
ifinfo->state);
|
||||
|
||||
switch (ifinfo->state) {
|
||||
case IFS_DOWN:
|
||||
case IFS_TENTATIVE:
|
||||
/* interface_up returns 0 on success */
|
||||
flags = interface_up(ifinfo->ifname);
|
||||
if (flags == 0)
|
||||
ifinfo->state = IFS_DELAY;
|
||||
else if (flags == IFS_TENTATIVE)
|
||||
ifinfo->state = IFS_TENTATIVE;
|
||||
else
|
||||
ifinfo->state = IFS_DOWN;
|
||||
break;
|
||||
case IFS_IDLE:
|
||||
{
|
||||
int oldstatus = ifinfo->active;
|
||||
int probe = 0;
|
||||
|
||||
ifinfo->active = interface_status(ifinfo);
|
||||
|
||||
if (oldstatus != ifinfo->active) {
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"%s status is changed"
|
||||
" from %d to %d",
|
||||
ifinfo->ifname,
|
||||
oldstatus, ifinfo->active);
|
||||
probe = 1;
|
||||
ifinfo->state = IFS_DELAY;
|
||||
} else if (ifinfo->probeinterval &&
|
||||
(ifinfo->probetimer -= (int)
|
||||
ifinfo->timer.tv_sec) <= 0) {
|
||||
/* probe timer expired */
|
||||
ifinfo->probetimer =
|
||||
ifinfo->probeinterval;
|
||||
probe = 1;
|
||||
ifinfo->state = IFS_PROBE;
|
||||
}
|
||||
|
||||
if (probe && mobile_node)
|
||||
defrouter_probe(ifinfo);
|
||||
break;
|
||||
}
|
||||
case IFS_DELAY:
|
||||
ifinfo->state = IFS_PROBE;
|
||||
sendpacket(ifinfo);
|
||||
break;
|
||||
case IFS_PROBE:
|
||||
if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
|
||||
sendpacket(ifinfo);
|
||||
else {
|
||||
warnmsg(LOG_INFO, __func__,
|
||||
"No answer after sending %d RSs",
|
||||
ifinfo->probes);
|
||||
ifinfo->probes = 0;
|
||||
ifinfo->state = IFS_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
rtsol_timer_update(ifinfo);
|
||||
}
|
||||
|
||||
if (timercmp(&ifinfo->expire, &rtsol_timer, <))
|
||||
rtsol_timer = ifinfo->expire;
|
||||
}
|
||||
|
||||
if (timercmp(&rtsol_timer, &tm_max, ==)) {
|
||||
warnmsg(LOG_DEBUG, __func__, "there is no timer");
|
||||
return NULL;
|
||||
} else if (timercmp(&rtsol_timer, &now, <))
|
||||
/* this may occur when the interval is too small */
|
||||
returnval.tv_sec = returnval.tv_usec = 0;
|
||||
else
|
||||
timersub(&rtsol_timer, &now, &returnval);
|
||||
|
||||
if (dflag > 1)
|
||||
warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld",
|
||||
(long)returnval.tv_sec, (long)returnval.tv_usec);
|
||||
|
||||
return &returnval;
|
||||
}
|
||||
|
||||
void
|
||||
rtsol_timer_update(struct ifinfo *ifinfo)
|
||||
{
|
||||
#define MILLION 1000000
|
||||
#define DADRETRY 10 /* XXX: adhoc */
|
||||
uint32_t interval;
|
||||
struct timeval now;
|
||||
|
||||
bzero(&ifinfo->timer, sizeof(ifinfo->timer));
|
||||
|
||||
switch (ifinfo->state) {
|
||||
case IFS_DOWN:
|
||||
case IFS_TENTATIVE:
|
||||
if (++ifinfo->dadcount > DADRETRY) {
|
||||
ifinfo->dadcount = 0;
|
||||
ifinfo->timer.tv_sec = PROBE_INTERVAL;
|
||||
} else
|
||||
ifinfo->timer.tv_sec = 1;
|
||||
break;
|
||||
case IFS_IDLE:
|
||||
if (mobile_node) {
|
||||
/* XXX should be configurable */
|
||||
ifinfo->timer.tv_sec = 3;
|
||||
} else
|
||||
ifinfo->timer = tm_max; /* stop timer(valid?) */
|
||||
break;
|
||||
case IFS_DELAY:
|
||||
interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
|
||||
ifinfo->timer.tv_sec = interval / MILLION;
|
||||
ifinfo->timer.tv_usec = (suseconds_t)(interval % MILLION);
|
||||
break;
|
||||
case IFS_PROBE:
|
||||
if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
|
||||
ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
|
||||
else {
|
||||
/*
|
||||
* After sending MAX_RTR_SOLICITATIONS solicitations,
|
||||
* we're just waiting for possible replies; there
|
||||
* will be no more solicatation. Thus, we change
|
||||
* the timer value to MAX_RTR_SOLICITATION_DELAY based
|
||||
* on RFC 2461, Section 6.3.7.
|
||||
*/
|
||||
ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warnmsg(LOG_ERR, __func__,
|
||||
"illegal interface state(%d) on %s",
|
||||
ifinfo->state, ifinfo->ifname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* reset the timer */
|
||||
if (timercmp(&ifinfo->timer, &tm_max, ==)) {
|
||||
ifinfo->expire = tm_max;
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"stop timer for %s", ifinfo->ifname);
|
||||
} else {
|
||||
gettimeofday(&now, NULL);
|
||||
timeradd(&now, &ifinfo->timer, &ifinfo->expire);
|
||||
|
||||
if (dflag > 1)
|
||||
warnmsg(LOG_DEBUG, __func__,
|
||||
"set timer for %s to %d:%d", ifinfo->ifname,
|
||||
(int)ifinfo->timer.tv_sec,
|
||||
(int)ifinfo->timer.tv_usec);
|
||||
}
|
||||
|
||||
#undef MILLION
|
||||
}
|
||||
|
||||
/* timer related utility functions */
|
||||
#define MILLION 1000000
|
||||
|
||||
#ifndef SMALL
|
||||
static void
|
||||
rtsold_set_dump_file(int sig)
|
||||
{
|
||||
do_dump = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
const char *opts = isdaemon ? "-1Ddfm" : "Dd";
|
||||
fprintf(stderr, "Usage: %s [%s] interface ...\n", getprogname(), opts);
|
||||
fprintf(stderr, "\t%s [%s] -a\n", getprogname(), opts);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
warnmsg(int priority, const char *func, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msg);
|
||||
if (fflag) {
|
||||
if (priority <= log_upto)
|
||||
vwarnx(msg, ap);
|
||||
} else {
|
||||
char *buf;
|
||||
evasprintf(&buf, msg, ap);
|
||||
syslog(priority, "<%s> %s", func, buf);
|
||||
free(buf);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* return a list of interfaces which is suitable to sending an RS.
|
||||
*/
|
||||
char **
|
||||
autoifprobe(void)
|
||||
{
|
||||
static char **argv = NULL;
|
||||
static size_t n = 0;
|
||||
char **a;
|
||||
size_t i;
|
||||
int found;
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
|
||||
/* initialize */
|
||||
while (n--)
|
||||
free(argv[n]);
|
||||
if (argv) {
|
||||
free(argv);
|
||||
argv = NULL;
|
||||
}
|
||||
n = 0;
|
||||
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return NULL;
|
||||
|
||||
/* find an ethernet */
|
||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
||||
if ((ifa->ifa_flags & IFF_UP) == 0)
|
||||
continue;
|
||||
if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
|
||||
continue;
|
||||
if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
|
||||
continue;
|
||||
if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
found = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strcmp(argv[i], ifa->ifa_name) == 0) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
/* if we find multiple candidates, just warn. */
|
||||
if (n != 0 && dflag > 1)
|
||||
warnx("multiple interfaces found");
|
||||
|
||||
a = realloc(argv, (n + 1) * sizeof(char **));
|
||||
if (a == NULL)
|
||||
err(EXIT_FAILURE, "realloc");
|
||||
argv = a;
|
||||
argv[n] = strdup(ifa->ifa_name);
|
||||
if (!argv[n])
|
||||
err(EXIT_FAILURE, "strdup");
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n) {
|
||||
a = realloc(argv, (n + 1) * sizeof(char **));
|
||||
if (a == NULL)
|
||||
err(EXIT_FAILURE, "realloc");
|
||||
argv = a;
|
||||
argv[n] = NULL;
|
||||
|
||||
if (dflag > 0) {
|
||||
for (i = 0; i < n; i++)
|
||||
warnx("probing %s", argv[i]);
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return argv;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/* $NetBSD: rtsold.h,v 1.11 2014/03/18 00:16:49 christos Exp $ */
|
||||
/* $KAME: rtsold.h,v 1.14 2002/05/31 10:10:03 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct ifinfo {
|
||||
struct ifinfo *next; /* pointer to the next interface */
|
||||
|
||||
struct sockaddr_dl *sdl; /* link-layer address */
|
||||
char ifname[IF_NAMESIZE]; /* interface name */
|
||||
u_int32_t linkid; /* link ID of this interface */
|
||||
int active; /* interface status */
|
||||
int probeinterval; /* interval of probe timer(if necessary) */
|
||||
int probetimer; /* rest of probe timer */
|
||||
int mediareqok; /* whether the IF supports SIOCGIFMEDIA */
|
||||
int state;
|
||||
int probes;
|
||||
int dadcount;
|
||||
struct timeval timer;
|
||||
struct timeval expire;
|
||||
int errors; /* # of errors we've got - detect wedge */
|
||||
|
||||
int racnt; /* total # of valid RAs it have got */
|
||||
|
||||
size_t rs_datalen;
|
||||
u_char *rs_data;
|
||||
};
|
||||
|
||||
/* per interface status */
|
||||
#define IFS_IDLE 0
|
||||
#define IFS_DELAY 1
|
||||
#define IFS_PROBE 2
|
||||
#define IFS_DOWN 3
|
||||
#define IFS_TENTATIVE 4
|
||||
|
||||
/* rtsold.c */
|
||||
extern struct timeval tm_max;
|
||||
extern int dflag;
|
||||
extern int aflag;
|
||||
extern struct ifinfo *iflist;
|
||||
extern int rssock;
|
||||
|
||||
int ifconfig(char *);
|
||||
void iflist_init(void);
|
||||
struct ifinfo *find_ifinfo(size_t);
|
||||
void rtsol_timer_update(struct ifinfo *);
|
||||
void warnmsg(int, const char *, const char *, ...) __printflike(3, 4);
|
||||
char **autoifprobe(void);
|
||||
|
||||
/* if.c */
|
||||
int ifinit(void);
|
||||
int interface_up(char *);
|
||||
int interface_status(struct ifinfo *);
|
||||
size_t lladdropt_length(struct sockaddr_dl *);
|
||||
void lladdropt_fill(struct sockaddr_dl *, struct nd_opt_hdr *);
|
||||
struct sockaddr_dl *if_nametosdl(char *);
|
||||
int getinet6sysctl(int);
|
||||
|
||||
/* rtsol.c */
|
||||
int sockopen(void);
|
||||
void sendpacket(struct ifinfo *);
|
||||
void rtsol_input(int);
|
||||
|
||||
/* probe.c */
|
||||
int probe_init(void);
|
||||
void defrouter_probe(struct ifinfo *);
|
||||
|
||||
/* dump.c */
|
||||
void rtsold_dump_file(const char *);
|
||||
|
||||
/* rtsock.c */
|
||||
int rtsock_open(void);
|
||||
int rtsock_input(int);
|
Loading…
Reference in New Issue