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:
roy 2014-09-11 13:10:03 +00:00
parent e8cd4b633c
commit c6314d6139
20 changed files with 147 additions and 2347 deletions

View File

@ -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

View File

@ -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]

View File

@ -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.

View File

@ -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 [ -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
if checkyesno rtsol; then
# dhcpcd will ensure DAD completes before forking
if checkyesno rtsol && !checkyesno dhcpcd; 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."
warn "rtsol has been removed, " \
"please configure dhcpcd in its place."
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
fi
}

View File

@ -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"

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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);

View File

@ -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>

View File

@ -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 \

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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 .

View File

@ -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;
}

View File

@ -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);