summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>2000-01-06 12:40:54 +0000
committershin <shin@FreeBSD.org>2000-01-06 12:40:54 +0000
commit9b5932fc47f3a7c965da9d2e15425aabc7f7dd26 (patch)
treebffabec553873cccf6ad30da0425fe8c806387da
parentf1787f2960aaad85fe0cce147b1d910ca08c1055 (diff)
downloadFreeBSD-src-9b5932fc47f3a7c965da9d2e15425aabc7f7dd26.zip
FreeBSD-src-9b5932fc47f3a7c965da9d2e15425aabc7f7dd26.tar.gz
libipsec and IPsec related apps. (and some KAME related man pages)
Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project
-rw-r--r--lib/Makefile3
-rw-r--r--lib/libipsec/Makefile50
-rw-r--r--lib/libipsec/ipsec_dump_policy.c253
-rw-r--r--lib/libipsec/ipsec_get_policylen.c44
-rw-r--r--lib/libipsec/ipsec_set_policy.3253
-rw-r--r--lib/libipsec/ipsec_strerror.366
-rw-r--r--lib/libipsec/ipsec_strerror.c87
-rw-r--r--lib/libipsec/ipsec_strerror.h62
-rw-r--r--lib/libipsec/pfkey.c1421
-rw-r--r--lib/libipsec/pfkey_dump.c463
-rw-r--r--lib/libipsec/policy_parse.y426
-rw-r--r--lib/libipsec/policy_token.l137
-rw-r--r--lib/libipsec/test-policy.c179
-rw-r--r--sbin/ping/Makefile5
-rw-r--r--sbin/ping/ping.88
-rw-r--r--sbin/ping/ping.c71
-rw-r--r--sbin/setkey/Makefile56
-rw-r--r--sbin/setkey/parse.y787
-rw-r--r--sbin/setkey/sample.cf219
-rw-r--r--sbin/setkey/scriptdump.pl54
-rw-r--r--sbin/setkey/setkey.8550
-rw-r--r--sbin/setkey/setkey.c566
-rw-r--r--sbin/setkey/test-pfkey.c480
-rw-r--r--sbin/setkey/test-policy.c161
-rw-r--r--sbin/setkey/token.l322
-rw-r--r--sbin/setkey/vchar.h35
-rw-r--r--share/man/man4/Makefile6
-rw-r--r--share/man/man4/faith.4122
-rw-r--r--share/man/man4/gif.4232
-rw-r--r--share/man/man4/inet6.4287
-rw-r--r--share/man/man4/ipsec.4228
-rw-r--r--share/man/man4/kame.4217
-rw-r--r--usr.bin/netstat/Makefile2
-rw-r--r--usr.sbin/Makefile4
-rw-r--r--usr.sbin/ndp/Makefile25
-rw-r--r--usr.sbin/ndp/gnuc.h2
-rw-r--r--usr.sbin/ndp/ndp.8138
-rw-r--r--usr.sbin/ndp/ndp.c1028
-rw-r--r--usr.sbin/rrenumd/Makefile41
-rw-r--r--usr.sbin/rrenumd/lexer.l248
-rw-r--r--usr.sbin/rrenumd/parser.y637
-rw-r--r--usr.sbin/rrenumd/rrenumd.895
-rw-r--r--usr.sbin/rrenumd/rrenumd.c460
-rw-r--r--usr.sbin/rrenumd/rrenumd.conf.5330
-rw-r--r--usr.sbin/rrenumd/rrenumd.h57
-rw-r--r--usr.sbin/rtadvd/Makefile26
-rw-r--r--usr.sbin/rtadvd/advcap.c452
-rw-r--r--usr.sbin/rtadvd/advcap.h45
-rw-r--r--usr.sbin/rtadvd/config.c639
-rw-r--r--usr.sbin/rtadvd/config.h34
-rw-r--r--usr.sbin/rtadvd/if.c556
-rw-r--r--usr.sbin/rtadvd/if.h57
-rw-r--r--usr.sbin/rtadvd/pathnames.h2
-rw-r--r--usr.sbin/rtadvd/rrenum.c414
-rw-r--r--usr.sbin/rtadvd/rrenum.h34
-rw-r--r--usr.sbin/rtadvd/rtadvd.8134
-rw-r--r--usr.sbin/rtadvd/rtadvd.c1239
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf14
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf.5250
-rw-r--r--usr.sbin/rtadvd/rtadvd.h107
-rw-r--r--usr.sbin/rtadvd/timer.c201
-rw-r--r--usr.sbin/rtadvd/timer.h63
-rw-r--r--usr.sbin/setkey/Makefile56
-rw-r--r--usr.sbin/setkey/parse.y787
-rw-r--r--usr.sbin/setkey/sample.cf219
-rw-r--r--usr.sbin/setkey/scriptdump.pl54
-rw-r--r--usr.sbin/setkey/setkey.8550
-rw-r--r--usr.sbin/setkey/setkey.c566
-rw-r--r--usr.sbin/setkey/test-pfkey.c480
-rw-r--r--usr.sbin/setkey/test-policy.c161
-rw-r--r--usr.sbin/setkey/token.l322
-rw-r--r--usr.sbin/setkey/vchar.h35
-rw-r--r--usr.sbin/traceroute6/Makefile4
73 files changed, 18408 insertions, 10 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 66fb360..6f3622d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -21,7 +21,8 @@ SUBDIR= ${_csu} libcom_err ${_libm} libmd ${_libcrypt} \
libncurses libradius libskey libtacplus \
${_compat} libalias libatm ${_libbind} libc ${_libc_r} libcalendar \
libcam libcompat libdevstat libdisk libedit libfetch libform \
- libftpio libgnumalloc ${_libio} libipx libkvm libmenu ${_libncp} \
+ libftpio libgnumalloc ${_libio} libipsec libipx libkvm libmenu \
+ ${_libncp} \
libnetgraph libopie libpam libpanel libpcap libresolv librpcsvc libss \
libstand ${_libtelnet} libutil ${_libvgl} libwrap libxpg4 liby libz
diff --git a/lib/libipsec/Makefile b/lib/libipsec/Makefile
new file mode 100644
index 0000000..963e96d
--- /dev/null
+++ b/lib/libipsec/Makefile
@@ -0,0 +1,50 @@
+# Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+# $FreeBSD$
+
+LIB= ipsec
+CFLAGS+=-I${.OBJDIR}
+CFLAGS+=-DIPSEC_DEBUG -DIPSEC -DINET6
+
+.PATH: ${.CURDIR}/../../sys/netkey
+SRCS= pfkey.c pfkey_dump.c
+SRCS+= ipsec_strerror.c policy_parse.y policy_token.l
+SRCS+= ipsec_dump_policy.c ipsec_get_policylen.c
+SRCS+= key_debug.c
+LDADD+= -ll -ly
+CLEANFILES+= y.tab.c y.tab.h
+YFLAGS+=-d -p __libyy
+LFLAGS+=-P__libyy
+
+MAN3= ipsec_set_policy.3 ipsec_strerror.3
+MLINKS+=ipsec_set_policy.3 ipsec_get_policylen.3 \
+ ipsec_set_policy.3 ipsec_dump_policy.3
+
+SRCS+= y.tab.h
+y.tab.h: policy_parse.y
+
+.include <bsd.lib.mk>
diff --git a/lib/libipsec/ipsec_dump_policy.c b/lib/libipsec/ipsec_dump_policy.c
new file mode 100644
index 0000000..a9ef2f5
--- /dev/null
+++ b/lib/libipsec/ipsec_dump_policy.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netkey/key_var.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+
+static const char *ipsp_dir_strs[] = {
+ "any", "in", "out",
+};
+
+static const char *ipsp_policy_strs[] = {
+ "discard", "none", "ipsec", "entrust", "bypass",
+};
+
+static int set_addresses __P((char *buf, caddr_t ptr));
+
+/*
+ * policy is sadb_x_policy buffer.
+ * Must call free() later.
+ * When delimiter == NULL, alternatively ' '(space) is applied.
+ */
+char *
+ipsec_dump_policy(policy, delimiter)
+ caddr_t policy;
+ char *delimiter;
+{
+ struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy;
+ struct sadb_x_ipsecrequest *xisr;
+ int xtlen, buflen;
+ char *buf;
+ int error;
+
+ /* sanity check */
+ if (policy == NULL)
+ return NULL;
+ if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
+ ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return NULL;
+ }
+
+ /* set delimiter */
+ if (delimiter == NULL)
+ delimiter = " ";
+
+ switch (xpl->sadb_x_policy_dir) {
+ case IPSEC_DIR_ANY:
+ case IPSEC_DIR_INBOUND:
+ case IPSEC_DIR_OUTBOUND:
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_DIR;
+ return NULL;
+ }
+
+ switch (xpl->sadb_x_policy_type) {
+ case IPSEC_POLICY_DISCARD:
+ case IPSEC_POLICY_NONE:
+ case IPSEC_POLICY_IPSEC:
+ case IPSEC_POLICY_BYPASS:
+ case IPSEC_POLICY_ENTRUST:
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_POLICY;
+ return NULL;
+ }
+
+ buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
+ + 1 /* space */
+ + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
+ + 1; /* NUL */
+
+ if ((buf = malloc(buflen)) == NULL) {
+ ipsec_errcode = EIPSEC_NO_BUFS;
+ return NULL;
+ }
+ strcpy(buf, ipsp_dir_strs[xpl->sadb_x_policy_dir]);
+ strcat(buf, " ");
+ strcat(buf, ipsp_policy_strs[xpl->sadb_x_policy_type]);
+
+ if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return buf;
+ }
+
+ xtlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl);
+ xisr = (struct sadb_x_ipsecrequest *)(xpl + 1);
+
+ /* count length of buffer for use */
+ /* XXX non-seriously */
+ while (xtlen > 0) {
+ buflen += 20;
+ if (xisr->sadb_x_ipsecrequest_mode ==IPSEC_MODE_TUNNEL)
+ buflen += 50;
+ xtlen -= xisr->sadb_x_ipsecrequest_len;
+ xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr
+ + xisr->sadb_x_ipsecrequest_len);
+ }
+
+ /* validity check */
+ if (xtlen < 0) {
+ ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+ free(buf);
+ return NULL;
+ }
+
+ if ((buf = realloc(buf, buflen)) == NULL) {
+ ipsec_errcode = EIPSEC_NO_BUFS;
+ return NULL;
+ }
+
+ xtlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl);
+ xisr = (struct sadb_x_ipsecrequest *)(xpl + 1);
+
+ while (xtlen > 0) {
+ strcat(buf, delimiter);
+
+ switch (xisr->sadb_x_ipsecrequest_proto) {
+ case IPPROTO_ESP:
+ strcat(buf, "esp");
+ break;
+ case IPPROTO_AH:
+ strcat(buf, "ah");
+ break;
+ case IPPROTO_IPCOMP:
+ strcat(buf, "ipcomp");
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_PROTO;
+ free(buf);
+ return NULL;
+ }
+
+ strcat(buf, "/");
+
+ switch (xisr->sadb_x_ipsecrequest_mode) {
+ case IPSEC_MODE_ANY:
+ strcat(buf, "any");
+ break;
+ case IPSEC_MODE_TRANSPORT:
+ strcat(buf, "transport");
+ break;
+ case IPSEC_MODE_TUNNEL:
+ strcat(buf, "tunnel");
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_MODE;
+ free(buf);
+ return NULL;
+ }
+
+ strcat(buf, "/");
+
+ if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+ error = set_addresses(buf, (caddr_t)(xisr + 1));
+ if (error) {
+ ipsec_errcode = EIPSEC_INVAL_MODE;
+ free(buf);
+ return NULL;
+ }
+ }
+
+ switch (xisr->sadb_x_ipsecrequest_level) {
+ case IPSEC_LEVEL_DEFAULT:
+ strcat(buf, "/default");
+ break;
+ case IPSEC_LEVEL_USE:
+ strcat(buf, "/use");
+ break;
+ case IPSEC_LEVEL_REQUIRE:
+ strcat(buf, "/require");
+ break;
+ case IPSEC_LEVEL_UNIQUE:
+ strcat(buf, "/unique");
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_LEVEL;
+ free(buf);
+ return NULL;
+ }
+
+ xtlen -= xisr->sadb_x_ipsecrequest_len;
+ xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr
+ + xisr->sadb_x_ipsecrequest_len);
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return buf;
+}
+
+static int
+set_addresses(buf, ptr)
+ char *buf;
+ caddr_t ptr;
+{
+ char tmp[100]; /* XXX */
+ struct sockaddr *saddr = (struct sockaddr *)ptr;
+
+ getnameinfo(saddr, saddr->sa_len, tmp, sizeof(tmp),
+ NULL, 0, NI_NUMERICHOST);
+
+ strcat(buf, tmp);
+
+ strcat(buf, "-");
+
+ saddr = (struct sockaddr *)((caddr_t)saddr + saddr->sa_len);
+ getnameinfo(saddr, saddr->sa_len, tmp, sizeof(tmp),
+ NULL, 0, NI_NUMERICHOST);
+
+ strcat(buf, tmp);
+
+ return 0;
+}
diff --git a/lib/libipsec/ipsec_get_policylen.c b/lib/libipsec/ipsec_get_policylen.c
new file mode 100644
index 0000000..a8a3e5d
--- /dev/null
+++ b/lib/libipsec/ipsec_get_policylen.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <net/pfkeyv2.h>
+
+#include "ipsec_strerror.h"
+
+int
+ipsec_get_policylen(policy)
+ caddr_t policy;
+{
+ return policy ? PFKEY_EXTLEN(policy) : -1;
+}
diff --git a/lib/libipsec/ipsec_set_policy.3 b/lib/libipsec/ipsec_set_policy.3
new file mode 100644
index 0000000..559d5fa
--- /dev/null
+++ b/lib/libipsec/ipsec_set_policy.3
@@ -0,0 +1,253 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ipsec_set_policy.3,v 1.5 1999/10/20 00:21:06 sakane Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 5, 1998
+.Dt IPSEC_SET_POLICY 3
+.Os KAME
+.\"
+.Sh NAME
+.Nm ipsec_set_policy ,
+.Nm ipsec_get_policylen ,
+.Nm ipsec_dump_policy
+.Nd manipulate IPsec policy specification structure from readable string
+.\"
+.Sh SYNOPSIS
+.Fd #include <netinet6/ipsec.h>
+.Ft "char *"
+.Fn ipsec_set_policy "char *policy" "int len"
+.Ft int
+.Fn ipsec_get_policylen "char *buf"
+.Ft "char *"
+.Fn ipsec_dump_policy "char *buf" "char *delim"
+.\"
+.Sh DESCRIPTION
+.Fn ipsec_set_policy
+generates IPsec policy specification structure, namely
+.Li struct sadb_x_policy
+and/or
+.Li struct sadb_x_ipsecrequest
+from human-readable policy specification.
+policy specification must be given as C string
+.Fa policy
+and length
+.Fa len
+of
+.Fa policy .
+.Fn ipsec_set_policy
+will return the buffer of IPsec policy specification structure.
+.Pp
+You may want the length of the generated buffer such when calling
+.Xr setsockopt 2 .
+.Fn ipsec_get_policylen
+will return the length.
+.Pp
+.Fn ipsec_dump_policy
+converts IPsec policy structure into readable form.
+Therefore,
+.Fn ipsec_dump_policy
+can be regarded as inverse conversion of
+.Fn ipsec_set_policy .
+.Fa buf
+points to a IPsec policy structure,
+.Li struct sadb_x_policy .
+.Fa delim
+is a delimiter string, which is usually a blank character.
+If you set
+.Fa delim
+to
+.Dv NULL ,
+single whitespace is assumed.
+.Fn ipsec_dump_policy
+returns pointer to dynamically allocated string.
+It is caller's responsibility to reclaim the region, by using
+.Xr free 3 .
+.Pp
+.\"
+.Fa policy
+is formatted as either of the following:
+.Bl -tag -width "discard"
+.It Ar direction Li entrust
+.Ar direction
+must be
+.Li in
+or
+.Li out .
+.Ar direction
+specifies which direction the policy needs to be applied.
+.Li entrust
+means to consult to SPD defined by
+.Xr setkey 8 .
+.It Ar direction Li bypass
+.Li bypass
+means to be bypassed the IPsec processing.
+.Po
+packet will be transmitted in clear
+.Pc .
+This is for privileged socket.
+.It Xo
+.Ar direction
+.Li ipsec
+.Ar request ...
+.Xc
+.Li ipsec
+means that the matching packets are subject to IPsec processing.
+.Li ipsec
+can be followed by one or more
+.Ar request
+string, which is formatted as below:
+.Bl -tag -width "discard"
+.It Xo
+.Ar protocol
+.Li /
+.Ar mode
+.Li /
+.Ar src
+.Li -
+.Ar dst
+.Op Ar /level
+.Xc
+.Ar protocol
+is either
+.Li ah ,
+.Li esp
+or
+.Li ipcomp .
+.Pp
+.Ar mode
+is either
+.Li transport
+or
+.Li tunnel .
+.Pp
+.Ar src
+and
+.Ar dst
+specifies IPsec endpoint.
+.Ar src
+always means
+.Dq sending node
+and
+.Ar dst
+always means
+.Dq receiving node .
+Therefore, when
+.Ar direction
+is
+.Li in ,
+.Ar dst
+is this node
+and
+.Ar src
+is the other node
+.Pq peer .
+.Pp
+.Ar level
+must be set to one of the following:
+.Li default , use
+or
+.Li require .
+.Li default
+means that the kernel should consult the system default policy
+defined by
+.Xr sysctl 8 ,
+such as
+.Li net.inet.ipsec.esp_trans_deflev .
+See
+.Xr ipsec 4
+regarding the system default.
+.Li use
+means that a relevant SA can be used when available,
+since the kernel may perform IPsec operation against packets when possible.
+In this case, packets can be transmitted in clear
+.Pq when SA is not available ,
+or encrypted
+.Pq when SA is available .
+.Li require
+means that a relevant SA is required,
+since the kernel must perform IPsec operation against packets.
+If the
+.Ar request
+string is kept unambiguous,
+.Ar level
+and slash prior to
+.Ar level
+can be omitted.
+However, it is encouraged to specify them explicitly
+to avoid unintended behaviors.
+If
+.Ar level
+is omitted, it will be interpreted as
+.Li default .
+.El
+.El
+.Pp
+Note that there is a bit difference of specification from
+.Xr setkey 8 .
+In specification by
+.Xr setkey 8 ,
+both entrust and bypass are not used. Refer to
+.Xr setkey 8
+for detail.
+.Pp
+Here are several examples
+.Pq long lines are wrapped for readability :
+.Bd -literal -offset indent
+in discard
+out ipsec esp/transport/10.1.1.1-10.1.1.2/require
+in ipsec ah/transport/10.1.1.2-10.1.1.1/require
+in ipsec esp/transport/10.1.1.2-10.1.1.1/use
+ ah/tunnel/10.1.1.2-10.1.1.1/require
+in ipsec ipcomp/transport/10.1.1.2-10.1.1.1/use
+ esp/transport/10.1.1.2-10.1.1.1/use
+.Ed
+.\"
+.Sh RETURN VALUES
+.Fn ipsec_set_policy
+returns a pointer to the allocated buffer of policy specification if successful; otherwise a NULL pointer is returned.
+.Fn ipsec_get_policylen
+returns with positive value
+.Pq meaning the buffer size
+on success, and negative value on errors.
+.Fn ipsec_dump_policy
+returns a pointer to dynamically allocated region on success,
+and
+.Dv NULL
+on errors.
+.\"
+.Sh SEE ALSO
+.Xr ipsec_strerror 3 ,
+.Xr ispec 4
+.Xr setkey 8
+.\"
+.Sh HISTORY
+The functions first appeared in WIDE/KAME IPv6 protocol stack kit.
+.\"
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/lib/libipsec/ipsec_strerror.3 b/lib/libipsec/ipsec_strerror.3
new file mode 100644
index 0000000..58ac2b6
--- /dev/null
+++ b/lib/libipsec/ipsec_strerror.3
@@ -0,0 +1,66 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ipsec_strerror.3,v 1.2 1999/09/21 03:49:19 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 6, 1998
+.Dt IPSEC_STRERROR 3
+.Os KAME
+.\"
+.Sh NAME
+.Nm ipsec_strerror
+.Nd error code for IPsec policy manipulation library
+.\"
+.Sh SYNOPSIS
+.Fd #include <netinet6/ipsec.h>
+.Ft "char *"
+.Fn ipsec_strerror
+.\"
+.Sh DESCRIPTION
+.Pa netinet6/ipsec.h
+declares
+.Pp
+.Dl extern int ipsec_errcode;
+.Pp
+which is used to pass error code from IPsec policy manipulation library
+to user program.
+.Fn ipsec_strerror
+can be used to obtain error message string for the error code.
+.\"
+.Sh RETURN VALUES
+.Fn ipsec_strerror
+always return a pointer to C string.
+The C string must not be overwritten by user programs.
+.\"
+.\" .Sh SEE ALSO
+.\"
+.Sh HISTORY
+The functions first appeared in WIDE/KAME IPv6 protocol stack kit.
+.\"
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/lib/libipsec/ipsec_strerror.c b/lib/libipsec/ipsec_strerror.c
new file mode 100644
index 0000000..601b1d7
--- /dev/null
+++ b/lib/libipsec/ipsec_strerror.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <string.h>
+#include <netinet6/ipsec.h>
+
+#include "ipsec_strerror.h"
+
+int ipsec_errcode;
+
+static char *ipsec_errlist[] = {
+"Success", /*EIPSEC_NO_ERROR*/
+"Not supported", /*EIPSEC_NOT_SUPPORTED*/
+"Invalid argument", /*EIPSEC_INVAL_ARGUMENT*/
+"Invalid sadb message", /*EIPSEC_INVAL_SADBMSG*/
+"Invalid version", /*EIPSEC_INVAL_VERSION*/
+"Invalid security policy", /*EIPSEC_INVAL_POLICY*/
+"Invalid address specification", /*EIPSEC_INVAL_ADDRESS*/
+"Invalid ipsec protocol", /*EIPSEC_INVAL_PROTO*/
+"Invalid ipsec mode", /*EIPSEC_INVAL_MODE*/
+"Invalid ipsec level", /*EIPSEC_INVAL_LEVEL*/
+"Invalid SA type", /*EIPSEC_INVAL_SATYPE*/
+"Invalid message type", /*EIPSEC_INVAL_MSGTYPE*/
+"Invalid extension type", /*EIPSEC_INVAL_EXTTYPE*/
+"Invalid algorithm type", /*EIPSEC_INVAL_ALGS*/
+"Invalid key length", /*EIPSEC_INVAL_KEYLEN*/
+"Invalid address family", /*EIPSEC_INVAL_FAMILY*/
+"Invalid prefix length", /*EIPSEC_INVAL_PREFIXLEN*/
+"Invalid direciton", /*EIPSEC_INVAL_DIR*/
+"SPI range violation", /*EIPSEC_INVAL_SPI*/
+"No protocol specified", /*EIPSEC_NO_PROTO*/
+"No algorithm specified", /*EIPSEC_NO_ALGS*/
+"No buffers available", /*EIPSEC_NO_BUFS*/
+"Must get supported algorithms list first", /*EIPSEC_DO_GET_SUPP_LIST*/
+"Protocol mismatch", /*EIPSEC_PROTO_MISMATCH*/
+"Family mismatch", /*EIPSEC_FAMILY_MISMATCH*/
+"Too few arguments", /*EIPSEC_FEW_ARGUMENTS*/
+NULL, /*EIPSEC_SYSTEM_ERROR*/
+"Unknown error", /*EIPSEC_MAX*/
+};
+
+char *ipsec_strerror(void)
+{
+ if (ipsec_errcode < 0 || ipsec_errcode > EIPSEC_MAX)
+ ipsec_errcode = EIPSEC_MAX;
+
+ return ipsec_errlist[ipsec_errcode];
+}
+
+void ipsec_set_strerror(char *str)
+{
+ ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str;
+
+ return;
+}
diff --git a/lib/libipsec/ipsec_strerror.h b/lib/libipsec/ipsec_strerror.h
new file mode 100644
index 0000000..752ba75
--- /dev/null
+++ b/lib/libipsec/ipsec_strerror.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+extern int ipsec_errcode;
+extern void ipsec_set_strerror(char *str);
+
+#define EIPSEC_NO_ERROR 0 /*success*/
+#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/
+#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/
+#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/
+#define EIPSEC_INVAL_VERSION 4 /*invalid version*/
+#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/
+#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/
+#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/
+#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/
+#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/
+#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/
+#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/
+#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/
+#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/
+#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/
+#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/
+#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/
+#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/
+#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/
+#define EIPSEC_NO_PROTO 19 /*no protocol specified*/
+#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/
+#define EIPSEC_NO_BUFS 21 /*no buffers available*/
+#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/
+#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/
+#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/
+#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/
+#define EIPSEC_SYSTEM_ERROR 26 /*system error*/
+#define EIPSEC_MAX 27 /*unknown error*/
diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c
new file mode 100644
index 0000000..318be33
--- /dev/null
+++ b/lib/libipsec/pfkey.c
@@ -0,0 +1,1421 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef lint
+static char *rcsid = "@(#) pfkey.c $Revision: 1.10 $";
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_var.h>
+#include <netinet/in.h>
+#include <netinet6/in6.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "ipsec_strerror.h"
+
+#define CALLOC(size, cast) (cast)calloc(1, (size))
+
+static int pfkey_send_x1 __P((int so, u_int type, u_int satype, u_int mode,
+ struct sockaddr *src, struct sockaddr *dst, u_int32_t spi, u_int wsize,
+ caddr_t keymat,
+ u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen,
+ u_int flags,
+ u_int32_t l_alloc, u_int32_t l_bytes,
+ u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq));
+static int pfkey_send_x2 __P((int so, u_int type, u_int satype, u_int mode,
+ struct sockaddr *src, struct sockaddr *dst, u_int32_t spi));
+static int pfkey_send_x3 __P((int so, u_int type, u_int satype));
+
+static caddr_t pfkey_setsadbmsg __P((caddr_t buf, u_int type, u_int tlen,
+ u_int satype, u_int mode, u_int32_t seq, pid_t pid));
+static caddr_t pfkey_setsadbsa __P((caddr_t buf, u_int32_t spi, u_int wsize,
+ u_int auth, u_int enc, u_int32_t flags));
+static caddr_t pfkey_setsadbaddr __P((caddr_t buf, u_int exttype,
+ struct sockaddr *saddr, u_int prefixlen, u_int ul_proto));
+static caddr_t pfkey_setsadbkey(caddr_t buf, u_int type,
+ caddr_t key, u_int keylen);
+static caddr_t pfkey_setsadblifetime(caddr_t buf, u_int type,
+ u_int32_t l_alloc, u_int32_t l_bytes,
+ u_int32_t l_addtime, u_int32_t l_usetime);
+
+/*
+ * check key length against algorithm specified.
+ * supported is either SADB_EXT_SUPPORTED_ENCRYPT or SADB_EXT_SUPPORTED_AUTH.
+ * Refer to keyv2.h to get more info.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+struct sadb_msg *ipsec_supported = NULL;
+
+int
+ipsec_check_keylen(supported, alg_id, keylen)
+ u_int supported;
+ u_int alg_id;
+ u_int keylen;
+{
+ u_int tlen;
+ caddr_t p;
+ struct sadb_supported *sup;
+ struct sadb_alg *alg;
+
+ /* validity check */
+ if (ipsec_supported == NULL) {
+ ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+ return -1;
+ }
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ tlen = ipsec_supported->sadb_msg_len - sizeof(struct sadb_msg);
+ p = (caddr_t)ipsec_supported + sizeof(struct sadb_msg);
+
+ for (;
+ tlen > 0;
+ tlen -= sup->sadb_supported_len, p += sup->sadb_supported_len) {
+
+ sup = (struct sadb_supported *)p;
+
+ if (sup->sadb_supported_exttype != supported)
+ continue;
+
+ {
+ u_int ttlen = sup->sadb_supported_len;
+ caddr_t pp = p + sizeof(*sup);
+
+ for (;
+ ttlen > 0;
+ ttlen -= sizeof(*alg), pp += sizeof(*alg)) {
+ alg = (struct sadb_alg *)pp;
+
+ if (alg->sadb_alg_id == alg_id)
+ goto found;
+ }
+ }
+ }
+
+ ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return -1;
+ /* NOTREACHED */
+
+ found:
+ if (keylen < alg->sadb_alg_minbits
+ || keylen > alg->sadb_alg_maxbits) {
+ ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+ return -1;
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set the rate for SOFT lifetime against HARD one.
+ * If rate is more than 100 or equal to zero, then set to 100.
+ */
+static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
+
+u_int
+pfkey_set_softrate(type, rate)
+ u_int type, rate;
+{
+ ipsec_errcode = EIPSEC_NO_ERROR;
+
+ if (rate > 100 || rate == 0)
+ rate = 100;
+
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ soft_lifetime_allocations_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_BYTES:
+ soft_lifetime_bytes_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_ADDTIME:
+ soft_lifetime_addtime_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_USETIME:
+ soft_lifetime_usetime_rate = rate;
+ return 0;
+ }
+
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return 1;
+}
+
+/*
+ * get current rate for SOFT lifetime against HARD one.
+ * ATTENTION: ~0 is returned if invalid type was passed.
+ */
+u_int
+pfkey_get_softrate(type)
+ u_int type;
+{
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ return soft_lifetime_allocations_rate;
+ case SADB_X_LIFETIME_BYTES:
+ return soft_lifetime_bytes_rate;
+ case SADB_X_LIFETIME_ADDTIME:
+ return soft_lifetime_addtime_rate;
+ case SADB_X_LIFETIME_USETIME:
+ return soft_lifetime_usetime_rate;
+ }
+
+ return ~0;
+}
+
+/*
+ * sending SADB_GETSPI message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_getspi(so, satype, mode, src, dst, min, max, seq)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t min, max, seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ int need_spirange = 0;
+ caddr_t p;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ if (min > max || (min > 0 && min <= 255)) {
+ ipsec_errcode = EIPSEC_INVAL_SPI;
+ return -1;
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if (min > 255 && max < ~0) {
+ need_spirange++;
+ len += sizeof(struct sadb_spirange);
+ }
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_GETSPI,
+ len, satype, mode, seq, getpid());
+
+ /* set sadb_address for source */
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_SRC,
+ src,
+ _INALENBYAF(src->sa_family) << 3,
+ IPSEC_ULPROTO_ANY);
+
+ /* set sadb_address for destination */
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_DST,
+ dst,
+ _INALENBYAF(dst->sa_family) << 3,
+ IPSEC_ULPROTO_ANY);
+
+ /* proccessing spi range */
+ if (need_spirange) {
+ int _len = sizeof(struct sadb_spirange);
+
+#define _SADB_SPIRANGE(p) ((struct sadb_spirange *)(p))
+ _SADB_SPIRANGE(p)->sadb_spirange_len = PFKEY_UNIT64(_len);
+ _SADB_SPIRANGE(p)->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ _SADB_SPIRANGE(p)->sadb_spirange_min = min;
+ _SADB_SPIRANGE(p)->sadb_spirange_max = max;
+#undef _SADB_SPIRANGE(p)
+ p += _len;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int satype, mode, wsize;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc;
+ u_int64_t l_bytes, l_addtime, l_usetime;
+ u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+ wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int satype, mode, wsize;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc;
+ u_int64_t l_bytes, l_addtime, l_usetime;
+ u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+ wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_delete(so, satype, mode, src, dst, spi)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_GET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_get(so, satype, mode, src, dst, spi)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_register(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_recv_register(so)
+ int so;
+{
+ pid_t pid = getpid();
+ struct sadb_msg *newmsg;
+ struct sadb_supported *sup;
+ caddr_t p;
+ int tlen;
+
+ /* receive message */
+ do {
+ if ((newmsg = pfkey_recv(so)) == NULL)
+ return -1;
+
+ } while (newmsg->sadb_msg_type != SADB_REGISTER
+ || newmsg->sadb_msg_pid != pid);
+
+ /* check and fix */
+ newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
+
+ tlen = newmsg->sadb_msg_len - sizeof(struct sadb_msg);
+ p = (caddr_t)newmsg + sizeof(struct sadb_msg);
+ while (tlen > 0) {
+ sup = (struct sadb_supported *)p;
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ free(newmsg);
+ return -1;
+ }
+
+ tlen -= sup->sadb_supported_len;
+ p += sup->sadb_supported_len;
+ }
+
+ if (tlen < 0) {
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ if (ipsec_supported != NULL)
+ free(ipsec_supported);
+
+ ipsec_supported = newmsg;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * sending SADB_FLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_flush(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_dump(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_PROMISC message to the kernel.
+ * NOTE that this function handles promisc mode toggle only.
+ * IN:
+ * flag: set promisc off if zero, set promisc on if non-zero.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ * 0 : error occured, and set errno.
+ * others: a pointer to new allocated buffer in which supported
+ * algorithms is.
+ */
+int
+pfkey_send_promisc_toggle(so, flag)
+ int so;
+ int flag;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ char *policy;
+ int policylen;
+ u_int32_t seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ if (prefs > (_INALENBYAF(src->sa_family) << 3)
+ || prefd > (_INALENBYAF(dst->sa_family) << 3)) {
+ ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(_SALENBYAF(src->sa_family))
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(_SALENBYAF(src->sa_family))
+ + policylen;
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_X_SPDADD, len,
+ SADB_SATYPE_UNSPEC, IPSEC_MODE_ANY, seq, getpid());
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_SRC,
+ src,
+ prefs,
+ proto);
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_DST,
+ dst,
+ prefd,
+ proto);
+ memcpy(p, policy, policylen);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int32_t seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ if (prefs > (_INALENBYAF(src->sa_family) << 3)
+ || prefd > (_INALENBYAF(dst->sa_family) << 3)) {
+ ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(_SALENBYAF(src->sa_family))
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(_SALENBYAF(src->sa_family));
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_X_SPDDELETE, len,
+ SADB_SATYPE_UNSPEC, IPSEC_MODE_ANY, seq, getpid());
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_SRC,
+ src,
+ prefs,
+ proto);
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_DST,
+ dst,
+ prefd,
+ proto);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_SPDFLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdflush(so)
+ int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDDUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddump(so)
+ int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int type, satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+ u_int wsize;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (satype) {
+ case SADB_SATYPE_ESP:
+ if (e_type == SADB_EALG_NONE) {
+ ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_AH:
+ if (e_type != SADB_EALG_NONE) {
+ ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type == SADB_AALG_NONE) {
+ ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_X_SATYPE_IPCOMP:
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + sizeof(struct sadb_lifetime);
+
+ if (e_type != SADB_EALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+ if (a_type != SADB_AALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, type, len,
+ satype, mode, seq, getpid());
+ p = pfkey_setsadbsa(p, spi, wsize, a_type, e_type, flags);
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_SRC,
+ src,
+ _INALENBYAF(src->sa_family) << 3,
+ IPSEC_ULPROTO_ANY);
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_DST,
+ dst,
+ _INALENBYAF(dst->sa_family) << 3,
+ IPSEC_ULPROTO_ANY);
+
+ if (e_type != SADB_EALG_NONE)
+ p = pfkey_setsadbkey(p, SADB_EXT_KEY_ENCRYPT,
+ keymat, e_keylen);
+ if (a_type != SADB_AALG_NONE)
+ p = pfkey_setsadbkey(p, SADB_EXT_KEY_AUTH,
+ keymat + e_keylen, a_keylen);
+
+ /* set sadb_lifetime for destination */
+ p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_HARD,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_SOFT,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_DELETE or SADB_GET message to the kernel */
+static int
+pfkey_send_x2(so, type, satype, mode, src, dst, spi)
+ int so;
+ u_int type, satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, mode, 0, getpid());
+ p = pfkey_setsadbsa(p, spi, 0, 0, 0, 0);
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_SRC,
+ src,
+ _INALENBYAF(src->sa_family) << 3,
+ IPSEC_ULPROTO_ANY);
+ p = pfkey_setsadbaddr(p,
+ SADB_EXT_ADDRESS_DST,
+ dst,
+ _INALENBYAF(dst->sa_family) << 3,
+ IPSEC_ULPROTO_ANY);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
+ * to the kernel
+ */
+static int
+pfkey_send_x3(so, type, satype)
+ int so;
+ u_int type, satype;
+{
+ struct sadb_msg *newmsg;
+ int len;
+
+ /* validity check */
+ switch (type) {
+ case SADB_X_PROMISC:
+ if (satype != 0 && satype != 1) {
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ default:
+ switch (satype) {
+ case SADB_SATYPE_UNSPEC:
+ case SADB_SATYPE_AH:
+ case SADB_SATYPE_ESP:
+ case SADB_X_SATYPE_IPCOMP:
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ (void)pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, 0, getpid());
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * open a socket.
+ * OUT:
+ * -1: fail.
+ * others : success and return value of socket.
+ */
+int
+pfkey_open()
+{
+ int so;
+ const int bufsiz = 128 * 1024; /*is 128K enough?*/
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ /*
+ * This is a temporary workaround for KAME PR 154.
+ * Don't really care even if it fails.
+ */
+ (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
+ (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return so;
+}
+
+/*
+ * close a socket.
+ * OUT:
+ * 0: success.
+ * -1: fail.
+ */
+void
+pfkey_close(so)
+ int so;
+{
+ (void)close(so);
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return;
+}
+
+/*
+ * receive sadb_msg data, and return pointer to new buffer allocated.
+ * Must free this buffer later.
+ * OUT:
+ * NULL : error occured.
+ * others : a pointer to sadb_msg structure.
+ */
+struct sadb_msg *
+pfkey_recv(so)
+ int so;
+{
+ struct sadb_msg buf, *newmsg;
+ int len, reallen;
+
+ while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
+ if (errno == EINTR) continue;
+ ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ if (len < sizeof(buf)) {
+ recv(so, (caddr_t)&buf, sizeof(buf), 0);
+ ipsec_errcode = EIPSEC_MAX;
+ return NULL;
+ }
+
+ /* read real message */
+ reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+ if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) {
+ ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
+ if (errno == EINTR) continue;
+ ipsec_set_strerror(strerror(errno));
+ free(newmsg);
+ return NULL;
+ }
+
+ if (len != reallen) {
+ ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return newmsg;
+}
+
+/*
+ * send message to a socket.
+ * OUT:
+ * others: success and return length sent.
+ * -1 : fail.
+ */
+int
+pfkey_send(so, msg, len)
+ int so;
+ struct sadb_msg *msg;
+ int len;
+{
+ if ((len = send(so, (caddr_t)msg, len, 0)) < 0) {
+ ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * %%% Utilities
+ * NOTE: These functions are derived from netkey/key.c in KAME.
+ */
+/*
+ * set the pointer to each header in this message buffer.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ * OUT: -1: invalid.
+ * 0: valid.
+ */
+int
+pfkey_align(msg, mhp)
+ struct sadb_msg *msg;
+ caddr_t *mhp;
+{
+ struct sadb_ext *ext;
+ int tlen, extlen;
+ int i;
+
+ /* validity check */
+ if (msg == NULL || mhp == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ /* initialize */
+ for (i = 0; i < SADB_EXT_MAX + 1; i++)
+ mhp[i] = NULL;
+
+ mhp[0] = (caddr_t)msg;
+
+ tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg);
+ ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg));
+
+ while (tlen > 0) {
+ /* duplicate check */
+ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
+ if (mhp[ext->sadb_ext_type] != NULL) {
+ ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ /* set pointer */
+ switch (ext->sadb_ext_type) {
+ case SADB_EXT_SA:
+ case SADB_EXT_LIFETIME_CURRENT:
+ case SADB_EXT_LIFETIME_HARD:
+ case SADB_EXT_LIFETIME_SOFT:
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_EXT_KEY_AUTH:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_KEY_ENCRYPT:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_IDENTITY_SRC:
+ case SADB_EXT_IDENTITY_DST:
+ case SADB_EXT_SENSITIVITY:
+ case SADB_EXT_PROPOSAL:
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ case SADB_EXT_SPIRANGE:
+ case SADB_X_EXT_POLICY:
+ mhp[ext->sadb_ext_type] = (caddr_t)ext;
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ extlen = PFKEY_EXTLEN(ext);
+ tlen -= extlen;
+ ext = (struct sadb_ext *)((caddr_t)ext + extlen);
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * check basic usage for sadb_msg,
+ * NOTE: This routine is derived from netkey/key.c in KAME.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ *
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ *
+ * OUT: -1: invalid.
+ * 0: valid.
+ */
+int
+pfkey_check(mhp)
+ caddr_t *mhp;
+{
+ struct sadb_msg *msg;
+
+ /* validity check */
+ if (mhp == NULL || mhp[0] == NULL) {
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ msg = (struct sadb_msg *)mhp[0];
+
+ /* check version */
+ if (msg->sadb_msg_version != PF_KEY_V2) {
+ ipsec_errcode = EIPSEC_INVAL_VERSION;
+ return -1;
+ }
+
+ /* check type */
+ if (msg->sadb_msg_type > SADB_MAX) {
+ ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
+ return -1;
+ }
+
+ /* check SA type */
+ switch (msg->sadb_msg_satype) {
+ case SADB_SATYPE_UNSPEC:
+ switch (msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_ACQUIRE:
+ case SADB_EXPIRE:
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_IPCOMP:
+ switch (msg->sadb_msg_type) {
+ case SADB_X_SPDADD:
+ case SADB_X_SPDDELETE:
+ case SADB_X_SPDGET:
+ case SADB_X_SPDDUMP:
+ case SADB_X_SPDFLUSH:
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_RSVP:
+ case SADB_SATYPE_OSPFV2:
+ case SADB_SATYPE_RIPV2:
+ case SADB_SATYPE_MIP:
+ ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return -1;
+ case 1: /* XXX: What does it do ? */
+ if (msg->sadb_msg_type == SADB_X_PROMISC)
+ break;
+ /*FALLTHROUGH*/
+ default:
+ ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* check field of upper layer protocol and address family */
+ if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
+ && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
+ struct sadb_address *src0, *dst0;
+
+ src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+
+ if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+ ipsec_errcode = EIPSEC_PROTO_MISMATCH;
+ return -1;
+ }
+
+ if (PFKEY_ADDR_SADDR(src0)->sa_family
+ != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /*
+ * prefixlen == 0 is valid because there must be the case
+ * all addresses are matched.
+ */
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set data into sadb_msg.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbmsg(buf, type, tlen, satype, mode, seq, pid)
+ caddr_t buf;
+ u_int type, satype, mode;
+ u_int tlen;
+ u_int32_t seq;
+ pid_t pid;
+{
+ struct sadb_msg *p;
+ u_int len;
+
+ p = (struct sadb_msg *)buf;
+ len = sizeof(struct sadb_sa);
+
+ memset(p, 0, len);
+ p->sadb_msg_version = PF_KEY_V2;
+ p->sadb_msg_type = type;
+ p->sadb_msg_errno = 0;
+ p->sadb_msg_satype = satype;
+ p->sadb_msg_len = PFKEY_UNIT64(tlen);
+ p->sadb_msg_mode = mode;
+ p->sadb_msg_reserved = 0;
+ p->sadb_msg_seq = seq;
+ p->sadb_msg_pid = (u_int32_t)pid;
+
+ return(buf + len);
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags)
+ caddr_t buf;
+ u_int32_t spi, flags;
+ u_int wsize, auth, enc;
+{
+ struct sadb_sa *p;
+ u_int len;
+
+ p = (struct sadb_sa *)buf;
+ len = sizeof(struct sadb_sa);
+
+ memset(p, 0, len);
+ p->sadb_sa_len = PFKEY_UNIT64(len);
+ p->sadb_sa_exttype = SADB_EXT_SA;
+ p->sadb_sa_spi = spi;
+ p->sadb_sa_replay = wsize;
+ p->sadb_sa_state = SADB_SASTATE_LARVAL;
+ p->sadb_sa_auth = auth;
+ p->sadb_sa_encrypt = enc;
+ p->sadb_sa_flags = flags;
+
+ return(buf + len);
+}
+
+/*
+ * set data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ * prefixlen is in bits.
+ */
+static caddr_t
+pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto)
+ caddr_t buf;
+ u_int exttype;
+ struct sockaddr *saddr;
+ u_int prefixlen;
+ u_int ul_proto;
+{
+ struct sadb_address *p;
+ u_int len;
+
+ p = (struct sadb_address *)buf;
+ len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+
+ memset(p, 0, len);
+ p->sadb_address_len = PFKEY_UNIT64(len);
+ p->sadb_address_exttype = exttype & 0xffff;
+ p->sadb_address_proto = ul_proto & 0xff;
+ p->sadb_address_prefixlen = prefixlen;
+ p->sadb_address_reserved = 0;
+
+ memcpy(p + 1, saddr, saddr->sa_len);
+
+ return(buf + len);
+}
+
+/*
+ * set sadb_key structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadbkey(buf, type, key, keylen)
+ caddr_t buf, key;
+ u_int type, keylen;
+{
+ struct sadb_key *p;
+ u_int len;
+
+ p = (struct sadb_key *)buf;
+ len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+
+ memset(p, 0, len);
+ p->sadb_key_len = PFKEY_UNIT64(len);
+ p->sadb_key_exttype = type;
+ p->sadb_key_bits = keylen << 3;
+ p->sadb_key_reserved = 0;
+
+ memcpy(p + 1, key, keylen);
+
+ return buf + len;
+}
+
+/*
+ * set sadb_lifetime structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime)
+ caddr_t buf;
+ u_int type;
+ u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+{
+ struct sadb_lifetime *p;
+ u_int len;
+
+ p = (struct sadb_lifetime *)buf;
+ len = sizeof(struct sadb_lifetime);
+
+ memset(p, 0, len);
+ p->sadb_lifetime_len = PFKEY_UNIT64(len);
+ p->sadb_lifetime_exttype = type;
+
+ switch (type) {
+ case SADB_EXT_LIFETIME_SOFT:
+ p->sadb_lifetime_allocations
+ = (l_alloc * soft_lifetime_allocations_rate) /100;
+ p->sadb_lifetime_bytes
+ = ((l_bytes * soft_lifetime_bytes_rate) /100) << 10;
+ p->sadb_lifetime_addtime
+ = (l_addtime * soft_lifetime_addtime_rate) /100;
+ p->sadb_lifetime_usetime
+ = (l_usetime * soft_lifetime_usetime_rate) /100;
+ break;
+ case SADB_EXT_LIFETIME_HARD:
+ p->sadb_lifetime_allocations = l_alloc;
+ p->sadb_lifetime_bytes = l_bytes << 10;
+ p->sadb_lifetime_addtime = l_addtime;
+ p->sadb_lifetime_usetime = l_usetime;
+ break;
+ }
+
+ return buf + len;
+}
+
diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c
new file mode 100644
index 0000000..b7def24
--- /dev/null
+++ b/lib/libipsec/pfkey_dump.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet6/ipsec.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_var.h>
+#include <netkey/key_debug.h>
+
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/in6.h>
+#endif
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "ipsec_strerror.h"
+
+#define GETMSGSTR(str, num) \
+{ \
+ if (sizeof((str)[0]) == 0 \
+ || num >= sizeof(str)/sizeof((str)[0])) \
+ printf("%d ", (num)); \
+ else if (strlen((str)[(num)]) == 0) \
+ printf("%d ", (num)); \
+ else \
+ printf("%s ", (str)[(num)]); \
+}
+
+#define GETAF(p) \
+ (((struct sockaddr *)(p))->sa_family)
+
+static char *_str_ipaddr __P((u_int family, caddr_t addr));
+static char *_str_prefport __P((u_int family, u_int pref, u_int port));
+static char *_str_time __P((time_t t));
+static void _str_lifetime_byte __P((struct sadb_lifetime *x, char *str));
+
+/*
+ * Must to be re-written about following strings.
+ */
+static char *_str_satype[] = {
+ "unspec",
+ "unknown",
+ "ah",
+ "esp",
+ "unknown",
+ "rsvp",
+ "ospfv2",
+ "ripv2",
+ "mip",
+ "ipcomp",
+};
+
+static char *_str_mode[] = {
+ "any",
+ "transport",
+ "tunnel",
+};
+
+static char *_str_upper[] = {
+/*0*/ "ip", "icmp", "igmp", "ggp", "ip4",
+ "", "tcp", "", "egp", "",
+/*10*/ "", "", "", "", "",
+ "", "", "udp", "", "",
+/*20*/ "", "", "idp", "", "",
+ "", "", "", "", "tp",
+/*30*/ "", "", "", "", "",
+ "", "", "", "", "",
+/*40*/ "", "ip6", "", "rt6", "frag6",
+ "", "rsvp", "gre", "", "",
+/*50*/ "esp", "ah", "", "", "",
+ "", "", "", "icmp6", "none",
+/*60*/ "dst6",
+};
+
+static char *_str_state[] = {
+ "larval",
+ "mature",
+ "dying",
+ "dead",
+};
+
+static char *_str_alg_auth[] = {
+ "none",
+ "hmac-md5",
+ "hmac-sha1",
+ "md5",
+ "sha",
+ "null",
+};
+
+static char *_str_alg_enc[] = {
+ "none",
+ "des-cbc",
+ "3des-cbc",
+ "null",
+ "blowfish-cbc",
+ "cast128-cbc",
+ "rc5-cbc",
+};
+
+static char *_str_alg_comp[] = {
+ "none",
+ "oui",
+ "deflate",
+ "lzs",
+};
+
+/*
+ * dump SADB_MSG formated. For debugging, you should use kdebug_sadb().
+ */
+void
+pfkey_sadump(m)
+ struct sadb_msg *m;
+{
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_sa *m_sa;
+ struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts;
+ struct sadb_address *m_saddr, *m_daddr, *m_paddr;
+ struct sadb_key *m_auth, *m_enc;
+ struct sadb_ident *m_sid, *m_did;
+ struct sadb_sens *m_sens;
+
+ /* check pfkey message. */
+ if (pfkey_align(m, mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+ if (pfkey_check(mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+
+ m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+ m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
+ m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+ m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
+ m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+ m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+ m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY];
+ m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH];
+ m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT];
+ m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC];
+ m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC];
+ m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY];
+
+ /* source address */
+ if (m_saddr == NULL) {
+ printf("no ADDRESS_SRC extension.\n");
+ return;
+ }
+ printf("%s ",
+ _str_ipaddr(GETAF(m_saddr + 1), _INADDRBYSA(m_saddr + 1)));
+
+ /* destination address */
+ if (m_daddr == NULL) {
+ printf("no ADDRESS_DST extension.\n");
+ return;
+ }
+ printf("%s ",
+ _str_ipaddr(GETAF(m_daddr + 1), _INADDRBYSA(m_daddr + 1)));
+
+ /* SA type */
+ if (m_sa == NULL) {
+ printf("no SA extension.\n");
+ return;
+ }
+ printf("\n\t");
+
+ GETMSGSTR(_str_satype, m->sadb_msg_satype);
+
+ printf("mode=");
+ GETMSGSTR(_str_mode, m->sadb_msg_mode);
+
+ printf("spi=%u(0x%08x) replay=%u flags=0x%08x\n",
+ (u_int32_t)ntohl(m_sa->sadb_sa_spi),
+ (u_int32_t)ntohl(m_sa->sadb_sa_spi),
+ m_sa->sadb_sa_replay,
+ m_sa->sadb_sa_flags);
+
+ /* encryption key */
+ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
+ printf("\tC: ");
+ GETMSGSTR(_str_alg_comp, m_sa->sadb_sa_encrypt);
+ } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) {
+ if (m_enc != NULL) {
+ printf("\tE: ");
+ GETMSGSTR(_str_alg_enc, m_sa->sadb_sa_encrypt);
+ ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc),
+ m_enc->sadb_key_bits / 8);
+ printf("\n");
+ }
+ }
+
+ /* authentication key */
+ if (m_auth != NULL) {
+ printf("\tA: ");
+ GETMSGSTR(_str_alg_auth, m_sa->sadb_sa_auth);
+ ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth),
+ m_auth->sadb_key_bits / 8);
+ printf("\n");
+ }
+
+ /* state */
+ printf("\tstate=");
+ GETMSGSTR(_str_state, m_sa->sadb_sa_state);
+
+ printf("seq=%lu pid=%lu\n",
+ (u_long)m->sadb_msg_seq,
+ (u_long)m->sadb_msg_pid);
+
+ /* lifetime */
+ if (m_lftc != NULL) {
+ time_t tmp_time = time(0);
+
+ printf("\tcreated: %s",
+ _str_time(m_lftc->sadb_lifetime_addtime));
+ printf("\tcurrent: %s\n", _str_time(tmp_time));
+ printf("\tdiff: %lu(s)",
+ (u_long)(m_lftc->sadb_lifetime_addtime == 0 ?
+ 0 : (tmp_time - m_lftc->sadb_lifetime_addtime)));
+
+ printf("\thard: %lu(s)",
+ (u_long)(m_lfth == NULL ?
+ 0 : m_lfth->sadb_lifetime_addtime));
+ printf("\tsoft: %lu(s)\n",
+ (u_long)(m_lfts == NULL ?
+ 0 : m_lfts->sadb_lifetime_addtime));
+
+ printf("\tlast: %s",
+ _str_time(m_lftc->sadb_lifetime_usetime));
+ printf("\thard: %lu(s)",
+ (u_long)(m_lfth == NULL ?
+ 0 : m_lfth->sadb_lifetime_usetime));
+ printf("\tsoft: %lu(s)\n",
+ (u_long)(m_lfts == NULL ?
+ 0 : m_lfts->sadb_lifetime_usetime));
+
+ _str_lifetime_byte(m_lftc, "current");
+ _str_lifetime_byte(m_lfth, "hard");
+ _str_lifetime_byte(m_lfts, "soft");
+ printf("\n");
+
+ printf("\tallocated: %lu",
+ (unsigned long)m_lftc->sadb_lifetime_allocations);
+ printf("\thard: %lu",
+ (u_long)(m_lfth == NULL ?
+ 0 : m_lfth->sadb_lifetime_allocations));
+ printf("\tsoft: %lu\n",
+ (u_long)(m_lfts == NULL ?
+ 0 : m_lfts->sadb_lifetime_allocations));
+ }
+
+ /* XXX DEBUG */
+ printf("\trefcnt=%d\n", m->sadb_msg_reserved);
+
+ return;
+}
+
+void
+pfkey_spdump(m)
+ struct sadb_msg *m;
+{
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_address *m_saddr, *m_daddr;
+ struct sadb_x_policy *m_xpl;
+
+ /* check pfkey message. */
+ if (pfkey_align(m, mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+ if (pfkey_check(mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+
+ m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+ m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+ m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+ /* source address */
+ if (m_saddr == NULL) {
+ printf("no ADDRESS_SRC extension.\n");
+ return;
+ }
+ printf("%s%s ",
+ _str_ipaddr(GETAF(m_saddr + 1), _INADDRBYSA(m_saddr + 1)),
+ _str_prefport(GETAF(m_saddr + 1),
+ m_saddr->sadb_address_prefixlen,
+ _INPORTBYSA(m_saddr + 1)));
+
+ /* destination address */
+ if (m_daddr == NULL) {
+ printf("no ADDRESS_DST extension.\n");
+ return;
+ }
+ printf("%s%s ",
+ _str_ipaddr(GETAF(m_daddr + 1), _INADDRBYSA(m_daddr + 1)),
+ _str_prefport(GETAF(m_daddr + 1),
+ m_daddr->sadb_address_prefixlen,
+ _INPORTBYSA(m_daddr + 1)));
+
+ /* upper layer protocol */
+ if (m_saddr->sadb_address_proto != m_saddr->sadb_address_proto) {
+ printf("upper layer protocol mismatched.\n");
+ return;
+ }
+ if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY)
+ printf("any");
+ else
+ GETMSGSTR(_str_upper, m_saddr->sadb_address_proto);
+
+ /* policy */
+ {
+ char *d_xpl;
+
+ if (m_xpl == NULL) {
+ printf("no X_POLICY extension.\n");
+ return;
+ }
+ d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t");
+
+ /* dump SPD */
+ printf("\n\t%s\n", d_xpl);
+ free(d_xpl);
+ }
+
+ printf("\tseq=%ld pid=%ld\n",
+ (u_long)m->sadb_msg_seq,
+ (u_long)m->sadb_msg_pid);
+
+ /* XXX TEST */
+ printf("\trefcnt=%d\n", m->sadb_msg_reserved);
+
+ return;
+}
+
+/*
+ * set "ipaddress" to buffer.
+ */
+static char *
+_str_ipaddr(family, addr)
+ u_int family;
+ caddr_t addr;
+{
+ static char buf[128];
+ char addrbuf[128];
+
+ if (addr == NULL)
+ return "";
+
+ inet_ntop(family, addr, addrbuf, sizeof(addrbuf));
+
+ snprintf(buf, sizeof(buf), "%s", addrbuf);
+
+ return buf;
+}
+
+/*
+ * set "/prefix[port number]" to buffer.
+ */
+static char *
+_str_prefport(family, pref, port)
+ u_int family, pref, port;
+{
+ static char buf[128];
+ char prefbuf[10];
+ char portbuf[10];
+
+ if (pref == (_INALENBYAF(family) << 3))
+ prefbuf[0] = '\0';
+ else
+ snprintf(prefbuf, sizeof(prefbuf), "/%u", pref);
+
+ if (port == IPSEC_PORT_ANY)
+ snprintf(portbuf, sizeof(portbuf), "[%s]", "any");
+ else
+ snprintf(portbuf, sizeof(portbuf), "[%u]", ntohs(port));
+
+ snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf);
+
+ return buf;
+}
+
+/*
+ * set "Mon Day Time Year" to buffer
+ */
+static char *
+_str_time(t)
+ time_t t;
+{
+ static char buf[128];
+
+ if (t == 0) {
+ int i = 0;
+ for (;i < 20;) buf[i++] = ' ';
+ } else {
+ char *t0;
+ t0 = ctime(&t);
+ memcpy(buf, t0 + 4, 20);
+ }
+
+ buf[20] = '\0';
+
+ return(buf);
+}
+
+static void
+_str_lifetime_byte(x, str)
+ struct sadb_lifetime *x;
+ char *str;
+{
+ double y;
+ char *unit;
+ int w;
+
+ if (x == NULL) {
+ printf("\t%s: 0(bytes)", str);
+ return;
+ }
+
+ y = (x->sadb_lifetime_bytes) * 1.0;
+ unit = "";
+ w = 0;
+ printf("\t%s: %.*f(%sbytes)", str, w, y, unit);
+}
diff --git a/lib/libipsec/policy_parse.y b/lib/libipsec/policy_parse.y
new file mode 100644
index 0000000..ffa1a6f
--- /dev/null
+++ b/lib/libipsec/policy_parse.y
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: policy_parse.y,v 1.1 1999/10/20 01:26:41 sakane Exp $ */
+
+/*
+ * IN/OUT bound policy configuration take place such below:
+ * in <policy>
+ * out <policy>
+ *
+ * <policy> is one of following:
+ * "discard", "none", "ipsec <requests>", "entrust", "bypass",
+ *
+ * The following requests are accepted as <requests>:
+ *
+ * protocol/mode/src-dst/level
+ * protocol/mode/src-dst parsed as protocol/mode/src-dst/default
+ * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default
+ * protocol/transport parsed as protocol/mode/any-any/default
+ * protocol/transport//level parsed as protocol/mode/any-any/level
+ *
+ * You can concatenate these requests with either ' '(single space) or '\n'.
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+
+#define ATOX(c) \
+ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
+
+static caddr_t pbuf = NULL; /* sadb_x_policy buffer */
+static int tlen = 0; /* total length of pbuf */
+static int offset = 0; /* offset of pbuf */
+static int p_dir, p_type, p_protocol, p_mode, p_level;
+static struct sockaddr *p_src = NULL;
+static struct sockaddr *p_dst = NULL;
+
+extern void yyerror __P((char *msg));
+static struct sockaddr *parse_sockaddr __P((/*struct _val *buf*/));
+static int rule_check __P((void));
+static int init_x_policy __P((void));
+static int set_x_request __P((struct sockaddr *src, struct sockaddr *dst));
+static int set_sockaddr __P((struct sockaddr *addr));
+static void policy_parse_request_init __P((void));
+static caddr_t policy_parse __P((char *msg, int msglen));
+
+extern void __policy__strbuffer__init__ __P((char *msg));
+extern int yyparse();
+extern int yylex();
+
+%}
+
+%union {
+ u_int num;
+ struct _val {
+ int len;
+ char *buf;
+ } val;
+}
+
+%token DIR ACTION PROTOCOL MODE LEVEL
+%token IPADDRESS
+%token ME ANY
+%token SLASH HYPHEN
+%type <num> DIR ACTION PROTOCOL MODE LEVEL
+%type <val> IPADDRESS
+
+%%
+policy_spec
+ : DIR ACTION
+ {
+ p_dir = $1;
+ p_type = $2;
+
+ if (init_x_policy())
+ return -1;
+ }
+ rules
+ ;
+
+rules
+ : /*NOTHING*/
+ | rules rule {
+ if (rule_check() < 0)
+ return -1;
+
+ if (set_x_request(p_src, p_dst) < 0)
+ return -1;
+
+ policy_parse_request_init();
+ }
+ ;
+
+rule
+ : protocol SLASH mode SLASH addresses SLASH level
+ | protocol SLASH mode SLASH addresses SLASH
+ | protocol SLASH mode SLASH addresses
+ | protocol SLASH mode SLASH
+ | protocol SLASH mode SLASH SLASH level
+ | protocol SLASH mode
+ | protocol SLASH {
+ ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
+ return -1;
+ }
+ | protocol {
+ ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
+ return -1;
+ }
+ ;
+
+protocol
+ : PROTOCOL { p_protocol = $1; }
+ ;
+
+mode
+ : MODE { p_mode = $1; }
+ ;
+
+level
+ : LEVEL { p_level = $1; }
+ ;
+
+addresses
+ : IPADDRESS {
+ p_src = parse_sockaddr(&$1);
+ if (p_src == NULL)
+ return -1;
+ }
+ HYPHEN
+ IPADDRESS {
+ p_dst = parse_sockaddr(&$4);
+ if (p_dst == NULL)
+ return -1;
+ }
+ | ME HYPHEN ANY {
+ if (p_dir != IPSEC_DIR_OUTBOUND) {
+ ipsec_errcode = EIPSEC_INVAL_DIR;
+ return -1;
+ }
+ }
+ | ANY HYPHEN ME {
+ if (p_dir != IPSEC_DIR_INBOUND) {
+ ipsec_errcode = EIPSEC_INVAL_DIR;
+ return -1;
+ }
+ }
+ /*
+ | ME HYPHEN ME
+ */
+ ;
+
+%%
+
+void
+yyerror(msg)
+ char *msg;
+{
+ fprintf(stderr, "%s\n", msg);
+
+ return;
+}
+
+static struct sockaddr *
+parse_sockaddr(buf)
+ struct _val *buf;
+{
+ struct addrinfo hints, *res;
+ char *serv = NULL;
+ int error;
+ struct sockaddr *newaddr = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(buf->buf, serv, &hints, &res);
+ if (error != 0 || res->ai_addr == NULL) {
+ ipsec_set_strerror(error == EAI_SYSTEM ?
+ gai_strerror(error) : strerror(errno));
+ return NULL;
+ }
+
+ if (res->ai_addr == NULL) {
+ ipsec_set_strerror(gai_strerror(error));
+ return NULL;
+ }
+
+ newaddr = malloc(res->ai_addr->sa_len);
+ if (newaddr == NULL) {
+ ipsec_errcode = EIPSEC_NO_BUFS;
+ freeaddrinfo(res);
+ return NULL;
+ }
+ memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
+
+ /*
+ * XXX: If the scope of the destination is link-local,
+ * embed the scope-id(in this case, interface index)
+ * into the address.
+ */
+ if (newaddr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)newaddr;
+ if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
+ sin6->sin6_scope_id != 0)
+ *(u_short *)&sin6->sin6_addr.s6_addr[2] =
+ htons(sin6->sin6_scope_id & 0xffff);
+ }
+
+ freeaddrinfo(res);
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return newaddr;
+}
+
+static int
+rule_check()
+{
+ if (p_type == IPSEC_POLICY_IPSEC) {
+ if (p_protocol == IPPROTO_IP) {
+ ipsec_errcode = EIPSEC_NO_PROTO;
+ return -1;
+ }
+
+ if (p_mode != IPSEC_MODE_TRANSPORT
+ && p_mode != IPSEC_MODE_TUNNEL) {
+ ipsec_errcode = EIPSEC_INVAL_MODE;
+ return -1;
+ }
+
+ if (p_src == NULL && p_dst == NULL) {
+ if (p_mode != IPSEC_MODE_TRANSPORT) {
+ ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+ return -1;
+ }
+ }
+ else if (p_src->sa_family != p_dst->sa_family) {
+ ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static int
+init_x_policy()
+{
+ struct sadb_x_policy *p;
+
+ tlen = sizeof(struct sadb_x_policy);
+
+ pbuf = malloc(tlen);
+ if (pbuf == NULL) {
+ ipsec_errcode = EIPSEC_NO_BUFS;
+ return -1;
+ }
+ p = (struct sadb_x_policy *)pbuf;
+ p->sadb_x_policy_len = 0; /* must update later */
+ p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ p->sadb_x_policy_type = p_type;
+ p->sadb_x_policy_dir = p_dir;
+ p->sadb_x_policy_reserved = 0;
+ offset = tlen;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static int
+set_x_request(src, dst)
+ struct sockaddr *src, *dst;
+{
+ struct sadb_x_ipsecrequest *p;
+ int reqlen;
+
+ reqlen = sizeof(*p)
+ + (src ? src->sa_len : 0)
+ + (dst ? dst->sa_len : 0);
+ tlen += reqlen; /* increment to total length */
+
+ pbuf = realloc(pbuf, tlen);
+ if (pbuf == NULL) {
+ ipsec_errcode = EIPSEC_NO_BUFS;
+ return -1;
+ }
+ p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
+ p->sadb_x_ipsecrequest_len = reqlen;
+ p->sadb_x_ipsecrequest_proto = p_protocol;
+ p->sadb_x_ipsecrequest_mode = p_mode;
+ p->sadb_x_ipsecrequest_level = p_level;
+ offset += sizeof(*p);
+
+ if (set_sockaddr(src) || set_sockaddr(dst))
+ return -1;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static int
+set_sockaddr(addr)
+ struct sockaddr *addr;
+{
+ if (addr == NULL) {
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+ }
+
+ /* tlen has already incremented */
+
+ memcpy(&pbuf[offset], addr, addr->sa_len);
+
+ offset += addr->sa_len;
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static void
+policy_parse_request_init()
+{
+ p_protocol = IPPROTO_IP;
+ p_mode = IPSEC_MODE_ANY;
+ p_level = IPSEC_LEVEL_DEFAULT;
+ if (p_src != NULL) {
+ free(p_src);
+ p_src = NULL;
+ }
+ if (p_dst != NULL) {
+ free(p_dst);
+ p_dst = NULL;
+ }
+
+ return;
+}
+
+static caddr_t
+policy_parse(msg, msglen)
+ char *msg;
+ int msglen;
+{
+ int error;
+ pbuf = NULL;
+ tlen = 0;
+
+ /* initialize */
+ p_dir = IPSEC_DIR_INVALID;
+ p_type = IPSEC_POLICY_DISCARD;
+ policy_parse_request_init();
+ __policy__strbuffer__init__(msg);
+
+ error = yyparse(); /* it must be set errcode. */
+ if (error) {
+ if (pbuf != NULL)
+ free(pbuf);
+ return NULL;
+ }
+
+ /* update total length */
+ ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return pbuf;
+}
+
+caddr_t
+ipsec_set_policy(msg, msglen)
+ char *msg;
+ int msglen;
+{
+ caddr_t policy;
+
+ policy = policy_parse(msg, msglen);
+ if (policy == NULL) {
+ if (ipsec_errcode == EIPSEC_NO_ERROR)
+ ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return NULL;
+ }
+
+ ipsec_errcode = EIPSEC_NO_ERROR;
+ return policy;
+}
+
diff --git a/lib/libipsec/policy_token.l b/lib/libipsec/policy_token.l
new file mode 100644
index 0000000..1e7b714
--- /dev/null
+++ b/lib/libipsec/policy_token.l
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netkey/key_debug.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "y.tab.h"
+#define yylval __libyylval /* XXX */
+%}
+
+%option noyywrap
+
+/* common section */
+nl \n
+ws [ \t]+
+digit [0-9]
+letter [0-9A-Za-z]
+hexdigit [0-9A-Fa-f]
+special [()+\|\?\*,]
+dot \.
+comma \,
+hyphen \-
+colon \:
+slash \/
+bcl \{
+ecl \}
+blcl \[
+elcl \]
+percent \%
+semi \;
+usec {dot}{digit}{1,6}
+comment \#.*
+ccomment "/*"
+bracketstring \<[^>]*\>
+quotedstring \"[^"]*\"
+decstring {digit}+
+hexpair {hexdigit}{hexdigit}
+hexstring 0[xX]{hexdigit}+
+octetstring {octet}({dot}{octet})+
+ipaddress [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(@{letter}{letter}+)?
+name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))*
+hostname {name}(({dot}{name})+{dot}?)?
+
+%%
+
+in { yylval.num = IPSEC_DIR_INBOUND; return(DIR); }
+out { yylval.num = IPSEC_DIR_OUTBOUND; return(DIR); }
+
+discard { yylval.num = IPSEC_POLICY_DISCARD; return(ACTION); }
+none { yylval.num = IPSEC_POLICY_NONE; return(ACTION); }
+ipsec { yylval.num = IPSEC_POLICY_IPSEC; return(ACTION); }
+bypass { yylval.num = IPSEC_POLICY_BYPASS; return(ACTION); }
+entrust { yylval.num = IPSEC_POLICY_ENTRUST; return(ACTION); }
+
+esp { yylval.num = IPPROTO_ESP; return(PROTOCOL); }
+ah { yylval.num = IPPROTO_AH; return(PROTOCOL); }
+ipcomp { yylval.num = IPPROTO_IPCOMP; return(PROTOCOL); }
+
+transport { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
+tunnel { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); }
+
+me { return(ME); }
+any { return(ANY); }
+
+default { yylval.num = IPSEC_LEVEL_DEFAULT; return(LEVEL); }
+use { yylval.num = IPSEC_LEVEL_USE; return(LEVEL); }
+require { yylval.num = IPSEC_LEVEL_REQUIRE; return(LEVEL); }
+unique { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); }
+{slash} { return(SLASH); }
+
+{ipaddress} {
+ yylval.val.len = strlen(yytext);
+ yylval.val.buf = strdup(yytext);
+ return(IPADDRESS);
+ }
+
+{hyphen} { return(HYPHEN); }
+
+{ws} { ; }
+{nl} { ; }
+
+%%
+
+void
+__policy__strbuffer__init__(msg)
+ char *msg;
+{
+ YY_BUFFER_STATE yyb;
+
+ yyb = (YY_BUFFER_STATE)yy_scan_string(msg);
+ yy_switch_to_buffer(yyb);
+
+ return;
+}
+
diff --git a/lib/libipsec/test-policy.c b/lib/libipsec/test-policy.c
new file mode 100644
index 0000000..3b9d18c
--- /dev/null
+++ b/lib/libipsec/test-policy.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet6/in6.h>
+#include <netkey/keyv2.h>
+#include <netkey/key_debug.h>
+#include <netinet6/ipsec.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+
+char *requests[] = {
+"must_error", /* error */
+"in ipsec must_error", /* error */
+"out ipsec esp/must_error", /* error */
+"out discard",
+"out none",
+"in entrust",
+"out entrust",
+"in bypass", /* may be error */
+"out ipsec esp", /* error */
+"in ipsec ah/transport",
+"in ipsec ah/tunnel", /* error */
+"out ipsec ah/transport/",
+"out ipsec ah/tunnel/", /* error */
+"in ipsec esp / transport / 10.0.0.1-10.0.0.2",
+"in ipsec esp/tunnel/::1-::2",
+"in ipsec esp/tunnel/10.0.0.1-::2", /* error */
+"in ipsec esp/tunnel/::1-::2/require",
+"out ipsec ah/transport//use",
+"out ipsec ah/transport esp/use",
+"in ipsec ah/transport esp/tunnel", /* error */
+"in ipsec
+ ah / transport
+ esp / tunnel / ::1-::2",
+"
+out ipsec
+ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require
+ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require
+ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require
+",
+"out ipsec esp/transport/fec0::10-fec0::11/use",
+};
+
+int test(char *buf, int family);
+
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ int do_setsockopt;
+ char *buf;
+ int i;
+
+ if (ac != 1)
+ do_setsockopt = 1;
+ else
+ do_setsockopt = 0;
+
+ for (i = 0; i < sizeof(requests)/sizeof(requests[0]); i++) {
+ printf("*** requests ***\n");
+ printf("\t[%s]\n", requests[i]);
+
+ buf = ipsec_set_policy(requests[i], strlen(requests[i]));
+ if (buf == NULL) {
+ printf("ipsec_set_policy: %s\n", ipsec_strerror());
+ continue;
+ }
+
+ printf("\tsetlen:%d\n", ipsec_get_policylen(buf));
+
+ if (do_setsockopt) {
+ printf("\tPF_INET:\n");
+ test(buf, PF_INET);
+
+ printf("\tPF_INET6:\n");
+ test(buf, PF_INET6);
+ } else {
+ kdebug_sadb_x_policy((struct sadb_ext *)buf);
+ }
+ free(buf);
+ }
+
+ return 0;
+}
+
+int
+test(policy, family)
+ char *policy;
+ int family;
+{
+ int so, proto, optname;
+ int len;
+ char getbuf[1024];
+
+ switch (family) {
+ case PF_INET:
+ proto = IPPROTO_IP;
+ optname = IP_IPSEC_POLICY;
+ break;
+ case PF_INET6:
+ proto = IPPROTO_IPV6;
+ optname = IPV6_IPSEC_POLICY;
+ break;
+ }
+
+ if ((so = socket(family, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ len = ipsec_get_policylen(policy);
+ if (setsockopt(so, proto, optname, policy, len) < 0) {
+ printf("error on setsockopt");
+ goto end;
+ }
+
+ len = sizeof(getbuf);
+ memset(getbuf, 0, sizeof(getbuf));
+ if (getsockopt(so, proto, optname, getbuf, &len) < 0) {
+ printf("error on getsockopt");
+ goto end;
+ }
+
+ {
+ char *buf = NULL;
+
+ printf("\tgetlen:%d\n", len);
+
+ if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) {
+ printf("%s\n", ipsec_strerror());
+ goto end;
+ } else {
+ printf("\t[%s]\n", buf);
+ free(buf);
+ }
+ }
+
+ end:
+ close (so);
+
+ return 0;
+}
+
diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile
index 1df0d93..2c6b08e 100644
--- a/sbin/ping/Makefile
+++ b/sbin/ping/Makefile
@@ -8,7 +8,8 @@ COPTS+= -Wall -Wmissing-prototypes
.if ${MACHINE_ARCH} == "alpha"
COPTS+= -fno-builtin # GCC's builtin memcpy doesn't do unaligned copies
.endif
-DPADD= ${LIBM}
-LDADD= -lm
+CFLAGS+=-DIPSEC
+DPADD= ${LIBM} ${LIBIPSEC}
+LDADD= -lm -lipsec
.include <bsd.prog.mk>
diff --git a/sbin/ping/ping.8 b/sbin/ping/ping.8
index 565a5af..fca80ac 100644
--- a/sbin/ping/ping.8
+++ b/sbin/ping/ping.8
@@ -47,6 +47,7 @@ packets to network hosts
.Op Fl i Ar wait
.Op Fl l Ar preload
.Op Fl p Ar pattern
+.Op Fl P Ar policy
.Op Fl s Ar packetsize
.Op Fl S Ar src_addr
.Bo
@@ -147,6 +148,13 @@ For example,
.Dq Li \-p ff
will cause the sent packet to be filled with all
ones.
+.It Fl P Ar policy
+.Ar policy
+specifies IPsec policy for the ping session.
+For details please refer to
+.Xr ipsec 4
+and
+.Xr ipsec_set_policy 3 .
.It Fl Q
Somewhat quiet output.
.No Don Ap t
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
index 1cd55fa..15bac46 100644
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -92,6 +92,10 @@ static const char rcsid[] =
#include <netinet/ip_var.h>
#include <arpa/inet.h>
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif /*IPSEC*/
+
#define PHDR_LEN sizeof(struct timeval)
#define DEFDATALEN (64 - PHDR_LEN) /* default data length */
#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */
@@ -124,6 +128,11 @@ int options;
#define F_MTTL 0x0800
#define F_MIF 0x1000
#define F_AUDIBLE 0x2000
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define F_POLICY 0x4000
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
/*
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
@@ -204,6 +213,10 @@ main(argc, argv)
struct msghdr msg;
struct sockaddr_in from;
char ctrl[sizeof(struct cmsghdr) + sizeof(struct timeval)];
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy_in = NULL;
+ char *policy_out = NULL;
+#endif
/*
* Do the stuff that we need root priv's for *first*, and
@@ -219,7 +232,14 @@ main(argc, argv)
preload = 0;
datap = &outpack[8 + PHDR_LEN];
- while ((ch = getopt(argc, argv, "I:LQRS:T:c:adfi:l:np:qrs:v")) != -1) {
+#ifndef IPSEC
+ while ((ch = getopt(argc, argv, "I:LQRT:c:adfi:l:np:qrs:v")) != -1)
+#else
+#ifdef IPSEC_POLICY_IPSEC
+ while ((ch = getopt(argc, argv, "I:LQRT:c:adfi:l:np:qrs:vP:")) != -1)
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif
+ {
switch(ch) {
case 'a':
options |= F_AUDIBLE;
@@ -331,6 +351,19 @@ main(argc, argv)
case 'v':
options |= F_VERBOSE;
break;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ case 'P':
+ options |= F_POLICY;
+ if (!strncmp("in", optarg, 2))
+ policy_in = strdup(optarg);
+ else if (!strncmp("out", optarg, 3))
+ policy_out = strdup(optarg);
+ else
+ errx(1, "invalid security policy");
+ break;
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
default:
usage();
}
@@ -419,6 +452,32 @@ main(argc, argv)
if (options & F_SO_DONTROUTE)
(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
sizeof(hold));
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (options & F_POLICY) {
+ char *buf;
+ if (policy_in != NULL) {
+ buf = ipsec_set_policy(policy_in, strlen(policy_in));
+ if (buf == NULL)
+ errx(EX_CONFIG, ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG, "ipsec policy cannot be configured");
+ free(buf);
+ }
+
+ if (policy_out != NULL) {
+ buf = ipsec_set_policy(policy_out, strlen(policy_out));
+ if (buf == NULL)
+ errx(EX_CONFIG, ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG, "ipsec policy cannot be configured");
+ free(buf);
+ }
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
/* record route option */
if (options & F_RROUTE) {
@@ -1326,7 +1385,13 @@ usage()
{
fprintf(stderr, "%s\n%s\n%s\n",
"usage: ping [-QRadfnqrv] [-c count] [-i wait] [-l preload] [-p pattern]",
-" [-s packetsize] [-S src_addr]",
-" [host | [-L] [-I iface] [-T ttl] mcast-group]");
+" "
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+"[-P policy] "
+#endif
+#endif
+"[-s packetsize] [-S src_addr]",
+ "[host | [-L] [-I iface] [-T ttl] mcast-group]");
exit(EX_USAGE);
}
diff --git a/sbin/setkey/Makefile b/sbin/setkey/Makefile
new file mode 100644
index 0000000..918dbf4
--- /dev/null
+++ b/sbin/setkey/Makefile
@@ -0,0 +1,56 @@
+# Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+# $FreeBSD$
+
+PROG= setkey
+SRCS= setkey.c parse.y token.l
+CFLAGS+=-g
+LDADD+= -ll -ly
+CLEANFILES+= y.tab.c y.tab.h key_test.o keytest
+YFLAGS+=-d
+
+SCRIPTS= scriptdump
+
+BINOWN = root
+BINGRP = bin
+BINMODE = 555
+
+all: ${PROG} scriptdump
+
+SRCS+=y.tab.h
+y.tab.h: parse.y
+CFLAGS+=-DIPSEC_DEBUG -DINET6 -DYY_NO_UNPUT -I${.OBJDIR}
+LDADD+= -lipsec
+CLEANFILES+= scriptdump y.tab.h
+
+MAN8= setkey.8
+LOCALPREFIX= /usr/local
+
+scriptdump: scriptdump.pl
+ sed -e 's#@LOCALPREFIX@#${LOCALPREFIX}#' < $> > scriptdump
+
+.include <bsd.prog.mk>
diff --git a/sbin/setkey/parse.y b/sbin/setkey/parse.y
new file mode 100644
index 0000000..761c34d
--- /dev/null
+++ b/sbin/setkey/parse.y
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: parse.y,v 1.7 1999/10/27 17:08:57 sakane Exp $ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_var.h>
+#include <netinet6/ipsec.h>
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "vchar.h"
+
+#define ATOX(c) \
+ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
+
+u_int p_type;
+u_int32_t p_spi;
+struct sockaddr *p_src, *p_dst;
+u_int p_prefs, p_prefd, p_upper;
+u_int p_satype, p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode;
+u_int p_key_enc_len, p_key_auth_len;
+caddr_t p_key_enc, p_key_auth;
+time_t p_lt_hard, p_lt_soft;
+
+u_int p_policy_len;
+char *p_policy;
+
+/* temporary buffer */
+static struct sockaddr *pp_addr;
+static u_int pp_prefix;
+static u_int pp_port;
+static caddr_t pp_key;
+
+extern u_char m_buf[BUFSIZ];
+extern int m_len;
+extern char cmdarg[8192];
+extern int f_debug;
+
+int setkeymsg __P((void));
+static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int));
+void parse_init __P((void));
+void free_buffer __P((void));
+
+extern int setkeymsg __P((void));
+extern int sendkeymsg __P((void));
+
+extern int yylex __P((void));
+extern void yyerror __P((char *));
+%}
+
+%union {
+ unsigned long num;
+ vchar_t val;
+}
+
+%token EOT
+%token ADD GET DELETE FLUSH DUMP
+%token IP4_ADDRESS IP6_ADDRESS PREFIX PORT PORTANY
+%token UP_PROTO PR_ESP PR_AH PR_IPCOMP
+%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI
+%token F_MODE MODE
+%token F_EXT EXTENSION
+%token ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP
+%token F_LIFETIME_HARD F_LIFETIME_SOFT
+%token DECSTRING QUOTEDSTRING HEXSTRING ANY
+ /* SPD management */
+%token SPDADD SPDDELETE SPDDUMP SPDFLUSH
+%token F_POLICY PL_REQUESTS
+
+%%
+commands
+ : /*NOTHING*/
+ | commands command
+ {
+ if (f_debug) {
+ printf("cmdarg:\n%s\n", cmdarg);
+ } else {
+ setkeymsg();
+ sendkeymsg();
+ }
+ free_buffer();
+ parse_init();
+ }
+ ;
+
+command
+ : add_command
+ | get_command
+ | delete_command
+ | flush_command
+ | dump_command
+ | spdadd_command
+ | spddelete_command
+ | spddump_command
+ | spdflush_command
+ ;
+ /* commands concerned with management, there is in tail of this file. */
+
+ /* add command */
+add_command
+ : ADD { p_type = SADB_ADD; }
+ sa_selector_spec extension_spec algorithm_spec EOT
+ ;
+
+ /* delete */
+delete_command
+ : DELETE { p_type = SADB_DELETE; }
+ sa_selector_spec extension_spec EOT
+ ;
+
+ /* get command */
+get_command
+ : GET { p_type = SADB_GET; }
+ sa_selector_spec extension_spec EOT
+ ;
+
+ /* flush */
+flush_command
+ : FLUSH { p_type = SADB_FLUSH; }
+ protocol_spec EOT
+ ;
+
+ /* dump */
+dump_command
+ : DUMP { p_type = SADB_DUMP; }
+ protocol_spec EOT
+ ;
+
+ /* sa_selector_spec */
+sa_selector_spec
+ : ipaddress { p_src = pp_addr; }
+ ipaddress { p_dst = pp_addr; }
+ protocol_spec spi
+ ;
+
+protocol_spec
+ : /*NOTHING*/ { p_satype = SADB_SATYPE_UNSPEC; }
+ | PR_ESP
+ {
+ p_satype = SADB_SATYPE_ESP;
+ if ($1.num == 1)
+ p_ext |= SADB_X_EXT_OLD;
+ else
+ p_ext &= ~SADB_X_EXT_OLD;
+ }
+ | PR_AH
+ {
+ p_satype = SADB_SATYPE_AH;
+ if ($1.num == 1)
+ p_ext |= SADB_X_EXT_OLD;
+ else
+ p_ext &= ~SADB_X_EXT_OLD;
+ }
+ | PR_IPCOMP
+ {
+ p_satype = SADB_X_SATYPE_IPCOMP;
+ }
+ ;
+
+spi
+ : DECSTRING { p_spi = $1.num; }
+ | HEXSTRING
+ {
+ caddr_t bp;
+ caddr_t yp = $1.val.buf;
+ char buf0[4], buf[4];
+ int i, j;
+
+ /* sanity check */
+ if ($1.val.len > 4) {
+ yyerror("SPI too big.");
+ free($1.val.buf);
+ return -1;
+ }
+
+ bp = buf0;
+ while (*yp) {
+ *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]);
+ yp += 2, bp++;
+ }
+
+ /* initialize */
+ for (i = 0; i < 4; i++) buf[i] = 0;
+
+ for (j = $1.val.len - 1, i = 3; j >= 0; j--, i--)
+ buf[i] = buf0[j];
+
+ /* XXX: endian */
+ p_spi = ntohl(*(u_int32_t *)buf);
+
+ free($1.val.buf);
+ }
+ ;
+
+algorithm_spec
+ : esp_spec
+ | ah_spec
+ | ipcomp_spec
+ ;
+
+esp_spec
+ : F_ENC enc_alg enc_key F_AUTH auth_alg auth_key
+ | F_ENC enc_alg enc_key
+ ;
+
+ah_spec
+ : F_AUTH auth_alg auth_key
+ ;
+
+ipcomp_spec
+ : F_COMP ALG_COMP { p_alg_enc = $2.num; }
+ | F_COMP ALG_COMP { p_alg_enc = $2.num; }
+ F_RAWCPI { p_ext |= SADB_X_EXT_RAWCPI; }
+ ;
+
+enc_alg
+ : ALG_ENC { p_alg_enc = $1.num; }
+ | ALG_ENC_DESDERIV
+ {
+ p_alg_enc = $1.num;
+ if (p_ext & SADB_X_EXT_OLD) {
+ yyerror("algorithm mismatched.");
+ return -1;
+ }
+ p_ext |= SADB_X_EXT_DERIV;
+ }
+ | ALG_ENC_DES32IV
+ {
+ p_alg_enc = $1.num;
+ if (!(p_ext & SADB_X_EXT_OLD)) {
+ yyerror("algorithm mismatched.");
+ return -1;
+ }
+ p_ext |= SADB_X_EXT_IV4B;
+ }
+ ;
+
+enc_key
+ : /*NOTHING*/
+ {
+ if (p_alg_enc != SADB_EALG_NULL) {
+ yyerror("no key found.");
+ return -1;
+ }
+ }
+ | key_string
+ {
+ p_key_enc_len = $1.val.len;
+ p_key_enc = pp_key;
+
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc,
+ PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ ;
+
+auth_alg
+ : ALG_AUTH { p_alg_auth = $1.num; }
+ ;
+
+auth_key
+ : /*NOTHING*/
+ {
+ if (p_alg_auth != SADB_AALG_NULL) {
+ yyerror("no key found.");
+ return -1;
+ }
+ }
+ | key_string
+ {
+ p_key_auth_len = $1.val.len;
+ p_key_auth = pp_key;
+
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH,
+ p_alg_auth,
+ PFKEY_UNUNIT64(p_key_auth_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ ;
+
+key_string
+ : QUOTEDSTRING
+ {
+ pp_key = $1.val.buf;
+ /* free pp_key later */
+ }
+ | HEXSTRING
+ {
+ caddr_t bp;
+ caddr_t yp = $1.val.buf;
+
+ if ((pp_key = malloc($1.val.len)) == 0) {
+ free($1.val.buf);
+ yyerror(strerror(errno));
+ return -1;
+ }
+ memset(pp_key, 0, $1.val.len);
+
+ bp = pp_key;
+ while (*yp) {
+ *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]);
+ yp += 2, bp++;
+ }
+
+ free($1.val.buf);
+ }
+ ;
+
+extension_spec
+ : /*NOTHING*/
+ | extension_spec extension
+ ;
+
+extension
+ : F_EXT EXTENSION { p_ext |= $1.num; }
+ | F_MODE MODE { p_mode = $2.num; }
+ | F_MODE ANY { p_mode = IPSEC_MODE_ANY; }
+ | F_REPLAY DECSTRING
+ {
+ if (p_ext & SADB_X_EXT_OLD) {
+ yyerror("replay prevention "
+ "only use on new spec.");
+ return -1;
+ }
+ p_replay = $2.num;
+ }
+ | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2.num; }
+ | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2.num; }
+ ;
+
+ /* definition about command for SPD management */
+ /* spdadd */
+spdadd_command
+ : SPDADD
+ {
+ p_type = SADB_X_SPDADD;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ sp_selector_spec policy_spec EOT
+ ;
+
+spddelete_command:
+ SPDDELETE
+ {
+ p_type = SADB_X_SPDDELETE;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ sp_selector_spec EOT
+ ;
+
+spddump_command:
+ SPDDUMP
+ {
+ p_type = SADB_X_SPDDUMP;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ EOT
+ ;
+
+spdflush_command:
+ SPDFLUSH
+ {
+ p_type = SADB_X_SPDFLUSH;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ EOT
+ ;
+
+ /* sp_selector_spec */
+sp_selector_spec
+ : ipaddress { p_src = pp_addr; }
+ prefix { p_prefs = pp_prefix; }
+ port { _INPORTBYSA(p_src) = htons(pp_port); }
+ ipaddress { p_dst = pp_addr; }
+ prefix { p_prefd = pp_prefix; }
+ port { _INPORTBYSA(p_dst) = htons(pp_port); }
+ upper_spec
+ ;
+
+ipaddress
+ : IP4_ADDRESS
+ {
+ struct sockaddr_in *in;
+ u_int sa_len = $1.val.len;
+
+ if ((in = (struct sockaddr_in *)malloc(sa_len)) == 0) {
+ yyerror(strerror(errno));
+ free($1.val.buf);
+ return -1;
+ }
+ memset((caddr_t)in, 0, sa_len);
+
+ in->sin_family = PF_INET;
+ in->sin_len = sa_len;
+ in->sin_port = IPSEC_PORT_ANY;
+ (void)inet_pton(PF_INET, $1.val.buf, &in->sin_addr);
+
+ pp_addr = (struct sockaddr *)in;
+ free($1.val.buf);
+ }
+ | IP6_ADDRESS
+ {
+#ifdef INET6
+ struct sockaddr_in6 *in6;
+ u_int sa_len = $1.val.len;
+ struct addrinfo hints, *res;
+ int ret_gai;
+
+ if ((in6 = (struct sockaddr_in6 *)malloc(sa_len)) == 0) {
+ free($1.val.buf);
+ yyerror(strerror(errno));
+ return -1;
+ }
+ memset((caddr_t)in6, 0, sa_len);
+
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = AF_INET6;
+ ret_gai = getaddrinfo($1.val.buf, NULL, &hints, &res);
+ if (ret_gai) {
+ free($1.val.buf);
+ free(in6);
+ yyerror(gai_strerror(ret_gai));
+ if (ret_gai == EAI_SYSTEM)
+ yyerror(strerror(errno));
+ return -1;
+ }
+ (void)memcpy(in6, res->ai_addr, res->ai_addrlen);
+
+ /*
+ * XXX: If the scope of the destination is link-local,
+ * embed the scope-id(in this case, interface index)
+ * into the address.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr) &&
+ in6->sin6_scope_id != 0)
+ *(u_short *)&in6->sin6_addr.s6_addr[2] =
+ htons(in6->sin6_scope_id & 0xffff);
+
+ freeaddrinfo(res);
+
+ pp_addr = (struct sockaddr *)in6;
+#else
+ yyerror("IPv6 address not supported");
+#endif
+ free($1.val.buf);
+ }
+ ;
+
+prefix
+ : /*NOTHING*/ { pp_prefix = ~0; }
+ | PREFIX { pp_prefix = $1.num; }
+ ;
+
+port
+ : /*NOTHING*/ { pp_port = IPSEC_PORT_ANY; }
+ | PORT { pp_port = $1.num; }
+ | PORTANY { pp_port = IPSEC_PORT_ANY; }
+ ;
+
+upper_spec
+ : DECSTRING { p_upper = $1.num; }
+ | UP_PROTO { p_upper = $1.num; }
+ | PR_ESP { p_upper = IPPROTO_ESP; };
+ | PR_AH { p_upper = IPPROTO_AH; };
+ | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; };
+ | ANY { p_upper = IPSEC_ULPROTO_ANY; }
+ ;
+
+policy_spec
+ : F_POLICY policy_requests
+ {
+ p_policy = ipsec_set_policy($2.val.buf, $2.val.len);
+ if (p_policy == NULL) {
+ free($2.val.buf);
+ p_policy = NULL;
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+
+ p_policy_len = ipsec_get_policylen(p_policy);
+
+ free($2.val.buf);
+ }
+ ;
+
+policy_requests:
+ /*NOTHING*/
+ | PL_REQUESTS { $$ = $1; }
+ ;
+
+%%
+
+int
+setkeymsg()
+{
+ struct sadb_msg m_msg;
+
+ m_msg.sadb_msg_version = PF_KEY_V2;
+ m_msg.sadb_msg_type = p_type;
+ m_msg.sadb_msg_errno = 0;
+ m_msg.sadb_msg_satype = p_satype;
+ m_msg.sadb_msg_mode = p_mode;
+ m_msg.sadb_msg_reserved = 0;
+ m_msg.sadb_msg_seq = 0;
+ m_msg.sadb_msg_pid = getpid();
+
+ m_len = sizeof(struct sadb_msg);
+ memcpy(m_buf, &m_msg, m_len);
+
+ switch (p_type) {
+ case SADB_FLUSH:
+ case SADB_DUMP:
+ break;
+
+ case SADB_ADD:
+ /* set encryption algorithm, if present. */
+ if (p_satype != SADB_X_SATYPE_IPCOMP && p_alg_enc != SADB_EALG_NONE) {
+ struct sadb_key m_key;
+
+ m_key.sadb_key_len =
+ PFKEY_UNIT64(sizeof(m_key)
+ + PFKEY_ALIGN8(p_key_enc_len));
+ m_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+ m_key.sadb_key_bits = p_key_enc_len * 8;
+ m_key.sadb_key_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_key, sizeof(m_key),
+ (caddr_t)p_key_enc, p_key_enc_len);
+ }
+
+ /* set authentication algorithm, if present. */
+ if (p_alg_auth != SADB_AALG_NONE) {
+ struct sadb_key m_key;
+
+ m_key.sadb_key_len =
+ PFKEY_UNIT64(sizeof(m_key)
+ + PFKEY_ALIGN8(p_key_auth_len));
+ m_key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
+ m_key.sadb_key_bits = p_key_auth_len * 8;
+ m_key.sadb_key_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_key, sizeof(m_key),
+ (caddr_t)p_key_auth, p_key_auth_len);
+ }
+
+ /* set lifetime for HARD */
+ if (p_lt_hard != 0) {
+ struct sadb_lifetime m_lt;
+ u_int len = sizeof(struct sadb_lifetime);
+
+ m_lt.sadb_lifetime_len = PFKEY_UNIT64(len);
+ m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+ m_lt.sadb_lifetime_allocations = 0;
+ m_lt.sadb_lifetime_bytes = 0;
+ m_lt.sadb_lifetime_addtime = p_lt_hard;
+ m_lt.sadb_lifetime_usetime = 0;
+
+ memcpy(m_buf + m_len, &m_lt, len);
+ m_len += len;
+ }
+
+ /* set lifetime for SOFT */
+ if (p_lt_soft != 0) {
+ struct sadb_lifetime m_lt;
+ u_int len = sizeof(struct sadb_lifetime);
+
+ m_lt.sadb_lifetime_len = PFKEY_UNIT64(len);
+ m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+ m_lt.sadb_lifetime_allocations = 0;
+ m_lt.sadb_lifetime_bytes = 0;
+ m_lt.sadb_lifetime_addtime = p_lt_soft;
+ m_lt.sadb_lifetime_usetime = 0;
+
+ memcpy(m_buf + m_len, &m_lt, len);
+ m_len += len;
+ }
+ /* FALLTHROUGH */
+
+ case SADB_DELETE:
+ case SADB_GET:
+ {
+ struct sadb_sa m_sa;
+ struct sadb_address m_addr;
+ u_int len;
+
+ len = sizeof(struct sadb_sa);
+ m_sa.sadb_sa_len = PFKEY_UNIT64(len);
+ m_sa.sadb_sa_exttype = SADB_EXT_SA;
+ m_sa.sadb_sa_spi = htonl(p_spi);
+ m_sa.sadb_sa_replay = p_replay;
+ m_sa.sadb_sa_state = 0;
+ m_sa.sadb_sa_auth = p_alg_auth;
+ m_sa.sadb_sa_encrypt = p_alg_enc;
+ m_sa.sadb_sa_flags = p_ext;
+
+ memcpy(m_buf + m_len, &m_sa, len);
+ m_len += len;
+
+ /* set src */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_src->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen =
+ _INALENBYAF(p_src->sa_family) << 3;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_src, p_src->sa_len);
+
+ /* set dst */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_dst->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen =
+ _INALENBYAF(p_dst->sa_family) << 3;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_dst, p_dst->sa_len);
+ }
+ break;
+
+ /* for SPD management */
+ case SADB_X_SPDFLUSH:
+ case SADB_X_SPDDUMP:
+ break;
+
+ case SADB_X_SPDADD:
+ {
+ memcpy(m_buf + m_len, p_policy, p_policy_len);
+ m_len += p_policy_len;
+ free(p_policy);
+ p_policy = NULL;
+ }
+ /* FALLTHROUGH */
+
+ case SADB_X_SPDDELETE:
+ {
+ struct sadb_address m_addr;
+
+ /* set src */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_src->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = p_upper;
+ m_addr.sadb_address_prefixlen =
+ (p_prefs != ~0 ? p_prefs :
+ _INALENBYAF(p_src->sa_family) << 3);
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_src, p_src->sa_len);
+
+ /* set dst */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_dst->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = p_upper;
+ m_addr.sadb_address_prefixlen =
+ (p_prefd != ~0 ? p_prefd :
+ _INALENBYAF(p_dst->sa_family) << 3);
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_dst, p_dst->sa_len);
+ }
+ break;
+ }
+
+ ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len);
+
+ return 0;
+}
+
+static int
+setvarbuf(off, ebuf, elen, vbuf, vlen)
+ caddr_t vbuf;
+ struct sadb_ext *ebuf;
+ int *off, elen, vlen;
+{
+ memset(m_buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len));
+ memcpy(m_buf + *off, (caddr_t)ebuf, elen);
+ memcpy(m_buf + *off + elen, vbuf, vlen);
+ (*off) += PFKEY_ALIGN8(elen + vlen);
+
+ return 0;
+}
+
+void
+parse_init()
+{
+ p_type = 0;
+ p_spi = 0;
+
+ p_src = 0, p_dst = 0;
+ pp_prefix = p_prefs = p_prefd = ~0;
+ pp_port = IPSEC_PORT_ANY;
+ p_upper = 0;
+
+ p_satype = 0;
+ p_ext = SADB_X_EXT_NONE;
+ p_alg_enc = SADB_EALG_NONE;
+ p_alg_auth = SADB_AALG_NONE;
+ p_mode = IPSEC_MODE_ANY;
+ p_replay = 4;
+ p_key_enc_len = p_key_auth_len = 0;
+ p_key_enc = p_key_auth = 0;
+ p_lt_hard = p_lt_soft = 0;
+
+ p_policy_len = 0;
+ p_policy = NULL;
+
+ memset(cmdarg, 0, sizeof(cmdarg));
+
+ return;
+}
+
+void
+free_buffer()
+{
+ if (p_src) free(p_src);
+ if (p_dst) free(p_dst);
+ if (p_key_enc) free(p_key_enc);
+ if (p_key_auth) free(p_key_auth);
+
+ return;
+}
+
diff --git a/sbin/setkey/sample.cf b/sbin/setkey/sample.cf
new file mode 100644
index 0000000..886c449
--- /dev/null
+++ b/sbin/setkey/sample.cf
@@ -0,0 +1,219 @@
+# Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+# There are sample scripts for IPsec configuration by manual keying.
+# A security association is uniquely identified by a triple consisting
+# of a Security Parameter Index (SPI), an IP Destination Address, and a
+# security protocol (AH or ESP) identifier. You must take care of these
+# parameters when you configure by manual keying.
+
+# ESP transport mode is recommended for TCP port number 110 between
+# Host-A and Host-B. Encryption algorithm is blowfish-cbc whose key
+# is "kamekame", and authentication algorithm is hmac-sha1 whose key
+# is "this is the test key".
+#
+# ============ ESP ============
+# | |
+# Host-A Host-B
+# fec0::10 -------------------- fec0::11
+#
+# At Host-A and Host-B,
+spdadd fec0::10[any] fec0::11[110] tcp -P out ipsec
+ esp/transport/fec0::10-fec0::11/use ;
+spdadd fec0::11[110] fec0::10[any] tcp -P in ipsec
+ esp/transport/fec0::11-fec0::10/use ;
+add fec0::10 fec0::11 esp 0x10001
+ -m transport
+ -E blowfish-cbc "kamekame"
+ -A hmac-sha1 "this is the test key" ;
+add fec0::11 fec0::10 esp 0x10002
+ -m transport
+ -E blowfish-cbc "kamekame"
+ -A hmac-sha1 "this is the test key" ;
+
+# "[any]" is wildcard of port number. Note that "[0]" is the number of
+# zero in port number.
+
+# Security protocol is old AH tunnel mode, i.e. RFC1826, with keyed-md5
+# whose key is "this is the test" as authentication algorithm.
+# That protocol takes place between Gateway-A and Gateway-B.
+#
+# ======= AH =======
+# | |
+# Network-A Gateway-A Gateway-B Network-B
+# 10.0.1.0/24 ---- 172.16.0.1 ----- 172.16.0.2 ---- 10.0.2.0/24
+#
+# At Gateway-A:
+spdadd 10.0.1.0/24 10.0.2.0/24 any -P out ipsec
+ ah/tunnel/172.16.0.1-172.16.0.2/require ;
+spdadd 10.0.2.0/24 10.0.1.0/24 any -P in ipsec
+ ah/tunnel/172.16.0.2-172.16.0.1/require ;
+add 172.16.0.1 172.16.0.2 ah-old 0x10003
+ -m any
+ -A keyed-md5 "this is the test" ;
+add 172.16.0.2 172.16.0.1 ah-old 0x10004
+ -m any
+ -A keyed-md5 "this is the test" ;
+
+# If port number field is omitted such above then "[any]" is employed.
+# -m specifies the mode of SA to be used. "-m any" means wildcard of
+# mode of security protocol. You can use this SAs for both tunnel and
+# transport mode.
+
+# At Gateway-B. Attention to the selector and peer's IP address for tunnel.
+spdadd 10.0.2.0/24 10.0.1.0/24 any -P out ipsec
+ ah/tunnel/172.16.0.2-172.16.0.1/require ;
+spdadd 10.0.1.0/24 10.0.2.0/24 any -P in ipsec
+ ah/tunnel/172.16.0.1-172.16.0.2/require ;
+add 172.16.0.1 172.16.0.2 ah-old 0x10003
+ -m tunnel
+ -A keyed-md5 "this is the test" ;
+add 172.16.0.2 172.16.0.1 ah-old 0x10004
+ -m tunnel
+ -A keyed-md5 "this is the test" ;
+
+# AH transport mode followed by ESP tunnel mode is required between
+# Gateway-A and Gateway-B.
+# Encryption algorithm is 3des-cbc, and authentication algorithm for ESP
+# is hmac-sha1. Authentication algorithm for AH is hmac-md5.
+#
+# ========== AH =========
+# | ======= ESP ===== |
+# | | | |
+# Network-A Gateway-A Gateway-B Network-B
+# fec0:0:0:1::/64 --- fec0:0:0:1::1 ---- fec0:0:0:2::1 --- fec0:0:0:2::/64
+#
+# At Gateway-A:
+spdadd fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out ipsec
+ esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require
+ ah/transport/fec0:0:0:1::1-fec0:0:0:2::1/require ;
+spdadd fec0:0:0:2::/64 fec0:0:0:1::/64 any -P in ipsec
+ esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require
+ ah/transport/fec0:0:0:2::1-fec0:0:0:1::1/require ;
+add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10001
+ -m tunnel
+ -E 3des-cbc "kamekame12341234kame1234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:1::1 fec0:0:0:2::1 ah 0x10001
+ -m transport
+ -A hmac-md5 "this is the test" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10001
+ -m tunnel
+ -E 3des-cbc "kamekame12341234kame1234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 ah 0x10001
+ -m transport
+ -A hmac-md5 "this is the test" ;
+
+# ESP tunnel mode is required between Host-A and Gateway-A.
+# Encryption algorithm is cast128-cbc, and authentication algorithm
+# for ESP is hmac-sha1.
+# ESP transport mode is recommended between Host-A and Host-B.
+# Encryption algorithm is rc5-cbc, and authentication algorithm
+# for ESP is hmac-md5.
+#
+# ================== ESP =================
+# | ======= ESP ======= |
+# | | | |
+# Host-A Gateway-A Host-B
+# fec0:0:0:1::1 ---- fec0:0:0:2::1 ---- fec0:0:0:2::2
+#
+# At Host-A:
+spdadd fec0:0:0:1::1[any] fec0:0:0:2::2[80] tcp -P out ipsec
+ esp/transport/fec0:0:0:1::1-fec0:0:0:2::2/use
+ esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require ;
+spdadd fec0:0:0:2::1[80] fec0:0:0:1::1[any] tcp -P in ipsec
+ esp/transport/fec0:0:0:2::2-fec0:0:0:1::1/use
+ esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require ;
+add fec0:0:0:1::1 fec0:0:0:2::2 esp 0x10001
+ -m transport
+ -E cast128-cbc "12341234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10002
+ -E rc5-cbc "kamekame"
+ -A hmac-md5 "this is the test" ;
+add fec0:0:0:2::2 fec0:0:0:1::1 esp 0x10003
+ -m transport
+ -E cast128-cbc "12341234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10004
+ -E rc5-cbc "kamekame"
+ -A hmac-md5 "this is the test" ;
+
+# By "get" command, you can get a entry of either SP or SA.
+get fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ;
+
+# Also delete command, you can delete a entry of either SP or SA.
+spddelete out fec0:0:0:1::/64 fec0:0:0:2:/64 any ;
+delete fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ;
+
+# By dump command, you can dump all entry of either SP or SA.
+dump ;
+spddump ;
+dump esp ;
+flush esp ;
+
+# By flush command, you can flush all entry of either SP or SA.
+flush ;
+spdflush ;
+
+# "flush" and "dump" commands can specify a security protocol.
+dump esp ;
+flush ah ;
+
+# XXX
+add ::1 ::1 esp 10001 -m transport -E simple ;
+add ::1 ::1 esp 10002 -m transport -E des-deriv "12341234" ;
+add ::1 ::1 esp-old 10003 -m transport -E des-32iv "12341234" ;
+add ::1 ::1 esp 10004 -m transport -E simple -A null ;
+add ::1 ::1 esp 10005 -m transport -E simple -A hmac-md5 "1234123412341234" ;
+add ::1 ::1 esp 10006 -m tunnel -E simple -A hmac-sha1 "12341234123412341234" ;
+add ::1 ::1 esp 10007 -m transport -E simple -A keyed-md5 "1234123412341234" ;
+add ::1 ::1 esp 10008 -m any -E simple -A keyed-sha1 "12341234123412341234" ;
+add ::1 ::1 esp 10009 -m transport -E des-cbc "testtest" ;
+add ::1 ::1 esp 10010 -m transport -E 3des-cbc "testtest12341234testtest" ;
+add ::1 ::1 esp 10011 -m tunnel -E cast128-cbc "testtest1234" ;
+add ::1 ::1 esp 10012 -m tunnel -E blowfish-cbc "testtest1234" ;
+add ::1 ::1 esp 10013 -m tunnel -E rc5-cbc "testtest1234" ;
+add ::1 ::1 esp 10014 -m any -E rc5-cbc "testtest1234" ;
+add ::1 ::1 esp 10015 -m transport -f zero-pad -E simple ;
+add ::1 ::1 esp 10016 -m tunnel -f random-pad -r 8 -lh 100 -ls 80 -E simple ;
+add ::1 ::1 esp 10017 -m transport -f seq-pad -f cyclic-seq -E simple ;
+add ::1 ::1 esp 10018 -m transport -E simple ;
+#add ::1 ::1 ah 20000 -m transport -A null ;
+add ::1 ::1 ah 20001 -m any -A hmac-md5 "1234123412341234";
+add ::1 ::1 ah 20002 -m tunnel -A hmac-sha1 "12341234123412341234";
+add ::1 ::1 ah 20003 -m transport -A keyed-md5 "1234123412341234";
+add ::1 ::1 ah-old 20004 -m transport -A keyed-md5 "1234123412341234";
+add ::1 ::1 ah 20005 -m transport -A keyed-sha1 "12341234123412341234";
+#add ::1 ::1 ipcomp 30000 -C oui ;
+add ::1 ::1 ipcomp 30001 -C deflate ;
+#add ::1 ::1 ipcomp 30002 -C lzs ;
+
+# enjoy.
diff --git a/sbin/setkey/scriptdump.pl b/sbin/setkey/scriptdump.pl
new file mode 100644
index 0000000..5df9b4f
--- /dev/null
+++ b/sbin/setkey/scriptdump.pl
@@ -0,0 +1,54 @@
+#! @LOCALPREFIX@/bin/perl
+# $FreeBSD$
+
+if ($< != 0) {
+ print STDERR "must be root to invoke this\n";
+ exit 1;
+}
+
+$mode = 'add';
+while ($i = shift @ARGV) {
+ if ($i eq '-d') {
+ $mode = 'delete';
+ } else {
+ print STDERR "usage: scriptdump [-d]\n";
+ exit 1;
+ }
+}
+
+open(IN, "setkey -D |") || die;
+foreach $_ (<IN>) {
+ if (/^[^\t]/) {
+ ($src, $dst) = split(/\s+/, $_);
+ } elsif (/^\t(esp|ah) mode=(\S+) spi=(\d+).*replay=(\d+)/) {
+ ($proto, $ipsecmode, $spi, $replay) = ($1, $2, $3, $4);
+ } elsif (/^\tE: (\S+) (.*)/) {
+ $ealgo = $1;
+ $ekey = $2;
+ $ekey =~ s/\s//g;
+ $ekey =~ s/^/0x/g;
+ } elsif (/^\tA: (\S+) (.*)/) {
+ $aalgo = $1;
+ $akey = $2;
+ $akey =~ s/\s//g;
+ $akey =~ s/^/0x/g;
+ } elsif (/^\tstate=/) {
+ print "$mode $src $dst $proto $spi -m $ipsecmode";
+ print " -r $replay" if $replay;
+ if ($mode eq 'add') {
+ if ($proto eq 'esp') {
+ print " -E $ealgo $ekey" if $ealgo;
+ print " -A $aalgo $akey" if $aalgo;
+ } elsif ($proto eq 'ah') {
+ print " -A $aalgo $akey" if $aalgo;
+ }
+ }
+ print ";\n";
+
+ $src = $dst = $upper = $proxy = '';
+ $ealgo = $ekey = $aalgo = $akey = '';
+ }
+}
+close(IN);
+
+exit 0;
diff --git a/sbin/setkey/setkey.8 b/sbin/setkey/setkey.8
new file mode 100644
index 0000000..1f6f33c
--- /dev/null
+++ b/sbin/setkey/setkey.8
@@ -0,0 +1,550 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: setkey.8,v 1.14 1999/10/27 17:08:58 sakane Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 17, 1998
+.Dt SETKEY 8
+.Os KAME
+.\"
+.Sh NAME
+.Nm setkey
+.Nd manually manipulate the SA/SP database.
+.\"
+.Sh SYNOPSIS
+.Nm setkey
+.Op Fl dv
+.Fl c
+.Nm setkey
+.Op Fl dv
+.Fl f Ar filename
+.Nm setkey
+.Op Fl adPlv
+.Fl D
+.Nm setkey
+.Op Fl dPv
+.Fl F
+.Nm setkey
+.Op Fl h
+.Fl x
+.\"
+.Sh DESCRIPTION
+.Nm
+updates, or lists the content of, Security Association Database (SAD) entries
+in the kernel as well as Security Policy Database (SPD) entries.
+.Pp
+.Nm
+takes a series of operation from standard input
+.Po
+if invoked with
+.Fl c
+.Pc
+or file named
+.Ar filename
+.Po
+if invoked with
+.Fl f Ar filename
+.Pc .
+.Bl -tag -width Ds
+.It Fl D
+Dump the SAD entries.
+If with
+.Fl P ,
+the SPD entries are dumped.
+.It Fl F
+Flush the SAD.
+If with
+.Fl P ,
+the SPD are flushed.
+.It Fl a
+.Nm
+usually do not display dead SAD entries on
+.Fl D .
+With
+.Fl a ,
+dead SAD entries will be displayed as well.
+Dead SAD entries are kept in the kernel,
+when they are referenced from any of SPD entries in the kernel.
+.It Fl d
+Enable debugging messages.
+.It Fl x
+Loop forever and dump all the messages transmitted to
+.Dv PF_KEY
+socket.
+.It Fl h
+Add hexadecimal dump on
+.Fl x
+mode. The order is significant.
+.It Fl l
+Loop forever with short output on
+.Fl D .
+.It Fl v
+Be verbose.
+.Dv PF_KEY
+socket
+.Po
+including messages sent from other processes
+.Pc .
+.El
+.Pp
+Operation has the following grammar. Note that lines, that start with a
+hashmark ('#') are treated as comment lines.
+Description of meta-arguments follows.
+.Bl -tag -width Ds
+.It Xo
+.Li add
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar extensions
+.Ar algorithm...
+.Li ;
+.Xc
+Add a SAD entry.
+.\"
+.It Xo
+.Li get
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar mode
+.Li ;
+.Xc
+Show a SAD entry.
+.\"
+.It Xo
+.Li delete
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar mode
+.Li ;
+.Xc
+Remove a SAD entry.
+.\"
+.It Xo
+.Li flush
+.Op Ar protocol
+.Li ;
+.Xc
+Clear all SAD entries that matches the options.
+.\"
+.It Xo
+.Li dump
+.Op Ar protocol
+.Li ;
+.Xc
+Dumps all SAD entries that matches the options.
+.\"
+.It Xo
+.Li spdadd
+.Ar src_range Ar dst_range Ar upperspec Ar policy
+.Li ;
+.Xc
+Add a SPD entry.
+.\"
+.It Xo
+.Li spddelete
+.Ar src_range Ar dst_range Ar upperspec
+.Li ;
+.Xc
+Delete a SPD entry.
+.\"
+.It Xo
+.Li spdflush
+.Li ;
+.Xc
+Clear all SPD entries.
+.\"
+.It Xo
+.Li spddump
+.Li ;
+.Xc
+Dumps all SAD entries.
+.El
+.\"
+.Pp
+Meta-arguments are as follows:
+.Bl -tag -compact -width Ds
+.It Ar src
+.It Ar dst
+Source/destination of the secure communication is specified as
+IPv4/v6 address.
+.Nm
+does not consult hostname-to-address for arguments
+.Ar src
+and
+.Ar dst .
+They must be in numeric form.
+.\"
+.Pp
+.It Ar protocol
+.Ar protocol
+is one of following:
+.Bl -tag -width Fl -compact
+.It Li esp
+ESP based on rfc2405
+.It Li esp-old
+ESP based on rfc1827
+.It Li ah
+AH based on rfc2402
+.It Li ah-old
+AH based on rfc1826
+.It Li ipcomp
+IPCOMP
+.El
+.\"
+.Pp
+.It Ar spi
+Security Parameter Index (SPI) for the SA and SPD.
+It must be decimal number or hexadecimal number
+.Po
+with
+.Li 0x
+attached
+.Pc .
+.\"
+.Pp
+.It Ar extensions
+takes some of the following:
+.Bl -tag -width Fl -compact
+.It Fl m Ar mode
+Specify an security protocol mode for use. By default,
+.Li any .
+.Ar mode
+is one of following:
+.Li transport , tunnel
+or
+.Li any .
+.It Fl r Ar size
+Specify window size of bytes for replay prevention.
+.Ar size
+must be decimal number in 32-bit word. If
+.Ar size
+is zero or not specified, replay check don't take place.
+.It Fl f Ar pad_option
+.Ar pad_option
+is one of following:
+.Li zero-pad , random-pad
+or
+.Li seq-pad
+.It Fl f Li cyclic-seq
+Allow cyclic sequence number.
+.It Fl lh Ar time
+.It Fl ls Ar time
+Specify hard/soft lifetime.
+.El
+.\"
+.Pp
+.It Ar algorithm
+.Bl -tag -width Fl -compact
+.It Fl E Ar ealgo Ar key
+Specify encryption algorithm.
+.It Fl A Ar ealgo Ar key
+Specify authentication algorithm.
+If
+.Fl A
+is used for esp, it will be treated as ESP payload authentication algorithm.
+.It Fl C Ar calgo Op Fl R
+Specify compression algorithm.
+If
+.Fl R
+is specified with
+.Li ipcomp
+line, the kernel will use well-known IPComp CPI
+.Pq compression parameter index
+on IPComp CPI field on packets, and
+.Ar spi
+field will be ignored.
+.Ar spi
+field is only for kernel internal use in this case.
+.\"Therefore, compression protocol number will appear on IPComp CPI field.
+If
+.Fl R
+is not used,
+the value on
+.Ar spi
+field will appear on IPComp CPI field on outgoing packets.
+.Ar spi
+field needs to be smaller than
+.Li 0x10000
+in this case.
+.El
+.Pp
+.Li esp
+SAs accept
+.Fl E
+and
+.Fl A .
+.Li esp-old
+SAs accept
+.Fl E
+only.
+.Li ah
+and
+.Li ah-old
+SAs accept
+.Fl A
+only.
+.Li ipcomp
+SAs accept
+.Fl C
+only.
+.Pp
+.Ar key
+must be double-quoted character string or a series of hexadecimal digits.
+.Pp
+Possible values for
+.Ar ealgo ,
+.Ar aalgo
+and
+.Ar calgo
+are specified in separate section.
+.\"
+.It Ar src_range
+.It Ar dst_range
+These are selection of the secure communication is specified as
+IPv4/v6 address or IPv4/v6 address range, and it may accompany
+TCP/UDP port specification.
+This takes the following form:
+.Bd -literal -offset
+.Ar address
+.Ar address/prefixlen
+.Ar address[port]
+.Ar address/prefixlen[port]
+.Ed
+.Pp
+.Ar prefixlen
+and
+.Ar port
+must be decimal number.
+The square bracket around
+.Ar port
+is really necessary.
+They are not manpage metacharacters.
+.Pp
+.Nm
+does not consult hostname-to-address for arguments
+.Ar src
+and
+.Ar dst .
+They must be in numeric form.
+.\"
+.It Ar upperspec
+Upper-layer protocol to be used.
+Currently
+.Li tcp ,
+.Li udp
+and
+.Li any
+can be specified.
+.Li any
+stands for
+.Dq any protocol .
+.Pp
+NOTE:
+.Ar upperspec
+does not work against forwarding case at this moment,
+as it requires extra reassembly at forwarding node
+.Pq not implemented as this moment .
+.\"
+.It Ar policy
+.Ar policy
+is the one of following:
+.Bd -literal -offset
+.Xo
+.Fl P
+.Ar direction
+.Li discard
+.Xc
+.Xo
+.Fl P
+.Ar direction
+.Li none
+.Xc
+.Xo
+.Fl P
+.Ar direction
+.Li ipsec
+.Ar protocol/mode/src-dst/level
+.Xc
+.Ed
+.Pp
+You must specify the direction of its policy as
+.Ar direction .
+Either
+.Li out
+or
+.Li in
+are used.
+.Li discard
+means the packet matching indexes will be discarded.
+.Li none
+means that IPsec operation will not take place onto the packet.
+.Li ipsec
+means that IPsec operation will take place onto the packet.
+Either
+.Li ah ,
+.Li esp
+or
+.Li ipcomp
+is to be set as
+.Ar protocol .
+.Ar mode
+is either
+.Li transport
+or
+.Li tunnel .
+You must specify the end-points addresses of the SA as
+.Ar src
+and
+.Ar dst
+with
+.Sq -
+between these addresses which is used to specify the SA to use.
+.Ar level
+is to be one of the following:
+.Li default , use
+or
+.Li require .
+.Li default
+means kernel consults to the system wide default against protocol you
+specified, e.g.
+.Li esp_trans_deflev
+sysctl variable, when kernel processes the packet.
+.Li use
+means that kernel use a SA if it's available,
+otherwise kernel keeps normal operation.
+.Li require
+means SA is required whenever kernel deals with the packet.
+Note that
+.Dq Li discard
+and
+.Dq Li none
+are not in the syntax described in
+.Xr ipsec_set_policy 3 .
+There are little differences in the syntax.
+See
+.Xr ipsec_set_policy 3
+for detail.
+.Pp
+.El
+.Pp
+.\"
+.Sh ALGORITHMS
+The following list shows the supported algorithms.
+.Sy protocol
+and
+.Sy algorithm
+are almost orthogonal.
+Following are the list of authentication algorithms that can be used as
+.Ar aalgo
+in
+.Fl A Ar aalgo
+of
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm keylen (bits) comment
+hmac-md5 128 ah: rfc2403
+ 128 ah-old: rfc2085
+hmac-sha1 160 ah: rfc2404
+ 160 ah-old: 128bit ICV (no document)
+keyed-md5 128 ah: 96bit ICV (no document)
+ 128 ah-old: rfc1828
+keyed-sha1 160 ah: 96bit ICV (no document)
+ 160 ah-old: 128bit ICV (no document)
+null 0 to 2048 for debugging
+.Ed
+.Pp
+Following are the list of encryption algorithms that can be used as
+.Ar ealgo
+in
+.Fl E Ar ealgo
+of
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm keylen (bits) comment
+des-cbc 64 esp-old: rfc1829, esp: rfc2405
+3des-cbc 192 rfc2451
+simple 0 to 2048 rfc2410
+blowfish-cbc 40 to 448 rfc2451
+cast128-cbc 40 to 128 rfc2451
+rc5-cbc 40 to 2040 rfc2451
+des-deriv 64 ipsec-ciph-des-derived-01 (expired)
+3des-deriv 192 no document
+.Ed
+.Pp
+Following are the list of compression algorithms that can be used as
+.Ar calgo
+in
+.Fl C Ar calgo
+of
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm comment
+deflate rfc2394
+lzs rfc2395
+.Ed
+.\"
+.Sh EXAMPLES
+.Bd -literal -offset
+add 3ffe:501:4819::1 3ffe:501:481d::1 esp 123457
+ -E des-cbc "ESP SA!!"
+
+add 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456
+ -A hmac-sha1 "AH SA configuration!" ;
+
+add 10.0.11.41 10.0.11.33 esp 0x10001
+ -E des-cbc "ESP with"
+ -A hmac-md5 "authentication!!" ;
+
+get 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 ;
+
+flush ;
+
+dump esp ;
+
+spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any
+ -P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ;
+
+.Ed
+.\"
+.Sh RETURN VALUES
+The command exits with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr ipsec_set_policy 3 ,
+.Xr sysctl 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+The command was completely re-designed in June 1998.
+.\"
+.\" .Sh BUGS
diff --git a/sbin/setkey/setkey.c b/sbin/setkey/setkey.c
new file mode 100644
index 0000000..73edc3f
--- /dev/null
+++ b/sbin/setkey/setkey.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: setkey.c,v 1.5 1999/10/26 09:39:37 sakane Exp $ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <err.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netkey/key_debug.h>
+#include <netinet6/ipsec.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+
+void Usage __P((void));
+int main __P((int, char **));
+int get_supported __P((void));
+void sendkeyshort __P((u_int));
+void promisc __P((void));
+int sendkeymsg __P((void));
+int postproc __P((struct sadb_msg *, int));
+const char *numstr __P((int));
+void shortdump_hdr __P((void));
+void shortdump __P((struct sadb_msg *));
+
+#define MODE_SCRIPT 1
+#define MODE_CMDDUMP 2
+#define MODE_CMDFLUSH 3
+
+int so;
+
+int f_forever = 0;
+int f_all = 0;
+int f_debug = 0;
+int f_verbose = 0;
+int f_mode = 0;
+int f_cmddump = 0;
+int f_policy = 0;
+int f_promisc = 0;
+int f_hexdump = 0;
+char *pname;
+
+u_char m_buf[BUFSIZ];
+u_int m_len;
+
+extern int lineno;
+
+extern int parse __P((FILE **));
+
+void
+Usage()
+{
+ printf("Usage:\t%s [-dv] -c\n", pname);
+ printf("\t%s [-dv] -f (file)\n", pname);
+ printf("\t%s [-Padlv] -D\n", pname);
+ printf("\t%s [-Pdv] -F\n", pname);
+ printf("\t%s [-h] -x\n", pname);
+ pfkey_close(so);
+ exit(0);
+}
+
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ FILE *fp = stdin;
+ int c;
+
+ pname = *av;
+
+ if (ac == 1) Usage();
+
+ while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) {
+ switch (c) {
+ case 'c':
+ f_mode = MODE_SCRIPT;
+ fp = stdin;
+ break;
+ case 'f':
+ f_mode = MODE_SCRIPT;
+ if ((fp = fopen(optarg, "r")) == NULL) {
+ err(-1, "fopen");
+ /*NOTREACHED*/
+ }
+ break;
+ case 'D':
+ f_mode = MODE_CMDDUMP;
+ break;
+ case 'F':
+ f_mode = MODE_CMDFLUSH;
+ break;
+ case 'a':
+ f_all = 1;
+ break;
+ case 'l':
+ f_forever = 1;
+ break;
+ case 'h':
+ f_hexdump = 1;
+ break;
+ case 'x':
+ f_promisc = 1;
+ promisc();
+ /*NOTREACHED*/
+ case 'P':
+ f_policy = 1;
+ break;
+ case 'd':
+ f_debug = 1;
+ break;
+ case 'v':
+ f_verbose = 1;
+ break;
+ default:
+ Usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ switch (f_mode) {
+ case MODE_CMDDUMP:
+ sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP);
+ break;
+ case MODE_CMDFLUSH:
+ sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
+ pfkey_close(so);
+ break;
+ case MODE_SCRIPT:
+ if (get_supported() < 0) {
+ errx(-1, "%s", ipsec_strerror());
+ /*NOTREACHED*/
+ }
+ parse(&fp);
+ break;
+ default:
+ Usage();
+ }
+
+ exit(0);
+}
+
+int
+get_supported()
+{
+ int so;
+
+ if ((so = pfkey_open()) < 0) {
+ perror("pfkey_open");
+ return -1;
+ }
+
+ /* debug mode ? */
+ if (f_debug)
+ return 0;
+
+ if (pfkey_send_register(so, PF_UNSPEC) < 0)
+ return -1;
+
+ if (pfkey_recv_register(so) < 0)
+ return -1;
+
+ return 0;
+}
+
+void
+sendkeyshort(type)
+ u_int type;
+{
+ struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
+
+ m_len = sizeof(struct sadb_msg);
+
+ m_msg->sadb_msg_version = PF_KEY_V2;
+ m_msg->sadb_msg_type = type;
+ m_msg->sadb_msg_errno = 0;
+ m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
+ m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_seq = 0;
+ m_msg->sadb_msg_pid = getpid();
+
+ sendkeymsg();
+
+ return;
+}
+
+void
+promisc()
+{
+ struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
+ u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+ int so, len;
+
+ m_len = sizeof(struct sadb_msg);
+
+ m_msg->sadb_msg_version = PF_KEY_V2;
+ m_msg->sadb_msg_type = SADB_X_PROMISC;
+ m_msg->sadb_msg_errno = 0;
+ m_msg->sadb_msg_satype = 1;
+ m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_seq = 0;
+ m_msg->sadb_msg_pid = getpid();
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ err(1, "socket(PF_KEY)");
+ /*NOTREACHED*/
+ }
+
+ if ((len = send(so, m_buf, m_len, 0)) < 0) {
+ err(1, "send");
+ /*NOTREACHED*/
+ }
+
+ while (1) {
+ struct sadb_msg *base;
+
+ if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
+ err(1, "recv");
+ /*NOTREACHED*/
+ }
+
+ if (len != sizeof(*base))
+ continue;
+
+ base = (struct sadb_msg *)rbuf;
+ if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
+ 0)) < 0) {
+ err(1, "recv");
+ /*NOTREACHED*/
+ }
+ if (f_hexdump) {
+ int i;
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0)
+ printf("%08x: ", i);
+ printf("%02x ", rbuf[i] & 0xff);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ if (len % 16)
+ printf("\n");
+ }
+ /* adjust base pointer for promisc mode */
+ if (base->sadb_msg_type == SADB_X_PROMISC) {
+ if (sizeof(*base) < len)
+ base++;
+ else
+ base = NULL;
+ }
+ if (base) {
+ kdebug_sadb(base);
+ printf("\n");
+ fflush(stdout);
+ }
+ }
+}
+
+int
+sendkeymsg()
+{
+ int so;
+
+ u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+ int len;
+ struct sadb_msg *msg;
+
+ if ((so = pfkey_open()) < 0) {
+ perror("pfkey_open");
+ return -1;
+ }
+
+ {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ perror("setsockopt");
+ goto end;
+ }
+ }
+
+ if (f_forever)
+ shortdump_hdr();
+again:
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)m_buf);
+
+ if ((len = send(so, m_buf, m_len, 0)) < 0) {
+ perror("send");
+ goto end;
+ }
+
+ msg = (struct sadb_msg *)rbuf;
+ do {
+ if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+ perror("recv");
+ goto end;
+ }
+
+ if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) {
+ warnx("invalid keymsg length");
+ break;
+ }
+
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)rbuf);
+ if (postproc(msg, len) < 0)
+ break;
+ } while (msg->sadb_msg_errno || msg->sadb_msg_seq);
+
+ if (f_forever) {
+ fflush(stdout);
+ sleep(1);
+ goto again;
+ }
+
+end:
+ pfkey_close(so);
+ return(0);
+}
+
+int
+postproc(msg, len)
+ struct sadb_msg *msg;
+ int len;
+{
+
+ if (msg->sadb_msg_errno != 0) {
+ char inf[80];
+ char *errmsg = NULL;
+
+ if (f_mode == MODE_SCRIPT)
+ snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
+ else
+ inf[0] = '\0';
+
+ switch (msg->sadb_msg_errno) {
+ case ENOENT:
+ switch (msg->sadb_msg_type) {
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_X_SPDDELETE:
+ errmsg = "No entry";
+ break;
+ case SADB_DUMP:
+ errmsg = "No SAD entries";
+ break;
+ case SADB_X_SPDDUMP:
+ errmsg = "No SPD entries";
+ break;
+ }
+ break;
+ default:
+ errmsg = strerror(msg->sadb_msg_errno);
+ }
+ printf("%s%s.\n", inf, errmsg);
+ return(-1);
+ }
+
+ switch (msg->sadb_msg_type) {
+ case SADB_GET:
+ pfkey_sadump(msg);
+ break;
+
+ case SADB_DUMP:
+ /* filter out DEAD SAs */
+ if (!f_all) {
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_sa *sa;
+ pfkey_align(msg, mhp);
+ pfkey_check(mhp);
+ if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
+ if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
+ break;
+ }
+ }
+ if (f_forever)
+ shortdump(msg);
+ else
+ pfkey_sadump(msg);
+ msg = (struct sadb_msg *)((caddr_t)msg +
+ PFKEY_UNUNIT64(msg->sadb_msg_len));
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)msg);
+ break;
+
+ case SADB_X_SPDDUMP:
+ pfkey_spdump(msg);
+ if (msg->sadb_msg_seq == 0) break;
+ msg = (struct sadb_msg *)((caddr_t)msg +
+ PFKEY_UNUNIT64(msg->sadb_msg_len));
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)msg);
+ break;
+ }
+
+ return(0);
+}
+
+/*------------------------------------------------------------*/
+static char *satype[] = {
+ NULL, NULL, "ah", "esp"
+};
+static char *sastate[] = {
+ "L", "M", "D", "d"
+};
+static char *ipproto[] = {
+/*0*/ "ip", "icmp", "igmp", "ggp", "ip4",
+ NULL, "tcp", NULL, "egp", NULL,
+/*10*/ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "udp", NULL, NULL,
+/*20*/ NULL, NULL, "idp", NULL, NULL,
+ NULL, NULL, NULL, NULL, "tp",
+/*30*/ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+/*40*/ NULL, "ip6", NULL, "rt6", "frag6",
+ NULL, "rsvp", "gre", NULL, NULL,
+/*50*/ "esp", "ah", NULL, NULL, NULL,
+ NULL, NULL, NULL, "icmp6", "none",
+/*60*/ "dst6",
+};
+
+#define STR_OR_ID(x, tab) \
+ (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x))
+
+const char *
+numstr(x)
+ int x;
+{
+ static char buf[20];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+shortdump_hdr()
+{
+ printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
+ "time", "p", "s", "spi", "ltime", "src", "dst");
+}
+
+void
+shortdump(msg)
+ struct sadb_msg *msg;
+{
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ char buf[1024], pbuf[10];
+ struct sadb_sa *sa;
+ struct sadb_address *saddr;
+ struct sadb_lifetime *lts, *lth, *ltc;
+ struct sockaddr *s;
+ u_int t;
+ time_t cur = time(0);
+
+ pfkey_align(msg, mhp);
+ pfkey_check(mhp);
+
+ printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
+
+ printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
+
+ if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
+ printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
+ printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
+ } else
+ printf("%-1s %-8s", "?", "?");
+
+ lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
+ lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+ ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
+ if (lts && lth && ltc) {
+ if (ltc->sadb_lifetime_addtime == 0)
+ t = (u_long)0;
+ else
+ t = (u_long)(cur - ltc->sadb_lifetime_addtime);
+ if (t >= 1000)
+ strcpy(buf, " big/");
+ else
+ snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
+ printf("%s", buf);
+
+ t = (u_long)lth->sadb_lifetime_addtime;
+ if (t >= 1000)
+ strcpy(buf, "big");
+ else
+ snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
+ printf("%s", buf);
+ } else
+ printf(" ???/???");
+
+ printf(" ");
+
+ if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
+ if (saddr->sadb_address_proto)
+ printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
+ s = (struct sockaddr *)(saddr + 1);
+ getnameinfo(s, s->sa_len, buf, sizeof(buf),
+ pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
+ if (strcmp(pbuf, "0") != 0)
+ printf("%s[%s]", buf, pbuf);
+ else
+ printf("%s", buf);
+ } else
+ printf("?");
+
+ printf(" -> ");
+
+ if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
+ if (saddr->sadb_address_proto)
+ printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
+
+ s = (struct sockaddr *)(saddr + 1);
+ getnameinfo(s, s->sa_len, buf, sizeof(buf),
+ pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
+ if (strcmp(pbuf, "0") != 0)
+ printf("%s[%s]", buf, pbuf);
+ else
+ printf("%s", buf);
+ } else
+ printf("?");
+
+ printf("\n");
+}
diff --git a/sbin/setkey/test-pfkey.c b/sbin/setkey/test-pfkey.c
new file mode 100644
index 0000000..849aba3
--- /dev/null
+++ b/sbin/setkey/test-pfkey.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: test-pfkey.c,v 1.2 1999/10/26 08:09:17 itojun Exp $ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <net/pfkeyv2.h>
+#include <netinet/in.h>
+#include <netkey/keydb.h>
+#include <netkey/key_var.h>
+#include <netkey/key_debug.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+u_char m_buf[BUFSIZ];
+u_int m_len;
+char *pname;
+
+void Usage __P((void));
+int sendkeymsg __P((void));
+void key_setsadbmsg __P((u_int));
+void key_setsadbsens __P((void));
+void key_setsadbprop __P((void));
+void key_setsadbid __P((u_int, caddr_t));
+void key_setsadblft __P((u_int, u_int));
+void key_setspirange __P((void));
+void key_setsadbkey __P((u_int, caddr_t));
+void key_setsadbsa __P((void));
+void key_setsadbaddr __P((u_int, u_int, caddr_t));
+void key_setsadbextbuf __P((caddr_t, int, caddr_t, int, caddr_t, int));
+
+void
+Usage()
+{
+ printf("Usage:\t%s number\n", pname);
+ exit(0);
+}
+
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ pname = *av;
+
+ if (ac == 1) Usage();
+
+ key_setsadbmsg(atoi(*(av+1)));
+ sendkeymsg();
+
+ exit(0);
+}
+
+/* %%% */
+int
+sendkeymsg()
+{
+ u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+ int so, len;
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ perror("socket(PF_KEY)");
+ goto end;
+ }
+
+ pfkey_sadump((struct sadb_msg *)m_buf);
+
+ if ((len = send(so, m_buf, m_len, 0)) < 0) {
+ perror("send");
+ goto end;
+ }
+
+ if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+ perror("recv");
+ goto end;
+ }
+
+ pfkey_sadump((struct sadb_msg *)rbuf);
+
+end:
+ (void)close(so);
+ return(0);
+}
+
+void
+key_setsadbmsg(type)
+ u_int type;
+{
+ struct sadb_msg m_msg;
+
+ m_msg.sadb_msg_version = PF_KEY_V2;
+ m_msg.sadb_msg_type = type;
+ m_msg.sadb_msg_errno = 0;
+ m_msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ m_msg.sadb_msg_reserved = 0;
+ m_msg.sadb_msg_seq = 0;
+ m_msg.sadb_msg_pid = getpid();
+
+ m_len = sizeof(struct sadb_msg);
+ memcpy(m_buf, &m_msg, m_len);
+
+ switch (type) {
+ case SADB_GETSPI:
+ /*<base, address(SD), SPI range>*/
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "127.0.0.1");
+ key_setspirange();
+ /*<base, SA(*), address(SD)>*/
+ break;
+
+ case SADB_ADD:
+ /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ key(AE), (identity(SD),) (sensitivity)> */
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ case SADB_UPDATE:
+ key_setsadbsa();
+ key_setsadblft(SADB_EXT_LIFETIME_HARD, 10);
+ key_setsadblft(SADB_EXT_LIFETIME_SOFT, 5);
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ /* XXX key_setsadbkey(SADB_EXT_KEY_AUTH, "abcde"); */
+ key_setsadbkey(SADB_EXT_KEY_AUTH, "1234567812345678");
+ key_setsadbkey(SADB_EXT_KEY_ENCRYPT, "12345678");
+ key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com");
+ key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net");
+ key_setsadbsens();
+ /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ (identity(SD),) (sensitivity)> */
+ break;
+
+ case SADB_DELETE:
+ /* <base, SA(*), address(SDP)> */
+ key_setsadbsa();
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ /* <base, SA(*), address(SDP)> */
+ break;
+
+ case SADB_GET:
+ /* <base, SA(*), address(SDP)> */
+ key_setsadbsa();
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ key(AE), (identity(SD),) (sensitivity)> */
+ break;
+
+ case SADB_ACQUIRE:
+ /* <base, address(SD), (address(P),) (identity(SD),)
+ (sensitivity,) proposal> */
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com");
+ key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net");
+ key_setsadbsens();
+ key_setsadbprop();
+ /* <base, address(SD), (address(P),) (identity(SD),)
+ (sensitivity,) proposal> */
+ break;
+
+ case SADB_REGISTER:
+ /* <base> */
+ /* <base, supported> */
+ break;
+
+ case SADB_EXPIRE:
+ case SADB_FLUSH:
+ break;
+
+ case SADB_DUMP:
+ break;
+
+ case SADB_X_PROMISC:
+ /* <base> */
+ /* <base, base(, others)> */
+ break;
+
+ case SADB_X_PCHANGE:
+ break;
+
+ /* for SPD management */
+ case SADB_X_SPDFLUSH:
+ case SADB_X_SPDDUMP:
+ break;
+
+ case SADB_X_SPDADD:
+ case SADB_X_SPDDELETE:
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ break;
+ }
+
+ ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len);
+
+ return;
+}
+
+void
+key_setsadbsens()
+{
+ struct sadb_sens m_sens;
+ u_char buf[64];
+ u_int s, i, slen, ilen, len;
+
+ /* make sens & integ */
+ s = htonl(0x01234567);
+ i = htonl(0x89abcdef);
+ slen = sizeof(s);
+ ilen = sizeof(i);
+ memcpy(buf, &s, slen);
+ memcpy(buf + slen, &i, ilen);
+
+ len = sizeof(m_sens) + PFKEY_ALIGN8(slen) + PFKEY_ALIGN8(ilen);
+ m_sens.sadb_sens_len = PFKEY_UNIT64(len);
+ m_sens.sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+ m_sens.sadb_sens_dpd = 1;
+ m_sens.sadb_sens_sens_level = 2;
+ m_sens.sadb_sens_sens_len = PFKEY_ALIGN8(slen);
+ m_sens.sadb_sens_integ_level = 3;
+ m_sens.sadb_sens_integ_len = PFKEY_ALIGN8(ilen);
+ m_sens.sadb_sens_reserved = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_sens, sizeof(struct sadb_sens),
+ buf, slen + ilen);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbprop()
+{
+ struct sadb_prop m_prop;
+ struct sadb_comb *m_comb;
+ u_char buf[256];
+ u_int len = sizeof(m_prop) + sizeof(m_comb) * 2;
+
+ /* make prop & comb */
+ m_prop.sadb_prop_len = PFKEY_UNIT64(len);
+ m_prop.sadb_prop_exttype = SADB_EXT_PROPOSAL;
+ m_prop.sadb_prop_replay = 0;
+ m_prop.sadb_prop_reserved[0] = 0;
+ m_prop.sadb_prop_reserved[1] = 0;
+ m_prop.sadb_prop_reserved[2] = 0;
+
+ /* the 1st is ESP DES-CBC HMAC-MD5 */
+ m_comb = (struct sadb_comb *)buf;
+ m_comb->sadb_comb_auth = SADB_AALG_MD5HMAC;
+ m_comb->sadb_comb_encrypt = SADB_EALG_DESCBC;
+ m_comb->sadb_comb_flags = 0;
+ m_comb->sadb_comb_auth_minbits = 8;
+ m_comb->sadb_comb_auth_maxbits = 96;
+ m_comb->sadb_comb_encrypt_minbits = 64;
+ m_comb->sadb_comb_encrypt_maxbits = 64;
+ m_comb->sadb_comb_reserved = 0;
+ m_comb->sadb_comb_soft_allocations = 0;
+ m_comb->sadb_comb_hard_allocations = 0;
+ m_comb->sadb_comb_soft_bytes = 0;
+ m_comb->sadb_comb_hard_bytes = 0;
+ m_comb->sadb_comb_soft_addtime = 0;
+ m_comb->sadb_comb_hard_addtime = 0;
+ m_comb->sadb_comb_soft_usetime = 0;
+ m_comb->sadb_comb_hard_usetime = 0;
+
+ /* the 2st is ESP 3DES-CBC and AH HMAC-SHA1 */
+ m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb));
+ m_comb->sadb_comb_auth = SADB_AALG_SHA1HMAC;
+ m_comb->sadb_comb_encrypt = SADB_EALG_3DESCBC;
+ m_comb->sadb_comb_flags = 0;
+ m_comb->sadb_comb_auth_minbits = 8;
+ m_comb->sadb_comb_auth_maxbits = 96;
+ m_comb->sadb_comb_encrypt_minbits = 64;
+ m_comb->sadb_comb_encrypt_maxbits = 64;
+ m_comb->sadb_comb_reserved = 0;
+ m_comb->sadb_comb_soft_allocations = 0;
+ m_comb->sadb_comb_hard_allocations = 0;
+ m_comb->sadb_comb_soft_bytes = 0;
+ m_comb->sadb_comb_hard_bytes = 0;
+ m_comb->sadb_comb_soft_addtime = 0;
+ m_comb->sadb_comb_hard_addtime = 0;
+ m_comb->sadb_comb_soft_usetime = 0;
+ m_comb->sadb_comb_hard_usetime = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_prop, sizeof(struct sadb_prop),
+ buf, sizeof(*m_comb) * 2);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbid(ext, str)
+ u_int ext;
+ caddr_t str;
+{
+ struct sadb_ident m_id;
+ u_int idlen = strlen(str), len;
+
+ len = sizeof(m_id) + PFKEY_ALIGN8(idlen);
+ m_id.sadb_ident_len = PFKEY_UNIT64(len);
+ m_id.sadb_ident_exttype = ext;
+ m_id.sadb_ident_type = SADB_IDENTTYPE_USERFQDN;
+ m_id.sadb_ident_reserved = 0;
+ m_id.sadb_ident_id = getpid();
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_id, sizeof(struct sadb_ident),
+ str, idlen);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadblft(ext, time)
+ u_int ext, time;
+{
+ struct sadb_lifetime m_lft;
+
+ m_lft.sadb_lifetime_len = PFKEY_UNIT64(sizeof(m_lft));
+ m_lft.sadb_lifetime_exttype = ext;
+ m_lft.sadb_lifetime_allocations = 0x2;
+ m_lft.sadb_lifetime_bytes = 0x1000;
+ m_lft.sadb_lifetime_addtime = time;
+ m_lft.sadb_lifetime_usetime = 0x0020;
+
+ memcpy(m_buf + m_len, &m_lft, sizeof(struct sadb_lifetime));
+ m_len += sizeof(struct sadb_lifetime);
+
+ return;
+}
+
+void
+key_setspirange()
+{
+ struct sadb_spirange m_spi;
+
+ m_spi.sadb_spirange_len = PFKEY_UNIT64(sizeof(m_spi));
+ m_spi.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ m_spi.sadb_spirange_min = 0x00001000;
+ m_spi.sadb_spirange_max = 0x00002000;
+ m_spi.sadb_spirange_reserved = 0;
+
+ memcpy(m_buf + m_len, &m_spi, sizeof(struct sadb_spirange));
+ m_len += sizeof(struct sadb_spirange);
+
+ return;
+}
+
+void
+key_setsadbkey(ext, str)
+ u_int ext;
+ caddr_t str;
+{
+ struct sadb_key m_key;
+ u_int keylen = strlen(str);
+ u_int len;
+
+ len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+ m_key.sadb_key_len = PFKEY_UNIT64(len);
+ m_key.sadb_key_exttype = ext;
+ m_key.sadb_key_bits = keylen * 8;
+ m_key.sadb_key_reserved = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_key, sizeof(struct sadb_key),
+ str, keylen);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbsa()
+{
+ struct sadb_sa m_sa;
+
+ m_sa.sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa));
+ m_sa.sadb_sa_exttype = SADB_EXT_SA;
+ m_sa.sadb_sa_spi = htonl(0x12345678);
+ m_sa.sadb_sa_replay = 4;
+ m_sa.sadb_sa_state = 0;
+ m_sa.sadb_sa_auth = SADB_AALG_MD5HMAC;
+ m_sa.sadb_sa_encrypt = SADB_EALG_DESCBC;
+ m_sa.sadb_sa_flags = 0;
+
+ memcpy(m_buf + m_len, &m_sa, sizeof(struct sadb_sa));
+ m_len += sizeof(struct sadb_sa);
+
+ return;
+}
+
+void
+key_setsadbaddr(ext, af, str)
+ u_int ext, af;
+ caddr_t str;
+{
+ struct sadb_address m_addr;
+ u_char abuf[64];
+ struct sockaddr *a = (struct sockaddr *)abuf;
+ u_int len;
+
+ /* make sockaddr buffer */
+ memset(abuf, 0, sizeof(abuf));
+ a->sa_len = _SALENBYAF(af);
+ a->sa_family = af;
+ _INPORTBYSA(a) =
+ (ext == SADB_EXT_ADDRESS_PROXY ? 0 : htons(0x1234));
+ if (inet_pton(af, str, _INADDRBYSA(a)) != 1)
+ ; /* XXX do something */
+
+ len = sizeof(struct sadb_address) + PFKEY_ALIGN8(a->sa_len);
+ m_addr.sadb_address_len = PFKEY_UNIT64(len);
+ m_addr.sadb_address_exttype = ext;
+ m_addr.sadb_address_proto =
+ (ext == SADB_EXT_ADDRESS_PROXY ? 0 : IPPROTO_TCP);
+ m_addr.sadb_address_prefixlen = _INALENBYAF(af);
+ m_addr.sadb_address_reserved = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_addr, sizeof(struct sadb_address),
+ abuf, a->sa_len);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbextbuf(dst, off, ebuf, elen, vbuf, vlen)
+ caddr_t dst, ebuf, vbuf;
+ int off, elen, vlen;
+{
+ memset(dst + off, 0, elen + vlen);
+ memcpy(dst + off, (caddr_t)ebuf, elen);
+ memcpy(dst + off + elen, vbuf, vlen);
+
+ return;
+}
+
diff --git a/sbin/setkey/test-policy.c b/sbin/setkey/test-policy.c
new file mode 100644
index 0000000..27cd478
--- /dev/null
+++ b/sbin/setkey/test-policy.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet6/in6.h>
+#include <netkey/keyv2.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet6/ipsec.h>
+
+char *requests[] = {
+"must_error", /* must be error */
+"ipsec must_error", /* must be error */
+"ipsec esp/must_error", /* must be error */
+"discard",
+"none",
+"entrust",
+"bypass", /* may be error */
+"ipsec esp", /* must be error */
+"ipsec ah/require",
+"ipsec ah/use/",
+"ipsec esp/require ah/default/203.178.141.194",
+"ipsec ah/use/203.178.141.195 esp/use/203.178.141.194",
+"ipsec esp/elf.wide.ydc.co.jp esp/www.wide.ydc.co.jp"
+"
+ipsec esp/require ah/use esp/require/10.0.0.1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1ah/use/3ffe:501:481d::1
+",
+};
+
+u_char *p_secpolicy;
+
+int test(char *buf, int family);
+char *setpolicy(char *req);
+
+main()
+{
+ int i;
+ char *buf;
+
+ for (i = 0; i < sizeof(requests)/sizeof(requests[0]); i++) {
+ printf("* requests:[%s]\n", requests[i]);
+ if ((buf = setpolicy(requests[i])) == NULL)
+ continue;
+ printf("\tsetlen:%d\n", PFKEY_EXTLEN(buf));
+
+ printf("\tPF_INET:\n");
+ test(buf, PF_INET);
+
+ printf("\tPF_INET6:\n");
+ test(buf, PF_INET6);
+ free(buf);
+ }
+}
+
+int test(char *policy, int family)
+{
+ int so, proto, optname;
+ int len;
+ char getbuf[1024];
+
+ switch (family) {
+ case PF_INET:
+ proto = IPPROTO_IP;
+ optname = IP_IPSEC_POLICY;
+ break;
+ case PF_INET6:
+ proto = IPPROTO_IPV6;
+ optname = IPV6_IPSEC_POLICY;
+ break;
+ }
+
+ if ((so = socket(family, SOCK_DGRAM, 0)) < 0)
+ perror("socket");
+
+ if (setsockopt(so, proto, optname, policy, PFKEY_EXTLEN(policy)) < 0)
+ perror("setsockopt");
+
+ len = sizeof(getbuf);
+ memset(getbuf, 0, sizeof(getbuf));
+ if (getsockopt(so, proto, optname, getbuf, &len) < 0)
+ perror("getsockopt");
+
+ {
+ char *buf = NULL;
+
+ printf("\tgetlen:%d\n", len);
+
+ if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL)
+ ipsec_strerror();
+ else
+ printf("\t[%s]\n", buf);
+
+ free(buf);
+ }
+
+ close (so);
+}
+
+char *setpolicy(char *req)
+{
+ int len;
+ char *buf;
+
+ if ((len = ipsec_get_policylen(req)) < 0) {
+ printf("ipsec_get_policylen: %s\n", ipsec_strerror());
+ return NULL;
+ }
+
+ if ((buf = malloc(len)) == NULL) {
+ perror("malloc");
+ return NULL;
+ }
+
+ if ((len = ipsec_set_policy(buf, len, req)) < 0) {
+ printf("ipsec_set_policy: %s\n", ipsec_strerror());
+ free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/sbin/setkey/token.l b/sbin/setkey/token.l
new file mode 100644
index 0000000..b75fd45
--- /dev/null
+++ b/sbin/setkey/token.l
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netkey/key_debug.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "vchar.h"
+#include "y.tab.h"
+
+#define DECHO \
+ if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); }
+
+#define CMDARG \
+{ \
+ char *__buf__ = strdup(yytext), *__p__; \
+ for (__p__ = __buf__; *__p__ != NULL; __p__++) \
+ if (*__p__ == '\n' || *__p__ == '\t') \
+ *__p__ = ' '; \
+ strcat(cmdarg, __buf__); \
+ free(__buf__); \
+}
+
+#define PREPROC DECHO CMDARG
+
+int lineno = 1;
+char cmdarg[8192]; /* XXX: BUFSIZ is the better ? */
+
+extern u_char m_buf[BUFSIZ];
+extern u_int m_len;
+extern int f_debug;
+
+int yylex __P((void));
+void yyerror __P((char *s));
+extern void parse_init __P((void));
+int parse __P((FILE **));
+int yyparse __P((void));
+
+%}
+
+/* common section */
+nl \n
+ws [ \t]+
+digit [0-9]
+letter [0-9A-Za-z]
+hexdigit [0-9A-Fa-f]
+/*octet (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5])))*/
+special [()+\|\?\*,]
+dot \.
+comma \,
+hyphen \-
+colon \:
+slash \/
+bcl \{
+ecl \}
+blcl \[
+elcl \]
+percent \%
+semi \;
+usec {dot}{digit}{1,6}
+comment \#.*
+ccomment "/*"
+bracketstring \<[^>]*\>
+quotedstring \"[^"]*\"
+decstring {digit}+
+hexpair {hexdigit}{hexdigit}
+hexstring 0[xX]{hexdigit}+
+octetstring {octet}({dot}{octet})+
+ipaddress {ipv4addr}|{ipv6addr}
+ipv4addr {digit}{1,3}({dot}{digit}{1,3}){0,3}
+ipv6addr {hexdigit}{0,4}({colon}{hexdigit}{0,4}){2,7}(@{letter}{letter}+)?
+ipaddrmask {slash}{digit}{1,3}
+ipaddrport {blcl}{decstring}{elcl}
+keyword {letter}{letter}+
+name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))*
+hostname {name}(({dot}{name})+{dot}?)?
+
+%s S_PL
+
+%%
+
+add { PREPROC; return(ADD); }
+delete { PREPROC; return(DELETE); }
+get { PREPROC; return(GET); }
+flush { PREPROC; return(FLUSH); }
+dump { PREPROC; return(DUMP); }
+
+ /* for management SPD */
+spdadd { PREPROC; return(SPDADD); }
+spddelete { PREPROC; return(SPDDELETE); }
+spddump { PREPROC; return(SPDDUMP); }
+spdflush { PREPROC; return(SPDFLUSH); }
+{hyphen}P { BEGIN S_PL; PREPROC; return(F_POLICY); }
+<S_PL>[a-zA-Z0-9:\.\-_/ \n\t][a-zA-Z0-9:\.\-_/ \n\t]* {
+ yymore();
+
+ /* count up for nl */
+ {
+ char *p;
+ for (p = yytext; *p != NULL; p++)
+ if (*p == '\n')
+ lineno++;
+ }
+
+ yylval.val.len = strlen(yytext);
+ yylval.val.buf = strdup(yytext);
+
+ return(PL_REQUESTS);
+}
+<S_PL>{semi} { PREPROC; BEGIN INITIAL; return(EOT); }
+
+ /* security protocols */
+ah { PREPROC; yylval.num = 0; return(PR_AH); }
+esp { PREPROC; yylval.num = 0; return(PR_ESP); }
+ah-old { PREPROC; yylval.num = 1; return(PR_AH); }
+esp-old { PREPROC; yylval.num = 1; return(PR_ESP); }
+ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); }
+
+ /* authentication alogorithm */
+{hyphen}A { PREPROC; return(F_AUTH); }
+hmac-md5 { PREPROC; yylval.num = SADB_AALG_MD5HMAC; return(ALG_AUTH); }
+hmac-sha1 { PREPROC; yylval.num = SADB_AALG_SHA1HMAC; return(ALG_AUTH); }
+keyed-md5 { PREPROC; yylval.num = SADB_AALG_MD5; return(ALG_AUTH); }
+keyed-sha1 { PREPROC; yylval.num = SADB_AALG_SHA; return(ALG_AUTH); }
+null { PREPROC; yylval.num = SADB_AALG_NULL; return(ALG_AUTH); }
+
+ /* encryption alogorithm */
+{hyphen}E { PREPROC; return(F_ENC); }
+des-cbc { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC); }
+3des-cbc { PREPROC; yylval.num = SADB_EALG_3DESCBC; return(ALG_ENC); }
+simple { PREPROC; yylval.num = SADB_EALG_NULL; return(ALG_ENC); }
+blowfish-cbc { PREPROC; yylval.num = SADB_EALG_BLOWFISHCBC; return(ALG_ENC); }
+cast128-cbc { PREPROC; yylval.num = SADB_EALG_CAST128CBC; return(ALG_ENC); }
+rc5-cbc { PREPROC; yylval.num = SADB_EALG_RC5CBC; return(ALG_ENC); }
+des-deriv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DESDERIV); }
+des-32iv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DES32IV); }
+
+ /* compression algorithms */
+{hyphen}C { PREPROC; return(F_COMP); }
+oui { PREPROC; yylval.num = SADB_X_CALG_OUI; return(ALG_COMP); }
+deflate { PREPROC; yylval.num = SADB_X_CALG_DEFLATE; return(ALG_COMP); }
+lzs { PREPROC; yylval.num = SADB_X_CALG_LZS; return(ALG_COMP); }
+{hyphen}R { PREPROC; return(F_RAWCPI); }
+
+ /* extension */
+{hyphen}m { PREPROC; return(F_MODE); }
+transport { PREPROC; yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
+tunnel { PREPROC; yylval.num = IPSEC_MODE_TUNNEL; return(MODE); }
+{hyphen}f { PREPROC; return(F_EXT); }
+random-pad { PREPROC; yylval.num = SADB_X_EXT_PRAND; return(EXTENSION); }
+seq-pad { PREPROC; yylval.num = SADB_X_EXT_PSEQ; return(EXTENSION); }
+zero-pad { PREPROC; yylval.num = SADB_X_EXT_PZERO; return(EXTENSION); }
+cyclic-seq { PREPROC; yylval.num = SADB_X_EXT_CYCSEQ; return(EXTENSION); }
+{hyphen}r { PREPROC; return(F_REPLAY); }
+{hyphen}lh { PREPROC; return(F_LIFETIME_HARD); }
+{hyphen}ls { PREPROC; return(F_LIFETIME_SOFT); }
+
+
+ /* upper layer protocols */
+icmp { PREPROC; yylval.num = IPPROTO_ICMP; return(UP_PROTO); }
+icmp6 { PREPROC; yylval.num = IPPROTO_ICMPV6; return(UP_PROTO); }
+tcp { PREPROC; yylval.num = IPPROTO_TCP; return(UP_PROTO); }
+udp { PREPROC; yylval.num = IPPROTO_UDP; return(UP_PROTO); }
+
+ /* ... */
+any { PREPROC; return(ANY); }
+{ws} { PREPROC; }
+{nl} { lineno++; }
+{comment}
+{semi} { PREPROC; return(EOT); }
+
+ /* parameter */
+{decstring} {
+ char *bp;
+
+ PREPROC;
+ yylval.num = strtol(yytext, &bp, 10);
+ return(DECSTRING);
+ }
+
+{ipv4addr} {
+ /*
+ * I can't supprt the type without dot,
+ * because it's umbiguous against {decstring}.
+ * e.g. 127
+ */
+ PREPROC;
+
+ yylval.val.len = sizeof(struct sockaddr_in);
+ yylval.val.buf = strdup(yytext);
+
+ return(IP4_ADDRESS);
+ }
+
+{ipv6addr} {
+#ifdef INET6
+ PREPROC;
+
+ yylval.val.len = sizeof(struct sockaddr_in6);
+ yylval.val.buf = strdup(yytext);
+
+ return(IP6_ADDRESS);
+#else
+ yyerror("IPv6 address not supported");
+#endif
+ }
+
+{ipaddrmask} {
+ PREPROC;
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(PREFIX);
+ }
+
+{ipaddrport} {
+ char *p = yytext;
+ PREPROC;
+ while (*++p != ']') ;
+ *p = NULL;
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(PORT);
+ }
+
+{blcl}any{elcl} {
+ char *p = yytext;
+ PREPROC;
+ return(PORTANY);
+ }
+
+{hexstring} {
+ int len = yyleng - 2; /* (str - "0x") */
+ PREPROC;
+ yylval.val.len = (len & 1) + (len / 2);
+ /* fixed string if length is odd. */
+ if (len & 1) {
+ yytext[1] = '0';
+ yylval.val.buf = strdup(yytext + 1);
+ } else
+ yylval.val.buf = strdup(yytext + 2);
+
+ return(HEXSTRING);
+ }
+
+{quotedstring} {
+ char *p = yytext;
+ PREPROC;
+ while (*++p != '"') ;
+ *p = NULL;
+ yytext++;
+ yylval.val.len = yyleng - 2;
+ yylval.val.buf = strdup(yytext);
+
+ return(QUOTEDSTRING);
+ }
+
+. { yyerror("Syntax error"); }
+
+%%
+
+void
+yyerror(char *s)
+{
+ printf("line %d: %s at [%s]\n", lineno, s, yytext);
+}
+
+int
+parse(fp)
+ FILE **fp;
+{
+ yyin = *fp;
+
+ parse_init();
+
+ if (yyparse()) {
+ printf("parse failed, line %d.\n", lineno);
+ return(-1);
+ }
+
+ return(0);
+}
+
diff --git a/sbin/setkey/vchar.h b/sbin/setkey/vchar.h
new file mode 100644
index 0000000..977f5f0
--- /dev/null
+++ b/sbin/setkey/vchar.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+typedef struct {
+ u_int len;
+ caddr_t buf;
+} vchar_t;
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 6fb71be..b1eb513 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -3,9 +3,11 @@
MAN4= ahc.4 alpm.4 amd.4 atkbd.4 atkbdc.4 aue.4 blackhole.4 bpf.4 \
bridge.4 ccd.4 cd.4 ch.4 da.4 dc.4 ddb.4 de.4 \
- divert.4 drum.4 dummynet.4 fd.4 fdc.4 fpa.4 fxp.4 \
+ divert.4 drum.4 dummynet.4 faith.4 fd.4 fdc.4 fpa.4 fxp.4 \
+ gif.4 \
icmp.4 ifmib.4 iic.4 iicbb.4 iicbus.4 iicsmb.4 \
- inet.4 intpm.4 intro.4 ip.4 ipfirewall.4 keyboard.4 kld.4 \
+ inet.4 inet6.4 intpm.4 intro.4 ip.4 ipfirewall.4 ipsec.4 \
+ kame.4 keyboard.4 kld.4 \
kue.4 lo.4 lp.4 lpbb.4 lpt.4 mem.4 mouse.4 mtio.4 natm.4 ncr.4 \
netintro.4 null.4 ohci.4 pass.4 pci.4 pcm.4 pcvt.4 \
ppbus.4 ppi.4 ppp.4 psm.4 pt.4 pty.4 rl.4 \
diff --git a/share/man/man4/faith.4 b/share/man/man4/faith.4
new file mode 100644
index 0000000..2b93993
--- /dev/null
+++ b/share/man/man4/faith.4
@@ -0,0 +1,122 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: faith.4,v 1.1.1.1 1999/08/08 23:30:37 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 10, 1999
+.Dt FAITH 4
+.Os KAME
+.Sh NAME
+.Nm faith
+.Nd
+.Tn IPv6-to-IPv4 TCP relay capturing interface
+.Sh SYNOPSIS
+.Cd "pseudo-device faith 1"
+.Sh DESCRIPTION
+The
+.Nm
+interface captures IPv6 TCP traffic,
+for implementing userland IPv6-to-IPv4 TCP relay
+like
+.Xr faithd 8 .
+.Pp
+Special action will be taken when IPv6 TCP traffic is seen on a router,
+and routing table suggests to route it to
+.Nm
+interface.
+In this case, the packet will be accepted by the router,
+regardless of list of IPv6 interface addresses assigned to the router.
+The packet will be captured by an IPv6 TCP socket, if it has
+.Dv IN6P_FAITH
+flag turned on and it has matching address/port pairs.
+In result,
+.Nm
+will let you capture IPv6 TCP traffic to some specific destination addresses.
+Userland programs, such as
+.Xr faithd 8
+can use this behavior to relay IPv6 TCP traffic to IPv4 TCP traffic.
+The program can accept some specific IPv6 TCP traffic, perform
+.Xr getsockname 3
+to get the IPv6 destination address specified by the client,
+and perform application-specific address mapping to relay IPv6 TCP to IPv4 TCP.
+.Pp
+.Dv IN6P_FAITH
+flag on IPv6 TCP socket can be set by using
+.Xr setsockopt 2 ,
+with level equals to
+.Dv IPPROTO_IPV6
+and optname equals to
+.Dv IPv6_FAITH .
+.Pp
+To handle error reports by ICMPv6, some of ICMPv6 packets routed to
+.Nm
+interface will be delivered to IPv6 TCP, as well.
+.Pp
+To understand how
+.Nm
+can be used, take a look at source code of
+.Xr faithd 8 .
+.Pp
+As
+.Nm
+interface implements potentially dangerous operation,
+great care must be taken when configuring
+.Nm
+interface.
+To avoid possible misuse,
+.Xr sysctl 8
+variable
+.Li net.inet6.ip6.keepfaith
+must be set to
+.Li 1
+prior to the use of the interface.
+When
+.Li net.inet6.ip6.keepfaith
+is
+.Li 0 ,
+no packet will be captured by
+.Nm
+interface.
+.Pp
+.Nm
+interface is intended to be used on routers, not on hosts.
+.\"
+.Sh SEE ALSO
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr faithd 8 .
+.\" .Rs
+.\" .%A Jun-ichiro itojun Hagino
+.\" .%A Kazu Yamamoto
+.\" .%T ``FAITH'' IPv6-to-IPv4 TCP relay translator
+.\" .%D July 1999
+.\" .Re
+.\"
+.Sh HISTORY
+The FAITH IPv6-to-IPv4 TCP relay translator was first appeared in
+WIDE hydrangea IPv6 stack.
diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4
new file mode 100644
index 0000000..1d11440
--- /dev/null
+++ b/share/man/man4/gif.4
@@ -0,0 +1,232 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: gif.4,v 1.2 1999/09/29 15:36:17 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 10, 1999
+.Dt GIF 4
+.Os KAME
+.Sh NAME
+.Nm gif
+.Nd
+.Tn Generic tunnel interface
+.Sh SYNOPSIS
+.Cd "pseudo-device gif 4"
+.Sh DESCRIPTION
+The
+.Nm
+interface is a generic tunnelling pseudo device for IPv4 and IPv6.
+It can tunnel IPv[46] traffic over IPv[46].
+Therefore, there can be four possible configurations.
+The behavior of
+.Nm
+is mainly based on RFC1933 IPv6-over-IPv4 configured tunnel.
+.Pp
+To use
+.Nm gif ,
+administrator needs to configure protocol and addresses used for the outer
+header.
+This can be done by using
+.Xr gifconfig 8 ,
+or
+.Dv SIOCSIFPHYADDR
+ioctl.
+Also, administrator needs to configure protocol and addresses used for the
+inner header, by using
+.Xr ifconfig 8 .
+Note that IPv6 link-local address
+.Pq those start with Li fe80::
+will be automatically configured whenever possible.
+You may need to remove IPv6 link-local address manually using
+.Xr ifconfig 8 ,
+when you would like to disable the use of IPv6 as inner header
+.Pq like when you need pure IPv4-over-IPv6 tunnel .
+Finally, use routing table to route the packets toward
+.Nm
+interface.
+.Pp
+.Nm
+interface can be configued to perform bidirectional tunnel, or
+multi-destination tunnel.
+This is controlled by
+.Dv IFF_LINK0
+interface flag.
+Also,
+.Nm
+can be configured to be ECN friendly.
+This can be configured by
+.Dv IFF_LINK1 .
+.\"
+.Ss Bidirectional and multi-destination mode
+Usually,
+.Nm
+implements bidirectional tunnel.
+.Xr gifconfig 8
+should configure a tunnel ingress point
+.Pq this node
+and an egress point
+.Pq tunnel endpoint ,
+and
+one
+.Nm
+interface will tunnel to only a single tunnel endpoint,
+and accept from only a single tunnel endpoint.
+Source and destination address for outer IP header is always the
+ingress and the egress point configued by
+.Xr gifconfig 8 .
+.Pp
+With
+.Dv IFF_LINK0
+interface flag,
+.Nm
+can be configured to implement multi-destination tunnel.
+With
+.Dv IFF_LINK0 ,
+it is able to configure egress point to IPv4 wildcard address
+.Pq Nm 0.0.0.0
+or IPv6 unspecified address
+.Pq Nm 0::0 .
+In this case, destination address for the outer IP header is
+determined based on the routing table setup.
+Therefore, one
+.Nm
+interface can tunnel to multiple destinations.
+Also,
+.Nm
+will accept tunneled traffic from any outer source address.
+.Pp
+When finding a
+.Nm gif
+interface from the inbound tunneled traffic,
+bidirectional mode interface is preferred than multi-destination mode interface.
+For example, if you have the following three
+.Nm
+interfaces on node A, tunneled traffic from C to A will match the second
+.Nm
+interface, not the third one.
+.Bl -bullet -compact -offset indent
+.It
+bidirectional, A to B
+.It
+bidirectional, A to C
+.It
+multi-destination, A to any
+.El
+.Pp
+Please note that multi-destination mode is far less secure
+than bidirectional mode.
+Multi-destination mode
+.Nm
+can accept tunneled packet from anybody,
+and can be attacked from a malicious node.
+.Pp
+.Ss ECN friendly behavior
+.Nm
+can be configured to be ECN friendly, as described in
+.Dv draft-ipsec-ecn-00.txt .
+This is turned off by default, and can be turned on by
+.Dv IFF_LINK1
+interface flag.
+.Pp
+Without
+.Dv IFF_LINK1 ,
+.Nm
+will show a normal behavior, like described in RFC1933.
+This can be summarized as follows:
+.Bl -tag -width "Ingress" -offset indent
+.It Ingress
+Set outer TOS bit to
+.Dv 0 .
+.It Egress
+Drop outer TOS bit.
+.El
+.Pp
+With
+.Dv IFF_LINK1 ,
+.Nm
+will copy ECN bits
+.Po
+.Dv 0x02
+and
+.Dv 0x01
+on IPv4 TOS byte or IPv6 traffic class byte
+.Pc
+on egress and ingress, as follows:
+.Bl -tag -width "Ingress" -offset indent
+.It Ingress
+Copy TOS bits except for ECN CE
+.Po
+masked with
+.Dv 0xfe
+.Pc
+from
+inner to outer.
+set ECN CE bit to
+.Dv 0 .
+.It Egress
+Use inner TOS bits with some change.
+If outer ECN CE bit is
+.Dv 1 ,
+enable ECN CE bit on the inner.
+.El
+.Pp
+Note that the ECN friendly behavior violates RFC1933.
+This should be used in mutual agreement with the tunnel endpoint.
+.Pp
+.Ss Backward compatibility
+.Nm
+interface will capture packets toward IPv4-in-IPv4 tunnel,
+which has been used by
+.Xr vif 4
+multicast tunnel device
+.Pq used in MBone community .
+For compatibility, IPv4-in-IPv4 traffic will be matched to
+.Nm
+interfaces first, and then sent to
+.Xr vif 4
+if no match is found.
+.\"
+.Sh SEE ALSO
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr vif 4 ,
+.Xr gifconfig 8 ,
+RFC1933
+.Rs
+.%A Sally Floyd
+.%A David L. Black
+.%A K. K. Ramakrishnan
+.%T "IPsec Interactions with ECN"
+.%D February 1999
+.%O http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
+.Re
+.\"
+.Sh HISTORY
+The
+.Nm
+device first appeared in WIDE hydrangea IPv6 kit.
diff --git a/share/man/man4/inet6.4 b/share/man/man4/inet6.4
new file mode 100644
index 0000000..0d2b690
--- /dev/null
+++ b/share/man/man4/inet6.4
@@ -0,0 +1,287 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: inet6.4,v 1.1.1.1 1999/08/08 23:30:37 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd January 29, 1999
+.Dt INET6 4
+.Os KAME
+.Sh NAME
+.Nm inet6
+.Nd Internet protocol version 6 family
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netinet/in.h>
+.Sh DESCRIPTION
+The
+.Nm
+family is an updated version of
+.Xr inet 4
+family.
+While
+.Xr inet 4
+implements Internet Protocol version 4,
+.Nm
+implements Internet Protocol version 6.
+.Pp
+.Nm
+is a collection of protocols layered atop the
+.Em Internet Protocol version 6
+.Pq Tn IPv6
+transport layer, and utilizing the IPv6 address format.
+The
+.Nm
+family provides protocol support for the
+.Dv SOCK_STREAM , SOCK_DGRAM ,
+and
+.Dv SOCK_RAW
+socket types; the
+.Dv SOCK_RAW
+interface provides access to the
+.Tn IPv6
+protocol.
+.Sh ADDRESSING
+IPv6 addresses are 16 byte quantities, stored in network standard format
+The include file
+.Aq Pa netinet/in.h
+defines this address
+as a discriminated union.
+.Pp
+Sockets bound to the
+.Nm
+family utilize the following addressing structure,
+.Bd -literal -offset indent
+struct sockaddr_in6 {
+ u_char sin6_len;
+ u_char sin6_family;
+ u_int16_t sin6_port;
+ u_int32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ u_int32_t sin6_scope_id;
+};
+.Ed
+.Pp
+Sockets may be created with the local address
+.Dq Dv ::
+.Po
+which is equal to IPv6 address
+.Dv 0:0:0:0:0:0:0:0
+.Pc
+to effect
+.Dq wildcard
+matching on incoming messages.
+The address in a
+.Xr connect 2
+or
+.Xr sendto 2
+call may be given as
+.Dq Dv ::
+to mean
+.Dq this host .
+.Dq Dv ::
+can be obtained by setting
+.Dv sin6_addr
+field into 0, or by using the address contained in variable
+.Dv in6addr_any .
+.Pp
+IPv6 defines scoped address such as link-local or site-local address.
+To manipulate link-local addresses properly from the userland,
+programs must use advanced API defined in RFC2292.
+Otherwise, the address is ambiguous to the kernel and error will be generated.
+Scoped address is not for daily use at this moment both from specification
+and implementation point of view.
+Most of normal userland program
+like
+.Xr telnet 1
+or
+.Xr telnetd 8
+cannot handle scoped address properly.
+Only special programs,
+like
+.Xr ping6 8 ,
+supports scoped address.
+For example,
+.Xr ping6 8
+has special option for specifying outgoing interface
+to disambiguate scoped addresses.
+.Pp
+Scoped addresses are handled specially in the kernel.
+Scoped addresses will have its interface index embedded into the address,
+in routing table or interface structure.
+Therefore,
+the address on some of the kernel structure is not the same as that on the wire.
+The embedded index will be visible on
+.Dv PF_ROUTE
+socket and results from
+.Xr ifconfig 8 ,
+HOWEVER, users should never use the embedded form.
+For details please consult
+.Pa IMPLEMENTATION
+supplied with KAME kit.
+.Sh PROTOCOLS
+The
+.Nm
+family is comprised of the
+.Tn IPv6
+network protocol, Internet Control
+Message Protocol version 6
+.Pq Tn ICMPv6 ,
+Transmission Control Protocol
+.Pq Tn TCP ,
+and User Datagram Protocol
+.Pq Tn UDP .
+.Tn TCP
+is used to support the
+.Dv SOCK_STREAM
+abstraction while
+.Tn UDP
+is used to support the
+.Dv SOCK_DGRAM
+abstraction.
+Note that
+.Tn TCP
+and
+.Tn UDP
+are common to
+.Xr inet 4
+and
+.Nm inet6 .
+A raw interface to
+.Tn IPv6
+is available
+by creating an Internet socket of type
+.Dv SOCK_RAW .
+The
+.Tn ICMPv6
+message protocol is accessible from a raw socket.
+.\" .Pp
+.\" The 128-bit IPv6 address contains both network and host parts.
+.\" However, direct examination of addresses is discouraged.
+.\" For those programs which absolutely need to break addresses
+.\" into their component parts, the following
+.\" .Xr ioctl 2
+.\" commands are provided for a datagram socket in the
+.\" .Nm
+.\" domain; they have the same form as the
+.\" .Dv SIOCIFADDR
+.\" command (see
+.\" .Xr intro 4 ) .
+.\" .Pp
+.\" .Bl -tag -width SIOCSIFNETMASK
+.\" .It Dv SIOCSIFNETMASK
+.\" Set interface network mask.
+.\" The network mask defines the network part of the address;
+.\" if it contains more of the address than the address type would indicate,
+.\" then subnets are in use.
+.\" .It Dv SIOCGIFNETMASK
+.\" Get interface network mask.
+.\" .El
+.\" .Sh ROUTING
+.\" The current implementation of Internet protocols includes some routing-table
+.\" adaptations to provide enhanced caching of certain end-to-end
+.\" information necessary for Transaction TCP and Path MTU Discovery. The
+.\" following changes are the most significant:
+.\" .Bl -enum
+.\" .It
+.\" All IP routes, except those with the
+.\" .Dv RTF_CLONING
+.\" flag and those to multicast destinations, have the
+.\" .Dv RTF_PRCLONING
+.\" flag forcibly enabled (they are thus said to be
+.\" .Dq "protocol cloning" ).
+.\" .It
+.\" When the last reference to an IP route is dropped, the route is
+.\" examined to determine if it was created by cloning such a route. If
+.\" this is the case, the
+.\" .Dv RTF_PROTO3
+.\" flag is turned on, and the expiration timer is initialized to go off
+.\" in net.inet.ip.rtexpire seconds. If such a route is re-referenced,
+.\" the flag and expiration timer are reset.
+.\" .It
+.\" A kernel timeout runs once every ten minutes, or sooner if there are
+.\" soon-to-expire routes in the kernel routing table, and deletes the
+.\" expired routes.
+.\" .El
+.\" .Pp
+.\" A dynamic process is in place to modify the value of
+.\" net.inet.ip.rtexpire if the number of cached routes grows too large.
+.\" If after an expiration run there are still more than
+.\" net.inet.ip.rtmaxcache unreferenced routes remaining, the rtexpire
+.\" value is multiplied by 3/4, and any routes which have longer
+.\" expiration times have those times adjusted. This process is damped
+.\" somewhat by specification of a minimum rtexpire value
+.\" (net.inet.ip.rtminexpire), and by restricting the reduction to once in
+.\" a ten-minute period.
+.\" .Pp
+.\" If some external process deletes the original route from which a
+.\" protocol-cloned route was generated, the ``child route'' is deleted.
+.\" (This is actually a generic mechanism in the routing code support for
+.\" protocol-requested cloning.)
+.\" .Pp
+.\" No attempt is made to manage routes which were not created by protocol
+.\" cloning; these are assumed to be static, under the management of an
+.\" external routing process, or under the management of a link layer
+.\" (e.g.,
+.\" .Tn ARP
+.\" for Ethernets).
+.\" .Pp
+.\" Only certain types of network activity will result in the cloning of a
+.\" route using this mechanism. Specifically, those protocols (such as
+.\" .Tn TCP
+.\" and
+.\" .Tn UDP )
+.\" which themselves cache a long-lasting reference to route for a destination
+.\" will trigger the mechanism; whereas raw
+.\" .Tn IP
+.\" packets, whether locally-generated or forwarded, will not.
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr icmp6 4 ,
+.Xr intro 4 ,
+.\" .Xr ip6 4 ,
+.Xr tcp 4 ,
+.Xr ttcp 4 ,
+.Xr udp 4
+.Sh CAVEAT
+The IPv6 support is subject to change as the Internet protocols develop.
+Users should not depend on details of the current implementation,
+but rather the services exported.
+.Pp
+Users are suggested to implement
+.Dq version independent
+code as much as possible, as you will need to support both
+.Xr inet 4
+and
+.Nm inet6 .
+.Sh HISTORY
+The
+.Nm
+protocol interface are defined in RFC2553 and RFC2292.
+The implementation described herein appeared in WIDE/KAME project.
diff --git a/share/man/man4/ipsec.4 b/share/man/man4/ipsec.4
new file mode 100644
index 0000000..6e074fe
--- /dev/null
+++ b/share/man/man4/ipsec.4
@@ -0,0 +1,228 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ipsec.4,v 1.2 1999/10/07 03:55:08 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd January 29, 1999
+.Dt IPSEC 4
+.Os KAME
+.Sh NAME
+.Nm ipsec
+.Nd IP security protocol
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netinet/in.h>
+.Fd #include <netinet6/ipsec.h>
+.Sh DESCRIPTION
+.Nm
+is a security protocol in Internet Protocol layer.
+.Nm
+is defined for both IPv4 and IPv6
+.Po
+.Xr inet 4
+and
+.Xr inet6 4
+.Pc .
+.Nm
+consists of two sub-protocols, namely
+ESP
+.Pq encapsulated security payload
+and AH
+.Pq authentication header .
+ESP protects IP payload from wire-tapping by encrypting it by
+secret key cryptography algorithms.
+AH guarantees integrity of IP packet
+and protects it from intermediate alteration or impersonation,
+by attaching cryptographic checksum computed by one-way hash functions.
+.Nm
+has two operation modes: transport mode and tunnel mode.
+Transport mode is for protecting peer-to-peer commuication between end nodes.
+Tunnel mode includes IP-in-IP encapsulation operation
+and is designed for security gateways, like VPN configurations.
+.\"
+.Sh KERNEL INTERFACE
+.Nm
+is controlled by key management engine, and policy engine in the
+operating system kernel.
+.Pp
+Key management engine can be accessed from the userland by using
+.Dv PF_KEY
+sockets.
+The
+.Dv PF_KEY
+socket API is defined in RFC2367.
+.Pp
+Policy engine can be controlled by extended part of
+.Dv PF_KEY
+API,
+.Xr setsockopt 2
+operations, and
+.Xr sysctl 3
+interface.
+The kernel implements
+extended version of
+.Dv PF_KEY
+interface, and allows you to define IPsec policy like per-packet filters.
+.Xr setsockopt 2
+interface is used to define per-socket behavior, and
+.Xr sysctl 3
+interface is used to define host-wide default behavior.
+.Pp
+The kernel code does not implement dynamic encryption key exchange protocol
+like IKE
+.Pq Internet Key Exchange .
+That should be implemented as userland programs
+.Pq usually as daemons ,
+by using the above described APIs.
+.\"
+.Sh POLICY MANAGEMENT
+The kernel implements experimental policy management code.
+You can manage the IPsec policy in two ways.
+One is to configure per-socket policy using
+.Xr setsockopt 3 .
+The other is to configure kernel packet filter-based policy using
+.Dv PF_KEY
+interface, via
+.Xr setkey 8 .
+In both cases, IPsec policy must be specified with syntax described in
+.Xr ipsec_set_policy 3 .
+.Pp
+With
+.Xr setsockopt 3 ,
+you can define IPsec policy in per-socket basis.
+You can enforce particular IPsec policy onto packets that go through
+particular socket.
+.Pp
+With
+.Xr setkey 8
+you can define IPsec policy against packets,
+using sort of packet filtering rule.
+Refer to
+.Xr setkey 8
+on how to use it.
+.Pp
+In the latter case,
+.Dq Li default
+policy is allowed for use with
+.Xr setkey 8 .
+By configuring policy to
+.Li default ,
+you can refer system-wide
+.Xr sysctl 8
+variable for default settings.
+The following variables are available.
+.Li 1
+means
+.Dq Li use ,
+and
+.Li 2
+means
+.Dq Li require
+in the syntax.
+.Bl -column net.inet6.ipsec6.esp_trans_deflev integerxxx
+.It Sy Name Type Changeable
+.It net.inet.ipsec.esp_trans_deflev integer yes
+.It net.inet.ipsec.esp_net_deflev integer yes
+.It net.inet.ipsec.ah_trans_deflev integer yes
+.It net.inet.ipsec.ah_net_deflev integer yes
+.It net.inet6.ipsec6.esp_trans_deflev integer yes
+.It net.inet6.ipsec6.esp_net_deflev integer yes
+.It net.inet6.ipsec6.ah_trans_deflev integer yes
+.It net.inet6.ipsec6.ah_net_deflev integer yes
+.El
+.Pp
+If kernel finds no matching policy system wide default value is applied.
+System wide default is specified by the following
+.Xr sysctl 8
+variables.
+.Li 0
+means
+.Dq Li discard
+which asks the kernel to drop the packet.
+.Li 1
+means
+.Dq Li none .
+.Bl -column net.inet6.ipsec6.def_policy integerxxx
+.It Sy Name Type Changeable
+.It net.inet.ipsec.def_policy integer yes
+.It net.inet6.ipsec6.def_policy integer yes
+.El
+.\"
+.Sh PROTOCOLS
+The
+.Nm
+protocol works like plug-in to
+.Xr inet 4
+and
+.Xr inet6 4
+protocols.
+Therefore,
+.Nm
+supports most of the protocols defined upon those IP-layer protocols.
+Some of the protocols, like
+.Xr icmp 4
+or
+.Xr icmp6 4 ,
+may behave differently with
+.Nm ipsec .
+This is because
+.Nm
+can prevent
+.Xr icmp 4
+or
+.Xr icmp6 4
+routines from looking into IP payload.
+.\"
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr ipsec_set_policy 3 ,
+.Xr icmp6 4 ,
+.Xr intro 4 ,
+.Xr ip6 4 ,
+.Xr setkey 8 ,
+.Xr sysctl 8 ,
+.Xr racoon 8 .
+.Pp
+.Rs
+.%T RFC2367
+.Re
+.Rs
+.%A "D. L. McDonald"
+.%T "A Simple IP Security API Extension to BSD Sockets"
+.%N "draft-mcdonald-simple-ipsec-api-03.txt"
+.%O "internet draft"
+.Re
+.Sh CAVEAT
+The IPsec support is subject to change as the IPsec protocols develop.
+.Pp
+There is no single standard for policy engine API,
+so the policy engine API described herein is just for KAME implementation.
+.\"
+.Sh HISTORY
+The implementation described herein appeared in WIDE/KAME IPv6/IPsec stack.
diff --git a/share/man/man4/kame.4 b/share/man/man4/kame.4
new file mode 100644
index 0000000..fa09d98
--- /dev/null
+++ b/share/man/man4/kame.4
@@ -0,0 +1,217 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: kame.4,v 1.4 1999/10/07 04:01:15 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 13, 1999
+.Dt KAME 4
+.Os KAME
+.\"
+.Sh NAME
+.Nm KAME
+.Nd introduction and roadmap to KAME IPv6 software package
+.\"
+.Sh DESCRIPTION
+.Nm KAME
+software package is a result of joint work of several IPv6 researchers
+in Japan, to provide reference implementation of IPv6 to
+Berkeley Software Distribution
+.Pq BSD
+derived system such as BSD/OS,
+FreeBSD, NetBSD and OpenBSD
+.Pq in alphabetical order .
+.Pp
+.\" Package consists of set of patches and additions to kernel,
+.\" modification to application, daemons, header files and libraries.
+KAME kit consists of IPv6/IPsec-ready kernel, application, daemons,
+header files and libraries.
+.\"
+.Sh HIGHLIGHTS
+Following are some of highlights of this implementation.
+.\"
+.Ss Kernel
+IPv6 and IPsec protocol stacks are implemented and available.
+See below for conformance to standards and/or internet drafts.
+.\"
+.Ss Plug and Play and protocol stack/interface configuration
+.Xr ndp 8 ,
+.Xr prefix 8 ,
+.Xr rrenumd 8 ,
+.Xr rtadvd 8 ,
+.Xr rtsol 8 ,
+.Xr rtsold 8 .
+.\"
+.Ss Routing
+.Xr bgpd 8 ,
+.Xr hroute6d 8 ,
+.Xr rip6admin 8 ,
+.Xr rip6query 8 ,
+.Xr route6d 8 .
+.\"
+.Ss Multicast (includes routing and utilities)
+.Xr mcastread 1 ,
+.Xr mcastsend 1 ,
+.Xr mchat 1 ,
+.Xr ifmcstat 8 ,
+.Xr mld6query 8 ,
+.Xr pim6dd 8 ,
+.Xr pim6sd 8 ,
+.Xr pim6stat 8 .
+.\"
+.Ss Transition Tools
+Two IPv4 to IPv6 transition tools are available.
+TCP relay translator, FAITH
+.Po
+.Xr faithd 8
+.Pc .
+and SIIT IPv6-to-v4 header translator implementation
+.Po
+.Xr ptrconfig 8
+.Pc .
+.\"
+.Ss IPsec and tunnelling
+.Xr gifconfig 8 ,
+.Xr ipsec 4 ,
+.Xr dtcpc 8 ,
+.Xr dtcps 8 ,
+.Xr racoon 8 ,
+.Xr setkey 8 .
+.Pp
+Dozen of existing tools are modified for IPsec support, like
+.Xr ping 8 .
+.\"
+.Ss Utilities/Diagnosis
+.Xr cksum6 1 ,
+.Xr v6test 1 ,
+.Xr icmp6dump 8 ,
+.Xr ping6 8 ,
+.Xr traceroute6 8 ,
+.Xr v6p 8 .
+.Pp
+Dozen of existing utilities are modified for IPv6/IPsec support, like
+.Xr ftp 1
+and/or
+.Xr telnet 1 .
+.\"
+.Ss Application Daemons
+.Xr inetd 8
+modified for IPv4/v6 support, or
+IPv6-only
+.Xr inet6d 8
+is supplied.
+.Pp
+Dozen of existing daemons are modified for IPv6/IPsec support, like
+.Xr ftpd 8
+and/or
+.Xr telnetd 8 .
+.\"
+.Ss Miscellaneous
+SuMiRe IPv4 NAT
+.Po
+.Xr pma 8
+.Pc
+is available in addition to OS-supplied IPv4 NAT.
+.\"
+.Sh DOCUMENTATION
+Although some of documentations have not modified yet, program itself
+may be heavily modified.
+Following lists are not complete, but give you some idea what kind of
+new software modules are available, or, modifications are made.
+Please refer to each manual page for detail.
+Manpages are installed into
+.Pa /usr/local/v6/man
+so you may want to add the pathname to
+.Dv MANPATH .
+.\"
+.Ss Installation and basic usage documentations
+Please read following files in directory
+.Pa /usr/local/v6/share/doc/kame
+to get basic idea and installation methods on
+.Nm KAME :
+.Pa README ,
+.Pa RELNOTES ,
+.Pa USAGE
+and
+.Pa IMPLEMENTATION .
+Also check latest status of project at web page:
+.Pa http://www.kame.net/ .
+.Po
+Hope you can see a
+.Dq Dancing Turtle
+.Dv :-)
+.Pc
+.\"
+.Ss APIs introduced or modified
+.Xr if_indextoname 3 ,
+.Xr getipnodebyname 3 ,
+.Xr gethostbyname 3 ,
+.Xr rresvport_af 3 ,
+.Xr hosts_ctl 3 ,
+.Xr ipsec_get_policylen 3 ,
+.Xr getnameinfo 3 ,
+.Xr freeaddrinfo 3 ,
+.Xr getaddrinfo 3 ,
+.Xr pcap 3 ,
+.Xr getipnodebyaddr 3 ,
+.Xr resolver 3 ,
+.Xr ipsec_strerror 3 ,
+.Xr gai_strerror 3 ,
+.Xr hosts_access 3 ,
+.Xr request_set 3 ,
+.Xr request_init 3 ,
+.Xr freehostent 3 ,
+.Xr if_nameindex 3 ,
+.Xr if_freenameindex 3 ,
+.Xr if_nametoindex 3 ,
+.Xr ipsec_dump_policy 3 ,
+.Xr ipsec_set_policy 3 .
+.\"
+.Ss Added/modified/renamed features and tools
+Please consult the manpages referred above.
+.\"
+.Sh REFERENCES
+To understand
+.Nm KAME
+protocol stack conformance, please refer
+.Pa /usr/local/v6/share/doc/kame/IMPLEMENTATION .
+.Pp
+Bug reporting form, user mailing list, frequently asked questions list,
+latest packages, related software, and more information can be found at
+.Pa http://www.kame.net/ .
+.\"
+.Ss "Related project"
+TAHI project who is providing verification technology for IPv6, is
+heavily related with KAME project.
+You can get current verification
+status of KAME software at following THAI project web page:
+.Pa http://www.tahi.org/
+.\"
+.Sh HISTORY
+The
+.Nm
+project started in April 1999.
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index 792797c..c1f7539 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -12,6 +12,6 @@ BINGRP= kmem
BINMODE=2555
DPADD= ${LIBKVM} ${LIBIPX} ${LIBNETGRAPH}
LDADD= -lkvm -lipx -lnetgraph
-CFLAGS+=-DINET6
+CFLAGS+=-DINET6 -DIPSEC
.include <bsd.prog.mk>
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 220b989..9ab3104 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -48,6 +48,7 @@ SUBDIR= IPXrouted \
mrouted \
mtest \
mtree \
+ ndp \
newsyslog \
ngctl \
ntp \
@@ -80,10 +81,13 @@ SUBDIR= IPXrouted \
rpc.yppasswdd \
rpc.ypupdated \
rpc.ypxfrd \
+ rrenumd \
+ rtadvd \
rtprio \
rtsold \
rwhod \
sa \
+ setkey \
sliplogin \
slstat \
spray \
diff --git a/usr.sbin/ndp/Makefile b/usr.sbin/ndp/Makefile
new file mode 100644
index 0000000..b0ba348
--- /dev/null
+++ b/usr.sbin/ndp/Makefile
@@ -0,0 +1,25 @@
+# Copyright (c) 1996 WIDE Project. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modifications, are permitted provided that the above copyright notice
+# and this paragraph are duplicated in all such forms and that any
+# documentation, advertising materials, and other materials related to
+# such distribution and use acknowledge that the software was developed
+# by the WIDE Project, Japan. The name of the Project may not be used to
+# endorse or promote products derived from this software without
+# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS''
+# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE.
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../contrib/tcpdump
+
+PROG= ndp
+SRCS= ndp.c gmt2local.c
+MAN8= ndp.8
+
+CFLAGS+=-DINET6
+CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../contrib/tcpdump
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ndp/gnuc.h b/usr.sbin/ndp/gnuc.h
new file mode 100644
index 0000000..c641296
--- /dev/null
+++ b/usr.sbin/ndp/gnuc.h
@@ -0,0 +1,2 @@
+/* $FreeBSD$ */
+/* this is dummy to pacify gmt2local.c. */
diff --git a/usr.sbin/ndp/ndp.8 b/usr.sbin/ndp/ndp.8
new file mode 100644
index 0000000..6f0382f
--- /dev/null
+++ b/usr.sbin/ndp/ndp.8
@@ -0,0 +1,138 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ndp.8,v 1.2 1999/10/07 05:26:13 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 17, 1998
+.Dt NDP 8
+.Os KAME
+.\"
+.Sh NAME
+.Nm ndp
+.Nd control/diagnose IPv6 neighbor discovery protocol
+.\"
+.Sh SYNOPSIS
+.Nm ndp
+.Fl a
+.Op Fl ntl
+.Nm ndp
+.Fl A Ar wait
+.Op Fl ntl
+.Nm ndp
+.Fl c
+.Op Fl nt
+.Nm ndp
+.Fl d
+.Op Fl nt
+.Ar hostname
+.Nm ndp
+.Fl f
+.Op Fl nt
+.Ar filename
+.Nm ndp
+.Fl H
+.Nm ndp
+.Fl i
+.Ar interface
+.Nm ndp
+.Fl p
+.Nm ndp
+.Fl P
+.Nm ndp
+.Fl r
+.Nm ndp
+.Fl R
+.Nm ndp
+.Fl s
+.Op Fl nt
+.Ar nodename
+.Ar ether_addr
+.Op temp
+.\"
+.Sh DESCRIPTION
+.Nm
+command manipulates the address mapping table
+used by Neighbor Discovery Protocol (NDP).
+.Bl -tag -width Ds
+.It Fl a
+Dump the currently existing NDP entries.
+.It Fl A Ar wait
+Repeat
+.Fl a
+.Pq dump NDP entries
+every
+.Ar wait
+seconds.
+.It Fl c
+Erase all the NDP entries.
+.It Fl d
+Delete specified NDP entry.
+.It Fl f
+Parse the file specified by
+.Ar filename .
+.It Fl H
+Harmonize consistency between the routing table and the default router
+list; install the top entry of the list into the kernel routing table.
+.It Fl i
+view ND information for specified interface.
+.It Fl l
+Do not truncate numeric IPv6 address.
+.It Fl n
+Do not try to resolve numeric address to hostname.
+.It Fl p
+Show prefix list.
+.It Fl P
+Flush all the entries in the prefix list.
+.It Fl r
+Show default router list.
+.It Fl R
+Flush all the entries in the default router list.
+.It Fl s
+Register a NDP entry for a node.
+.It Fl t
+Print timestamp on each entries,
+to make it possible to merge output with
+.Xr tcpdump 1 .
+Most useful when used with
+.Fl A .
+.El
+.\"
+.Sh RETURN VALUES
+.Nm Ndp
+will exit with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr arp 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\"
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c
new file mode 100644
index 0000000..01cea32
--- /dev/null
+++ b/usr.sbin/ndp/ndp.c
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sun Microsystems, Inc.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Based on:
+ * "@(#) Copyright (c) 1984, 1993\n\
+ * The Regents of the University of California. All rights reserved.\n";
+ *
+ * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
+ */
+
+/*
+ * ndp - display, set, delete and flush neighbor cache
+ */
+
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/icmp6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <string.h>
+#include <paths.h>
+#include <err.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "gmt2local.h"
+
+/* packing rule for routing socket */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+extern int errno;
+static int pid;
+static int fflag;
+static int nflag;
+static int tflag;
+static int32_t thiszone; /* time difference with gmt */
+static int s = -1;
+static int repeat = 0;
+static int lflag = 0;
+
+char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */
+char host_buf[NI_MAXHOST]; /* getnameinfo() */
+char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
+
+int main __P((int, char **));
+int file __P((char *));
+void getsocket __P((void));
+int set __P((int, char **));
+void get __P((char *));
+int delete __P((char *));
+void dump __P((struct in6_addr *));
+static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, int ifindex));
+static char *ether_str __P((struct sockaddr_dl *));
+int ndp_ether_aton __P((char *, u_char *));
+void usage __P((void));
+int rtmsg __P((int));
+void ifinfo __P((char *));
+void list __P((void));
+void plist __P((void));
+void pfx_flush __P((void));
+void rtr_flush __P((void));
+void harmonize_rtr __P((void));
+static char *sec2str __P((time_t t));
+static char *ether_str __P((struct sockaddr_dl *sdl));
+static void ts_print __P((const struct timeval *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch;
+ int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0,
+ pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
+ extern char *optarg;
+ extern int optind;
+
+ pid = getpid();
+ thiszone = gmt2local(0);
+ while ((ch = getopt(argc, argv, "acndfilprstA:HPR")) != EOF)
+ switch ((char)ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ fflag = 1;
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'i' :
+ if (argc != 3)
+ usage();
+ ifinfo(argv[2]);
+ exit(0);
+ case 'n':
+ nflag = 1;
+ continue;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'f' :
+ if (argc != 3)
+ usage();
+ file(argv[2]);
+ exit(0);
+ case 'l' :
+ lflag = 1;
+ break;
+ case 'r' :
+ rflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'A':
+ aflag = 1;
+ repeat = atoi(optarg);
+ if (repeat < 0)
+ usage();
+ break;
+ case 'H' :
+ Hflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (aflag || cflag) {
+ dump(0);
+ exit(0);
+ }
+ if (dflag) {
+ if (argc != 1)
+ usage();
+ delete(argv[0]);
+ }
+ if (pflag) {
+ plist();
+ exit(0);
+ }
+ if (rflag) {
+ rtrlist();
+ exit(0);
+ }
+ if (sflag) {
+ if (argc < 2 || argc > 4)
+ usage();
+ exit(set(argc, argv) ? 1 : 0);
+ }
+ if (Hflag) {
+ harmonize_rtr();
+ exit(0);
+ }
+ if (Pflag) {
+ pfx_flush();
+ exit(0);
+ }
+ if (Rflag) {
+ rtr_flush();
+ exit(0);
+ }
+
+ if (argc != 1)
+ usage();
+ get(argv[0]);
+ exit(0);
+}
+
+/*
+ * Process a file to set standard ndp entries
+ */
+int
+file(name)
+ char *name;
+{
+ FILE *fp;
+ int i, retval;
+ char line[100], arg[5][50], *args[5];
+
+ if ((fp = fopen(name, "r")) == NULL) {
+ fprintf(stderr, "ndp: cannot open %s\n", name);
+ exit(1);
+ }
+ args[0] = &arg[0][0];
+ args[1] = &arg[1][0];
+ args[2] = &arg[2][0];
+ args[3] = &arg[3][0];
+ args[4] = &arg[4][0];
+ retval = 0;
+ while(fgets(line, 100, fp) != NULL) {
+ i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
+ arg[3], arg[4]);
+ if (i < 2) {
+ fprintf(stderr, "ndp: bad line: %s\n", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+void
+getsocket()
+{
+ if (s < 0) {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ }
+}
+
+struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
+struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
+struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
+int expire_time, flags, found_entry;
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+/*
+ * Set an individual neighbor cache entry
+ */
+int
+set(argc, argv)
+ int argc;
+ char **argv;
+{
+ register struct sockaddr_in6 *sin = &sin_m;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ struct addrinfo hints, *res;
+ int gai_error;
+ u_char *ea;
+ char *host = argv[0], *eaddr = argv[1];
+
+ getsocket();
+ argc -= 2;
+ argv += 2;
+ sdl_m = blank_sdl;
+ sin_m = blank_sin;
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return 1;
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+ ea = (u_char *)LLADDR(&sdl_m);
+ if (ndp_ether_aton(eaddr, ea) == 0)
+ sdl_m.sdl_alen = 6;
+ flags = expire_time = 0;
+ while (argc-- > 0) {
+ if (strncmp(argv[0], "temp", 4) == 0) {
+ struct timeval time;
+ gettimeofday(&time, 0);
+ expire_time = time.tv_sec + 20 * 60;
+ }
+ argv++;
+ }
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ perror(host);
+ return (1);
+ }
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
+ if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ goto overwrite;
+ }
+ goto tryagain;
+ }
+overwrite:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot intuit interface index and type for %s\n", host);
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD));
+}
+
+/*
+ * Display an individual neighbor cache entry
+ */
+void
+get(host)
+ char *host;
+{
+ struct sockaddr_in6 *sin = &sin_m;
+ struct addrinfo hints, *res;
+ int gai_error;
+
+ sin_m = blank_sin;
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return;
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+ dump(&sin->sin6_addr);
+ if (found_entry == 0) {
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof(host_buf), NULL ,0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ printf("%s (%s) -- no entry\n", host, host_buf);
+ exit(1);
+ }
+}
+
+/*
+ * Delete a neighbor cache entry
+ */
+int
+delete(host)
+ char *host;
+{
+ struct sockaddr_in6 *sin = &sin_m;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ struct sockaddr_dl *sdl;
+ struct addrinfo hints, *res;
+ int gai_error;
+
+ getsocket();
+ sin_m = blank_sin;
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return 1;
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+/*tryagain:*/
+ if (rtmsg(RTM_GET) < 0) {
+ perror(host);
+ return (1);
+ }
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
+ if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ goto delete;
+ }
+ }
+delete:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot locate %s\n", host);
+ return (1);
+ }
+ if (rtmsg(RTM_DELETE) == 0) {
+ getnameinfo((struct sockaddr *)sin,
+ sin->sin6_len, host_buf,
+ sizeof(host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ printf("%s (%s) deleted\n", host, host_buf);
+ }
+
+ return 0;
+}
+
+/*
+ * Dump the entire neighbor cache
+ */
+void
+dump(addr)
+ struct in6_addr *addr;
+{
+ int mib[6];
+ size_t needed;
+ char *host, *lim, *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_in6 *sin;
+ struct sockaddr_dl *sdl;
+ extern int h_errno;
+ struct hostent *hp;
+ struct in6_nbrinfo *nbi;
+ struct timeval time;
+ int addrwidth;
+
+ /* Print header */
+ if (!tflag)
+ printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n",
+ "Neighbor", "Linklayer Address", "Netif", "Expire",
+ "St", "Flgs", "Prbs");
+
+again:;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE estimate)");
+ if (needed > 0) {
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
+ lim = buf + needed;
+ } else
+ buf = lim = NULL;
+
+ for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
+ int isrouter = 0, prbs = 0;
+
+ rtm = (struct rt_msghdr *)next;
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
+ if (addr) {
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
+ continue;
+ found_entry = 1;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
+ continue;
+ if (fflag == 1) {
+ delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+ continue;
+ }
+
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
+ /* XXX: should scope id be filled in the kernel? */
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = sdl->sdl_index;
+
+ /* XXX: KAME specific hack; removed the embedded id */
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
+ }
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof(host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ gettimeofday(&time, 0);
+ if (tflag)
+ ts_print(&time);
+
+ if (lflag) {
+ addrwidth = strlen(host_buf);
+ if (addrwidth < 29)
+ addrwidth = 29;
+ } else
+ addrwidth = 29;
+
+ printf("%-*.*s %-18.18s %6.6s", addrwidth, addrwidth, host_buf,
+ ether_str(sdl),
+ if_indextoname(sdl->sdl_index, ifix_buf));
+
+ /* Print neighbor discovery specific informations */
+ putchar(' ');
+ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index);
+ if (nbi) {
+ if (nbi->expire > time.tv_sec) {
+ printf(" %-9.9s",
+ sec2str(nbi->expire - time.tv_sec));
+ }
+ else if (nbi->expire == 0)
+ printf(" %-9.9s", "permanent");
+ else
+ printf(" %-9.9s", "expired");
+
+ switch(nbi->state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
+ case ND6_LLINFO_WAITDELETE:
+ printf(" W");
+ break;
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
+ }
+
+ isrouter = nbi->isrouter;
+ prbs = nbi->asked;
+ }
+ else {
+ warnx("failed to get neighbor information");
+ printf(" ");
+ }
+
+ /* other flags */
+ putchar(' ');
+ {
+ u_char flgbuf[8], *p = flgbuf;
+
+ flgbuf[0] = '\0';
+ if (isrouter)
+ p += sprintf((char *)p, "R");
+#ifndef RADISH
+ if (rtm->rtm_addrs & RTA_NETMASK) {
+ sin = (struct sockaddr_in6 *)
+ (sdl->sdl_len + (char *)sdl);
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
+ p += sprintf((char *)p, "P");
+ if (sin->sin6_len != sizeof(struct sockaddr_in6))
+ p += sprintf((char *)p, "W");
+ }
+#endif /*RADISH*/
+ printf("%4s", flgbuf);
+ }
+
+ putchar(' ');
+ if (prbs)
+ printf("% 4d", prbs);
+
+ printf("\n");
+ }
+
+ if (repeat) {
+ printf("\n");
+ sleep(repeat);
+ goto again;
+ }
+}
+
+static struct in6_nbrinfo *
+getnbrinfo(addr, ifindex)
+ struct in6_addr *addr;
+ int ifindex;
+{
+ static struct in6_nbrinfo nbi;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ bzero(&nbi, sizeof(nbi));
+ if_indextoname(ifindex, nbi.ifname);
+ nbi.addr = *addr;
+ if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
+ warn("ioctl");
+ close(s);
+ return(NULL);
+ }
+
+ close(s);
+ return(&nbi);
+}
+
+static char *
+ether_str(sdl)
+ struct sockaddr_dl *sdl;
+{
+ static char ebuf[32];
+ u_char *cp;
+
+ if (sdl->sdl_alen) {
+ cp = (u_char *)LLADDR(sdl);
+ sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ }
+ else {
+ sprintf(ebuf, "(incomplete)");
+ }
+
+ return(ebuf);
+}
+
+int
+ndp_ether_aton(a, n)
+ char *a;
+ u_char *n;
+{
+ int i, o[6];
+
+ i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
+ &o[3], &o[4], &o[5]);
+ if (i != 6) {
+ fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
+ return (1);
+ }
+ for (i=0; i<6; i++)
+ n[i] = o[i];
+ return (0);
+}
+
+void
+usage()
+{
+ printf("usage: ndp hostname\n");
+ printf(" ndp -a[ntl]\n");
+ printf(" ndp [-ntl] -A wait\n");
+ printf(" ndp -c[nt]\n");
+ printf(" ndp -d[nt] hostname\n");
+ printf(" ndp -f[nt] filename\n");
+ printf(" ndp -i interface\n");
+ printf(" ndp -p\n");
+ printf(" ndp -r\n");
+ printf(" ndp -s hostname ether_addr [temp]\n");
+ printf(" ndp -H\n");
+ printf(" ndp -P\n");
+ printf(" ndp -R\n");
+ exit(1);
+}
+
+int
+rtmsg(cmd)
+ int cmd;
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+ errno = 0;
+ if (cmd == RTM_DELETE)
+ goto doit;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ fprintf(stderr, "ndp: internal wrong cmd\n");
+ exit(1);
+ case RTM_ADD:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if (rtm->rtm_addrs & (w)) { \
+ bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
+
+ NEXTADDR(RTA_DST, sin_m);
+ NEXTADDR(RTA_GATEWAY, sdl_m);
+ NEXTADDR(RTA_NETMASK, so_mask);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+doit:
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if (errno != ESRCH || cmd != RTM_DELETE) {
+ perror("writing to routing socket");
+ return (-1);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+ if (l < 0)
+ (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
+ strerror(errno));
+ return (0);
+}
+
+void
+ifinfo(ifname)
+ char *ifname;
+{
+ struct in6_ndireq nd;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ bzero(&nd, sizeof(nd));
+ strcpy(nd.ifname, ifname);
+ if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
+ perror("ioctl (SIOCGIFINFO_IN6)");
+ exit(1);
+ }
+#define ND nd.ndi
+ printf("linkmtu=%d", ND.linkmtu);
+ printf(", curhlim=%d", ND.chlim);
+ printf(", basereachable=%ds%dms",
+ ND.basereachable / 1000, ND.basereachable % 1000);
+ printf(", reachable=%ds", ND.reachable);
+ printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000);
+#undef ND
+ close(s);
+}
+
+void
+rtrlist()
+{
+ struct in6_drlist dr;
+ int s, i;
+ struct timeval time;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ bzero(&dr, sizeof(dr));
+ strcpy(dr.ifname, "lo0"); /* dummy */
+ if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
+ perror("ioctl (SIOCGDRLST_IN6)");
+ exit(1);
+ }
+#define DR dr.defrouter[i]
+ for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) {
+ struct sockaddr_in6 sin6;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_addr = DR.rtaddr;
+ getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
+ sizeof(host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+
+ printf("%s if=%s", host_buf,
+ if_indextoname(DR.if_index, ifix_buf));
+ printf(", flags=%s%s",
+ DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
+ DR.flags & ND_RA_FLAG_OTHER ? "O" : "");
+ gettimeofday(&time, 0);
+ if (DR.expire == 0)
+ printf(", expire=Never\n");
+ else
+ printf(", expire=%s\n",
+ sec2str(DR.expire - time.tv_sec));
+ }
+#undef DR
+ close(s);
+}
+
+void
+plist()
+{
+ struct in6_prlist pr;
+ int s, i;
+ struct timeval time;
+
+ gettimeofday(&time, 0);
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ bzero(&pr, sizeof(pr));
+ strcpy(pr.ifname, "lo0"); /* dummy */
+ if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
+ perror("ioctl (SIOCGPRLST_IN6)");
+ exit(1);
+ }
+#define PR pr.prefix[i]
+ for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
+ printf("%s/%d if=%s\n",
+ inet_ntop(AF_INET6, &PR.prefix, ntop_buf,
+ sizeof(ntop_buf)), PR.prefixlen,
+ if_indextoname(PR.if_index, ifix_buf));
+ gettimeofday(&time, 0);
+ printf(" flags=%s%s",
+ PR.raflags.onlink ? "L" : "",
+ PR.raflags.autonomous ? "A" : "");
+ if (PR.vltime == ND6_INFINITE_LIFETIME)
+ printf(" vltime=infinity");
+ else
+ printf(" vltime=%ld", (long)PR.vltime);
+ if (PR.pltime == ND6_INFINITE_LIFETIME)
+ printf(", pltime=infinity");
+ else
+ printf(", pltime=%ld", (long)PR.pltime);
+ if (PR.expire == 0)
+ printf(", expire=Never\n");
+ else if (PR.expire >= time.tv_sec)
+ printf(", expire=%s\n",
+ sec2str(PR.expire - time.tv_sec));
+ else
+ printf(", expired\n");
+ if (PR.advrtrs) {
+ int j;
+ printf(" advertised by\n");
+ for (j = 0; j < PR.advrtrs; j++) {
+ struct sockaddr_in6 sin6;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_addr = PR.advrtr[j];
+ getnameinfo((struct sockaddr *)&sin6,
+ sin6.sin6_len, host_buf,
+ sizeof(host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+
+ printf(" %s\n", host_buf);
+ }
+ if (PR.advrtrs > DRLSTSIZ)
+ printf(" and %d routers\n",
+ PR.advrtrs - DRLSTSIZ);
+ }
+ else
+ printf(" No advertising router\n");
+ }
+#undef PR
+ close(s);
+}
+
+void
+pfx_flush()
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strcpy(dummyif, "lo0"); /* dummy */
+ if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
+}
+
+void
+rtr_flush()
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strcpy(dummyif, "lo0"); /* dummy */
+ if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
+}
+
+void
+harmonize_rtr()
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ strcpy(dummyif, "lo0"); /* dummy */
+ if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) {
+ perror("ioctl (SIOCSNDFLUSH_IN6)");
+ exit(1);
+ }
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += sprintf(p, "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += sprintf(p, "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += sprintf(p, "%dm", mins);
+ }
+ sprintf(p, "%ds", secs);
+
+ return(result);
+}
+
+/*
+ * Print the timestamp
+ * from tcpdump/util.c
+ */
+static void
+ts_print(tvp)
+ const struct timeval *tvp;
+{
+ int s;
+
+ /* Default */
+ s = (tvp->tv_sec + thiszone) % 86400;
+ (void)printf("%02d:%02d:%02d.%06u ",
+ s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
+}
diff --git a/usr.sbin/rrenumd/Makefile b/usr.sbin/rrenumd/Makefile
new file mode 100644
index 0000000..990ddab
--- /dev/null
+++ b/usr.sbin/rrenumd/Makefile
@@ -0,0 +1,41 @@
+# Copyright (c) 1996 WIDE Project. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modifications, are permitted provided that the above copyright notice
+# and this paragraph are duplicated in all such forms and that any
+# documentation, advertising materials, and other materials related to
+# such distribution and use acknowledge that the software was developed
+# by the WIDE Project, Japan. The name of the Project may not be used to
+# endorse or promote products derived from this software without
+# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS''
+# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE.
+# $FreeBSD$
+
+PROG= rrenumd
+SRCS= rrenumd.c parser.y lexer.l
+YFLAGS+= -d
+
+CC= gcc
+
+CFLAGS+= -DINET6 -DIPSEC -I${.OBJDIR}
+LDADD+= -lipsec -lcompat
+DPADD+= ${LIBIPSEC} ${LIBCOMPAT}
+LDADD+= -ll -ly
+DPADD+= ${LIBL} ${LIBY}
+
+MAN5= rrenumd.conf.5
+MAN8= rrenumd.8
+
+SRCS+=y.tab.h
+y.tab.h: parser.y
+
+.if defined(YACCDEBUG)
+CFLAGS+= -DYYDEBUG
+YFLAGS+= -t -v
+.endif
+
+.include <bsd.prog.mk>
+
+CLEANFILES+= y.tab.h
diff --git a/usr.sbin/rrenumd/lexer.l b/usr.sbin/rrenumd/lexer.l
new file mode 100644
index 0000000..80429af
--- /dev/null
+++ b/usr.sbin/rrenumd/lexer.l
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+%{
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+#include "y.tab.h"
+
+int lineno = 1;
+
+#define LINEBUF_SIZE 1000
+char linebuf[LINEBUF_SIZE];
+%}
+
+/* common section */
+nl \n
+ws [ \t]+
+digit [0-9]
+letter [0-9A-Za-z]
+hexdigit [0-9A-Fa-f]
+special [()+\|\?\*,]
+dot \.
+hyphen \-
+colon \:
+slash \/
+bcl \{
+ecl \}
+semi \;
+usec {dot}{digit}{1,6}
+comment \#.*
+qstring \"[^"]*\"
+decstring {digit}+
+hexpair {hexdigit}{hexdigit}
+hexstring 0[xX]{hexdigit}+
+octetstring {octet}({dot}{octet})+
+ipv4addr {digit}{1,3}({dot}{digit}{1,3}){0,3}
+ipv6addr {hexdigit}{0,4}({colon}{hexdigit}{0,4}){2,7}
+ipaddrmask {slash}{digit}{1,3}
+keyword {letter}{letter}+
+name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))*
+hostname {name}(({dot}{name})+{dot}?)?
+
+timeval {digit}{0,2}
+days d{timeval}
+hours h{timeval}
+minutes m{timeval}
+seconds s{timeval}
+
+mprefix match_prefix|match-prefix
+uprefix use_prefix|use-prefix
+
+%%
+ /* rrenumd keywords */
+debug {
+ return(DEBUG_CMD);
+ }
+dest {
+ return(DEST_CMD);
+ }
+retry {
+ return(RETRY_CMD);
+ }
+seqnum {
+ return(SEQNUM_CMD);
+ }
+add {
+ yylval.num = RPM_PCO_ADD;
+ return(ADD);
+ }
+change {
+ yylval.num = RPM_PCO_CHANGE;
+ return(CHANGE);
+ }
+setglobal {
+ yylval.num = RPM_PCO_SETGLOBAL;
+ return(SETGLOBAL);
+ }
+{mprefix} {
+ return(MATCH_PREFIX_CMD);
+ }
+maxlen {
+ return(MAXLEN_CMD);
+ }
+minlen {
+ return(MINLEN_CMD);
+ }
+{uprefix} {
+ return(USE_PREFIX_CMD);
+ }
+keeplen {
+ return(KEEPLEN_CMD);
+ }
+
+vltime {
+ return(VLTIME_CMD);
+ }
+pltime {
+ return(PLTIME_CMD);
+ }
+raf_onlink {
+ return(RAF_ONLINK_CMD);
+ }
+raf_auto {
+ return(RAF_AUTO_CMD);
+ }
+rrf_decrvalid {
+ return(RAF_DECRVALID_CMD);
+ }
+rrf_decrprefd {
+ return(RAF_DECRPREFD_CMD);
+ }
+{days} {
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(DAYS);
+ }
+{hours} {
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(HOURS);
+ }
+{minutes} {
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(MINUTES);
+ }
+{seconds} {
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(SECONDS);
+ }
+infinity {
+ return(INFINITY);
+ }
+
+on {
+ yylval.num = 1;
+ return(ON);
+ }
+off {
+ yylval.num = 0;
+ return(OFF);
+ }
+
+ /* basic rules */
+{ws} ;
+{nl} {
+ lineno++;
+ }
+{semi} {
+ return EOS;
+ }
+{bcl} {
+ return BCL;
+ }
+{ecl} {
+ return ECL;
+ }
+{qstring} {
+ yylval.cs.cp = yytext;
+ yylval.cs.len = yyleng;
+ return QSTRING;
+ }
+{decstring} {
+ yylval.cs.cp = yytext;
+ yylval.cs.len = yyleng;
+ return DECSTRING;
+ }
+{name} {
+ yylval.cs.cp = yytext;
+ yylval.cs.len = yyleng;
+ return NAME;
+ }
+{ipv6addr} {
+ memset(&yylval.addr6, 0, sizeof(struct in6_addr));
+ if (inet_pton(AF_INET6, yytext,
+ &yylval.addr6) == 1) {
+ return IPV6ADDR;
+ } else {
+ return ERROR;
+ }
+ }
+{ipaddrmask} {
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(PREFIXLEN);
+ }
+{hostname} {
+ yylval.cs.cp = yytext;
+ yylval.cs.len = yyleng;
+ return HOSTNAME;
+ }
+%%
+
+int parse(FILE **fp)
+{
+ yyin = *fp;
+
+ if(yyparse())
+ return(-1);
+
+ return(0);
+
+}
+
+void
+yyerror(const char *s)
+{
+ printf("%s: at %s in line %d\n", s, yytext, lineno);
+}
diff --git a/usr.sbin/rrenumd/parser.y b/usr.sbin/rrenumd/parser.y
new file mode 100644
index 0000000..eecc7bb
--- /dev/null
+++ b/usr.sbin/rrenumd/parser.y
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+%{
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+
+#include <netdb.h>
+#include <string.h>
+
+#include "rrenumd.h"
+
+struct config_is_set {
+ u_short cis_dest : 1;
+} cis;
+
+struct dst_list *dl_head;
+struct payload_list *pl_head, ple_cur;
+u_int retry;
+char errbuf[LINE_MAX];
+
+extern int lineno;
+extern void yyerror __P((const char *s));
+static struct payload_list * pllist_lookup __P((int seqnum));
+static void pllist_enqueue __P((struct payload_list *pl_entry));
+
+#define MAX_RETRYNUM 10 /* upper limit of retry in this rrenumd program */
+#define MAX_SEQNUM 256 /* upper limit of seqnum in this rrenumd program */
+#define NOSPEC -1
+
+%}
+
+%union {
+ u_long num;
+ struct {
+ char *cp;
+ int len;
+ } cs;
+ struct in_addr addr4;
+ struct in6_addr addr6;
+ struct {
+ struct in6_addr addr;
+ u_char plen;
+ } prefix;
+ struct dst_list *dl;
+ struct payload_list *pl;
+ struct sockaddr *sa;
+}
+
+%token <num> ADD CHANGE SETGLOBAL
+%token DEBUG_CMD DEST_CMD RETRY_CMD SEQNUM_CMD
+%token MATCH_PREFIX_CMD MAXLEN_CMD MINLEN_CMD
+%token USE_PREFIX_CMD KEEPLEN_CMD
+%token VLTIME_CMD PLTIME_CMD
+%token RAF_ONLINK_CMD RAF_AUTO_CMD RAF_DECRVALID_CMD RAF_DECRPREFD_CMD
+%token <num> DAYS HOURS MINUTES SECONDS INFINITY
+%token <num> ON OFF
+%token BCL ECL EOS ERROR
+%token <cs> NAME HOSTNAME QSTRING DECSTRING
+%token <addr4> IPV4ADDR
+%token <addr6> IPV6ADDR
+%token <num> PREFIXLEN
+
+%type <num> retrynum seqnum rrenum_cmd
+%type <num> prefixlen maxlen minlen keeplen vltime pltime
+%type <num> lifetime days hours minutes seconds
+%type <num> decstring
+%type <num> raf_onlink raf_auto raf_decrvalid raf_decrprefd flag
+%type <dl> dest_addrs dest_addr sin6
+%type <pl> rrenum_statement
+%type <cs> ifname
+%type <prefix> prefixval
+
+%%
+config:
+ /* empty */
+ | statements
+ ;
+
+statements:
+ statement
+ | statements statement
+ ;
+
+statement:
+ debug_statement
+ | destination_statement
+ | rrenum_statement_without_seqnum
+ | rrenum_statement_with_seqnum
+ | error EOS
+ {
+ yyerrok;
+ }
+ | EOS
+ ;
+
+debug_statement:
+ DEBUG_CMD flag EOS
+ {
+#ifdef YYDEBUG
+ yydebug = $2;
+#endif /* YYDEBUG */
+ }
+ ;
+
+destination_statement:
+ DEST_CMD dest_addrs retrynum EOS
+ {
+ dl_head = $2;
+ retry = $3;
+ }
+ ;
+
+dest_addrs:
+ dest_addr
+ | dest_addrs dest_addr
+ {
+ $2->dl_next = $1;
+ $$ = $2;
+ }
+ ;
+
+dest_addr :
+ sin6
+ {
+ with_v6dest = 1;
+ }
+ | sin6 ifname
+ {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)$1->dl_dst;
+ sin6->sin6_scope_id = if_nametoindex($2.cp);
+ with_v6dest = 1;
+ $$ = $1;
+ }
+ | HOSTNAME
+ {
+ struct sockaddr_storage *ss;
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = 0;
+ error = getaddrinfo($1.cp, 0, &hints, &res);
+ if (error) {
+ sprintf(errbuf, "name resolution failed for %s"
+ ":%s", $1, gai_strerror(error));
+ yyerror(errbuf);
+ }
+ ss = (struct sockaddr_storage *)malloc(sizeof(*ss));
+ memset(ss, 0, sizeof(*ss));
+ memcpy(ss, res->ai_addr, res->ai_addr->sa_len);
+ freeaddrinfo(res);
+
+ $$ = (struct dst_list *)
+ malloc(sizeof(struct dst_list));
+ memset($$, 0, sizeof(struct dst_list));
+ $$->dl_dst = (struct sockaddr *)ss;
+ }
+ ;
+
+sin6:
+ IPV6ADDR
+ {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)malloc(sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr = $1;
+
+ $$ = (struct dst_list *)
+ malloc(sizeof(struct dst_list));
+ memset($$, 0, sizeof(struct dst_list));
+ $$->dl_dst = (struct sockaddr *)sin6;
+ }
+
+ifname:
+ NAME
+ {
+ $$.cp = strdup($1.cp);
+ $$.len = $1.len;
+ }
+ | QSTRING
+ {
+ $1.cp[$1.len - 1] = 0;
+ $$.cp = strdup(&$1.cp[1]);
+ $$.len = $1.len - 2;
+ }
+ ;
+
+retrynum:
+ /* empty */
+ {
+ $$ = 2;
+ }
+ | RETRY_CMD decstring
+ {
+ if ($2 > MAX_RETRYNUM)
+ $2 = MAX_RETRYNUM;
+ $$ = $2;
+ }
+ ;
+
+rrenum_statement_with_seqnum:
+ SEQNUM_CMD seqnum
+ {
+ if (pllist_lookup($2)) {
+ sprintf(errbuf, "duplicate seqnum %d specified"
+ " at %d", $2, lineno);
+ yyerror(errbuf);
+ }
+ }
+ BCL rrenum_statement EOS ECL EOS
+ {
+ $5->pl_irr.rr_seqnum = $2;
+ pllist_enqueue($5);
+ }
+ ;
+
+seqnum:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | decstring
+ {
+ if ($1 > MAX_SEQNUM) {
+ sprintf(errbuf, "seqnum %d is illegal for this"
+ " program. should be between 0 and %d",
+ $1, MAX_SEQNUM);
+ yyerror(errbuf);
+ }
+ $$ = $1;
+ }
+ ;
+
+rrenum_statement_without_seqnum:
+ rrenum_statement EOS
+ {
+ if (pllist_lookup(0)) {
+ sprintf(errbuf, "duplicate seqnum %d specified"
+ " at %d", 0, lineno);
+ yyerror(errbuf);
+ }
+ $1->pl_irr.rr_seqnum = 0;
+ pllist_enqueue($1);
+ }
+ ;
+
+rrenum_statement:
+ match_prefix_definition use_prefix_definition
+ {
+ $$ = (struct payload_list *)
+ malloc(sizeof(struct payload_list));
+ memcpy($$, &ple_cur, sizeof(ple_cur));
+ }
+ ;
+
+match_prefix_definition:
+ rrenum_cmd MATCH_PREFIX_CMD prefixval maxlen minlen
+ {
+ struct icmp6_router_renum *irr;
+ struct rr_pco_match *rpm;
+
+ irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
+ rpm = (struct rr_pco_match *)(irr + 1);
+ memset(rpm, 0, sizeof(*rpm));
+
+ rpm->rpm_code = $1;
+ rpm->rpm_prefix = $3.addr;
+ rpm->rpm_matchlen = $3.plen;
+ rpm->rpm_maxlen = $4;
+ rpm->rpm_minlen = $5;
+ }
+ ;
+
+rrenum_cmd:
+ /* empty */
+ {
+ $$ = RPM_PCO_ADD;
+ }
+ | ADD
+ | CHANGE
+ | SETGLOBAL
+ ;
+
+prefixval:
+ IPV6ADDR prefixlen
+ {
+ $$.addr = $1;
+ $$.plen = $2;
+ }
+ ;
+
+prefixlen:
+ /* empty */
+ {
+ $$ = 64;
+ }
+ | PREFIXLEN
+ ;
+
+maxlen:
+ /* empty */
+ {
+ $$ = 128;
+ }
+ | MAXLEN_CMD decstring
+ {
+ if ($2 > 128)
+ $2 = 128;
+ $$ = $2;
+ }
+ ;
+
+minlen:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | MINLEN_CMD decstring
+ {
+ if ($2 > 128)
+ $2 = 128;
+ $$ = $2;
+ }
+ ;
+
+use_prefix_definition:
+ /* empty */
+ {
+ struct icmp6_router_renum *irr;
+ struct rr_pco_match *rpm;
+ struct rr_pco_use *rpu;
+
+ irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
+ rpm = (struct rr_pco_match *)(irr + 1);
+ rpu = (struct rr_pco_use *)(rpm + 1);
+ memset(rpu, 0, sizeof(*rpu));
+ }
+ | USE_PREFIX_CMD prefixval keeplen use_prefix_values
+ {
+ struct icmp6_router_renum *irr;
+ struct rr_pco_match *rpm;
+ struct rr_pco_use *rpu;
+
+ irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
+ rpm = (struct rr_pco_match *)(irr + 1);
+ rpu = (struct rr_pco_use *)(rpm + 1);
+
+ rpu->rpu_prefix = $2.addr;
+ rpu->rpu_uselen = $2.plen;
+ rpu->rpu_keeplen = $3;
+ }
+ ;
+
+use_prefix_values:
+ /* empty */
+ {
+ struct icmp6_router_renum *irr;
+ struct rr_pco_match *rpm;
+ struct rr_pco_use *rpu;
+
+ irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
+ rpm = (struct rr_pco_match *)(irr + 1);
+ rpu = (struct rr_pco_use *)(rpm + 1);
+ memset(rpu, 0, sizeof(*rpu));
+
+ rpu->rpu_vltime = DEF_VLTIME;
+ rpu->rpu_pltime = DEF_PLTIME;
+ rpu->rpu_ramask = 0;
+ rpu->rpu_flags = 0;
+ }
+ | BCL vltime pltime raf_onlink raf_auto raf_decrvalid raf_decrprefd ECL
+ {
+ struct icmp6_router_renum *irr;
+ struct rr_pco_match *rpm;
+ struct rr_pco_use *rpu;
+
+ irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
+ rpm = (struct rr_pco_match *)(irr + 1);
+ rpu = (struct rr_pco_use *)(rpm + 1);
+ memset(rpu, 0, sizeof(*rpu));
+
+ rpu->rpu_vltime = $2;
+ rpu->rpu_pltime = $3;
+ if ($4 == NOSPEC)
+ rpu->rpu_ramask &=
+ ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
+ else {
+ rpu->rpu_ramask |=
+ ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
+ if ($4 == ON)
+ rpu->rpu_raflags |=
+ ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
+ else
+ rpu->rpu_raflags &=
+ ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
+ }
+ if ($5 == NOSPEC)
+ rpu->rpu_ramask &=
+ ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
+ else {
+ rpu->rpu_ramask |=
+ ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
+ if ($5 == ON)
+ rpu->rpu_raflags |=
+ ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
+ else
+ rpu->rpu_raflags &=
+ ~ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
+ }
+ rpu->rpu_flags = 0;
+ if ($6 == ON)
+ rpu->rpu_flags |=
+ ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME;
+ if ($7 == ON)
+ rpu->rpu_flags |=
+ ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME;
+ }
+ ;
+
+keeplen:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | KEEPLEN_CMD decstring
+ {
+ if ($2 > 128)
+ $2 = 128;
+ $$ = $2;
+ }
+ ;
+
+
+vltime:
+ /* empty */
+ {
+ $$ = DEF_VLTIME;
+ }
+ | VLTIME_CMD lifetime
+ {
+ $$ = htonl($2);
+ }
+ ;
+
+pltime:
+ /* empty */
+ {
+ $$ = DEF_PLTIME;
+ }
+ | PLTIME_CMD lifetime
+ {
+ $$ = htonl($2);
+ }
+
+raf_onlink:
+ /* empty */
+ {
+ $$ = NOSPEC;
+ }
+ | RAF_ONLINK_CMD flag
+ {
+ $$ = $2;
+ }
+ ;
+
+raf_auto:
+ /* empty */
+ {
+ $$ = NOSPEC;
+ }
+ | RAF_AUTO_CMD flag
+ {
+ $$ = $2;
+ }
+ ;
+
+raf_decrvalid:
+ /* empty */
+ {
+ $$ = NOSPEC;
+ }
+ | RAF_DECRVALID_CMD flag
+ {
+ $$ = $2;
+ }
+ ;
+
+raf_decrprefd:
+ /* empty */
+ {
+ $$ = NOSPEC;
+ }
+ | RAF_DECRPREFD_CMD flag
+ {
+ $$ = $2;
+ }
+ ;
+
+flag:
+ ON
+ | OFF
+ ;
+
+lifetime:
+ decstring
+ | INFINITY
+ {
+ $$ = 0xffffffff;
+ }
+ | days hours minutes seconds
+ {
+ int d, h, m, s;
+
+ d = $1 * 24 * 60 * 60;
+ h = $2 * 60 * 60;
+ m = $3 * 60;
+ s = $4;
+ $$ = d + h + m + s;
+ }
+ ;
+
+days:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | DAYS
+ ;
+
+hours:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | HOURS
+ ;
+
+minutes:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | MINUTES
+ ;
+
+seconds:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | SECONDS
+ ;
+
+decstring:
+ DECSTRING
+ {
+ int dval;
+
+ dval = atoi($1.cp);
+ $$ = dval;
+ }
+ ;
+
+%%
+
+static struct payload_list *
+pllist_lookup(int seqnum)
+{
+ struct payload_list *pl;
+ for (pl = pl_head; pl && pl->pl_irr.rr_seqnum != seqnum;
+ pl = pl->pl_next)
+ continue;
+ return (pl);
+}
+
+static void
+pllist_enqueue(struct payload_list *pl_entry)
+{
+ struct payload_list *pl, *pl_last;
+ if (pl_head == NULL) {
+ pl_head = pl_entry;
+ return;
+ }
+ for (pl = pl_head;
+ pl && pl->pl_irr.rr_seqnum < pl_entry->pl_irr.rr_seqnum;
+ pl_last = pl, pl = pl->pl_next)
+ continue;
+ pl_last->pl_next = pl_entry;
+
+ return;
+}
diff --git a/usr.sbin/rrenumd/rrenumd.8 b/usr.sbin/rrenumd/rrenumd.8
new file mode 100644
index 0000000..aa7ae6b
--- /dev/null
+++ b/usr.sbin/rrenumd/rrenumd.8
@@ -0,0 +1,95 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: rrenumd.8,v 1.1.1.1 1999/08/08 23:31:38 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd Sep 7, 1998
+.Dt RRENUMD 8
+.Os KAME
+.Sh NAME
+.Nm rrenumd
+.Nd router renumbering daemon
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl c Ar conf_file | Fl s
+.Oc
+.Op Fl P Ar policy
+.Op Fl df
+.Sh DESCRIPTION
+.Nm Rrenumd
+assigns prefixes to subnets inside the site, or renumbers them.
+.Pp
+The program will daemonize itself on invocation.
+It reads configuration information from standard input if
+.Fl s
+is specified, or from
+.Ar conf_file
+if
+.Fl c Ar conf_file
+is specified.
+.Pp
+The contents of configuration information are described in
+.Xr rrenumd.conf 5 .
+.Pp
+After successful configuration,
+.Nm
+sends router renumbering
+messages periodically to configured destinations.
+Messages contain prefixes configured to be renumbered.
+.Bl -tag -width indent
+.\"
+.It Fl d
+Debug mode.
+.It Fl f
+Foreground mode.
+Do not become daemon.
+.It Fl s
+Script mode.
+Configuration information is obtained from standard input.
+.It Fl P Ar policy
+.Ar policy
+specifies IPsec policy for the rrenumd session.
+For details please refer to
+.Xr ipsec 4
+and
+.Xr ipsec_set_policy 3 .
+.It Fl c Ar conf_file
+Specify a configuration file where configuration information is kept.
+.Sh RETURN VALUES
+The program exits with 0 on success, and non-zero on failures.
+.El
+.Sh SEE ALSO
+.Xr daemon 3
+.Xr rrenumd.conf 5 ,
+.Sh HISTORY
+The
+.Nm
+command first appeared in KAME IPv6 protocol stack kit.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/usr.sbin/rrenumd/rrenumd.c b/usr.sbin/rrenumd/rrenumd.c
new file mode 100644
index 0000000..ced5afc
--- /dev/null
+++ b/usr.sbin/rrenumd/rrenumd.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+
+#include <string.h>
+
+#include <net/route.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include "rrenumd.h"
+
+#define LL_ALLROUTERS "ff02::2"
+#define SL_ALLROUTERS "ff05::2"
+
+#ifndef IN6_IS_SCOPE_LINKLOCAL
+#define IN6_IS_SCOPE_LINKLOCAL(a) \
+ ((IN6_IS_ADDR_LINKLOCAL(a)) || \
+ (IN6_IS_ADDR_MC_LINKLOCAL(a)))
+#endif /* IN6_IS_SCOPE_LINKLOCAL */
+
+struct flags {
+ u_long debug : 1;
+ u_long fg : 1;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ u_long policy : 1;
+#endif /* IPSEC_POLICY_IPSEC */
+#endif /*IPSEC*/
+};
+
+struct msghdr sndmhdr;
+struct msghdr rcvmhdr;
+struct sockaddr_in6 from;
+struct sockaddr_in6 sin6_ll_allrouters;
+
+int s6;
+int with_v6dest;
+struct in6_addr prefix; /* ADHOC */
+int prefixlen = 64; /* ADHOC */
+
+extern int parse(FILE **fp);
+
+/* Print usage. Don't call this after daemonized. */
+static void
+show_usage()
+{
+ fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df"
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ "] [-P policy"
+#endif /* IPSEC_POLICY_IPSEC */
+#endif /* IPSEC */
+ "]\n");
+ exit(1);
+}
+
+void
+init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii)
+{
+ memset(sin6, 0, sizeof(*sin6));
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1)
+ ; /* XXX do something */
+}
+
+void
+init_globals()
+{
+ static struct iovec rcviov;
+ static u_char rprdata[4500]; /* maximal MTU of connected links */
+ static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+ static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+
+ /* init ll_allrouters */
+ init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS);
+
+ /* initialize msghdr for receiving packets */
+ rcviov.iov_base = (caddr_t)rprdata;
+ rcviov.iov_len = sizeof(rprdata);
+ rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ rcvmhdr.msg_iov = &rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf;
+ rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf);
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = sizeof(sndcmsgbuf);
+}
+
+void
+config(FILE **fpp)
+{
+ struct payload_list *pl;
+ struct iovec *iov;
+ struct icmp6_router_renum *irr;
+ struct rr_pco_match *rpm;
+
+ if (parse(fpp) < 0) {
+ syslog(LOG_ERR, "<%s> parse failed", __FUNCTION__);
+ exit(1);
+ }
+
+ /* initialize fields not configured by parser */
+ for (pl = pl_head; pl; pl = pl->pl_next) {
+ iov = (struct iovec *)&pl->pl_sndiov;
+ irr = (struct icmp6_router_renum *)&pl->pl_irr;
+ rpm = (struct rr_pco_match *)&pl->pl_rpm;
+
+ irr->rr_type = ICMP6_ROUTER_RENUMBERING;
+ irr->rr_code = 0;
+ /*
+ * now we don't support multiple PCOs in a rr message.
+ * so segment number is not supported.
+ */
+ /* TODO: rr flags config in parser */
+ irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE;
+ /* TODO: max delay config in parser */
+
+ /*
+ * means only 1 use_prefix is contained as router-renum-05.txt.
+ * now we don't support multiple PCOs in a rr message,
+ * nor multiple use_prefix in one PCO.
+ */
+ rpm->rpm_len = 4*1 +3;
+ rpm->rpm_ordinal = 0;
+ iov->iov_base = (caddr_t)irr;
+ iov->iov_len = sizeof(struct icmp6_router_renum)
+ + sizeof(struct rr_pco_match)
+ + sizeof(struct rr_pco_use);
+ }
+}
+
+void
+sock6_open(struct flags *flags
+#ifdef IPSEC_POLICY_IPSEC
+ , char *policy
+#endif /* IPSEC_POLICY_IPSEC */
+ )
+{
+ struct icmp6_filter filt;
+ int on, optval;
+
+ if (with_v6dest == 0)
+ return;
+ if (with_v6dest &&
+ (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ syslog(LOG_ERR, "<%s> socket(v6): %s", __FUNCTION__,
+ strerror(errno));
+ exit(1);
+ }
+
+ /* join all routers multicast addresses, not necessary? */
+
+ /* set icmpv6 filter */
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
+ if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0) {
+ syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
+ __FUNCTION__, strerror(errno));
+ exit(1);
+ }
+
+ /* specify to tell receiving interface */
+ on = 1;
+ if (setsockopt(s6, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0) {
+ syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s",
+ __FUNCTION__, strerror(errno));
+ exit(1);
+ }
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (flags->policy) {
+ char *buf;
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL)
+ errx(1, ipsec_strerror());
+ /* XXX should handle in/out bound policy. */
+ if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(1, NULL);
+ free(buf);
+ }
+#endif /* IPSEC_POLICY_IPSEC */
+#endif /* IPSEC */
+
+ return;
+}
+
+void
+rrenum_output(struct payload_list *pl, struct dst_list *dl)
+{
+ int i, msglen = 0;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi;
+ struct icmp6_router_renum *rr;
+ struct sockaddr_in6 *sin6 = NULL;
+
+ sndmhdr.msg_name = (caddr_t)dl->dl_dst;
+ if (dl->dl_dst->sa_family == AF_INET6)
+ sin6 = (struct sockaddr_in6 *)dl->dl_dst;
+
+ if (sin6 != NULL &&
+ IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
+ int hoplimit = 255;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = sin6->sin6_scope_id;
+ msglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+ /* specify the hop limit of the packet if dest is link local */
+ /* not defined by router-renum-05.txt, but maybe its OK */
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ msglen += CMSG_SPACE(sizeof(int));
+ }
+ sndmhdr.msg_controllen = msglen;
+ if (sndmhdr.msg_controllen == 0)
+ sndmhdr.msg_control = 0;
+
+ sndmhdr.msg_iov = &pl->pl_sndiov;
+ i = sendmsg(s6, &sndmhdr, 0);
+
+ if (i < 0 || i != sndmhdr.msg_iov->iov_len)
+ syslog(LOG_ERR, "<%s> sendmsg: %s", __FUNCTION__,
+ strerror(errno));
+}
+
+void
+rrenum_snd_eachdst(struct payload_list *pl)
+{
+ struct dst_list *dl;
+
+ for (dl = dl_head; dl; dl = dl->dl_next) {
+ rrenum_output(pl, dl);
+ }
+}
+
+void
+rrenum_snd_fullsequence()
+{
+ struct payload_list *pl;
+
+ for (pl = pl_head; pl; pl = pl->pl_next) {
+ rrenum_snd_eachdst(pl);
+ }
+}
+
+void
+rrenum_input(int s)
+{
+ int i;
+ struct icmp6_router_renum *rr;
+
+ /* get message */
+ if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
+ syslog(LOG_ERR, "<%s> recvmsg: %s", __FUNCTION__,
+ strerror(errno));
+ return;
+ }
+ if (i < sizeof(struct icmp6_router_renum)) {
+ syslog(LOG_ERR, "<%s> packet size(%d) is too short",
+ __FUNCTION__, i);
+ return;
+ }
+ rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base;
+
+ switch(rr->rr_code) {
+ case ICMP6_ROUTER_RENUMBERING_COMMAND:
+ /* COMMAND will be processed by rtadvd */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_RESULT:
+ /* TODO: receiving result message */
+ break;
+ default:
+ syslog(LOG_ERR, "<%s> received unknown code %d"
+ __FUNCTION__, rr->rr_code);
+ break;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *cfile = NULL;
+ FILE *fp = stdin;
+ fd_set fdset;
+ struct timeval timeout;
+ int ch, i, maxfd = 0, send_counter = 0;
+ struct flags flags;
+ struct payload_list *pl;
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy = NULL;
+#endif
+
+ memset(&flags, 0, sizeof(flags));
+ openlog(*argv, LOG_PID, LOG_DAEMON);
+
+ /* get options */
+ while ((ch = getopt(argc, argv, "c:sdf"
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ "P:"
+#endif /* IPSEC_POLICY_IPSEC */
+#endif /* IPSEC */
+ )) != -1){
+ switch (ch) {
+ case 'c':
+ if((fp = fopen(optarg, "r")) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> config file %s open failed",
+ __FUNCTION__, optarg);
+ exit(1);
+ }
+ break;
+ case 's':
+ fp = stdin;
+ break;
+ case 'd':
+ flags.debug = 1;
+ break;
+ case 'f':
+ flags.fg = 1;
+ break;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ case 'P':
+ flags.policy = 1;
+ policy = strdup(optarg);
+ break;
+#endif /* IPSEC_POLICY_IPSEC */
+#endif /*IPSEC*/
+ default:
+ show_usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* set log level */
+ if (flags.debug == 0)
+ (void)setlogmask(LOG_UPTO(LOG_ERR));
+ if (flags.debug == 1)
+ (void)setlogmask(LOG_UPTO(LOG_INFO));
+
+ /* init global variables */
+ init_globals();
+
+ config(&fp);
+
+ sock6_open(&flags
+#ifdef IPSEC_POLICY_IPSEC
+ , policy
+#endif /* IPSEC_POLICY_IPSEC */
+ );
+
+ if (!flags.fg)
+ daemon(0, 0);
+
+ FD_ZERO(&fdset);
+ if (with_v6dest) {
+ FD_SET(s6, &fdset);
+ if (s6 > maxfd)
+ maxfd = s6;
+ }
+
+ /* ADHOC: timeout each 30seconds */
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.tv_sec = 30;
+
+ /* init temporal payload_list and send_counter*/
+ pl = pl_head;
+ send_counter = retry + 1;
+ while (1) {
+ struct fd_set select_fd = fdset; /* reinitialize */
+
+ if ((i = select(maxfd + 1, &select_fd, NULL, NULL,
+ &timeout)) < 0){
+ syslog(LOG_ERR, "<%s> select: %s",
+ __FUNCTION__, strerror(errno));
+ continue;
+ }
+ if (i == 0) { /* timeout */
+ if (pl == NULL)
+ exit(0);
+ rrenum_snd_eachdst(pl);
+ send_counter--;
+ if (send_counter == 0) {
+ pl = pl->pl_next;
+ send_counter = retry + 1;
+ }
+ }
+ if (FD_ISSET(s6, &select_fd))
+ rrenum_input(s6);
+ }
+}
diff --git a/usr.sbin/rrenumd/rrenumd.conf.5 b/usr.sbin/rrenumd/rrenumd.conf.5
new file mode 100644
index 0000000..76453cb
--- /dev/null
+++ b/usr.sbin/rrenumd/rrenumd.conf.5
@@ -0,0 +1,330 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: rrenumd.conf.5,v 1.1.1.1 1999/08/08 23:31:39 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd Nov 5, 1998
+.Dt RRENUMD.CONF 5
+.Os KAME
+.Sh NAME
+.\"
+.Nm rrenumd.conf
+.Nd configuration file for router renumbering daemon
+.\"
+.Sh DESCRIPTION
+The rrenumd config file describes how the router renumbering packet
+must be constructed and to which destinations it should be sent.
+This file consists of a sequence of statements terminated by a semi-colon (`;').
+Statements are composed of tokens
+separated by white space, which can be any combination of blanks, tabs
+and newlines.
+This structure simplifies identification of
+the parts of the configuration associated with each other.
+Lines beginning with
+.Ql #
+are comments.
+.\"
+.Sh Meta Syntax
+Keywords and special characters that the parser expects exactly are
+displayed using the
+.Ic bold
+font.
+Parameters are specifying with
+.Ar underline .
+Parameters shown in
+square brackets (`[' and `]') are used to show optional
+keywords and parameters.
+The vertical bar (`|') is used to indicate
+between a choice of optional parameters.
+Parentheses (`(' and
+`)') are used to group keywords and parameters when necessary.
+.\"
+.Sh Interface specification
+There are some statements that may or have to specify interface.
+Interfaces are specified in the form of "name unit", such as
+.Ar lo0
+and
+.Ar ep1.
+.\"
+.Sh Configuration Statements
+.Bl -tag -width Ds
+.\"
+.It Ic debug on|off ;
+Enables configuration file parser debugging.
+If
+.Ic on
+is specified,
+then debugging is enabled,
+If
+.Ic off
+is specified,
+then debugging is disabled. It is disabled by default.
+.\"
+.It Ic dest Ar dest-list Op Ar retrycmd ;
+Specifies destinations to which router renumbering messages should be
+sent.
+.Ar dest-list
+can be any combination of single or multiple numerical IPv6 addrs,
+or Full Qualified Domain Names.
+.Ar retrycmd
+has following syntax.
+
+.\"
+.Bl -tag -width Ds -compact
+.It Ic retry Ar retry-num
+.Ar retry-num
+specifies how many router renumbering messages are sent repeatedly.
+.El
+.It Op Ic add|change|setglobal
+.Cm match-prefix Ar match-prefix-val
+.Op /match-prefix-len
+.Op Cm maxlen Ar maxlen-val
+.Op Cm minlen Ar minlen-val
+.Op Cm use-prefix Ar use-prefix-val
+.Op /use-prefix-len
+.Op Cm keeplen Ar keeplen-val
+.Op Ar use-prefix-values ;
+.Pp
+Specifies contents of sending router renumbering message with seqnum 0.
+If
+.Cm add|change|setglobal
+is not specified, then
+.Cm add
+is assumed.
+.Ar use-prefix-values
+has following syntax.
+.Pp
+{
+.Op Cm vltime Ar vltime-val
+.Op Cm pltime Ar pltime-val
+.Op Cm raf_onlink Cm on|off
+.Op Cm raf_auto Cm on|off
+.Op Cm rrf_decrprefd Cm on|off
+.Op Cm rrf_decrvalid Cm on|off
+}
+.Pp
+Each value has following meaning.
+.Pp
+.Bl -tag -width Ds -compact
+.It Cm match-prefix Ar match-prefix-val Op /match-prefix-len
+Specify
+.Ar match-prefix-val
+that is used for matching with preassigned prefixes to which
+.Cm add|change|setglobal
+command should be applied.
+.Ar /match-prefix-len
+Specify the starting part of
+.Ar match-prefix-val
+to be used for matching with preassigned prefixes, as decimal bit number.
+.It Cm maxlen Ar maxlen-val
+Specify the maximum length of prefixes which is allowed to be
+matched to
+.Ar match-prefix-val ,
+as decimal bit number.
+.It Cm minlen Ar minlen-val
+Specify the minimum length of prefixes which is allowed to be matched to
+.Ar match-prefix-val ,
+as decimal bit number.
+.It Cm use-prefix Ar use-prefix-val Op /usr-prefix-len
+Specify
+.Ar use-prefix-val
+that is used for prefixes to be added on
+.Cm add|change|setglobal
+command.
+.Ar /use-prefix-len
+Specify the starting part of
+.Ar use-prefix-val
+copied to the starting part of prefixes to be added on
+.Cm add|change|setglobal
+command, as decimal bit number.
+.It Cm keeplen Ar keeplen-val
+Specify the midium part of
+.Ar use-prefix-val
+just next to the starting part specified by
+.Ar use-prefix-len
+, as decimal bit number.
+Contiguous bits part in the same bit position of an existent prefix
+matched with
+.Ar match-prefix-val
+is copied to the same bit position of prefixes to be added.
+.It Cm vltime Ar vmtime-val
+Assign an
+.Ar time
+as prefix valid life time for a prefix to be added.
+Valid value for
+.Ar time
+is decimal seconds number or special format as "d00h00m00s00",
+where 00 can take any decimal number, and "d" means days, "h" means hours,
+"m" means minutes, "s" means seconds. And alternatively, special keyword
+"infinity" can be also be specified.
+.It Cm pltime Ar pltime-val
+Assign an
+.Ar time
+as prefix preferred life time for a prefix to be added.
+Valid value for
+.Ar time
+is same as for
+.Ar vltime-val .
+.It Cm raf_onlink Cm on|off
+Let the prefix to be added to have on-link or off-link nature
+for the assigned interface. If
+.Cm on
+is specified, the prefix have on-link nature. (e.g. the prefix
+belong to the link) If
+.Cm off
+is specified, the prefix have off-link nature. (e.g. the
+prefix does not belong to the link)
+.It Cm raf_auto Cm on|off
+Enable or disable the autonomous address auto configuration
+for the prefix to be added. If
+.Cm on
+is specified, autonomous address auto configuration is
+enabled. If
+.Cm off
+is specified, it is disabled.
+.It Cm rrf_decrprefd Cm on|off
+Enable or disable the decrementation of the pltime. If
+.Cm on
+is specified, decrementation of the pltime is enabled. If
+.Cm off
+is specified, decrementation of the pltime is disabled.
+.It Cm rrf_decrvalid Cm on|off
+Enable or disable the decrementation of the vltime. If
+.Cm on
+is specified, decrementation of the vltime is enabled. If
+.Cm off
+is specified, decrementation of the vltime is disabled.
+.El
+.\"
+.It seqnum Ar seqnum-val { Ar rrenum-cmd } ;
+Specifies contents of sending router renumbering message with some
+specific seqnum. Multiple of this statement can be specified if they
+have different
+.Ar seqnum-val
+each other.
+.Ar rrenum-cmd
+has just same syntax with above add|change|setglobal statement.
+.El
+.\"
+.Sh EXAMPLE
+For each configuration file example shown below, we suppose
+every IPv6 subnet has its own prefix beginning with
+fec0:0:0::/48 and with its own subnet number. (in this case,
+subnet number is 7th and 8th octet value of the prefix)
+.Pp
+If you want to assigne prefixes beginning with fec0:1:1::/48
+to each subnet, then following configuration will be enough,
+if each of your routers supports IPv6 multicast forwarding.
+The subnet number of the existing fec0:0:0::/48 prefix and the
+newly assigned fec0:1:1::/48 prefix will be same.
+.\"
+.Bd -literal -offset indent
+dest ff05::2;
+
+add match-prefix fec0:0:0:: /48 use-prefix fec0:1:1:: /48 keeplen 16;
+.Ed
+.\"
+
+If your routers don't support IPv6 multicast forwarding,
+you'll need to specify each destination at
+.Cm dest
+command.
+.\"
+.Bd -literal -offset indent
+dest fec0:0:0:1:260:8ff:fe24:fb3a fec0:0:0:2:200:eff:fe2e:dfe1 fec0:0:0:3:5254:ff:fedc:5217;
+
+add match-prefix fec0:0:0:: /48 use-prefix fec0:1:1:: /48 keeplen 16;
+.Ed
+.\"
+
+If you are going to do renumbering, then following procedure will be natural.
+.Bl -enum -offset indent
+.It
+Assigne new prefix.
+.It
+Set old prefix lifetimes to some appropriate transition
+period. In the followng example we use 1 week for valid
+lifetime, and 0 for preferred lifetime.
+Also, enable old prefix lifetime expiration.
+(By default, it is static and does not expire)
+.It
+After the transition period, old prefixes should become
+invalid, and may have been deleted.
+To make sure that they are deleted, send new router
+renumbering message, which specifies old prefixes as match
+prefix, and no use prefix.
+.El
+.\"
+
+The following configuration file will do 1 and 2.
+.\"
+.Bd -literal -offset indent
+dest ff05::2;
+
+seqnum 0 {
+ add match-prefix fec0:0:0:: /48 use-prefix fec0:2:2:: /48 keeplen 16;
+ };
+
+seqnum 1 {
+ change match-prefix fec0:1:1:: /48 use-prefix fec0:1:1:: /48 keeplen 16 vltime d7 pltime 0 rrf_decrvalid on rrf_decrprefd on;
+ };
+.Ed
+.\"
+
+And the following configuration file will do 3. (should be
+used for the router renumbering message to be sent 1 week
+afterward)
+.\"
+.Bd -literal -offset indent
+dest ff05::2;
+
+change match-prefix fec0:1:1:: /48;
+.Ed
+.\"
+
+In the above example, only
+.Cm add
+and
+.Cm change
+commands are used, and there is no example for
+.Cm setglobal
+command.
+.Cm setglobal
+command is almost same with
+.Cm change
+command except that it deletes all pre-defined IPv6 global address.
+
+.Sh SEE ALSO
+.Xr rrenumd 8
+.Xr prefix 8
+.Sh HISTORY
+The
+.Nm
+configuration file was first appeared in KAME IPv6 protocol stack kit.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/usr.sbin/rrenumd/rrenumd.h b/usr.sbin/rrenumd/rrenumd.h
new file mode 100644
index 0000000..dae2cd0
--- /dev/null
+++ b/usr.sbin/rrenumd/rrenumd.h
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by WIDE Project and
+ * its contributors.
+ * 4. 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.
+ *
+ * $FreeBSD$
+ */
+
+struct dst_list {
+ struct dst_list *dl_next;
+ struct sockaddr *dl_dst;
+};
+
+extern struct dst_list *dl_head;
+
+struct payload_list {
+ struct payload_list *pl_next;
+ struct iovec pl_sndiov;
+ struct icmp6_router_renum pl_irr;
+ struct rr_pco_match pl_rpm;
+ /* currently, support only 1 rr_pco_use field per packet */
+ struct rr_pco_use pl_rpu;
+};
+
+extern struct payload_list *pl_head;
+extern u_int retry;
+extern int with_v4dest, with_v6dest;
+
+#define DEF_VLTIME 2592000
+#define DEF_PLTIME 604800
diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile
new file mode 100644
index 0000000..7b5d2a8
--- /dev/null
+++ b/usr.sbin/rtadvd/Makefile
@@ -0,0 +1,26 @@
+# Copyright (c) 1996 WIDE Project. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modifications, are permitted provided that the above copyright notice
+# and this paragraph are duplicated in all such forms and that any
+# documentation, advertising materials, and other materials related to
+# such distribution and use acknowledge that the software was developed
+# by the WIDE Project, Japan. The name of the Project may not be used to
+# endorse or promote products derived from this software without
+# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS''
+# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE.
+# $FreeBSD$
+
+PROG= rtadvd
+SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c
+
+CFLAGS+=-DINET6 -DIPSEC
+LDADD+= -lcompat -lipsec
+DPADD+= ${LIBCOMPAT} ${LIBIPSEC}
+
+MAN5= rtadvd.conf.5
+MAN8= rtadvd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c
new file mode 100644
index 0000000..f0825b5
--- /dev/null
+++ b/usr.sbin/rtadvd/advcap.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)remcap.c 5.5 (Berkeley) 2/2/91";
+#endif /* not lint */
+
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+#define tgetent agetent
+#define tnchktc anchktc
+#define tnamatch anamatch
+#define tgetnum agetnum
+#define tgetflag agetflag
+#define tgetstr agetstr
+
+char *RM;
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+
+static char *remotefile;
+
+extern char *conffile;
+
+int tgetent __P((char *, char *));
+int getent __P((char *, char *, char *));
+int tnchktc __P((void));
+int tnamatch __P((char *));
+static char *tskip __P((char *));
+int tgetnum __P((char *));
+int tgetflag __P((char *));
+char *tgetstr __P((char *, char **));
+static char *tdecode __P((char *, char **));
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+int
+tgetent(bp, name)
+ char *bp, *name;
+{
+ char *cp;
+
+ remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
+ return (getent(bp, name, cp));
+}
+
+int
+getent(bp, name, cp)
+ char *bp, *name, *cp;
+{
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ tf = open(RM = cp, O_RDONLY);
+ }
+ if (tf < 0) {
+ syslog(LOG_WARNING,
+ "<%s> open: %s", __FUNCTION__, strerror(errno));
+ return (-2);
+ }
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\') {
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFSIZ) {
+ write(2,"Remcap entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return (tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+int
+tnchktc()
+{
+ register char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p<tbuf) {
+ write(2, "Bad remcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return (1);
+ strcpy(tcname, p+3);
+ q = tcname;
+ while (*q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(2, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (getent(tcbuf, tcname, remotefile) != 1) {
+ return (0);
+ }
+ for (q = tcbuf; *q++ != ':'; )
+ ;
+ l = p - holdtbuf + strlen(q);
+ if (l > BUFSIZ) {
+ write(2, "Remcap entry too long\n", 23);
+ q[BUFSIZ - (p-holdtbuf)] = 0;
+ }
+ strcpy(p, q);
+ tbuf = holdtbuf;
+ return (1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+int
+tnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return (0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ register char *bp;
+{
+ int dquote;
+
+ dquote = 0;
+ while (*bp) {
+ switch (*bp) {
+ case ':':
+ if (!dquote)
+ goto breakbreak;
+ else
+ bp++;
+ break;
+ case '\\':
+ bp++;
+ if (isdigit(*bp)) {
+ while (isdigit(*bp++))
+ ;
+ } else
+ bp++;
+ case '"':
+ dquote = (dquote ? 1 : 0);
+ bp++;
+ break;
+ default:
+ bp++;
+ break;
+ }
+ }
+breakbreak:
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+int
+tgetnum(id)
+ char *id;
+{
+ register long int i;
+ register int base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (strncmp(bp, id, strlen(id)) != 0)
+ continue;
+ bp += strlen(id);
+ if (*bp == '@')
+ return (-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+int
+tgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (strncmp(bp, id, strlen(id)) == 0) {
+ bp += strlen(id);
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return (0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (strncmp(bp, id, strlen(id)) != 0)
+ continue;
+ bp += strlen(id);
+ if (*bp == '@')
+ return (0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+ char term;
+
+ term = ':';
+ cp = *area;
+again:
+ if (*str == '"') {
+ term = '"';
+ str++;
+ }
+ while ((c = *str++) && c != term) {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\"";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ if (c == term && term != ':') {
+ term = ':';
+ goto again;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
diff --git a/usr.sbin/rtadvd/advcap.h b/usr.sbin/rtadvd/advcap.h
new file mode 100644
index 0000000..9c4520b
--- /dev/null
+++ b/usr.sbin/rtadvd/advcap.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia.
+ * 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 AUTHOR ``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 AUTHOR 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$
+ */
+
+/* Based on Id: termcap.h,v 1.8 1996/09/10 12:42:10 peter Exp */
+
+#ifndef _ADVCAP_H_
+#define _ADVCAP_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int agetent __P((char *, const char *));
+extern int agetflag __P((const char *));
+extern int agetnum __P((const char *));
+extern char *agetstr __P((const char *, char **));
+
+__END_DECLS
+
+#endif /* _ADVCAP_H_ */
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
new file mode 100644
index 0000000..3055161
--- /dev/null
+++ b/usr.sbin/rtadvd/config.c
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet6/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "rtadvd.h"
+#include "advcap.h"
+#include "timer.h"
+#include "if.h"
+#include "config.h"
+
+static void makeentry __P((char *, int, char *, int));
+static void make_packet __P((struct rainfo *));
+static void get_prefix __P((struct rainfo *));
+
+extern struct rainfo *ralist;
+
+void
+getconfig(intface)
+ char *intface;
+{
+ int stat, pfxs, i;
+ char tbuf[BUFSIZ];
+ struct rainfo *tmp;
+ long val;
+ char buf[BUFSIZ];
+ char *bp = buf;
+ char *addr;
+
+#define MUSTHAVE(var, cap) \
+ { \
+ int t; \
+ if ((t = agetnum(cap)) < 0) { \
+ fprintf(stderr, "rtadvd: need %s for interface %s\n", \
+ cap, intface); \
+ exit(1); \
+ } \
+ var = t; \
+ }
+#define MAYHAVE(var, cap, def) \
+ { \
+ if ((var = agetnum(cap)) < 0) \
+ var = def; \
+ }
+
+ if ((stat = agetent(tbuf, intface)) <= 0) {
+ memset(tbuf, 0, sizeof(tbuf));
+ syslog(LOG_INFO,
+ "<%s> %s isn't defined in the configuration file"
+ " or the configuration file doesn't exist."
+ " Treat it as default",
+ __FUNCTION__, intface);
+ }
+
+ tmp = (struct rainfo *)malloc(sizeof(*ralist));
+ memset(tmp, 0, sizeof(*tmp));
+ tmp->prefix.next = tmp->prefix.prev = &tmp->prefix;
+
+ /* get interface information */
+ if (agetflag("nolladdr"))
+ tmp->advlinkopt = 0;
+ else
+ tmp->advlinkopt = 1;
+ if (tmp->advlinkopt) {
+ if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't get information of %s",
+ __FUNCTION__, intface);
+ exit(1);
+ }
+ tmp->ifindex = tmp->sdl->sdl_index;
+ } else
+ tmp->ifindex = if_nametoindex(intface);
+ strncpy(tmp->ifname, intface, sizeof(tmp->ifname));
+ if ((tmp->phymtu = if_getmtu(intface)) == 0) {
+ tmp->phymtu = IPV6_MMTU;
+ syslog(LOG_WARNING,
+ "<%s> can't get interface mtu of %s. Treat as %d",
+ __FUNCTION__, intface, IPV6_MMTU);
+ }
+
+ /*
+ * set router configuration variables.
+ */
+ MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
+ if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
+ syslog(LOG_ERR,
+ "<%s> maxinterval must be between %d and %d",
+ __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
+ exit(1);
+ }
+ tmp->maxinterval = (u_int)val;
+ MAYHAVE(val, "mininterval", tmp->maxinterval/3);
+ if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
+ syslog(LOG_ERR,
+ "<%s> mininterval must be between %d and %d",
+ __FUNCTION__,
+ MIN_MININTERVAL,
+ (tmp->maxinterval * 3) / 4);
+ exit(1);
+ }
+ tmp->mininterval = (u_int)val;
+
+ MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
+ tmp->hoplimit = val & 0xff;
+
+ MAYHAVE(val, "raflags", 0);
+ tmp->managedflg= val & ND_RA_FLAG_MANAGED;
+ tmp->otherflg = val & ND_RA_FLAG_OTHER;
+
+ MAYHAVE(val, "rltime", tmp->maxinterval * 3);
+ if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
+ syslog(LOG_ERR,
+ "<%s> router lifetime on %s must be 0 or"
+ " between %d and %d",
+ __FUNCTION__, intface,
+ tmp->maxinterval, MAXROUTERLIFETIME);
+ exit(1);
+ }
+ tmp->lifetime = val & 0xffff;
+
+ MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
+ if (val > MAXREACHABLETIME) {
+ syslog(LOG_ERR,
+ "<%s> reachable time must be no greater than %d",
+ __FUNCTION__, MAXREACHABLETIME);
+ exit(1);
+ }
+ tmp->reachabletime = (u_int32_t)val;
+
+ MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER);
+ if (val < 0 || val > 0xffffffff) {
+ syslog(LOG_ERR,
+ "<%s> retrans time out of range", __FUNCTION__);
+ exit(1);
+ }
+ tmp->retranstimer = (u_int32_t)val;
+
+ /* prefix information */
+ if ((pfxs = agetnum("addrs")) < 0) {
+ /* auto configure prefix information */
+ if (agetstr("addr", &bp) || agetstr("addr1", &bp)) {
+ syslog(LOG_ERR,
+ "<%s> conflicting prefix configuration for %s: "
+ "automatic and manual config at the same time",
+ __FUNCTION__, intface);
+ exit(1);
+ }
+ get_prefix(tmp);
+ }
+ else {
+ tmp->pfxs = pfxs;
+ for (i = 0; i < pfxs; i++) {
+ struct prefix *pfx;
+ char entbuf[256];
+ int added = (pfxs > 1) ? 1 : 0;
+
+ /* allocate memory to store prefix information */
+ if ((pfx = malloc(sizeof(struct prefix))) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't allocate enough memory",
+ __FUNCTION__);
+ exit(1);
+ }
+ /* link into chain */
+ insque(pfx, &tmp->prefix);
+
+ makeentry(entbuf, i, "prefixlen", added);
+ MAYHAVE(val, entbuf, 64);
+ if (val < 0 || val > 128) {
+ syslog(LOG_ERR,
+ "<%s> prefixlen out of range",
+ __FUNCTION__);
+ exit(1);
+ }
+ pfx->prefixlen = (int)val;
+
+ makeentry(entbuf, i, "pinfoflags", added);
+ MAYHAVE(val, entbuf,
+ (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
+ pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
+ pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
+
+ makeentry(entbuf, i, "vltime", added);
+ MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME);
+ if (val < 0 || val > 0xffffffff) {
+ syslog(LOG_ERR,
+ "<%s> vltime out of range",
+ __FUNCTION__);
+ exit(1);
+ }
+ pfx->validlifetime = (u_int32_t)val;
+
+ makeentry(entbuf, i, "pltime", added);
+ MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME);
+ if (val < 0 || val > 0xffffffff) {
+ syslog(LOG_ERR,
+ "<%s> pltime out of range",
+ __FUNCTION__);
+ exit(1);
+ }
+ pfx->preflifetime = (u_int32_t)val;
+
+ makeentry(entbuf, i, "addr", added);
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL) {
+ syslog(LOG_ERR,
+ "<%s> need %s as an prefix for "
+ "interface %s",
+ __FUNCTION__, entbuf, intface);
+ exit(1);
+ }
+ if (inet_pton(AF_INET6, addr,
+ &pfx->prefix) != 1) {
+ syslog(LOG_ERR,
+ "<%s> inet_pton failed for %s",
+ __FUNCTION__, addr);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
+ syslog(LOG_ERR,
+ "<%s> multicast prefix(%s) must "
+ "not be advertised (IF=%s)",
+ __FUNCTION__, addr, intface);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
+ syslog(LOG_NOTICE,
+ "<%s> link-local prefix(%s) will be"
+ " advertised on %s",
+ __FUNCTION__, addr, intface);
+ }
+ }
+
+ MAYHAVE(val, "mtu", 0);
+ if (val < 0 || val > 0xffffffff) {
+ syslog(LOG_ERR,
+ "<%s> mtu out of range", __FUNCTION__);
+ exit(1);
+ }
+ tmp->linkmtu = (u_int32_t)val;
+ if (tmp->linkmtu == 0) {
+ char *mtustr;
+
+ if ((mtustr = (char *)agetstr("mtu", &bp)) &&
+ strcmp(mtustr, "auto") == 0)
+ tmp->linkmtu = tmp->phymtu;
+ }
+ else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
+ syslog(LOG_ERR,
+ "<%s> advertised link mtu must be between"
+ " least MTU and physical link MTU",
+ __FUNCTION__);
+ exit(1);
+ }
+
+ /* okey */
+ tmp->next = ralist;
+ ralist = tmp;
+
+ /* construct the sending packet */
+ make_packet(tmp);
+
+ /* set timer */
+ tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
+ tmp, tmp);
+ ra_timer_update((void *)tmp, &tmp->timer->tm);
+ rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
+}
+
+static void
+get_prefix(struct rainfo *rai)
+{
+ size_t len;
+ u_char *buf, *lim, *next;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ if ((len = rtbuf_len()) < 0) {
+ syslog(LOG_ERR,
+ "<%s> can't get buffer length for routing info",
+ __FUNCTION__);
+ exit(1);
+ }
+ if ((buf = malloc(len)) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't allocate buffer", __FUNCTION__);
+ exit(1);
+ }
+ if (get_rtinfo(buf, &len) < 0) {
+ syslog(LOG_ERR,
+ "<%s> can't get routing inforamtion", __FUNCTION__);
+ exit(1);
+ }
+
+ lim = buf + len;
+ next = get_next_msg(buf, lim, rai->ifindex, &len,
+ RTADV_TYPE2BITMASK(RTM_GET));
+ while (next < lim) {
+ struct prefix *pp;
+ struct in6_addr *a;
+
+ /* allocate memory to store prefix info. */
+ if ((pp = malloc(sizeof(*pp))) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't get allocate buffer for prefix",
+ __FUNCTION__);
+ exit(1);
+ }
+ memset(pp, 0, sizeof(*pp));
+
+ /* set prefix and its length */
+ a = get_addr(next);
+ memcpy(&pp->prefix, a, sizeof(*a));
+ if ((pp->prefixlen = get_prefixlen(next)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> failed to get prefixlen "
+ "or prefixl is invalid",
+ __FUNCTION__);
+ exit(1);
+ }
+ syslog(LOG_DEBUG,
+ "<%s> add %s/%d to prefix list on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN),
+ pp->prefixlen, rai->ifname);
+
+ /* set other fields with protocol defaults */
+ pp->validlifetime = DEF_ADVVALIDLIFETIME;
+ pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
+ pp->onlinkflg = 1;
+ pp->autoconfflg = 1;
+
+ /* link into chain */
+ insque(pp, &rai->prefix);
+
+ /* counter increment */
+ rai->pfxs++;
+
+ /* forward pointer and get next prefix(if any) */
+ next += len;
+ next = get_next_msg(next, lim, rai->ifindex,
+ &len, RTADV_TYPE2BITMASK(RTM_GET));
+ }
+
+ free(buf);
+}
+
+static void
+makeentry(buf, id, string, add)
+ char *buf, *string;
+ int id, add;
+{
+ strcpy(buf, string);
+ if (add) {
+ char *cp;
+
+ cp = (char *)index(buf, '\0');
+ cp += sprintf(cp, "%d", id);
+ *cp = '\0';
+ }
+}
+
+/*
+ * Add a prefix to the list of specified interface and reconstruct
+ * the outgoing packet.
+ * The prefix must not be in the list.
+ * XXX: other parameter of the prefix(e.g. lifetime) shoule be
+ * able to be specified.
+ */
+static void
+add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
+{
+ struct prefix *prefix;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ if ((prefix = malloc(sizeof(*prefix))) == NULL) {
+ syslog(LOG_ERR, "<%s> memory allocation failed",
+ __FUNCTION__);
+ return; /* XXX: error or exit? */
+ }
+ prefix->prefix = ipr->ipr_prefix.sin6_addr;
+ prefix->prefixlen = ipr->ipr_plen;
+ prefix->validlifetime = ipr->ipr_vltime;
+ prefix->preflifetime = ipr->ipr_pltime;
+ prefix->onlinkflg = ipr->ipr_raf_onlink;
+ prefix->autoconfflg = ipr->ipr_raf_auto;
+
+ insque(prefix, &rai->prefix);
+
+ syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
+ __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ ipr->ipr_plen, rai->ifname);
+
+ /* free the previous packet */
+ free(rai->ra_data);
+ rai->ra_data = 0;
+
+ /* reconstruct the packet */
+ rai->pfxs++;
+ make_packet(rai);
+
+ /*
+ * reset the timer so that the new prefix will be advertised quickly.
+ */
+ rai->initcounter = 0;
+ ra_timer_update((void *)rai, &rai->timer->tm);
+ rtadvd_set_timer(&rai->timer->tm, rai->timer);
+}
+
+/*
+ * Delete a prefix to the list of specified interface and reconstruct
+ * the outgoing packet.
+ * The prefix must be in the list
+ */
+void
+delete_prefix(struct rainfo *rai, struct prefix *prefix)
+{
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ remque(prefix);
+ syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
+ __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix,
+ ntopbuf, INET6_ADDRSTRLEN),
+ prefix->prefixlen, rai->ifname);
+ free(prefix);
+ rai->pfxs--;
+ make_packet(rai);
+}
+
+/*
+ * Try to get an in6_prefixreq contents for a prefix which matches
+ * ipr->ipr_prefix and ipr->ipr_plen and belongs to
+ * the interface whose name is ipr->ipr_name[].
+ */
+static int
+init_prefix(struct in6_prefixreq *ipr)
+{
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
+ strerror(errno));
+ exit(1);
+ }
+
+ if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
+ syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__,
+ strerror(errno));
+
+ ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
+ ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
+ ipr->ipr_raf_onlink = 1;
+ ipr->ipr_raf_auto = 1;
+ /* omit other field initialization */
+ }
+ else if (ipr->ipr_origin < PR_ORIG_RR) {
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
+ "lower than PR_ORIG_RR(router renumbering)."
+ "This should not happen if I am router", __FUNCTION__,
+ inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), ipr->ipr_origin);
+ return 1;
+ }
+
+ close(s);
+ return 0;
+}
+
+void
+make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
+{
+ struct in6_prefixreq ipr;
+
+ memset(&ipr, 0, sizeof(ipr));
+ if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
+ syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
+ "exist. This should not happen! %s", __FUNCTION__,
+ ifindex, strerror(errno));
+ exit(1);
+ }
+ ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
+ ipr.ipr_prefix.sin6_family = AF_INET6;
+ ipr.ipr_prefix.sin6_addr = *addr;
+ ipr.ipr_plen = plen;
+
+ if (init_prefix(&ipr))
+ return; /* init failed by some error */
+ add_prefix(rai, &ipr);
+}
+
+static void
+make_packet(struct rainfo *rainfo)
+{
+ size_t packlen, lladdroptlen = 0;
+ char *buf;
+ struct nd_router_advert *ra;
+ struct nd_opt_prefix_info *ndopt_pi;
+ struct nd_opt_mtu *ndopt_mtu;
+ struct prefix *pfx;
+
+ /* calculate total length */
+ packlen = sizeof(struct nd_router_advert);
+ if (rainfo->advlinkopt) {
+ if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
+ syslog(LOG_INFO,
+ "<%s> link-layer address option has"
+ " null length on %s."
+ " Treat as not included.",
+ __FUNCTION__, rainfo->ifname);
+ rainfo->advlinkopt = 0;
+ }
+ packlen += lladdroptlen;
+ }
+ if (rainfo->pfxs)
+ packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
+ if (rainfo->linkmtu)
+ packlen += sizeof(struct nd_opt_mtu);
+
+ /* allocate memory for the packet */
+ if ((buf = malloc(packlen)) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't get enough memory for an RA packet",
+ __FUNCTION__);
+ exit(1);
+ }
+ rainfo->ra_data = buf;
+ /* XXX: what if packlen > 576? */
+ rainfo->ra_datalen = packlen;
+
+ /*
+ * construct the packet
+ */
+ ra = (struct nd_router_advert *)buf;
+ ra->nd_ra_type = ND_ROUTER_ADVERT;
+ ra->nd_ra_code = 0;
+ ra->nd_ra_cksum = 0;
+ ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
+ ra->nd_ra_flags_reserved = 0;
+ ra->nd_ra_flags_reserved |=
+ rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
+ ra->nd_ra_flags_reserved |=
+ rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
+ ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
+ ra->nd_ra_reachable = htonl(rainfo->reachabletime);
+ ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
+ buf += sizeof(*ra);
+
+ if (rainfo->advlinkopt) {
+ lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
+ buf += lladdroptlen;
+ }
+
+ if (rainfo->linkmtu) {
+ ndopt_mtu = (struct nd_opt_mtu *)buf;
+ ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
+ ndopt_mtu->nd_opt_mtu_len = 1;
+ ndopt_mtu->nd_opt_mtu_reserved = 0;
+ ndopt_mtu->nd_opt_mtu_mtu = ntohl(rainfo->linkmtu);
+ buf += sizeof(struct nd_opt_mtu);
+ }
+
+ for (pfx = rainfo->prefix.next;
+ pfx != &rainfo->prefix; pfx = pfx->next) {
+ ndopt_pi = (struct nd_opt_prefix_info *)buf;
+ ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+ ndopt_pi->nd_opt_pi_len = 4;
+ ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
+ ndopt_pi->nd_opt_pi_flags_reserved = 0;
+ if (pfx->onlinkflg)
+ ndopt_pi->nd_opt_pi_flags_reserved |=
+ ND_OPT_PI_FLAG_ONLINK;
+ if (pfx->autoconfflg)
+ ndopt_pi->nd_opt_pi_flags_reserved |=
+ ND_OPT_PI_FLAG_AUTO;
+ ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime);
+ ndopt_pi->nd_opt_pi_preferred_time =
+ ntohl(pfx->preflifetime);
+ ndopt_pi->nd_opt_pi_reserved2 = 0;
+ ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
+
+ buf += sizeof(struct nd_opt_prefix_info);
+ }
+
+ return;
+}
diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h
new file mode 100644
index 0000000..f8729d4
--- /dev/null
+++ b/usr.sbin/rtadvd/config.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+extern void getconfig __P((char *));
+extern void delete_prefix __P((struct rainfo *, struct prefix *));
+extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int));
diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c
new file mode 100644
index 0000000..98aefee
--- /dev/null
+++ b/usr.sbin/rtadvd/if.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "rtadvd.h"
+#include "if.h"
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
+ sizeof(u_long)) :\
+ sizeof(u_long)))
+
+struct if_msghdr **iflist;
+int iflist_init_ok;
+size_t ifblock_size;
+char *ifblock;
+
+static void get_iflist __P((char **buf, size_t *size));
+static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf,
+ size_t bufsize));
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ NEXT_SA(sa);
+ }
+ else
+ rti_info[i] = NULL;
+ }
+}
+
+struct sockaddr_dl *
+if_nametosdl(char *name)
+{
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
+ char *buf, *next, *lim;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ struct sockaddr_dl *sdl = NULL, *ret_sdl;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(NULL);
+ if ((buf = malloc(len)) == NULL)
+ return(NULL);
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return(NULL);
+ }
+
+ lim = buf + len;
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sa = (struct sockaddr *)(ifm + 1);
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
+ if ((sa = rti_info[RTAX_IFP]) != NULL) {
+ if (sa->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)sa;
+ if (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)
+ return(NULL);
+ memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
+ return(ret_sdl);
+}
+
+int
+if_getmtu(char *name)
+{
+ 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);
+
+ return(ifr.ifr_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", __FUNCTION__,
+ 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",
+ __FUNCTION__, ifr.ifr_name);
+ close(s);
+ return (oifflags & ~IFF_UP);
+ }
+ return (ifr.ifr_flags);
+}
+
+#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
+int
+lladdropt_length(struct sockaddr_dl *sdl)
+{
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+ return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ default:
+ return(0);
+ }
+}
+
+void
+lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
+{
+ char *addr;
+
+ ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
+
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+ ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
+ addr = (char *)(ndopt + 1);
+ memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ default:
+ syslog(LOG_ERR,
+ "<%s> unsupported link type(%d)",
+ __FUNCTION__, sdl->sdl_type);
+ exit(1);
+ }
+
+ return;
+}
+
+int
+rtbuf_len()
+{
+ size_t len;
+
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(-1);
+
+ return(len);
+}
+
+int
+get_rtinfo(char *buf, size_t *len)
+{
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
+
+ if (sysctl(mib, 6, buf, len, NULL, 0) < 0)
+ return(-1);
+
+ return(0);
+}
+
+#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
+#define SIN6(s) ((struct sockaddr_in6 *)(s))
+#define SDL(s) ((struct sockaddr_dl *)(s))
+char *
+get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
+{
+ struct rt_msghdr *rtm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
+
+ *lenp = 0;
+ for (rtm = (struct rt_msghdr *)buf;
+ rtm < (struct rt_msghdr *)lim;
+ rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
+ /* just for safety */
+ if (!rtm->rtm_msglen) {
+ syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
+ "(buf=%p lim=%p rtm=%p)", __FUNCTION__,
+ buf, lim, rtm);
+ break;
+ }
+ if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
+ continue;
+ }
+
+ switch (rtm->rtm_type) {
+ case RTM_GET:
+ case RTM_ADD:
+ case RTM_DELETE:
+ /* address related checks */
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ if ((dst = rti_info[RTAX_DST]) == NULL ||
+ dst->sa_family != AF_INET6)
+ continue;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
+ continue;
+
+ if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
+ gw->sa_family != AF_LINK)
+ continue;
+ if (ifindex && SDL(gw)->sdl_index != ifindex)
+ continue;
+
+ if (rti_info[RTAX_NETMASK] == NULL)
+ continue;
+
+ /* found */
+ *lenp = rtm->rtm_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+
+ /* address related checks */
+ sa = (struct sockaddr *)(ifam + 1);
+ get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
+ if ((ifa = rti_info[RTAX_IFA]) == NULL ||
+ (ifa->sa_family != AF_INET &&
+ ifa->sa_family != AF_INET6))
+ continue;
+
+ if (ifa->sa_family == AF_INET6 &&
+ (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
+ continue;
+
+ if (ifindex && ifam->ifam_index != ifindex)
+ continue;
+
+ /* found */
+ *lenp = ifam->ifam_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ case RTM_IFINFO:
+ /* found */
+ *lenp = rtm->rtm_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ }
+ }
+
+ return (char *)rtm;
+}
+#undef FILTER_MATCH(type, filter)
+
+struct in6_addr *
+get_addr(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+ return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
+}
+
+int
+get_rtm_ifindex(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+ 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
+get_prefixlen(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ int masklen;
+ u_char *p, *lim;
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ sa = rti_info[RTAX_NETMASK];
+
+ p = (u_char *)(&SIN6(sa)->sin6_addr);
+ lim = (u_char *)sa + sa->sa_len;
+ for (masklen = 0; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ return(-1);
+ }
+ }
+
+ return(masklen);
+}
+
+int
+rtmsg_type(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+
+ return(rtm->rtm_type);
+}
+
+int
+rtmsg_len(char *buf)
+{
+ 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",
+ __FUNCTION__);
+ exit(1);
+ }
+ if ((*buf = malloc(*size)) == NULL) {
+ syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__);
+ exit(1);
+ }
+ if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
+ syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
+ __FUNCTION__);
+ 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", __FUNCTION__);
+ 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)", __FUNCTION__,
+ buf, lim, ifm);
+ return;
+ }
+
+ if (ifm->ifm_type == RTM_IFINFO) {
+ (*ifmlist_p)[ifm->ifm_index] = ifm;
+ } else {
+ syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
+ "expected %d, got %d\n msglen = %d\n"
+ "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)", __FUNCTION__,
+ buf, lim, ifam);
+ return;
+ }
+ if (ifam->ifam_type != RTM_NEWADDR)
+ break;
+ }
+ ifm = (struct if_msghdr *)ifam;
+ }
+}
+
+void
+init_iflist()
+{
+ if (ifblock) {
+ free(ifblock);
+ ifblock_size = 0;
+ }
+ if (iflist)
+ free(iflist);
+ /* get iflist block from kernel */
+ get_iflist(&ifblock, &ifblock_size);
+
+ /* make list of pointers to each if_msghdr */
+ parse_iflist(&iflist, ifblock, ifblock_size);
+
+}
diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h
new file mode 100644
index 0000000..e8e14d4
--- /dev/null
+++ b/usr.sbin/rtadvd/if.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define RTADV_TYPE2BITMASK(type) (0x1 << type)
+
+extern struct if_msghdr **iflist;
+extern size_t ifblock_size;
+extern char *ifblock;
+
+struct sockaddr_dl *if_nametosdl __P((char *name));
+int if_getmtu __P((char *name));
+int if_getflags __P((int ifindex, int oifflags));
+int lladdropt_length __P((struct sockaddr_dl *sdl));
+void lladdropt_fill __P((struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt));
+int rtbuf_len __P((void));
+int get_rtinfo __P((char *buf, size_t *len));
+char *get_next_msg __P((char *buf, char *lim, int ifindex, size_t *lenp,
+ int filter));
+struct in6_addr *get_addr __P((char *buf));
+int get_rtm_ifindex __P((char *buf));
+int get_ifm_ifindex __P((char *buf));
+int get_ifam_ifindex __P((char *buf));
+int get_ifm_flags __P((char *buf));
+int get_prefixlen __P((char *buf));
+int rtmsg_type __P((char *buf));
+int ifmsg_type __P((char *buf));
+int rtmsg_len __P((char *buf));
+int ifmsg_len __P((char *buf));
+void init_iflist __P((void));
diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h
new file mode 100644
index 0000000..70d9021
--- /dev/null
+++ b/usr.sbin/rtadvd/pathnames.h
@@ -0,0 +1,2 @@
+/* $FreeBSD$ */
+#define _PATH_RTADVDCONF "/usr/local/v6/etc/rtadvd.conf"
diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c
new file mode 100644
index 0000000..ec69ff2
--- /dev/null
+++ b/usr.sbin/rtadvd/rrenum.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include "rrenum.h"
+#include "if.h"
+
+#define RR_ISSET_SEGNUM(segnum_bits, segnum) \
+ ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0)
+#define RR_SET_SEGNUM(segnum_bits, segnum) \
+ (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31)))
+
+struct rr_operation {
+ u_long rro_seqnum;
+ u_long rro_segnum_bits[8];
+};
+
+static struct rr_operation rro;
+static int rr_rcvifindex;
+static int rrcmd2pco[4] = {0,
+ SIOCAIFPREFIX_IN6,
+ SIOCCIFPREFIX_IN6,
+ SIOCSGIFPREFIX_IN6
+};
+static int s;
+
+/*
+ * Check validity of a Prefix Control Operation(PCO).
+ * Return 0 on success, 1 on failure.
+ */
+static int
+rr_pco_check(int len, struct rr_pco_match *rpm)
+{
+ struct rr_pco_use *rpu, *rpulim;
+ int checklen;
+
+ /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */
+ if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */
+ (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */
+ syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3",
+ __FUNCTION__, rpm->rpm_len);
+ return 1;
+ }
+ /* rpm->rpm_code must be valid value */
+ switch(rpm->rpm_code) {
+ case RPM_PCO_ADD:
+ case RPM_PCO_CHANGE:
+ case RPM_PCO_SETGLOBAL:
+ break;
+ default:
+ syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __FUNCTION__,
+ rpm->rpm_code);
+ return 1;
+ }
+ /* rpm->rpm_matchlen must be 0 to 128 inclusive */
+ if (rpm->rpm_matchlen > 128) {
+ syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128",
+ __FUNCTION__, rpm->rpm_matchlen);
+ return 1;
+ }
+
+ /*
+ * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be
+ * between 0 and 128 inclusive
+ */
+ for (rpu = (struct rr_pco_use *)(rpm + 1),
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+ rpu < rpulim;
+ rpu += 1) {
+ checklen = rpu->rpu_uselen;
+ checklen += rpu->rpu_keeplen;
+ /*
+ * omit these check, because either of rpu_uselen
+ * and rpu_keeplen is unsigned char
+ * (128 > rpu_uselen > 0)
+ * (128 > rpu_keeplen > 0)
+ * (rpu_uselen + rpu_keeplen > 0)
+ */
+ if (checklen > 128) {
+ syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and"
+ " rpu_keeplen %d is %d(over 128)",
+ __FUNCTION__, rpu->rpu_uselen,
+ rpu->rpu_keeplen,
+ rpu->rpu_uselen + rpu->rpu_keeplen);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) {
+ struct rr_pco_use *rpu, *rpulim;
+
+ rpu = (struct rr_pco_use *)(rpm + 1);
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+
+ if (rpu == rpulim) {
+ if (rpm->rpm_code == RPM_PCO_ADD)
+ return;
+
+ irr->irr_u_uselen = 0;
+ irr->irr_u_keeplen = 0;
+ irr->irr_raf_mask_onlink = 0;
+ irr->irr_raf_mask_auto = 0;
+ irr->irr_vltime = 0;
+ irr->irr_pltime = 0;
+ memset(&irr->irr_flags, 0, sizeof(irr->irr_flags));
+ irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */
+ irr->irr_useprefix.sin6_family = 0;
+ irr->irr_useprefix.sin6_addr = in6addr_any;
+ if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
+ errno != EADDRNOTAVAIL)
+ syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__,
+ strerror(errno));
+ return;
+ }
+
+ for (rpu = (struct rr_pco_use *)(rpm + 1),
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+ rpu < rpulim;
+ rpu += 1) {
+ /* init in6_rrenumreq fields */
+ irr->irr_u_uselen = rpu->rpu_uselen;
+ irr->irr_u_keeplen = rpu->rpu_keeplen;
+ irr->irr_raf_mask_onlink =
+ (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
+ irr->irr_raf_mask_auto =
+ (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
+ irr->irr_vltime = rpu->rpu_vltime;
+ irr->irr_pltime = rpu->rpu_pltime;
+ irr->irr_raf_onlink =
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
+ irr->irr_raf_auto =
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
+ irr->irr_rrf_decrvalid =
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME);
+ irr->irr_rrf_decrprefd =
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME);
+ irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix);
+ irr->irr_useprefix.sin6_family = AF_INET6;
+ irr->irr_useprefix.sin6_addr = rpu->rpu_prefix;
+
+ if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
+ errno != EADDRNOTAVAIL)
+ syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__,
+ strerror(errno));
+ }
+}
+
+/*
+ * process a Prefix Control Operation(PCO).
+ * return 0 on success, 1 on failure
+ */
+static int
+do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
+{
+ int ifindex = 0;
+ struct in6_rrenumreq irr;
+
+ if ((rr_pco_check(len, rpm) != NULL))
+ return 1;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
+ strerror(errno));
+ exit(1);
+ }
+
+ memset(&irr, 0, sizeof(irr));
+ irr.irr_origin = PR_ORIG_RR;
+ irr.irr_m_len = rpm->rpm_matchlen;
+ irr.irr_m_minlen = rpm->rpm_minlen;
+ irr.irr_m_maxlen = rpm->rpm_maxlen;
+ irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix);
+ irr.irr_matchprefix.sin6_family = AF_INET6;
+ irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
+
+ while (if_indextoname(++ifindex, irr.irr_name)) {
+ /*
+ * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
+ * the interface is not applied
+ */
+ if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
+ (iflist[ifindex]->ifm_flags & IFF_UP) == 0)
+ continue;
+ /* TODO: interface scope check */
+ do_use_prefix(len, rpm, &irr);
+ }
+ if (errno == ENXIO)
+ return 0;
+ else if (errno) {
+ syslog(LOG_ERR, "<%s> if_indextoname: %s", __FUNCTION__,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * call do_pco() for each Prefix Control Operations(PCOs) in a received
+ * Router Renumbering Command packet.
+ * return 0 on success, 1 on failure
+ */
+static int
+do_rr(int len, struct icmp6_router_renum *rr)
+{
+ struct rr_pco_match *rpm;
+ char *cp, *lim;
+
+ lim = (char *)rr + len;
+ cp = (char *)(rr + 1);
+ len -= sizeof(struct icmp6_router_renum);
+
+ /* get iflist block from kernel again, to get up-to-date information */
+ init_iflist();
+
+ while (cp < lim) {
+ int rpmlen;
+
+ rpm = (struct rr_pco_match *)cp;
+ if (len < sizeof(struct rr_pco_match)) {
+ tooshort:
+ syslog(LOG_ERR, "<%s> pkt too short. left len = %d. "
+ "gabage at end of pkt?", __FUNCTION__, len);
+ return 1;
+ }
+ rpmlen = rpm->rpm_len << 3;
+ if (len < rpmlen)
+ goto tooshort;
+
+ if (do_pco(rr, rpmlen, rpm)) {
+ syslog(LOG_WARNING, "<%s> invalid PCO", __FUNCTION__);
+ goto next;
+ }
+
+ next:
+ cp += rpmlen;
+ len -= rpmlen;
+ }
+
+ return 0;
+}
+
+/*
+ * check validity of a router renumbering command packet
+ * return 0 on success, 1 on failure
+ */
+static int
+rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
+ struct in6_addr *dst)
+{
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ /* omit rr minimal length check. hope kernel have done it. */
+ /* rr_command length check */
+ if (len < (sizeof(struct icmp6_router_renum) +
+ sizeof(struct rr_pco_match))) {
+ syslog(LOG_ERR, "<%s> rr_command len %d is too short",
+ __FUNCTION__, len);
+ return 1;
+ }
+
+ /* destination check. only for multicast. omit unicast check. */
+ if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) &&
+ !IN6_IS_ADDR_MC_SITELOCAL(dst)) {
+ syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN));
+ return 1;
+ }
+
+ /* seqnum and segnum check */
+ if (rro.rro_seqnum > rr->rr_seqnum) {
+ syslog(LOG_WARNING,
+ "<%s> rcvd old seqnum %d from %s",
+ __FUNCTION__, (u_int32_t)ntohl(rr->rr_seqnum),
+ inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN));
+ return 1;
+ }
+ if (rro.rro_seqnum == rr->rr_seqnum &&
+ (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 &&
+ RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) {
+ if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0)
+ syslog(LOG_WARNING,
+ "<%s> rcvd duped segnum %d from %s",
+ __FUNCTION__, rr->rr_segnum,
+ inet_ntop(AF_INET6, from, ntopbuf,
+ INET6_ADDRSTRLEN));
+ return 0;
+ }
+
+ /* update seqnum */
+ if (rro.rro_seqnum != rr->rr_seqnum) {
+ /* then must be "<" */
+
+ /* init rro_segnum_bits */
+ memset(rro.rro_segnum_bits, 0,
+ sizeof(rro.rro_segnum_bits));
+ }
+ rro.rro_seqnum = rr->rr_seqnum;
+
+ return 0;
+}
+
+static void
+rr_command_input(int len, struct icmp6_router_renum *rr,
+ struct in6_addr *from, struct in6_addr *dst)
+{
+ /* rr_command validity check */
+ if (rr_command_check(len, rr, from, dst))
+ goto failed;
+ if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) ==
+ ICMP6_RR_FLAGS_TEST)
+ return;
+
+ /* do router renumbering */
+ if (do_rr(len, rr)) {
+ goto failed;
+ }
+
+ /* update segnum */
+ RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum);
+
+ return;
+
+ failed:
+ syslog(LOG_ERR, "<%s> received RR was invalid", __FUNCTION__);
+ return;
+}
+
+void
+rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
+ struct sockaddr_in6 *from, struct in6_addr *dst)
+{
+ u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+
+ syslog(LOG_DEBUG,
+ "<%s> RR received from %s to %s on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ rr_rcvifindex = pi->ipi6_ifindex;
+
+ /* TODO: some consistency check. */
+
+ switch (rr->rr_code) {
+ case ICMP6_ROUTER_RENUMBERING_COMMAND:
+ rr_command_input(len, rr, &from->sin6_addr, dst);
+ /* TODO: send reply msg */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_RESULT:
+ /* RESULT will be processed by rrenumd */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
+ /* TODO: sequence number reset */
+ break;
+ default:
+ syslog(LOG_ERR, "<%s> received unknown code %d",
+ __FUNCTION__, rr->rr_code);
+ break;
+
+ }
+
+ return;
+}
diff --git a/usr.sbin/rtadvd/rrenum.h b/usr.sbin/rtadvd/rrenum.h
new file mode 100644
index 0000000..d3c73a7
--- /dev/null
+++ b/usr.sbin/rtadvd/rrenum.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+void rr_input __P((int len, struct icmp6_router_renum *rr,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from,
+ struct in6_addr *dst));
diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8
new file mode 100644
index 0000000..a9b36b8
--- /dev/null
+++ b/usr.sbin/rtadvd/rtadvd.8
@@ -0,0 +1,134 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: rtadvd.8,v 1.1.1.1 1999/08/08 23:31:42 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 17, 1998
+.Dt RTADVD 8
+.Os KAME
+.Sh NAME
+.Nm rtadvd
+.Nd router advertisement daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl c Ar configfile
+.Op Fl P Ar policy
+.Op Fl dDfs
+.Ar interface ...
+.Sh DESCRIPTION
+.Nm Rtadvd
+advertises router advertisement packet to the specified
+.Ar interfaces .
+.Pp
+The program will daemonize itself on invocation.
+Then, it will voluntarily send router advertisement packet periodically.
+If a router solicitation packet from host has reached the program,
+the program will respond by router advertisement packet.
+.Pp
+For each interface, which is called advertising interface,
+content of router advertisement can be described in
+.Xr rtadvd.conf 5 .
+.Pp
+If there is no description for the interface in the configuration file
+or if the configuration file does not exist,
+.Nm
+sets all the parameters to their default values.
+In particular,
+.Nm
+gets all the interface routes from the routing table and advertises
+them as on-link prefixes.
+.Pp
+.Nm Rtadvd
+watches the routing table.
+By default, if an interface direct route is
+added/deleted on an advertising interface,
+.Nm
+adds/deletes the corresponding prefix to/from its advertising list,
+respectively.
+If you do not want to enable this feature, you should specify the
+.Ic Fl s
+command line option when advocation.
+.Pp
+.Nm Rtadvd
+can also receive router renumbering packets, and can do router
+renumbering for the system it runs on, as the contents of those
+packets.
+.Bl -tag -width indent
+.\"
+.It Fl c
+Specify an alternate location,
+.Ar configfile ,
+for the configuration file.
+By default,
+.Pa /usr/local/v6/etc/rtadvd.conf
+is used.
+.It Fl P
+Specifies that
+.Nm
+receives router renumbering messages. Also, specifies IPsec policy for
+rrenumd sessions. Because router renumbering can change the system's
+IPv6 prefix, its messages must be protected by IPsec. For details about
+.Ar policy ,
+please refer to
+.Xr ipsec 4
+and
+.Xr ipsec_set_policy 3 .
+.It Fl d
+Debug.
+.It Fl D
+More debug.
+.It Fl f
+Foreground mode.
+Do not become daemon.
+.It Fl s
+Static prefix.
+Do not watch the routing table.
+.El
+.Sh RETURN VALUES
+The program exits with 0 on success, and non-zero on failures.
+.Sh FILES
+.Bl -tag -width /usr/local/v6/etc/rtadvd.conf -compact
+.It Pa /usr/local/v6/etc/rtadvd.conf
+The default configuration file.
+.El
+.Sh SEE ALSO
+.Xr daemon 3 ,
+.Xr rtadvd.conf 5 ,
+.Xr rtsol 8
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.Sh CAVEAT
+Do not perform router advertisement toward upstream direction,
+you should only advertise to downstream direction.
+If you advertise toward upstream by mistake,
+you will see icmp6 redirect storm on that subnet.
+This is because of the specification,
+which says that advertising router is assumed to become
+the default outgoing router for end hosts in the subnet.
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
new file mode 100644
index 0000000..03ed974
--- /dev/null
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif /*IPSEC*/
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include "rtadvd.h"
+#include "rrenum.h"
+#include "advcap.h"
+#include "timer.h"
+#include "if.h"
+#include "config.h"
+
+struct msghdr rcvmhdr;
+static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+struct msghdr sndmhdr;
+struct iovec rcviov[2];
+struct iovec sndiov[2];
+struct sockaddr_in6 from;
+struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
+int sock, rrsock, rtsock;
+int accept_rr = 0;
+int dflag = 0, sflag = 0;
+
+u_char *conffile = NULL;
+
+struct rainfo *ralist = NULL;
+struct nd_optlist {
+ struct nd_optlist *next;
+ struct nd_opt_hdr *opt;
+};
+union nd_opts {
+ struct nd_opt_hdr *nd_opt_array[7];
+ struct {
+ struct nd_opt_hdr *zero;
+ struct nd_opt_hdr *src_lladdr;
+ struct nd_opt_hdr *tgt_lladdr;
+ struct nd_opt_prefix_info *pi;
+ struct nd_opt_rd_hdr *rh;
+ struct nd_opt_mtu *mtu;
+ struct nd_optlist *list;
+ } nd_opt_each;
+};
+#define nd_opts_src_lladdr nd_opt_each.src_lladdr
+#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
+#define nd_opts_pi nd_opt_each.pi
+#define nd_opts_rh nd_opt_each.rh
+#define nd_opts_mtu nd_opt_each.mtu
+#define nd_opts_list nd_opt_each.list
+
+#define NDOPT_FLAG_SRCLINKADDR 0x1
+#define NDOPT_FLAG_TGTLINKADDR 0x2
+#define NDOPT_FLAG_PREFIXINFO 0x4
+#define NDOPT_FLAG_RDHDR 0x8
+#define NDOPT_FLAG_MTU 0x10
+
+u_int32_t ndopt_flags[] = {
+ 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
+ NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU
+};
+
+int main __P((int, char *[]));
+static void sock_open __P((int *, int, char *));
+static void rtsock_open __P((void));
+static void rtadvd_input __P((int));
+static void rs_input __P((int, struct nd_router_solicit *,
+ struct in6_pktinfo *, struct sockaddr_in6 *));
+static void ra_input __P((int, struct nd_router_advert *,
+ struct in6_pktinfo *, struct sockaddr_in6 *));
+static void prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *,
+ struct sockaddr_in6 *));
+static int nd6_options __P((struct nd_opt_hdr *, int,
+ union nd_opts *, u_int32_t));
+static void free_ndopts __P((union nd_opts *));
+static struct rainfo *if_indextorainfo __P((int));
+static void ra_output __P((struct rainfo *));
+static void rtmsg_input __P((void));
+struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int));
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ fd_set fdset;
+ int maxfd = 0;
+ struct timeval *timeout;
+ int i, ch;
+ int fflag = 0;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy = NULL;
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+ openlog(*argv, LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+ /* get command line options and arguments */
+ while ((ch = getopt(argc, argv, "c:dDfR:s")) != -1) {
+ switch(ch) {
+ case 'c':
+ conffile = optarg;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'D':
+ dflag = 2;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ case 'P':
+ policy = strdup(optarg);
+ accept_rr = 1;
+ break;
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+ case 's':
+ sflag = 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0) {
+ fprintf(stderr,
+ "usage: rtadvd [-c conffile] [-d|D] [-f] [-s]"
+ "interfaces...\n");
+ exit(1);
+ }
+
+ /* set log level */
+ if (dflag == 0)
+ (void)setlogmask(LOG_UPTO(LOG_ERR));
+ if (dflag == 1)
+ (void)setlogmask(LOG_UPTO(LOG_INFO));
+
+ /* timer initialization */
+ rtadvd_timer_init();
+
+ /* random value initialization */
+ srandom((u_long)time(NULL));
+
+ /* get iflist block from kernel */
+ init_iflist();
+
+ while (argc--)
+ getconfig(*argv++);
+
+ if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
+ fprintf(stderr, "fatal: inet_pton failed\n");
+ exit(1);
+ }
+ sock_open(&sock, 0, NULL);
+ if (accept_rr != 0)
+ sock_open(&rrsock, 1, policy);
+
+ if (!fflag)
+ daemon(1, 0);
+
+ FD_ZERO(&fdset);
+ FD_SET(sock, &fdset);
+ if (accept_rr)
+ FD_SET(rrsock, &fdset);
+ maxfd = sock > rrsock ? sock : rrsock;
+ if (sflag == 0) {
+ rtsock_open();
+ FD_SET(rtsock, &fdset);
+ if (rtsock > maxfd)
+ maxfd = rtsock;
+ }
+
+ while (1) {
+ struct fd_set select_fd = fdset; /* reinitialize */
+
+ /* timer expiration check and reset the timer */
+ timeout = rtadvd_check_timer();
+
+ syslog(LOG_DEBUG,
+ "<%s> set timer to %ld:%ld. waiting for inputs "
+ "or timeout",
+ __FUNCTION__,
+ timeout->tv_sec, timeout->tv_usec);
+
+ if ((i = select(maxfd + 1, &select_fd,
+ NULL, NULL, timeout)) < 0){
+ syslog(LOG_ERR, "<%s> select: %s",
+ __FUNCTION__, strerror(errno));
+ continue;
+ }
+ if (i == 0) /* timeout */
+ continue;
+ if (sflag == 0 && FD_ISSET(rtsock, &select_fd))
+ rtmsg_input();
+ if (FD_ISSET(sock, &select_fd))
+ rtadvd_input(sock);
+ if (accept_rr && FD_ISSET(rrsock, &select_fd))
+ rtadvd_input(rrsock);
+ }
+ exit(0); /* NOTREACHED */
+}
+
+static void
+rtmsg_input()
+{
+ int n, type, ifindex, plen;
+ size_t len;
+ char msg[2048], *next, *lim;
+ u_char ifname[16];
+ struct prefix *prefix;
+ struct rainfo *rai;
+ struct in6_addr *addr;
+ char addrbuf[INET6_ADDRSTRLEN];
+
+ n = read(rtsock, msg, 2048);
+ if (dflag > 1) {
+ syslog(LOG_DEBUG,
+ "<%s> received a routing message "
+ "(type = %d, len = %d)",
+ __FUNCTION__,
+ rtmsg_type(msg), n);
+ }
+ if (n > rtmsg_len(msg)) {
+ /*
+ * This usually won't happen for messages received on
+ * an routing socket.
+ */
+ if (dflag > 1)
+ syslog(LOG_DEBUG,
+ "<%s> received data length is larger than"
+ "1st routing message len. multiple messages?"
+ " read %d bytes, but 1st msg len = %d",
+ __FUNCTION__, n, rtmsg_len(msg));
+ }
+
+ lim = msg + n;
+ for (next = msg; next < lim; next += len) {
+ next = get_next_msg(next, lim, 0, &len,
+ RTADV_TYPE2BITMASK(RTM_ADD) |
+ RTADV_TYPE2BITMASK(RTM_DELETE) |
+ RTADV_TYPE2BITMASK(RTM_NEWADDR) |
+ RTADV_TYPE2BITMASK(RTM_DELADDR) |
+ RTADV_TYPE2BITMASK(RTM_IFINFO));
+ if (len == 0)
+ break;
+ type = rtmsg_type(next);
+ switch (type) {
+ case RTM_ADD:
+ case RTM_DELETE:
+ ifindex = get_rtm_ifindex(next);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifindex = get_ifam_ifindex(next);
+ break;
+ case RTM_IFINFO:
+ ifindex = get_ifm_ifindex(next);
+ break;
+ default:
+ /* should not reach here */
+ if (dflag > 1) {
+ syslog(LOG_DEBUG,
+ "<%s:%d> unknown rtmsg %d on %s",
+ __FUNCTION__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ }
+ return;
+ }
+
+ if ((rai = if_indextorainfo(ifindex)) == NULL) {
+ if (dflag > 1) {
+ syslog(LOG_DEBUG,
+ "<%s> route changed on "
+ "non advertising interface(%s)",
+ __FUNCTION__,
+ if_indextoname(ifindex, ifname));
+ }
+ return;
+ }
+
+ switch(type) {
+ case RTM_ADD:
+ /* init iffalgs because it may have changed */
+ iflist[ifindex]->ifm_flags =
+ if_getflags(ifindex,
+ iflist[ifindex]->ifm_flags);
+
+ addr = get_addr(msg);
+ plen = get_prefixlen(msg);
+ /* sanity check for plen */
+ if (plen < 4 /* as RFC2373, prefixlen is at least 4 */
+ || plen > 127) {
+ syslog(LOG_INFO, "<%s> new interface route's"
+ "plen %d is invalid for a prefix",
+ __FUNCTION__, plen);
+ return;
+ }
+ prefix = find_prefix(rai, addr, plen);
+ if (prefix) {
+ if (dflag > 1) {
+ syslog(LOG_DEBUG,
+ "<%s> new prefix(%s/%d) "
+ "added on %s, "
+ "but it was already in list",
+ __FUNCTION__,
+ inet_ntop(AF_INET6,
+ addr, (char *)addrbuf,
+ INET6_ADDRSTRLEN),
+ plen,
+ rai->ifname);
+ }
+ return;
+ }
+ make_prefix(rai, ifindex, addr, plen);
+ break;
+ case RTM_DELETE:
+ /* init ifflags because it may have changed */
+ iflist[ifindex]->ifm_flags =
+ if_getflags(ifindex,
+ iflist[ifindex]->ifm_flags);
+
+ addr = get_addr(msg);
+ plen = get_prefixlen(msg);
+ /* sanity check for plen */
+ if (plen < 4 /* as RFC2373, prefixlen is at least 4 */
+ || plen > 127) {
+ syslog(LOG_INFO, "<%s> deleted interface"
+ "route's"
+ "plen %d is invalid for a prefix",
+ __FUNCTION__, plen);
+ return;
+ }
+ prefix = find_prefix(rai, addr, plen);
+ if (prefix == NULL) {
+ if (dflag > 1) {
+ syslog(LOG_DEBUG,
+ "<%s> prefix(%s/%d) was "
+ "deleted on %s, "
+ "but it was not in list",
+ __FUNCTION__,
+ inet_ntop(AF_INET6,
+ addr, (char *)addrbuf,
+ INET6_ADDRSTRLEN),
+ plen,
+ rai->ifname);
+ }
+ return;
+ }
+ delete_prefix(rai, prefix);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ /* init ifflags because it may have changed */
+ iflist[ifindex]->ifm_flags =
+ if_getflags(ifindex,
+ iflist[ifindex]->ifm_flags);
+ break;
+ case RTM_IFINFO:
+ iflist[ifindex]->ifm_flags = get_ifm_flags(next);
+ break;
+ default:
+ /* should not reach here */
+ if (dflag > 1) {
+ syslog(LOG_DEBUG,
+ "<%s:%d> unknown rtmsg %d on %s",
+ __FUNCTION__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ }
+ return;
+ }
+ }
+
+ return;
+}
+
+void
+rtadvd_input(skt)
+{
+ int i;
+ int *hlimp = NULL;
+ struct icmp6_hdr *icp;
+ int ifindex = 0;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi = NULL;
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ struct in6_addr dst = in6addr_any;
+
+ /*
+ * Get message. We reset msg_controllen since the field could
+ * be modified if we had received a message before setting
+ * receive options.
+ */
+ rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf);
+ if ((i = recvmsg(skt, &rcvmhdr, 0)) < 0)
+ return;
+
+ /* extract optional information via Advanced API */
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
+ cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
+ pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+ ifindex = pi->ipi6_ifindex;
+ dst = pi->ipi6_addr;
+ }
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+ if (ifindex == 0) {
+ syslog(LOG_ERR,
+ "<%s> failed to get receiving interface",
+ __FUNCTION__);
+ return;
+ }
+ if (hlimp == NULL) {
+ syslog(LOG_ERR,
+ "<%s> failed to get receiving hop limit",
+ __FUNCTION__);
+ return;
+ }
+
+ if (i < sizeof(struct icmp6_hdr)) {
+ syslog(LOG_ERR,
+ "<%s> packet size(%d) is too short",
+ __FUNCTION__, i);
+ return;
+ }
+
+ icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+
+ switch(icp->icmp6_type) {
+ case ND_ROUTER_SOLICIT:
+ /* hop limit verification - RFC-2461 6.1.1 */
+ if (*hlimp != 255) {
+ syslog(LOG_NOTICE,
+ "<%s> invalid hop limit(%d) "
+ "received from %s on %s",
+ __FUNCTION__, *hlimp,
+ inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ rs_input(i, (struct nd_router_solicit *)icp, pi, &from);
+ break;
+ case ND_ROUTER_ADVERT:
+ /* hop limit verification - RFC-2461 6.1.1 */
+ if (*hlimp != 255) {
+ syslog(LOG_NOTICE,
+ "<%s> invalid hop limit(%d) "
+ "received from %s on %s",
+ __FUNCTION__, *hlimp,
+ inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ ra_input(i, (struct nd_router_advert *)icp, pi, &from);
+ break;
+ case ICMP6_ROUTER_RENUMBERING:
+ if (accept_rr == 0) {
+ syslog(LOG_ERR,
+ "<%s> received a router renumbering "
+ "message, but not allowed to be accepted",
+ __FUNCTION__);
+ break;
+ }
+ rr_input(i, (struct icmp6_router_renum *)icp, pi, &from,
+ &dst);
+ break;
+ default:
+ /*
+ * Note that this case is POSSIBLE, especially just
+ * after invocation of the daemon. This is because we
+ * could receive message after opening the socket and
+ * before setting ICMP6 type filter(see sock_open()).
+ */
+ syslog(LOG_ERR,
+ "<%s> invalid icmp type(%d)",
+ __FUNCTION__, icp->icmp6_type);
+ return;
+ }
+
+ return;
+}
+
+static void
+rs_input(int len, struct nd_router_solicit *rs,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from)
+{
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ union nd_opts ndopts;
+ struct rainfo *ra;
+
+ syslog(LOG_DEBUG,
+ "<%s> RS received from %s on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* ND option check */
+ memset(&ndopts, 0, sizeof(ndopts));
+ if (nd6_options((struct nd_opt_hdr *)(rs + 1),
+ len - sizeof(struct nd_router_solicit),
+ &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
+ syslog(LOG_DEBUG,
+ "<%s> ND option check failed for an RS from %s on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * If the IP source address is the unspecified address, there
+ * must be no source link-layer address option in the message.
+ * (RFC-2461 6.1.1)
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
+ ndopts.nd_opts_src_lladdr) {
+ syslog(LOG_ERR,
+ "<%s> RS from unspecified src on %s has a link-layer"
+ " address option",
+ __FUNCTION__,
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+
+ ra = ralist;
+ while (ra != NULL) {
+ if (pi->ipi6_ifindex == ra->ifindex)
+ break;
+ ra = ra->next;
+ }
+ if (ra == NULL) {
+ syslog(LOG_INFO,
+ "<%s> RS received on non advertising interface(%s)",
+ __FUNCTION__,
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+
+ /*
+ * Decide whether to send RA according to the rate-limit
+ * consideration.
+ */
+ {
+ long delay; /* must not be greater than 1000000 */
+ struct timeval interval, now, min_delay, tm_tmp, *rest;
+
+ /*
+ * If there is already a waiting RS packet, don't
+ * update the timer.
+ */
+ if (ra->waiting++)
+ goto done;
+
+ /*
+ * Compute a random delay. If the computed value
+ * corresponds to a time later than the time the next
+ * multicast RA is scheduled to be sent, ignore the random
+ * delay and send the advertisement at the
+ * already-scheduled time. RFC-2461 6.2.6
+ */
+ delay = random() % MAX_RA_DELAY_TIME;
+ interval.tv_sec = 0;
+ interval.tv_usec = delay;
+ rest = rtadvd_timer_rest(ra->timer);
+ if (TIMEVAL_LT(*rest, interval)) {
+ syslog(LOG_DEBUG,
+ "<%s> random delay is larger than "
+ "the rest of normal timer",
+ __FUNCTION__);
+ interval = *rest;
+ }
+
+ /*
+ * If we sent a multicast Router Advertisement within
+ * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
+ * the advertisement to be sent at a time corresponding to
+ * MIN_DELAY_BETWEEN_RAS plus the random value after the
+ * previous advertisement was sent.
+ */
+ gettimeofday(&now, NULL);
+ TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp);
+ min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
+ min_delay.tv_usec = 0;
+ if (TIMEVAL_LT(tm_tmp, min_delay)) {
+ TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
+ TIMEVAL_ADD(&min_delay, &interval, &interval);
+ }
+ rtadvd_set_timer(&interval, ra->timer);
+ goto done;
+ }
+
+ done:
+ free_ndopts(&ndopts);
+ return;
+}
+
+static void
+ra_input(int len, struct nd_router_advert *ra,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from)
+{
+ struct rainfo *rai;
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ union nd_opts ndopts;
+ char *on_off[] = {"OFF", "ON"};
+ u_int32_t reachabletime, retranstimer, mtu;
+
+ syslog(LOG_DEBUG,
+ "<%s> RA received from %s on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* ND option check */
+ memset(&ndopts, 0, sizeof(ndopts));
+ if (nd6_options((struct nd_opt_hdr *)(ra + 1),
+ len - sizeof(struct nd_router_advert),
+ &ndopts,
+ NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
+ syslog(LOG_ERR,
+ "<%s> ND option check failed for an RA from %s on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * RA consistency check according to RFC-2461 6.2.7
+ */
+ if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
+ syslog(LOG_INFO,
+ "<%s> received RA from %s on non-advertising"
+ " interface(%s)",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+ /* Cur Hop Limit value */
+ if (ra->nd_ra_curhoplimit && rai->hoplimit &&
+ ra->nd_ra_curhoplimit != rai->hoplimit) {
+ syslog(LOG_WARNING,
+ "<%s> CurHopLimit inconsistent on %s:"
+ " %d from %s, %d from us",
+ __FUNCTION__,
+ rai->ifname,
+ ra->nd_ra_curhoplimit,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->hoplimit);
+ }
+ /* M flag */
+ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
+ rai->managedflg) {
+ syslog(LOG_WARNING,
+ "<%s> M flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __FUNCTION__,
+ rai->ifname,
+ on_off[!rai->managedflg],
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ on_off[rai->managedflg]);
+ }
+ /* O flag */
+ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
+ rai->otherflg) {
+ syslog(LOG_WARNING,
+ "<%s> O flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __FUNCTION__,
+ rai->ifname,
+ on_off[!rai->otherflg],
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ on_off[rai->otherflg]);
+ }
+ /* Reachable Time */
+ reachabletime = ntohl(ra->nd_ra_reachable);
+ if (reachabletime && rai->reachabletime &&
+ reachabletime != rai->reachabletime) {
+ syslog(LOG_WARNING,
+ "<%s> ReachableTime inconsistent on %s:"
+ " %d from %s, %d from us",
+ __FUNCTION__,
+ rai->ifname,
+ reachabletime,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->reachabletime);
+ }
+ /* Retrans Timer */
+ retranstimer = ntohl(ra->nd_ra_retransmit);
+ if (retranstimer && rai->retranstimer &&
+ retranstimer != rai->retranstimer) {
+ syslog(LOG_WARNING,
+ "<%s> RetranceTimer inconsistent on %s:"
+ " %d from %s, %d from us",
+ __FUNCTION__,
+ rai->ifname,
+ retranstimer,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->retranstimer);
+ }
+ /* Values in the MTU options */
+ if (ndopts.nd_opts_mtu) {
+ mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
+ if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
+ syslog(LOG_WARNING,
+ "<%s> MTU option value inconsistent on %s:"
+ " %d from %s, %d from us",
+ __FUNCTION__,
+ rai->ifname, mtu,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->linkmtu);
+ }
+ }
+ /* Preferred and Valid Lifetimes for prefixes */
+ {
+ struct nd_optlist *optp = ndopts.nd_opts_list;
+
+ if (ndopts.nd_opts_pi)
+ prefix_check(ndopts.nd_opts_pi, rai, from);
+ while (optp) {
+ prefix_check((struct nd_opt_prefix_info *)optp->opt,
+ rai, from);
+ optp = optp->next;
+ }
+ }
+
+ done:
+ free_ndopts(&ndopts);
+ return;
+}
+
+static void
+prefix_check(struct nd_opt_prefix_info *pinfo,
+ struct rainfo *rai, struct sockaddr_in6 *from)
+{
+ u_int32_t preferred_time, valid_time;
+ struct prefix *pp;
+ u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
+
+ /*
+ * log if the adveritsed prefix has link-local scope(sanity check?)
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
+ syslog(LOG_INFO,
+ "<%s> link-local prefix %s/%d is advertised "
+ "from %s on %s",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->ifname);
+ }
+
+ if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
+ pinfo->nd_opt_pi_prefix_len)) == NULL) {
+ syslog(LOG_INFO,
+ "<%s> prefix %s/%d from %s on %s is not in our list",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->ifname);
+ return;
+ }
+
+ preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
+ if (preferred_time != pp->preflifetime)
+ syslog(LOG_WARNING,
+ "<%s> prefeerred lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->preflifetime);
+
+ valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
+ if (valid_time != pp->validlifetime)
+ syslog(LOG_WARNING,
+ "<%s> valid lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __FUNCTION__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, valid_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->validlifetime);
+}
+
+struct prefix *
+find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
+{
+ struct prefix *pp;
+ int bytelen, bitlen;
+
+ for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
+ if (plen != pp->prefixlen)
+ continue;
+ bytelen = plen / 8;
+ bitlen = plen % 8;
+ if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
+ continue;
+ if (prefix->s6_addr[bytelen] >> (8 - bitlen) ==
+ pp->prefix.s6_addr[bytelen] >> (8 - bitlen))
+ return(pp);
+ }
+
+ return(NULL);
+}
+
+static int
+nd6_options(struct nd_opt_hdr *hdr, int limit,
+ union nd_opts *ndopts, u_int32_t optflags)
+{
+ int optlen = 0;
+
+ for (; limit > 0; limit -= optlen) {
+ hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen);
+ optlen = hdr->nd_opt_len << 3;
+ if (hdr->nd_opt_len == 0) {
+ syslog(LOG_ERR,
+ "<%s> bad ND option length(0) (type = %d)",
+ __FUNCTION__, hdr->nd_opt_type);
+ goto bad;
+ }
+
+ if (hdr->nd_opt_type > ND_OPT_MTU) {
+ syslog(LOG_INFO,
+ "<%s> unknown ND option(type %d)",
+ __FUNCTION__,
+ hdr->nd_opt_type);
+ continue;
+ }
+
+ if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
+ syslog(LOG_INFO,
+ "<%s> unexpected ND option(type %d)",
+ __FUNCTION__,
+ hdr->nd_opt_type);
+ continue;
+ }
+
+ switch(hdr->nd_opt_type) {
+ case ND_OPT_SOURCE_LINKADDR:
+ case ND_OPT_TARGET_LINKADDR:
+ case ND_OPT_REDIRECTED_HEADER:
+ case ND_OPT_MTU:
+ if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
+ syslog(LOG_INFO,
+ "<%s> duplicated ND option"
+ " (type = %d)",
+ __FUNCTION__,
+ hdr->nd_opt_type);
+ }
+ ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
+ break;
+ case ND_OPT_PREFIX_INFORMATION:
+ {
+ struct nd_optlist *pfxlist;
+
+ if (ndopts->nd_opts_pi == 0) {
+ ndopts->nd_opts_pi =
+ (struct nd_opt_prefix_info *)hdr;
+ continue;
+ }
+ if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't allocate memory",
+ __FUNCTION__);
+ goto bad;
+ }
+ pfxlist->next = ndopts->nd_opts_list;
+ pfxlist->opt = hdr;
+ ndopts->nd_opts_list = pfxlist;
+
+ break;
+ }
+ default: /* impossible */
+ break;
+ }
+ }
+
+ return(0);
+
+ bad:
+ free_ndopts(ndopts);
+
+ return(-1);
+}
+
+static void
+free_ndopts(union nd_opts *ndopts)
+{
+ struct nd_optlist *opt = ndopts->nd_opts_list, *next;
+
+ while(opt) {
+ next = opt->next;
+ free(opt);
+ opt = next;
+ }
+}
+
+void
+sock_open(int *sockp, int is_rr, char *policy)
+{
+ struct icmp6_filter filt;
+ struct ipv6_mreq mreq;
+ struct rainfo *ra = ralist;
+ int on;
+ char *rtr_str;
+ /* XXX: should be max MTU attached to the node */
+ static u_char answer[1500];
+ static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+
+ if ((*sockp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
+ strerror(errno));
+ exit(1);
+ }
+
+ /* specify to tell receiving interface */
+ on = 1;
+ if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0) {
+ syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s",
+ __FUNCTION__, strerror(errno));
+ exit(1);
+ }
+
+ on = 1;
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+ if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s",
+ __FUNCTION__, strerror(errno));
+ exit(1);
+ }
+
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ if (is_rr)
+ ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
+ else {
+ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+ }
+ if (setsockopt(*sockp, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0) {
+ syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
+ __FUNCTION__, strerror(errno));
+ exit(1);
+ }
+
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (is_rr && policy != NULL) {
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL)
+ errx(EX_CONFIG, ipsec_strerror());
+ if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG, "ipsec policy cannot be configured");
+ free(buf);
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+ /*
+ * join all routers multicast address on each advertising interface.
+ */
+ rtr_str = is_rr ? ALLSITEROUTERS : ALLROUTERS;
+ if (inet_pton(AF_INET6, rtr_str, &mreq.ipv6mr_multiaddr.s6_addr)
+ != 1) {
+ syslog(LOG_ERR, "<%s> inet_pton for %s failed(library bug?)",
+ __FUNCTION__, rtr_str);
+ exit(1);
+ }
+ while(ra) {
+ mreq.ipv6mr_interface = ra->ifindex;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
+ sizeof(mreq)) < 0) {
+ syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP for %s on"
+ "%s: %s", __FUNCTION__,
+ rtr_str, ra->ifname, strerror(errno));
+ exit(1);
+ }
+ ra = ra->next;
+ }
+ if (is_rr) /* msghdrs should have been alreadey initialized. */
+ return;
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)answer;
+ rcviov[0].iov_len = sizeof(answer);
+ rcvmhdr.msg_name = (caddr_t)&from;
+ rcvmhdr.msg_namelen = sizeof(from);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf);
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = sizeof(sndcmsgbuf);
+
+ return;
+}
+
+/* open a routing socket to watch the routing table */
+static void
+rtsock_open()
+{
+ if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> socket: %s", __FUNCTION__, strerror(errno));
+ exit(1);
+ }
+}
+
+static struct rainfo *
+if_indextorainfo(int index)
+{
+ struct rainfo *rai = ralist;
+
+ for (rai = ralist; rai; rai = rai->next) {
+ if (rai->ifindex == index)
+ return(rai);
+ }
+
+ return(NULL); /* search failed */
+}
+
+static void
+ra_output(rainfo)
+struct rainfo *rainfo;
+{
+ int i;
+
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi;
+
+ sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
+ sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = rainfo->ifindex;
+
+ /* specify the hop limit of the packet */
+ {
+ int hoplimit = 255;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ syslog(LOG_DEBUG,
+ "<%s> send RA on %s, # of waitings = %d",
+ __FUNCTION__, rainfo->ifname, rainfo->waiting);
+
+ i = sendmsg(sock, &sndmhdr, 0);
+
+ if (i < 0 || i != rainfo->ra_datalen) {
+ if (i < 0) {
+ syslog(LOG_ERR, "<%s> sendmsg: %s",
+ __FUNCTION__, strerror(errno));
+ }
+ }
+
+ /* update counter */
+ if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
+ rainfo->initcounter++;
+
+ /* update timestamp */
+ gettimeofday(&rainfo->lastsent, NULL);
+
+ /* reset waiting conter */
+ rainfo->waiting = 0;
+}
+
+/* process RA timer */
+void
+ra_timeout(void *data)
+{
+ struct rainfo *rai = (struct rainfo *)data;
+
+#ifdef notyet
+ /* if necessary, reconstruct the packet. */
+#endif
+
+ syslog(LOG_DEBUG,
+ "<%s> RA timer on %s is expired",
+ __FUNCTION__, rai->ifname);
+
+ if (iflist[rai->ifindex]->ifm_flags & IFF_UP)
+ ra_output(rai);
+ else
+ syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
+ __FUNCTION__, rai->ifname);
+}
+
+/* update RA timer */
+void
+ra_timer_update(void *data, struct timeval *tm)
+{
+ struct rainfo *rai = (struct rainfo *)data;
+ long interval;
+
+ /*
+ * Whenever a multicast advertisement is sent from an interface,
+ * the timer is reset to a uniformly-distributed random value
+ * between the interface's configured MinRtrAdvInterval and
+ * MaxRtrAdvInterval(discovery-v2-02 6.2.4).
+ */
+ interval = rai->mininterval;
+ interval += random() % (rai->maxinterval - rai->mininterval);
+
+ /*
+ * For the first few advertisements (up to
+ * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
+ * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
+ * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
+ * (RFC-2461 6.2.4)
+ */
+ if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
+ interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
+ interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
+
+ tm->tv_sec = interval;
+ tm->tv_usec = 0;
+
+ syslog(LOG_DEBUG,
+ "<%s> RA timer on %s is set to %ld:%ld",
+ __FUNCTION__, rai->ifname, tm->tv_sec, tm->tv_usec);
+
+ return;
+}
diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf
new file mode 100644
index 0000000..f40a650
--- /dev/null
+++ b/usr.sbin/rtadvd/rtadvd.conf
@@ -0,0 +1,14 @@
+# $FreeBSD$
+#
+# common definitions.
+#
+default:\
+ :chlim#64:raflags#0:rltime#1800:rtime#30000:retrans#1000:\
+ :pinfoflags#192:vltime#3600000:pltime#3600000:mtu#1500:
+ether:\
+ :mtu#1500:tc=default:
+#
+# interfaces.
+#
+ef0:\
+ :addrs#1:addr="fec0:0:0:1000::":prefixlen#64:tc=ether:
diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5
new file mode 100644
index 0000000..5d1fed2
--- /dev/null
+++ b/usr.sbin/rtadvd/rtadvd.conf.5
@@ -0,0 +1,250 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: rtadvd.conf.5,v 1.1.1.1 1999/08/08 23:31:42 itojun Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 17, 1998
+.Dt RTADVD.CONF 5
+.Os KAME
+.Sh NAME
+.Nm rtadvd.conf
+.Nd config file for router advertisement daemon
+.Sh DESCRIPTION
+The file describes how the router advertisement packet must be constructed
+for each of the interfaces.
+.Pp
+It obeys famous
+.Xr termcap 5
+file format.
+Each line in the file describes a network interface.
+Fields are separated by a colon
+.Po
+.Dq \&:
+.Pc ,
+and each field contains one capability description.
+Lines may be concatenated by \e character.
+The comment marker is `#' character.
+.Pp
+.Sh CAPABILITIES
+Capabilities describe the value to be filled into ICMPv6 router
+advertisement message and to control
+.Xr rtadvd 8
+behavior.
+Therefore, you are encouraged to read IETF neighbor discovery documents
+if you would like to modify sample configuration file.
+.Pp
+Note that almost all items have default values.
+If you omit an item, the default value of the item will be used.
+.Pp
+There are two items to control interval of sending router advertisements.
+.Bl -tag -width indent
+.It Cm \&maxinterval
+(num) The maximum time allowed between sending unsolicited
+multicast router advertisements
+.Pq unit: seconds .
+The default value is 600. Its value must be no less than 4 seconds
+and no greater than 1800 seconds.
+.It Cm \&mininterval
+(num) The minimum time allowed between sending unsolicited multicast
+router advertisements
+.Pq unit: seconds .
+The default value is the one third of value of
+.Ic maxinterval.
+Its value must be no less than 3 seconds and no greater than .75 *
+the value of
+.Ic maxinterval.
+.El
+.Pp
+The following items are for ICMPv6 router advertisement message
+header.
+.Bl -tag -width indent
+.It Cm \&chlim
+(num) The value for Cur Hop Limit field.
+The default value is 64.
+.It Cm \&raflags
+(num) Flags field in router advertisement message header.
+Bit 7
+.Po
+.Li 0x80
+.Pc
+means Managed address configuration flag bit,
+and Bit 6
+.Po
+.Li 0x40
+.Pc
+means Other stateful configuration flag bit.
+The default value is 0.
+.It Cm \&rltime
+(num) Router lifetime field
+.Pq unit: seconds .
+Its value must be no greater than 3600000.
+The default value is 1800.
+.It Cm \&rtime
+(num) Reachable time field
+.Pq unit: milliseconds .
+The default value is 0, which means unspecified by this router.
+.It Cm \&retrans
+(num) Retrans Timer field
+.Pq unit: milliseconds .
+The default value is 0, which means unspecified by this router.
+.El
+.Pp
+The following items are for ICMPv6 prefix information option,
+which will be attached to router advertisement header.
+.Bl -tag -width indent
+.It Cm \&addrs
+(num) Number of prefixes.
+Its default is 0, so it must explicitly be set to positve values
+if you want to specify any prefix information option.
+If its value is 0,
+.Xr rtadvd 8
+looks up the system routing table and
+advertise the prefixes corresponding to interface routes
+on the interface.
+If its value is more than 1, you must specify the index of the prefix
+for each item below.
+Indices vary from 0 to N-1, where N is the
+value of
+.Ic addrs.
+Each index shall follows the name of each item, e.g.
+.Dq prefixlen2 .
+.It Cm \&prefixlen
+(num) Prefix length field.
+The default value is 64.
+.It Cm \&pinfoflags
+(num) Flags field in prefix information option.
+Bit 7
+.Po
+.Li 0x80
+.Pc
+means On-link flag bit,
+and Bit 6
+.Po
+.Li 0x40
+.Pc
+means Autonomous address-configuration flag bit.
+The default value is 0xc0, i.e. both bits are set.
+.It Cm \&addr
+(str) The address filled into Prefix field.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+This field cannot be
+omitted if the value of
+.Ic addrs
+is more than 0.
+.It Cm \&vltime
+(num) Valid lifetime field
+.Pq unit: seconds .
+The default value is 2592000(30 days).
+.It Cm \&pltime
+(num) Preferred lifetime field
+.Pq unit: seconds .
+The default value is 604800(7 days).
+.El
+.Pp
+The following items are for ICMPv6 MTU option,
+which will be attached to router advertisement header.
+.Bl -tag -width indent
+.It Cm \&mtu
+(num or str) MTU (maximum transmission unit) field.
+If 0 is specified, it means that the option will not be included.
+The default value is 0. If the special string
+.Dq auto
+is specified for this item, MTU option will be included and its value
+will be set to the interface MTU automatically.
+.El
+.Pp
+The following item controls ICMPv6 source link-layer address option,
+which will be attached to router advertisement header.
+.Bl -tag -width indent
+.It Cm \&nolladdr
+(bool) By default
+.Po
+if
+.Cm \&nolladdr
+is not specified
+.Pc ,
+.Xr rtadvd 8
+will try to get link-layer address for the interface from the kernel,
+and attach that in source link-layer address option.
+If this capability exists,
+.Xr rtadvd 8
+will not attach source link-layer address option to
+router advertisement packets.
+.El
+.Pp
+You can also refer one line from another by using
+.Cm tc
+capability.
+See
+.Xr termcap 5
+for details on the capability.
+.Sh EXAMPLE
+.Bd -literal -offset
+#
+# common definitions.
+#
+default:\\
+ :raflags#0:rltime#3600:\\
+ :pinfoflags#64:vltime#360000:pltime#360000:mtu#1500:
+ether:\\
+ :mtu#1280:tc=default:
+
+#
+# interfaces.
+#
+ef0:\\
+ :addrs#1:\\
+ :addr="3ffe:501:4819:1000::":tc=ether:
+ef1:\\
+ :addrs#2:addr0="3ffe:501:4819:2000::":\\
+ :addr1="3ffe:501:4819:3000::":tc=ether:
+
+.Ed
+.Sh SEE ALSO
+.Xr termcap 5 ,
+.Xr rtadvd 8 ,
+.Xr rtsol 8
+.Pp
+Thomas Narten, Erik Nordmark and W. A. Simpson,
+.Do
+Neighbor Discovery for IP version 6 (IPv6)
+.Dc ,
+RFC 2461
+.Sh HISTORY
+The
+.Xr rtadvd 8
+and the configuration file
+.Nm
+first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
new file mode 100644
index 0000000..92fbcdf
--- /dev/null
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#define ALLNODES "ff02::1"
+#define ALLROUTERS "ff02::2"
+#define ALLSITEROUTERS "ff05::2"
+#define ANY "::"
+#define RTSOLLEN 8
+
+/* protocol constants and default values */
+#define DEF_MAXRTRADVINTERVAL 600
+#define DEF_ADVLINKMTU 0
+#define DEF_ADVREACHABLETIME 0
+#define DEF_ADVRETRANSTIMER 0
+#define DEF_ADVCURHOPLIMIT 64
+#define DEF_ADVVALIDLIFETIME 2592000
+#define DEF_ADVPREFERREDLIFETIME 604800
+
+#define MAXROUTERLIFETIME 9000
+#define MIN_MAXINTERVAL 4
+#define MAX_MAXINTERVAL 1800
+#define MIN_MININTERVAL 3
+#define MAXREACHABLETIME 3600000
+
+#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16
+#define MAX_INITIAL_RTR_ADVERTISEMENTS 3
+#define MAX_FINAL_RTR_ADVERTISEMENTS 3
+#define MIN_DELAY_BETWEEN_RAS 3
+#define MAX_RA_DELAY_TIME 500000 /* usec */
+
+struct prefix {
+ struct prefix *next; /* forward link */
+ struct prefix *prev; /* previous link */
+
+ u_int32_t validlifetime; /* AdvValidLifetime */
+ u_int32_t preflifetime; /* AdvPreferredLifetime */
+ u_int onlinkflg; /* bool: AdvOnLinkFlag */
+ u_int autoconfflg; /* bool: AdvAutonomousFlag */
+ int prefixlen;
+ struct in6_addr prefix;
+};
+
+struct rainfo {
+ /* pointer for list */
+ struct rainfo *next;
+
+ /* timer related parameters */
+ struct rtadvd_timer *timer;
+ int initcounter; /* counter for the first few advertisements */
+ struct timeval lastsent; /* timestamp when the lates RA was sent */
+ int waiting; /* number of RS waiting for RA */
+
+ /* interface information */
+ int ifindex;
+ int advlinkopt; /* bool: whether include link-layer addr opt */
+ struct sockaddr_dl *sdl;
+ char ifname[16];
+ int phymtu; /* mtu of the physical interface */
+
+ /* Router configuration variables */
+ u_short lifetime; /* AdvDefaultLifetime */
+ u_int maxinterval; /* MaxRtrAdvInterval */
+ u_int mininterval; /* MinRtrAdvInterval */
+ int managedflg; /* AdvManagedFlag */
+ int otherflg; /* AdvOtherConfigFlag */
+ u_int32_t linkmtu; /* AdvLinkMTU */
+ u_int32_t reachabletime; /* AdvReachableTime */
+ u_int32_t retranstimer; /* AdvRetransTimer */
+ u_int hoplimit; /* AdvCurHopLimit */
+ struct prefix prefix; /* AdvPrefixList(link head) */
+ int pfxs; /* number of prefixes */
+
+ /* actual RA packet data and its length */
+ size_t ra_datalen;
+ u_char *ra_data;
+};
+
+void ra_timeout __P((void *));
+void ra_timer_update __P((void *, struct timeval *));
diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c
new file mode 100644
index 0000000..f93968a
--- /dev/null
+++ b/usr.sbin/rtadvd/timer.c
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/time.h>
+
+#include <unistd.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __NetBSD__
+#include <search.h>
+#endif
+#include "timer.h"
+
+static struct rtadvd_timer timer_head;
+
+#define MILLION 1000000
+
+static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
+
+void
+rtadvd_timer_init()
+{
+ memset(&timer_head, 0, sizeof(timer_head));
+
+ timer_head.next = timer_head.prev = &timer_head;
+ timer_head.tm = tm_max;
+}
+
+struct rtadvd_timer *
+rtadvd_add_timer(void (*timeout) __P((void *)),
+ void (*update) __P((void *, struct timeval *)),
+ void *timeodata, void *updatedata)
+{
+ struct rtadvd_timer *newtimer;
+
+ if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> can't allocate memory", __FUNCTION__);
+ exit(1);
+ }
+
+ memset(newtimer, 0, sizeof(*newtimer));
+
+ if (timeout == NULL) {
+ syslog(LOG_ERR,
+ "<%s> timeout function unspecfied", __FUNCTION__);
+ exit(1);
+ }
+ if (update == NULL) {
+ syslog(LOG_ERR,
+ "<%s> update function unspecfied", __FUNCTION__);
+ exit(1);
+ }
+ newtimer->expire = timeout;
+ newtimer->update = update;
+ newtimer->expire_data = timeodata;
+ newtimer->update_data = updatedata;
+ newtimer->tm = tm_max;
+
+ /* link into chain */
+ insque(newtimer, &timer_head);
+
+ return(newtimer);
+}
+
+void
+rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
+{
+ struct timeval now;
+
+ /* reset the timer */
+ gettimeofday(&now, NULL);
+
+ TIMEVAL_ADD(&now, tm, &timer->tm);
+
+ /* update the next expiration time */
+ if (TIMEVAL_LT(timer->tm, timer_head.tm))
+ timer_head.tm = timer->tm;
+
+ return;
+}
+
+/*
+ * Check expiration for each timer. If a timer is expired,
+ * call the expire function for the timer and update the timer.
+ * Return the next interval for select() call.
+ */
+struct timeval *
+rtadvd_check_timer()
+{
+ static struct timeval returnval;
+ struct timeval now;
+ struct rtadvd_timer *tm = timer_head.next;
+
+ gettimeofday(&now, NULL);
+
+ timer_head.tm = tm_max;
+
+ while(tm != &timer_head) {
+ if (TIMEVAL_LEQ(tm->tm, now)) {
+ (*tm->expire)(tm->expire_data);
+ (*tm->update)(tm->update_data, &tm->tm);
+ TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
+ }
+
+ if (TIMEVAL_LT(tm->tm, timer_head.tm))
+ timer_head.tm = tm->tm;
+
+ tm = tm->next;
+ }
+
+ if (TIMEVAL_LT(timer_head.tm, now)) {
+ /* this may occur when the interval is too small */
+ returnval.tv_sec = returnval.tv_usec = 0;
+ }
+ else
+ TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
+ return(&returnval);
+}
+
+struct timeval *
+rtadvd_timer_rest(struct rtadvd_timer *timer)
+{
+ static struct timeval returnval, now;
+
+ gettimeofday(&now, NULL);
+ if (TIMEVAL_LEQ(timer->tm, now)) {
+ syslog(LOG_DEBUG,
+ "<%s> a timer must be expired, but not yet",
+ __FUNCTION__);
+ returnval.tv_sec = returnval.tv_usec = 0;
+ }
+ else
+ TIMEVAL_SUB(&timer->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;
+ }
+}
diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h
new file mode 100644
index 0000000..e9f2c35
--- /dev/null
+++ b/usr.sbin/rtadvd/timer.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/* 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)))
+
+struct rtadvd_timer {
+ struct rtadvd_timer *next;
+ struct rtadvd_timer *prev;
+ struct rainfo *rai;
+ struct timeval tm;
+
+ void (*expire) __P((void *)); /* expiration function */
+ void *expire_data;
+ void (*update) __P((void *, struct timeval *)); /* update function */
+ void *update_data;
+};
+
+void rtadvd_timer_init __P((void));
+struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)),
+ void (*) __P((void *, struct timeval *)), void *, void *));
+void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *));
+struct timeval * rtadvd_check_timer __P((void));
+struct timeval * rtadvd_timer_rest __P((struct rtadvd_timer *));
+void TIMEVAL_ADD __P((struct timeval *, struct timeval *,
+ struct timeval *));
+void TIMEVAL_SUB __P((struct timeval *, struct timeval *,
+ struct timeval *));
diff --git a/usr.sbin/setkey/Makefile b/usr.sbin/setkey/Makefile
new file mode 100644
index 0000000..918dbf4
--- /dev/null
+++ b/usr.sbin/setkey/Makefile
@@ -0,0 +1,56 @@
+# Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+# $FreeBSD$
+
+PROG= setkey
+SRCS= setkey.c parse.y token.l
+CFLAGS+=-g
+LDADD+= -ll -ly
+CLEANFILES+= y.tab.c y.tab.h key_test.o keytest
+YFLAGS+=-d
+
+SCRIPTS= scriptdump
+
+BINOWN = root
+BINGRP = bin
+BINMODE = 555
+
+all: ${PROG} scriptdump
+
+SRCS+=y.tab.h
+y.tab.h: parse.y
+CFLAGS+=-DIPSEC_DEBUG -DINET6 -DYY_NO_UNPUT -I${.OBJDIR}
+LDADD+= -lipsec
+CLEANFILES+= scriptdump y.tab.h
+
+MAN8= setkey.8
+LOCALPREFIX= /usr/local
+
+scriptdump: scriptdump.pl
+ sed -e 's#@LOCALPREFIX@#${LOCALPREFIX}#' < $> > scriptdump
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/setkey/parse.y b/usr.sbin/setkey/parse.y
new file mode 100644
index 0000000..761c34d
--- /dev/null
+++ b/usr.sbin/setkey/parse.y
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: parse.y,v 1.7 1999/10/27 17:08:57 sakane Exp $ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_var.h>
+#include <netinet6/ipsec.h>
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "vchar.h"
+
+#define ATOX(c) \
+ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
+
+u_int p_type;
+u_int32_t p_spi;
+struct sockaddr *p_src, *p_dst;
+u_int p_prefs, p_prefd, p_upper;
+u_int p_satype, p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode;
+u_int p_key_enc_len, p_key_auth_len;
+caddr_t p_key_enc, p_key_auth;
+time_t p_lt_hard, p_lt_soft;
+
+u_int p_policy_len;
+char *p_policy;
+
+/* temporary buffer */
+static struct sockaddr *pp_addr;
+static u_int pp_prefix;
+static u_int pp_port;
+static caddr_t pp_key;
+
+extern u_char m_buf[BUFSIZ];
+extern int m_len;
+extern char cmdarg[8192];
+extern int f_debug;
+
+int setkeymsg __P((void));
+static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int));
+void parse_init __P((void));
+void free_buffer __P((void));
+
+extern int setkeymsg __P((void));
+extern int sendkeymsg __P((void));
+
+extern int yylex __P((void));
+extern void yyerror __P((char *));
+%}
+
+%union {
+ unsigned long num;
+ vchar_t val;
+}
+
+%token EOT
+%token ADD GET DELETE FLUSH DUMP
+%token IP4_ADDRESS IP6_ADDRESS PREFIX PORT PORTANY
+%token UP_PROTO PR_ESP PR_AH PR_IPCOMP
+%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI
+%token F_MODE MODE
+%token F_EXT EXTENSION
+%token ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP
+%token F_LIFETIME_HARD F_LIFETIME_SOFT
+%token DECSTRING QUOTEDSTRING HEXSTRING ANY
+ /* SPD management */
+%token SPDADD SPDDELETE SPDDUMP SPDFLUSH
+%token F_POLICY PL_REQUESTS
+
+%%
+commands
+ : /*NOTHING*/
+ | commands command
+ {
+ if (f_debug) {
+ printf("cmdarg:\n%s\n", cmdarg);
+ } else {
+ setkeymsg();
+ sendkeymsg();
+ }
+ free_buffer();
+ parse_init();
+ }
+ ;
+
+command
+ : add_command
+ | get_command
+ | delete_command
+ | flush_command
+ | dump_command
+ | spdadd_command
+ | spddelete_command
+ | spddump_command
+ | spdflush_command
+ ;
+ /* commands concerned with management, there is in tail of this file. */
+
+ /* add command */
+add_command
+ : ADD { p_type = SADB_ADD; }
+ sa_selector_spec extension_spec algorithm_spec EOT
+ ;
+
+ /* delete */
+delete_command
+ : DELETE { p_type = SADB_DELETE; }
+ sa_selector_spec extension_spec EOT
+ ;
+
+ /* get command */
+get_command
+ : GET { p_type = SADB_GET; }
+ sa_selector_spec extension_spec EOT
+ ;
+
+ /* flush */
+flush_command
+ : FLUSH { p_type = SADB_FLUSH; }
+ protocol_spec EOT
+ ;
+
+ /* dump */
+dump_command
+ : DUMP { p_type = SADB_DUMP; }
+ protocol_spec EOT
+ ;
+
+ /* sa_selector_spec */
+sa_selector_spec
+ : ipaddress { p_src = pp_addr; }
+ ipaddress { p_dst = pp_addr; }
+ protocol_spec spi
+ ;
+
+protocol_spec
+ : /*NOTHING*/ { p_satype = SADB_SATYPE_UNSPEC; }
+ | PR_ESP
+ {
+ p_satype = SADB_SATYPE_ESP;
+ if ($1.num == 1)
+ p_ext |= SADB_X_EXT_OLD;
+ else
+ p_ext &= ~SADB_X_EXT_OLD;
+ }
+ | PR_AH
+ {
+ p_satype = SADB_SATYPE_AH;
+ if ($1.num == 1)
+ p_ext |= SADB_X_EXT_OLD;
+ else
+ p_ext &= ~SADB_X_EXT_OLD;
+ }
+ | PR_IPCOMP
+ {
+ p_satype = SADB_X_SATYPE_IPCOMP;
+ }
+ ;
+
+spi
+ : DECSTRING { p_spi = $1.num; }
+ | HEXSTRING
+ {
+ caddr_t bp;
+ caddr_t yp = $1.val.buf;
+ char buf0[4], buf[4];
+ int i, j;
+
+ /* sanity check */
+ if ($1.val.len > 4) {
+ yyerror("SPI too big.");
+ free($1.val.buf);
+ return -1;
+ }
+
+ bp = buf0;
+ while (*yp) {
+ *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]);
+ yp += 2, bp++;
+ }
+
+ /* initialize */
+ for (i = 0; i < 4; i++) buf[i] = 0;
+
+ for (j = $1.val.len - 1, i = 3; j >= 0; j--, i--)
+ buf[i] = buf0[j];
+
+ /* XXX: endian */
+ p_spi = ntohl(*(u_int32_t *)buf);
+
+ free($1.val.buf);
+ }
+ ;
+
+algorithm_spec
+ : esp_spec
+ | ah_spec
+ | ipcomp_spec
+ ;
+
+esp_spec
+ : F_ENC enc_alg enc_key F_AUTH auth_alg auth_key
+ | F_ENC enc_alg enc_key
+ ;
+
+ah_spec
+ : F_AUTH auth_alg auth_key
+ ;
+
+ipcomp_spec
+ : F_COMP ALG_COMP { p_alg_enc = $2.num; }
+ | F_COMP ALG_COMP { p_alg_enc = $2.num; }
+ F_RAWCPI { p_ext |= SADB_X_EXT_RAWCPI; }
+ ;
+
+enc_alg
+ : ALG_ENC { p_alg_enc = $1.num; }
+ | ALG_ENC_DESDERIV
+ {
+ p_alg_enc = $1.num;
+ if (p_ext & SADB_X_EXT_OLD) {
+ yyerror("algorithm mismatched.");
+ return -1;
+ }
+ p_ext |= SADB_X_EXT_DERIV;
+ }
+ | ALG_ENC_DES32IV
+ {
+ p_alg_enc = $1.num;
+ if (!(p_ext & SADB_X_EXT_OLD)) {
+ yyerror("algorithm mismatched.");
+ return -1;
+ }
+ p_ext |= SADB_X_EXT_IV4B;
+ }
+ ;
+
+enc_key
+ : /*NOTHING*/
+ {
+ if (p_alg_enc != SADB_EALG_NULL) {
+ yyerror("no key found.");
+ return -1;
+ }
+ }
+ | key_string
+ {
+ p_key_enc_len = $1.val.len;
+ p_key_enc = pp_key;
+
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc,
+ PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ ;
+
+auth_alg
+ : ALG_AUTH { p_alg_auth = $1.num; }
+ ;
+
+auth_key
+ : /*NOTHING*/
+ {
+ if (p_alg_auth != SADB_AALG_NULL) {
+ yyerror("no key found.");
+ return -1;
+ }
+ }
+ | key_string
+ {
+ p_key_auth_len = $1.val.len;
+ p_key_auth = pp_key;
+
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH,
+ p_alg_auth,
+ PFKEY_UNUNIT64(p_key_auth_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ ;
+
+key_string
+ : QUOTEDSTRING
+ {
+ pp_key = $1.val.buf;
+ /* free pp_key later */
+ }
+ | HEXSTRING
+ {
+ caddr_t bp;
+ caddr_t yp = $1.val.buf;
+
+ if ((pp_key = malloc($1.val.len)) == 0) {
+ free($1.val.buf);
+ yyerror(strerror(errno));
+ return -1;
+ }
+ memset(pp_key, 0, $1.val.len);
+
+ bp = pp_key;
+ while (*yp) {
+ *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]);
+ yp += 2, bp++;
+ }
+
+ free($1.val.buf);
+ }
+ ;
+
+extension_spec
+ : /*NOTHING*/
+ | extension_spec extension
+ ;
+
+extension
+ : F_EXT EXTENSION { p_ext |= $1.num; }
+ | F_MODE MODE { p_mode = $2.num; }
+ | F_MODE ANY { p_mode = IPSEC_MODE_ANY; }
+ | F_REPLAY DECSTRING
+ {
+ if (p_ext & SADB_X_EXT_OLD) {
+ yyerror("replay prevention "
+ "only use on new spec.");
+ return -1;
+ }
+ p_replay = $2.num;
+ }
+ | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2.num; }
+ | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2.num; }
+ ;
+
+ /* definition about command for SPD management */
+ /* spdadd */
+spdadd_command
+ : SPDADD
+ {
+ p_type = SADB_X_SPDADD;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ sp_selector_spec policy_spec EOT
+ ;
+
+spddelete_command:
+ SPDDELETE
+ {
+ p_type = SADB_X_SPDDELETE;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ sp_selector_spec EOT
+ ;
+
+spddump_command:
+ SPDDUMP
+ {
+ p_type = SADB_X_SPDDUMP;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ EOT
+ ;
+
+spdflush_command:
+ SPDFLUSH
+ {
+ p_type = SADB_X_SPDFLUSH;
+ p_satype = SADB_SATYPE_UNSPEC;
+ }
+ EOT
+ ;
+
+ /* sp_selector_spec */
+sp_selector_spec
+ : ipaddress { p_src = pp_addr; }
+ prefix { p_prefs = pp_prefix; }
+ port { _INPORTBYSA(p_src) = htons(pp_port); }
+ ipaddress { p_dst = pp_addr; }
+ prefix { p_prefd = pp_prefix; }
+ port { _INPORTBYSA(p_dst) = htons(pp_port); }
+ upper_spec
+ ;
+
+ipaddress
+ : IP4_ADDRESS
+ {
+ struct sockaddr_in *in;
+ u_int sa_len = $1.val.len;
+
+ if ((in = (struct sockaddr_in *)malloc(sa_len)) == 0) {
+ yyerror(strerror(errno));
+ free($1.val.buf);
+ return -1;
+ }
+ memset((caddr_t)in, 0, sa_len);
+
+ in->sin_family = PF_INET;
+ in->sin_len = sa_len;
+ in->sin_port = IPSEC_PORT_ANY;
+ (void)inet_pton(PF_INET, $1.val.buf, &in->sin_addr);
+
+ pp_addr = (struct sockaddr *)in;
+ free($1.val.buf);
+ }
+ | IP6_ADDRESS
+ {
+#ifdef INET6
+ struct sockaddr_in6 *in6;
+ u_int sa_len = $1.val.len;
+ struct addrinfo hints, *res;
+ int ret_gai;
+
+ if ((in6 = (struct sockaddr_in6 *)malloc(sa_len)) == 0) {
+ free($1.val.buf);
+ yyerror(strerror(errno));
+ return -1;
+ }
+ memset((caddr_t)in6, 0, sa_len);
+
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = AF_INET6;
+ ret_gai = getaddrinfo($1.val.buf, NULL, &hints, &res);
+ if (ret_gai) {
+ free($1.val.buf);
+ free(in6);
+ yyerror(gai_strerror(ret_gai));
+ if (ret_gai == EAI_SYSTEM)
+ yyerror(strerror(errno));
+ return -1;
+ }
+ (void)memcpy(in6, res->ai_addr, res->ai_addrlen);
+
+ /*
+ * XXX: If the scope of the destination is link-local,
+ * embed the scope-id(in this case, interface index)
+ * into the address.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr) &&
+ in6->sin6_scope_id != 0)
+ *(u_short *)&in6->sin6_addr.s6_addr[2] =
+ htons(in6->sin6_scope_id & 0xffff);
+
+ freeaddrinfo(res);
+
+ pp_addr = (struct sockaddr *)in6;
+#else
+ yyerror("IPv6 address not supported");
+#endif
+ free($1.val.buf);
+ }
+ ;
+
+prefix
+ : /*NOTHING*/ { pp_prefix = ~0; }
+ | PREFIX { pp_prefix = $1.num; }
+ ;
+
+port
+ : /*NOTHING*/ { pp_port = IPSEC_PORT_ANY; }
+ | PORT { pp_port = $1.num; }
+ | PORTANY { pp_port = IPSEC_PORT_ANY; }
+ ;
+
+upper_spec
+ : DECSTRING { p_upper = $1.num; }
+ | UP_PROTO { p_upper = $1.num; }
+ | PR_ESP { p_upper = IPPROTO_ESP; };
+ | PR_AH { p_upper = IPPROTO_AH; };
+ | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; };
+ | ANY { p_upper = IPSEC_ULPROTO_ANY; }
+ ;
+
+policy_spec
+ : F_POLICY policy_requests
+ {
+ p_policy = ipsec_set_policy($2.val.buf, $2.val.len);
+ if (p_policy == NULL) {
+ free($2.val.buf);
+ p_policy = NULL;
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+
+ p_policy_len = ipsec_get_policylen(p_policy);
+
+ free($2.val.buf);
+ }
+ ;
+
+policy_requests:
+ /*NOTHING*/
+ | PL_REQUESTS { $$ = $1; }
+ ;
+
+%%
+
+int
+setkeymsg()
+{
+ struct sadb_msg m_msg;
+
+ m_msg.sadb_msg_version = PF_KEY_V2;
+ m_msg.sadb_msg_type = p_type;
+ m_msg.sadb_msg_errno = 0;
+ m_msg.sadb_msg_satype = p_satype;
+ m_msg.sadb_msg_mode = p_mode;
+ m_msg.sadb_msg_reserved = 0;
+ m_msg.sadb_msg_seq = 0;
+ m_msg.sadb_msg_pid = getpid();
+
+ m_len = sizeof(struct sadb_msg);
+ memcpy(m_buf, &m_msg, m_len);
+
+ switch (p_type) {
+ case SADB_FLUSH:
+ case SADB_DUMP:
+ break;
+
+ case SADB_ADD:
+ /* set encryption algorithm, if present. */
+ if (p_satype != SADB_X_SATYPE_IPCOMP && p_alg_enc != SADB_EALG_NONE) {
+ struct sadb_key m_key;
+
+ m_key.sadb_key_len =
+ PFKEY_UNIT64(sizeof(m_key)
+ + PFKEY_ALIGN8(p_key_enc_len));
+ m_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+ m_key.sadb_key_bits = p_key_enc_len * 8;
+ m_key.sadb_key_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_key, sizeof(m_key),
+ (caddr_t)p_key_enc, p_key_enc_len);
+ }
+
+ /* set authentication algorithm, if present. */
+ if (p_alg_auth != SADB_AALG_NONE) {
+ struct sadb_key m_key;
+
+ m_key.sadb_key_len =
+ PFKEY_UNIT64(sizeof(m_key)
+ + PFKEY_ALIGN8(p_key_auth_len));
+ m_key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
+ m_key.sadb_key_bits = p_key_auth_len * 8;
+ m_key.sadb_key_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_key, sizeof(m_key),
+ (caddr_t)p_key_auth, p_key_auth_len);
+ }
+
+ /* set lifetime for HARD */
+ if (p_lt_hard != 0) {
+ struct sadb_lifetime m_lt;
+ u_int len = sizeof(struct sadb_lifetime);
+
+ m_lt.sadb_lifetime_len = PFKEY_UNIT64(len);
+ m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+ m_lt.sadb_lifetime_allocations = 0;
+ m_lt.sadb_lifetime_bytes = 0;
+ m_lt.sadb_lifetime_addtime = p_lt_hard;
+ m_lt.sadb_lifetime_usetime = 0;
+
+ memcpy(m_buf + m_len, &m_lt, len);
+ m_len += len;
+ }
+
+ /* set lifetime for SOFT */
+ if (p_lt_soft != 0) {
+ struct sadb_lifetime m_lt;
+ u_int len = sizeof(struct sadb_lifetime);
+
+ m_lt.sadb_lifetime_len = PFKEY_UNIT64(len);
+ m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+ m_lt.sadb_lifetime_allocations = 0;
+ m_lt.sadb_lifetime_bytes = 0;
+ m_lt.sadb_lifetime_addtime = p_lt_soft;
+ m_lt.sadb_lifetime_usetime = 0;
+
+ memcpy(m_buf + m_len, &m_lt, len);
+ m_len += len;
+ }
+ /* FALLTHROUGH */
+
+ case SADB_DELETE:
+ case SADB_GET:
+ {
+ struct sadb_sa m_sa;
+ struct sadb_address m_addr;
+ u_int len;
+
+ len = sizeof(struct sadb_sa);
+ m_sa.sadb_sa_len = PFKEY_UNIT64(len);
+ m_sa.sadb_sa_exttype = SADB_EXT_SA;
+ m_sa.sadb_sa_spi = htonl(p_spi);
+ m_sa.sadb_sa_replay = p_replay;
+ m_sa.sadb_sa_state = 0;
+ m_sa.sadb_sa_auth = p_alg_auth;
+ m_sa.sadb_sa_encrypt = p_alg_enc;
+ m_sa.sadb_sa_flags = p_ext;
+
+ memcpy(m_buf + m_len, &m_sa, len);
+ m_len += len;
+
+ /* set src */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_src->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen =
+ _INALENBYAF(p_src->sa_family) << 3;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_src, p_src->sa_len);
+
+ /* set dst */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_dst->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen =
+ _INALENBYAF(p_dst->sa_family) << 3;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_dst, p_dst->sa_len);
+ }
+ break;
+
+ /* for SPD management */
+ case SADB_X_SPDFLUSH:
+ case SADB_X_SPDDUMP:
+ break;
+
+ case SADB_X_SPDADD:
+ {
+ memcpy(m_buf + m_len, p_policy, p_policy_len);
+ m_len += p_policy_len;
+ free(p_policy);
+ p_policy = NULL;
+ }
+ /* FALLTHROUGH */
+
+ case SADB_X_SPDDELETE:
+ {
+ struct sadb_address m_addr;
+
+ /* set src */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_src->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = p_upper;
+ m_addr.sadb_address_prefixlen =
+ (p_prefs != ~0 ? p_prefs :
+ _INALENBYAF(p_src->sa_family) << 3);
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_src, p_src->sa_len);
+
+ /* set dst */
+ m_addr.sadb_address_len =
+ PFKEY_UNIT64(sizeof(m_addr)
+ + PFKEY_ALIGN8(p_dst->sa_len));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = p_upper;
+ m_addr.sadb_address_prefixlen =
+ (p_prefd != ~0 ? p_prefd :
+ _INALENBYAF(p_dst->sa_family) << 3);
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(&m_len,
+ (struct sadb_ext *)&m_addr, sizeof(m_addr),
+ (caddr_t)p_dst, p_dst->sa_len);
+ }
+ break;
+ }
+
+ ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len);
+
+ return 0;
+}
+
+static int
+setvarbuf(off, ebuf, elen, vbuf, vlen)
+ caddr_t vbuf;
+ struct sadb_ext *ebuf;
+ int *off, elen, vlen;
+{
+ memset(m_buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len));
+ memcpy(m_buf + *off, (caddr_t)ebuf, elen);
+ memcpy(m_buf + *off + elen, vbuf, vlen);
+ (*off) += PFKEY_ALIGN8(elen + vlen);
+
+ return 0;
+}
+
+void
+parse_init()
+{
+ p_type = 0;
+ p_spi = 0;
+
+ p_src = 0, p_dst = 0;
+ pp_prefix = p_prefs = p_prefd = ~0;
+ pp_port = IPSEC_PORT_ANY;
+ p_upper = 0;
+
+ p_satype = 0;
+ p_ext = SADB_X_EXT_NONE;
+ p_alg_enc = SADB_EALG_NONE;
+ p_alg_auth = SADB_AALG_NONE;
+ p_mode = IPSEC_MODE_ANY;
+ p_replay = 4;
+ p_key_enc_len = p_key_auth_len = 0;
+ p_key_enc = p_key_auth = 0;
+ p_lt_hard = p_lt_soft = 0;
+
+ p_policy_len = 0;
+ p_policy = NULL;
+
+ memset(cmdarg, 0, sizeof(cmdarg));
+
+ return;
+}
+
+void
+free_buffer()
+{
+ if (p_src) free(p_src);
+ if (p_dst) free(p_dst);
+ if (p_key_enc) free(p_key_enc);
+ if (p_key_auth) free(p_key_auth);
+
+ return;
+}
+
diff --git a/usr.sbin/setkey/sample.cf b/usr.sbin/setkey/sample.cf
new file mode 100644
index 0000000..886c449
--- /dev/null
+++ b/usr.sbin/setkey/sample.cf
@@ -0,0 +1,219 @@
+# Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+# There are sample scripts for IPsec configuration by manual keying.
+# A security association is uniquely identified by a triple consisting
+# of a Security Parameter Index (SPI), an IP Destination Address, and a
+# security protocol (AH or ESP) identifier. You must take care of these
+# parameters when you configure by manual keying.
+
+# ESP transport mode is recommended for TCP port number 110 between
+# Host-A and Host-B. Encryption algorithm is blowfish-cbc whose key
+# is "kamekame", and authentication algorithm is hmac-sha1 whose key
+# is "this is the test key".
+#
+# ============ ESP ============
+# | |
+# Host-A Host-B
+# fec0::10 -------------------- fec0::11
+#
+# At Host-A and Host-B,
+spdadd fec0::10[any] fec0::11[110] tcp -P out ipsec
+ esp/transport/fec0::10-fec0::11/use ;
+spdadd fec0::11[110] fec0::10[any] tcp -P in ipsec
+ esp/transport/fec0::11-fec0::10/use ;
+add fec0::10 fec0::11 esp 0x10001
+ -m transport
+ -E blowfish-cbc "kamekame"
+ -A hmac-sha1 "this is the test key" ;
+add fec0::11 fec0::10 esp 0x10002
+ -m transport
+ -E blowfish-cbc "kamekame"
+ -A hmac-sha1 "this is the test key" ;
+
+# "[any]" is wildcard of port number. Note that "[0]" is the number of
+# zero in port number.
+
+# Security protocol is old AH tunnel mode, i.e. RFC1826, with keyed-md5
+# whose key is "this is the test" as authentication algorithm.
+# That protocol takes place between Gateway-A and Gateway-B.
+#
+# ======= AH =======
+# | |
+# Network-A Gateway-A Gateway-B Network-B
+# 10.0.1.0/24 ---- 172.16.0.1 ----- 172.16.0.2 ---- 10.0.2.0/24
+#
+# At Gateway-A:
+spdadd 10.0.1.0/24 10.0.2.0/24 any -P out ipsec
+ ah/tunnel/172.16.0.1-172.16.0.2/require ;
+spdadd 10.0.2.0/24 10.0.1.0/24 any -P in ipsec
+ ah/tunnel/172.16.0.2-172.16.0.1/require ;
+add 172.16.0.1 172.16.0.2 ah-old 0x10003
+ -m any
+ -A keyed-md5 "this is the test" ;
+add 172.16.0.2 172.16.0.1 ah-old 0x10004
+ -m any
+ -A keyed-md5 "this is the test" ;
+
+# If port number field is omitted such above then "[any]" is employed.
+# -m specifies the mode of SA to be used. "-m any" means wildcard of
+# mode of security protocol. You can use this SAs for both tunnel and
+# transport mode.
+
+# At Gateway-B. Attention to the selector and peer's IP address for tunnel.
+spdadd 10.0.2.0/24 10.0.1.0/24 any -P out ipsec
+ ah/tunnel/172.16.0.2-172.16.0.1/require ;
+spdadd 10.0.1.0/24 10.0.2.0/24 any -P in ipsec
+ ah/tunnel/172.16.0.1-172.16.0.2/require ;
+add 172.16.0.1 172.16.0.2 ah-old 0x10003
+ -m tunnel
+ -A keyed-md5 "this is the test" ;
+add 172.16.0.2 172.16.0.1 ah-old 0x10004
+ -m tunnel
+ -A keyed-md5 "this is the test" ;
+
+# AH transport mode followed by ESP tunnel mode is required between
+# Gateway-A and Gateway-B.
+# Encryption algorithm is 3des-cbc, and authentication algorithm for ESP
+# is hmac-sha1. Authentication algorithm for AH is hmac-md5.
+#
+# ========== AH =========
+# | ======= ESP ===== |
+# | | | |
+# Network-A Gateway-A Gateway-B Network-B
+# fec0:0:0:1::/64 --- fec0:0:0:1::1 ---- fec0:0:0:2::1 --- fec0:0:0:2::/64
+#
+# At Gateway-A:
+spdadd fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out ipsec
+ esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require
+ ah/transport/fec0:0:0:1::1-fec0:0:0:2::1/require ;
+spdadd fec0:0:0:2::/64 fec0:0:0:1::/64 any -P in ipsec
+ esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require
+ ah/transport/fec0:0:0:2::1-fec0:0:0:1::1/require ;
+add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10001
+ -m tunnel
+ -E 3des-cbc "kamekame12341234kame1234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:1::1 fec0:0:0:2::1 ah 0x10001
+ -m transport
+ -A hmac-md5 "this is the test" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10001
+ -m tunnel
+ -E 3des-cbc "kamekame12341234kame1234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 ah 0x10001
+ -m transport
+ -A hmac-md5 "this is the test" ;
+
+# ESP tunnel mode is required between Host-A and Gateway-A.
+# Encryption algorithm is cast128-cbc, and authentication algorithm
+# for ESP is hmac-sha1.
+# ESP transport mode is recommended between Host-A and Host-B.
+# Encryption algorithm is rc5-cbc, and authentication algorithm
+# for ESP is hmac-md5.
+#
+# ================== ESP =================
+# | ======= ESP ======= |
+# | | | |
+# Host-A Gateway-A Host-B
+# fec0:0:0:1::1 ---- fec0:0:0:2::1 ---- fec0:0:0:2::2
+#
+# At Host-A:
+spdadd fec0:0:0:1::1[any] fec0:0:0:2::2[80] tcp -P out ipsec
+ esp/transport/fec0:0:0:1::1-fec0:0:0:2::2/use
+ esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require ;
+spdadd fec0:0:0:2::1[80] fec0:0:0:1::1[any] tcp -P in ipsec
+ esp/transport/fec0:0:0:2::2-fec0:0:0:1::1/use
+ esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require ;
+add fec0:0:0:1::1 fec0:0:0:2::2 esp 0x10001
+ -m transport
+ -E cast128-cbc "12341234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10002
+ -E rc5-cbc "kamekame"
+ -A hmac-md5 "this is the test" ;
+add fec0:0:0:2::2 fec0:0:0:1::1 esp 0x10003
+ -m transport
+ -E cast128-cbc "12341234"
+ -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10004
+ -E rc5-cbc "kamekame"
+ -A hmac-md5 "this is the test" ;
+
+# By "get" command, you can get a entry of either SP or SA.
+get fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ;
+
+# Also delete command, you can delete a entry of either SP or SA.
+spddelete out fec0:0:0:1::/64 fec0:0:0:2:/64 any ;
+delete fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ;
+
+# By dump command, you can dump all entry of either SP or SA.
+dump ;
+spddump ;
+dump esp ;
+flush esp ;
+
+# By flush command, you can flush all entry of either SP or SA.
+flush ;
+spdflush ;
+
+# "flush" and "dump" commands can specify a security protocol.
+dump esp ;
+flush ah ;
+
+# XXX
+add ::1 ::1 esp 10001 -m transport -E simple ;
+add ::1 ::1 esp 10002 -m transport -E des-deriv "12341234" ;
+add ::1 ::1 esp-old 10003 -m transport -E des-32iv "12341234" ;
+add ::1 ::1 esp 10004 -m transport -E simple -A null ;
+add ::1 ::1 esp 10005 -m transport -E simple -A hmac-md5 "1234123412341234" ;
+add ::1 ::1 esp 10006 -m tunnel -E simple -A hmac-sha1 "12341234123412341234" ;
+add ::1 ::1 esp 10007 -m transport -E simple -A keyed-md5 "1234123412341234" ;
+add ::1 ::1 esp 10008 -m any -E simple -A keyed-sha1 "12341234123412341234" ;
+add ::1 ::1 esp 10009 -m transport -E des-cbc "testtest" ;
+add ::1 ::1 esp 10010 -m transport -E 3des-cbc "testtest12341234testtest" ;
+add ::1 ::1 esp 10011 -m tunnel -E cast128-cbc "testtest1234" ;
+add ::1 ::1 esp 10012 -m tunnel -E blowfish-cbc "testtest1234" ;
+add ::1 ::1 esp 10013 -m tunnel -E rc5-cbc "testtest1234" ;
+add ::1 ::1 esp 10014 -m any -E rc5-cbc "testtest1234" ;
+add ::1 ::1 esp 10015 -m transport -f zero-pad -E simple ;
+add ::1 ::1 esp 10016 -m tunnel -f random-pad -r 8 -lh 100 -ls 80 -E simple ;
+add ::1 ::1 esp 10017 -m transport -f seq-pad -f cyclic-seq -E simple ;
+add ::1 ::1 esp 10018 -m transport -E simple ;
+#add ::1 ::1 ah 20000 -m transport -A null ;
+add ::1 ::1 ah 20001 -m any -A hmac-md5 "1234123412341234";
+add ::1 ::1 ah 20002 -m tunnel -A hmac-sha1 "12341234123412341234";
+add ::1 ::1 ah 20003 -m transport -A keyed-md5 "1234123412341234";
+add ::1 ::1 ah-old 20004 -m transport -A keyed-md5 "1234123412341234";
+add ::1 ::1 ah 20005 -m transport -A keyed-sha1 "12341234123412341234";
+#add ::1 ::1 ipcomp 30000 -C oui ;
+add ::1 ::1 ipcomp 30001 -C deflate ;
+#add ::1 ::1 ipcomp 30002 -C lzs ;
+
+# enjoy.
diff --git a/usr.sbin/setkey/scriptdump.pl b/usr.sbin/setkey/scriptdump.pl
new file mode 100644
index 0000000..5df9b4f
--- /dev/null
+++ b/usr.sbin/setkey/scriptdump.pl
@@ -0,0 +1,54 @@
+#! @LOCALPREFIX@/bin/perl
+# $FreeBSD$
+
+if ($< != 0) {
+ print STDERR "must be root to invoke this\n";
+ exit 1;
+}
+
+$mode = 'add';
+while ($i = shift @ARGV) {
+ if ($i eq '-d') {
+ $mode = 'delete';
+ } else {
+ print STDERR "usage: scriptdump [-d]\n";
+ exit 1;
+ }
+}
+
+open(IN, "setkey -D |") || die;
+foreach $_ (<IN>) {
+ if (/^[^\t]/) {
+ ($src, $dst) = split(/\s+/, $_);
+ } elsif (/^\t(esp|ah) mode=(\S+) spi=(\d+).*replay=(\d+)/) {
+ ($proto, $ipsecmode, $spi, $replay) = ($1, $2, $3, $4);
+ } elsif (/^\tE: (\S+) (.*)/) {
+ $ealgo = $1;
+ $ekey = $2;
+ $ekey =~ s/\s//g;
+ $ekey =~ s/^/0x/g;
+ } elsif (/^\tA: (\S+) (.*)/) {
+ $aalgo = $1;
+ $akey = $2;
+ $akey =~ s/\s//g;
+ $akey =~ s/^/0x/g;
+ } elsif (/^\tstate=/) {
+ print "$mode $src $dst $proto $spi -m $ipsecmode";
+ print " -r $replay" if $replay;
+ if ($mode eq 'add') {
+ if ($proto eq 'esp') {
+ print " -E $ealgo $ekey" if $ealgo;
+ print " -A $aalgo $akey" if $aalgo;
+ } elsif ($proto eq 'ah') {
+ print " -A $aalgo $akey" if $aalgo;
+ }
+ }
+ print ";\n";
+
+ $src = $dst = $upper = $proxy = '';
+ $ealgo = $ekey = $aalgo = $akey = '';
+ }
+}
+close(IN);
+
+exit 0;
diff --git a/usr.sbin/setkey/setkey.8 b/usr.sbin/setkey/setkey.8
new file mode 100644
index 0000000..1f6f33c
--- /dev/null
+++ b/usr.sbin/setkey/setkey.8
@@ -0,0 +1,550 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: setkey.8,v 1.14 1999/10/27 17:08:58 sakane Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 17, 1998
+.Dt SETKEY 8
+.Os KAME
+.\"
+.Sh NAME
+.Nm setkey
+.Nd manually manipulate the SA/SP database.
+.\"
+.Sh SYNOPSIS
+.Nm setkey
+.Op Fl dv
+.Fl c
+.Nm setkey
+.Op Fl dv
+.Fl f Ar filename
+.Nm setkey
+.Op Fl adPlv
+.Fl D
+.Nm setkey
+.Op Fl dPv
+.Fl F
+.Nm setkey
+.Op Fl h
+.Fl x
+.\"
+.Sh DESCRIPTION
+.Nm
+updates, or lists the content of, Security Association Database (SAD) entries
+in the kernel as well as Security Policy Database (SPD) entries.
+.Pp
+.Nm
+takes a series of operation from standard input
+.Po
+if invoked with
+.Fl c
+.Pc
+or file named
+.Ar filename
+.Po
+if invoked with
+.Fl f Ar filename
+.Pc .
+.Bl -tag -width Ds
+.It Fl D
+Dump the SAD entries.
+If with
+.Fl P ,
+the SPD entries are dumped.
+.It Fl F
+Flush the SAD.
+If with
+.Fl P ,
+the SPD are flushed.
+.It Fl a
+.Nm
+usually do not display dead SAD entries on
+.Fl D .
+With
+.Fl a ,
+dead SAD entries will be displayed as well.
+Dead SAD entries are kept in the kernel,
+when they are referenced from any of SPD entries in the kernel.
+.It Fl d
+Enable debugging messages.
+.It Fl x
+Loop forever and dump all the messages transmitted to
+.Dv PF_KEY
+socket.
+.It Fl h
+Add hexadecimal dump on
+.Fl x
+mode. The order is significant.
+.It Fl l
+Loop forever with short output on
+.Fl D .
+.It Fl v
+Be verbose.
+.Dv PF_KEY
+socket
+.Po
+including messages sent from other processes
+.Pc .
+.El
+.Pp
+Operation has the following grammar. Note that lines, that start with a
+hashmark ('#') are treated as comment lines.
+Description of meta-arguments follows.
+.Bl -tag -width Ds
+.It Xo
+.Li add
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar extensions
+.Ar algorithm...
+.Li ;
+.Xc
+Add a SAD entry.
+.\"
+.It Xo
+.Li get
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar mode
+.Li ;
+.Xc
+Show a SAD entry.
+.\"
+.It Xo
+.Li delete
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar mode
+.Li ;
+.Xc
+Remove a SAD entry.
+.\"
+.It Xo
+.Li flush
+.Op Ar protocol
+.Li ;
+.Xc
+Clear all SAD entries that matches the options.
+.\"
+.It Xo
+.Li dump
+.Op Ar protocol
+.Li ;
+.Xc
+Dumps all SAD entries that matches the options.
+.\"
+.It Xo
+.Li spdadd
+.Ar src_range Ar dst_range Ar upperspec Ar policy
+.Li ;
+.Xc
+Add a SPD entry.
+.\"
+.It Xo
+.Li spddelete
+.Ar src_range Ar dst_range Ar upperspec
+.Li ;
+.Xc
+Delete a SPD entry.
+.\"
+.It Xo
+.Li spdflush
+.Li ;
+.Xc
+Clear all SPD entries.
+.\"
+.It Xo
+.Li spddump
+.Li ;
+.Xc
+Dumps all SAD entries.
+.El
+.\"
+.Pp
+Meta-arguments are as follows:
+.Bl -tag -compact -width Ds
+.It Ar src
+.It Ar dst
+Source/destination of the secure communication is specified as
+IPv4/v6 address.
+.Nm
+does not consult hostname-to-address for arguments
+.Ar src
+and
+.Ar dst .
+They must be in numeric form.
+.\"
+.Pp
+.It Ar protocol
+.Ar protocol
+is one of following:
+.Bl -tag -width Fl -compact
+.It Li esp
+ESP based on rfc2405
+.It Li esp-old
+ESP based on rfc1827
+.It Li ah
+AH based on rfc2402
+.It Li ah-old
+AH based on rfc1826
+.It Li ipcomp
+IPCOMP
+.El
+.\"
+.Pp
+.It Ar spi
+Security Parameter Index (SPI) for the SA and SPD.
+It must be decimal number or hexadecimal number
+.Po
+with
+.Li 0x
+attached
+.Pc .
+.\"
+.Pp
+.It Ar extensions
+takes some of the following:
+.Bl -tag -width Fl -compact
+.It Fl m Ar mode
+Specify an security protocol mode for use. By default,
+.Li any .
+.Ar mode
+is one of following:
+.Li transport , tunnel
+or
+.Li any .
+.It Fl r Ar size
+Specify window size of bytes for replay prevention.
+.Ar size
+must be decimal number in 32-bit word. If
+.Ar size
+is zero or not specified, replay check don't take place.
+.It Fl f Ar pad_option
+.Ar pad_option
+is one of following:
+.Li zero-pad , random-pad
+or
+.Li seq-pad
+.It Fl f Li cyclic-seq
+Allow cyclic sequence number.
+.It Fl lh Ar time
+.It Fl ls Ar time
+Specify hard/soft lifetime.
+.El
+.\"
+.Pp
+.It Ar algorithm
+.Bl -tag -width Fl -compact
+.It Fl E Ar ealgo Ar key
+Specify encryption algorithm.
+.It Fl A Ar ealgo Ar key
+Specify authentication algorithm.
+If
+.Fl A
+is used for esp, it will be treated as ESP payload authentication algorithm.
+.It Fl C Ar calgo Op Fl R
+Specify compression algorithm.
+If
+.Fl R
+is specified with
+.Li ipcomp
+line, the kernel will use well-known IPComp CPI
+.Pq compression parameter index
+on IPComp CPI field on packets, and
+.Ar spi
+field will be ignored.
+.Ar spi
+field is only for kernel internal use in this case.
+.\"Therefore, compression protocol number will appear on IPComp CPI field.
+If
+.Fl R
+is not used,
+the value on
+.Ar spi
+field will appear on IPComp CPI field on outgoing packets.
+.Ar spi
+field needs to be smaller than
+.Li 0x10000
+in this case.
+.El
+.Pp
+.Li esp
+SAs accept
+.Fl E
+and
+.Fl A .
+.Li esp-old
+SAs accept
+.Fl E
+only.
+.Li ah
+and
+.Li ah-old
+SAs accept
+.Fl A
+only.
+.Li ipcomp
+SAs accept
+.Fl C
+only.
+.Pp
+.Ar key
+must be double-quoted character string or a series of hexadecimal digits.
+.Pp
+Possible values for
+.Ar ealgo ,
+.Ar aalgo
+and
+.Ar calgo
+are specified in separate section.
+.\"
+.It Ar src_range
+.It Ar dst_range
+These are selection of the secure communication is specified as
+IPv4/v6 address or IPv4/v6 address range, and it may accompany
+TCP/UDP port specification.
+This takes the following form:
+.Bd -literal -offset
+.Ar address
+.Ar address/prefixlen
+.Ar address[port]
+.Ar address/prefixlen[port]
+.Ed
+.Pp
+.Ar prefixlen
+and
+.Ar port
+must be decimal number.
+The square bracket around
+.Ar port
+is really necessary.
+They are not manpage metacharacters.
+.Pp
+.Nm
+does not consult hostname-to-address for arguments
+.Ar src
+and
+.Ar dst .
+They must be in numeric form.
+.\"
+.It Ar upperspec
+Upper-layer protocol to be used.
+Currently
+.Li tcp ,
+.Li udp
+and
+.Li any
+can be specified.
+.Li any
+stands for
+.Dq any protocol .
+.Pp
+NOTE:
+.Ar upperspec
+does not work against forwarding case at this moment,
+as it requires extra reassembly at forwarding node
+.Pq not implemented as this moment .
+.\"
+.It Ar policy
+.Ar policy
+is the one of following:
+.Bd -literal -offset
+.Xo
+.Fl P
+.Ar direction
+.Li discard
+.Xc
+.Xo
+.Fl P
+.Ar direction
+.Li none
+.Xc
+.Xo
+.Fl P
+.Ar direction
+.Li ipsec
+.Ar protocol/mode/src-dst/level
+.Xc
+.Ed
+.Pp
+You must specify the direction of its policy as
+.Ar direction .
+Either
+.Li out
+or
+.Li in
+are used.
+.Li discard
+means the packet matching indexes will be discarded.
+.Li none
+means that IPsec operation will not take place onto the packet.
+.Li ipsec
+means that IPsec operation will take place onto the packet.
+Either
+.Li ah ,
+.Li esp
+or
+.Li ipcomp
+is to be set as
+.Ar protocol .
+.Ar mode
+is either
+.Li transport
+or
+.Li tunnel .
+You must specify the end-points addresses of the SA as
+.Ar src
+and
+.Ar dst
+with
+.Sq -
+between these addresses which is used to specify the SA to use.
+.Ar level
+is to be one of the following:
+.Li default , use
+or
+.Li require .
+.Li default
+means kernel consults to the system wide default against protocol you
+specified, e.g.
+.Li esp_trans_deflev
+sysctl variable, when kernel processes the packet.
+.Li use
+means that kernel use a SA if it's available,
+otherwise kernel keeps normal operation.
+.Li require
+means SA is required whenever kernel deals with the packet.
+Note that
+.Dq Li discard
+and
+.Dq Li none
+are not in the syntax described in
+.Xr ipsec_set_policy 3 .
+There are little differences in the syntax.
+See
+.Xr ipsec_set_policy 3
+for detail.
+.Pp
+.El
+.Pp
+.\"
+.Sh ALGORITHMS
+The following list shows the supported algorithms.
+.Sy protocol
+and
+.Sy algorithm
+are almost orthogonal.
+Following are the list of authentication algorithms that can be used as
+.Ar aalgo
+in
+.Fl A Ar aalgo
+of
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm keylen (bits) comment
+hmac-md5 128 ah: rfc2403
+ 128 ah-old: rfc2085
+hmac-sha1 160 ah: rfc2404
+ 160 ah-old: 128bit ICV (no document)
+keyed-md5 128 ah: 96bit ICV (no document)
+ 128 ah-old: rfc1828
+keyed-sha1 160 ah: 96bit ICV (no document)
+ 160 ah-old: 128bit ICV (no document)
+null 0 to 2048 for debugging
+.Ed
+.Pp
+Following are the list of encryption algorithms that can be used as
+.Ar ealgo
+in
+.Fl E Ar ealgo
+of
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm keylen (bits) comment
+des-cbc 64 esp-old: rfc1829, esp: rfc2405
+3des-cbc 192 rfc2451
+simple 0 to 2048 rfc2410
+blowfish-cbc 40 to 448 rfc2451
+cast128-cbc 40 to 128 rfc2451
+rc5-cbc 40 to 2040 rfc2451
+des-deriv 64 ipsec-ciph-des-derived-01 (expired)
+3des-deriv 192 no document
+.Ed
+.Pp
+Following are the list of compression algorithms that can be used as
+.Ar calgo
+in
+.Fl C Ar calgo
+of
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm comment
+deflate rfc2394
+lzs rfc2395
+.Ed
+.\"
+.Sh EXAMPLES
+.Bd -literal -offset
+add 3ffe:501:4819::1 3ffe:501:481d::1 esp 123457
+ -E des-cbc "ESP SA!!"
+
+add 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456
+ -A hmac-sha1 "AH SA configuration!" ;
+
+add 10.0.11.41 10.0.11.33 esp 0x10001
+ -E des-cbc "ESP with"
+ -A hmac-md5 "authentication!!" ;
+
+get 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 ;
+
+flush ;
+
+dump esp ;
+
+spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any
+ -P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ;
+
+.Ed
+.\"
+.Sh RETURN VALUES
+The command exits with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr ipsec_set_policy 3 ,
+.Xr sysctl 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+The command was completely re-designed in June 1998.
+.\"
+.\" .Sh BUGS
diff --git a/usr.sbin/setkey/setkey.c b/usr.sbin/setkey/setkey.c
new file mode 100644
index 0000000..73edc3f
--- /dev/null
+++ b/usr.sbin/setkey/setkey.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: setkey.c,v 1.5 1999/10/26 09:39:37 sakane Exp $ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <err.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netkey/key_debug.h>
+#include <netinet6/ipsec.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+
+void Usage __P((void));
+int main __P((int, char **));
+int get_supported __P((void));
+void sendkeyshort __P((u_int));
+void promisc __P((void));
+int sendkeymsg __P((void));
+int postproc __P((struct sadb_msg *, int));
+const char *numstr __P((int));
+void shortdump_hdr __P((void));
+void shortdump __P((struct sadb_msg *));
+
+#define MODE_SCRIPT 1
+#define MODE_CMDDUMP 2
+#define MODE_CMDFLUSH 3
+
+int so;
+
+int f_forever = 0;
+int f_all = 0;
+int f_debug = 0;
+int f_verbose = 0;
+int f_mode = 0;
+int f_cmddump = 0;
+int f_policy = 0;
+int f_promisc = 0;
+int f_hexdump = 0;
+char *pname;
+
+u_char m_buf[BUFSIZ];
+u_int m_len;
+
+extern int lineno;
+
+extern int parse __P((FILE **));
+
+void
+Usage()
+{
+ printf("Usage:\t%s [-dv] -c\n", pname);
+ printf("\t%s [-dv] -f (file)\n", pname);
+ printf("\t%s [-Padlv] -D\n", pname);
+ printf("\t%s [-Pdv] -F\n", pname);
+ printf("\t%s [-h] -x\n", pname);
+ pfkey_close(so);
+ exit(0);
+}
+
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ FILE *fp = stdin;
+ int c;
+
+ pname = *av;
+
+ if (ac == 1) Usage();
+
+ while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) {
+ switch (c) {
+ case 'c':
+ f_mode = MODE_SCRIPT;
+ fp = stdin;
+ break;
+ case 'f':
+ f_mode = MODE_SCRIPT;
+ if ((fp = fopen(optarg, "r")) == NULL) {
+ err(-1, "fopen");
+ /*NOTREACHED*/
+ }
+ break;
+ case 'D':
+ f_mode = MODE_CMDDUMP;
+ break;
+ case 'F':
+ f_mode = MODE_CMDFLUSH;
+ break;
+ case 'a':
+ f_all = 1;
+ break;
+ case 'l':
+ f_forever = 1;
+ break;
+ case 'h':
+ f_hexdump = 1;
+ break;
+ case 'x':
+ f_promisc = 1;
+ promisc();
+ /*NOTREACHED*/
+ case 'P':
+ f_policy = 1;
+ break;
+ case 'd':
+ f_debug = 1;
+ break;
+ case 'v':
+ f_verbose = 1;
+ break;
+ default:
+ Usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ switch (f_mode) {
+ case MODE_CMDDUMP:
+ sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP);
+ break;
+ case MODE_CMDFLUSH:
+ sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
+ pfkey_close(so);
+ break;
+ case MODE_SCRIPT:
+ if (get_supported() < 0) {
+ errx(-1, "%s", ipsec_strerror());
+ /*NOTREACHED*/
+ }
+ parse(&fp);
+ break;
+ default:
+ Usage();
+ }
+
+ exit(0);
+}
+
+int
+get_supported()
+{
+ int so;
+
+ if ((so = pfkey_open()) < 0) {
+ perror("pfkey_open");
+ return -1;
+ }
+
+ /* debug mode ? */
+ if (f_debug)
+ return 0;
+
+ if (pfkey_send_register(so, PF_UNSPEC) < 0)
+ return -1;
+
+ if (pfkey_recv_register(so) < 0)
+ return -1;
+
+ return 0;
+}
+
+void
+sendkeyshort(type)
+ u_int type;
+{
+ struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
+
+ m_len = sizeof(struct sadb_msg);
+
+ m_msg->sadb_msg_version = PF_KEY_V2;
+ m_msg->sadb_msg_type = type;
+ m_msg->sadb_msg_errno = 0;
+ m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
+ m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_seq = 0;
+ m_msg->sadb_msg_pid = getpid();
+
+ sendkeymsg();
+
+ return;
+}
+
+void
+promisc()
+{
+ struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
+ u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+ int so, len;
+
+ m_len = sizeof(struct sadb_msg);
+
+ m_msg->sadb_msg_version = PF_KEY_V2;
+ m_msg->sadb_msg_type = SADB_X_PROMISC;
+ m_msg->sadb_msg_errno = 0;
+ m_msg->sadb_msg_satype = 1;
+ m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_reserved = 0;
+ m_msg->sadb_msg_seq = 0;
+ m_msg->sadb_msg_pid = getpid();
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ err(1, "socket(PF_KEY)");
+ /*NOTREACHED*/
+ }
+
+ if ((len = send(so, m_buf, m_len, 0)) < 0) {
+ err(1, "send");
+ /*NOTREACHED*/
+ }
+
+ while (1) {
+ struct sadb_msg *base;
+
+ if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
+ err(1, "recv");
+ /*NOTREACHED*/
+ }
+
+ if (len != sizeof(*base))
+ continue;
+
+ base = (struct sadb_msg *)rbuf;
+ if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
+ 0)) < 0) {
+ err(1, "recv");
+ /*NOTREACHED*/
+ }
+ if (f_hexdump) {
+ int i;
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0)
+ printf("%08x: ", i);
+ printf("%02x ", rbuf[i] & 0xff);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ if (len % 16)
+ printf("\n");
+ }
+ /* adjust base pointer for promisc mode */
+ if (base->sadb_msg_type == SADB_X_PROMISC) {
+ if (sizeof(*base) < len)
+ base++;
+ else
+ base = NULL;
+ }
+ if (base) {
+ kdebug_sadb(base);
+ printf("\n");
+ fflush(stdout);
+ }
+ }
+}
+
+int
+sendkeymsg()
+{
+ int so;
+
+ u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+ int len;
+ struct sadb_msg *msg;
+
+ if ((so = pfkey_open()) < 0) {
+ perror("pfkey_open");
+ return -1;
+ }
+
+ {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ perror("setsockopt");
+ goto end;
+ }
+ }
+
+ if (f_forever)
+ shortdump_hdr();
+again:
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)m_buf);
+
+ if ((len = send(so, m_buf, m_len, 0)) < 0) {
+ perror("send");
+ goto end;
+ }
+
+ msg = (struct sadb_msg *)rbuf;
+ do {
+ if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+ perror("recv");
+ goto end;
+ }
+
+ if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) {
+ warnx("invalid keymsg length");
+ break;
+ }
+
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)rbuf);
+ if (postproc(msg, len) < 0)
+ break;
+ } while (msg->sadb_msg_errno || msg->sadb_msg_seq);
+
+ if (f_forever) {
+ fflush(stdout);
+ sleep(1);
+ goto again;
+ }
+
+end:
+ pfkey_close(so);
+ return(0);
+}
+
+int
+postproc(msg, len)
+ struct sadb_msg *msg;
+ int len;
+{
+
+ if (msg->sadb_msg_errno != 0) {
+ char inf[80];
+ char *errmsg = NULL;
+
+ if (f_mode == MODE_SCRIPT)
+ snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
+ else
+ inf[0] = '\0';
+
+ switch (msg->sadb_msg_errno) {
+ case ENOENT:
+ switch (msg->sadb_msg_type) {
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_X_SPDDELETE:
+ errmsg = "No entry";
+ break;
+ case SADB_DUMP:
+ errmsg = "No SAD entries";
+ break;
+ case SADB_X_SPDDUMP:
+ errmsg = "No SPD entries";
+ break;
+ }
+ break;
+ default:
+ errmsg = strerror(msg->sadb_msg_errno);
+ }
+ printf("%s%s.\n", inf, errmsg);
+ return(-1);
+ }
+
+ switch (msg->sadb_msg_type) {
+ case SADB_GET:
+ pfkey_sadump(msg);
+ break;
+
+ case SADB_DUMP:
+ /* filter out DEAD SAs */
+ if (!f_all) {
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_sa *sa;
+ pfkey_align(msg, mhp);
+ pfkey_check(mhp);
+ if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
+ if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
+ break;
+ }
+ }
+ if (f_forever)
+ shortdump(msg);
+ else
+ pfkey_sadump(msg);
+ msg = (struct sadb_msg *)((caddr_t)msg +
+ PFKEY_UNUNIT64(msg->sadb_msg_len));
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)msg);
+ break;
+
+ case SADB_X_SPDDUMP:
+ pfkey_spdump(msg);
+ if (msg->sadb_msg_seq == 0) break;
+ msg = (struct sadb_msg *)((caddr_t)msg +
+ PFKEY_UNUNIT64(msg->sadb_msg_len));
+ if (f_verbose)
+ kdebug_sadb((struct sadb_msg *)msg);
+ break;
+ }
+
+ return(0);
+}
+
+/*------------------------------------------------------------*/
+static char *satype[] = {
+ NULL, NULL, "ah", "esp"
+};
+static char *sastate[] = {
+ "L", "M", "D", "d"
+};
+static char *ipproto[] = {
+/*0*/ "ip", "icmp", "igmp", "ggp", "ip4",
+ NULL, "tcp", NULL, "egp", NULL,
+/*10*/ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "udp", NULL, NULL,
+/*20*/ NULL, NULL, "idp", NULL, NULL,
+ NULL, NULL, NULL, NULL, "tp",
+/*30*/ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+/*40*/ NULL, "ip6", NULL, "rt6", "frag6",
+ NULL, "rsvp", "gre", NULL, NULL,
+/*50*/ "esp", "ah", NULL, NULL, NULL,
+ NULL, NULL, NULL, "icmp6", "none",
+/*60*/ "dst6",
+};
+
+#define STR_OR_ID(x, tab) \
+ (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x))
+
+const char *
+numstr(x)
+ int x;
+{
+ static char buf[20];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+shortdump_hdr()
+{
+ printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
+ "time", "p", "s", "spi", "ltime", "src", "dst");
+}
+
+void
+shortdump(msg)
+ struct sadb_msg *msg;
+{
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ char buf[1024], pbuf[10];
+ struct sadb_sa *sa;
+ struct sadb_address *saddr;
+ struct sadb_lifetime *lts, *lth, *ltc;
+ struct sockaddr *s;
+ u_int t;
+ time_t cur = time(0);
+
+ pfkey_align(msg, mhp);
+ pfkey_check(mhp);
+
+ printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
+
+ printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
+
+ if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
+ printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
+ printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
+ } else
+ printf("%-1s %-8s", "?", "?");
+
+ lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
+ lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+ ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
+ if (lts && lth && ltc) {
+ if (ltc->sadb_lifetime_addtime == 0)
+ t = (u_long)0;
+ else
+ t = (u_long)(cur - ltc->sadb_lifetime_addtime);
+ if (t >= 1000)
+ strcpy(buf, " big/");
+ else
+ snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
+ printf("%s", buf);
+
+ t = (u_long)lth->sadb_lifetime_addtime;
+ if (t >= 1000)
+ strcpy(buf, "big");
+ else
+ snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
+ printf("%s", buf);
+ } else
+ printf(" ???/???");
+
+ printf(" ");
+
+ if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
+ if (saddr->sadb_address_proto)
+ printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
+ s = (struct sockaddr *)(saddr + 1);
+ getnameinfo(s, s->sa_len, buf, sizeof(buf),
+ pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
+ if (strcmp(pbuf, "0") != 0)
+ printf("%s[%s]", buf, pbuf);
+ else
+ printf("%s", buf);
+ } else
+ printf("?");
+
+ printf(" -> ");
+
+ if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
+ if (saddr->sadb_address_proto)
+ printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
+
+ s = (struct sockaddr *)(saddr + 1);
+ getnameinfo(s, s->sa_len, buf, sizeof(buf),
+ pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
+ if (strcmp(pbuf, "0") != 0)
+ printf("%s[%s]", buf, pbuf);
+ else
+ printf("%s", buf);
+ } else
+ printf("?");
+
+ printf("\n");
+}
diff --git a/usr.sbin/setkey/test-pfkey.c b/usr.sbin/setkey/test-pfkey.c
new file mode 100644
index 0000000..849aba3
--- /dev/null
+++ b/usr.sbin/setkey/test-pfkey.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/* KAME $Id: test-pfkey.c,v 1.2 1999/10/26 08:09:17 itojun Exp $ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <net/pfkeyv2.h>
+#include <netinet/in.h>
+#include <netkey/keydb.h>
+#include <netkey/key_var.h>
+#include <netkey/key_debug.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+u_char m_buf[BUFSIZ];
+u_int m_len;
+char *pname;
+
+void Usage __P((void));
+int sendkeymsg __P((void));
+void key_setsadbmsg __P((u_int));
+void key_setsadbsens __P((void));
+void key_setsadbprop __P((void));
+void key_setsadbid __P((u_int, caddr_t));
+void key_setsadblft __P((u_int, u_int));
+void key_setspirange __P((void));
+void key_setsadbkey __P((u_int, caddr_t));
+void key_setsadbsa __P((void));
+void key_setsadbaddr __P((u_int, u_int, caddr_t));
+void key_setsadbextbuf __P((caddr_t, int, caddr_t, int, caddr_t, int));
+
+void
+Usage()
+{
+ printf("Usage:\t%s number\n", pname);
+ exit(0);
+}
+
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ pname = *av;
+
+ if (ac == 1) Usage();
+
+ key_setsadbmsg(atoi(*(av+1)));
+ sendkeymsg();
+
+ exit(0);
+}
+
+/* %%% */
+int
+sendkeymsg()
+{
+ u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+ int so, len;
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ perror("socket(PF_KEY)");
+ goto end;
+ }
+
+ pfkey_sadump((struct sadb_msg *)m_buf);
+
+ if ((len = send(so, m_buf, m_len, 0)) < 0) {
+ perror("send");
+ goto end;
+ }
+
+ if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+ perror("recv");
+ goto end;
+ }
+
+ pfkey_sadump((struct sadb_msg *)rbuf);
+
+end:
+ (void)close(so);
+ return(0);
+}
+
+void
+key_setsadbmsg(type)
+ u_int type;
+{
+ struct sadb_msg m_msg;
+
+ m_msg.sadb_msg_version = PF_KEY_V2;
+ m_msg.sadb_msg_type = type;
+ m_msg.sadb_msg_errno = 0;
+ m_msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ m_msg.sadb_msg_reserved = 0;
+ m_msg.sadb_msg_seq = 0;
+ m_msg.sadb_msg_pid = getpid();
+
+ m_len = sizeof(struct sadb_msg);
+ memcpy(m_buf, &m_msg, m_len);
+
+ switch (type) {
+ case SADB_GETSPI:
+ /*<base, address(SD), SPI range>*/
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "127.0.0.1");
+ key_setspirange();
+ /*<base, SA(*), address(SD)>*/
+ break;
+
+ case SADB_ADD:
+ /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ key(AE), (identity(SD),) (sensitivity)> */
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ case SADB_UPDATE:
+ key_setsadbsa();
+ key_setsadblft(SADB_EXT_LIFETIME_HARD, 10);
+ key_setsadblft(SADB_EXT_LIFETIME_SOFT, 5);
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ /* XXX key_setsadbkey(SADB_EXT_KEY_AUTH, "abcde"); */
+ key_setsadbkey(SADB_EXT_KEY_AUTH, "1234567812345678");
+ key_setsadbkey(SADB_EXT_KEY_ENCRYPT, "12345678");
+ key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com");
+ key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net");
+ key_setsadbsens();
+ /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ (identity(SD),) (sensitivity)> */
+ break;
+
+ case SADB_DELETE:
+ /* <base, SA(*), address(SDP)> */
+ key_setsadbsa();
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ /* <base, SA(*), address(SDP)> */
+ break;
+
+ case SADB_GET:
+ /* <base, SA(*), address(SDP)> */
+ key_setsadbsa();
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ key(AE), (identity(SD),) (sensitivity)> */
+ break;
+
+ case SADB_ACQUIRE:
+ /* <base, address(SD), (address(P),) (identity(SD),)
+ (sensitivity,) proposal> */
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+ key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com");
+ key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net");
+ key_setsadbsens();
+ key_setsadbprop();
+ /* <base, address(SD), (address(P),) (identity(SD),)
+ (sensitivity,) proposal> */
+ break;
+
+ case SADB_REGISTER:
+ /* <base> */
+ /* <base, supported> */
+ break;
+
+ case SADB_EXPIRE:
+ case SADB_FLUSH:
+ break;
+
+ case SADB_DUMP:
+ break;
+
+ case SADB_X_PROMISC:
+ /* <base> */
+ /* <base, base(, others)> */
+ break;
+
+ case SADB_X_PCHANGE:
+ break;
+
+ /* for SPD management */
+ case SADB_X_SPDFLUSH:
+ case SADB_X_SPDDUMP:
+ break;
+
+ case SADB_X_SPDADD:
+ case SADB_X_SPDDELETE:
+ key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+ key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+ break;
+ }
+
+ ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len);
+
+ return;
+}
+
+void
+key_setsadbsens()
+{
+ struct sadb_sens m_sens;
+ u_char buf[64];
+ u_int s, i, slen, ilen, len;
+
+ /* make sens & integ */
+ s = htonl(0x01234567);
+ i = htonl(0x89abcdef);
+ slen = sizeof(s);
+ ilen = sizeof(i);
+ memcpy(buf, &s, slen);
+ memcpy(buf + slen, &i, ilen);
+
+ len = sizeof(m_sens) + PFKEY_ALIGN8(slen) + PFKEY_ALIGN8(ilen);
+ m_sens.sadb_sens_len = PFKEY_UNIT64(len);
+ m_sens.sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+ m_sens.sadb_sens_dpd = 1;
+ m_sens.sadb_sens_sens_level = 2;
+ m_sens.sadb_sens_sens_len = PFKEY_ALIGN8(slen);
+ m_sens.sadb_sens_integ_level = 3;
+ m_sens.sadb_sens_integ_len = PFKEY_ALIGN8(ilen);
+ m_sens.sadb_sens_reserved = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_sens, sizeof(struct sadb_sens),
+ buf, slen + ilen);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbprop()
+{
+ struct sadb_prop m_prop;
+ struct sadb_comb *m_comb;
+ u_char buf[256];
+ u_int len = sizeof(m_prop) + sizeof(m_comb) * 2;
+
+ /* make prop & comb */
+ m_prop.sadb_prop_len = PFKEY_UNIT64(len);
+ m_prop.sadb_prop_exttype = SADB_EXT_PROPOSAL;
+ m_prop.sadb_prop_replay = 0;
+ m_prop.sadb_prop_reserved[0] = 0;
+ m_prop.sadb_prop_reserved[1] = 0;
+ m_prop.sadb_prop_reserved[2] = 0;
+
+ /* the 1st is ESP DES-CBC HMAC-MD5 */
+ m_comb = (struct sadb_comb *)buf;
+ m_comb->sadb_comb_auth = SADB_AALG_MD5HMAC;
+ m_comb->sadb_comb_encrypt = SADB_EALG_DESCBC;
+ m_comb->sadb_comb_flags = 0;
+ m_comb->sadb_comb_auth_minbits = 8;
+ m_comb->sadb_comb_auth_maxbits = 96;
+ m_comb->sadb_comb_encrypt_minbits = 64;
+ m_comb->sadb_comb_encrypt_maxbits = 64;
+ m_comb->sadb_comb_reserved = 0;
+ m_comb->sadb_comb_soft_allocations = 0;
+ m_comb->sadb_comb_hard_allocations = 0;
+ m_comb->sadb_comb_soft_bytes = 0;
+ m_comb->sadb_comb_hard_bytes = 0;
+ m_comb->sadb_comb_soft_addtime = 0;
+ m_comb->sadb_comb_hard_addtime = 0;
+ m_comb->sadb_comb_soft_usetime = 0;
+ m_comb->sadb_comb_hard_usetime = 0;
+
+ /* the 2st is ESP 3DES-CBC and AH HMAC-SHA1 */
+ m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb));
+ m_comb->sadb_comb_auth = SADB_AALG_SHA1HMAC;
+ m_comb->sadb_comb_encrypt = SADB_EALG_3DESCBC;
+ m_comb->sadb_comb_flags = 0;
+ m_comb->sadb_comb_auth_minbits = 8;
+ m_comb->sadb_comb_auth_maxbits = 96;
+ m_comb->sadb_comb_encrypt_minbits = 64;
+ m_comb->sadb_comb_encrypt_maxbits = 64;
+ m_comb->sadb_comb_reserved = 0;
+ m_comb->sadb_comb_soft_allocations = 0;
+ m_comb->sadb_comb_hard_allocations = 0;
+ m_comb->sadb_comb_soft_bytes = 0;
+ m_comb->sadb_comb_hard_bytes = 0;
+ m_comb->sadb_comb_soft_addtime = 0;
+ m_comb->sadb_comb_hard_addtime = 0;
+ m_comb->sadb_comb_soft_usetime = 0;
+ m_comb->sadb_comb_hard_usetime = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_prop, sizeof(struct sadb_prop),
+ buf, sizeof(*m_comb) * 2);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbid(ext, str)
+ u_int ext;
+ caddr_t str;
+{
+ struct sadb_ident m_id;
+ u_int idlen = strlen(str), len;
+
+ len = sizeof(m_id) + PFKEY_ALIGN8(idlen);
+ m_id.sadb_ident_len = PFKEY_UNIT64(len);
+ m_id.sadb_ident_exttype = ext;
+ m_id.sadb_ident_type = SADB_IDENTTYPE_USERFQDN;
+ m_id.sadb_ident_reserved = 0;
+ m_id.sadb_ident_id = getpid();
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_id, sizeof(struct sadb_ident),
+ str, idlen);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadblft(ext, time)
+ u_int ext, time;
+{
+ struct sadb_lifetime m_lft;
+
+ m_lft.sadb_lifetime_len = PFKEY_UNIT64(sizeof(m_lft));
+ m_lft.sadb_lifetime_exttype = ext;
+ m_lft.sadb_lifetime_allocations = 0x2;
+ m_lft.sadb_lifetime_bytes = 0x1000;
+ m_lft.sadb_lifetime_addtime = time;
+ m_lft.sadb_lifetime_usetime = 0x0020;
+
+ memcpy(m_buf + m_len, &m_lft, sizeof(struct sadb_lifetime));
+ m_len += sizeof(struct sadb_lifetime);
+
+ return;
+}
+
+void
+key_setspirange()
+{
+ struct sadb_spirange m_spi;
+
+ m_spi.sadb_spirange_len = PFKEY_UNIT64(sizeof(m_spi));
+ m_spi.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ m_spi.sadb_spirange_min = 0x00001000;
+ m_spi.sadb_spirange_max = 0x00002000;
+ m_spi.sadb_spirange_reserved = 0;
+
+ memcpy(m_buf + m_len, &m_spi, sizeof(struct sadb_spirange));
+ m_len += sizeof(struct sadb_spirange);
+
+ return;
+}
+
+void
+key_setsadbkey(ext, str)
+ u_int ext;
+ caddr_t str;
+{
+ struct sadb_key m_key;
+ u_int keylen = strlen(str);
+ u_int len;
+
+ len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+ m_key.sadb_key_len = PFKEY_UNIT64(len);
+ m_key.sadb_key_exttype = ext;
+ m_key.sadb_key_bits = keylen * 8;
+ m_key.sadb_key_reserved = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_key, sizeof(struct sadb_key),
+ str, keylen);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbsa()
+{
+ struct sadb_sa m_sa;
+
+ m_sa.sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa));
+ m_sa.sadb_sa_exttype = SADB_EXT_SA;
+ m_sa.sadb_sa_spi = htonl(0x12345678);
+ m_sa.sadb_sa_replay = 4;
+ m_sa.sadb_sa_state = 0;
+ m_sa.sadb_sa_auth = SADB_AALG_MD5HMAC;
+ m_sa.sadb_sa_encrypt = SADB_EALG_DESCBC;
+ m_sa.sadb_sa_flags = 0;
+
+ memcpy(m_buf + m_len, &m_sa, sizeof(struct sadb_sa));
+ m_len += sizeof(struct sadb_sa);
+
+ return;
+}
+
+void
+key_setsadbaddr(ext, af, str)
+ u_int ext, af;
+ caddr_t str;
+{
+ struct sadb_address m_addr;
+ u_char abuf[64];
+ struct sockaddr *a = (struct sockaddr *)abuf;
+ u_int len;
+
+ /* make sockaddr buffer */
+ memset(abuf, 0, sizeof(abuf));
+ a->sa_len = _SALENBYAF(af);
+ a->sa_family = af;
+ _INPORTBYSA(a) =
+ (ext == SADB_EXT_ADDRESS_PROXY ? 0 : htons(0x1234));
+ if (inet_pton(af, str, _INADDRBYSA(a)) != 1)
+ ; /* XXX do something */
+
+ len = sizeof(struct sadb_address) + PFKEY_ALIGN8(a->sa_len);
+ m_addr.sadb_address_len = PFKEY_UNIT64(len);
+ m_addr.sadb_address_exttype = ext;
+ m_addr.sadb_address_proto =
+ (ext == SADB_EXT_ADDRESS_PROXY ? 0 : IPPROTO_TCP);
+ m_addr.sadb_address_prefixlen = _INALENBYAF(af);
+ m_addr.sadb_address_reserved = 0;
+
+ key_setsadbextbuf(m_buf, m_len,
+ (caddr_t)&m_addr, sizeof(struct sadb_address),
+ abuf, a->sa_len);
+ m_len += len;
+
+ return;
+}
+
+void
+key_setsadbextbuf(dst, off, ebuf, elen, vbuf, vlen)
+ caddr_t dst, ebuf, vbuf;
+ int off, elen, vlen;
+{
+ memset(dst + off, 0, elen + vlen);
+ memcpy(dst + off, (caddr_t)ebuf, elen);
+ memcpy(dst + off + elen, vbuf, vlen);
+
+ return;
+}
+
diff --git a/usr.sbin/setkey/test-policy.c b/usr.sbin/setkey/test-policy.c
new file mode 100644
index 0000000..27cd478
--- /dev/null
+++ b/usr.sbin/setkey/test-policy.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet6/in6.h>
+#include <netkey/keyv2.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet6/ipsec.h>
+
+char *requests[] = {
+"must_error", /* must be error */
+"ipsec must_error", /* must be error */
+"ipsec esp/must_error", /* must be error */
+"discard",
+"none",
+"entrust",
+"bypass", /* may be error */
+"ipsec esp", /* must be error */
+"ipsec ah/require",
+"ipsec ah/use/",
+"ipsec esp/require ah/default/203.178.141.194",
+"ipsec ah/use/203.178.141.195 esp/use/203.178.141.194",
+"ipsec esp/elf.wide.ydc.co.jp esp/www.wide.ydc.co.jp"
+"
+ipsec esp/require ah/use esp/require/10.0.0.1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1
+ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1ah/use/3ffe:501:481d::1
+",
+};
+
+u_char *p_secpolicy;
+
+int test(char *buf, int family);
+char *setpolicy(char *req);
+
+main()
+{
+ int i;
+ char *buf;
+
+ for (i = 0; i < sizeof(requests)/sizeof(requests[0]); i++) {
+ printf("* requests:[%s]\n", requests[i]);
+ if ((buf = setpolicy(requests[i])) == NULL)
+ continue;
+ printf("\tsetlen:%d\n", PFKEY_EXTLEN(buf));
+
+ printf("\tPF_INET:\n");
+ test(buf, PF_INET);
+
+ printf("\tPF_INET6:\n");
+ test(buf, PF_INET6);
+ free(buf);
+ }
+}
+
+int test(char *policy, int family)
+{
+ int so, proto, optname;
+ int len;
+ char getbuf[1024];
+
+ switch (family) {
+ case PF_INET:
+ proto = IPPROTO_IP;
+ optname = IP_IPSEC_POLICY;
+ break;
+ case PF_INET6:
+ proto = IPPROTO_IPV6;
+ optname = IPV6_IPSEC_POLICY;
+ break;
+ }
+
+ if ((so = socket(family, SOCK_DGRAM, 0)) < 0)
+ perror("socket");
+
+ if (setsockopt(so, proto, optname, policy, PFKEY_EXTLEN(policy)) < 0)
+ perror("setsockopt");
+
+ len = sizeof(getbuf);
+ memset(getbuf, 0, sizeof(getbuf));
+ if (getsockopt(so, proto, optname, getbuf, &len) < 0)
+ perror("getsockopt");
+
+ {
+ char *buf = NULL;
+
+ printf("\tgetlen:%d\n", len);
+
+ if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL)
+ ipsec_strerror();
+ else
+ printf("\t[%s]\n", buf);
+
+ free(buf);
+ }
+
+ close (so);
+}
+
+char *setpolicy(char *req)
+{
+ int len;
+ char *buf;
+
+ if ((len = ipsec_get_policylen(req)) < 0) {
+ printf("ipsec_get_policylen: %s\n", ipsec_strerror());
+ return NULL;
+ }
+
+ if ((buf = malloc(len)) == NULL) {
+ perror("malloc");
+ return NULL;
+ }
+
+ if ((len = ipsec_set_policy(buf, len, req)) < 0) {
+ printf("ipsec_set_policy: %s\n", ipsec_strerror());
+ free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/usr.sbin/setkey/token.l b/usr.sbin/setkey/token.l
new file mode 100644
index 0000000..b75fd45
--- /dev/null
+++ b/usr.sbin/setkey/token.l
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netkey/key_debug.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "vchar.h"
+#include "y.tab.h"
+
+#define DECHO \
+ if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); }
+
+#define CMDARG \
+{ \
+ char *__buf__ = strdup(yytext), *__p__; \
+ for (__p__ = __buf__; *__p__ != NULL; __p__++) \
+ if (*__p__ == '\n' || *__p__ == '\t') \
+ *__p__ = ' '; \
+ strcat(cmdarg, __buf__); \
+ free(__buf__); \
+}
+
+#define PREPROC DECHO CMDARG
+
+int lineno = 1;
+char cmdarg[8192]; /* XXX: BUFSIZ is the better ? */
+
+extern u_char m_buf[BUFSIZ];
+extern u_int m_len;
+extern int f_debug;
+
+int yylex __P((void));
+void yyerror __P((char *s));
+extern void parse_init __P((void));
+int parse __P((FILE **));
+int yyparse __P((void));
+
+%}
+
+/* common section */
+nl \n
+ws [ \t]+
+digit [0-9]
+letter [0-9A-Za-z]
+hexdigit [0-9A-Fa-f]
+/*octet (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5])))*/
+special [()+\|\?\*,]
+dot \.
+comma \,
+hyphen \-
+colon \:
+slash \/
+bcl \{
+ecl \}
+blcl \[
+elcl \]
+percent \%
+semi \;
+usec {dot}{digit}{1,6}
+comment \#.*
+ccomment "/*"
+bracketstring \<[^>]*\>
+quotedstring \"[^"]*\"
+decstring {digit}+
+hexpair {hexdigit}{hexdigit}
+hexstring 0[xX]{hexdigit}+
+octetstring {octet}({dot}{octet})+
+ipaddress {ipv4addr}|{ipv6addr}
+ipv4addr {digit}{1,3}({dot}{digit}{1,3}){0,3}
+ipv6addr {hexdigit}{0,4}({colon}{hexdigit}{0,4}){2,7}(@{letter}{letter}+)?
+ipaddrmask {slash}{digit}{1,3}
+ipaddrport {blcl}{decstring}{elcl}
+keyword {letter}{letter}+
+name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))*
+hostname {name}(({dot}{name})+{dot}?)?
+
+%s S_PL
+
+%%
+
+add { PREPROC; return(ADD); }
+delete { PREPROC; return(DELETE); }
+get { PREPROC; return(GET); }
+flush { PREPROC; return(FLUSH); }
+dump { PREPROC; return(DUMP); }
+
+ /* for management SPD */
+spdadd { PREPROC; return(SPDADD); }
+spddelete { PREPROC; return(SPDDELETE); }
+spddump { PREPROC; return(SPDDUMP); }
+spdflush { PREPROC; return(SPDFLUSH); }
+{hyphen}P { BEGIN S_PL; PREPROC; return(F_POLICY); }
+<S_PL>[a-zA-Z0-9:\.\-_/ \n\t][a-zA-Z0-9:\.\-_/ \n\t]* {
+ yymore();
+
+ /* count up for nl */
+ {
+ char *p;
+ for (p = yytext; *p != NULL; p++)
+ if (*p == '\n')
+ lineno++;
+ }
+
+ yylval.val.len = strlen(yytext);
+ yylval.val.buf = strdup(yytext);
+
+ return(PL_REQUESTS);
+}
+<S_PL>{semi} { PREPROC; BEGIN INITIAL; return(EOT); }
+
+ /* security protocols */
+ah { PREPROC; yylval.num = 0; return(PR_AH); }
+esp { PREPROC; yylval.num = 0; return(PR_ESP); }
+ah-old { PREPROC; yylval.num = 1; return(PR_AH); }
+esp-old { PREPROC; yylval.num = 1; return(PR_ESP); }
+ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); }
+
+ /* authentication alogorithm */
+{hyphen}A { PREPROC; return(F_AUTH); }
+hmac-md5 { PREPROC; yylval.num = SADB_AALG_MD5HMAC; return(ALG_AUTH); }
+hmac-sha1 { PREPROC; yylval.num = SADB_AALG_SHA1HMAC; return(ALG_AUTH); }
+keyed-md5 { PREPROC; yylval.num = SADB_AALG_MD5; return(ALG_AUTH); }
+keyed-sha1 { PREPROC; yylval.num = SADB_AALG_SHA; return(ALG_AUTH); }
+null { PREPROC; yylval.num = SADB_AALG_NULL; return(ALG_AUTH); }
+
+ /* encryption alogorithm */
+{hyphen}E { PREPROC; return(F_ENC); }
+des-cbc { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC); }
+3des-cbc { PREPROC; yylval.num = SADB_EALG_3DESCBC; return(ALG_ENC); }
+simple { PREPROC; yylval.num = SADB_EALG_NULL; return(ALG_ENC); }
+blowfish-cbc { PREPROC; yylval.num = SADB_EALG_BLOWFISHCBC; return(ALG_ENC); }
+cast128-cbc { PREPROC; yylval.num = SADB_EALG_CAST128CBC; return(ALG_ENC); }
+rc5-cbc { PREPROC; yylval.num = SADB_EALG_RC5CBC; return(ALG_ENC); }
+des-deriv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DESDERIV); }
+des-32iv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DES32IV); }
+
+ /* compression algorithms */
+{hyphen}C { PREPROC; return(F_COMP); }
+oui { PREPROC; yylval.num = SADB_X_CALG_OUI; return(ALG_COMP); }
+deflate { PREPROC; yylval.num = SADB_X_CALG_DEFLATE; return(ALG_COMP); }
+lzs { PREPROC; yylval.num = SADB_X_CALG_LZS; return(ALG_COMP); }
+{hyphen}R { PREPROC; return(F_RAWCPI); }
+
+ /* extension */
+{hyphen}m { PREPROC; return(F_MODE); }
+transport { PREPROC; yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
+tunnel { PREPROC; yylval.num = IPSEC_MODE_TUNNEL; return(MODE); }
+{hyphen}f { PREPROC; return(F_EXT); }
+random-pad { PREPROC; yylval.num = SADB_X_EXT_PRAND; return(EXTENSION); }
+seq-pad { PREPROC; yylval.num = SADB_X_EXT_PSEQ; return(EXTENSION); }
+zero-pad { PREPROC; yylval.num = SADB_X_EXT_PZERO; return(EXTENSION); }
+cyclic-seq { PREPROC; yylval.num = SADB_X_EXT_CYCSEQ; return(EXTENSION); }
+{hyphen}r { PREPROC; return(F_REPLAY); }
+{hyphen}lh { PREPROC; return(F_LIFETIME_HARD); }
+{hyphen}ls { PREPROC; return(F_LIFETIME_SOFT); }
+
+
+ /* upper layer protocols */
+icmp { PREPROC; yylval.num = IPPROTO_ICMP; return(UP_PROTO); }
+icmp6 { PREPROC; yylval.num = IPPROTO_ICMPV6; return(UP_PROTO); }
+tcp { PREPROC; yylval.num = IPPROTO_TCP; return(UP_PROTO); }
+udp { PREPROC; yylval.num = IPPROTO_UDP; return(UP_PROTO); }
+
+ /* ... */
+any { PREPROC; return(ANY); }
+{ws} { PREPROC; }
+{nl} { lineno++; }
+{comment}
+{semi} { PREPROC; return(EOT); }
+
+ /* parameter */
+{decstring} {
+ char *bp;
+
+ PREPROC;
+ yylval.num = strtol(yytext, &bp, 10);
+ return(DECSTRING);
+ }
+
+{ipv4addr} {
+ /*
+ * I can't supprt the type without dot,
+ * because it's umbiguous against {decstring}.
+ * e.g. 127
+ */
+ PREPROC;
+
+ yylval.val.len = sizeof(struct sockaddr_in);
+ yylval.val.buf = strdup(yytext);
+
+ return(IP4_ADDRESS);
+ }
+
+{ipv6addr} {
+#ifdef INET6
+ PREPROC;
+
+ yylval.val.len = sizeof(struct sockaddr_in6);
+ yylval.val.buf = strdup(yytext);
+
+ return(IP6_ADDRESS);
+#else
+ yyerror("IPv6 address not supported");
+#endif
+ }
+
+{ipaddrmask} {
+ PREPROC;
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(PREFIX);
+ }
+
+{ipaddrport} {
+ char *p = yytext;
+ PREPROC;
+ while (*++p != ']') ;
+ *p = NULL;
+ yytext++;
+ yylval.num = atoi(yytext);
+ return(PORT);
+ }
+
+{blcl}any{elcl} {
+ char *p = yytext;
+ PREPROC;
+ return(PORTANY);
+ }
+
+{hexstring} {
+ int len = yyleng - 2; /* (str - "0x") */
+ PREPROC;
+ yylval.val.len = (len & 1) + (len / 2);
+ /* fixed string if length is odd. */
+ if (len & 1) {
+ yytext[1] = '0';
+ yylval.val.buf = strdup(yytext + 1);
+ } else
+ yylval.val.buf = strdup(yytext + 2);
+
+ return(HEXSTRING);
+ }
+
+{quotedstring} {
+ char *p = yytext;
+ PREPROC;
+ while (*++p != '"') ;
+ *p = NULL;
+ yytext++;
+ yylval.val.len = yyleng - 2;
+ yylval.val.buf = strdup(yytext);
+
+ return(QUOTEDSTRING);
+ }
+
+. { yyerror("Syntax error"); }
+
+%%
+
+void
+yyerror(char *s)
+{
+ printf("line %d: %s at [%s]\n", lineno, s, yytext);
+}
+
+int
+parse(fp)
+ FILE **fp;
+{
+ yyin = *fp;
+
+ parse_init();
+
+ if (yyparse()) {
+ printf("parse failed, line %d.\n", lineno);
+ return(-1);
+ }
+
+ return(0);
+}
+
diff --git a/usr.sbin/setkey/vchar.h b/usr.sbin/setkey/vchar.h
new file mode 100644
index 0000000..977f5f0
--- /dev/null
+++ b/usr.sbin/setkey/vchar.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+typedef struct {
+ u_int len;
+ caddr_t buf;
+} vchar_t;
diff --git a/usr.sbin/traceroute6/Makefile b/usr.sbin/traceroute6/Makefile
index 2b151a6..d2f6de1 100644
--- a/usr.sbin/traceroute6/Makefile
+++ b/usr.sbin/traceroute6/Makefile
@@ -19,7 +19,9 @@ BINOWN= root
BINGRP= bin
BINMODE=4555
-CFLAGS+=-DINET6
+CFLAGS+=-DINET6 -DIPSEC
+DPADD= ${LIBIPSEC}
+LDADD= -lipsec
MAN8= traceroute6.8
OpenPOWER on IntegriCloud