From 9a4365d0e0833374e893c519639bde71756aa104 Mon Sep 17 00:00:00 2001 From: Yoshinobu Inoue Date: Thu, 6 Jan 2000 12:40:54 +0000 Subject: [PATCH] libipsec and IPsec related apps. (and some KAME related man pages) Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project --- lib/Makefile | 3 +- lib/libipsec/Makefile | 50 + lib/libipsec/ipsec_dump_policy.c | 253 +++++ lib/libipsec/ipsec_get_policylen.c | 44 + lib/libipsec/ipsec_set_policy.3 | 253 +++++ lib/libipsec/ipsec_strerror.3 | 66 ++ lib/libipsec/ipsec_strerror.c | 87 ++ lib/libipsec/ipsec_strerror.h | 62 ++ lib/libipsec/pfkey.c | 1421 ++++++++++++++++++++++++++++ lib/libipsec/pfkey_dump.c | 463 +++++++++ lib/libipsec/policy_parse.y | 426 +++++++++ lib/libipsec/policy_token.l | 137 +++ lib/libipsec/test-policy.c | 179 ++++ sbin/ping/Makefile | 5 +- sbin/ping/ping.8 | 8 + sbin/ping/ping.c | 71 +- sbin/setkey/Makefile | 56 ++ sbin/setkey/parse.y | 787 +++++++++++++++ sbin/setkey/sample.cf | 219 +++++ sbin/setkey/scriptdump.pl | 54 ++ sbin/setkey/setkey.8 | 550 +++++++++++ sbin/setkey/setkey.c | 566 +++++++++++ sbin/setkey/test-pfkey.c | 480 ++++++++++ sbin/setkey/test-policy.c | 161 ++++ sbin/setkey/token.l | 322 +++++++ sbin/setkey/vchar.h | 35 + share/man/man4/Makefile | 6 +- share/man/man4/faith.4 | 122 +++ share/man/man4/gif.4 | 232 +++++ share/man/man4/inet6.4 | 287 ++++++ share/man/man4/ipsec.4 | 228 +++++ share/man/man4/kame.4 | 217 +++++ usr.bin/netstat/Makefile | 2 +- usr.sbin/Makefile | 4 + usr.sbin/ndp/Makefile | 25 + usr.sbin/ndp/gnuc.h | 2 + usr.sbin/ndp/ndp.8 | 138 +++ usr.sbin/ndp/ndp.c | 1028 ++++++++++++++++++++ usr.sbin/rrenumd/Makefile | 41 + usr.sbin/rrenumd/lexer.l | 248 +++++ usr.sbin/rrenumd/parser.y | 637 +++++++++++++ usr.sbin/rrenumd/rrenumd.8 | 95 ++ usr.sbin/rrenumd/rrenumd.c | 460 +++++++++ usr.sbin/rrenumd/rrenumd.conf.5 | 330 +++++++ usr.sbin/rrenumd/rrenumd.h | 57 ++ usr.sbin/rtadvd/Makefile | 26 + usr.sbin/rtadvd/advcap.c | 452 +++++++++ usr.sbin/rtadvd/advcap.h | 45 + usr.sbin/rtadvd/config.c | 639 +++++++++++++ usr.sbin/rtadvd/config.h | 34 + usr.sbin/rtadvd/if.c | 556 +++++++++++ usr.sbin/rtadvd/if.h | 57 ++ usr.sbin/rtadvd/pathnames.h | 2 + usr.sbin/rtadvd/rrenum.c | 414 ++++++++ usr.sbin/rtadvd/rrenum.h | 34 + usr.sbin/rtadvd/rtadvd.8 | 134 +++ usr.sbin/rtadvd/rtadvd.c | 1239 ++++++++++++++++++++++++ usr.sbin/rtadvd/rtadvd.conf | 14 + usr.sbin/rtadvd/rtadvd.conf.5 | 250 +++++ usr.sbin/rtadvd/rtadvd.h | 107 +++ usr.sbin/rtadvd/timer.c | 201 ++++ usr.sbin/rtadvd/timer.h | 63 ++ usr.sbin/setkey/Makefile | 56 ++ usr.sbin/setkey/parse.y | 787 +++++++++++++++ usr.sbin/setkey/sample.cf | 219 +++++ usr.sbin/setkey/scriptdump.pl | 54 ++ usr.sbin/setkey/setkey.8 | 550 +++++++++++ usr.sbin/setkey/setkey.c | 566 +++++++++++ usr.sbin/setkey/test-pfkey.c | 480 ++++++++++ usr.sbin/setkey/test-policy.c | 161 ++++ usr.sbin/setkey/token.l | 322 +++++++ usr.sbin/setkey/vchar.h | 35 + usr.sbin/traceroute6/Makefile | 4 +- 73 files changed, 18408 insertions(+), 10 deletions(-) create mode 100644 lib/libipsec/Makefile create mode 100644 lib/libipsec/ipsec_dump_policy.c create mode 100644 lib/libipsec/ipsec_get_policylen.c create mode 100644 lib/libipsec/ipsec_set_policy.3 create mode 100644 lib/libipsec/ipsec_strerror.3 create mode 100644 lib/libipsec/ipsec_strerror.c create mode 100644 lib/libipsec/ipsec_strerror.h create mode 100644 lib/libipsec/pfkey.c create mode 100644 lib/libipsec/pfkey_dump.c create mode 100644 lib/libipsec/policy_parse.y create mode 100644 lib/libipsec/policy_token.l create mode 100644 lib/libipsec/test-policy.c create mode 100644 sbin/setkey/Makefile create mode 100644 sbin/setkey/parse.y create mode 100644 sbin/setkey/sample.cf create mode 100644 sbin/setkey/scriptdump.pl create mode 100644 sbin/setkey/setkey.8 create mode 100644 sbin/setkey/setkey.c create mode 100644 sbin/setkey/test-pfkey.c create mode 100644 sbin/setkey/test-policy.c create mode 100644 sbin/setkey/token.l create mode 100644 sbin/setkey/vchar.h create mode 100644 share/man/man4/faith.4 create mode 100644 share/man/man4/gif.4 create mode 100644 share/man/man4/inet6.4 create mode 100644 share/man/man4/ipsec.4 create mode 100644 share/man/man4/kame.4 create mode 100644 usr.sbin/ndp/Makefile create mode 100644 usr.sbin/ndp/gnuc.h create mode 100644 usr.sbin/ndp/ndp.8 create mode 100644 usr.sbin/ndp/ndp.c create mode 100644 usr.sbin/rrenumd/Makefile create mode 100644 usr.sbin/rrenumd/lexer.l create mode 100644 usr.sbin/rrenumd/parser.y create mode 100644 usr.sbin/rrenumd/rrenumd.8 create mode 100644 usr.sbin/rrenumd/rrenumd.c create mode 100644 usr.sbin/rrenumd/rrenumd.conf.5 create mode 100644 usr.sbin/rrenumd/rrenumd.h create mode 100644 usr.sbin/rtadvd/Makefile create mode 100644 usr.sbin/rtadvd/advcap.c create mode 100644 usr.sbin/rtadvd/advcap.h create mode 100644 usr.sbin/rtadvd/config.c create mode 100644 usr.sbin/rtadvd/config.h create mode 100644 usr.sbin/rtadvd/if.c create mode 100644 usr.sbin/rtadvd/if.h create mode 100644 usr.sbin/rtadvd/pathnames.h create mode 100644 usr.sbin/rtadvd/rrenum.c create mode 100644 usr.sbin/rtadvd/rrenum.h create mode 100644 usr.sbin/rtadvd/rtadvd.8 create mode 100644 usr.sbin/rtadvd/rtadvd.c create mode 100644 usr.sbin/rtadvd/rtadvd.conf create mode 100644 usr.sbin/rtadvd/rtadvd.conf.5 create mode 100644 usr.sbin/rtadvd/rtadvd.h create mode 100644 usr.sbin/rtadvd/timer.c create mode 100644 usr.sbin/rtadvd/timer.h create mode 100644 usr.sbin/setkey/Makefile create mode 100644 usr.sbin/setkey/parse.y create mode 100644 usr.sbin/setkey/sample.cf create mode 100644 usr.sbin/setkey/scriptdump.pl create mode 100644 usr.sbin/setkey/setkey.8 create mode 100644 usr.sbin/setkey/setkey.c create mode 100644 usr.sbin/setkey/test-pfkey.c create mode 100644 usr.sbin/setkey/test-policy.c create mode 100644 usr.sbin/setkey/token.l create mode 100644 usr.sbin/setkey/vchar.h diff --git a/lib/Makefile b/lib/Makefile index 66fb360c207f..6f3622d88223 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 000000000000..963e96d5c162 --- /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 diff --git a/lib/libipsec/ipsec_dump_policy.c b/lib/libipsec/ipsec_dump_policy.c new file mode 100644 index 000000000000..a9ef2f5a7aa0 --- /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 +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#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 000000000000..a8a3e5d05b70 --- /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 +#include + +#include + +#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 000000000000..559d5fa1d60b --- /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 +.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 000000000000..58ac2b6475e0 --- /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 +.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 000000000000..601b1d7023f3 --- /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 +#include + +#include +#include + +#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 000000000000..752ba75ba2ab --- /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 000000000000..318be331a9cf --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 000000000000..b7def246f683 --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef INET6 +#include +#endif +#include + +#include +#include +#include +#include +#include + +#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 000000000000..ffa1a6f8ae8d --- /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 + * out + * + * is one of following: + * "discard", "none", "ipsec ", "entrust", "bypass", + * + * The following requests are accepted as : + * + * 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 +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#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 DIR ACTION PROTOCOL MODE LEVEL +%type 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 000000000000..1e7b7140676d --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 000000000000..3b9d18c64a77 --- /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 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 1df0d93b0530..2c6b08e0ba10 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 diff --git a/sbin/ping/ping.8 b/sbin/ping/ping.8 index 565a5afed962..fca80acb44f8 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 1cd55fa7aa7d..15bac460a394 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -92,6 +92,10 @@ static const char rcsid[] = #include #include +#ifdef IPSEC +#include +#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 000000000000..918dbf4cb71c --- /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 diff --git a/sbin/setkey/parse.y b/sbin/setkey/parse.y new file mode 100644 index 000000000000..761c34d6e6d8 --- /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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 000000000000..886c449a35f1 --- /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 000000000000..5df9b4f4fd7b --- /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 $_ () { + 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 000000000000..1f6f33c1de15 --- /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 000000000000..73edc3f2bbc2 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 000000000000..849aba355a99 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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: + /**/ + 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(); + /**/ + break; + + case SADB_ADD: + /* */ + 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(); + /* */ + break; + + case SADB_DELETE: + /* */ + 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"); + /* */ + break; + + case SADB_GET: + /* */ + 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"); + /* */ + break; + + case SADB_ACQUIRE: + /* */ + 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(); + /* */ + break; + + case SADB_REGISTER: + /* */ + /* */ + break; + + case SADB_EXPIRE: + case SADB_FLUSH: + break; + + case SADB_DUMP: + break; + + case SADB_X_PROMISC: + /* */ + /* */ + 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 000000000000..27cd478fc939 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include + +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 000000000000..b75fd45e3e7d --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#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); } +[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); +} +{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 000000000000..977f5f0f60d4 --- /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 6fb71becc74b..b1eb513d7bc8 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 000000000000..2b939937f594 --- /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 000000000000..1d114406c33d --- /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 000000000000..0d2b690b3fe9 --- /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 +.Fd #include +.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 000000000000..6e074feb9224 --- /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 +.Fd #include +.Fd #include +.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 000000000000..fa09d980756a --- /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 792797ca829d..c1f75394317b 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 diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 220b989c1ee0..9ab3104dec97 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 000000000000..b0ba34841fc8 --- /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 diff --git a/usr.sbin/ndp/gnuc.h b/usr.sbin/ndp/gnuc.h new file mode 100644 index 000000000000..c6412965c9db --- /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 000000000000..6f0382f2628c --- /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 000000000000..01cea32290d1 --- /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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 000000000000..990ddab13a6b --- /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 + +CLEANFILES+= y.tab.h diff --git a/usr.sbin/rrenumd/lexer.l b/usr.sbin/rrenumd/lexer.l new file mode 100644 index 000000000000..80429af3b4a6 --- /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 +#include +#include + +#include + +#include +#include + +#include +#include +#include +#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 000000000000..eecc7bb94a0a --- /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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#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 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 DAYS HOURS MINUTES SECONDS INFINITY +%token ON OFF +%token BCL ECL EOS ERROR +%token NAME HOSTNAME QSTRING DECSTRING +%token IPV4ADDR +%token IPV6ADDR +%token PREFIXLEN + +%type retrynum seqnum rrenum_cmd +%type prefixlen maxlen minlen keeplen vltime pltime +%type lifetime days hours minutes seconds +%type decstring +%type raf_onlink raf_auto raf_decrvalid raf_decrprefd flag +%type
dest_addrs dest_addr sin6 +%type rrenum_statement +%type ifname +%type 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 000000000000..aa7ae6bef133 --- /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 000000000000..ced5afc0a924 --- /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 +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#ifdef IPSEC +#include +#endif + +#include +#include +#include +#include +#include + +#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 000000000000..76453cbc3517 --- /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 000000000000..dae2cd0c9e42 --- /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 000000000000..7b5d2a8d2380 --- /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 diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c new file mode 100644 index 000000000000..f0825b543a91 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 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 000000000000..9c4520b3a7f8 --- /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 + +__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 000000000000..30551614e828 --- /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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#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 000000000000..f8729d46a1d5 --- /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 000000000000..98aefeef7581 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 000000000000..e8e14d4203dd --- /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 000000000000..70d9021dc9e2 --- /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 000000000000..ec69ff2a3048 --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#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 000000000000..d3c73a7477f6 --- /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 000000000000..a9b36b8326f0 --- /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 000000000000..03ed974f656a --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef IPSEC +#include +#endif /*IPSEC*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 000000000000..f40a6503df8b --- /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 000000000000..5d1fed2ae4f2 --- /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 000000000000..92fbcdf02213 --- /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 000000000000..f93968a3be0e --- /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 + +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#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 000000000000..e9f2c3505762 --- /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 000000000000..918dbf4cb71c --- /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 diff --git a/usr.sbin/setkey/parse.y b/usr.sbin/setkey/parse.y new file mode 100644 index 000000000000..761c34d6e6d8 --- /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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 000000000000..886c449a35f1 --- /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 000000000000..5df9b4f4fd7b --- /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 $_ () { + 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 000000000000..1f6f33c1de15 --- /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 000000000000..73edc3f2bbc2 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 000000000000..849aba355a99 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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: + /**/ + 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(); + /**/ + break; + + case SADB_ADD: + /* */ + 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(); + /* */ + break; + + case SADB_DELETE: + /* */ + 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"); + /* */ + break; + + case SADB_GET: + /* */ + 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"); + /* */ + break; + + case SADB_ACQUIRE: + /* */ + 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(); + /* */ + break; + + case SADB_REGISTER: + /* */ + /* */ + break; + + case SADB_EXPIRE: + case SADB_FLUSH: + break; + + case SADB_DUMP: + break; + + case SADB_X_PROMISC: + /* */ + /* */ + 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 000000000000..27cd478fc939 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include + +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 000000000000..b75fd45e3e7d --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#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); } +[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); +} +{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 000000000000..977f5f0f60d4 --- /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 2b151a68faf9..d2f6de1e04ce 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