- Improve interface list handling. The rtadvd(8) now supports dynamically-
added/removed interfaces in a more consistent manner and reloading the configuration file. - Implement burst unsolicited RA sending into the internal RA timer framework when AdvSendAdvertisements and/or configuration entries are changed as described in RFC 4861 6.2.4. This fixes issues that make termination of the rtadvd(8) daemon take very long time. An interface now has three internal states, UNCONFIGURED, TRANSITIVE, or CONFIGURED, and the burst unsolicited sending happens in TRANSITIVE. See rtadvd.h for the details. - rtadvd(8) now accepts non-existent interfaces as well in the command line. - Add control socket support and rtadvctl(8) utility to show the RA information in rtadvd(8). Dumping by SIGUSR1 has been removed in favor of it.
This commit is contained in:
parent
dafdd69986
commit
3724189620
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224144
@ -178,6 +178,7 @@ SUBDIR+= ndp
|
|||||||
SUBDIR+= rip6query
|
SUBDIR+= rip6query
|
||||||
SUBDIR+= route6d
|
SUBDIR+= route6d
|
||||||
SUBDIR+= rrenumd
|
SUBDIR+= rrenumd
|
||||||
|
SUBDIR+= rtadvctl
|
||||||
SUBDIR+= rtadvd
|
SUBDIR+= rtadvd
|
||||||
SUBDIR+= rtsold
|
SUBDIR+= rtsold
|
||||||
SUBDIR+= traceroute6
|
SUBDIR+= traceroute6
|
||||||
|
13
usr.sbin/rtadvctl/Makefile
Normal file
13
usr.sbin/rtadvctl/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
#
|
||||||
|
.PATH: ${.CURDIR}/../rtadvd
|
||||||
|
|
||||||
|
PROG= rtadvctl
|
||||||
|
MAN= rtadvctl.8
|
||||||
|
|
||||||
|
SRCS= rtadvctl.c control.c control_client.c if.c timer_subr.c
|
||||||
|
|
||||||
|
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../rtadvd
|
||||||
|
WARNS?= 1
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
103
usr.sbin/rtadvctl/rtadvctl.8
Normal file
103
usr.sbin/rtadvctl/rtadvctl.8
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
.\" Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>.
|
||||||
|
.\" 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.
|
||||||
|
.\"
|
||||||
|
.\" 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.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.Dd July 16, 2011
|
||||||
|
.Dt RTADVCTL 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm rtadvctl
|
||||||
|
.Nd control program for
|
||||||
|
.Xr rtadvd 8 daemon
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl v
|
||||||
|
.Ar subcommand
|
||||||
|
.Op Ar interface ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is a utility that communicates with
|
||||||
|
.Xr rtadvd 8
|
||||||
|
daemon and displays information about Router Advertisement messages being
|
||||||
|
sent on each interface.
|
||||||
|
.Pp
|
||||||
|
This utility provides several options and subcommands.
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.\"
|
||||||
|
.It Fl v
|
||||||
|
Increase verbosity level.
|
||||||
|
When specified once, the
|
||||||
|
.Nm
|
||||||
|
utility shows additional information about prefixes, RDNSS, and DNSSL
|
||||||
|
options.
|
||||||
|
When given twice, it additionally shows information about
|
||||||
|
inactive interfaces and some statistics.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The subcommands are as follows:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.\"
|
||||||
|
.It reload Op interfaces...
|
||||||
|
Specifies to reload the configuration file. If one or more
|
||||||
|
.Ar interface
|
||||||
|
is specified, configuration entries for the interfaces will be reloaded
|
||||||
|
selectively.
|
||||||
|
.It enable interfaces...
|
||||||
|
Specifies to mark the interface as enable and to try to reload the
|
||||||
|
configuration entry.
|
||||||
|
This subcommand is useful for dynamically-added interfaces.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Xr rtadvd 8
|
||||||
|
daemon marks an interface as enable if the interface exists and the
|
||||||
|
configuration file has a valid entry for that when it is invoked.
|
||||||
|
.It disable interfaces...
|
||||||
|
Specifies to mark the interface as disable.
|
||||||
|
.It shutdown
|
||||||
|
Makes the
|
||||||
|
.Xr rtadvd 8
|
||||||
|
daemon shut down.
|
||||||
|
Note that the
|
||||||
|
.Xr rtadvd 8
|
||||||
|
daemon will send several RAs with zero lifetime to invalidate the old
|
||||||
|
information on each interface.
|
||||||
|
It will take at most nine seconds.
|
||||||
|
.It show Op interfaces...
|
||||||
|
Displays information on Router Advertisement messages being sent
|
||||||
|
on each interface.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr rtadvd 8 ,
|
||||||
|
.Xr rtadvd.conf 5
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
command first appeared in
|
||||||
|
.Fx 9.0 .
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm
|
||||||
|
was written by
|
||||||
|
.An "Hiroki Sato" Aq hrs@FreeBSD.org .
|
926
usr.sbin/rtadvctl/rtadvctl.c
Normal file
926
usr.sbin/rtadvctl/rtadvctl.c
Normal file
@ -0,0 +1,926 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#include <net/if_var.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
#include <netinet6/in6_var.h>
|
||||||
|
#include <netinet6/nd6.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
|
#include "rtadvd.h"
|
||||||
|
#include "if.h"
|
||||||
|
#include "timer_subr.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "control.h"
|
||||||
|
#include "control_client.h"
|
||||||
|
|
||||||
|
#define RA_IFSTATUS_INACTIVE 0
|
||||||
|
#define RA_IFSTATUS_RA_RECV 1
|
||||||
|
#define RA_IFSTATUS_RA_SEND 2
|
||||||
|
|
||||||
|
static int vflag = LOG_ERR;
|
||||||
|
|
||||||
|
static void usage(void);
|
||||||
|
|
||||||
|
static int action_propset(char *);
|
||||||
|
static int action_propget(char *, struct ctrl_msg_pl *);
|
||||||
|
static int action_plgeneric(int, char *, char *);
|
||||||
|
|
||||||
|
static int action_enable(int, char **);
|
||||||
|
static int action_disable(int, char **);
|
||||||
|
static int action_reload(int, char **);
|
||||||
|
static int action_echo(int, char **);
|
||||||
|
static int action_version(int, char **);
|
||||||
|
static int action_shutdown(int, char **);
|
||||||
|
|
||||||
|
static int action_show(int, char **);
|
||||||
|
static int action_show_prefix(struct prefix *);
|
||||||
|
static int action_show_rtinfo(struct rtinfo *);
|
||||||
|
static int action_show_rdnss(void *);
|
||||||
|
static int action_show_dnssl(void *);
|
||||||
|
|
||||||
|
static int csock_client_open(struct sockinfo *);
|
||||||
|
static size_t dname_labeldec(char *, size_t, const char *);
|
||||||
|
static void mysyslog(int, const char *, ...);
|
||||||
|
|
||||||
|
static const char *rtpref_str[] = {
|
||||||
|
"medium", /* 00 */
|
||||||
|
"high", /* 01 */
|
||||||
|
"rsv", /* 10 */
|
||||||
|
"low" /* 11 */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dispatch_table {
|
||||||
|
const char *dt_comm;
|
||||||
|
int (*dt_act)(int, char **);
|
||||||
|
} dtable[] = {
|
||||||
|
{ "show", action_show },
|
||||||
|
{ "reload", action_reload },
|
||||||
|
{ "shutdown", action_shutdown },
|
||||||
|
{ "enable", action_enable },
|
||||||
|
{ "disable", action_disable },
|
||||||
|
{ NULL, NULL },
|
||||||
|
{ "echo", action_echo },
|
||||||
|
{ "version", action_version },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static char errmsgbuf[1024];
|
||||||
|
static char *errmsg = NULL;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mysyslog(int priority, const char * restrict fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (vflag >= priority) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
|
||||||
|
if (dtable[i].dt_comm == NULL)
|
||||||
|
break;
|
||||||
|
printf("%s\n", dtable[i].dt_comm);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ch;
|
||||||
|
int (*action)(int, char **) = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "Dv")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'D':
|
||||||
|
vflag = LOG_DEBUG;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
vflag++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc == 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
|
||||||
|
if (dtable[i].dt_comm == NULL ||
|
||||||
|
strcmp(dtable[i].dt_comm, argv[0]) == 0) {
|
||||||
|
action = dtable[i].dt_act;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == NULL)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
error = (dtable[i].dt_act)(--argc, ++argv);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "%s failed", dtable[i].dt_comm);
|
||||||
|
if (errmsg != NULL)
|
||||||
|
fprintf(stderr, ": %s", errmsg);
|
||||||
|
fprintf(stderr, ".\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
csock_client_open(struct sockinfo *s)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
|
||||||
|
if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
|
err(1, "cannot open control socket.");
|
||||||
|
|
||||||
|
memset(&sun, 0, sizeof(sun));
|
||||||
|
sun.sun_family = AF_UNIX;
|
||||||
|
sun.sun_len = sizeof(sun);
|
||||||
|
strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
|
||||||
|
|
||||||
|
if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
|
||||||
|
err(1, "connect: %s", s->si_name);
|
||||||
|
|
||||||
|
mysyslog(LOG_DEBUG,
|
||||||
|
"<%s> connected to %s", __func__, sun.sun_path);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_plgeneric(int action, char *plstr, char *buf)
|
||||||
|
{
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
struct ctrl_msg_pl cp;
|
||||||
|
struct sockinfo *s;
|
||||||
|
char *msg;
|
||||||
|
char *p;
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
s = &ctrlsock;
|
||||||
|
csock_client_open(s);
|
||||||
|
|
||||||
|
cm = (struct ctrl_msg_hdr *)buf;
|
||||||
|
msg = (char *)buf + sizeof(*cm);
|
||||||
|
|
||||||
|
cm->cm_version = CM_VERSION;
|
||||||
|
cm->cm_type = action;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
|
||||||
|
if (plstr != NULL) {
|
||||||
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
p = strchr(plstr, ':');
|
||||||
|
q = strchr(plstr, '=');
|
||||||
|
if (p != NULL && q != NULL && p > q)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (p == NULL) { /* No : */
|
||||||
|
cp.cp_ifname = NULL;
|
||||||
|
cp.cp_key = plstr;
|
||||||
|
} else if (p == plstr) { /* empty */
|
||||||
|
cp.cp_ifname = NULL;
|
||||||
|
cp.cp_key = plstr + 1;
|
||||||
|
} else {
|
||||||
|
*p++ = '\0';
|
||||||
|
cp.cp_ifname = plstr;
|
||||||
|
cp.cp_key = p;
|
||||||
|
}
|
||||||
|
if (q == NULL)
|
||||||
|
cp.cp_val = NULL;
|
||||||
|
else {
|
||||||
|
*q++ = '\0';
|
||||||
|
cp.cp_val = q;
|
||||||
|
}
|
||||||
|
cm->cm_len += cmsg_pl2bin(msg, &cp);
|
||||||
|
|
||||||
|
mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
|
||||||
|
__func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cmsg_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_propget(char *argv, struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
char buf[CM_MSG_MAXLEN];
|
||||||
|
char *msg;
|
||||||
|
|
||||||
|
memset(cp, 0, sizeof(*cp));
|
||||||
|
cm = (struct ctrl_msg_hdr *)buf;
|
||||||
|
msg = (char *)buf + sizeof(*cm);
|
||||||
|
|
||||||
|
error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf);
|
||||||
|
if (error || cm->cm_len <= sizeof(*cm))
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
cmsg_bin2pl(msg, cp);
|
||||||
|
mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d",
|
||||||
|
__func__, cm->cm_type, cm->cm_len);
|
||||||
|
mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
|
||||||
|
__func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_propset(char *argv)
|
||||||
|
{
|
||||||
|
char buf[CM_MSG_MAXLEN];
|
||||||
|
|
||||||
|
return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_disable(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
char argv_disable[IFNAMSIZ + sizeof(":disable=")];
|
||||||
|
int i;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
sprintf(argv_disable, "%s:disable=", argv[i]);
|
||||||
|
action_argv = argv_disable;
|
||||||
|
error += action_propset(action_argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_enable(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
char argv_enable[IFNAMSIZ + sizeof(":enable=")];
|
||||||
|
int i;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
sprintf(argv_enable, "%s:enable=", argv[i]);
|
||||||
|
action_argv = argv_enable;
|
||||||
|
error += action_propset(action_argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_reload(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
char argv_reload[IFNAMSIZ + sizeof(":reload=")];
|
||||||
|
int i;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
action_argv = strdup(":reload=");
|
||||||
|
return (action_propset(action_argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
sprintf(argv_reload, "%s:reload=", argv[i]);
|
||||||
|
action_argv = argv_reload;
|
||||||
|
error += action_propset(action_argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_echo(int argc __unused, char **argv __unused)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
|
||||||
|
action_argv = strdup("echo");
|
||||||
|
return (action_propset(action_argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_shutdown(int argc __unused, char **argv __unused)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
|
||||||
|
action_argv = strdup("shutdown");
|
||||||
|
return (action_propset(action_argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX */
|
||||||
|
static int
|
||||||
|
action_version(int argc __unused, char **argv __unused)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
struct ctrl_msg_pl cp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
action_argv = strdup(":version=");
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
printf("version=%s\n", cp.cp_val);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_show(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *action_argv;
|
||||||
|
char argv_ifilist[sizeof(":ifilist=")] = ":ifilist=";
|
||||||
|
char argv_ifi[IFNAMSIZ + sizeof(":ifi=")];
|
||||||
|
char argv_rai[IFNAMSIZ + sizeof(":rai=")];
|
||||||
|
char argv_rti[IFNAMSIZ + sizeof(":rti=")];
|
||||||
|
char argv_pfx[IFNAMSIZ + sizeof(":pfx=")];
|
||||||
|
char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")];
|
||||||
|
char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")];
|
||||||
|
char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")];
|
||||||
|
char ssbuf[SSBUFLEN];
|
||||||
|
|
||||||
|
struct ctrl_msg_pl cp;
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl);
|
||||||
|
char *endp;
|
||||||
|
char *p;
|
||||||
|
int error;
|
||||||
|
int i;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
action_argv = argv_ifilist;
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
p = cp.cp_val;
|
||||||
|
endp = p + cp.cp_val_len;
|
||||||
|
while (p < endp) {
|
||||||
|
ifi = malloc(sizeof(*ifi));
|
||||||
|
if (ifi == NULL)
|
||||||
|
return (1);
|
||||||
|
memset(ifi, 0, sizeof(*ifi));
|
||||||
|
|
||||||
|
strcpy(ifi->ifi_ifname, p);
|
||||||
|
ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
|
||||||
|
TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
|
||||||
|
p += strlen(ifi->ifi_ifname) + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
ifi = malloc(sizeof(*ifi));
|
||||||
|
if (ifi == NULL)
|
||||||
|
return (1);
|
||||||
|
memset(ifi, 0, sizeof(*ifi));
|
||||||
|
|
||||||
|
strcpy(ifi->ifi_ifname, argv[i]);
|
||||||
|
ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
|
||||||
|
if (ifi->ifi_ifindex == 0) {
|
||||||
|
sprintf(errmsgbuf, "invalid interface %s",
|
||||||
|
ifi->ifi_ifname);
|
||||||
|
errmsg = errmsgbuf;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifl, ifi_next) {
|
||||||
|
struct ifinfo *ifi_s;
|
||||||
|
struct rtadvd_timer *rat;
|
||||||
|
struct rainfo *rai;
|
||||||
|
struct rtinfo *rti;
|
||||||
|
struct prefix *pfx;
|
||||||
|
int c;
|
||||||
|
int ra_ifstatus;
|
||||||
|
|
||||||
|
sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname);
|
||||||
|
action_argv = argv_ifi;
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
ifi_s = (struct ifinfo *)cp.cp_val;
|
||||||
|
|
||||||
|
if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("%s: flags=<", ifi->ifi_ifname);
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
if (ifi_s->ifi_ifindex == 0)
|
||||||
|
c += printf("NONEXISTENT");
|
||||||
|
else
|
||||||
|
c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ?
|
||||||
|
"UP" : "DOWN");
|
||||||
|
switch (ifi_s->ifi_state) {
|
||||||
|
case IFI_STATE_CONFIGURED:
|
||||||
|
c += printf("%s%s", (c) ? "," : "", "CONFIGURED");
|
||||||
|
break;
|
||||||
|
case IFI_STATE_TRANSITIVE:
|
||||||
|
c += printf("%s%s", (c) ? "," : "", "TRANSITIVE");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi_s->ifi_persist)
|
||||||
|
c += printf("%s%s", (c) ? "," : "", "PERSIST");
|
||||||
|
printf(">");
|
||||||
|
|
||||||
|
ra_ifstatus = RA_IFSTATUS_INACTIVE;
|
||||||
|
if ((ifi_s->ifi_flags & IFF_UP) &&
|
||||||
|
((ifi_s->ifi_state == IFI_STATE_CONFIGURED) ||
|
||||||
|
(ifi_s->ifi_state == IFI_STATE_TRANSITIVE))) {
|
||||||
|
#if (__FreeBSD_version < 900000)
|
||||||
|
/*
|
||||||
|
* RA_RECV: !ip6.forwarding && ip6.accept_rtadv
|
||||||
|
* RA_SEND: ip6.forwarding
|
||||||
|
*/
|
||||||
|
if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
|
||||||
|
if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
|
||||||
|
ra_ifstatus = RA_IFSTATUS_RA_RECV;
|
||||||
|
else
|
||||||
|
ra_ifstatus = RA_IFSTATUS_INACTIVE;
|
||||||
|
} else
|
||||||
|
ra_ifstatus = RA_IFSTATUS_RA_SEND;
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* RA_RECV: ND6_IFF_ACCEPT_RTADV
|
||||||
|
* RA_SEND: ip6.forwarding
|
||||||
|
*/
|
||||||
|
if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
|
||||||
|
ra_ifstatus = RA_IFSTATUS_RA_RECV;
|
||||||
|
else if (getinet6sysctl(IPV6CTL_FORWARDING))
|
||||||
|
ra_ifstatus = RA_IFSTATUS_RA_SEND;
|
||||||
|
else
|
||||||
|
ra_ifstatus = RA_IFSTATUS_INACTIVE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
printf(" status=<");
|
||||||
|
if (ra_ifstatus == RA_IFSTATUS_INACTIVE)
|
||||||
|
printf("%s%s", (c) ? "," : "", "INACTIVE");
|
||||||
|
else if (ra_ifstatus == RA_IFSTATUS_RA_RECV)
|
||||||
|
printf("%s%s", (c) ? "," : "", "RA_RECV");
|
||||||
|
else if (ra_ifstatus == RA_IFSTATUS_RA_SEND)
|
||||||
|
printf("%s%s", (c) ? "," : "", "RA_SEND");
|
||||||
|
printf("> ");
|
||||||
|
|
||||||
|
switch (ifi_s->ifi_state) {
|
||||||
|
case IFI_STATE_CONFIGURED:
|
||||||
|
case IFI_STATE_TRANSITIVE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("mtu %d\n", ifi_s->ifi_phymtu);
|
||||||
|
|
||||||
|
sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
|
||||||
|
action_argv = argv_rai;
|
||||||
|
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rai = (struct rainfo *)cp.cp_val;
|
||||||
|
|
||||||
|
printf("\tDefaultLifetime: %s",
|
||||||
|
sec2str(rai->rai_lifetime, ssbuf));
|
||||||
|
if (ra_ifstatus != RA_IFSTATUS_RA_SEND &&
|
||||||
|
rai->rai_lifetime == 0)
|
||||||
|
printf(" (RAs will be sent with zero lifetime)");
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("\tMinAdvInterval/MaxAdvInterval: %s/%s\n",
|
||||||
|
sec2str(rai->rai_mininterval, ssbuf),
|
||||||
|
sec2str(rai->rai_maxinterval, ssbuf));
|
||||||
|
if (rai->rai_linkmtu)
|
||||||
|
printf("\tAdvLinkMTU: %d", rai->rai_linkmtu);
|
||||||
|
else
|
||||||
|
printf("\tAdvLinkMTU: <none>");
|
||||||
|
|
||||||
|
printf(", ");
|
||||||
|
|
||||||
|
printf("Flags: ");
|
||||||
|
if (rai->rai_managedflg || rai->rai_otherflg) {
|
||||||
|
printf("%s", rai->rai_managedflg ? "M" : "");
|
||||||
|
printf("%s", rai->rai_otherflg ? "O" : "");
|
||||||
|
} else
|
||||||
|
printf("<none>");
|
||||||
|
|
||||||
|
printf(", ");
|
||||||
|
|
||||||
|
printf("Preference: %s\n",
|
||||||
|
rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
|
||||||
|
|
||||||
|
printf("\t"
|
||||||
|
"ReachableTime: %s, "
|
||||||
|
"RetransTimer: %s, "
|
||||||
|
"CurHopLimit: %d\n",
|
||||||
|
sec2str(rai->rai_reachabletime, ssbuf),
|
||||||
|
sec2str(rai->rai_retranstimer, ssbuf),
|
||||||
|
rai->rai_hoplimit);
|
||||||
|
printf("\tAdvIfPrefixes: %s\n",
|
||||||
|
rai->rai_advifprefix ? "yes" : "no");
|
||||||
|
|
||||||
|
/* RA timer */
|
||||||
|
rat = NULL;
|
||||||
|
if (ifi_s->ifi_ra_timer != NULL) {
|
||||||
|
sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
|
||||||
|
ifi->ifi_ifname);
|
||||||
|
action_argv = argv_ifi_ra_timer;
|
||||||
|
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
rat = (struct rtadvd_timer *)cp.cp_val;
|
||||||
|
}
|
||||||
|
printf("\tNext RA send: %s",
|
||||||
|
(rat == NULL) ? "never\n" :
|
||||||
|
ctime((time_t *)&rat->rat_tm.tv_sec));
|
||||||
|
printf("\tLast RA sent: %s",
|
||||||
|
(ifi_s->ifi_ra_lastsent.tv_sec == 0) ? "never\n" :
|
||||||
|
ctime((time_t *)&ifi_s->ifi_ra_lastsent.tv_sec));
|
||||||
|
if (rai->rai_clockskew)
|
||||||
|
printf("\tClock skew: %" PRIu16 "sec\n",
|
||||||
|
rai->rai_clockskew);
|
||||||
|
|
||||||
|
if (vflag < LOG_WARNING)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* route information */
|
||||||
|
sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
|
||||||
|
action_argv = argv_rti;
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
rti = (struct rtinfo *)cp.cp_val;
|
||||||
|
len = cp.cp_val_len / sizeof(*rti);
|
||||||
|
if (len > 0) {
|
||||||
|
printf("\tRoute Info:\n");
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
action_show_rtinfo(&rti[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prefix information */
|
||||||
|
sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
|
||||||
|
action_argv = argv_pfx;
|
||||||
|
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pfx = (struct prefix *)cp.cp_val;
|
||||||
|
len = cp.cp_val_len / sizeof(*pfx);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
printf("\tPrefixes (%d):\n", len);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
action_show_prefix(&pfx[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RDNSS information */
|
||||||
|
sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
|
||||||
|
action_argv = argv_rdnss;
|
||||||
|
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = *((uint16_t *)cp.cp_val);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
printf("\tRDNSS entries:\n");
|
||||||
|
action_show_rdnss(cp.cp_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DNSSL information */
|
||||||
|
sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
|
||||||
|
action_argv = argv_dnssl;
|
||||||
|
|
||||||
|
error = action_propget(action_argv, &cp);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = *((uint16_t *)cp.cp_val);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
printf("\tDNSSL entries:\n");
|
||||||
|
action_show_dnssl(cp.cp_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vflag < LOG_NOTICE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("\tCounters\n"
|
||||||
|
"\t RA burst counts: %" PRIu16 " (interval: %s)\n"
|
||||||
|
"\t RS wait counts: %" PRIu16 "\n",
|
||||||
|
ifi_s->ifi_burstcount,
|
||||||
|
sec2str(ifi_s->ifi_burstinterval, ssbuf),
|
||||||
|
ifi_s->ifi_rs_waitcount);
|
||||||
|
|
||||||
|
printf("\tOutputs\n"
|
||||||
|
"\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
|
||||||
|
|
||||||
|
printf("\tInputs\n"
|
||||||
|
"\t RA: %" PRIu64 " (normal)\n"
|
||||||
|
"\t RA: %" PRIu64 " (inconsistent)\n"
|
||||||
|
"\t RS: %" PRIu64 "\n",
|
||||||
|
ifi_s->ifi_rainput,
|
||||||
|
ifi_s->ifi_rainconsistent,
|
||||||
|
ifi_s->ifi_rsinput);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
#if 0 /* Not implemented yet */
|
||||||
|
printf("\tReceived RAs:\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_show_rtinfo(struct rtinfo *rti)
|
||||||
|
{
|
||||||
|
char ntopbuf[INET6_ADDRSTRLEN];
|
||||||
|
char ssbuf[SSBUFLEN];
|
||||||
|
|
||||||
|
printf("\t %s/%d (pref: %s, ltime: %s)\n",
|
||||||
|
inet_ntop(AF_INET6, &rti->rti_prefix,
|
||||||
|
ntopbuf, sizeof(ntopbuf)),
|
||||||
|
rti->rti_prefixlen,
|
||||||
|
rtpref_str[0xff & (rti->rti_rtpref >> 3)],
|
||||||
|
(rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
|
||||||
|
"infinity" : sec2str(rti->rti_ltime, ssbuf));
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_show_prefix(struct prefix *pfx)
|
||||||
|
{
|
||||||
|
char ntopbuf[INET6_ADDRSTRLEN];
|
||||||
|
char ssbuf[SSBUFLEN];
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix,
|
||||||
|
ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen);
|
||||||
|
|
||||||
|
printf(" (");
|
||||||
|
switch (pfx->pfx_origin) {
|
||||||
|
case PREFIX_FROM_KERNEL:
|
||||||
|
printf("KERNEL");
|
||||||
|
break;
|
||||||
|
case PREFIX_FROM_CONFIG:
|
||||||
|
printf("CONFIG");
|
||||||
|
break;
|
||||||
|
case PREFIX_FROM_DYNAMIC:
|
||||||
|
printf("DYNAMIC");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(",");
|
||||||
|
|
||||||
|
printf(" vltime=%s",
|
||||||
|
(pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
|
||||||
|
"infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
|
||||||
|
|
||||||
|
if (pfx->pfx_vltimeexpire > 0)
|
||||||
|
printf("(expire: %s)",
|
||||||
|
((long)pfx->pfx_vltimeexpire > now.tv_sec) ?
|
||||||
|
sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) :
|
||||||
|
"0");
|
||||||
|
|
||||||
|
printf(",");
|
||||||
|
|
||||||
|
printf(" pltime=%s",
|
||||||
|
(pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
|
||||||
|
"infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
|
||||||
|
|
||||||
|
if (pfx->pfx_pltimeexpire > 0)
|
||||||
|
printf("(expire %s)",
|
||||||
|
((long)pfx->pfx_pltimeexpire > now.tv_sec) ?
|
||||||
|
sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) :
|
||||||
|
"0");
|
||||||
|
|
||||||
|
printf(",");
|
||||||
|
|
||||||
|
printf(" flags=");
|
||||||
|
if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
|
||||||
|
printf("%s", pfx->pfx_onlinkflg ? "L" : "");
|
||||||
|
printf("%s", pfx->pfx_autoconfflg ? "A" : "");
|
||||||
|
} else
|
||||||
|
printf("<none>");
|
||||||
|
|
||||||
|
if (pfx->pfx_timer) {
|
||||||
|
struct timeval *rest;
|
||||||
|
|
||||||
|
rest = rtadvd_timer_rest(pfx->pfx_timer);
|
||||||
|
if (rest) { /* XXX: what if not? */
|
||||||
|
printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(")\n");
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_show_rdnss(void *msg)
|
||||||
|
{
|
||||||
|
struct rdnss *rdn;
|
||||||
|
struct rdnss_addr *rda;
|
||||||
|
uint16_t *rdn_cnt;
|
||||||
|
uint16_t *rda_cnt;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
char *p;
|
||||||
|
uint32_t ltime;
|
||||||
|
char ntopbuf[INET6_ADDRSTRLEN];
|
||||||
|
char ssbuf[SSBUFLEN];
|
||||||
|
|
||||||
|
p = msg;
|
||||||
|
rdn_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*rdn_cnt);
|
||||||
|
|
||||||
|
if (*rdn_cnt > 0) {
|
||||||
|
for (i = 0; i < *rdn_cnt; i++) {
|
||||||
|
rdn = (struct rdnss *)p;
|
||||||
|
ltime = rdn->rd_ltime;
|
||||||
|
p += sizeof(*rdn);
|
||||||
|
|
||||||
|
rda_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*rda_cnt);
|
||||||
|
if (*rda_cnt > 0)
|
||||||
|
for (j = 0; j < *rda_cnt; j++) {
|
||||||
|
rda = (struct rdnss_addr *)p;
|
||||||
|
printf("\t %s (ltime=%s)\n",
|
||||||
|
inet_ntop(AF_INET6,
|
||||||
|
&rda->ra_dns,
|
||||||
|
ntopbuf,
|
||||||
|
sizeof(ntopbuf)),
|
||||||
|
sec2str(ltime, ssbuf));
|
||||||
|
p += sizeof(*rda);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
action_show_dnssl(void *msg)
|
||||||
|
{
|
||||||
|
struct dnssl *dns;
|
||||||
|
struct dnssl_addr *dna;
|
||||||
|
uint16_t *dns_cnt;
|
||||||
|
uint16_t *dna_cnt;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
char *p;
|
||||||
|
uint32_t ltime;
|
||||||
|
char hbuf[NI_MAXHOST];
|
||||||
|
char ssbuf[SSBUFLEN];
|
||||||
|
|
||||||
|
p = msg;
|
||||||
|
dns_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*dns_cnt);
|
||||||
|
|
||||||
|
if (*dns_cnt > 0) {
|
||||||
|
for (i = 0; i < *dns_cnt; i++) {
|
||||||
|
dns = (struct dnssl *)p;
|
||||||
|
ltime = dns->dn_ltime;
|
||||||
|
p += sizeof(*dns);
|
||||||
|
|
||||||
|
dna_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*dna_cnt);
|
||||||
|
if (*dna_cnt > 0)
|
||||||
|
for (j = 0; j < *dna_cnt; j++) {
|
||||||
|
dna = (struct dnssl_addr *)p;
|
||||||
|
dname_labeldec(hbuf, sizeof(hbuf),
|
||||||
|
dna->da_dom);
|
||||||
|
printf("\t %s (ltime=%s)\n",
|
||||||
|
hbuf, sec2str(ltime, ssbuf));
|
||||||
|
p += sizeof(*dna);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
|
||||||
|
static size_t
|
||||||
|
dname_labeldec(char *dst, size_t dlen, const char *src)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
const char *src_origin;
|
||||||
|
const char *src_last;
|
||||||
|
const char *dst_origin;
|
||||||
|
|
||||||
|
src_origin = src;
|
||||||
|
src_last = strchr(src, '\0');
|
||||||
|
dst_origin = dst;
|
||||||
|
memset(dst, '\0', dlen);
|
||||||
|
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
|
||||||
|
(src + len) <= src_last) {
|
||||||
|
if (dst != dst_origin)
|
||||||
|
*dst++ = '.';
|
||||||
|
mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
|
||||||
|
memcpy(dst, src, len);
|
||||||
|
src += len;
|
||||||
|
dst += len;
|
||||||
|
}
|
||||||
|
*dst = '\0';
|
||||||
|
|
||||||
|
return (src - src_origin);
|
||||||
|
}
|
@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
PROG= rtadvd
|
PROG= rtadvd
|
||||||
MAN= rtadvd.conf.5 rtadvd.8
|
MAN= rtadvd.conf.5 rtadvd.8
|
||||||
SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c dump.c
|
SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c timer_subr.c \
|
||||||
|
control.c control_server.c
|
||||||
|
|
||||||
DPADD= ${LIBUTIL}
|
DPADD= ${LIBUTIL}
|
||||||
LDADD= -lutil
|
LDADD= -lutil
|
||||||
|
|
||||||
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO
|
CFLAGS+= -DHAVE_ARC4RANDOM
|
||||||
|
|
||||||
WARNS?= 1
|
WARNS?= 1
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,9 +30,12 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int getconfig(int);
|
extern struct ifinfo *getconfig(struct ifinfo *);
|
||||||
extern int rmconfig(int);
|
extern int rm_ifinfo(struct ifinfo *);
|
||||||
extern int loadconfig(char *[], const int);
|
extern int rm_ifinfo_index(int);
|
||||||
|
extern int rm_rainfo(struct rainfo *);
|
||||||
|
extern int loadconfig_ifname(char *);
|
||||||
|
extern int loadconfig_index(int);
|
||||||
extern void delete_prefix(struct prefix *);
|
extern void delete_prefix(struct prefix *);
|
||||||
extern void invalidate_prefix(struct prefix *);
|
extern void invalidate_prefix(struct prefix *);
|
||||||
extern void update_prefix(struct prefix *);
|
extern void update_prefix(struct prefix *);
|
||||||
@ -40,7 +43,6 @@ extern void make_prefix(struct rainfo *, int, struct in6_addr *, int);
|
|||||||
extern void make_packet(struct rainfo *);
|
extern void make_packet(struct rainfo *);
|
||||||
extern void get_prefix(struct rainfo *);
|
extern void get_prefix(struct rainfo *);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* it is highly unlikely to have 100 prefix information options,
|
* it is highly unlikely to have 100 prefix information options,
|
||||||
* so it should be okay to limit it
|
* so it should be okay to limit it
|
||||||
|
456
usr.sbin/rtadvd/control.c
Normal file
456
usr.sbin/rtadvd/control.c
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "rtadvd.h"
|
||||||
|
#include "if.h"
|
||||||
|
#include "pathnames.h"
|
||||||
|
#include "control.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
cmsg_recv(int fd, char *buf)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd);
|
||||||
|
|
||||||
|
memset(buf, 0, CM_MSG_MAXLEN);
|
||||||
|
cm = (struct ctrl_msg_hdr *)buf;
|
||||||
|
msg = (char *)buf + sizeof(*cm);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
n = read(fd, cm, sizeof(*cm));
|
||||||
|
if (n < 0 && errno == EAGAIN) {
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> waiting...", __func__);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n != sizeof(*cm)) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> received a too small message.", __func__);
|
||||||
|
goto cmsg_recv_err;
|
||||||
|
}
|
||||||
|
if (cm->cm_len > CM_MSG_MAXLEN) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> received a too large message.", __func__);
|
||||||
|
goto cmsg_recv_err;
|
||||||
|
}
|
||||||
|
if (cm->cm_version != CM_VERSION) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> version mismatch", __func__);
|
||||||
|
goto cmsg_recv_err;
|
||||||
|
}
|
||||||
|
if (cm->cm_type >= CM_TYPE_MAX) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> invalid msg type.", __func__);
|
||||||
|
goto cmsg_recv_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> ctrl msg received: type=%d", __func__,
|
||||||
|
cm->cm_type);
|
||||||
|
|
||||||
|
if (cm->cm_len > sizeof(cm)) {
|
||||||
|
int msglen = cm->cm_len - sizeof(*cm);
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> ctrl msg has payload (len=%d)", __func__,
|
||||||
|
msglen);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
n = read(fd, msg, msglen);
|
||||||
|
if (n < 0 && errno == EAGAIN) {
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> waiting...", __func__);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (n != msglen) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> payload size mismatch.", __func__);
|
||||||
|
goto cmsg_recv_err;
|
||||||
|
}
|
||||||
|
buf[CM_MSG_MAXLEN - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
cmsg_recv_err:
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cmsg_send(int fd, char *buf)
|
||||||
|
{
|
||||||
|
struct iovec iov[2];
|
||||||
|
int iovcnt;
|
||||||
|
ssize_t len;
|
||||||
|
ssize_t iov_len_total;
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
|
cm = (struct ctrl_msg_hdr *)buf;
|
||||||
|
msg = (char *)buf + sizeof(*cm);
|
||||||
|
|
||||||
|
iovcnt = 1;
|
||||||
|
iov[0].iov_base = cm;
|
||||||
|
iov[0].iov_len = sizeof(*cm);
|
||||||
|
iov_len_total = iov[0].iov_len;
|
||||||
|
if (cm->cm_len > sizeof(*cm)) {
|
||||||
|
iovcnt++;
|
||||||
|
iov[1].iov_base = msg;
|
||||||
|
iov[1].iov_len = cm->cm_len - iov[0].iov_len;
|
||||||
|
iov_len_total += iov[1].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> ctrl msg send: type=%d, count=%d, total_len=%zd", __func__,
|
||||||
|
cm->cm_type, iovcnt, iov_len_total);
|
||||||
|
|
||||||
|
len = writev(fd, iov, iovcnt);
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> ctrl msg send: length=%zd", __func__, len);
|
||||||
|
|
||||||
|
if (len == -1) {
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> write failed: (%d)%s", __func__, errno,
|
||||||
|
strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> write length = %zd (actual)", __func__, len);
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> write length = %zd (expected)", __func__, iov_len_total);
|
||||||
|
|
||||||
|
if (len != iov_len_total) {
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
csock_accept(struct sockinfo *s)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
int flags;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
sun.sun_len = sizeof(sun);
|
||||||
|
if ((fd = accept(s->si_fd, (struct sockaddr *)&sun,
|
||||||
|
(socklen_t *)&sun.sun_len)) == -1) {
|
||||||
|
if (errno != EWOULDBLOCK && errno != EINTR)
|
||||||
|
syslog(LOG_WARNING, "<%s> accept ", __func__);
|
||||||
|
syslog(LOG_WARNING, "<%s> Xaccept: %s", __func__, strerror(errno));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
|
||||||
|
syslog(LOG_WARNING, "<%s> fcntl F_GETFL", __func__);
|
||||||
|
close(s->si_fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if ((flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
|
||||||
|
syslog(LOG_WARNING, "<%s> fcntl F_SETFL", __func__);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG, "<%s> accept connfd=%d, listenfd=%d", __func__,
|
||||||
|
fd, s->si_fd);
|
||||||
|
|
||||||
|
return (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
csock_close(struct sockinfo *s)
|
||||||
|
{
|
||||||
|
close(s->si_fd);
|
||||||
|
unlink(s->si_name);
|
||||||
|
syslog(LOG_DEBUG, "<%s> remove %s", __func__, s->si_name);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
csock_listen(struct sockinfo *s)
|
||||||
|
{
|
||||||
|
if (s->si_fd == -1) {
|
||||||
|
syslog(LOG_ERR, "<%s> listen failed", __func__);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (listen(s->si_fd, SOCK_BACKLOG) == -1) {
|
||||||
|
syslog(LOG_ERR, "<%s> listen failed", __func__);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
csock_open(struct sockinfo *s, mode_t mode)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
mode_t old_umask;
|
||||||
|
|
||||||
|
if (s == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> internal error.", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (s->si_name == NULL)
|
||||||
|
s->si_name = _PATH_CTRL_SOCK;
|
||||||
|
|
||||||
|
if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> cannot open control socket", __func__);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
memset(&sun, 0, sizeof(sun));
|
||||||
|
sun.sun_family = AF_UNIX;
|
||||||
|
sun.sun_len = sizeof(sun);
|
||||||
|
strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
|
||||||
|
|
||||||
|
if (unlink(s->si_name) == -1)
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> unlink %s", __func__, s->si_name);
|
||||||
|
close(s->si_fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
|
||||||
|
if (bind(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> bind failed: %s", __func__, s->si_name);
|
||||||
|
close(s->si_fd);
|
||||||
|
umask(old_umask);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
umask(old_umask);
|
||||||
|
if (chmod(s->si_name, mode) == -1) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> chmod failed: %s", __func__, s->si_name);
|
||||||
|
goto csock_open_err;
|
||||||
|
}
|
||||||
|
if ((flags = fcntl(s->si_fd, F_GETFL, 0)) == -1) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> fcntl F_GETFL failed: %s", __func__, s->si_name);
|
||||||
|
goto csock_open_err;
|
||||||
|
}
|
||||||
|
if ((flags = fcntl(s->si_fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> fcntl F_SETFL failed: %s", __func__, s->si_name);
|
||||||
|
goto csock_open_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (s->si_fd);
|
||||||
|
|
||||||
|
csock_open_err:
|
||||||
|
close(s->si_fd);
|
||||||
|
unlink(s->si_name);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctrl_msg_pl *
|
||||||
|
cmsg_bin2pl(char *str, struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
size_t *lenp;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
memset(cp, 0, sizeof(*cp));
|
||||||
|
|
||||||
|
p = str;
|
||||||
|
|
||||||
|
lenp = (size_t *)p;
|
||||||
|
len = *lenp++;
|
||||||
|
p = (char *)lenp;
|
||||||
|
syslog(LOG_DEBUG, "<%s> len(ifname) = %zu", __func__, len);
|
||||||
|
if (len > 0) {
|
||||||
|
cp->cp_ifname = malloc(len + 1);
|
||||||
|
if (cp->cp_ifname == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> malloc", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memcpy(cp->cp_ifname, p, len);
|
||||||
|
cp->cp_ifname[len] = '\0';
|
||||||
|
p += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
lenp = (size_t *)p;
|
||||||
|
len = *lenp++;
|
||||||
|
p = (char *)lenp;
|
||||||
|
syslog(LOG_DEBUG, "<%s> len(key) = %zu", __func__, len);
|
||||||
|
if (len > 0) {
|
||||||
|
cp->cp_key = malloc(len + 1);
|
||||||
|
if (cp->cp_key == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> malloc", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memcpy(cp->cp_key, p, len);
|
||||||
|
cp->cp_key[len] = '\0';
|
||||||
|
p += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
lenp = (size_t *)p;
|
||||||
|
len = *lenp++;
|
||||||
|
p = (char *)lenp;
|
||||||
|
syslog(LOG_DEBUG, "<%s> len(val) = %zu", __func__, len);
|
||||||
|
if (len > 0) {
|
||||||
|
cp->cp_val = malloc(len + 1);
|
||||||
|
if (cp->cp_val == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> malloc", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memcpy(cp->cp_val, p, len);
|
||||||
|
cp->cp_val[len] = '\0';
|
||||||
|
cp->cp_val_len = len;
|
||||||
|
} else
|
||||||
|
cp->cp_val_len = 0;
|
||||||
|
|
||||||
|
return (cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
cmsg_pl2bin(char *str, struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
size_t *lenp;
|
||||||
|
char *p;
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (cp->cp_ifname != NULL)
|
||||||
|
len += strlen(cp->cp_ifname);
|
||||||
|
len += sizeof(size_t);
|
||||||
|
if (cp->cp_key != NULL)
|
||||||
|
len += strlen(cp->cp_key);
|
||||||
|
len += sizeof(size_t);
|
||||||
|
if (cp->cp_val != NULL && cp->cp_val_len > 0)
|
||||||
|
len += cp->cp_val_len;
|
||||||
|
|
||||||
|
if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
|
||||||
|
syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
|
||||||
|
__func__, len);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
|
||||||
|
memset(str, 0, len);
|
||||||
|
p = str;
|
||||||
|
lenp = (size_t *)p;
|
||||||
|
|
||||||
|
if (cp->cp_ifname != NULL) {
|
||||||
|
*lenp++ = strlen(cp->cp_ifname);
|
||||||
|
p = (char *)lenp;
|
||||||
|
memcpy(p, cp->cp_ifname, strlen(cp->cp_ifname));
|
||||||
|
p += strlen(cp->cp_ifname);
|
||||||
|
} else {
|
||||||
|
*lenp++ = '\0';
|
||||||
|
p = (char *)lenp;
|
||||||
|
}
|
||||||
|
|
||||||
|
lenp = (size_t *)p;
|
||||||
|
if (cp->cp_key != NULL) {
|
||||||
|
*lenp++ = strlen(cp->cp_key);
|
||||||
|
p = (char *)lenp;
|
||||||
|
memcpy(p, cp->cp_key, strlen(cp->cp_key));
|
||||||
|
p += strlen(cp->cp_key);
|
||||||
|
} else {
|
||||||
|
*lenp++ = '\0';
|
||||||
|
p = (char *)lenp;
|
||||||
|
}
|
||||||
|
|
||||||
|
lenp = (size_t *)p;
|
||||||
|
if (cp->cp_val != NULL && cp->cp_val_len > 0) {
|
||||||
|
*lenp++ = cp->cp_val_len;
|
||||||
|
p = (char *)lenp;
|
||||||
|
memcpy(p, cp->cp_val, cp->cp_val_len);
|
||||||
|
p += cp->cp_val_len;
|
||||||
|
} else {
|
||||||
|
*lenp++ = '\0';
|
||||||
|
p = (char *)lenp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (len);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
cmsg_str2bin(char *bin, void *str, size_t len)
|
||||||
|
{
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
|
||||||
|
syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
|
||||||
|
__func__, len);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
|
||||||
|
memcpy(bin, (char *)str, len);
|
||||||
|
|
||||||
|
return (len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
cmsg_bin2str(char *bin, void *str, size_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
memcpy((char *)str, bin, len);
|
||||||
|
|
||||||
|
return (str);
|
||||||
|
}
|
74
usr.sbin/rtadvd/control.h
Normal file
74
usr.sbin/rtadvd/control.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SOCK_BACKLOG 5
|
||||||
|
|
||||||
|
#define CM_MSG_MAXLEN 8192
|
||||||
|
#define CM_VERSION 1
|
||||||
|
#define CM_VERSION_STR "1.0"
|
||||||
|
|
||||||
|
#define CM_TYPE_EOM 0
|
||||||
|
#define CM_TYPE_ACK 1
|
||||||
|
#define CM_TYPE_ERR 2
|
||||||
|
#define CM_TYPE_NUL 3
|
||||||
|
#define CM_TYPE_REQ_SET_PROP 4
|
||||||
|
#define CM_TYPE_REQ_GET_PROP 5
|
||||||
|
#define CM_TYPE_MAX 6
|
||||||
|
|
||||||
|
#define CM_STATE_EOM 0
|
||||||
|
#define CM_STATE_INIT 1
|
||||||
|
#define CM_STATE_MSG_DISPATCH 2
|
||||||
|
#define CM_STATE_MSG_RECV 3
|
||||||
|
#define CM_STATE_ACK_WAIT 4
|
||||||
|
|
||||||
|
struct ctrl_msg_hdr {
|
||||||
|
int cm_version;
|
||||||
|
size_t cm_len;
|
||||||
|
int cm_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ctrl_msg_pl {
|
||||||
|
char *cp_ifname;
|
||||||
|
char *cp_key;
|
||||||
|
|
||||||
|
size_t cp_val_len;
|
||||||
|
char *cp_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
int csock_open(struct sockinfo *, mode_t);
|
||||||
|
int csock_close(struct sockinfo *);
|
||||||
|
int csock_listen(struct sockinfo *);
|
||||||
|
int csock_accept(struct sockinfo *);
|
||||||
|
int cmsg_send(int, char *);
|
||||||
|
int cmsg_recv(int, char *);
|
||||||
|
|
||||||
|
size_t cmsg_pl2bin(char *, struct ctrl_msg_pl *);
|
||||||
|
struct ctrl_msg_pl *cmsg_bin2pl(char *, struct ctrl_msg_pl *);
|
||||||
|
size_t cmsg_str2bin(char *, void *, size_t);
|
||||||
|
void *cmsg_bin2str(char *, void *, size_t);
|
131
usr.sbin/rtadvd/control_client.c
Normal file
131
usr.sbin/rtadvd/control_client.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
|
#include "rtadvd.h"
|
||||||
|
#include "if.h"
|
||||||
|
#include "control.h"
|
||||||
|
#include "control_client.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
cmsg_handler_client(int fd, int state, char *buf_orig)
|
||||||
|
{
|
||||||
|
char buf[CM_MSG_MAXLEN];
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
struct ctrl_msg_hdr *cm_orig;
|
||||||
|
int error;
|
||||||
|
char *msg;
|
||||||
|
char *msg_orig;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
cm = (struct ctrl_msg_hdr *)buf;
|
||||||
|
cm_orig = (struct ctrl_msg_hdr *)buf_orig;
|
||||||
|
msg = (char *)buf + sizeof(*cm);
|
||||||
|
msg_orig = (char *)buf_orig + sizeof(*cm_orig);
|
||||||
|
|
||||||
|
if (cm_orig->cm_len > CM_MSG_MAXLEN) {
|
||||||
|
syslog(LOG_DEBUG, "<%s> msg too long", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
cm->cm_type = cm_orig->cm_type;
|
||||||
|
if (cm_orig->cm_len > sizeof(*cm_orig)) {
|
||||||
|
memcpy(msg, msg_orig, cm_orig->cm_len - sizeof(*cm));
|
||||||
|
cm->cm_len = cm_orig->cm_len;
|
||||||
|
}
|
||||||
|
while (state != CM_STATE_EOM) {
|
||||||
|
syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case CM_STATE_INIT:
|
||||||
|
state = CM_STATE_EOM;
|
||||||
|
break;
|
||||||
|
case CM_STATE_MSG_DISPATCH:
|
||||||
|
cm->cm_version = CM_VERSION;
|
||||||
|
error = cmsg_send(fd, buf);
|
||||||
|
if (error)
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> cmsg_send()", __func__);
|
||||||
|
state = CM_STATE_ACK_WAIT;
|
||||||
|
break;
|
||||||
|
case CM_STATE_ACK_WAIT:
|
||||||
|
error = cmsg_recv(fd, buf);
|
||||||
|
if (error) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> cmsg_recv()", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
switch (cm->cm_type) {
|
||||||
|
case CM_TYPE_ACK:
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> CM_TYPE_ACK", __func__);
|
||||||
|
break;
|
||||||
|
case CM_TYPE_ERR:
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> CM_TYPE_ERR", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
default:
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> unknown status", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
memcpy(buf_orig, buf, cm->cm_len);
|
||||||
|
state = CM_STATE_EOM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return (0);
|
||||||
|
}
|
30
usr.sbin/rtadvd/control_client.h
Normal file
30
usr.sbin/rtadvd/control_client.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int cmsg_handler_client(int, int, char *);
|
742
usr.sbin/rtadvd/control_server.c
Normal file
742
usr.sbin/rtadvd/control_server.c
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
|
#include "rtadvd.h"
|
||||||
|
#include "if.h"
|
||||||
|
#include "control.h"
|
||||||
|
#include "control_server.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
static char *do_reload_ifname;
|
||||||
|
static int do_reload;
|
||||||
|
static int do_shutdown;
|
||||||
|
|
||||||
|
void set_do_reload(int sig __unused) { do_reload = 1; }
|
||||||
|
void set_do_reload_ifname(char *ifname){ do_reload_ifname = ifname; }
|
||||||
|
void set_do_shutdown(int sig __unused) { do_shutdown = 1; }
|
||||||
|
void reset_do_reload(void) { do_reload = 0; do_reload_ifname = NULL; }
|
||||||
|
void reset_do_shutdown(void) { do_shutdown = 0; }
|
||||||
|
int is_do_reload(void) { return (do_reload); }
|
||||||
|
int is_do_shutdown(void) { return (do_shutdown); }
|
||||||
|
char *reload_ifname(void) { return (do_reload_ifname); }
|
||||||
|
|
||||||
|
#define DEF_PL_HANDLER(key) { #key, cmsg_getprop_##key }
|
||||||
|
|
||||||
|
static int cmsg_getprop_echo(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_version(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_ifilist(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_ifi(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_ifi_ra_timer(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_rai(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_pfx(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_rdnss(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_dnssl(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_getprop_rti(struct ctrl_msg_pl *);
|
||||||
|
|
||||||
|
static int cmsg_setprop_reload(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_setprop_enable(struct ctrl_msg_pl *);
|
||||||
|
static int cmsg_setprop_disable(struct ctrl_msg_pl *);
|
||||||
|
|
||||||
|
static struct dispatch_table {
|
||||||
|
const char *dt_comm;
|
||||||
|
int (*dt_act)(struct ctrl_msg_pl *cp);
|
||||||
|
} getprop_dtable[] = {
|
||||||
|
{ "", cmsg_getprop_echo },
|
||||||
|
DEF_PL_HANDLER(echo),
|
||||||
|
DEF_PL_HANDLER(version),
|
||||||
|
DEF_PL_HANDLER(ifilist),
|
||||||
|
DEF_PL_HANDLER(ifi),
|
||||||
|
DEF_PL_HANDLER(ifi_ra_timer),
|
||||||
|
DEF_PL_HANDLER(rai),
|
||||||
|
DEF_PL_HANDLER(rti),
|
||||||
|
DEF_PL_HANDLER(pfx),
|
||||||
|
DEF_PL_HANDLER(rdnss),
|
||||||
|
DEF_PL_HANDLER(dnssl),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_echo(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
cp->cp_val = strdup("");
|
||||||
|
cp->cp_val_len = strlen(cp->cp_val) + 1;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_version(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
cp->cp_val = strdup(CM_VERSION_STR);
|
||||||
|
cp->cp_val_len = strlen(cp->cp_val) + 1;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_ifilist(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
len += strlen(ifi->ifi_ifname) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
p = malloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
memset(p, 0, len);
|
||||||
|
cp->cp_val = p;
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
syslog(LOG_DEBUG, "<%s> add ifname=%s(%d)",
|
||||||
|
__func__, ifi->ifi_ifname, ifi->ifi_ifindex);
|
||||||
|
strcpy(p, ifi->ifi_ifname);
|
||||||
|
p += strlen(ifi->ifi_ifname) + 1;
|
||||||
|
}
|
||||||
|
cp->cp_val_len = p - cp->cp_val;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_ifi(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = malloc(sizeof(*ifi));
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
len = cmsg_str2bin(p, ifi, sizeof(*ifi));
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
cp->cp_val = p;
|
||||||
|
cp->cp_val_len = len;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_rai(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
struct rainfo *rai;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if ((rai = ifi->ifi_rainfo) == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = malloc(sizeof(*rai));
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
len = cmsg_str2bin(p, rai, sizeof(*rai));
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
cp->cp_val = p;
|
||||||
|
cp->cp_val_len = len;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_ifi_ra_timer(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
struct rainfo *rai;
|
||||||
|
struct rtadvd_timer *rtimer;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if ((rai = ifi->ifi_rainfo) == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if ((rtimer = ifi->ifi_ra_timer) == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no ifi_ra_timer", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
p = malloc(sizeof(*rtimer));
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
len = cmsg_str2bin(p, rtimer, sizeof(*rtimer));
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
cp->cp_val = p;
|
||||||
|
cp->cp_val_len = len;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_rti(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
struct rainfo *rai;
|
||||||
|
struct rtinfo *rti;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (ifi->ifi_rainfo == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
rai = ifi->ifi_rainfo;
|
||||||
|
TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
|
||||||
|
len += sizeof(*rti);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
p = malloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
memset(p, 0, len);
|
||||||
|
cp->cp_val = p;
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
|
||||||
|
memcpy(p, rti, sizeof(*rti));
|
||||||
|
p += sizeof(*rti);
|
||||||
|
}
|
||||||
|
cp->cp_val_len = p - cp->cp_val;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_pfx(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
struct rainfo *rai;
|
||||||
|
struct prefix *pfx;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (ifi->ifi_rainfo == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
rai = ifi->ifi_rainfo;
|
||||||
|
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
|
||||||
|
len += sizeof(*pfx);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
p = malloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
memset(p, 0, len);
|
||||||
|
cp->cp_val = p;
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
|
||||||
|
memcpy(p, pfx, sizeof(*pfx));
|
||||||
|
p += sizeof(*pfx);
|
||||||
|
}
|
||||||
|
cp->cp_val_len = p - cp->cp_val;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_rdnss(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
struct rainfo *rai;
|
||||||
|
struct rdnss *rdn;
|
||||||
|
struct rdnss_addr *rda;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
uint16_t *rdn_cnt;
|
||||||
|
uint16_t *rda_cnt;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (ifi->ifi_rainfo == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
rai = ifi->ifi_rainfo;
|
||||||
|
|
||||||
|
len = sizeof(*rdn_cnt);
|
||||||
|
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
|
||||||
|
len += sizeof(*rdn);
|
||||||
|
len += sizeof(*rda_cnt);
|
||||||
|
TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
|
||||||
|
len += sizeof(*rda);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
p = malloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
memset(p, 0, len);
|
||||||
|
cp->cp_val = p;
|
||||||
|
|
||||||
|
rdn_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*rdn_cnt);
|
||||||
|
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
|
||||||
|
*rdn_cnt += 1;
|
||||||
|
memcpy(p, rdn, sizeof(*rdn));
|
||||||
|
p += sizeof(*rdn);
|
||||||
|
|
||||||
|
rda_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*rda_cnt);
|
||||||
|
TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
|
||||||
|
*rda_cnt += 1;
|
||||||
|
memcpy(p, rda, sizeof(*rda));
|
||||||
|
p += sizeof(*rda);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
|
||||||
|
cp->cp_val_len = p - cp->cp_val;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_getprop_dnssl(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
struct rainfo *rai;
|
||||||
|
struct dnssl *dns;
|
||||||
|
struct dnssl_addr *dna;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
uint16_t *dns_cnt;
|
||||||
|
uint16_t *dna_cnt;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (ifi->ifi_rainfo == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
rai = ifi->ifi_rainfo;
|
||||||
|
|
||||||
|
len = sizeof(*dns_cnt);
|
||||||
|
TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
|
||||||
|
len += sizeof(*dns);
|
||||||
|
len += sizeof(*dna_cnt);
|
||||||
|
TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
|
||||||
|
len += sizeof(*dna);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||||
|
|
||||||
|
p = malloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
exit(1);
|
||||||
|
memset(p, 0, len);
|
||||||
|
cp->cp_val = p;
|
||||||
|
|
||||||
|
dns_cnt = (uint16_t *)cp->cp_val;
|
||||||
|
p += sizeof(*dns_cnt);
|
||||||
|
TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
|
||||||
|
(*dns_cnt)++;
|
||||||
|
memcpy(p, dns, sizeof(*dns));
|
||||||
|
p += sizeof(*dns);
|
||||||
|
|
||||||
|
dna_cnt = (uint16_t *)p;
|
||||||
|
p += sizeof(*dna_cnt);
|
||||||
|
TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
|
||||||
|
(*dna_cnt)++;
|
||||||
|
memcpy(p, dna, sizeof(*dna));
|
||||||
|
p += sizeof(*dna);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cp->cp_val_len = p - cp->cp_val;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cmsg_getprop(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (cp == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
|
||||||
|
i++) {
|
||||||
|
if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
|
||||||
|
return (getprop_dtable[i].dt_act(cp));
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cmsg_setprop(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (cp == NULL || cp->cp_key == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (strncmp(cp->cp_key, "reload", sizeof("reload")) == 0)
|
||||||
|
cmsg_setprop_reload(cp);
|
||||||
|
else if (strncmp(cp->cp_key, "shutdown", sizeof("shutdown")) == 0)
|
||||||
|
set_do_shutdown(0);
|
||||||
|
else if (strncmp(cp->cp_key, "enable", sizeof("enable")) == 0)
|
||||||
|
cmsg_setprop_enable(cp);
|
||||||
|
else if (strncmp(cp->cp_key, "disable", sizeof("disable")) == 0)
|
||||||
|
cmsg_setprop_disable(cp);
|
||||||
|
else if (strncmp(cp->cp_key, "echo", 8) == 0)
|
||||||
|
; /* do nothing */
|
||||||
|
else
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_setprop_reload(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
set_do_reload_ifname(cp->cp_ifname);
|
||||||
|
set_do_reload(1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_setprop_enable(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifi->ifi_persist = 1;
|
||||||
|
set_do_reload_ifname(ifi->ifi_ifname);
|
||||||
|
set_do_reload(0);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmsg_setprop_disable(struct ctrl_msg_pl *cp)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||||
|
cp->cp_ifname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifi->ifi_persist = 0;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cmsg_handler_server(int fd)
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
char *msg;
|
||||||
|
struct ctrl_msg_hdr *cm;
|
||||||
|
struct ctrl_msg_pl cp;
|
||||||
|
char buf[CM_MSG_MAXLEN];
|
||||||
|
char pbuf[CM_MSG_MAXLEN];
|
||||||
|
int error;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
memset(pbuf, 0, sizeof(pbuf));
|
||||||
|
cm = (struct ctrl_msg_hdr *)buf;
|
||||||
|
msg = (char *)buf + sizeof(*cm);
|
||||||
|
|
||||||
|
state = CM_STATE_INIT;
|
||||||
|
while (state != CM_STATE_EOM) {
|
||||||
|
syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case CM_STATE_INIT:
|
||||||
|
state = CM_STATE_MSG_RECV;
|
||||||
|
break;
|
||||||
|
case CM_STATE_MSG_DISPATCH:
|
||||||
|
cm->cm_version = CM_VERSION;
|
||||||
|
error = cmsg_send(fd, buf);
|
||||||
|
if (error)
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> cmsg_send()", __func__);
|
||||||
|
state = CM_STATE_EOM;
|
||||||
|
break;
|
||||||
|
case CM_STATE_ACK_WAIT:
|
||||||
|
error = cmsg_recv(fd, buf);
|
||||||
|
if (error) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> cmsg_recv()", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cm->cm_type) {
|
||||||
|
case CM_TYPE_ACK:
|
||||||
|
break;
|
||||||
|
case CM_TYPE_ERR:
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> CM_TYPE_ERR", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
default:
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> unknown status", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
state = CM_STATE_EOM;
|
||||||
|
break;
|
||||||
|
case CM_STATE_MSG_RECV:
|
||||||
|
error = cmsg_recv(fd, buf);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> cmsg_recv()", __func__);
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> cm->cm_type = %d", __func__, cm->cm_type);
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> cm->cm_len = %zu", __func__, cm->cm_len);
|
||||||
|
|
||||||
|
switch (cm->cm_type) {
|
||||||
|
case CM_TYPE_EOM:
|
||||||
|
state = CM_STATE_EOM;
|
||||||
|
case CM_TYPE_NUL:
|
||||||
|
cm->cm_type = CM_TYPE_ACK;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
break;
|
||||||
|
case CM_TYPE_REQ_GET_PROP:
|
||||||
|
cmsg_bin2pl(msg, &cp);
|
||||||
|
error = cmsg_getprop(&cp);
|
||||||
|
if (error) {
|
||||||
|
cm->cm_type = CM_TYPE_ERR;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
} else {
|
||||||
|
cm->cm_type = CM_TYPE_ACK;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
cm->cm_len += cmsg_pl2bin(msg, &cp);
|
||||||
|
}
|
||||||
|
if (cp.cp_val != NULL)
|
||||||
|
free(cp.cp_val);
|
||||||
|
break;
|
||||||
|
case CM_TYPE_REQ_SET_PROP:
|
||||||
|
cmsg_bin2pl(msg, &cp);
|
||||||
|
error = cmsg_setprop(&cp);
|
||||||
|
if (error) {
|
||||||
|
cm->cm_type = CM_TYPE_ERR;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
} else {
|
||||||
|
cm->cm_type = CM_TYPE_ACK;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cm->cm_type = CM_TYPE_ERR;
|
||||||
|
cm->cm_len = sizeof(*cm);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cm->cm_type) {
|
||||||
|
case CM_TYPE_ERR:
|
||||||
|
case CM_TYPE_ACK:
|
||||||
|
state = CM_STATE_MSG_DISPATCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG, "<%s> leave", __func__);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
42
usr.sbin/rtadvd/control_server.h
Normal file
42
usr.sbin/rtadvd/control_server.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int cmsg_getprop(struct ctrl_msg_pl *);
|
||||||
|
int cmsg_setprop(struct ctrl_msg_pl *);
|
||||||
|
|
||||||
|
int cmsg_handler_server(int);
|
||||||
|
|
||||||
|
void set_do_reload(int);
|
||||||
|
void set_do_reload_ifname(char *);
|
||||||
|
void set_do_shutdown(int);
|
||||||
|
void reset_do_reload(void);
|
||||||
|
void reset_do_shutdown(void);
|
||||||
|
int is_do_reload(void);
|
||||||
|
char *reload_ifname(void);
|
||||||
|
int is_do_shutdown(void);
|
@ -1,321 +0,0 @@
|
|||||||
/* $FreeBSD$ */
|
|
||||||
/* $KAME: dump.c,v 1.32 2003/05/19 09:46:50 keiichi 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/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/queue.h>
|
|
||||||
|
|
||||||
#include <net/if.h>
|
|
||||||
#include <net/if_var.h>
|
|
||||||
#include <net/if_dl.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
/* XXX: the following two are non-standard include files */
|
|
||||||
#include <netinet6/in6_var.h>
|
|
||||||
#include <netinet6/nd6.h>
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "rtadvd.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "if.h"
|
|
||||||
#include "dump.h"
|
|
||||||
|
|
||||||
static FILE *fp;
|
|
||||||
|
|
||||||
extern struct rainfo *ralist;
|
|
||||||
|
|
||||||
static char *ether_str(struct sockaddr_dl *);
|
|
||||||
static void if_dump(void);
|
|
||||||
static size_t dname_labeldec(char *, size_t, const char *);
|
|
||||||
|
|
||||||
static const char *rtpref_str[] = {
|
|
||||||
"medium", /* 00 */
|
|
||||||
"high", /* 01 */
|
|
||||||
"rsv", /* 10 */
|
|
||||||
"low" /* 11 */
|
|
||||||
};
|
|
||||||
|
|
||||||
static char *
|
|
||||||
ether_str(struct sockaddr_dl *sdl)
|
|
||||||
{
|
|
||||||
static char hbuf[32];
|
|
||||||
u_char *cp;
|
|
||||||
|
|
||||||
if (sdl->sdl_alen && sdl->sdl_alen > 5) {
|
|
||||||
cp = (u_char *)LLADDR(sdl);
|
|
||||||
snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
|
|
||||||
cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
|
|
||||||
} else
|
|
||||||
snprintf(hbuf, sizeof(hbuf), "NONE");
|
|
||||||
|
|
||||||
return (hbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
if_dump(void)
|
|
||||||
{
|
|
||||||
struct rainfo *rai;
|
|
||||||
struct prefix *pfx;
|
|
||||||
#ifdef ROUTEINFO
|
|
||||||
struct rtinfo *rti;
|
|
||||||
#endif
|
|
||||||
struct rdnss *rdn;
|
|
||||||
struct dnssl *dns;
|
|
||||||
char prefixbuf[INET6_ADDRSTRLEN];
|
|
||||||
struct timeval now;
|
|
||||||
|
|
||||||
gettimeofday(&now, NULL); /* XXX: unused in most cases */
|
|
||||||
TAILQ_FOREACH(rai, &railist, rai_next) {
|
|
||||||
fprintf(fp, "%s:\n", rai->rai_ifname);
|
|
||||||
|
|
||||||
fprintf(fp, " Status: %s\n",
|
|
||||||
(iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) ? "UP" :
|
|
||||||
"DOWN");
|
|
||||||
|
|
||||||
/* control information */
|
|
||||||
if (rai->rai_lastsent.tv_sec) {
|
|
||||||
/* note that ctime() appends CR by itself */
|
|
||||||
fprintf(fp, " Last RA sent: %s",
|
|
||||||
ctime((time_t *)&rai->rai_lastsent.tv_sec));
|
|
||||||
}
|
|
||||||
if (rai->rai_timer)
|
|
||||||
fprintf(fp, " Next RA will be sent: %s",
|
|
||||||
ctime((time_t *)&rai->rai_timer->rat_tm.tv_sec));
|
|
||||||
else
|
|
||||||
fprintf(fp, " RA timer is stopped");
|
|
||||||
fprintf(fp, " waits: %d, initcount: %d\n",
|
|
||||||
rai->rai_waiting, rai->rai_initcounter);
|
|
||||||
|
|
||||||
/* statistics */
|
|
||||||
fprintf(fp, " statistics: RA(out/in/inconsistent): "
|
|
||||||
"%llu/%llu/%llu, ",
|
|
||||||
(unsigned long long)rai->rai_raoutput,
|
|
||||||
(unsigned long long)rai->rai_rainput,
|
|
||||||
(unsigned long long)rai->rai_rainconsistent);
|
|
||||||
fprintf(fp, "RS(input): %llu\n",
|
|
||||||
(unsigned long long)rai->rai_rsinput);
|
|
||||||
|
|
||||||
/* interface information */
|
|
||||||
if (rai->rai_advlinkopt)
|
|
||||||
fprintf(fp, " Link-layer address: %s\n",
|
|
||||||
ether_str(rai->rai_sdl));
|
|
||||||
fprintf(fp, " MTU: %d\n", rai->rai_phymtu);
|
|
||||||
|
|
||||||
/* Router configuration variables */
|
|
||||||
fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, "
|
|
||||||
"MinAdvInterval: %d\n", rai->rai_lifetime,
|
|
||||||
rai->rai_maxinterval, rai->rai_mininterval);
|
|
||||||
fprintf(fp, " Flags: ");
|
|
||||||
if (rai->rai_managedflg || rai->rai_otherflg) {
|
|
||||||
fprintf(fp, "%s", rai->rai_managedflg ? "M" : "");
|
|
||||||
fprintf(fp, "%s", rai->rai_otherflg ? "O" : "");
|
|
||||||
} else
|
|
||||||
fprintf(fp, "<none>");
|
|
||||||
fprintf(fp, ", ");
|
|
||||||
fprintf(fp, "Preference: %s, ",
|
|
||||||
rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
|
|
||||||
fprintf(fp, "MTU: %d\n", rai->rai_linkmtu);
|
|
||||||
fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
|
|
||||||
"CurHopLimit: %d\n", rai->rai_reachabletime,
|
|
||||||
rai->rai_retranstimer, rai->rai_hoplimit);
|
|
||||||
if (rai->rai_clockskew)
|
|
||||||
fprintf(fp, " Clock skew: %ldsec\n",
|
|
||||||
rai->rai_clockskew);
|
|
||||||
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
|
|
||||||
if (pfx == TAILQ_FIRST(&rai->rai_prefix))
|
|
||||||
fprintf(fp, " Prefixes:\n");
|
|
||||||
fprintf(fp, " %s/%d(",
|
|
||||||
inet_ntop(AF_INET6, &pfx->pfx_prefix, prefixbuf,
|
|
||||||
sizeof(prefixbuf)), pfx->pfx_prefixlen);
|
|
||||||
switch (pfx->pfx_origin) {
|
|
||||||
case PREFIX_FROM_KERNEL:
|
|
||||||
fprintf(fp, "KERNEL, ");
|
|
||||||
break;
|
|
||||||
case PREFIX_FROM_CONFIG:
|
|
||||||
fprintf(fp, "CONFIG, ");
|
|
||||||
break;
|
|
||||||
case PREFIX_FROM_DYNAMIC:
|
|
||||||
fprintf(fp, "DYNAMIC, ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME)
|
|
||||||
fprintf(fp, "vltime: infinity");
|
|
||||||
else
|
|
||||||
fprintf(fp, "vltime: %ld",
|
|
||||||
(long)pfx->pfx_validlifetime);
|
|
||||||
if (pfx->pfx_vltimeexpire != 0)
|
|
||||||
fprintf(fp, "(decr,expire %ld), ",
|
|
||||||
(long)pfx->pfx_vltimeexpire > now.tv_sec ?
|
|
||||||
(long)pfx->pfx_vltimeexpire - now.tv_sec :
|
|
||||||
0);
|
|
||||||
else
|
|
||||||
fprintf(fp, ", ");
|
|
||||||
if (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME)
|
|
||||||
fprintf(fp, "pltime: infinity");
|
|
||||||
else
|
|
||||||
fprintf(fp, "pltime: %ld",
|
|
||||||
(long)pfx->pfx_preflifetime);
|
|
||||||
if (pfx->pfx_pltimeexpire != 0)
|
|
||||||
fprintf(fp, "(decr,expire %ld), ",
|
|
||||||
(long)pfx->pfx_pltimeexpire > now.tv_sec ?
|
|
||||||
(long)pfx->pfx_pltimeexpire - now.tv_sec :
|
|
||||||
0);
|
|
||||||
else
|
|
||||||
fprintf(fp, ", ");
|
|
||||||
fprintf(fp, "flags: ");
|
|
||||||
if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
|
|
||||||
fprintf(fp, "%s",
|
|
||||||
pfx->pfx_onlinkflg ? "L" : "");
|
|
||||||
fprintf(fp, "%s",
|
|
||||||
pfx->pfx_autoconfflg ? "A" : "");
|
|
||||||
} else
|
|
||||||
fprintf(fp, "<none>");
|
|
||||||
if (pfx->pfx_timer) {
|
|
||||||
struct timeval *rest;
|
|
||||||
|
|
||||||
rest = rtadvd_timer_rest(pfx->pfx_timer);
|
|
||||||
if (rest) { /* XXX: what if not? */
|
|
||||||
fprintf(fp, ", expire in: %ld",
|
|
||||||
(long)rest->tv_sec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(fp, ")\n");
|
|
||||||
}
|
|
||||||
#ifdef ROUTEINFO
|
|
||||||
TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
|
|
||||||
if (rti == TAILQ_FIRST(&rai->rai_route))
|
|
||||||
fprintf(fp, " Route Information:\n");
|
|
||||||
fprintf(fp, " %s/%d (",
|
|
||||||
inet_ntop(AF_INET6, &rti->rti_prefix,
|
|
||||||
prefixbuf, sizeof(prefixbuf)),
|
|
||||||
rti->rti_prefixlen);
|
|
||||||
fprintf(fp, "preference: %s, ",
|
|
||||||
rtpref_str[0xff & (rti->rti_rtpref >> 3)]);
|
|
||||||
if (rti->rti_ltime == ND6_INFINITE_LIFETIME)
|
|
||||||
fprintf(fp, "lifetime: infinity");
|
|
||||||
else
|
|
||||||
fprintf(fp, "lifetime: %ld",
|
|
||||||
(long)rti->rti_ltime);
|
|
||||||
fprintf(fp, ")\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
|
|
||||||
struct rdnss_addr *rdna;
|
|
||||||
|
|
||||||
if (rdn == TAILQ_FIRST(&rai->rai_rdnss))
|
|
||||||
fprintf(fp, " Recursive DNS servers:\n"
|
|
||||||
" Lifetime\tServers\n");
|
|
||||||
|
|
||||||
fprintf(fp, " %8u\t", rdn->rd_ltime);
|
|
||||||
TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
|
|
||||||
inet_ntop(AF_INET6, &rdna->ra_dns,
|
|
||||||
prefixbuf, sizeof(prefixbuf));
|
|
||||||
|
|
||||||
if (rdna != TAILQ_FIRST(&rdn->rd_list))
|
|
||||||
fprintf(fp, " \t");
|
|
||||||
fprintf(fp, "%s\n", prefixbuf);
|
|
||||||
}
|
|
||||||
fprintf(fp, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
|
|
||||||
struct dnssl_addr *dnsa;
|
|
||||||
char buf[NI_MAXHOST];
|
|
||||||
|
|
||||||
if (dns == TAILQ_FIRST(&rai->rai_dnssl))
|
|
||||||
fprintf(fp, " DNS search list:\n"
|
|
||||||
" Lifetime\tDomains\n");
|
|
||||||
|
|
||||||
fprintf(fp, " %8u\t", dns->dn_ltime);
|
|
||||||
TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
|
|
||||||
dname_labeldec(buf, sizeof(buf), dnsa->da_dom);
|
|
||||||
if (dnsa != TAILQ_FIRST(&dns->dn_list))
|
|
||||||
fprintf(fp, " \t");
|
|
||||||
fprintf(fp, "%s(%d)\n", buf, dnsa->da_len);
|
|
||||||
}
|
|
||||||
fprintf(fp, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rtadvd_dump_file(const char *dumpfile)
|
|
||||||
{
|
|
||||||
syslog(LOG_DEBUG, "<%s> dump current status to %s", __func__,
|
|
||||||
dumpfile);
|
|
||||||
|
|
||||||
if ((fp = fopen(dumpfile, "w")) == NULL) {
|
|
||||||
syslog(LOG_WARNING, "<%s> open a dump file(%s)",
|
|
||||||
__func__, dumpfile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if_dump();
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
|
|
||||||
static size_t
|
|
||||||
dname_labeldec(char *dst, size_t dlen, const char *src)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
const char *src_origin;
|
|
||||||
const char *src_last;
|
|
||||||
const char *dst_origin;
|
|
||||||
|
|
||||||
src_origin = src;
|
|
||||||
src_last = strchr(src, '\0');
|
|
||||||
dst_origin = dst;
|
|
||||||
memset(dst, '\0', dlen);
|
|
||||||
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
|
|
||||||
(src + len) <= src_last) {
|
|
||||||
if (dst != dst_origin)
|
|
||||||
*dst++ = '.';
|
|
||||||
syslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
|
|
||||||
memcpy(dst, src, len);
|
|
||||||
src += len;
|
|
||||||
dst += len;
|
|
||||||
}
|
|
||||||
*dst = '\0';
|
|
||||||
|
|
||||||
return (src - src_origin);
|
|
||||||
}
|
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -35,19 +36,24 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_types.h>
|
|
||||||
#include <net/ethernet.h>
|
|
||||||
#include <ifaddrs.h>
|
|
||||||
#include <net/route.h>
|
|
||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#include <net/if_var.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <net/route.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
#include <netinet/icmp6.h>
|
#include <netinet/icmp6.h>
|
||||||
|
#include <netinet6/nd6.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
#include "rtadvd.h"
|
#include "rtadvd.h"
|
||||||
#include "if.h"
|
#include "if.h"
|
||||||
|
|
||||||
@ -59,14 +65,34 @@
|
|||||||
((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \
|
((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \
|
||||||
sizeof(u_long)))
|
sizeof(u_long)))
|
||||||
|
|
||||||
struct if_msghdr **iflist;
|
struct sockaddr_in6 sin6_linklocal_allnodes = {
|
||||||
int iflist_init_ok;
|
.sin6_len = sizeof(sin6_linklocal_allnodes),
|
||||||
size_t ifblock_size;
|
.sin6_family = AF_INET6,
|
||||||
char *ifblock;
|
.sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
|
||||||
|
};
|
||||||
|
|
||||||
static void get_iflist(char **buf, size_t *size);
|
struct sockaddr_in6 sin6_linklocal_allrouters = {
|
||||||
static void parse_iflist(struct if_msghdr ***ifmlist_p,
|
.sin6_len = sizeof(sin6_linklocal_allrouters),
|
||||||
char *buf, size_t bufsize);
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sockaddr_in6 sin6_sitelocal_allrouters = {
|
||||||
|
.sin6_len = sizeof(sin6_sitelocal_allrouters),
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sockinfo sock = { .si_fd = -1, .si_name = NULL };
|
||||||
|
struct sockinfo rtsock = { .si_fd = -1, .si_name = NULL };
|
||||||
|
struct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK };
|
||||||
|
|
||||||
|
char *mcastif;
|
||||||
|
|
||||||
|
static void get_rtaddrs(int, struct sockaddr *,
|
||||||
|
struct sockaddr **);
|
||||||
|
static struct if_msghdr *get_next_msghdr(struct if_msghdr *,
|
||||||
|
struct if_msghdr *);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
|
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
|
||||||
@ -83,133 +109,6 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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_version != RTM_VERSION) {
|
|
||||||
syslog(LOG_ERR,
|
|
||||||
"<%s> RTM_VERSION mismatch (%d != %d).",
|
|
||||||
__func__, ifm->ifm_version, RTM_VERSION);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
/* search failed */
|
|
||||||
free(buf);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
|
|
||||||
goto end;
|
|
||||||
memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
|
|
||||||
|
|
||||||
end:
|
|
||||||
free(buf);
|
|
||||||
return (ret_sdl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
if_getmtu(char *name)
|
|
||||||
{
|
|
||||||
struct ifaddrs *ifap, *ifa;
|
|
||||||
struct if_data *ifd;
|
|
||||||
u_long mtu = 0;
|
|
||||||
|
|
||||||
if (getifaddrs(&ifap) < 0)
|
|
||||||
return (0);
|
|
||||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
||||||
if (strcmp(ifa->ifa_name, name) == 0) {
|
|
||||||
ifd = ifa->ifa_data;
|
|
||||||
if (ifd)
|
|
||||||
mtu = ifd->ifi_mtu;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
freeifaddrs(ifap);
|
|
||||||
|
|
||||||
#ifdef SIOCGIFMTU /* XXX: this ifdef may not be necessary */
|
|
||||||
if (mtu == 0) {
|
|
||||||
struct ifreq ifr;
|
|
||||||
int s;
|
|
||||||
|
|
||||||
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET6;
|
|
||||||
strncpy(ifr.ifr_name, name,
|
|
||||||
sizeof(ifr.ifr_name));
|
|
||||||
if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
|
|
||||||
close(s);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
close(s);
|
|
||||||
|
|
||||||
mtu = ifr.ifr_mtu;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (mtu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* give interface index and its old flags, then new flags returned */
|
|
||||||
int
|
|
||||||
if_getflags(int ifindex, int oifflags)
|
|
||||||
{
|
|
||||||
struct ifreq ifr;
|
|
||||||
int s;
|
|
||||||
|
|
||||||
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
|
||||||
syslog(LOG_ERR, "<%s> socket: %s", __func__,
|
|
||||||
strerror(errno));
|
|
||||||
return (oifflags & ~IFF_UP);
|
|
||||||
}
|
|
||||||
|
|
||||||
if_indextoname(ifindex, ifr.ifr_name);
|
|
||||||
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
|
|
||||||
syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s",
|
|
||||||
__func__, ifr.ifr_name);
|
|
||||||
close(s);
|
|
||||||
return (oifflags & ~IFF_UP);
|
|
||||||
}
|
|
||||||
close(s);
|
|
||||||
return (ifr.ifr_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
|
#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
|
||||||
int
|
int
|
||||||
lladdropt_length(struct sockaddr_dl *sdl)
|
lladdropt_length(struct sockaddr_dl *sdl)
|
||||||
@ -377,48 +276,24 @@ get_rtm_ifindex(char *buf)
|
|||||||
return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
|
return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
get_ifm_ifindex(char *buf)
|
|
||||||
{
|
|
||||||
struct if_msghdr *ifm = (struct if_msghdr *)buf;
|
|
||||||
|
|
||||||
return ((int)ifm->ifm_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
get_ifam_ifindex(char *buf)
|
|
||||||
{
|
|
||||||
struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf;
|
|
||||||
|
|
||||||
return ((int)ifam->ifam_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
get_ifm_flags(char *buf)
|
|
||||||
{
|
|
||||||
struct if_msghdr *ifm = (struct if_msghdr *)buf;
|
|
||||||
|
|
||||||
return (ifm->ifm_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
get_prefixlen(char *buf)
|
get_prefixlen(char *buf)
|
||||||
{
|
{
|
||||||
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
|
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
|
||||||
struct sockaddr *sa, *rti_info[RTAX_MAX];
|
struct sockaddr *sa, *rti_info[RTAX_MAX];
|
||||||
u_char *p, *lim;
|
char *p, *lim;
|
||||||
|
|
||||||
sa = (struct sockaddr *)(rtm + 1);
|
sa = (struct sockaddr *)(rtm + 1);
|
||||||
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
|
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
|
||||||
sa = rti_info[RTAX_NETMASK];
|
sa = rti_info[RTAX_NETMASK];
|
||||||
|
|
||||||
p = (u_char *)(&SIN6(sa)->sin6_addr);
|
p = (char *)(&SIN6(sa)->sin6_addr);
|
||||||
lim = (u_char *)sa + sa->sa_len;
|
lim = (char *)sa + sa->sa_len;
|
||||||
return prefixlen(p, lim);
|
return prefixlen(p, lim);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
prefixlen(u_char *p, u_char *lim)
|
prefixlen(unsigned char *p, unsigned char *lim)
|
||||||
{
|
{
|
||||||
int masklen;
|
int masklen;
|
||||||
|
|
||||||
@ -458,140 +333,418 @@ prefixlen(u_char *p, u_char *lim)
|
|||||||
return (masklen);
|
return (masklen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
struct ifinfo *
|
||||||
rtmsg_type(char *buf)
|
update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname)
|
||||||
{
|
{
|
||||||
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
|
struct ifinfo *ifi;
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
return (rtm->rtm_type);
|
ifi = NULL;
|
||||||
}
|
ifindex = if_nametoindex(ifname);
|
||||||
|
TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
|
||||||
int
|
if (ifindex != 0) {
|
||||||
rtmsg_len(char *buf)
|
if (ifindex == ifi->ifi_ifindex)
|
||||||
{
|
break;
|
||||||
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
|
|
||||||
|
|
||||||
return (rtm->rtm_msglen);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ifmsg_len(char *buf)
|
|
||||||
{
|
|
||||||
struct if_msghdr *ifm = (struct if_msghdr *)buf;
|
|
||||||
|
|
||||||
return (ifm->ifm_msglen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* alloc buffer and get if_msghdrs block from kernel,
|
|
||||||
* and put them into the buffer
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
get_iflist(char **buf, size_t *size)
|
|
||||||
{
|
|
||||||
int mib[6];
|
|
||||||
|
|
||||||
mib[0] = CTL_NET;
|
|
||||||
mib[1] = PF_ROUTE;
|
|
||||||
mib[2] = 0;
|
|
||||||
mib[3] = AF_INET6;
|
|
||||||
mib[4] = NET_RT_IFLIST;
|
|
||||||
mib[5] = 0;
|
|
||||||
|
|
||||||
if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
|
|
||||||
syslog(LOG_ERR, "<%s> sysctl: iflist size get failed",
|
|
||||||
__func__);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if ((*buf = malloc(*size)) == NULL) {
|
|
||||||
syslog(LOG_ERR, "<%s> malloc failed", __func__);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
|
|
||||||
syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
|
|
||||||
__func__);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* alloc buffer and parse if_msghdrs block passed as arg,
|
|
||||||
* and init the buffer as list of pointers ot each of the if_msghdr.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
|
|
||||||
{
|
|
||||||
int iflentry_size, malloc_size;
|
|
||||||
struct if_msghdr *ifm;
|
|
||||||
struct ifa_msghdr *ifam;
|
|
||||||
char *lim;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Estimate least size of an iflist entry, to be obtained from kernel.
|
|
||||||
* Should add sizeof(sockaddr) ??
|
|
||||||
*/
|
|
||||||
iflentry_size = sizeof(struct if_msghdr);
|
|
||||||
/* roughly estimate max list size of pointers to each if_msghdr */
|
|
||||||
malloc_size = (bufsize/iflentry_size) * sizeof(size_t);
|
|
||||||
if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) {
|
|
||||||
syslog(LOG_ERR, "<%s> malloc failed", __func__);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
lim = buf + bufsize;
|
|
||||||
for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
|
|
||||||
if (ifm->ifm_msglen == 0) {
|
|
||||||
syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
|
|
||||||
"(buf=%p lim=%p ifm=%p)", __func__,
|
|
||||||
buf, lim, ifm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifm->ifm_type == RTM_IFINFO) {
|
|
||||||
(*ifmlist_p)[ifm->ifm_index] = ifm;
|
|
||||||
} else {
|
} else {
|
||||||
syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
|
if (strncmp(ifname, ifi->ifi_ifname,
|
||||||
"expected %d, got %d\n msglen = %d\n"
|
sizeof(ifi->ifi_ifname)) == 0)
|
||||||
"buf:%p, ifm:%p, lim:%p\n",
|
|
||||||
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
|
|
||||||
buf, ifm, lim);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
for (ifam = (struct ifa_msghdr *)
|
|
||||||
((char *)ifm + ifm->ifm_msglen);
|
|
||||||
ifam < (struct ifa_msghdr *)lim;
|
|
||||||
ifam = (struct ifa_msghdr *)
|
|
||||||
((char *)ifam + ifam->ifam_msglen)) {
|
|
||||||
/* just for safety */
|
|
||||||
if (!ifam->ifam_msglen) {
|
|
||||||
syslog(LOG_WARNING, "<%s> ifa_msglen is 0 "
|
|
||||||
"(buf=%p lim=%p ifam=%p)", __func__,
|
|
||||||
buf, lim, ifam);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ifam->ifam_type != RTM_NEWADDR)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ifm = (struct if_msghdr *)ifam;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ifi == NULL) {
|
||||||
|
/* A new ifinfo element is needed. */
|
||||||
|
syslog(LOG_DEBUG, "<%s> new entry: %s", __func__,
|
||||||
|
ifname);
|
||||||
|
|
||||||
|
ELM_MALLOC(ifi, exit(1));
|
||||||
|
ifi->ifi_ifindex = 0;
|
||||||
|
strncpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)-1);
|
||||||
|
ifi->ifi_ifname[sizeof(ifi->ifi_ifname)-1] = '\0';
|
||||||
|
ifi->ifi_rainfo = NULL;
|
||||||
|
ifi->ifi_state = IFI_STATE_UNCONFIGURED;
|
||||||
|
TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifi->ifi_persist = 1;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__,
|
||||||
|
ifi->ifi_ifname);
|
||||||
|
syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__,
|
||||||
|
ifi->ifi_ifname, ifi->ifi_state);
|
||||||
|
return (ifi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
init_iflist(void)
|
update_ifinfo_nd_flags(struct ifinfo *ifi)
|
||||||
{
|
{
|
||||||
syslog(LOG_DEBUG,
|
struct in6_ndireq nd;
|
||||||
"<%s> generate iflist.", __func__);
|
int s;
|
||||||
|
int error;
|
||||||
|
|
||||||
if (ifblock) {
|
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||||
free(ifblock);
|
syslog(LOG_ERR,
|
||||||
ifblock_size = 0;
|
"<%s> socket() failed.", __func__);
|
||||||
|
return (1);
|
||||||
}
|
}
|
||||||
if (iflist)
|
/* ND flags */
|
||||||
free(iflist);
|
memset(&nd, 0, sizeof(nd));
|
||||||
/* get iflist block from kernel */
|
strncpy(nd.ifname, ifi->ifi_ifname,
|
||||||
get_iflist(&ifblock, &ifblock_size);
|
sizeof(nd.ifname));
|
||||||
|
error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd);
|
||||||
|
if (error) {
|
||||||
|
close(s);
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> ioctl() failed.", __func__);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
ifi->ifi_nd_flags = nd.ndi.flags;
|
||||||
|
close(s);
|
||||||
|
|
||||||
/* make list of pointers to each if_msghdr */
|
return (0);
|
||||||
parse_iflist(&iflist, ifblock, ifblock_size);
|
}
|
||||||
|
|
||||||
|
struct ifinfo *
|
||||||
|
update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex)
|
||||||
|
{
|
||||||
|
struct if_msghdr *ifm;
|
||||||
|
struct ifinfo *ifi = NULL;
|
||||||
|
struct sockaddr *sa;
|
||||||
|
struct sockaddr *rti_info[RTAX_MAX];
|
||||||
|
char *msg;
|
||||||
|
size_t len;
|
||||||
|
char *lim;
|
||||||
|
int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 };
|
||||||
|
int error;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) <
|
||||||
|
0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> sysctl: NET_RT_IFLIST size get failed", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((msg = malloc(len)) == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> malloc failed", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) <
|
||||||
|
0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> sysctl: NET_RT_IFLIST get failed", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lim = msg + len;
|
||||||
|
for (ifm = (struct if_msghdr *)msg;
|
||||||
|
ifm != NULL && ifm < (struct if_msghdr *)lim;
|
||||||
|
ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) {
|
||||||
|
int ifi_new;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu",
|
||||||
|
__func__, ifm, lim, (char *)lim - (char *)ifm);
|
||||||
|
|
||||||
|
if (ifm->ifm_version != RTM_VERSION) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> ifm_vesrion mismatch", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (ifm->ifm_msglen == 0) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> ifm_msglen is 0", __func__);
|
||||||
|
free(msg);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifi_new = 0;
|
||||||
|
if (ifm->ifm_type == RTM_IFINFO) {
|
||||||
|
struct ifreq ifr;
|
||||||
|
int s;
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. "
|
||||||
|
"ifm_index = %d, ifindex = %d",
|
||||||
|
__func__, ifm->ifm_index, ifindex);
|
||||||
|
|
||||||
|
/* when ifindex is specified */
|
||||||
|
if (ifindex != UPDATE_IFINFO_ALL &&
|
||||||
|
ifindex != ifm->ifm_index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* lookup an entry with the same ifindex */
|
||||||
|
TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
|
||||||
|
if (ifm->ifm_index == ifi->ifi_ifindex)
|
||||||
|
break;
|
||||||
|
if_indextoname(ifm->ifm_index, ifname);
|
||||||
|
if (strncmp(ifname, ifi->ifi_ifname,
|
||||||
|
sizeof(ifname)) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> new entry for idx=%d",
|
||||||
|
__func__, ifm->ifm_index);
|
||||||
|
ELM_MALLOC(ifi, exit(1));
|
||||||
|
ifi->ifi_rainfo = NULL;
|
||||||
|
ifi->ifi_state = IFI_STATE_UNCONFIGURED;
|
||||||
|
ifi->ifi_persist = 0;
|
||||||
|
ifi_new = 1;
|
||||||
|
}
|
||||||
|
/* ifindex */
|
||||||
|
ifi->ifi_ifindex = ifm->ifm_index;
|
||||||
|
|
||||||
|
/* ifname */
|
||||||
|
if_indextoname(ifm->ifm_index, ifi->ifi_ifname);
|
||||||
|
if (ifi->ifi_ifname == NULL) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> ifname not found (idx=%d)",
|
||||||
|
__func__, ifm->ifm_index);
|
||||||
|
if (ifi_new)
|
||||||
|
free(ifi);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> socket() failed.", __func__);
|
||||||
|
if (ifi_new)
|
||||||
|
free(ifi);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MTU */
|
||||||
|
ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu;
|
||||||
|
if (ifi->ifi_phymtu == 0) {
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
ifr.ifr_addr.sa_family = AF_INET6;
|
||||||
|
strncpy(ifr.ifr_name, ifi->ifi_ifname,
|
||||||
|
sizeof(ifr.ifr_name));
|
||||||
|
error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr);
|
||||||
|
if (error) {
|
||||||
|
close(s);
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> ioctl() failed.",
|
||||||
|
__func__);
|
||||||
|
if (ifi_new)
|
||||||
|
free(ifi);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ifi->ifi_phymtu = ifr.ifr_mtu;
|
||||||
|
if (ifi->ifi_phymtu == 0) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> no interface mtu info"
|
||||||
|
" on %s. %d will be used.",
|
||||||
|
__func__, ifi->ifi_ifname,
|
||||||
|
IPV6_MMTU);
|
||||||
|
ifi->ifi_phymtu = IPV6_MMTU;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
|
||||||
|
/* ND flags */
|
||||||
|
error = update_ifinfo_nd_flags(ifi);
|
||||||
|
if (error) {
|
||||||
|
if (ifi_new)
|
||||||
|
free(ifi);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SDL */
|
||||||
|
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) {
|
||||||
|
memcpy(&ifi->ifi_sdl,
|
||||||
|
(struct sockaddr_dl *)sa,
|
||||||
|
sizeof(ifi->ifi_sdl));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
memset(&ifi->ifi_sdl, 0,
|
||||||
|
sizeof(ifi->ifi_sdl));
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ifi->ifi_flags = ifm->ifm_flags;
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
ifi->ifi_type = ifm->ifm_type;
|
||||||
|
} else {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"out of sync parsing NET_RT_IFLIST\n"
|
||||||
|
"expected %d, got %d\n msglen = %d\n",
|
||||||
|
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifi_new) {
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> adding %s(idx=%d) to ifilist",
|
||||||
|
__func__, ifi->ifi_ifname, ifi->ifi_ifindex);
|
||||||
|
TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(msg);
|
||||||
|
|
||||||
|
if (mcastif != NULL) {
|
||||||
|
error = sock_mc_rr_update(&sock, mcastif);
|
||||||
|
if (error)
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ifi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct if_msghdr *
|
||||||
|
get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim)
|
||||||
|
{
|
||||||
|
struct ifa_msghdr *ifam;
|
||||||
|
|
||||||
|
for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen);
|
||||||
|
ifam < (struct ifa_msghdr *)lim;
|
||||||
|
ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) {
|
||||||
|
if (!ifam->ifam_msglen) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"<%s> ifa_msglen is 0", __func__);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
if (ifam->ifam_type != RTM_NEWADDR)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((struct if_msghdr *)ifam);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
|
||||||
|
__func__, code,
|
||||||
|
strerror(errno));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
sock_mc_join(struct sockinfo *s, int ifindex)
|
||||||
|
{
|
||||||
|
struct ipv6_mreq mreq;
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (ifindex == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* join all routers multicast address on each advertising
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
memset(&mreq, 0, sizeof(mreq));
|
||||||
|
/* XXX */
|
||||||
|
memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
|
||||||
|
&sin6_linklocal_allrouters.sin6_addr,
|
||||||
|
sizeof(mreq.ipv6mr_multiaddr.s6_addr));
|
||||||
|
|
||||||
|
mreq.ipv6mr_interface = ifindex;
|
||||||
|
if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
|
||||||
|
sizeof(mreq)) < 0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> IPV6_JOIN_GROUP(link) on %s: %s",
|
||||||
|
__func__, if_indextoname(ifindex, ifname),
|
||||||
|
strerror(errno));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> %s: join link-local all-routers MC group",
|
||||||
|
__func__, if_indextoname(ifindex, ifname));
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sock_mc_leave(struct sockinfo *s, int ifindex)
|
||||||
|
{
|
||||||
|
struct ipv6_mreq mreq;
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (ifindex == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* join all routers multicast address on each advertising
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(&mreq, 0, sizeof(mreq));
|
||||||
|
/* XXX */
|
||||||
|
memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
|
||||||
|
&sin6_linklocal_allrouters.sin6_addr,
|
||||||
|
sizeof(mreq.ipv6mr_multiaddr.s6_addr));
|
||||||
|
|
||||||
|
mreq.ipv6mr_interface = ifindex;
|
||||||
|
if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
|
||||||
|
sizeof(mreq)) < 0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> IPV6_JOIN_LEAVE(link) on %s: %s",
|
||||||
|
__func__, if_indextoname(ifindex, ifname),
|
||||||
|
strerror(errno));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> %s: leave link-local all-routers MC group",
|
||||||
|
__func__, if_indextoname(ifindex, ifname));
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sock_mc_rr_update(struct sockinfo *s, char *mif)
|
||||||
|
{
|
||||||
|
struct ipv6_mreq mreq;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||||
|
|
||||||
|
if (mif == NULL)
|
||||||
|
return (1);
|
||||||
|
/*
|
||||||
|
* When attending router renumbering, join all-routers site-local
|
||||||
|
* multicast group.
|
||||||
|
*/
|
||||||
|
/* XXX */
|
||||||
|
memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
|
||||||
|
&sin6_sitelocal_allrouters.sin6_addr,
|
||||||
|
sizeof(mreq.ipv6mr_multiaddr.s6_addr));
|
||||||
|
if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> invalid interface: %s",
|
||||||
|
__func__, mif);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
|
||||||
|
&mreq, sizeof(mreq)) < 0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"<%s> IPV6_JOIN_GROUP(site) on %s: %s",
|
||||||
|
__func__, mif, strerror(errno));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> %s: join site-local all-routers MC group",
|
||||||
|
__func__, mif);
|
||||||
|
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -30,29 +30,32 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define RTADV_TYPE2BITMASK(type) (0x1 << type)
|
#define UPDATE_IFINFO_ALL 0
|
||||||
|
|
||||||
extern struct if_msghdr **iflist;
|
struct sockinfo {
|
||||||
extern size_t ifblock_size;
|
int si_fd;
|
||||||
extern char *ifblock;
|
const char *si_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct sockinfo sock;
|
||||||
|
extern struct sockinfo rtsock;
|
||||||
|
extern struct sockinfo ctrlsock;
|
||||||
|
|
||||||
struct nd_opt_hdr;
|
|
||||||
struct sockaddr_dl *if_nametosdl(char *);
|
|
||||||
int if_getmtu(char *);
|
|
||||||
int if_getflags(int, int);
|
|
||||||
int lladdropt_length(struct sockaddr_dl *);
|
int lladdropt_length(struct sockaddr_dl *);
|
||||||
void lladdropt_fill(struct sockaddr_dl *, struct nd_opt_hdr *);
|
void lladdropt_fill(struct sockaddr_dl *, struct nd_opt_hdr *);
|
||||||
int rtbuf_len(void);
|
int rtbuf_len(void);
|
||||||
char *get_next_msg(char *, char *, int, size_t *, int);
|
char *get_next_msg(char *, char *, int, size_t *, int);
|
||||||
struct in6_addr *get_addr(char *);
|
struct in6_addr *get_addr(char *);
|
||||||
int get_rtm_ifindex(char *);
|
int get_rtm_ifindex(char *);
|
||||||
int get_ifm_ifindex(char *);
|
|
||||||
int get_ifam_ifindex(char *);
|
|
||||||
int get_ifm_flags(char *);
|
|
||||||
int get_prefixlen(char *);
|
int get_prefixlen(char *);
|
||||||
int prefixlen(u_char *, u_char *);
|
int prefixlen(unsigned char *, unsigned char *);
|
||||||
int rtmsg_type(char *);
|
|
||||||
int ifmsg_type(char *);
|
struct ifinfo *update_ifinfo(struct ifilist_head_t *, int);
|
||||||
int rtmsg_len(char *);
|
int update_ifinfo_nd_flags(struct ifinfo *);
|
||||||
int ifmsg_len(char *);
|
struct ifinfo *update_persist_ifinfo(struct ifilist_head_t *,
|
||||||
void init_iflist(void);
|
const char *);
|
||||||
|
|
||||||
|
int sock_mc_join(struct sockinfo *, int);
|
||||||
|
int sock_mc_leave(struct sockinfo *, int);
|
||||||
|
int sock_mc_rr_update(struct sockinfo *, char *);
|
||||||
|
int getinet6sysctl(int);
|
||||||
|
@ -2,6 +2,5 @@
|
|||||||
/* $FreeBSD$ */
|
/* $FreeBSD$ */
|
||||||
|
|
||||||
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
|
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
|
||||||
#define _PATH_RTADVDDUMP "/var/run/rtadvd.dump"
|
|
||||||
#define _PATH_RTADVDPID "/var/run/rtadvd.pid"
|
#define _PATH_RTADVDPID "/var/run/rtadvd.pid"
|
||||||
|
#define _PATH_CTRL_SOCK "/var/run/rtadvd.sock"
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
#include <net/if_var.h>
|
#include <net/if_var.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@ -142,6 +143,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
|
|||||||
{
|
{
|
||||||
struct rr_pco_use *rpu, *rpulim;
|
struct rr_pco_use *rpu, *rpulim;
|
||||||
struct rainfo *rai;
|
struct rainfo *rai;
|
||||||
|
struct ifinfo *ifi;
|
||||||
struct prefix *pfx;
|
struct prefix *pfx;
|
||||||
|
|
||||||
rpu = (struct rr_pco_use *)(rpm + 1);
|
rpu = (struct rr_pco_use *)(rpm + 1);
|
||||||
@ -207,8 +209,10 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
|
|||||||
IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) &&
|
IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) &&
|
||||||
rpm->rpm_matchlen == rpu->rpu_uselen &&
|
rpm->rpm_matchlen == rpu->rpu_uselen &&
|
||||||
rpu->rpu_uselen == rpu->rpu_keeplen) {
|
rpu->rpu_uselen == rpu->rpu_keeplen) {
|
||||||
if ((rai = if_indextorainfo(ifindex)) == NULL)
|
ifi = if_indextoifinfo(ifindex);
|
||||||
|
if (ifi == NULL || ifi->ifi_rainfo == NULL)
|
||||||
continue; /* non-advertising IF */
|
continue; /* non-advertising IF */
|
||||||
|
rai = ifi->ifi_rainfo;
|
||||||
|
|
||||||
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
|
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
@ -250,7 +254,8 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
|
|||||||
{
|
{
|
||||||
int ifindex = 0;
|
int ifindex = 0;
|
||||||
struct in6_rrenumreq irr;
|
struct in6_rrenumreq irr;
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
|
||||||
if ((rr_pco_check(len, rpm) != 0))
|
if ((rr_pco_check(len, rpm) != 0))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
@ -270,12 +275,18 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
|
|||||||
irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
|
irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
|
||||||
|
|
||||||
while (if_indextoname(++ifindex, irr.irr_name)) {
|
while (if_indextoname(++ifindex, irr.irr_name)) {
|
||||||
|
ifi = if_indextoifinfo(ifindex);
|
||||||
|
if (ifi == NULL) {
|
||||||
|
syslog(LOG_ERR, "<%s> ifindex not found.",
|
||||||
|
__func__);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and
|
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and
|
||||||
* IFF_UP is off, the interface is not applied
|
* IFF_UP is off, the interface is not applied
|
||||||
*/
|
*/
|
||||||
if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
|
if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
|
||||||
(iflist[ifindex]->ifm_flags & IFF_UP) == 0)
|
(ifi->ifi_flags & IFF_UP) == 0)
|
||||||
continue;
|
continue;
|
||||||
/* TODO: interface scope check */
|
/* TODO: interface scope check */
|
||||||
do_use_prefix(len, rpm, &irr, ifindex);
|
do_use_prefix(len, rpm, &irr, ifindex);
|
||||||
@ -305,8 +316,7 @@ do_rr(int len, struct icmp6_router_renum *rr)
|
|||||||
cp = (char *)(rr + 1);
|
cp = (char *)(rr + 1);
|
||||||
len -= sizeof(struct icmp6_router_renum);
|
len -= sizeof(struct icmp6_router_renum);
|
||||||
|
|
||||||
/* get iflist block from kernel again, to get up-to-date information */
|
update_ifinfo(&ifilist, UPDATE_IFINFO_ALL);
|
||||||
init_iflist();
|
|
||||||
|
|
||||||
while (cp < lim) {
|
while (cp < lim) {
|
||||||
int rpmlen;
|
int rpmlen;
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd December 22, 2010
|
.Dd July 14, 2011
|
||||||
.Dt RTADVD 8
|
.Dt RTADVD 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -39,7 +39,6 @@
|
|||||||
.Nm
|
.Nm
|
||||||
.Op Fl dDfRs
|
.Op Fl dDfRs
|
||||||
.Op Fl c Ar configfile
|
.Op Fl c Ar configfile
|
||||||
.Op Fl F Ar dumpfile
|
|
||||||
.Op Fl M Ar ifname
|
.Op Fl M Ar ifname
|
||||||
.Op Fl p Ar pidfile
|
.Op Fl p Ar pidfile
|
||||||
.Ar interface ...
|
.Ar interface ...
|
||||||
@ -129,13 +128,6 @@ Even more debugging information is printed.
|
|||||||
.It Fl f
|
.It Fl f
|
||||||
Foreground mode (useful when debugging).
|
Foreground mode (useful when debugging).
|
||||||
Log messages will be dumped to stderr when this option is specified.
|
Log messages will be dumped to stderr when this option is specified.
|
||||||
.It Fl F
|
|
||||||
Specify an alternative file in which to dump internal states when
|
|
||||||
.Nm
|
|
||||||
receives signal
|
|
||||||
.Dv SIGUSR1 .
|
|
||||||
The default is
|
|
||||||
.Pa /var/run/rtadvd.dump .
|
|
||||||
.It Fl M
|
.It Fl M
|
||||||
Specify an interface to join the all-routers site-local multicast group.
|
Specify an interface to join the all-routers site-local multicast group.
|
||||||
By default,
|
By default,
|
||||||
@ -160,14 +152,6 @@ Do not add or delete prefixes dynamically.
|
|||||||
Only statically configured prefixes, if any, will be advertised.
|
Only statically configured prefixes, if any, will be advertised.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Upon receipt of signal
|
|
||||||
.Dv SIGUSR1 ,
|
|
||||||
.Nm
|
|
||||||
will dump the current internal state into
|
|
||||||
.Pa /var/run/rtadvd.dump
|
|
||||||
or the file specified with option
|
|
||||||
.Fl F .
|
|
||||||
.Pp
|
|
||||||
Use
|
Use
|
||||||
.Dv SIGHUP
|
.Dv SIGHUP
|
||||||
to reload the configuration file
|
to reload the configuration file
|
||||||
@ -196,10 +180,6 @@ to all the interfaces
|
|||||||
The default configuration file.
|
The default configuration file.
|
||||||
.It Pa /var/run/rtadvd.pid
|
.It Pa /var/run/rtadvd.pid
|
||||||
The default process ID file.
|
The default process ID file.
|
||||||
.It Pa /var/run/rtadvd.dump
|
|
||||||
The default file in which
|
|
||||||
.Nm
|
|
||||||
dumps its internal state.
|
|
||||||
.El
|
.El
|
||||||
.Sh EXIT STATUS
|
.Sh EXIT STATUS
|
||||||
.Ex -std
|
.Ex -std
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 1998 WIDE Project.
|
* Copyright (C) 1998 WIDE Project.
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -30,6 +31,17 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define ELM_MALLOC(p,error_action) \
|
||||||
|
do { \
|
||||||
|
p = malloc(sizeof(*p)); \
|
||||||
|
if (p == NULL) { \
|
||||||
|
syslog(LOG_ERR, "<%s> malloc failed: %s", \
|
||||||
|
__func__, strerror(errno)); \
|
||||||
|
error_action; \
|
||||||
|
} \
|
||||||
|
memset(p, 0, sizeof(*p)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
|
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
|
||||||
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
|
||||||
@ -101,28 +113,26 @@ struct prefix {
|
|||||||
*/
|
*/
|
||||||
struct rtadvd_timer *pfx_timer;
|
struct rtadvd_timer *pfx_timer;
|
||||||
|
|
||||||
u_int32_t pfx_validlifetime; /* AdvValidLifetime */
|
uint32_t pfx_validlifetime; /* AdvValidLifetime */
|
||||||
long pfx_vltimeexpire; /* Expiration of vltime */
|
uint32_t pfx_vltimeexpire; /* Expiration of vltime */
|
||||||
u_int32_t pfx_preflifetime; /* AdvPreferredLifetime */
|
uint32_t pfx_preflifetime; /* AdvPreferredLifetime */
|
||||||
long pfx_pltimeexpire; /* Expiration of pltime */
|
uint32_t pfx_pltimeexpire; /* Expiration of pltime */
|
||||||
u_int pfx_onlinkflg; /* bool: AdvOnLinkFlag */
|
int pfx_onlinkflg; /* bool: AdvOnLinkFlag */
|
||||||
u_int pfx_autoconfflg; /* bool: AdvAutonomousFlag */
|
int pfx_autoconfflg; /* bool: AdvAutonomousFlag */
|
||||||
int pfx_prefixlen;
|
int pfx_prefixlen;
|
||||||
int pfx_origin; /* From kernel or config */
|
int pfx_origin; /* From kernel or config */
|
||||||
|
|
||||||
struct in6_addr pfx_prefix;
|
struct in6_addr pfx_prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ROUTEINFO
|
|
||||||
struct rtinfo {
|
struct rtinfo {
|
||||||
TAILQ_ENTRY(rtinfo) rti_next;
|
TAILQ_ENTRY(rtinfo) rti_next;
|
||||||
|
|
||||||
u_int32_t rti_ltime; /* route lifetime */
|
uint32_t rti_ltime; /* route lifetime */
|
||||||
u_int rti_rtpref; /* route preference */
|
int rti_rtpref; /* route preference */
|
||||||
int rti_prefixlen;
|
int rti_prefixlen;
|
||||||
struct in6_addr rti_prefix;
|
struct in6_addr rti_prefix;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
struct rdnss_addr {
|
struct rdnss_addr {
|
||||||
TAILQ_ENTRY(rdnss_addr) ra_next;
|
TAILQ_ENTRY(rdnss_addr) ra_next;
|
||||||
@ -134,8 +144,7 @@ struct rdnss {
|
|||||||
TAILQ_ENTRY(rdnss) rd_next;
|
TAILQ_ENTRY(rdnss) rd_next;
|
||||||
|
|
||||||
TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
|
TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
|
||||||
int rd_cnt; /* number of DNS servers */
|
uint32_t rd_ltime; /* number of seconds valid */
|
||||||
u_int32_t rd_ltime; /* number of seconds valid */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -160,7 +169,7 @@ struct dnssl {
|
|||||||
TAILQ_ENTRY(dnssl) dn_next;
|
TAILQ_ENTRY(dnssl) dn_next;
|
||||||
|
|
||||||
TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
|
TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
|
||||||
u_int32_t dn_ltime; /* number of seconds valid */
|
uint32_t dn_ltime; /* number of seconds valid */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct soliciter {
|
struct soliciter {
|
||||||
@ -173,70 +182,117 @@ struct rainfo {
|
|||||||
/* pointer for list */
|
/* pointer for list */
|
||||||
TAILQ_ENTRY(rainfo) rai_next;
|
TAILQ_ENTRY(rainfo) rai_next;
|
||||||
|
|
||||||
/* timer related parameters */
|
|
||||||
struct rtadvd_timer *rai_timer;
|
|
||||||
/* counter for the first few advertisements */
|
|
||||||
int rai_initcounter;
|
|
||||||
/* timestamp when the latest RA was sent */
|
|
||||||
struct timeval rai_lastsent;
|
|
||||||
/* number of RS waiting for RA */
|
|
||||||
int rai_waiting;
|
|
||||||
|
|
||||||
/* interface information */
|
/* interface information */
|
||||||
int rai_ifindex;
|
struct ifinfo *rai_ifinfo;
|
||||||
int rai_advlinkopt; /* bool: whether include link-layer addr opt */
|
|
||||||
|
int rai_advlinkopt; /* bool: whether include link-layer addr opt */
|
||||||
int rai_advifprefix; /* bool: gather IF prefixes? */
|
int rai_advifprefix; /* bool: gather IF prefixes? */
|
||||||
struct sockaddr_dl *rai_sdl;
|
|
||||||
char rai_ifname[IFNAMSIZ];
|
|
||||||
u_int32_t rai_phymtu; /* mtu of the physical interface */
|
|
||||||
|
|
||||||
/* Router configuration variables */
|
/* Router configuration variables */
|
||||||
u_short rai_lifetime; /* AdvDefaultLifetime */
|
uint16_t rai_lifetime; /* AdvDefaultLifetime */
|
||||||
u_int rai_maxinterval; /* MaxRtrAdvInterval */
|
uint16_t rai_maxinterval; /* MaxRtrAdvInterval */
|
||||||
u_int rai_mininterval; /* MinRtrAdvInterval */
|
uint16_t rai_mininterval; /* MinRtrAdvInterval */
|
||||||
int rai_managedflg; /* AdvManagedFlag */
|
int rai_managedflg; /* AdvManagedFlag */
|
||||||
int rai_otherflg; /* AdvOtherConfigFlag */
|
int rai_otherflg; /* AdvOtherConfigFlag */
|
||||||
|
|
||||||
int rai_rtpref; /* router preference */
|
int rai_rtpref; /* router preference */
|
||||||
u_int32_t rai_linkmtu; /* AdvLinkMTU */
|
uint32_t rai_linkmtu; /* AdvLinkMTU */
|
||||||
u_int32_t rai_reachabletime; /* AdvReachableTime */
|
uint32_t rai_reachabletime; /* AdvReachableTime */
|
||||||
u_int32_t rai_retranstimer; /* AdvRetransTimer */
|
uint32_t rai_retranstimer; /* AdvRetransTimer */
|
||||||
u_int rai_hoplimit; /* AdvCurHopLimit */
|
uint8_t rai_hoplimit; /* AdvCurHopLimit */
|
||||||
|
|
||||||
TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */
|
TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */
|
||||||
int rai_pfxs; /* number of prefixes */
|
int rai_pfxs; /* number of prefixes */
|
||||||
|
|
||||||
long rai_clockskew; /* used for consisitency check of lifetimes */
|
uint16_t rai_clockskew; /* used for consisitency check of lifetimes */
|
||||||
|
|
||||||
TAILQ_HEAD(, rdnss) rai_rdnss; /* DNS server list */
|
TAILQ_HEAD(, rdnss) rai_rdnss; /* DNS server list */
|
||||||
TAILQ_HEAD(, dnssl) rai_dnssl; /* search domain list */
|
TAILQ_HEAD(, dnssl) rai_dnssl; /* search domain list */
|
||||||
#ifdef ROUTEINFO
|
|
||||||
TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */
|
TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */
|
||||||
int rai_routes; /* number of route information options */
|
int rai_routes; /* number of route information options */
|
||||||
#endif
|
|
||||||
/* actual RA packet data and its length */
|
/* actual RA packet data and its length */
|
||||||
size_t rai_ra_datalen;
|
size_t rai_ra_datalen;
|
||||||
u_char *rai_ra_data;
|
char *rai_ra_data;
|
||||||
|
|
||||||
/* statistics */
|
|
||||||
u_quad_t rai_raoutput; /* # of RAs sent */
|
|
||||||
u_quad_t rai_rainput; /* # of RAs received */
|
|
||||||
u_quad_t rai_rainconsistent; /* # of RAs inconsistent with ours */
|
|
||||||
u_quad_t rai_rsinput; /* # of RSs received */
|
|
||||||
|
|
||||||
/* info about soliciter */
|
/* info about soliciter */
|
||||||
TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
|
TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Interface list including RA information */
|
/* RA information list */
|
||||||
extern TAILQ_HEAD(railist_head_t, rainfo) railist;
|
extern TAILQ_HEAD(railist_head_t, rainfo) railist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ifi_state:
|
||||||
|
*
|
||||||
|
* (INIT)
|
||||||
|
* |
|
||||||
|
* | update_ifinfo()
|
||||||
|
* | update_persist_ifinfo()
|
||||||
|
* v
|
||||||
|
* UNCONFIGURED
|
||||||
|
* | ^
|
||||||
|
* loadconfig()| |rm_ifinfo(), ra_output()
|
||||||
|
* (MC join)| |(MC leave)
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* v |
|
||||||
|
* TRANSITIVE
|
||||||
|
* | ^
|
||||||
|
* ra_output()| |getconfig()
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* v |
|
||||||
|
* CONFIGURED
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define IFI_STATE_UNCONFIGURED 0
|
||||||
|
#define IFI_STATE_CONFIGURED 1
|
||||||
|
#define IFI_STATE_TRANSITIVE 2
|
||||||
|
|
||||||
|
struct ifinfo {
|
||||||
|
TAILQ_ENTRY(ifinfo) ifi_next;
|
||||||
|
|
||||||
|
uint16_t ifi_state;
|
||||||
|
uint16_t ifi_persist;
|
||||||
|
uint16_t ifi_ifindex;
|
||||||
|
char ifi_ifname[IFNAMSIZ];
|
||||||
|
uint8_t ifi_type;
|
||||||
|
uint16_t ifi_flags;
|
||||||
|
uint32_t ifi_nd_flags;
|
||||||
|
uint32_t ifi_phymtu;
|
||||||
|
struct sockaddr_dl ifi_sdl;
|
||||||
|
|
||||||
|
struct rainfo *ifi_rainfo;
|
||||||
|
struct rainfo *ifi_rainfo_trans;
|
||||||
|
uint16_t ifi_burstcount;
|
||||||
|
uint32_t ifi_burstinterval;
|
||||||
|
struct rtadvd_timer *ifi_ra_timer;
|
||||||
|
/* timestamp when the latest RA was sent */
|
||||||
|
struct timeval ifi_ra_lastsent;
|
||||||
|
uint16_t ifi_rs_waitcount;
|
||||||
|
|
||||||
|
/* statistics */
|
||||||
|
uint64_t ifi_raoutput; /* # of RAs sent */
|
||||||
|
uint64_t ifi_rainput; /* # of RAs received */
|
||||||
|
uint64_t ifi_rainconsistent; /* # of inconsistent recv'd RAs */
|
||||||
|
uint64_t ifi_rsinput; /* # of RSs received */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Interface list */
|
||||||
|
extern TAILQ_HEAD(ifilist_head_t, ifinfo) ifilist;
|
||||||
|
|
||||||
|
extern char *mcastif;
|
||||||
|
|
||||||
struct rtadvd_timer *ra_timeout(void *);
|
struct rtadvd_timer *ra_timeout(void *);
|
||||||
void ra_timer_update(void *, struct timeval *);
|
void ra_timer_update(void *, struct timeval *);
|
||||||
void ra_output(struct rainfo *);
|
void ra_output(struct ifinfo *);
|
||||||
|
|
||||||
int prefix_match(struct in6_addr *, int,
|
int prefix_match(struct in6_addr *, int,
|
||||||
struct in6_addr *, int);
|
struct in6_addr *, int);
|
||||||
struct rainfo *if_indextorainfo(int);
|
struct ifinfo *if_indextoifinfo(int);
|
||||||
struct prefix *find_prefix(struct rainfo *,
|
struct prefix *find_prefix(struct rainfo *,
|
||||||
struct in6_addr *, int);
|
struct in6_addr *, int);
|
||||||
|
void rtadvd_set_reload(int);
|
||||||
|
void rtadvd_set_shutdown(int);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 1998 WIDE Project.
|
* Copyright (C) 1998 WIDE Project.
|
||||||
|
* Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,15 +33,22 @@
|
|||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <search.h>
|
#include <search.h>
|
||||||
#include "timer.h"
|
#include <netdb.h>
|
||||||
|
|
||||||
#define MILLION 1000000
|
#include "rtadvd.h"
|
||||||
|
#include "timer_subr.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
struct rtadvd_timer_head_t ra_timer =
|
struct rtadvd_timer_head_t ra_timer =
|
||||||
TAILQ_HEAD_INITIALIZER(ra_timer);
|
TAILQ_HEAD_INITIALIZER(ra_timer);
|
||||||
@ -55,6 +63,43 @@ rtadvd_timer_init(void)
|
|||||||
TAILQ_INIT(&ra_timer);
|
TAILQ_INIT(&ra_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtadvd_update_timeout_handler(void)
|
||||||
|
{
|
||||||
|
struct ifinfo *ifi;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||||
|
switch (ifi->ifi_state) {
|
||||||
|
case IFI_STATE_CONFIGURED:
|
||||||
|
case IFI_STATE_TRANSITIVE:
|
||||||
|
if (ifi->ifi_ra_timer != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "<%s> add timer for %s (idx=%d)",
|
||||||
|
__func__, ifi->ifi_ifname, ifi->ifi_ifindex);
|
||||||
|
ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout,
|
||||||
|
ra_timer_update, ifi, ifi);
|
||||||
|
ra_timer_update((void *)ifi,
|
||||||
|
&ifi->ifi_ra_timer->rat_tm);
|
||||||
|
rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
|
||||||
|
ifi->ifi_ra_timer);
|
||||||
|
break;
|
||||||
|
case IFI_STATE_UNCONFIGURED:
|
||||||
|
if (ifi->ifi_ra_timer == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> remove timer for %s (idx=%d)", __func__,
|
||||||
|
ifi->ifi_ifname, ifi->ifi_ifindex);
|
||||||
|
rtadvd_remove_timer(ifi->ifi_ra_timer);
|
||||||
|
ifi->ifi_ra_timer = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct rtadvd_timer *
|
struct rtadvd_timer *
|
||||||
rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
|
rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
|
||||||
void (*update)(void *, struct timeval *),
|
void (*update)(void *, struct timeval *),
|
||||||
@ -99,22 +144,6 @@ rtadvd_remove_timer(struct rtadvd_timer *rat)
|
|||||||
free(rat);
|
free(rat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
|
|
||||||
{
|
|
||||||
struct timeval now;
|
|
||||||
|
|
||||||
/* reset the timer */
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
TIMEVAL_ADD(&now, tm, &rat->rat_tm);
|
|
||||||
|
|
||||||
/* update the next expiration time */
|
|
||||||
if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
|
|
||||||
tm_max = rat->rat_tm;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check expiration for each timer. If a timer expires,
|
* Check expiration for each timer. If a timer expires,
|
||||||
* call the expire function for the timer and update the timer.
|
* call the expire function for the timer and update the timer.
|
||||||
@ -151,55 +180,18 @@ rtadvd_check_timer(void)
|
|||||||
return (&returnval);
|
return (&returnval);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval *
|
void
|
||||||
rtadvd_timer_rest(struct rtadvd_timer *rat)
|
rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
|
||||||
{
|
{
|
||||||
static struct timeval returnval, now;
|
struct timeval now;
|
||||||
|
|
||||||
|
/* reset the timer */
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
|
TIMEVAL_ADD(&now, tm, &rat->rat_tm);
|
||||||
syslog(LOG_DEBUG,
|
|
||||||
"<%s> a timer must be expired, but not yet",
|
|
||||||
__func__);
|
|
||||||
returnval.tv_sec = returnval.tv_usec = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
|
|
||||||
|
|
||||||
return (&returnval);
|
/* update the next expiration time */
|
||||||
}
|
if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
|
||||||
|
tm_max = rat->rat_tm;
|
||||||
/* result = a + b */
|
|
||||||
void
|
return;
|
||||||
TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
|
|
||||||
{
|
|
||||||
long l;
|
|
||||||
|
|
||||||
if ((l = a->tv_usec + b->tv_usec) < MILLION) {
|
|
||||||
result->tv_usec = l;
|
|
||||||
result->tv_sec = a->tv_sec + b->tv_sec;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result->tv_usec = l - MILLION;
|
|
||||||
result->tv_sec = a->tv_sec + b->tv_sec + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* result = a - b
|
|
||||||
* XXX: this function assumes that a >= b.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
|
|
||||||
{
|
|
||||||
long l;
|
|
||||||
|
|
||||||
if ((l = a->tv_usec - b->tv_usec) >= 0) {
|
|
||||||
result->tv_usec = l;
|
|
||||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result->tv_usec = MILLION + l;
|
|
||||||
result->tv_sec = a->tv_sec - b->tv_sec - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -30,22 +30,6 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* a < b */
|
|
||||||
#define TIMEVAL_LT(a, b) \
|
|
||||||
(((a)->tv_sec < (b)->tv_sec) || \
|
|
||||||
(((a)->tv_sec == (b)->tv_sec) && \
|
|
||||||
((a)->tv_usec < (b)->tv_usec)))
|
|
||||||
|
|
||||||
/* a <= b */
|
|
||||||
#define TIMEVAL_LEQ(a, b) \
|
|
||||||
(((a)->tv_sec < (b)->tv_sec) || \
|
|
||||||
(((a)->tv_sec == (b)->tv_sec) && \
|
|
||||||
((a)->tv_usec <= (b)->tv_usec)))
|
|
||||||
|
|
||||||
#define TIMEVAL_EQUAL(a,b) \
|
|
||||||
(((a)->tv_sec == (b)->tv_sec) && \
|
|
||||||
((a)->tv_usec == (b)->tv_usec))
|
|
||||||
|
|
||||||
extern TAILQ_HEAD(rtadvd_timer_head_t, rtadvd_timer) ra_timer;
|
extern TAILQ_HEAD(rtadvd_timer_head_t, rtadvd_timer) ra_timer;
|
||||||
struct rtadvd_timer {
|
struct rtadvd_timer {
|
||||||
TAILQ_ENTRY(rtadvd_timer) rat_next;
|
TAILQ_ENTRY(rtadvd_timer) rat_next;
|
||||||
@ -59,14 +43,10 @@ struct rtadvd_timer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void rtadvd_timer_init(void);
|
void rtadvd_timer_init(void);
|
||||||
|
void rtadvd_update_timeout_handler(void);
|
||||||
struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
|
struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
|
||||||
void (*)(void *, struct timeval *), void *, void *);
|
void (*)(void *, struct timeval *), void *, void *);
|
||||||
void rtadvd_set_timer(struct timeval *,
|
void rtadvd_set_timer(struct timeval *,
|
||||||
struct rtadvd_timer *);
|
struct rtadvd_timer *);
|
||||||
void rtadvd_remove_timer(struct rtadvd_timer *);
|
void rtadvd_remove_timer(struct rtadvd_timer *);
|
||||||
struct timeval *rtadvd_check_timer(void);
|
struct timeval *rtadvd_check_timer(void);
|
||||||
struct timeval *rtadvd_timer_rest(struct rtadvd_timer *);
|
|
||||||
void TIMEVAL_ADD(struct timeval *, struct timeval *,
|
|
||||||
struct timeval *);
|
|
||||||
void TIMEVAL_SUB(struct timeval *, struct timeval *,
|
|
||||||
struct timeval *);
|
|
||||||
|
126
usr.sbin/rtadvd/timer_subr.c
Normal file
126
usr.sbin/rtadvd/timer_subr.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/* $FreeBSD$ */
|
||||||
|
/* $KAME: timer.c,v 1.9 2002/06/10 19:59:47 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/time.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "timer.h"
|
||||||
|
#include "timer_subr.h"
|
||||||
|
|
||||||
|
struct timeval *
|
||||||
|
rtadvd_timer_rest(struct rtadvd_timer *rat)
|
||||||
|
{
|
||||||
|
static struct timeval returnval, now;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
|
||||||
|
syslog(LOG_DEBUG,
|
||||||
|
"<%s> a timer must be expired, but not yet",
|
||||||
|
__func__);
|
||||||
|
returnval.tv_sec = returnval.tv_usec = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
|
||||||
|
|
||||||
|
return (&returnval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* result = a + b */
|
||||||
|
void
|
||||||
|
TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
|
||||||
|
{
|
||||||
|
long l;
|
||||||
|
|
||||||
|
if ((l = a->tv_usec + b->tv_usec) < MILLION) {
|
||||||
|
result->tv_usec = l;
|
||||||
|
result->tv_sec = a->tv_sec + b->tv_sec;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result->tv_usec = l - MILLION;
|
||||||
|
result->tv_sec = a->tv_sec + b->tv_sec + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* result = a - b
|
||||||
|
* XXX: this function assumes that a >= b.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
|
||||||
|
{
|
||||||
|
long l;
|
||||||
|
|
||||||
|
if ((l = a->tv_usec - b->tv_usec) >= 0) {
|
||||||
|
result->tv_usec = l;
|
||||||
|
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result->tv_usec = MILLION + l;
|
||||||
|
result->tv_sec = a->tv_sec - b->tv_sec - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
sec2str(uint32_t s, char *buf)
|
||||||
|
{
|
||||||
|
uint32_t day;
|
||||||
|
uint32_t hour;
|
||||||
|
uint32_t min;
|
||||||
|
uint32_t sec;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
min = s / 60;
|
||||||
|
sec = s % 60;
|
||||||
|
|
||||||
|
hour = min / 60;
|
||||||
|
min = min % 60;
|
||||||
|
|
||||||
|
day = hour / 24;
|
||||||
|
hour = hour % 24;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
if (day > 0)
|
||||||
|
p += sprintf(p, "%" PRIu32 "d", day);
|
||||||
|
if (hour > 0)
|
||||||
|
p += sprintf(p, "%" PRIu32 "h", hour);
|
||||||
|
if (min > 0)
|
||||||
|
p += sprintf(p, "%" PRIu32 "m", min);
|
||||||
|
|
||||||
|
if ((p == buf) || (sec > 0 && p > buf))
|
||||||
|
sprintf(p, "%" PRIu32 "s", sec);
|
||||||
|
|
||||||
|
return (buf);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/* $FreeBSD$ */
|
/* $FreeBSD$ */
|
||||||
/* $KAME: dump.h,v 1.1 2000/05/23 11:31:26 itojun Exp $ */
|
/* $KAME: timer.h,v 1.5 2002/05/31 13:30:38 jinmei Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 1998 WIDE Project.
|
* Copyright (C) 1998 WIDE Project.
|
||||||
@ -30,4 +30,28 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern void rtadvd_dump_file(const char *);
|
#define SSBUFLEN 1024
|
||||||
|
#define MILLION 1000000
|
||||||
|
|
||||||
|
/* a < b */
|
||||||
|
#define TIMEVAL_LT(a, b) \
|
||||||
|
(((a)->tv_sec < (b)->tv_sec) || \
|
||||||
|
(((a)->tv_sec == (b)->tv_sec) && \
|
||||||
|
((a)->tv_usec < (b)->tv_usec)))
|
||||||
|
|
||||||
|
/* a <= b */
|
||||||
|
#define TIMEVAL_LEQ(a, b) \
|
||||||
|
(((a)->tv_sec < (b)->tv_sec) || \
|
||||||
|
(((a)->tv_sec == (b)->tv_sec) && \
|
||||||
|
((a)->tv_usec <= (b)->tv_usec)))
|
||||||
|
|
||||||
|
#define TIMEVAL_EQUAL(a,b) \
|
||||||
|
(((a)->tv_sec == (b)->tv_sec) && \
|
||||||
|
((a)->tv_usec == (b)->tv_usec))
|
||||||
|
|
||||||
|
struct timeval *rtadvd_timer_rest(struct rtadvd_timer *);
|
||||||
|
void TIMEVAL_ADD(struct timeval *, struct timeval *,
|
||||||
|
struct timeval *);
|
||||||
|
void TIMEVAL_SUB(struct timeval *, struct timeval *,
|
||||||
|
struct timeval *);
|
||||||
|
char *sec2str(uint32_t, char *buf);
|
Loading…
Reference in New Issue
Block a user