diff options
author | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
commit | 832f8d224926758a9ae0b23a6b45353e44fbc87a (patch) | |
tree | a79fc7ad2b97862c4a404f352f0211ad93a7b5f1 | |
parent | 2693854b01a52b0395a91322aa3edf926bddff38 (diff) | |
download | FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.zip FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.tar.gz |
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some
critical problem after the snap was out were fixed.
There are many many changes since last KAME merge.
TODO:
- The definitions of SADB_* in sys/net/pfkeyv2.h are still different
from RFC2407/IANA assignment because of binary compatibility
issue. It should be fixed under 5-CURRENT.
- ip6po_m member of struct ip6_pktopts is no longer used. But, it
is still there because of binary compatibility issue. It should
be removed under 5-CURRENT.
Reviewed by: itojun
Obtained from: KAME
MFC after: 3 weeks
247 files changed, 20320 insertions, 11898 deletions
diff --git a/etc/network.subr b/etc/network.subr index 00f6250..e3af24e 100644 --- a/etc/network.subr +++ b/etc/network.subr @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.d/netoptions b/etc/rc.d/netoptions index 00f6250..e3af24e 100644 --- a/etc/rc.d/netoptions +++ b/etc/rc.d/netoptions @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.d/network1 b/etc/rc.d/network1 index 00f6250..e3af24e 100644 --- a/etc/rc.d/network1 +++ b/etc/rc.d/network1 @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.d/network2 b/etc/rc.d/network2 index 00f6250..e3af24e 100644 --- a/etc/rc.d/network2 +++ b/etc/rc.d/network2 @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.d/network3 b/etc/rc.d/network3 index 00f6250..e3af24e 100644 --- a/etc/rc.d/network3 +++ b/etc/rc.d/network3 @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.d/network_ipv6 b/etc/rc.d/network_ipv6 index dc6188a..a46194f 100644 --- a/etc/rc.d/network_ipv6 +++ b/etc/rc.d/network_ipv6 @@ -232,11 +232,11 @@ network6_pass1() { case ${ipv6_ipv4mapping} in [Yy][Ee][Ss]) echo -n ' IPv4 mapped IPv6 address support=YES' - sysctl -w net.inet6.ip6.mapped_addr=1 >/dev/null + sysctl -w net.inet6.ip6.v6only=0 >/dev/null ;; '' | *) echo -n ' IPv4 mapped IPv6 address support=NO' - sysctl -w net.inet6.ip6.mapped_addr=0 >/dev/null + sysctl -w net.inet6.ip6.v6only=1 >/dev/null ;; esac @@ -256,7 +256,6 @@ network6_interface_setup() { ;; *) rtsol_available=yes - prefixcmd_enable=NO ;; esac for i in $interfaces; do @@ -265,24 +264,11 @@ network6_interface_setup() { if [ -n "${prefix}" ]; then rtsol_available=no rtsol_interface=no + laddr=`network6_getladdr $i` + hostid=`expr "${laddr}" : 'fe80::\(.*\)%\(.*\)'` for j in ${prefix}; do - case ${prefixcmd_enable} in - [Yy][Ee][Ss]) - prefix $i $j:: - ;; - *) - laddr=`network6_getladdr $i` - hostid=`expr "${laddr}" : \ - 'fe80::\(.*\)%\(.*\)'` - address=$j\:${hostid} - - eval hostid_$i=${hostid} - eval address_$i=${address} - - ifconfig $i inet6 ${address} \ - prefixlen 64 alias - ;; - esac + address=$j\:${hostid} + ifconfig $i inet6 ${address} prefixlen 64 alias case ${ipv6_gateway_enable} in [Yy][Ee][Ss]) diff --git a/etc/rc.d/routing b/etc/rc.d/routing index 00f6250..e3af24e 100644 --- a/etc/rc.d/routing +++ b/etc/rc.d/routing @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.network b/etc/rc.network index 00f6250..e3af24e 100644 --- a/etc/rc.network +++ b/etc/rc.network @@ -766,7 +766,7 @@ network_gif_setup() { continue ;; *) - gifconfig $i ${peers} + ifconfig $i tunnel ${peers} ;; esac done diff --git a/etc/rc.network6 b/etc/rc.network6 index dc6188a..a46194f 100644 --- a/etc/rc.network6 +++ b/etc/rc.network6 @@ -232,11 +232,11 @@ network6_pass1() { case ${ipv6_ipv4mapping} in [Yy][Ee][Ss]) echo -n ' IPv4 mapped IPv6 address support=YES' - sysctl -w net.inet6.ip6.mapped_addr=1 >/dev/null + sysctl -w net.inet6.ip6.v6only=0 >/dev/null ;; '' | *) echo -n ' IPv4 mapped IPv6 address support=NO' - sysctl -w net.inet6.ip6.mapped_addr=0 >/dev/null + sysctl -w net.inet6.ip6.v6only=1 >/dev/null ;; esac @@ -256,7 +256,6 @@ network6_interface_setup() { ;; *) rtsol_available=yes - prefixcmd_enable=NO ;; esac for i in $interfaces; do @@ -265,24 +264,11 @@ network6_interface_setup() { if [ -n "${prefix}" ]; then rtsol_available=no rtsol_interface=no + laddr=`network6_getladdr $i` + hostid=`expr "${laddr}" : 'fe80::\(.*\)%\(.*\)'` for j in ${prefix}; do - case ${prefixcmd_enable} in - [Yy][Ee][Ss]) - prefix $i $j:: - ;; - *) - laddr=`network6_getladdr $i` - hostid=`expr "${laddr}" : \ - 'fe80::\(.*\)%\(.*\)'` - address=$j\:${hostid} - - eval hostid_$i=${hostid} - eval address_$i=${address} - - ifconfig $i inet6 ${address} \ - prefixlen 64 alias - ;; - esac + address=$j\:${hostid} + ifconfig $i inet6 ${address} prefixlen 64 alias case ${ipv6_gateway_enable} in [Yy][Ee][Ss]) diff --git a/lib/libipsec/ipsec_set_policy.3 b/lib/libipsec/ipsec_set_policy.3 index 7b71c53..bb27a5b 100644 --- a/lib/libipsec/ipsec_set_policy.3 +++ b/lib/libipsec/ipsec_set_policy.3 @@ -1,7 +1,7 @@ -.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" $KAME: ipsec_set_policy.3,v 1.14 2001/04/06 07:00:46 itojun Exp $ .\" $FreeBSD$ -.\" $KAME: ipsec_set_policy.3,v 1.10 2000/05/07 05:25:03 itojun Exp $ .\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -92,7 +92,7 @@ It is caller's responsibility to reclaim the region, by using .Fa policy is formatted as either of the following: .Bl -tag -width "discard" -.It Ar direction Li entrust +.It Ar direction Li discard .Ar direction must be .Li in @@ -100,6 +100,10 @@ or .Li out . .Ar direction specifies which direction the policy needs to be applied. +With +.Li discard +policy, packets will be dropped if they match the policy. +.It Ar direction Li entrust .Li entrust means to consult to SPD defined by .Xr setkey 8 . @@ -164,6 +168,15 @@ and .Ar src is the other node .Pq peer . +If +.Ar mode +is +.Li transport , +Both +.Ar src +and +.Ar dst +can be omited. .Pp .Ar level must be set to one of the following: @@ -222,7 +235,8 @@ 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 +both entrust and bypass are not used. +Refer to .Xr setkey 8 for detail. .Pp @@ -230,12 +244,11 @@ 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 -out ipsec esp/transport/10.1.1.2-10.1.1.1/use - ah/tunnel/10.1.1.2-10.1.1.1/unique:1000 -in ipsec ipcomp/transport/10.1.1.2-10.1.1.1/use - esp/transport/10.1.1.2-10.1.1.1/use +out ipsec esp/transport//require +in ipsec ah/transport//require +out ipsec esp/tunnel/10.1.1.2-10.1.1.1/use +in ipsec ipcomp/transport//use + esp/transport//use .Ed .Sh RETURN VALUES .Fn ipsec_set_policy @@ -255,3 +268,7 @@ on errors. .Xr setkey 8 .Sh HISTORY The functions first appeared in WIDE/KAME IPv6 protocol stack kit. +.Pp +IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack +was initially integrated into +.Fx 4.0 diff --git a/lib/libipsec/ipsec_strerror.3 b/lib/libipsec/ipsec_strerror.3 index 66ae950..82fa99c 100644 --- a/lib/libipsec/ipsec_strerror.3 +++ b/lib/libipsec/ipsec_strerror.3 @@ -1,7 +1,7 @@ -.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" $KAME: ipsec_strerror.3,v 1.8 2000/11/20 00:35:14 sakane Exp $ .\" $FreeBSD$ -.\" $KAME: ipsec_strerror.3,v 1.6 2000/05/07 05:25:03 itojun Exp $ .\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -34,24 +34,23 @@ .\" .Sh NAME .Nm ipsec_strerror -.Nd error code for IPsec policy manipulation library +.Nd error message for IPsec policy manipulation library .\" .Sh SYNOPSIS .Fd #include <netinet6/ipsec.h> -.Ft "char *" +.Ft "const char *" .Fn ipsec_strerror .\" .Sh DESCRIPTION .Pa netinet6/ipsec.h declares -.Bd -ragged -offset indent -.Vt extern int ipsec_errcode ; -.Ed .Pp -which is used to pass error code from IPsec policy manipulation library -to user program. +.Dl extern int ipsec_errcode; +.Pp +which is used to pass an error code from IPsec policy manipulation library +to an user program. .Fn ipsec_strerror -can be used to obtain error message string for the error code. +can be used to obtain the error message string for the error code. .Pp The array pointed to is not to be modified by the program. Since @@ -75,7 +74,9 @@ The C string must not be overwritten by user programs. .Xr ipsec_set_policy 3 .\" .Sh HISTORY -The functions first appeared in WIDE/KAME IPv6 protocol stack kit. +.Fn ipsec_strerror +first appeared in WIDE/KAME IPv6 protocol stack kit. .\" -.\" .Sh BUGS -.\" (to be written) +.Sh BUGS +.Fn ipsec_strerror +will return its result which may be overwritten by subsequent calls. diff --git a/lib/libipsec/ipsec_strerror.c b/lib/libipsec/ipsec_strerror.c index 1cf4e4c..d53a9e3 100644 --- a/lib/libipsec/ipsec_strerror.c +++ b/lib/libipsec/ipsec_strerror.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipsec_strerror.c,v 1.6 2000/05/07 05:25:03 itojun Exp $ */ +/* $KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -40,7 +40,7 @@ int __ipsec_errcode; -static char *ipsec_errlist[] = { +static const char *ipsec_errlist[] = { "Success", /*EIPSEC_NO_ERROR*/ "Not supported", /*EIPSEC_NOT_SUPPORTED*/ "Invalid argument", /*EIPSEC_INVAL_ARGUMENT*/ @@ -71,7 +71,7 @@ NULL, /*EIPSEC_SYSTEM_ERROR*/ "Unknown error", /*EIPSEC_MAX*/ }; -char *ipsec_strerror(void) +const char *ipsec_strerror(void) { if (__ipsec_errcode < 0 || __ipsec_errcode > EIPSEC_MAX) __ipsec_errcode = EIPSEC_MAX; @@ -79,7 +79,7 @@ char *ipsec_strerror(void) return ipsec_errlist[__ipsec_errcode]; } -void __ipsec_set_strerror(char *str) +void __ipsec_set_strerror(const char *str) { __ipsec_errcode = EIPSEC_SYSTEM_ERROR; ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str; diff --git a/lib/libipsec/ipsec_strerror.h b/lib/libipsec/ipsec_strerror.h index 02448cd..24d4199 100644 --- a/lib/libipsec/ipsec_strerror.h +++ b/lib/libipsec/ipsec_strerror.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipsec_strerror.h,v 1.7 2000/05/07 05:25:03 itojun Exp $ */ +/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -31,7 +31,7 @@ */ extern int __ipsec_errcode; -extern void __ipsec_set_strerror __P((char *)); +extern void __ipsec_set_strerror __P((const char *)); #define EIPSEC_NO_ERROR 0 /*success*/ #define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ diff --git a/lib/libipsec/libpfkey.h b/lib/libipsec/libpfkey.h index ad87700..1f25a30 100644 --- a/lib/libipsec/libpfkey.h +++ b/lib/libipsec/libpfkey.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: libpfkey.h,v 1.1 2000/06/08 21:28:32 itojun Exp $ */ +/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -30,11 +30,15 @@ * SUCH DAMAGE. */ +struct sadb_msg; extern void pfkey_sadump __P((struct sadb_msg *)); extern void pfkey_spdump __P((struct sadb_msg *)); struct sockaddr; +struct sadb_alg; int ipsec_check_keylen __P((u_int, u_int, u_int)); +int ipsec_check_keylen2 __P((u_int, u_int, u_int)); +int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *)); u_int pfkey_set_softrate __P((u_int, u_int)); u_int pfkey_get_softrate __P((u_int)); int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, @@ -49,17 +53,26 @@ int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, u_int64_t, u_int64_t, u_int32_t)); int pfkey_send_delete __P((int, u_int, u_int, struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_delete_all __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *)); int pfkey_send_get __P((int, u_int, u_int, struct sockaddr *, struct sockaddr *, u_int32_t)); int pfkey_send_register __P((int, u_int)); int pfkey_recv_register __P((int)); +int pfkey_set_supported __P((struct sadb_msg *, int)); int pfkey_send_flush __P((int, u_int)); int pfkey_send_dump __P((int, u_int)); int pfkey_send_promisc_toggle __P((int, int)); int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int, struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); int pfkey_send_spddelete2 __P((int, u_int32_t)); diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c index 11b6722..6cdea34 100644 --- a/lib/libipsec/pfkey.c +++ b/lib/libipsec/pfkey.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: pfkey.c,v 1.31 2000/06/10 14:17:43 sakane Exp $ */ +/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -42,12 +42,16 @@ #include <unistd.h> #include <string.h> #include <errno.h> +#include <stdio.h> #include "ipsec_strerror.h" #include "libpfkey.h" #define CALLOC(size, cast) (cast)calloc(1, (size)) +static int findsupportedmap __P((int)); +static int setsupportedmap __P((struct sadb_supported *)); +static struct sadb_alg *findsupportedalg __P((u_int, u_int)); static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, @@ -56,94 +60,215 @@ static int pfkey_send_x2 __P((int, u_int, u_int, u_int, struct sockaddr *, struct sockaddr *, u_int32_t)); static int pfkey_send_x3 __P((int, u_int, u_int)); static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, - struct sockaddr *, u_int, u_int, char *, int, u_int32_t)); + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + char *, int, u_int32_t)); static int pfkey_send_x5 __P((int, u_int, u_int32_t)); -static caddr_t pfkey_setsadbmsg __P((caddr_t, u_int, u_int, +static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int, u_int, u_int32_t, pid_t)); -static caddr_t pfkey_setsadbsa __P((caddr_t, u_int32_t, u_int, +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, u_int, u_int, u_int32_t)); -static caddr_t pfkey_setsadbaddr __P((caddr_t, u_int, +static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, struct sockaddr *, u_int, u_int)); -static caddr_t pfkey_setsadbkey __P((caddr_t, u_int, caddr_t, u_int)); -static caddr_t pfkey_setsadblifetime __P((caddr_t, u_int, u_int32_t, u_int32_t, - u_int32_t, u_int32_t)); -static caddr_t pfkey_setsadbxsa2 __P((caddr_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t)); + +/* + * make and search supported algorithm structure. + */ +static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, }; + +static int supported_map[] = { + SADB_SATYPE_AH, + SADB_SATYPE_ESP, + SADB_X_SATYPE_IPCOMP, +}; + +static int +findsupportedmap(satype) + int satype; +{ + int i; + + for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) + if (supported_map[i] == satype) + return i; + return -1; +} + +static struct sadb_alg * +findsupportedalg(satype, alg_id) + u_int satype, alg_id; +{ + int algno; + int tlen; + caddr_t p; + + /* validity check */ + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + if (ipsec_supported[algno] == NULL) { + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + return NULL; + } + + tlen = ipsec_supported[algno]->sadb_supported_len + - sizeof(struct sadb_supported); + p = (caddr_t)(ipsec_supported[algno] + 1); + while (tlen > 0) { + if (tlen < sizeof(struct sadb_alg)) { + /* invalid format */ + break; + } + if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) + return (struct sadb_alg *)p; + + tlen -= sizeof(struct sadb_alg); + p += sizeof(struct sadb_alg); + } + + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return NULL; +} + +static int +setsupportedmap(sup) + struct sadb_supported *sup; +{ + struct sadb_supported **ipsup; + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (*ipsup) + free(*ipsup); + + *ipsup = malloc(sup->sadb_supported_len); + if (!*ipsup) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + memcpy(*ipsup, sup, sup->sadb_supported_len); + + return 0; +} /* * 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. + * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the + * augument, and only calls to ipsec_check_keylen2(); * 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; + int satype; /* validity check */ - if (ipsec_supported == NULL) { - __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; - return -1; - } switch (supported) { case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; 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); + return ipsec_check_keylen2(satype, alg_id, keylen); +} - for (; - tlen > 0; - tlen -= sup->sadb_supported_len, p += sup->sadb_supported_len) { +/* + * check key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen2(satype, alg_id, keylen) + u_int satype; + u_int alg_id; + u_int keylen; +{ + struct sadb_alg *alg; - sup = (struct sadb_supported *)p; + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; - if (sup->sadb_supported_exttype != supported) - continue; + if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; + return -1; + } - { - u_int ttlen = sup->sadb_supported_len; - caddr_t pp = p + sizeof(*sup); + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} - for (; - ttlen > 0; - ttlen -= sizeof(*alg), pp += sizeof(*alg)) { - alg = (struct sadb_alg *)pp; +/* + * get max/min key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_get_keylen(supported, alg_id, alg0) + u_int supported, alg_id; + struct sadb_alg *alg0; +{ + struct sadb_alg *alg; + u_int satype; - if (alg->sadb_alg_id == alg_id) - goto found; - } - } + /* validity check */ + if (!alg0) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; } - __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; + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + memcpy(alg0, alg, sizeof(*alg0)); + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -221,6 +346,7 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) u_int32_t min, max, reqid, seq; { struct sadb_msg *newmsg; + caddr_t ep; int len; int need_spirange = 0; caddr_t p; @@ -268,31 +394,59 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) __ipsec_set_strerror(strerror(errno)); return -1; } + ep = ((caddr_t)newmsg) + len; - p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_GETSPI, - len, satype, seq, getpid()); + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, + len, satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } - p = pfkey_setsadbxsa2(p, mode, reqid); + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } /* set sadb_address for source */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen, + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } /* set sadb_address for destination */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen, + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } /* proccessing spi range */ if (need_spirange) { - int _len = sizeof(struct sadb_spirange); + struct sadb_spirange 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; + if (p + sizeof(spirange) > ep) { + free(newmsg); + return -1; + } + + memset(&spirange, 0, sizeof(spirange)); + spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_min = min; + spirange.sadb_spirange_max = max; + + memcpy(p, &spirange, sizeof(spirange)); + + p += sizeof(spirange); + } + if (p != ep) { + free(newmsg); + return -1; } /* send message */ @@ -389,6 +543,91 @@ pfkey_send_delete(so, satype, mode, src, dst, spi) } /* + * sending SADB_DELETE without spi to the kernel. This is + * the "delete all" request (an extension also present in + * Solaris). + * + * OUT: + * positive: success and return length sent + * -1 : error occured, and set errno + */ +int +pfkey_send_delete_all(so, satype, mode, src, dst) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* 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 (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + 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; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* * sending SADB_GET message to the kernel. * OUT: * positive: success and return length sent. @@ -419,7 +658,29 @@ pfkey_send_register(so, satype) int so; u_int satype; { - int len; + int len, algno; + + if (satype == PF_UNSPEC) { + for (algno = 0; + algno < sizeof(supported_map)/sizeof(supported_map[0]); + algno++) { + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + } else { + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) return -1; @@ -440,51 +701,92 @@ pfkey_recv_register(so) { pid_t pid = getpid(); struct sadb_msg *newmsg; - struct sadb_supported *sup; - caddr_t p; - int tlen; + int error = -1; /* 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) { + error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); + free(newmsg); + + if (error == 0) + __ipsec_errcode = EIPSEC_NO_ERROR; + + return error; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * NOTE: sadb_msg_len must be host order. + * IN: + * tlen: msg length, it's to makeing sure. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_set_supported(msg, tlen) + struct sadb_msg *msg; + int tlen; +{ + struct sadb_supported *sup; + caddr_t p; + caddr_t ep; + + /* validity */ + if (msg->sadb_msg_len != tlen) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + p = (caddr_t)msg; + ep = p + tlen; + + p += sizeof(struct sadb_msg); + + while (p < ep) { sup = (struct sadb_supported *)p; + if (ep < p + sizeof(*sup) || + PFKEY_EXTLEN(sup) < sizeof(*sup) || + ep < p + sup->sadb_supported_len) { + /* invalid format */ + break; + } + 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; + /* fixed length */ + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + + /* set supported map */ + if (setsupportedmap(sup) != 0) + return -1; + p += sup->sadb_supported_len; } - if (tlen < 0) { + if (p != ep) { __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } - if (ipsec_supported != NULL) - free(ipsec_supported); - - ipsec_supported = newmsg; - __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; } @@ -570,6 +872,35 @@ pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) if ((len = pfkey_send_x4(so, SADB_X_SPDADD, src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq)) < 0) return -1; @@ -595,6 +926,35 @@ pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq)) < 0) return -1; @@ -625,6 +985,7 @@ pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, src, prefs, dst, prefd, proto, + 0, 0, policy, policylen, seq)) < 0) return -1; @@ -693,6 +1054,7 @@ pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, src, prefs, dst, prefd, proto, + 0, 0, policy, policylen, seq)) < 0) return -1; @@ -753,6 +1115,7 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, int len; caddr_t p; int plen; + caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { @@ -793,6 +1156,14 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, } break; case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } break; default: __ipsec_errcode = EIPSEC_INVAL_SATYPE; @@ -819,28 +1190,67 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, __ipsec_set_strerror(strerror(errno)); return -1; } + ep = ((caddr_t)newmsg) + len; - p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, seq, getpid()); - p = pfkey_setsadbsa(p, spi, wsize, a_type, e_type, flags); - p = pfkey_setsadbxsa2(p, mode, reqid); - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen, + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen, + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } - if (e_type != SADB_EALG_NONE) - p = pfkey_setsadbkey(p, SADB_EXT_KEY_ENCRYPT, + if (e_type != SADB_EALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, keymat, e_keylen); - if (a_type != SADB_AALG_NONE) - p = pfkey_setsadbkey(p, SADB_EXT_KEY_AUTH, + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } /* set sadb_lifetime for destination */ - p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_HARD, + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, l_alloc, l_bytes, l_addtime, l_usetime); - p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_SOFT, + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, l_alloc, l_bytes, l_addtime, l_usetime); + if (!p || p != ep) { + free(newmsg); + return -1; + } /* send message */ len = pfkey_send(so, newmsg, len); @@ -865,6 +1275,7 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi) int len; caddr_t p; int plen; + caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { @@ -899,13 +1310,31 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi) __ipsec_set_strerror(strerror(errno)); return -1; } + ep = ((caddr_t)newmsg) + len; - p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, getpid()); - p = pfkey_setsadbsa(p, spi, 0, 0, 0, 0); - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen, + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen, + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } /* send message */ len = pfkey_send(so, newmsg, len); @@ -929,6 +1358,8 @@ pfkey_send_x3(so, type, satype) { struct sadb_msg *newmsg; int len; + caddr_t p; + caddr_t ep; /* validity check */ switch (type) { @@ -958,8 +1389,14 @@ pfkey_send_x3(so, type, satype) __ipsec_set_strerror(strerror(errno)); return -1; } + ep = ((caddr_t)newmsg) + len; - (void)pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, getpid()); + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p || p != ep) { + free(newmsg); + return -1; + } /* send message */ len = pfkey_send(so, newmsg, len); @@ -974,10 +1411,12 @@ pfkey_send_x3(so, type, satype) /* sending SADB_X_SPDADD message to the kernel */ static int -pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq) +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq) int so; struct sockaddr *src, *dst; u_int type, prefs, prefd, proto; + u_int64_t ltime, vtime; char *policy; int policylen; u_int32_t seq; @@ -986,6 +1425,7 @@ pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq) int len; caddr_t p; int plen; + caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { @@ -1019,25 +1459,37 @@ pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_lifetime) + policylen; if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } + ep = ((caddr_t)newmsg) + len; - p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, - SADB_SATYPE_UNSPEC, seq, getpid()); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - src, - prefs, - proto); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - dst, - prefd, - proto); + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + 0, 0, ltime, vtime); + if (!p || p + policylen != ep) { + free(newmsg); + return -1; + } memcpy(p, policy, policylen); /* send message */ @@ -1062,6 +1514,7 @@ pfkey_send_x5(so, type, spid) struct sadb_x_policy xpl; int len; caddr_t p; + caddr_t ep; /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) @@ -1071,15 +1524,23 @@ pfkey_send_x5(so, type, spid) __ipsec_set_strerror(strerror(errno)); return -1; } + ep = ((caddr_t)newmsg) + len; - p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, - SADB_SATYPE_UNSPEC, 0, getpid()); + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + if (p + sizeof(xpl) != ep) { + free(newmsg); + return -1; + } memset(&xpl, 0, sizeof(xpl)); xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl)); xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; xpl.sadb_x_policy_id = spid; - memcpy(p, &xpl, sizeof(xpl)); /* send message */ @@ -1143,6 +1604,8 @@ pfkey_close(so) * OUT: * NULL : error occured. * others : a pointer to sadb_msg structure. + * + * XXX should be rewritten to pass length explicitly */ struct sadb_msg * pfkey_recv(so) @@ -1152,7 +1615,8 @@ pfkey_recv(so) int len, reallen; while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { - if (errno == EINTR) continue; + if (errno == EINTR) + continue; __ipsec_set_strerror(strerror(errno)); return NULL; } @@ -1171,7 +1635,8 @@ pfkey_recv(so) } while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { - if (errno == EINTR) continue; + if (errno == EINTR) + continue; __ipsec_set_strerror(strerror(errno)); free(newmsg); return NULL; @@ -1183,6 +1648,13 @@ pfkey_recv(so) return NULL; } + /* don't trust what the kernel says, validate! */ + if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + __ipsec_errcode = EIPSEC_NO_ERROR; return newmsg; } @@ -1219,6 +1691,8 @@ pfkey_send(so, msg, len) * caddr_t mhp[SADB_EXT_MAX + 1]; * OUT: -1: invalid. * 0: valid. + * + * XXX should be rewritten to obtain length explicitly */ int pfkey_align(msg, mhp) @@ -1226,8 +1700,9 @@ pfkey_align(msg, mhp) caddr_t *mhp; { struct sadb_ext *ext; - int tlen, extlen; int i; + caddr_t p; + caddr_t ep; /* XXX should be passed from upper layer */ /* validity check */ if (msg == NULL || mhp == NULL) { @@ -1241,10 +1716,21 @@ pfkey_align(msg, mhp) 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)); + /* initialize */ + p = (caddr_t) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (struct sadb_ext *)p; + if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || + ep < p + PFKEY_EXTLEN(ext)) { + /* invalid format */ + break; + } - while (tlen > 0) { /* duplicate check */ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ if (mhp[ext->sadb_ext_type] != NULL) { @@ -1281,9 +1767,12 @@ pfkey_align(msg, mhp) return -1; } - extlen = PFKEY_EXTLEN(ext); - tlen -= extlen; - ext = (struct sadb_ext *)((caddr_t)ext + extlen); + p += PFKEY_EXTLEN(ext); + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + return -1; } __ipsec_errcode = EIPSEC_NO_ERROR; @@ -1413,8 +1902,9 @@ pfkey_check(mhp) * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid) +pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) caddr_t buf; + caddr_t lim; u_int type, satype; u_int tlen; u_int32_t seq; @@ -1426,6 +1916,9 @@ pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid) p = (struct sadb_msg *)buf; len = sizeof(struct sadb_msg); + if (buf + len > lim) + return NULL; + memset(p, 0, len); p->sadb_msg_version = PF_KEY_V2; p->sadb_msg_type = type; @@ -1444,8 +1937,9 @@ pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid) * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags) +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) caddr_t buf; + caddr_t lim; u_int32_t spi, flags; u_int wsize, auth, enc; { @@ -1455,6 +1949,9 @@ pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags) p = (struct sadb_sa *)buf; len = sizeof(struct sadb_sa); + if (buf + len > lim) + return NULL; + memset(p, 0, len); p->sadb_sa_len = PFKEY_UNIT64(len); p->sadb_sa_exttype = SADB_EXT_SA; @@ -1474,8 +1971,9 @@ pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags) * prefixlen is in bits. */ static caddr_t -pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) +pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) caddr_t buf; + caddr_t lim; u_int exttype; struct sockaddr *saddr; u_int prefixlen; @@ -1487,6 +1985,9 @@ pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) p = (struct sadb_address *)buf; len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + if (buf + len > lim) + return NULL; + memset(p, 0, len); p->sadb_address_len = PFKEY_UNIT64(len); p->sadb_address_exttype = exttype & 0xffff; @@ -1504,8 +2005,10 @@ pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) * OUT: the pointer of buf + len. */ static caddr_t -pfkey_setsadbkey(buf, type, key, keylen) - caddr_t buf, key; +pfkey_setsadbkey(buf, lim, type, key, keylen) + caddr_t buf; + caddr_t lim; + caddr_t key; u_int type, keylen; { struct sadb_key *p; @@ -1514,6 +2017,9 @@ pfkey_setsadbkey(buf, type, key, keylen) p = (struct sadb_key *)buf; len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + if (buf + len > lim) + return NULL; + memset(p, 0, len); p->sadb_key_len = PFKEY_UNIT64(len); p->sadb_key_exttype = type; @@ -1530,8 +2036,9 @@ pfkey_setsadbkey(buf, type, key, keylen) * OUT: the pointer of buf + len. */ static caddr_t -pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) +pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) caddr_t buf; + caddr_t lim; u_int type; u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; { @@ -1541,6 +2048,9 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) p = (struct sadb_lifetime *)buf; len = sizeof(struct sadb_lifetime); + if (buf + len > lim) + return NULL; + memset(p, 0, len); p->sadb_lifetime_len = PFKEY_UNIT64(len); p->sadb_lifetime_exttype = type; @@ -1572,8 +2082,9 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbxsa2(buf, mode0, reqid) +pfkey_setsadbxsa2(buf, lim, mode0, reqid) caddr_t buf; + caddr_t lim; u_int32_t mode0; u_int32_t reqid; { @@ -1584,6 +2095,9 @@ pfkey_setsadbxsa2(buf, mode0, reqid) p = (struct sadb_x_sa2 *)buf; len = sizeof(struct sadb_x_sa2); + if (buf + len > lim) + return NULL; + memset(p, 0, len); p->sadb_x_sa2_len = PFKEY_UNIT64(len); p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; @@ -1592,4 +2106,3 @@ pfkey_setsadbxsa2(buf, mode0, reqid) return(buf + len); } - diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c index 6408651..6c74bcd 100644 --- a/lib/libipsec/pfkey_dump.c +++ b/lib/libipsec/pfkey_dump.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: pfkey_dump.c,v 1.19 2000/06/10 06:47:11 sakane Exp $ */ +/* $KAME: pfkey_dump.c,v 1.27 2001/03/12 09:03:38 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -52,6 +52,29 @@ #include "ipsec_strerror.h" #include "libpfkey.h" +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + #define GETMSGSTR(str, num) \ do { \ if (sizeof((str)[0]) == 0 \ @@ -63,15 +86,33 @@ do { \ printf("%s ", (str)[(num)]); \ } while (0) +#define GETMSGV2S(v2s, num) \ +do { \ + struct val2str *p; \ + for (p = (v2s); p && p->str; p++) { \ + if (p->val == (num)) \ + break; \ + } \ + if (p && p->str) \ + printf("%s ", p->str); \ + else \ + printf("%d ", (num)); \ +} while (0) + static char *str_ipaddr __P((struct sockaddr *)); static char *str_prefport __P((u_int, u_int, u_int)); static char *str_time __P((time_t)); static void str_lifetime_byte __P((struct sadb_lifetime *, char *)); +struct val2str { + int val; + const char *str; +}; + /* * Must to be re-written about following strings. */ -static char *_str_satype[] = { +static char *str_satype[] = { "unspec", "unknown", "ah", @@ -84,13 +125,13 @@ static char *_str_satype[] = { "ipcomp", }; -static char *_str_mode[] = { +static char *str_mode[] = { "any", "transport", "tunnel", }; -static char *_str_upper[] = { +static char *str_upper[] = { /*0*/ "ip", "icmp", "igmp", "ggp", "ip4", "", "tcp", "", "egp", "", /*10*/ "", "", "", "", "", @@ -106,37 +147,57 @@ static char *_str_upper[] = { /*60*/ "dst6", }; -static char *_str_state[] = { +static char *str_state[] = { "larval", "mature", "dying", "dead", }; -static char *_str_alg_auth[] = { - "none", - "hmac-md5", - "hmac-sha1", - "md5", - "sha", - "null", +static struct val2str str_alg_auth[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif + { -1, NULL, }, }; -static char *_str_alg_enc[] = { - "none", - "des-cbc", - "3des-cbc", - "null", - "blowfish-cbc", - "cast128-cbc", - "rc5-cbc", +static struct val2str str_alg_enc[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", }, +#endif + { -1, NULL, }, }; -static char *_str_alg_comp[] = { - "none", - "oui", - "deflate", - "lzs", +static struct val2str str_alg_comp[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL, }, }; /* @@ -204,10 +265,10 @@ pfkey_sadump(m) } printf("\n\t"); - GETMSGSTR(_str_satype, m->sadb_msg_satype); + GETMSGSTR(str_satype, m->sadb_msg_satype); printf("mode="); - GETMSGSTR(_str_mode, m_sa2->sadb_x_sa2_mode); + GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", (u_int32_t)ntohl(m_sa->sadb_sa_spi), @@ -218,11 +279,11 @@ pfkey_sadump(m) /* encryption key */ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { printf("\tC: "); - GETMSGSTR(_str_alg_comp, m_sa->sadb_sa_encrypt); + GETMSGV2S(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); + GETMSGV2S(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"); @@ -232,7 +293,7 @@ pfkey_sadump(m) /* authentication key */ if (m_auth != NULL) { printf("\tA: "); - GETMSGSTR(_str_alg_auth, m_sa->sadb_sa_auth); + GETMSGV2S(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"); @@ -245,7 +306,7 @@ pfkey_sadump(m) /* state */ printf("state="); - GETMSGSTR(_str_state, m_sa->sadb_sa_state); + GETMSGSTR(str_state, m_sa->sadb_sa_state); printf("seq=%lu pid=%lu\n", (u_long)m->sadb_msg_seq, @@ -307,6 +368,7 @@ pfkey_spdump(m) caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *m_saddr, *m_daddr; struct sadb_x_policy *m_xpl; + struct sadb_lifetime *m_lft = NULL; struct sockaddr *sa; u_int16_t port; @@ -323,6 +385,7 @@ pfkey_spdump(m) 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]; + m_lft = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; /* source address */ if (m_saddr == NULL) { @@ -378,7 +441,7 @@ pfkey_spdump(m) if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) printf("any"); else - GETMSGSTR(_str_upper, m_saddr->sadb_address_proto); + GETMSGSTR(str_upper, m_saddr->sadb_address_proto); /* policy */ { @@ -395,6 +458,13 @@ pfkey_spdump(m) free(d_xpl); } + /* lifetime */ + if (m_lft) { + printf("\tlifetime:%lu validtime:%lu\n", + (u_long)m_lft->sadb_lifetime_addtime, + (u_long)m_lft->sadb_lifetime_usetime); + } + printf("\tspid=%ld seq=%ld pid=%ld\n", (u_long)m_xpl->sadb_x_policy_id, (u_long)m->sadb_msg_seq, diff --git a/lib/libipsec/policy_token.l b/lib/libipsec/policy_token.l index 81d632b..91c89dc 100644 --- a/lib/libipsec/policy_token.l +++ b/lib/libipsec/policy_token.l @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: policy_token.l,v 1.9 2000/05/07 05:25:03 itojun Exp $ */ +/* $KAME: policy_token.l,v 1.11 2000/12/01 10:08:29 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -37,7 +37,6 @@ #include <net/route.h> #include <net/pfkeyv2.h> #include <netkey/keydb.h> -#include <netkey/key_debug.h> #include <netinet/in.h> #include <netinet6/ipsec.h> @@ -58,6 +57,7 @@ int yylex __P((void)); %} %option noyywrap +%option nounput /* common section */ nl \n diff --git a/lib/libipsec/test-policy.c b/lib/libipsec/test-policy.c index 5a4faf5..960de20 100644 --- a/lib/libipsec/test-policy.c +++ b/lib/libipsec/test-policy.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: test-policy.c,v 1.13 2000/05/07 05:25:03 itojun Exp $ */ +/* $KAME: test-policy.c,v 1.14 2000/12/27 11:38:11 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -46,6 +46,8 @@ #include <errno.h> #include <err.h> +#include "libpfkey.h" + struct req_t { int result; /* expected result; 0:ok 1:ng */ char *str; @@ -111,9 +113,9 @@ test1() result = test1sub1(&reqs[i]); if (result == 0 && reqs[i].result == 1) { - errx(1, "ERROR: expecting failure.\n"); + warnx("ERROR: expecting failure.\n"); } else if (result == 1 && reqs[i].result == 0) { - errx(1, "ERROR: expecting success.\n"); + warnx("ERROR: expecting success.\n"); } } @@ -245,7 +247,8 @@ test2() errx(1, "ERROR: %s\n", ipsec_strerror()); m = pfkey_recv(so); free(m); - + +#if 0 printf("spdsetidx()\n"); if (pfkey_send_spdsetidx(so, (struct sockaddr *)addr, 128, (struct sockaddr *)addr, 128, @@ -262,6 +265,8 @@ test2() m = pfkey_recv(so); free(m); + sleep(4); + printf("spddelete()\n"); if (pfkey_send_spddelete(so, (struct sockaddr *)addr, 128, (struct sockaddr *)addr, 128, @@ -283,19 +288,31 @@ test2() m = pfkey_recv(so); free(m); + sleep(4); + printf("spddelete2()\n"); if (pfkey_send_spddelete2(so, spid) < 0) errx(1, "ERROR: %s\n", ipsec_strerror()); m = pfkey_recv(so); free(m); +#endif + printf("spdadd() with lifetime's 10(s)\n"); + if (pfkey_send_spdadd2(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, 0, 10, sp2, splen2, 0) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + spid = test2sub(so); + +#if 0 /* expecting failure */ printf("spdupdate()\n"); if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128, (struct sockaddr *)addr, 128, 255, sp2, splen2, 0) == 0) { - errx(1, "ERROR: expecting failure.\n"); + warnx("ERROR: expecting failure.\n"); } +#endif return 0; } diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 176af6a..e4ef0f4 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -256,6 +256,19 @@ list of available options. .It Fl mediaopt Ar opts If the driver supports the media selection system, disable the specified media options on the interface. +.It Cm tunnel Ar src_addr Ar dest_addr +(IP tunnel devices only) +Configure the physical source and destination address for IP tunnel +interfaces (gif). The arguments +.Ar src_addr +and +.Ar dest_addr +are interpreted as the outer source/destination for the encapsulating +IPv4/IPv6 header. +.It Cm deletetunnel +Unconfigure the physical source and destination address for IP tunnel +interfaces previously configured with +.Cm tunnel . .It Cm vlan Ar vlan_tag If the interface is a vlan pseudo interface, set the vlan tag value to diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index f865af24..72c0f16 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -149,35 +149,43 @@ void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); void status __P((const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, struct if_msghdr *ifm, struct ifa_msghdr *ifam)); +void tunnel_status __P((int s)); void usage __P((void)); void ifmaybeload __P((char *name)); #ifdef INET6 +void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); int prefix __P((void *, int)); static char *sec2str __P((time_t)); int explicit_prefix = 0; #endif typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); +typedef void c_func2 __P((const char *arg, const char *arg2, int s, const struct afswtch *afp)); c_func setatphase, setatrange; c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask; +c_func2 settunnel; +c_func deletetunnel; #ifdef INET6 c_func setifprefixlen; c_func setip6flags; -c_func setip6vltime; c_func setip6pltime; +c_func setip6vltime; +c_func2 setip6lifetime; #endif c_func setifipdst; c_func setifflags, setifmetric, setifmtu, setiflladdr; #define NEXTARG 0xffffff +#define NEXTARG2 0xfffffe const struct cmd { const char *c_name; int c_parameter; /* NEXTARG means next argv */ void (*c_func) __P((const char *, int, int, const struct afswtch *afp)); + void (*c_func2) __P((const char *, const char *, int, const struct afswtch *afp)); } cmds[] = { { "up", IFF_UP, setifflags } , { "down", -IFF_UP, setifflags }, @@ -201,14 +209,20 @@ struct cmd { { "anycast", IN6_IFF_ANYCAST, setip6flags }, { "tentative", IN6_IFF_TENTATIVE, setip6flags }, { "-tentative", -IN6_IFF_TENTATIVE, setip6flags }, - { "vltime", NEXTARG, setip6vltime }, + { "deprecated", IN6_IFF_DEPRECATED, setip6flags }, + { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags }, + { "autoconf", IN6_IFF_AUTOCONF, setip6flags }, + { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags }, { "pltime", NEXTARG, setip6pltime }, + { "vltime", NEXTARG, setip6vltime }, #endif { "range", NEXTARG, setatrange }, { "phase", NEXTARG, setatphase }, { "metric", NEXTARG, setifmetric }, { "broadcast", NEXTARG, setifbroadaddr }, { "ipdst", NEXTARG, setifipdst }, + { "tunnel", NEXTARG2, NULL, settunnel }, + { "deletetunnel", 0, deletetunnel }, { "link0", IFF_LINK0, setifflags }, { "-link0", -IFF_LINK0, setifflags }, { "link1", IFF_LINK1, setifflags }, @@ -600,13 +614,19 @@ ifconfig(argc, argv, afp) break; if (p->c_name == 0 && setaddr) p++; /* got src, do dst */ - if (p->c_func) { + if (p->c_func || p->c_func2) { if (p->c_parameter == NEXTARG) { if (argv[1] == NULL) errx(1, "'%s' requires argument", p->c_name); (*p->c_func)(argv[1], 0, s, afp); argc--, argv++; + } else if (p->c_parameter == NEXTARG2) { + if (argc < 3) + errx(1, "'%s' requires 2 arguments", + p->c_name); + (*p->c_func2)(argv[1], argv[2], s, afp); + argc -= 2, argv += 2; } else (*p->c_func)(*argv, p->c_parameter, s, afp); } @@ -704,6 +724,82 @@ setifaddr(addr, param, s, afp) } void +settunnel(src, dst, s, afp) + const char *src, *dst; + int s; + const struct afswtch *afp; +{ + struct addrinfo hints, *srcres, *dstres; + struct ifaliasreq addreq; + int ecode; +#ifdef INET6 + struct in6_aliasreq in6_addreq; +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afp->af_af; + + if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) + errx(1, + "source and destination address families do not match"); + + switch (srcres->ai_addr->sa_family) { + case AF_INET: + memset(&addreq, 0, sizeof(addreq)); + strncpy(addreq.ifra_name, name, IFNAMSIZ); + memcpy(&addreq.ifra_addr, srcres->ai_addr, + srcres->ai_addr->sa_len); + memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) + warn("SIOCSIFPHYADDR"); + break; + +#ifdef INET6 + case AF_INET6: + memset(&in6_addreq, 0, sizeof(in6_addreq)); + strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); + memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, + srcres->ai_addr->sa_len); + memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) + warn("SIOCSIFPHYADDR_IN6"); + break; +#endif /* INET6 */ + + default: + warn("address family not supported"); + } + + freeaddrinfo(srcres); + freeaddrinfo(dstres); +} + +/* ARGSUSED */ +void +deletetunnel(vname, param, s, afp) + const char *vname; + int param; + int s; + const struct afswtch *afp; +{ + + if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) + err(1, "SIOCDIFPHYADDR"); +} + +void setifnetmask(addr, dummy, s, afp) const char *addr; int dummy __unused; @@ -745,23 +841,48 @@ setip6flags(dummyaddr, flag, dummysoc, afp) } void -setip6vltime(seconds, dummy, s, afp) +setip6pltime(seconds, dummy, s, afp) const char *seconds; int dummy __unused; int s; const struct afswtch *afp; { - in6_addreq.ifra_lifetime.ia6t_vltime = atoi(seconds); + setip6lifetime("pltime", seconds, s, afp); } void -setip6pltime(seconds, dummy, s, afp) +setip6vltime(seconds, dummy, s, afp) const char *seconds; int dummy __unused; int s; const struct afswtch *afp; { - in6_addreq.ifra_lifetime.ia6t_pltime = atoi(seconds); + setip6lifetime("vltime", seconds, s, afp); +} + +void +setip6lifetime(cmd, val, s, afp) + const char *cmd; + const char *val; + int s; + const struct afswtch *afp; +{ + time_t newval, t; + char *ep; + + t = time(NULL); + newval = (time_t)strtoul(val, &ep, 0); + if (val == ep) + errx(1, "invalid %s", cmd); + if (afp->af_af != AF_INET6) + errx(1, "%s not allowed for the AF", cmd); + if (strcmp(cmd, "vltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_expire = t + newval; + in6_addreq.ifra_lifetime.ia6t_vltime = newval; + } else if (strcmp(cmd, "pltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; + in6_addreq.ifra_lifetime.ia6t_pltime = newval; + } } #endif @@ -964,6 +1085,8 @@ status(afp, addrcount, sdl, ifm, ifam) printf(" mtu %d", mtu); putchar('\n'); + tunnel_status(s); + while (addrcount > 0) { info.rti_addrs = ifam->ifam_addrs; @@ -1015,6 +1138,73 @@ status(afp, addrcount, sdl, ifm, ifam) } void +tunnel_status(s) + int s; +{ + char psrcaddr[NI_MAXHOST]; + char pdstaddr[NI_MAXHOST]; + u_long srccmd, dstcmd; + struct ifreq *ifrp; + const char *ver = ""; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif +#ifdef INET6 + struct in6_ifreq in6_ifr; + int s6; +#endif /* INET6 */ + + psrcaddr[0] = pdstaddr[0] = '\0'; + +#ifdef INET6 + memset(&in6_ifr, 0, sizeof(in6_ifr)); + strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); + s6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (s6 < 0) { + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; + ifrp = 𝔦 + } else { + close(s6); + srccmd = SIOCGIFPSRCADDR_IN6; + dstcmd = SIOCGIFPDSTADDR_IN6; + ifrp = (struct ifreq *)&in6_ifr; + } +#else /* INET6 */ + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; + ifrp = 𝔦 +#endif /* INET6 */ + + if (ioctl(s, srccmd, (caddr_t)ifrp) < 0) + return; +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); +#endif + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + psrcaddr, sizeof(psrcaddr), 0, 0, niflag); +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + ver = "6"; +#endif + + if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0) + return; +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); +#endif + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + pdstaddr, sizeof(pdstaddr), 0, 0, niflag); + + printf("\ttunnel inet%s %s --> %s\n", ver, + psrcaddr, pdstaddr); +} + +void in_status(s, info) int s __unused; struct rt_addrinfo * info; @@ -1050,6 +1240,19 @@ in_status(s, info) #ifdef INET6 void +in6_fillscopeid(sin6) + struct sockaddr_in6 *sin6; +{ +#if defined(__KAME__) && defined(KAME_SCOPEID) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} + +void in6_status(s, info) int s __unused; struct rt_addrinfo * info; @@ -1146,16 +1349,20 @@ in6_status(s, info) printf("prefixlen %d ", prefix(&sin->sin6_addr, sizeof(struct in6_addr))); - if (flags6 & IN6_IFF_ANYCAST) + if ((flags6 & IN6_IFF_ANYCAST) != 0) printf("anycast "); - if (flags6 & IN6_IFF_TENTATIVE) + if ((flags6 & IN6_IFF_TENTATIVE) != 0) printf("tentative "); - if (flags6 & IN6_IFF_DUPLICATED) + if ((flags6 & IN6_IFF_DUPLICATED) != 0) printf("duplicated "); - if (flags6 & IN6_IFF_DETACHED) + if ((flags6 & IN6_IFF_DETACHED) != 0) printf("detached "); - if (flags6 & IN6_IFF_DEPRECATED) + if ((flags6 & IN6_IFF_DEPRECATED) != 0) printf("deprecated "); + if ((flags6 & IN6_IFF_AUTOCONF) != 0) + printf("autoconf "); + if ((flags6 & IN6_IFF_TEMPORARY) != 0) + printf("temporary "); if (scopeid) printf("scopeid 0x%x ", scopeid); diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8 index 6f8855d..eb3251c 100644 --- a/sbin/ping6/ping6.8 +++ b/sbin/ping6/ping6.8 @@ -1,4 +1,4 @@ -.\" $KAME: ping6.8,v 1.22 2000/05/31 17:00:07 itojun Exp $ +.\" $KAME: ping6.8,v 1.39 2001/04/04 00:08:34 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -40,9 +40,9 @@ packets to network hosts .Sh SYNOPSIS .Nm .\" without ipsec, or new ipsec -.Op Fl dfHnNqRvw +.Op Fl dfHnNqRtvw .\" old ipsec -.\" .Op Fl AdEfnNqRvw +.\" .Op Fl AdEfnNqRtvw .Bk -words .Op Fl a Ar addrtype .Ek @@ -184,13 +184,13 @@ option. If .Ar preload is specified, -.Nm ping +.Nm sends that many packets as fast as possible before falling into its normal mode of behavior. Only the super-user may use this option. .It Fl n Numeric output only. -No attempt will be made to lookup symbolic names for host addresses. +No attempt will be made to lookup symbolic names from addresses in the reply. .It Fl N Probe node information multicast group .Pq Li ff02::2:xxxx:xxxx . @@ -213,11 +213,6 @@ For example, .Dq Li \-p ff will cause the sent packet to be filled with all ones. -.Fl Q -flag, -.Nm -prints out any ICMP error messages caused by its own ECHO_REQUEST -messages. .\" new ipsec .It Fl P Ar policy .Ar policy @@ -259,6 +254,13 @@ header data. You may need to specify .Fl b as well to extend socket buffer size. +.It Fl t +Generate ICMPv6 Node Information supported query types query, +rather than echo-request. +.Fl s +has no effect if +.Fl t +is specified. .It Fl v Verbose output. .Tn ICMP @@ -266,7 +268,7 @@ packets other than .Tn ECHO_RESPONSE that are received are listed. .It Fl w -Generate ICMPv6 Node Information FQDN query, rather than echo-request. +Generate ICMPv6 Node Information DNS Name query, rather than echo-request. .Fl s has no effect if .Fl w @@ -335,7 +337,7 @@ during normal operations or from automated scripts. .\" If less than eight bytes of pad are specified, no round trip times are .\" given. .Sh DUPLICATE AND DAMAGED PACKETS -.Nm Ping6 +.Nm will report duplicate and damaged packets. Duplicate packets should never occur when pinging a unicast address, and seem to be caused by @@ -350,7 +352,7 @@ to the same request. .Pp Damaged packets are obviously serious cause for alarm and often indicate broken hardware somewhere in the -.Nm ping +.Nm packet's path .Pq in the network or in the hosts . .Sh TRYING DIFFERENT DATA PATTERNS @@ -386,8 +388,39 @@ option of .Nm returns 0 on success (the host is alive), and non-zero if the arguments are incorrect or the host is not responding. +.Sh EXAMPLES +Normally, +.Xr ping6 8 +works just like +.Xr ping 8 +would work; the following will send ICMPv6 echo request to +.Li dst.foo.com . +.Bd -literal -offset indent +ping6 -n dst.foo.com +.Ed +.Pp +The following will probe hostnames for all nodes on the network link attached to +.Li wi0 +interface. +The address +.Li ff02::1 +is named the link-local all-node multicast address, and the packet would +reach every node on the network link. +.Bd -literal -offset indent +ping6 -w ff02::1%wi0 +.Ed +.Pp +The following will probe addresses assigned to the destination node, +.Li dst.foo.com . +.Bd -literal -offset indent +ping6 -a agl dst.foo.com +.Ed +.Pp .Sh SEE ALSO .Xr netstat 1 , +.Xr icmp6 4 , +.Xr inet6 4 , +.Xr ip6 4 , .Xr ifconfig 8 , .Xr ping 8 , .Xr routed 8 , @@ -403,8 +436,8 @@ and non-zero if the arguments are incorrect or the host is not responding. .Rs .%A Matt Crawford .%T "IPv6 Node Information Queries" -.%N draft-ietf-ipngwg-icmp-name-lookups-05.txt -.%D October 22, 1999 +.%N draft-ietf-ipngwg-icmp-name-lookups-07.txt +.%D August 2000 .%O work in progress material .Re .Sh BUGS @@ -438,7 +471,7 @@ option (or something like those) to specify the particular address family. This essentially means that we have two different commands. .Sh HISTORY The -.Nm ping +.Xr ping 8 command appeared in .Bx 4.3 . The diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c index 3d529b6..e7079a3 100644 --- a/sbin/ping6/ping6.c +++ b/sbin/ping6/ping6.c @@ -1,4 +1,4 @@ -/* $KAME: ping6.c,v 1.54 2000/06/12 16:16:44 itojun Exp $ */ +/* $KAME: ping6.c,v 1.126 2001/05/17 03:39:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -99,8 +99,8 @@ static const char rcsid[] = /* * NOTE: * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics - * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* while - * IPV6_PKTINFO specifies *interface*. Link is defined as collection of + * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* + * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of * network attached to 1 or more interfaces) */ @@ -116,12 +116,16 @@ static const char rcsid[] = #include <netinet/ip6.h> #include <netinet/icmp6.h> #include <arpa/inet.h> +#include <arpa/nameser.h> #include <netdb.h> #include <ctype.h> #include <err.h> #include <errno.h> #include <fcntl.h> +#if defined(__OpenBSD__) || defined(__NetBSD__) +#include <math.h> +#endif #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -144,7 +148,8 @@ static const char rcsid[] = #define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ #define ICMP6ECHOTMLEN sizeof(struct timeval) #define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) -#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) /* 64 bits of nonce + 32 bits ttl */ +/* FQDN case, 64 bits of nonce + 32 bits ttl */ +#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) #define EXTRA 256 /* for AH and various other headers. weird. */ #define DEFDATALEN ICMP6ECHOTMLEN #define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN @@ -158,7 +163,6 @@ static const char rcsid[] = #define F_FLOOD 0x0001 #define F_INTERVAL 0x0002 -#define F_NUMERIC 0x0004 #define F_PINGFILLED 0x0008 #define F_QUIET 0x0010 #define F_RROUTE 0x0020 @@ -182,13 +186,16 @@ static const char rcsid[] = #define F_HOSTNAME 0x10000 #define F_FQDNOLD 0x20000 #define F_NIGROUP 0x40000 +#define F_SUPTYPES 0x80000 +#define F_NOMINMTU 0x100000 +#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) u_int options; #define IN6LEN sizeof(struct in6_addr) #define SA6LEN sizeof(struct sockaddr_in6) -#define DUMMY_PORT 10101 +#define DUMMY_PORT 10101 -#define SIN6(s) ((struct sockaddr_in6 *)(s)) +#define SIN6(s) ((struct sockaddr_in6 *)(s)) /* * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum @@ -199,9 +206,9 @@ u_int options; int mx_dup_ck = MAX_DUP_CHK; char rcvd_tbl[MAX_DUP_CHK / 8]; -struct addrinfo *res; -struct sockaddr_in6 dst; /* who to ping6 */ -struct sockaddr_in6 src; /* src addr of this packet */ +struct addrinfo *res; +struct sockaddr_in6 dst; /* who to ping6 */ +struct sockaddr_in6 src; /* src addr of this packet */ int datalen = DEFDATALEN; int s; /* socket file descriptor */ u_char outpack[MAXPACKETLEN]; @@ -209,21 +216,26 @@ char BSPACE = '\b'; /* characters written for flood */ char DOT = '.'; char *hostname; int ident; /* process id to identify our packets */ +u_int8_t nonce[8]; /* nonce field for node information */ struct in6_addr srcaddr; +int hoplimit = -1; /* hoplimit */ +int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */ /* counters */ long npackets; /* max packets to transmit */ long nreceived; /* # of packets we got back */ long nrepeats; /* number of duplicates */ long ntransmitted; /* sequence # for outbound packets = #sent */ -int interval = 1; /* interval between packets */ -int hoplimit = -1; /* hoplimit */ +struct timeval interval = {1, 0}; /* interval between packets */ /* timing */ int timing; /* flag to do timing */ double tmin = 999999999.0; /* minimum round trip time */ double tmax = 0.0; /* maximum round trip time */ double tsum = 0.0; /* sum of all times, for doing average */ +#if defined(__OpenBSD__) || defined(__NetBSD__) +double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ +#endif /* for node addresses */ u_short naflags; @@ -233,22 +245,38 @@ struct msghdr smsghdr; struct iovec smsgiov; char *scmsg = 0; +volatile int signo; +volatile sig_atomic_t seenalrm; +volatile sig_atomic_t seenint; +#ifdef SIGINFO +volatile sig_atomic_t seeninfo; +#endif + int main __P((int, char *[])); void fill __P((char *, char *)); int get_hoplim __P((struct msghdr *)); +int get_pathmtu __P((struct msghdr *)); +void set_pathmtu __P((int)); struct in6_pktinfo *get_rcvpktinfo __P((struct msghdr *)); -void onalrm __P((int)); -void oninfo __P((int)); +void onsignal __P((int)); +void retransmit __P((void)); void onint __P((int)); +size_t pingerlen __P((void)); void pinger __P((void)); -const char *pr_addr __P((struct sockaddr_in6 *)); +const char *pr_addr __P((struct sockaddr *, int)); void pr_icmph __P((struct icmp6_hdr *, u_char *)); void pr_iph __P((struct ip6_hdr *)); +void pr_suptypes __P((struct icmp6_nodeinfo *, size_t)); void pr_nodeaddr __P((struct icmp6_nodeinfo *, int)); +int myechoreply __P((const struct icmp6_hdr *)); +int mynireply __P((const struct icmp6_nodeinfo *)); +char *dnsdecode __P((const u_char **, const u_char *, const u_char *, + u_char *, size_t)); void pr_pack __P((u_char *, int, struct msghdr *)); void pr_exthdrs __P((struct msghdr *)); void pr_ip6opt __P((void *)); void pr_rthdr __P((void *)); +int pr_bitrange __P((u_int32_t, int, int)); void pr_retip __P((struct ip6_hdr *, u_char *)); void summary __P((void)); void tvsub __P((struct timeval *, struct timeval *)); @@ -263,7 +291,7 @@ main(argc, argv) { struct itimerval itimer; struct sockaddr_in6 from; - struct timeval timeout; + struct timeval timeout, *tv; struct addrinfo hints; fd_set *fdmaskp; int fdmasks; @@ -283,6 +311,8 @@ main(argc, argv) char *policy_in = NULL; char *policy_out = NULL; #endif + double intval; + size_t rthlen; /* just to be sure */ memset(&smsghdr, 0, sizeof(&smsghdr)); @@ -291,54 +321,62 @@ main(argc, argv) preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; #ifndef IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwW")) != EOF) +#define ADDOPTS #else #ifdef IPSEC_POLICY_IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWP:")) != EOF) +#define ADDOPTS "P:" #else - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWAE")) != EOF) +#define ADDOPTS "AE" #endif /*IPSEC_POLICY_IPSEC*/ #endif - { - switch(ch) { - case 'a': - { - char *cp; - - options |= F_NODEADDR; - datalen = 2048; /* XXX: enough? */ - for (cp = optarg; *cp != '\0'; cp++) { - switch(*cp) { - case 'a': - naflags |= NI_NODEADDR_FLAG_ALL; - break; - case 'c': - case 'C': - naflags |= NI_NODEADDR_FLAG_COMPAT; - break; - case 'l': - case 'L': - naflags |= NI_NODEADDR_FLAG_LINKLOCAL; - break; - case 's': - case 'S': - naflags |= NI_NODEADDR_FLAG_SITELOCAL; - break; - case 'g': - case 'G': - naflags |= NI_NODEADDR_FLAG_GLOBAL; - break; - case 'A': /* experimental. not in the spec */ - naflags |= NI_NODEADDR_FLAG_ANYCAST; - break; - default: - usage(); - /*NOTREACHED*/ - } - } - break; - } - case 'b': + while ((ch = getopt(argc, argv, + "a:b:c:dfHh:I:i:l:mnNp:qRS:s:tvwW" ADDOPTS)) != -1) { +#undef ADDOPTS + switch (ch) { + case 'a': + { + char *cp; + + options &= ~F_NOUSERDATA; + options |= F_NODEADDR; + for (cp = optarg; *cp != '\0'; cp++) { + switch (*cp) { + case 'a': + naflags |= NI_NODEADDR_FLAG_ALL; + break; + case 'c': + case 'C': + naflags |= NI_NODEADDR_FLAG_COMPAT; + break; + case 'l': + case 'L': + naflags |= NI_NODEADDR_FLAG_LINKLOCAL; + break; + case 's': + case 'S': + naflags |= NI_NODEADDR_FLAG_SITELOCAL; + break; + case 'g': + case 'G': + naflags |= NI_NODEADDR_FLAG_GLOBAL; + break; + case 'A': /* experimental. not in the spec */ +#ifdef NI_NODEADDR_FLAG_ANYCAST + naflags |= NI_NODEADDR_FLAG_ANYCAST; + break; +#else + errx(1, +"-a A is not supported on the platform"); + /*NOTREACHED*/ +#endif + default: + usage(); + /*NOTREACHED*/ + } + } + break; + } + case 'b': #if defined(SO_SNDBUF) && defined(SO_RCVBUF) sockbufsize = atoi(optarg); #else @@ -380,10 +418,23 @@ main(argc, argv) #endif break; case 'i': /* wait between sending packets */ - interval = strtol(optarg, &e, 10); - if (interval <= 0 || *optarg == '\0' || *e != '\0') - errx(1, - "illegal timing interval -- %s", optarg); + intval = strtod(optarg, &e); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal timing interval %s", optarg); + if (intval < 1 && getuid()) { + errx(1, "%s: only root may use interval < 1s", + strerror(EPERM)); + } + interval.tv_sec = (long)intval; + interval.tv_usec = + (long)((intval - interval.tv_sec) * 1000000); + if (interval.tv_sec < 0) + errx(1, "illegal timing interval %s", optarg); + /* less than 1/hz does not make sense */ + if (interval.tv_sec == 0 && interval.tv_usec < 10000) { + warnx("too small interval, raised to 0.01"); + interval.tv_usec = 10000; + } options |= F_INTERVAL; break; case 'l': @@ -395,8 +446,16 @@ main(argc, argv) if (preload < 0 || *optarg == '\0' || *e != '\0') errx(1, "illegal preload value -- %s", optarg); break; + case 'm': +#ifdef IPV6_USE_MIN_MTU + options |= F_NOMINMTU; + break; +#else + errx(1, "-%c is not supported on this platform", ch); + /*NOTREACHED*/ +#endif case 'n': - options |= F_NUMERIC; + options &= ~F_HOSTNAME; break; case 'N': options |= F_NIGROUP; @@ -426,18 +485,25 @@ main(argc, argv) datalen = strtol(optarg, &e, 10); if (datalen <= 0 || *optarg == '\0' || *e != '\0') errx(1, "illegal datalen value -- %s", optarg); - if (datalen > MAXDATALEN) + if (datalen > MAXDATALEN) { errx(1, "datalen value too large, maximum is %d", MAXDATALEN); + } + break; + case 't': + options &= ~F_NOUSERDATA; + options |= F_SUPTYPES; break; case 'v': options |= F_VERBOSE; break; case 'w': + options &= ~F_NOUSERDATA; options |= F_FQDN; break; case 'W': + options &= ~F_NOUSERDATA; options |= F_FQDNOLD; break; #ifdef IPSEC @@ -476,11 +542,17 @@ main(argc, argv) } if (argc > 1) { -#ifdef USE_SIN6_SCOPE_ID - ip6optlen += CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1)); -#else /* old advanced API */ - ip6optlen += inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); +#ifdef IPV6_RECVRTHDR /* 2292bis */ + rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, + argc - 1)); +#else /* RFC2292 */ + rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); #endif + if (rthlen == 0) { + errx(1, "too many intermediate hops"); + /*NOTREACHED*/ + } + ip6optlen += rthlen; } if (options & F_NIGROUP) { @@ -494,8 +566,7 @@ main(argc, argv) /* getaddrinfo */ bzero(&hints, sizeof(struct addrinfo)); - if ((options & F_NUMERIC) != 0) - hints.ai_flags = AI_CANONNAME; + hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; @@ -509,28 +580,91 @@ main(argc, argv) hostname = res->ai_canonname; else hostname = target; - + if (!res->ai_addr) errx(1, "getaddrinfo failed"); (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + err(1, "socket"); + + /* + * let the kerel pass extension headers of incoming packets, + * for privileged socket options + */ + if ((options & F_VERBOSE) != 0) { + int opton = 1; + +#ifdef IPV6_RECVHOPOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVHOPOPTS)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_HOPOPTS)"); +#endif +#ifdef IPV6_RECVDSTOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVDSTOPTS)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_DSTOPTS)"); +#endif +#ifdef IPV6_RECVRTHDRDSTOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); +#endif + } + + /* revoke root privilege */ + seteuid(getuid()); + setuid(getuid()); + if (options & F_FLOOD && options & F_INTERVAL) errx(1, "-f and -i incompatible options"); - if (datalen >= sizeof(struct timeval)) /* can we time transfer */ - timing = 1; - packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; + if ((options & F_NOUSERDATA) == 0) { + if (datalen >= sizeof(struct timeval)) { + /* we can time transfer */ + timing = 1; + } else + timing = 0; + /* in F_VERBOSE case, we may get non-echoreply packets*/ + if (options & F_VERBOSE) + packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + else + packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; + } else { + /* suppress timing for node information query */ + timing = 0; + datalen = 2048; + packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + } + if (!(packet = (u_char *)malloc((u_int)packlen))) err(1, "Unable to allocate packet"); if (!(options & F_PINGFILLED)) - for (i = 8; i < datalen; ++i) + for (i = ICMP6ECHOLEN; i < packlen; ++i) *datap++ = i; ident = getpid() & 0xFFFF; - - if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - err(1, "socket"); +#ifndef __OpenBSD__ + gettimeofday(&timeout, NULL); + srand((unsigned int)(timeout.tv_sec ^ timeout.tv_usec ^ (long)ident)); + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < sizeof(nonce); i += sizeof(int)) + *((int *)&nonce[i]) = rand(); +#else + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t)) + *((u_int32_t *)&nonce[i]) = arc4random(); +#endif hold = 1; @@ -540,8 +674,24 @@ main(argc, argv) optval = IPV6_DEFHLIM; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_HOPS"); +#ifdef IPV6_USE_MIN_MTU + if ((options & F_NOMINMTU) == 0) { + optval = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_USE_MIN_MTU)"); + } +#ifdef IPV6_RECVPATHMTU + else { + optval = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_RECVPATHMTU)"); + } +#endif /* IPV6_RECVPATHMTU */ +#endif /* IPV6_USE_MIN_MTU */ #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC @@ -556,18 +706,18 @@ main(argc, argv) optval = IPSEC_LEVEL_REQUIRE; #ifdef IPV6_AUTH_TRANS_LEVEL if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); #else /* old def */ if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_LEVEL)"); #endif } if (options & F_ENCRYPT) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); } #endif /*IPSEC_POLICY_IPSEC*/ @@ -579,7 +729,7 @@ main(argc, argv) if (!(options & F_VERBOSE)) { ICMP6_FILTER_SETBLOCKALL(&filt); if ((options & F_FQDN) || (options & F_FQDNOLD) || - (options & F_NODEADDR)) + (options & F_NODEADDR) || (options & F_SUPTYPES)) ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); else ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); @@ -587,55 +737,31 @@ main(argc, argv) ICMP6_FILTER_SETPASSALL(&filt); } if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - sizeof(filt)) < 0) + sizeof(filt)) < 0) err(1, "setsockopt(ICMP6_FILTER)"); } #endif /*ICMP6_FILTER*/ /* let the kerel pass extension headers of incoming packets */ - /* TODO: implement parsing routine */ if ((options & F_VERBOSE) != 0) { int opton = 1; #ifdef IPV6_RECVRTHDR if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, - sizeof(opton))) + sizeof(opton))) err(1, "setsockopt(IPV6_RECVRTHDR)"); #else /* old adv. API */ if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, - sizeof(opton))) + sizeof(opton))) err(1, "setsockopt(IPV6_RTHDR)"); #endif -#ifdef IPV6_RECVHOPOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, - sizeof(opton))) - err(1, "setsockopt(IPV6_RECVHOPOPTS)"); -#else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, - sizeof(opton))) - err(1, "setsockopt(IPV6_HOPOPTS)"); -#endif -#ifdef IPV6_RECVDSTOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, - sizeof(opton))) - err(1, "setsockopt(IPV6_RECVDSTOPTS)"); -#else /* olad adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, - sizeof(opton))) - err(1, "setsockopt(IPV6_DSTOPTS)"); -#endif -#ifdef IPV6_RECVRTHDRDSTOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, - sizeof(opton))) - err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); -#endif } /* optval = 1; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_LOOP"); */ @@ -673,7 +799,7 @@ main(argc, argv) #ifndef USE_SIN6_SCOPE_ID /* pktinfo must have already been allocated */ if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) - errx(1, "%s: invalid interface name", ifname); + errx(1, "%s: invalid interface name", ifname); #else if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) errx(1, "%s: invalid interface name", ifname); @@ -714,34 +840,36 @@ main(argc, argv) scmsgp->cmsg_type = IPV6_RTHDR; rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp); rthdr = inet6_rth_init((void *)rthdr, rthdrlen, - IPV6_RTHDR_TYPE_0, argc - 1); + IPV6_RTHDR_TYPE_0, argc - 1); if (rthdr == NULL) errx(1, "can't initialize rthdr"); #else /* old advanced API */ if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp, - IPV6_RTHDR_TYPE_0)) == 0) + IPV6_RTHDR_TYPE_0)) == 0) errx(1, "can't initialize rthdr"); #endif /* USE_RFC2292BIS */ for (hops = 0; hops < argc - 1; hops++) { struct addrinfo *iaip; - if ((error = getaddrinfo(argv[hops], NULL, &hints, &iaip))) + if ((error = getaddrinfo(argv[hops], NULL, &hints, + &iaip))) errx(1, "%s", gai_strerror(error)); - if (SIN6(res->ai_addr)->sin6_family != AF_INET6) + if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6) errx(1, - "bad addr family of an intermediate addr"); + "bad addr family of an intermediate addr"); #ifdef USE_RFC2292BIS if (inet6_rth_add(rthdr, - &(SIN6(iaip->ai_addr))->sin6_addr)) + &(SIN6(iaip->ai_addr))->sin6_addr)) errx(1, "can't add an intermediate node"); #else /* old advanced API */ if (inet6_rthdr_add(scmsgp, - &(SIN6(iaip->ai_addr))->sin6_addr, - IPV6_RTHDR_LOOSE)) + &(SIN6(iaip->ai_addr))->sin6_addr, + IPV6_RTHDR_LOOSE)) errx(1, "can't add an intermediate node"); #endif /* USE_RFC2292BIS */ + freeaddrinfo(iaip); } #ifndef USE_RFC2292BIS @@ -757,7 +885,7 @@ main(argc, argv) * source selection */ int dummy, len = sizeof(src); - + if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) err(1, "UDP socket"); @@ -766,38 +894,31 @@ main(argc, argv) src.sin6_port = ntohs(DUMMY_PORT); src.sin6_scope_id = dst.sin6_scope_id; - -#ifdef USE_SIN6_SCOPE_ID - src.sin6_scope_id = dst.sin6_scope_id; -#endif - #ifdef USE_RFC2292BIS if (pktinfo && setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, - (void *)pktinfo, sizeof(*pktinfo))) + (void *)pktinfo, sizeof(*pktinfo))) err(1, "UDP setsockopt(IPV6_PKTINFO)"); if (hoplimit != -1 && setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT, - (void *)&hoplimit, sizeof(hoplimit))) + (void *)&hoplimit, sizeof(hoplimit))) err(1, "UDP setsockopt(IPV6_HOPLIMIT)"); if (rthdr && setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR, - (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) + (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) err(1, "UDP setsockopt(IPV6_RTHDR)"); #else /* old advanced API */ if (smsghdr.msg_control && setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, - (void *)smsghdr.msg_control, - smsghdr.msg_controllen)) { + (void *)smsghdr.msg_control, smsghdr.msg_controllen)) err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); - } #endif - + if (connect(dummy, (struct sockaddr *)&src, len) < 0) err(1, "UDP connect"); - + if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0) err(1, "getsockname"); @@ -809,10 +930,10 @@ main(argc, argv) if (datalen > sockbufsize) warnx("you need -b to increase socket buffer size"); if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, - sizeof(sockbufsize)) < 0) + sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_SNDBUF)"); if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, - sizeof(sockbufsize)) < 0) + sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_RCVBUF)"); } else { @@ -825,7 +946,8 @@ main(argc, argv) * to get some stuff for /etc/ethers. */ hold = 48 * 1024; - setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); + setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + sizeof(hold)); } #endif @@ -833,64 +955,99 @@ main(argc, argv) #ifndef USE_SIN6_SCOPE_ID #ifdef IPV6_RECVPKTINFO if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, - sizeof(optval)) < 0) + sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ #else /* old adv. API */ if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, - sizeof(optval)) < 0) + sizeof(optval)) < 0) warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ #endif #endif /* USE_SIN6_SCOPE_ID */ #ifdef IPV6_RECVHOPLIMIT if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, - sizeof(optval)) < 0) + sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ #else /* old adv. API */ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, - sizeof(optval)) < 0) + sizeof(optval)) < 0) warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ #endif - printf("PING6(%d=40+8+%d bytes) ", datalen + 48, datalen); - printf("%s --> ", pr_addr(&src)); - printf("%s\n", pr_addr(&dst)); + printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), + (unsigned long)(pingerlen() - 8)); + printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); + printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); while (preload--) /* Fire off them quickies. */ pinger(); - (void)signal(SIGINT, onint); - (void)signal(SIGINFO, oninfo); + (void)signal(SIGINT, onsignal); +#ifdef SIGINFO + (void)signal(SIGINFO, onsignal); +#endif if ((options & F_FLOOD) == 0) { - (void)signal(SIGALRM, onalrm); - itimer.it_interval.tv_sec = interval; - itimer.it_interval.tv_usec = 0; - itimer.it_value.tv_sec = 0; - itimer.it_value.tv_usec = 1; + (void)signal(SIGALRM, onsignal); + itimer.it_interval = interval; + itimer.it_value = interval; (void)setitimer(ITIMER_REAL, &itimer, NULL); + retransmit(); } - fdmasks = howmany(s+1, NFDBITS); + fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); if ((fdmaskp = malloc(fdmasks)) == NULL) err(1, "malloc"); + signo = seenalrm = seenint = 0; +#ifdef SIGINFO + seeninfo = 0; +#endif + for (;;) { struct msghdr m; struct cmsghdr *cm; u_char buf[1024]; struct iovec iov[2]; + /* signal handling */ + if (seenalrm) { + retransmit(); + seenalrm = 0; + continue; + } + if (seenint) { + onint(SIGINT); + seenint = 0; + continue; + } +#ifdef SIGINFO + if (seeninfo) { + summary(); + seeninfo = 0; + continue; + } +#endif + if (options & F_FLOOD) { pinger(); timeout.tv_sec = 0; timeout.tv_usec = 10000; - memset(fdmaskp, 0, fdmasks); - FD_SET(s, fdmaskp); - if (select(s + 1, fdmaskp, NULL, NULL, &timeout) < 1) - continue; - } - fromlen = sizeof(from); + tv = &timeout; + } else + tv = NULL; + memset(fdmaskp, 0, fdmasks); + FD_SET(s, fdmaskp); + cc = select(s + 1, fdmaskp, NULL, NULL, tv); + if (cc < 0) { + if (errno != EINTR) { + warn("select"); + sleep(1); + } + continue; + } else if (cc == 0) + continue; + fromlen = sizeof(from); m.msg_name = (caddr_t)&from; m.msg_namelen = sizeof(from); memset(&iov, 0, sizeof(iov)); @@ -902,14 +1059,35 @@ main(argc, argv) m.msg_control = (caddr_t)buf; m.msg_controllen = sizeof(buf); - if ((cc = recvmsg(s, &m, 0)) < 0) { - if (errno == EINTR) - continue; - warn("recvfrom"); + cc = recvmsg(s, &m, 0); + if (cc < 0) { + if (errno != EINTR) { + warn("recvmsg"); + sleep(1); + } + continue; + } else if (cc == 0) { + int mtu; + + /* + * receive control messages only. Process the + * exceptions (currently the only possiblity is + * a path MTU notification.) + */ + if ((mtu = get_pathmtu(&m)) > 0) { + if ((options & F_VERBOSE) != 0) { + printf("new path MTU (%d) is " + "notified\n", mtu); + } + set_pathmtu(mtu); + } continue; + } else { + /* + * an ICMPv6 message (probably an echoreply) arrived. + */ + pr_pack(packet, cc, &m); } - - pr_pack(packet, cc, &m); if (npackets && nreceived >= npackets) break; } @@ -917,14 +1095,32 @@ main(argc, argv) exit(nreceived == 0); } +void +onsignal(sig) + int sig; +{ + signo = sig; + switch (sig) { + case SIGALRM: + seenalrm++; + break; + case SIGINT: + seenint++; + break; +#ifdef SIGINFO + case SIGINFO: + seeninfo++; + break; +#endif + } +} + /* - * onalrm -- + * retransmit -- * This routine transmits another ping6. */ -/* ARGSUSED */ void -onalrm(signo) - int signo; +retransmit() { struct itimerval itimer; @@ -961,32 +1157,51 @@ onalrm(signo) * of the data portion are used to hold a UNIX "timeval" struct in VAX * byte-order, to compute the round-trip time. */ +size_t +pingerlen() +{ + size_t l; + + if (options & F_FQDN) + l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + else if (options & F_FQDNOLD) + l = ICMP6_NIQLEN; + else if (options & F_NODEADDR) + l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + else if (options & F_SUPTYPES) + l = ICMP6_NIQLEN; + else + l = ICMP6ECHOLEN + datalen; + + return l; +} + void pinger() { struct icmp6_hdr *icp; struct iovec iov[2]; int i, cc; + struct icmp6_nodeinfo *nip; + int seq; icp = (struct icmp6_hdr *)outpack; + nip = (struct icmp6_nodeinfo *)outpack; memset(icp, 0, sizeof(*icp)); - icp->icmp6_code = 0; icp->icmp6_cksum = 0; - icp->icmp6_seq = ntransmitted++; /* htons later */ - icp->icmp6_id = htons(ident); /* ID */ - - CLR(icp->icmp6_seq % mx_dup_ck); - icp->icmp6_seq = htons(icp->icmp6_seq); + seq = ntransmitted++; + CLR(seq % mx_dup_ck); if (options & F_FQDN) { icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; - /* XXX: overwrite icmp6_id */ - ((struct icmp6_nodeinfo *)icp)->ni_qtype = htons(NI_QTYPE_FQDN); - ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0); - if (timing) - (void)gettimeofday((struct timeval *) - &outpack[ICMP6ECHOLEN], NULL); + nip->ni_qtype = htons(NI_QTYPE_FQDN); + nip->ni_flags = htons(0); + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, sizeof(dst.sin6_addr)); cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); @@ -994,39 +1209,58 @@ pinger() } else if (options & F_FQDNOLD) { /* packet format in 03 draft - no Subject data on queries */ icp->icmp6_type = ICMP6_NI_QUERY; - /* code field is always 0 */ - /* XXX: overwrite icmp6_id */ - ((struct icmp6_nodeinfo *)icp)->ni_qtype = htons(NI_QTYPE_FQDN); - ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0); - if (timing) - (void)gettimeofday((struct timeval *) - &outpack[ICMP6ECHOLEN], NULL); + icp->icmp6_code = 0; /* code field is always 0 */ + nip->ni_qtype = htons(NI_QTYPE_FQDN); + nip->ni_flags = htons(0); + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + cc = ICMP6_NIQLEN; datalen = 0; } else if (options & F_NODEADDR) { icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; - /* XXX: overwrite icmp6_id */ - ((struct icmp6_nodeinfo *)icp)->ni_qtype = - htons(NI_QTYPE_NODEADDR); - ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0); - if (timing) - (void)gettimeofday((struct timeval *) - &outpack[ICMP6ECHOLEN], NULL); + nip->ni_qtype = htons(NI_QTYPE_NODEADDR); + nip->ni_flags = naflags; + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, sizeof(dst.sin6_addr)); cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); datalen = 0; - ((struct icmp6_nodeinfo *)icp)->ni_flags = naflags; - } - else { + } else if (options & F_SUPTYPES) { + icp->icmp6_type = ICMP6_NI_QUERY; + icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ + nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); + /* we support compressed bitmap */ + nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS; + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + cc = ICMP6_NIQLEN; + datalen = 0; + } else { icp->icmp6_type = ICMP6_ECHO_REQUEST; + icp->icmp6_code = 0; + icp->icmp6_id = htons(ident); + icp->icmp6_seq = ntohs(seq); if (timing) (void)gettimeofday((struct timeval *) &outpack[ICMP6ECHOLEN], NULL); cc = ICMP6ECHOLEN + datalen; } +#ifdef DIAGNOSTIC + if (pingerlen() != cc) + errx(1, "internal error; length mismatch"); +#endif + smsghdr.msg_name = (caddr_t)&dst; smsghdr.msg_namelen = sizeof(dst); memset(&iov, 0, sizeof(iov)); @@ -1047,6 +1281,91 @@ pinger() (void)write(STDOUT_FILENO, &DOT, 1); } +int +myechoreply(icp) + const struct icmp6_hdr *icp; +{ + if (ntohs(icp->icmp6_id) == ident) + return 1; + else + return 0; +} + +int +mynireply(nip) + const struct icmp6_nodeinfo *nip; +{ + if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), + nonce + sizeof(u_int16_t), + sizeof(nonce) - sizeof(u_int16_t)) == 0) + return 1; + else + return 0; +} + +char * +dnsdecode(sp, ep, base, buf, bufsiz) + const u_char **sp; + const u_char *ep; + const u_char *base; /*base for compressed name*/ + u_char *buf; + size_t bufsiz; +{ + int i; + const u_char *cp; + char cresult[MAXDNAME + 1]; + const u_char *comp; + int l; + + cp = *sp; + *buf = '\0'; + + if (cp >= ep) + return NULL; + while (cp < ep) { + i = *cp; + if (i == 0 || cp != *sp) { + if (strlcat(buf, ".", bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + } + if (i == 0) + break; + cp++; + + if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) { + /* DNS compression */ + if (!base) + return NULL; + + comp = base + (i & 0x3f); + if (dnsdecode(&comp, cp, base, cresult, + sizeof(cresult)) == NULL) + return NULL; + if (strlcat(buf, cresult, bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + break; + } else if ((i & 0x3f) == i) { + if (i > ep - cp) + return NULL; /*source overrun*/ + while (i-- > 0 && cp < ep) { + l = snprintf(cresult, sizeof(cresult), + isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); + if (l >= sizeof(cresult)) + return NULL; + if (strlcat(buf, cresult, bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + cp++; + } + } else + return NULL; /*invalid label*/ + } + if (i != 0) + return NULL; /*not terminated*/ + cp++; + *sp = cp; + return buf; +} + /* * pr_pack -- * Print out the packet, if it came from us. This logic is necessary @@ -1062,9 +1381,11 @@ pr_pack(buf, cc, mhdr) { #define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) struct icmp6_hdr *icp; + struct icmp6_nodeinfo *ni; int i; int hoplim; - struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; + struct sockaddr *from; + int fromlen; u_char *cp = NULL, *dp, *end = buf + cc; struct in6_pktinfo *pktinfo = NULL; struct timeval tv, *tp; @@ -1072,16 +1393,28 @@ pr_pack(buf, cc, mhdr) int dupflag; size_t off; int oldfqdn; + u_int16_t seq; + char dnsname[MAXDNAME + 1]; (void)gettimeofday(&tv, NULL); + if (!mhdr || !mhdr->msg_name || + mhdr->msg_namelen != sizeof(struct sockaddr_in6) || + ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { + if (options & F_VERBOSE) + warnx("invalid peername\n"); + return; + } + from = (struct sockaddr *)mhdr->msg_name; + fromlen = mhdr->msg_namelen; if (cc < sizeof(struct icmp6_hdr)) { if (options & F_VERBOSE) warnx("packet too short (%d bytes) from %s\n", cc, - pr_addr(from)); + pr_addr(from, fromlen)); return; } icp = (struct icmp6_hdr *)buf; + ni = (struct icmp6_nodeinfo *)buf; off = 0; if ((hoplim = get_hoplim(mhdr)) == -1) { @@ -1093,11 +1426,8 @@ pr_pack(buf, cc, mhdr) return; } - if (icp->icmp6_type == ICMP6_ECHO_REPLY) { - /* XXX the following line overwrites the original packet */ - icp->icmp6_seq = ntohs(icp->icmp6_seq); - if (ntohs(icp->icmp6_id) != ident) - return; /* It was not our ECHO */ + if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { + seq = ntohs(icp->icmp6_seq); ++nreceived; if (timing) { tp = (struct timeval *)(icp + 1); @@ -1105,18 +1435,21 @@ pr_pack(buf, cc, mhdr) triptime = ((double)tv.tv_sec) * 1000.0 + ((double)tv.tv_usec) / 1000.0; tsum += triptime; +#if defined(__OpenBSD__) || defined(__NetBSD__) + tsumsq += triptime * triptime; +#endif if (triptime < tmin) tmin = triptime; if (triptime > tmax) tmax = triptime; } - if (TST(icp->icmp6_seq % mx_dup_ck)) { + if (TST(seq % mx_dup_ck)) { ++nrepeats; --nreceived; dupflag = 1; } else { - SET(icp->icmp6_seq % mx_dup_ck); + SET(seq % mx_dup_ck); dupflag = 0; } @@ -1127,18 +1460,21 @@ pr_pack(buf, cc, mhdr) (void)write(STDOUT_FILENO, &BSPACE, 1); else { (void)printf("%d bytes from %s, icmp_seq=%u", cc, - pr_addr(from), - icp->icmp6_seq); + pr_addr(from, fromlen), seq); (void)printf(" hlim=%d", hoplim); if ((options & F_VERBOSE) != 0) { struct sockaddr_in6 dstsa; memset(&dstsa, 0, sizeof(dstsa)); dstsa.sin6_family = AF_INET6; +#ifdef SIN6_LEN dstsa.sin6_len = sizeof(dstsa); +#endif dstsa.sin6_scope_id = pktinfo->ipi6_ifindex; dstsa.sin6_addr = pktinfo->ipi6_addr; - (void)printf(" dst=%s", pr_addr(&dstsa)); + (void)printf(" dst=%s", + pr_addr((struct sockaddr *)&dstsa, + sizeof(dstsa))); } if (timing) (void)printf(" time=%g ms", triptime); @@ -1154,24 +1490,50 @@ pr_pack(buf, cc, mhdr) } } } - } else if (icp->icmp6_type == ICMP6_NI_REPLY) { /* ICMP6_NI_REPLY */ - struct icmp6_nodeinfo *ni = (struct icmp6_nodeinfo *)(buf + off); - - (void)printf("%d bytes from %s: ", cc, - pr_addr(from)); - - switch(ntohs(ni->ni_qtype)) { - case NI_QTYPE_NOOP: - printf("NodeInfo NOOP"); - break; - case NI_QTYPE_SUPTYPES: - printf("NodeInfo Supported Qtypes"); - break; - case NI_QTYPE_NODEADDR: - pr_nodeaddr(ni, end - (u_char *)ni); - break; - case NI_QTYPE_FQDN: - default: /* XXX: for backward compatibility */ + } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) { + seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce); + ++nreceived; + if (TST(seq % mx_dup_ck)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(seq % mx_dup_ck); + dupflag = 0; + } + + if (options & F_QUIET) + return; + + (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); + + switch (ntohs(ni->ni_code)) { + case ICMP6_NI_SUCCESS: + break; + case ICMP6_NI_REFUSED: + printf("refused, type 0x%x", ntohs(ni->ni_type)); + goto fqdnend; + case ICMP6_NI_UNKNOWN: + printf("unknown, type 0x%x", ntohs(ni->ni_type)); + goto fqdnend; + default: + printf("unknown code 0x%x, type 0x%x", + ntohs(ni->ni_code), ntohs(ni->ni_type)); + goto fqdnend; + } + + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + printf("NodeInfo NOOP"); + break; + case NI_QTYPE_SUPTYPES: + pr_suptypes(ni, end - (u_char *)ni); + break; + case NI_QTYPE_NODEADDR: + pr_nodeaddr(ni, end - (u_char *)ni); + break; + case NI_QTYPE_FQDN: + default: /* XXX: for backward compatibility */ cp = (u_char *)ni + ICMP6_NIRLEN; if (buf[off + ICMP6_NIRLEN] == cc - off - ICMP6_NIRLEN - 1) @@ -1179,38 +1541,31 @@ pr_pack(buf, cc, mhdr) else oldfqdn = 0; if (oldfqdn) { - cp++; + cp++; /* skip length */ while (cp < end) { safeputc(*cp & 0xff); cp++; } } else { + i = 0; while (cp < end) { - i = *cp++; - if (i) { - if (i > end - cp) { - printf("???"); - break; - } - while (i-- && cp < end) { - safeputc(*cp & 0xff); - cp++; - } - if (cp + 1 < end && *cp) - printf("."); - } else { - if (cp == end) { - /* FQDN */ - printf("."); - } else if (cp + 1 == end && - *cp == '\0') { - /* truncated */ - } else { - /* invalid */ - printf("???"); - } + if (dnsdecode((const u_char **)&cp, end, + (const u_char *)(ni + 1), dnsname, + sizeof(dnsname)) == NULL) { + printf("???"); break; } + /* + * name-lookup special handling for + * truncated name + */ + if (cp + 1 <= end && !*cp && + strlen(dnsname) > 0) { + dnsname[strlen(dnsname) - 1] = '\0'; + cp++; + } + printf("%s%s", i > 0 ? "," : "", + dnsname); } } if (options & F_VERBOSE) { @@ -1219,7 +1574,7 @@ pr_pack(buf, cc, mhdr) (void)printf(" ("); /*)*/ - switch(ni->ni_code) { + switch (ni->ni_code) { case ICMP6_NI_REFUSED: (void)printf("refused"); comma++; @@ -1231,19 +1586,21 @@ pr_pack(buf, cc, mhdr) } if ((end - (u_char *)ni) < ICMP6_NIRLEN) { - /* case of refusion, unkown */ + /* case of refusion, unknown */ + /*(*/ + putchar(')'); goto fqdnend; } ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); if (comma) printf(","); - if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) + if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) { (void)printf("TTL=%d:meaningless", - (int)ttl); - else { + (int)ttl); + } else { if (ttl < 0) { (void)printf("TTL=%d:invalid", - ttl); + ttl); } else (void)printf("TTL=%d", ttl); } @@ -1269,22 +1626,21 @@ pr_pack(buf, cc, mhdr) if (comma) printf(","); (void)printf("invalid namelen:%d/%lu", - buf[off + ICMP6_NIRLEN], - (u_long)cc - off - ICMP6_NIRLEN - 1); + buf[off + ICMP6_NIRLEN], + (u_long)cc - off - ICMP6_NIRLEN - 1); comma++; } /*(*/ putchar(')'); } - fqdnend: + fqdnend: ; } } else { /* We've got something other than an ECHOREPLY */ if (!(options & F_VERBOSE)) return; - (void)printf("%d bytes from %s: ", cc, - pr_addr(from)); + (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); pr_icmph(icp, end); } @@ -1308,7 +1664,7 @@ pr_exthdrs(mhdr) if (cm->cmsg_level != IPPROTO_IPV6) continue; - switch(cm->cmsg_type) { + switch (cm->cmsg_type) { case IPV6_HOPOPTS: printf(" HbH Options: "); pr_ip6opt(CMSG_DATA(cm)); @@ -1343,13 +1699,13 @@ pr_ip6opt(void *extbuf) ext = (struct ip6_hbh *)extbuf; extlen = (ext->ip6h_len + 1) * 8; - printf("nxt %u, len %u (%d bytes)\n", ext->ip6h_nxt, - ext->ip6h_len, extlen); + printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, + (unsigned int)ext->ip6h_len, (unsigned long)extlen); currentlen = 0; while (1) { currentlen = inet6_opt_next(extbuf, extlen, currentlen, - &type, &len, &databuf); + &type, &len, &databuf); if (currentlen == -1) break; switch (type) { @@ -1360,19 +1716,20 @@ pr_ip6opt(void *extbuf) case IP6OPT_JUMBO: offset = 0; offset = inet6_opt_get_val(databuf, offset, - &value4, sizeof(value4)); + &value4, sizeof(value4)); printf(" Jumbo Payload Opt: Length %u\n", - (unsigned int)ntohl(value4)); + (u_int32_t)ntohl(value4)); break; case IP6OPT_ROUTER_ALERT: offset = 0; offset = inet6_opt_get_val(databuf, offset, &value2, sizeof(value2)); printf(" Router Alert Opt: Type %u\n", - ntohs(value2)); + ntohs(value2)); break; default: - printf(" Received Opt %u len %u\n", type, len); + printf(" Received Opt %u len %lu\n", + type, (unsigned long)len); break; } } @@ -1399,7 +1756,7 @@ pr_rthdr(void *extbuf) /* print fixed part of the header */ printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, - rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); + rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); if ((segments = inet6_rth_segments(extbuf)) >= 0) printf("%d segments, ", segments); else @@ -1410,15 +1767,18 @@ pr_rthdr(void *extbuf) in6 = inet6_rth_getaddr(extbuf, i); if (in6 == NULL) printf(" [%d]<NULL>\n", i); - else - printf(" [%d]%s\n", i, - inet_ntop(AF_INET6, in6, - ntopbuf, sizeof(ntopbuf))); + else { + if (!inet_ntop(AF_INET6, in6, ntopbuf, + sizeof(ntopbuf))) + strncpy(ntopbuf, "?", sizeof(ntopbuf)); + printf(" [%d]%s\n", i, ntopbuf); + } } return; - + } + #else /* !USE_RFC2292BIS */ /* ARGSUSED */ void @@ -1429,35 +1789,186 @@ pr_rthdr(void *extbuf) } #endif /* USE_RFC2292BIS */ +int +pr_bitrange(v, s, ii) + u_int32_t v; + int s; + int ii; +{ + int off; + int i; + + off = 0; + while (off < 32) { + /* shift till we have 0x01 */ + if ((v & 0x01) == 0) { + if (ii > 1) + printf("-%u", s + off - 1); + ii = 0; + switch (v & 0x0f) { + case 0x00: + v >>= 4; + off += 4; + continue; + case 0x08: + v >>= 3; + off += 3; + continue; + case 0x04: case 0x0c: + v >>= 2; + off += 2; + continue; + default: + v >>= 1; + off += 1; + continue; + } + } + + /* we have 0x01 with us */ + for (i = 0; i < 32 - off; i++) { + if ((v & (0x01 << i)) == 0) + break; + } + if (!ii) + printf(" %u", s + off); + ii += i; + v >>= i; off += i; + } + return ii; +} + +void +pr_suptypes(ni, nilen) + struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */ + size_t nilen; +{ + size_t clen; + u_int32_t v; + const u_char *cp, *end; + u_int16_t cur; + struct cbit { + u_int16_t words; /*32bit count*/ + u_int16_t skip; + } cbit; +#define MAXQTYPES (1 << 16) + size_t off; + int b; + + cp = (u_char *)(ni + 1); + end = ((u_char *)ni) + nilen; + cur = 0; + b = 0; + + printf("NodeInfo Supported Qtypes"); + if (options & F_VERBOSE) { + if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) + printf(", compressed bitmap"); + else + printf(", raw bitmap"); + } + + while (cp < end) { + clen = (size_t)(end - cp); + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) { + if (clen == 0 || clen > MAXQTYPES / 8 || + clen % sizeof(v)) { + printf("???"); + return; + } + } else { + if (clen < sizeof(cbit) || clen % sizeof(v)) + return; + memcpy(&cbit, cp, sizeof(cbit)); + if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) > + clen) + return; + cp += sizeof(cbit); + clen = ntohs(cbit.words) * sizeof(v); + if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 > + MAXQTYPES) + return; + } + + for (off = 0; off < clen; off += sizeof(v)) { + memcpy(&v, cp + off, sizeof(v)); + v = (u_int32_t)ntohl(v); + b = pr_bitrange(v, (int)(cur + off * 8), b); + } + /* flush the remaining bits */ + b = pr_bitrange(0, (int)(cur + off * 8), b); + + cp += clen; + cur += clen * 8; + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) + cur += ntohs(cbit.skip) * 32; + } +} void pr_nodeaddr(ni, nilen) struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */ int nilen; { - struct in6_addr *ia6 = (struct in6_addr *)(ni + 1); + u_char *cp = (u_char *)(ni + 1); char ntop_buf[INET6_ADDRSTRLEN]; + int withttl = 0; nilen -= sizeof(struct icmp6_nodeinfo); if (options & F_VERBOSE) { - switch(ni->ni_code) { - case ICMP6_NI_REFUSED: - (void)printf("refused"); - break; - case ICMP6_NI_UNKNOWN: - (void)printf("unknown qtype"); - break; + switch (ni->ni_code) { + case ICMP6_NI_REFUSED: + (void)printf("refused"); + break; + case ICMP6_NI_UNKNOWN: + (void)printf("unknown qtype"); + break; } - if (ni->ni_flags & NI_NODEADDR_FLAG_ALL) + if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE) (void)printf(" truncated"); } putchar('\n'); if (nilen <= 0) printf(" no address\n"); - for (; nilen > 0; nilen -= sizeof(*ia6), ia6 += 1) { - printf(" %s\n", - inet_ntop(AF_INET6, ia6, ntop_buf, sizeof(ntop_buf))); + + /* + * In icmp-name-lookups 05 and later, TTL of each returned address + * is contained in the resposne. We try to detect the version + * by the length of the data, but note that the detection algorithm + * is incomplete. We assume the latest draft by default. + */ + if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) + withttl = 1; + while (nilen > 0) { + u_int32_t ttl; + + if (withttl) { + /* XXX: alignment? */ + ttl = (u_int32_t)ntohl(*(u_int32_t *)cp); + cp += sizeof(u_int32_t); + nilen -= sizeof(u_int32_t); + } + + if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) == + NULL) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf(" %s", ntop_buf); + if (withttl) { + if (ttl == 0xffffffff) { + /* + * XXX: can this convention be applied to all + * type of TTL (i.e. non-ND TTL)? + */ + printf("(TTL=infty)"); + } + else + printf("(TTL=%u)", ttl); + } + putchar('\n'); + + nilen -= sizeof(struct in6_addr); + cp += sizeof(struct in6_addr); } } @@ -1469,6 +1980,9 @@ get_hoplim(mhdr) for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(-1); + if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT && cm->cmsg_len == CMSG_LEN(sizeof(int))) @@ -1486,6 +2000,9 @@ get_rcvpktinfo(mhdr) for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(NULL); + if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) @@ -1495,6 +2012,116 @@ get_rcvpktinfo(mhdr) return(NULL); } +int +get_pathmtu(mhdr) + struct msghdr *mhdr; +{ +#ifdef IPV6_RECVPATHMTU + struct cmsghdr *cm; + struct ip6_mtuinfo *mtuctl = NULL; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(0); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PATHMTU && + cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { + mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm); + + /* + * If the notified destination is different from + * the one we are pinging, just ignore the info. + * We check the scope ID only when both notified value + * and our own value have non-0 values, because we may + * have used the default scope zone ID for sending, + * in which case the scope ID value is 0. + */ + if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr, + &dst.sin6_addr) || + (mtuctl->ip6m_addr.sin6_scope_id && + dst.sin6_scope_id && + mtuctl->ip6m_addr.sin6_scope_id != + dst.sin6_scope_id)) { + if ((options & F_VERBOSE) != 0) { + printf("path MTU for %s is notified. " + "(ignored)\n", + pr_addr((struct sockaddr *)&mtuctl->ip6m_addr, + sizeof(mtuctl->ip6m_addr))); + } + return(0); + } + + /* + * Ignore an invalid MTU. XXX: can we just believe + * the kernel check? + */ + if (mtuctl->ip6m_mtu < IPV6_MMTU) + return(0); + + /* notification for our destination. return the MTU. */ + return((int)mtuctl->ip6m_mtu); + } + } +#endif + return(0); +} + +void +set_pathmtu(mtu) + int mtu; +{ +#ifdef IPV6_USE_MTU + static int firsttime = 1; + struct cmsghdr *cm; + + if (firsttime) { + int oldlen = smsghdr.msg_controllen; + char *oldbuf = smsghdr.msg_control; + + /* XXX: We need to enlarge control message buffer */ + firsttime = 0; /* prevent further enlargement */ + + smsghdr.msg_controllen = oldlen + CMSG_SPACE(sizeof(int)); + if ((smsghdr.msg_control = + (char *)malloc(smsghdr.msg_controllen)) == NULL) + err(1, "set_pathmtu: malloc"); + cm = (struct cmsghdr *)CMSG_FIRSTHDR(&smsghdr); + cm->cmsg_len = CMSG_LEN(sizeof(int)); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_USE_MTU; + + cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm); + if (oldlen) + memcpy((void *)cm, (void *)oldbuf, oldlen); + + free(oldbuf); + } + + /* + * look for a cmsgptr that points MTU structure. + * XXX: this procedure seems redundant at this moment, but we'd better + * keep the code generic enough for future extensions. + */ + for (cm = CMSG_FIRSTHDR(&smsghdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm)) { + if (cm->cmsg_len == 0) /* XXX: paranoid check */ + errx(1, "set_pathmtu: internal error"); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_USE_MTU && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + break; + } + + if (cm == NULL) + errx(1, "set_pathmtu: internal error: no space for path MTU"); + + *(int *)CMSG_DATA(cm) = mtu; +#endif +} + /* * tvsub -- * Subtract 2 timeval structs: out = out - in. Out is assumed to @@ -1512,18 +2139,6 @@ tvsub(out, in) } /* - * oninfo -- - * SIGINFO handler. - */ -/* ARGSUSED */ -void -oninfo(notused) - int notused; -{ - summary(); -} - -/* * onint -- * SIGINT handler. */ @@ -1548,7 +2163,6 @@ onint(notused) void summary() { - register int i; (void)printf("\n--- %s ping6 statistics ---\n", hostname); (void)printf("%ld packets transmitted, ", ntransmitted); @@ -1566,28 +2180,35 @@ summary() (void)putchar('\n'); if (nreceived && timing) { /* Only display average to microseconds */ - i = 1000.0 * tsum / (nreceived + nrepeats); - (void)printf("round-trip min/avg/max = %g/%g/%g ms\n", - tmin, ((double)i) / 1000.0, tmax); + double num = nreceived + nrepeats; + double avg = tsum / num; +#if defined(__OpenBSD__) || defined(__NetBSD__) + double dev = sqrt(tsumsq / num - avg * avg); + (void)printf( + "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", + tmin, avg, tmax, dev); +#else + (void)printf( + "round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", + tmin, avg, tmax); +#endif (void)fflush(stdout); } + (void)fflush(stdout); } -#ifdef notdef -static char *ttab[] = { - "Echo Reply", /* ip + seq + udata */ - "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ - "Source Quench", /* IP */ - "Redirect", /* redirect type, gateway, + IP */ - "Echo", - "Time Exceeded", /* transit, frag reassem + IP */ - "Parameter Problem", /* pointer + IP */ - "Timestamp", /* id + seq + three timestamps */ - "Timestamp Reply", /* " */ - "Info Request", /* id + sq */ - "Info Reply" /* " */ +/*subject type*/ +static char *niqcode[] = { + "IPv6 address", + "DNS label", /*or empty*/ + "IPv4 address", }; -#endif + +/*result code*/ +static char *nircode[] = { + "Success", "Refused", "Unknown", +}; + /* * pr_icmph -- @@ -1599,16 +2220,21 @@ pr_icmph(icp, end) u_char *end; { char ntop_buf[INET6_ADDRSTRLEN]; + struct nd_redirect *red; + struct icmp6_nodeinfo *ni; + char dnsname[MAXDNAME + 1]; + const u_char *cp; + size_t l; - switch(icp->icmp6_type) { + switch (icp->icmp6_type) { case ICMP6_DST_UNREACH: - switch(icp->icmp6_code) { + switch (icp->icmp6_code) { case ICMP6_DST_UNREACH_NOROUTE: (void)printf("No Route to Destination\n"); break; case ICMP6_DST_UNREACH_ADMIN: (void)printf("Destination Administratively " - "Unreachable\n"); + "Unreachable\n"); break; case ICMP6_DST_UNREACH_BEYONDSCOPE: (void)printf("Destination Unreachable Beyond Scope\n"); @@ -1629,11 +2255,11 @@ pr_icmph(icp, end) break; case ICMP6_PACKET_TOO_BIG: (void)printf("Packet too big mtu = %d\n", - (int)ntohl(icp->icmp6_mtu)); + (int)ntohl(icp->icmp6_mtu)); pr_retip((struct ip6_hdr *)(icp + 1), end); break; case ICMP6_TIME_EXCEEDED: - switch(icp->icmp6_code) { + switch (icp->icmp6_code) { case ICMP6_TIME_EXCEED_TRANSIT: (void)printf("Time to live exceeded\n"); break; @@ -1649,22 +2275,22 @@ pr_icmph(icp, end) break; case ICMP6_PARAM_PROB: (void)printf("Parameter problem: "); - switch(icp->icmp6_code) { - case ICMP6_PARAMPROB_HEADER: - (void)printf("Erroneous Header "); - break; - case ICMP6_PARAMPROB_NEXTHEADER: - (void)printf("Unknown Nextheader "); - break; - case ICMP6_PARAMPROB_OPTION: - (void)printf("Unrecognized Option "); - break; - default: - (void)printf("Bad code(%d) ", icp->icmp6_code); - break; + switch (icp->icmp6_code) { + case ICMP6_PARAMPROB_HEADER: + (void)printf("Erroneous Header "); + break; + case ICMP6_PARAMPROB_NEXTHEADER: + (void)printf("Unknown Nextheader "); + break; + case ICMP6_PARAMPROB_OPTION: + (void)printf("Unrecognized Option "); + break; + default: + (void)printf("Bad code(%d) ", icp->icmp6_code); + break; } (void)printf("pointer = 0x%02x\n", - (int)ntohl(icp->icmp6_pptr)); + (u_int32_t)ntohl(icp->icmp6_pptr)); pr_retip((struct ip6_hdr *)(icp + 1), end); break; case ICMP6_ECHO_REQUEST: @@ -1697,25 +2323,119 @@ pr_icmph(icp, end) (void)printf("Neighbor Advertisement"); break; case ND_REDIRECT: - { - struct nd_redirect *red = (struct nd_redirect *)icp; - + red = (struct nd_redirect *)icp; (void)printf("Redirect\n"); - (void)printf("Destination: %s", - inet_ntop(AF_INET6, &red->nd_rd_dst, - ntop_buf, sizeof(ntop_buf))); - (void)printf("New Target: %s", - inet_ntop(AF_INET6, &red->nd_rd_target, - ntop_buf, sizeof(ntop_buf))); + if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, + sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + (void)printf("Destination: %s", ntop_buf); + if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, + sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + (void)printf(" New Target: %s", ntop_buf); break; - } case ICMP6_NI_QUERY: (void)printf("Node Information Query"); /* XXX ID + Seq + Data */ + ni = (struct icmp6_nodeinfo *)icp; + l = end - (u_char *)(ni + 1); + printf(", "); + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + (void)printf("NOOP"); + break; + case NI_QTYPE_SUPTYPES: + (void)printf("Supported qtypes"); + break; + case NI_QTYPE_FQDN: + (void)printf("DNS name"); + break; + case NI_QTYPE_NODEADDR: + (void)printf("nodeaddr"); + break; + case NI_QTYPE_IPV4ADDR: + (void)printf("IPv4 nodeaddr"); + break; + default: + (void)printf("unknown qtype"); + break; + } + if (options & F_VERBOSE) { + switch (ni->ni_code) { + case ICMP6_NI_SUBJ_IPV6: + if (l == sizeof(struct in6_addr) && + inet_ntop(AF_INET6, ni + 1, ntop_buf, + sizeof(ntop_buf)) != NULL) { + (void)printf(", subject=%s(%s)", + niqcode[ni->ni_code], ntop_buf); + } else { +#if 1 + /* backward compat to -W */ + (void)printf(", oldfqdn"); +#else + (void)printf(", invalid"); +#endif + } + break; + case ICMP6_NI_SUBJ_FQDN: + if (end == (u_char *)(ni + 1)) { + (void)printf(", no subject"); + break; + } + printf(", subject=%s", niqcode[ni->ni_code]); + cp = (const u_char *)(ni + 1); + if (dnsdecode(&cp, end, NULL, dnsname, + sizeof(dnsname)) != NULL) + printf("(%s)", dnsname); + else + printf("(invalid)"); + break; + case ICMP6_NI_SUBJ_IPV4: + if (l == sizeof(struct in_addr) && + inet_ntop(AF_INET, ni + 1, ntop_buf, + sizeof(ntop_buf)) != NULL) { + (void)printf(", subject=%s(%s)", + niqcode[ni->ni_code], ntop_buf); + } else + (void)printf(", invalid"); + break; + default: + (void)printf(", invalid"); + break; + } + } break; case ICMP6_NI_REPLY: (void)printf("Node Information Reply"); /* XXX ID + Seq + Data */ + ni = (struct icmp6_nodeinfo *)icp; + printf(", "); + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + (void)printf("NOOP"); + break; + case NI_QTYPE_SUPTYPES: + (void)printf("Supported qtypes"); + break; + case NI_QTYPE_FQDN: + (void)printf("DNS name"); + break; + case NI_QTYPE_NODEADDR: + (void)printf("nodeaddr"); + break; + case NI_QTYPE_IPV4ADDR: + (void)printf("IPv4 nodeaddr"); + break; + default: + (void)printf("unknown qtype"); + break; + } + if (options & F_VERBOSE) { + if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) + printf(", invalid"); + else + printf(", %s", nircode[ni->ni_code]); + } break; default: (void)printf("Bad ICMP type: %d", icp->icmp6_type); @@ -1740,13 +2460,14 @@ pr_iph(ip6) printf("Vr TC Flow Plen Nxt Hlim\n"); printf(" %1x %02x %05x %04x %02x %02x\n", - (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (int)ntohl(flow), - ntohs(ip6->ip6_plen), - ip6->ip6_nxt, ip6->ip6_hlim); - printf("%s->", inet_ntop(AF_INET6, &ip6->ip6_src, - ntop_buf, sizeof(ntop_buf))); - printf("%s\n", inet_ntop(AF_INET6, &ip6->ip6_dst, - ntop_buf, sizeof(ntop_buf))); + (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow), + ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); + if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf("%s->", ntop_buf); + if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf("%s\n", ntop_buf); } /* @@ -1755,22 +2476,25 @@ pr_iph(ip6) * a hostname. */ const char * -pr_addr(addr) - struct sockaddr_in6 *addr; +pr_addr(addr, addrlen) + struct sockaddr *addr; + int addrlen; { - static char buf[MAXHOSTNAMELEN]; - int flag = 0; + static char buf[NI_MAXHOST]; + int flag; +#ifdef NI_WITHSCOPEID + flag = NI_WITHSCOPEID; +#else + flag = 0; +#endif if ((options & F_HOSTNAME) == 0) flag |= NI_NUMERICHOST; -#ifdef KAME_SCOPEID - flag |= NI_WITHSCOPEID; -#endif - - getnameinfo((struct sockaddr *)addr, addr->sin6_len, buf, sizeof(buf), - NULL, 0, flag); - return (buf); + if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) + return (buf); + else + return "?"; } /* @@ -1796,53 +2520,53 @@ pr_retip(ip6, end) cp += hlen; while (end - cp >= 8) { switch (nh) { - case IPPROTO_HOPOPTS: - printf("HBH "); - hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; - nh = ((struct ip6_hbh *)cp)->ip6h_nxt; - break; - case IPPROTO_DSTOPTS: - printf("DSTOPT "); - hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; - nh = ((struct ip6_dest *)cp)->ip6d_nxt; - break; - case IPPROTO_FRAGMENT: - printf("FRAG "); - hlen = sizeof(struct ip6_frag); - nh = ((struct ip6_frag *)cp)->ip6f_nxt; - break; - case IPPROTO_ROUTING: - printf("RTHDR "); - hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; - nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; - break; + case IPPROTO_HOPOPTS: + printf("HBH "); + hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; + nh = ((struct ip6_hbh *)cp)->ip6h_nxt; + break; + case IPPROTO_DSTOPTS: + printf("DSTOPT "); + hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; + nh = ((struct ip6_dest *)cp)->ip6d_nxt; + break; + case IPPROTO_FRAGMENT: + printf("FRAG "); + hlen = sizeof(struct ip6_frag); + nh = ((struct ip6_frag *)cp)->ip6f_nxt; + break; + case IPPROTO_ROUTING: + printf("RTHDR "); + hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; + nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; + break; #ifdef IPSEC - case IPPROTO_AH: - printf("AH "); - hlen = (((struct ah *)cp)->ah_len+2) << 2; - nh = ((struct ah *)cp)->ah_nxt; - break; + case IPPROTO_AH: + printf("AH "); + hlen = (((struct ah *)cp)->ah_len+2) << 2; + nh = ((struct ah *)cp)->ah_nxt; + break; #endif - case IPPROTO_ICMPV6: - printf("ICMP6: type = %d, code = %d\n", - *cp, *(cp + 1)); - return; - case IPPROTO_ESP: - printf("ESP\n"); - return; - case IPPROTO_TCP: - printf("TCP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), - (*(cp + 2) * 256 + *(cp + 3))); - return; - case IPPROTO_UDP: - printf("UDP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), - (*(cp + 2) * 256 + *(cp + 3))); - return; - default: - printf("Unknown Header(%d)\n", nh); - return; + case IPPROTO_ICMPV6: + printf("ICMP6: type = %d, code = %d\n", + *cp, *(cp + 1)); + return; + case IPPROTO_ESP: + printf("ESP\n"); + return; + case IPPROTO_TCP: + printf("TCP: from port %u, to port %u (decimal)\n", + (*cp * 256 + *(cp + 1)), + (*(cp + 2) * 256 + *(cp + 3))); + return; + case IPPROTO_UDP: + printf("UDP: from port %u, to port %u (decimal)\n", + (*cp * 256 + *(cp + 1)), + (*(cp + 2) * 256 + *(cp + 3))); + return; + default: + printf("Unknown Header(%d)\n", nh); + return; } if ((cp += hlen) >= end) @@ -1876,7 +2600,7 @@ fill(bp, patp) &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], &pat[13], &pat[14], &pat[15]); -/* xxx */ +/* xxx */ if (ii > 0) for (kk = 0; kk <= MAXDATALEN - (8 + sizeof(struct timeval) + ii); @@ -1906,8 +2630,8 @@ setpolicy(so, policy) buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); - if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, - buf, ipsec_get_policylen(buf)) < 0) + if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, + ipsec_get_policylen(buf)) < 0) warnx("Unable to set IPSec policy"); free(buf); @@ -1921,30 +2645,38 @@ nigroup(name) char *name; { char *p; + unsigned char *q; MD5_CTX ctxt; u_int8_t digest[16]; - char l; + u_int8_t c; + size_t l; char hbuf[NI_MAXHOST]; struct in6_addr in6; - p = name; - while (p && *p && *p != '.') - p++; - if (p - name > 63) - return NULL; /*label too long*/ + p = strchr(name, '.'); + if (!p) + p = name + strlen(name); l = p - name; + if (l > 63 || l > sizeof(hbuf) - 1) + return NULL; /*label too long*/ + strncpy(hbuf, name, l); + hbuf[(int)l] = '\0'; + + for (q = name; *q; q++) { + if (isupper(*q)) + *q = tolower(*q); + } /* generate 8 bytes of pseudo-random value. */ bzero(&ctxt, sizeof(ctxt)); MD5Init(&ctxt); - MD5Update(&ctxt, &l, sizeof(l)); - MD5Update(&ctxt, name, p - name); + c = l & 0xff; + MD5Update(&ctxt, &c, sizeof(c)); + MD5Update(&ctxt, name, l); MD5Final(digest, &ctxt); - bzero(&in6, sizeof(in6)); - in6.s6_addr[0] = 0xff; - in6.s6_addr[1] = 0x02; - in6.s6_addr[11] = 0x02; + if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1) + return NULL; /*XXX*/ bcopy(digest, &in6.s6_addr[12], 4); if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) @@ -1957,19 +2689,20 @@ void usage() { (void)fprintf(stderr, -"usage: ping6 [-dfHnNqvwW" + "usage: ping6 [-dfHmnNqvwW" #ifdef IPV6_REACHCONF - "R" + "R" #endif #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC - "] [-P policy" + "] [-P policy" #else - "AE" + "AE" +#endif #endif -#endif - "] [-a [aAclsg]] [-b sockbufsiz] [-c count] \n\ - [-I interface] [-i wait] [-l preload] [-p pattern] [-S sourceaddr]\n\ - [-s packetsize] [-h hoplimit] [hops...] host\n"); + "] [-a [aAclsg]] [-b sockbufsiz] [-c count] \n" + "\t[-I interface] [-i wait] [-l preload] [-p pattern] " + "[-S sourceaddr]\n" + "\t[-s packetsize] [-h hoplimit] [hops...] host\n"); exit(1); } diff --git a/sbin/route/route.c b/sbin/route/route.c index 2b7d246..46d61c2 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -72,11 +72,7 @@ static const char rcsid[] = #include <string.h> #include <sysexits.h> #include <unistd.h> - -/* wrapper for KAME-special getnameinfo() */ -#ifndef NI_WITHSCOPEID -#define NI_WITHSCOPEID 0 -#endif +#include <ifaddrs.h> struct keytab { char *kt_cp; @@ -98,6 +94,7 @@ union sockunion { struct sockaddr_ns sns; #endif struct sockaddr_dl sdl; + struct sockaddr_storage ss; /* added to avoid memory overrun */ } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; typedef union sockunion *sup; @@ -110,10 +107,7 @@ struct rt_metrics rt_metrics; u_long rtm_inits; int atalk_aton __P((const char *, struct at_addr *)); char *atalk_ntoa __P((struct at_addr)); -#ifdef INET6 -char *inet6_ntoa __P((struct sockaddr *sa)); -#endif -char *routename(), *netname(); +const char *routename(), *netname(); void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf(); void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr(); int getaddr(), rtmsg(), x25_makemask(); @@ -122,10 +116,6 @@ extern char *iso_ntoa(); void usage __P((const char *)) __dead2; -#ifdef INET6 -char name_buf[MAXHOSTNAMELEN * 2 + 1]; /*for getnameinfo()*/ -#endif - void usage(cp) const char *cp; @@ -303,14 +293,14 @@ bad: usage(*argv); struct sockaddr *sa = (struct sockaddr *)(rtm + 1); (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? routename(sa) : netname(sa)); - sa = (struct sockaddr *)(sa->sa_len + (char *)sa); + sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); (void) printf("%-20.20s ", routename(sa)); (void) printf("done\n"); } } } -char * +const char * routename(sa) struct sockaddr *sa; { @@ -364,8 +354,36 @@ routename(sa) #ifdef INET6 case AF_INET6: - (void) snprintf(line, sizeof(line), "%s", inet6_ntoa(sa)); - break; + { + struct sockaddr_in6 sin6; /* use static var for safety */ + int niflags = 0; +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#endif + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + + return(line); + } #endif case AF_APPLETALK: @@ -399,7 +417,7 @@ routename(sa) * Return the name of the network whose address is given. * The address is assumed to be that of a net or subnet, not a host. */ -char * +const char * netname(sa) struct sockaddr *sa; { @@ -469,8 +487,36 @@ netname(sa) #ifdef INET6 case AF_INET6: - (void) snprintf(line, sizeof(line), "%s", inet6_ntoa(sa)); - break; + { + struct sockaddr_in6 sin6; /* use static var for safety */ + int niflags = 0; +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#endif + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + + return(line); + } #endif case AF_APPLETALK: @@ -827,47 +873,35 @@ getaddr(which, s, hpp) case RTA_GATEWAY: su = &so_gate; if (iflag) { - #define MAX_IFACES 400 - int sock; - struct ifreq iflist[MAX_IFACES]; - struct ifconf ifconf; - struct ifreq *ifr, *ifr_end; - struct sockaddr_dl *dl, *sdl = NULL; - - /* Get socket */ - if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - - /* Get interface list */ - ifconf.ifc_req = iflist; - ifconf.ifc_len = sizeof(iflist); - if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) - err(1, "ioctl(SIOCGIFCONF)"); - close(sock); - - /* Look for this interface in the list */ - for (ifr = ifconf.ifc_req, - ifr_end = (struct ifreq *) - (ifconf.ifc_buf + ifconf.ifc_len); - ifr < ifr_end; - ifr = (struct ifreq *) ((char *) &ifr->ifr_addr - + MAX(ifr->ifr_addr.sa_len, - sizeof(ifr->ifr_addr)))) { - dl = (struct sockaddr_dl *)&ifr->ifr_addr; - if (ifr->ifr_addr.sa_family == AF_LINK - && (ifr->ifr_flags & IFF_POINTOPOINT) - && !strncmp(s, dl->sdl_data, dl->sdl_nlen) - && s[dl->sdl_nlen] == 0) { - sdl = dl; - break; - } - } + struct ifaddrs *ifap, *ifa; + struct sockaddr_dl *sdl = NULL; + + if (getifaddrs(&ifap)) + err(1, "getifaddrs"); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + + if (strcmp(s, ifa->ifa_name) || + (ifa->ifa_flags & IFF_POINTOPOINT) == 0) + continue; + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + } /* If we found it, then use it */ if (sdl) { - su->sdl = *sdl; - return(1); + /* + * Copy is safe since we have a + * sockaddr_storage member in sockunion{}. + * Note that we need to copy before calling + * freeifaddrs(). + */ + memcpy(&su->sdl, sdl, sdl->sdl_len); } + freeifaddrs(ifap); + if (sdl) + return(1); } break; case RTA_NETMASK: @@ -908,31 +942,33 @@ getaddr(which, s, hpp) switch (afamily) { #ifdef INET6 case AF_INET6: - { + { struct addrinfo hints, *res; - int error; - - bzero(&hints, sizeof(struct addrinfo)); - hints.ai_family = AF_INET6; - - error = getaddrinfo(s, NULL, &hints, &res); - if (error != 0) { - (void) fprintf(stderr, "%s: bad value\n", - gai_strerror(error)); - if (error == EAI_SYSTEM) - (void) fprintf(stderr, "%s\n", - strerror(errno)); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afamily; /*AF_INET6*/ + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + if (getaddrinfo(s, "0", &hints, &res) != 0 || + res->ai_family != AF_INET6 || + res->ai_addrlen != sizeof(su->sin6)) { + (void) fprintf(stderr, "%s: bad value\n", s); exit(1); } - bcopy(res->ai_addr, &su->sa, res->ai_addrlen); - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) - *(u_short *)&su->sin6.sin6_addr.s6_addr[2] = - ntohs(su->sin6.sin6_scope_id); - su->sin6.sin6_scope_id = 0; - return 0; - } + memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); +#ifdef __KAME__ + if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || + IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) && + su->sin6.sin6_scope_id) { + *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = + htons(su->sin6.sin6_scope_id); + su->sin6.sin6_scope_id = 0; + } #endif + freeaddrinfo(res); + return (0); + } +#endif /* INET6 */ #ifdef NS case AF_NS: @@ -1624,45 +1660,3 @@ atalk_ntoa(struct at_addr at) (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); return(buf); } - -#ifdef INET6 -char * -inet6_ntoa(struct sockaddr *sa) -{ - char *cp; - struct sockaddr_in6 *sin6; - int error = -1, gap; - - cp = NULL; - sin6 = (struct sockaddr_in6 *)sa; - gap = sizeof(struct sockaddr_in6) - sin6->sin6_len; - if (gap > 0) - bzero((char *)(sin6) + sin6->sin6_len, gap); - - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && - *(u_short *)&sin6->sin6_addr.s6_addr[2] != 0) { - u_short index; - - index = *(u_short *)&sin6->sin6_addr.s6_addr[2]; - *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0; - if (sin6->sin6_scope_id == 0) - sin6->sin6_scope_id = ntohs(index); - } - - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || sa->sa_len < 4) - cp = "default"; - if (cp == 0 && !nflag) - error = getnameinfo(sa, sa->sa_len, name_buf, sizeof(name_buf), - NULL, 0, NI_NAMEREQD); - if (error != 0) - error = getnameinfo(sa, sa->sa_len, name_buf, - sizeof(name_buf), NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID); - if (error != 0) - inet_ntop(AF_INET6, &sin6->sin6_addr, name_buf, - sizeof(name_buf)); - - return (cp != NULL) ? cp : name_buf; -} -#endif diff --git a/sbin/rtsol/Makefile b/sbin/rtsol/Makefile index 4926191..f533ed8 100644 --- a/sbin/rtsol/Makefile +++ b/sbin/rtsol/Makefile @@ -16,11 +16,9 @@ SRCDIR= ${.CURDIR}/../../usr.sbin/rtsold PROG= rtsol -SRCS= rtsold.c rtsol.c if.c probe.c dump.c +SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c CFLAGS+=-DINET6 -DHAVE_GETIFADDRS -LDADD= -lkvm -DPADD= ${LIBKVM} NOMAN= yes diff --git a/sbin/setkey/parse.y b/sbin/setkey/parse.y index 0eea4c1..1d43dc4 100644 --- a/sbin/setkey/parse.y +++ b/sbin/setkey/parse.y @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: parse.y,v 1.29 2000/06/10 14:17:44 sakane Exp $ */ +/* $KAME: kame/kame/kame/setkey/parse.y,v 1.36 2001/06/07 15:53:12 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -57,6 +57,7 @@ u_int p_type; u_int32_t p_spi; +int p_no_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; @@ -79,7 +80,6 @@ extern int m_len; extern char cmdarg[8192]; extern int f_debug; -int setkeymsg __P((void)); static struct addrinfo *parse_addr __P((char *, char *, int)); static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int)); void parse_init __P((void)); @@ -107,7 +107,7 @@ extern void yyerror __P((const char *)); %token F_EXT EXTENSION NOCYCLICSEQ %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 +%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY /* SPD management */ %token SPDADD SPDDELETE SPDDUMP SPDFLUSH %token F_POLICY PL_REQUESTS @@ -118,7 +118,7 @@ extern void yyerror __P((const char *)); %type <num> DECSTRING %type <val> ADDRESS PL_REQUESTS %type <val> key_string policy_requests -%type <val> QUOTEDSTRING HEXSTRING +%type <val> QUOTEDSTRING HEXSTRING STRING %% commands @@ -140,6 +140,7 @@ command : add_command | get_command | delete_command + | deleteall_command | flush_command | dump_command | spdadd_command @@ -166,6 +167,16 @@ delete_command EOT ; + /* deleteall command */ +deleteall_command + : DELETEALL { p_type = SADB_DELETE; } + ipaddress { p_src = pp_addr; } + ipaddress { p_dst = pp_addr; } + protocol_spec + { p_no_spi = 1; } + EOT + ; + /* get command */ get_command : GET { p_type = SADB_GET; } @@ -327,7 +338,7 @@ auth_alg auth_key : /*NOTHING*/ { - if (p_alg_auth != SADB_AALG_NULL) { + if (p_alg_auth != SADB_X_AALG_NULL) { yyerror("no key found."); return -1; } @@ -541,10 +552,27 @@ port upper_spec : DECSTRING { p_upper = $1; } | UP_PROTO { p_upper = $1; } - | PR_ESP { p_upper = IPPROTO_ESP; }; - | PR_AH { p_upper = IPPROTO_AH; }; - | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; }; | ANY { p_upper = IPSEC_ULPROTO_ANY; } + | STRING + { + struct protoent *ent; + + ent = getprotobyname($1.buf); + if (ent) + p_upper = ent->p_proto; + else { + if (strcmp("icmp6", $1.buf) == 0) { + p_upper = IPPROTO_ICMPV6; + } else if(strcmp("ip4", $1.buf) == 0) { + p_upper = IPPROTO_IPV4; + } else { + yyerror("invalid upper layer protocol"); + free($1.buf); + return -1; + } + } + free($1.buf); + } ; policy_spec @@ -665,27 +693,29 @@ setkeymsg() 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; + if (p_no_spi == 0) { + 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; - len = sizeof(struct sadb_x_sa2); - m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); - m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - m_sa2.sadb_x_sa2_mode = p_mode; - m_sa2.sadb_x_sa2_reqid = p_reqid; + len = sizeof(struct sadb_x_sa2); + m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); + m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + m_sa2.sadb_x_sa2_mode = p_mode; + m_sa2.sadb_x_sa2_reqid = p_reqid; - memcpy(m_buf + m_len, &m_sa2, len); - m_len += len; + memcpy(m_buf + m_len, &m_sa2, len); + m_len += len; + } /* set src */ m_addr.sadb_address_len = @@ -864,6 +894,7 @@ parse_init() { p_type = 0; p_spi = 0; + p_no_spi = 0; p_src = 0, p_dst = 0; pp_prefix = p_prefs = p_prefd = ~0; diff --git a/sbin/setkey/scriptdump.pl b/sbin/setkey/scriptdump.pl index aa36544..33907dc 100644 --- a/sbin/setkey/scriptdump.pl +++ b/sbin/setkey/scriptdump.pl @@ -33,11 +33,11 @@ foreach $_ (<IN>) { $akey =~ s/\s//g; $akey =~ s/^/0x/g; } elsif (/^\treplay=(\d+) flags=(0x\d+) state=/) { - print "$mode $src $dst $proto $spi -m $ipsecmode"; + print "$mode $src $dst $proto $spi"; $replay = $1; print " -u $reqid" if $reqid; if ($mode eq 'add') { - print " -r $replay" if $replay; + print " -m $ipsecmode -r $replay" if $replay; if ($proto eq 'esp') { print " -E $ealgo $ekey" if $ealgo; print " -A $aalgo $akey" if $aalgo; diff --git a/sbin/setkey/setkey.8 b/sbin/setkey/setkey.8 index 7921800..368fc5d 100644 --- a/sbin/setkey/setkey.8 +++ b/sbin/setkey/setkey.8 @@ -1,5 +1,5 @@ -.\" $FreeBSD$ -.\" $KAME: setkey.8,v 1.28 2000/06/16 12:03:46 sakane Exp $ +.\" $KAME: setkey.8,v 1.49 2001/05/18 05:49:51 sakane Exp $ +.\" $FreeBSD$ .\" .\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. .\" All rights reserved. @@ -28,9 +28,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 17, 1998 +.Dd November 20, 2000 .Dt SETKEY 8 -.Os KAME +.Os .\" .Sh NAME .Nm setkey @@ -55,7 +55,7 @@ .\" .Sh DESCRIPTION .Nm -addes, updates, dumpes, or flushes +adds, updates, dumps, or flushes Security Association Database (SAD) entries as well as Security Policy Database (SPD) entries in the kernel. .Pp @@ -94,11 +94,14 @@ it has been expired but remains because it is referenced by SPD entries. .It Fl d Enable to print debugging messages for command parser, -without talking to kernel. It is not used usually. +without talking to kernel. +It is not used usually. .It Fl x Loop forever and dump all the messages transmitted to .Dv PF_KEY socket. +.Fl xx +makes each timestamps unformatted. .It Fl h Add hexadecimal dump on .Fl x @@ -108,14 +111,13 @@ Loop forever with short output on .Fl D . .It Fl v Be verbose. +The program will dump messages exchanged on .Dv PF_KEY -socket -.Po -including messages sent from other processes -.Pc . +socket, including messages sent from other processes to the kernel. .El .Pp -Operations have the following grammar. Note that lines starting with +Operations have the following grammar. +Note that lines starting with hashmarks ('#') are treated as comment lines. .Bl -tag -width Ds .It Xo @@ -142,6 +144,13 @@ Show an SAD entry. Remove an SAD entry. .\" .It Xo +.Li deleteall +.Ar src Ar dst Ar protocol +.Li ; +.Xc +Remove all SAD entries that match the specification. +.\" +.It Xo .Li flush .Op Ar protocol .Li ; @@ -227,7 +236,7 @@ attached .\" .Pp .It Ar extensions -take some of the following: +takes some of the following: .Bl -tag -width Fl -compact .\" .It Fl m Ar mode @@ -243,39 +252,49 @@ The default value is .It Fl r Ar size Specify window size of bytes for replay prevention. .Ar size -must be decimal number in 32-bit word. If +must be decimal number in 32-bit word. +If .Ar size is zero or not specified, replay check don't take place. .\" .It Fl u Ar id -Specify the identifier of policy. See also -.Xr ipsec_set_policy 3 . +Specify the identifier of the policy entry in SPD. +See +.Ar policy . .\" .It Fl f Ar pad_option +defines the content of the ESP padding. .Ar pad_option is one of following: -.Li zero-pad , random-pad -or -.Li seq-pad +.Bl -tag -width random-pad -compact +.It Li zero-pad +All of the padding are zero. +.It Li random-pad +A series of randomized values are set. +.It Li seq-pad +A series of sequential increasing numbers started from 1 are set. +.El .\" .It Fl f Li nocyclic-seq Don't allow cyclic sequence number. .\" .It Fl lh Ar time .It Fl ls Ar time -Specify hard/soft lifetime. +Specify hard/soft life time duration of the SA. .El .\" .Pp .It Ar algorithm .Bl -tag -width Fl -compact .It Fl E Ar ealgo Ar key -Specify encryption algorithm. +Specify a encryption algorithm. .It Fl A Ar aalgo Ar key -Specify authentication algorithm. +Specify a authentication algorithm. If .Fl A -is used for esp, it will be treated as ESP payload authentication algorithm. +is used with +.Ar protocol Li esp , +it will be treated as ESP payload authentication algorithm. .It Fl C Ar calgo Op Fl R Specify compression algorithm. If @@ -302,23 +321,23 @@ field needs to be smaller than in this case. .El .Pp -.Li esp -SAs accept +.Ar protocol Li esp +accepts .Fl E and .Fl A . -.Li esp-old -SAs accept +.Ar protocol Li esp-old +accepts .Fl E only. -.Li ah +.Ar protocol Li ah and .Li ah-old -SAs accept +accept .Fl A only. -.Li ipcomp -SAs accept +.Ar protocol Li ipcomp +accepts .Fl C only. .Pp @@ -365,45 +384,57 @@ They must be in numeric form. .Pp .It Ar upperspec Upper-layer protocol to be used. -Currently -.Li icmp , +You can use one of words in +.Pa /etc/protocols +as +.Ar upperspec . +Or .Li icmp6 , .Li ip4 , -.Li tcp , -.Li udp and .Li any can be specified. .Li any stands for .Dq any protocol . +Also you can use the protocol number. .Pp NOTE: .Ar upperspec does not work against forwarding case at this moment, as it requires extra reassembly at forwarding node .Pq not implemented at this moment . +We have many protocols in +.Pa /etc/protocols , +but protocols except of TCP, UDP and ICMP may not be suitable to use with IPSec. +You have to consider and be careful to use them. +.Li icmp +.Li tcp +.Li udp +all protocols .\" .Pp .It Ar policy .Ar policy is the one of following: -.Pp -.Bl -item -compact -.It +.Bd -literal -offset +.Xo .Fl P .Ar direction .Li discard -.It +.Xc +.Xo .Fl P .Ar direction .Li none -.It +.Xc +.Xo .Fl P .Ar direction .Li ipsec .Ar protocol/mode/src-dst/level -.El +.Xc +.Ed .Pp You must specify the direction of its policy as .Ar direction . @@ -430,18 +461,33 @@ is either .Li transport or .Li tunnel . -You must specify the end-points addresses of the SA as +If +.Ar mode +is +.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. +If +.Ar mode +is +.Li transport , +both +.Ar src +and +.Ar dst +can be omited. .Ar level is to be one of the following: -.Li default , use +.Li default , use , require or -.Li require . +.Li unique . +If the SA is not available in every level, the kernel will request +getting SA to the key exchange daemon. .Li default means the kernel consults to the system wide default against protocol you specified, e.g. @@ -451,7 +497,23 @@ sysctl variable, when the kernel processes the packet. means that the kernel use a SA if it's available, otherwise the kernel keeps normal operation. .Li require -means SA is required whenever the kernel deals with the packet. +means SA is required whenever the kernel sends a packet matched +with the policy. +.Li unique +is the same to require. +In addition, it allows the policy to bind with the unique out-bound SA. +If you use the SA by manual keying, +you can put the decimal number as the policy identifier after +.Li unique +separated by colon +.Sq \: +like the following; +.Li unique:number . +.Li number +must be between 1 and 32767. +It corresponds to +.Ar extensions Fl u . +.Pp Note that .Dq Li discard and @@ -491,6 +553,12 @@ keyed-md5 128 ah: 96bit ICV (no document) keyed-sha1 160 ah: 96bit ICV (no document) 160 ah-old: 128bit ICV (no document) null 0 to 2048 for debugging +hmac-sha2-256 256 ah: 96bit ICV (no document) + 256 ah-old: 128bit ICV (no document) +hmac-sha2-384 384 ah: 96bit ICV (no document) + 384 ah-old: 128bit ICV (no document) +hmac-sha2-512 512 ah: 96bit ICV (no document) + 512 ah-old: 128bit ICV (no document) .Ed .Pp Followings are the list of encryption algorithms that can be used as @@ -508,9 +576,9 @@ des-cbc 64 esp-old: rfc1829, esp: rfc2405 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 +rijndael-cbc 128/192/256 draft-ietf-ipsec-ciph-aes-cbc-00 .Ed .Pp Followings are the list of compression algorithms that can be used as @@ -555,7 +623,8 @@ The command exits with 0 on success, and non-zero on errors. .\" .Sh SEE ALSO .Xr ipsec_set_policy 3 , -.Xr sysctl 8 +.Xr sysctl 8 , +.Xr racoon 8 .\" .Sh HISTORY The diff --git a/sbin/setkey/setkey.c b/sbin/setkey/setkey.c index b1e1c1e..e729e7d 100644 --- a/sbin/setkey/setkey.c +++ b/sbin/setkey/setkey.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: setkey.c,v 1.14 2000/06/10 06:47:09 sakane Exp $ */ +/* $KAME: setkey.c,v 1.18 2001/05/08 04:36:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -63,6 +63,8 @@ int postproc __P((struct sadb_msg *, int)); const char *numstr __P((int)); void shortdump_hdr __P((void)); void shortdump __P((struct sadb_msg *)); +static void printdate __P((void)); +static int32_t gmt2local __P((time_t)); #define MODE_SCRIPT 1 #define MODE_CMDDUMP 2 @@ -79,11 +81,14 @@ int f_mode = 0; int f_cmddump = 0; int f_policy = 0; int f_hexdump = 0; +int f_tflag = 0; char *pname; u_char m_buf[BUFSIZ]; u_int m_len; +static time_t thiszone; + extern int lineno; extern int parse __P((FILE **)); @@ -112,7 +117,9 @@ main(ac, av) if (ac == 1) Usage(); - while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) { + thiszone = gmt2local(0); + + while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { switch (c) { case 'c': f_mode = MODE_SCRIPT; @@ -142,6 +149,7 @@ main(ac, av) break; case 'x': f_mode = MODE_PROMISC; + f_tflag++; break; case 'P': f_policy = 1; @@ -199,7 +207,7 @@ get_supported() if (f_debug) return 0; - if (pfkey_send_register(so, PF_UNSPEC) < 0) + if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) return -1; if (pfkey_recv_register(so) < 0) @@ -275,6 +283,7 @@ promisc() err(1, "recv"); /*NOTREACHED*/ } + printdate(); if (f_hexdump) { int i; for (i = 0; i < len; i++) { @@ -541,7 +550,7 @@ shortdump(msg) snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); printf("%s", buf); } else - printf(" ???/???"); + printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ printf(" "); @@ -576,3 +585,64 @@ shortdump(msg) printf("\n"); } + +/* From: tcpdump(1):gmt2local.c and util.c */ +/* + * Print the timestamp + */ +static void +printdate() +{ + struct timeval tp; + int s; + + if (gettimeofday(&tp, NULL) == -1) { + perror("gettimeofday"); + return; + } + + if (f_tflag == 1) { + /* Default */ + s = (tp.tv_sec + thiszone ) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); + } else if (f_tflag > 1) { + /* Unix timeval style */ + (void)printf("%u.%06u ", + (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); + } + + printf("\n"); +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + */ +int32_t +gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} diff --git a/sbin/setkey/token.l b/sbin/setkey/token.l index c2eaad5..208196e 100644 --- a/sbin/setkey/token.l +++ b/sbin/setkey/token.l @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: token.l,v 1.13 2000/06/07 00:29:14 itojun Exp $ */ +/* $KAME: token.l,v 1.21 2001/05/18 05:35:01 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -47,7 +47,11 @@ #include <unistd.h> #include <errno.h> #include "vchar.h" +#ifdef __NetBSD__ +#include "parse.h" +#else #include "y.tab.h" +#endif #define DECHO \ if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); } @@ -121,6 +125,7 @@ hostname {name}(({dot}{name})+{dot}?)? add { PREPROC; return(ADD); } delete { PREPROC; return(DELETE); } +deleteall { PREPROC; return(DELETEALL); } get { PREPROC; return(GET); } flush { PREPROC; return(FLUSH); } dump { PREPROC; return(DUMP); } @@ -160,20 +165,23 @@ ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); } {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); } +keyed-md5 { PREPROC; yylval.num = SADB_X_AALG_MD5; return(ALG_AUTH); } +keyed-sha1 { PREPROC; yylval.num = SADB_X_AALG_SHA; return(ALG_AUTH); } +hmac-sha2-256 { PREPROC; yylval.num = SADB_X_AALG_SHA2_256; return(ALG_AUTH); } +hmac-sha2-384 { PREPROC; yylval.num = SADB_X_AALG_SHA2_384; return(ALG_AUTH); } +hmac-sha2-512 { PREPROC; yylval.num = SADB_X_AALG_SHA2_512; return(ALG_AUTH); } +null { PREPROC; yylval.num = SADB_X_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); } +blowfish-cbc { PREPROC; yylval.num = SADB_X_EALG_BLOWFISHCBC; return(ALG_ENC); } +cast128-cbc { PREPROC; yylval.num = SADB_X_EALG_CAST128CBC; 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); } +rijndael-cbc { PREPROC; yylval.num = SADB_X_EALG_RIJNDAELCBC; return(ALG_ENC); } /* compression algorithms */ {hyphen}C { PREPROC; return(F_COMP); } @@ -196,14 +204,6 @@ nocyclic-seq { PREPROC; return(NOCYCLICSEQ); } {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); } -ip4 { PREPROC; yylval.num = IPPROTO_IPV4; 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; } @@ -277,6 +277,12 @@ any { PREPROC; return(ANY); } return(QUOTEDSTRING); } +[a-z0-9.\-]* { + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + return(STRING); + } + . { yyfatal("Syntax error"); /*NOTREACHED*/ diff --git a/share/doc/IPv6/IMPLEMENTATION b/share/doc/IPv6/IMPLEMENTATION index 98150d5..ea1715f 100644 --- a/share/doc/IPv6/IMPLEMENTATION +++ b/share/doc/IPv6/IMPLEMENTATION @@ -2,11 +2,12 @@ # Some portion of this document is not applicable to the code merged into # FreeBSD-current (for example, section 5). - Implementation Note + Implementation Note - KAME Project - http://www.kame.net/ - $FreeBSD$ + KAME Project + http://www.kame.net/ + $KAME: IMPLEMENTATION,v 1.216 2001/05/25 07:43:01 jinmei Exp $ + $FreeBSD$ 1. IPv6 @@ -27,12 +28,7 @@ RFC1639: FTP Operation Over Big Address Records (FOOBAR) * RFC2428 is preferred over RFC1639. ftp clients will first try RFC2428, then RFC1639 if failed. RFC1886: DNS Extensions to support IPv6 -RFC1933: Transition Mechanisms for IPv6 Hosts and Routers - * IPv4 compatible address is not supported. - * automatic tunneling (4.3) is not supported. - * "gif" interface implements IPv[46]-over-IPv[46] tunnel in a generic way, - and it covers "configured tunnel" described in the spec. - See 1.5 in this document for details. +RFC1933: (see RFC2893) RFC1981: Path MTU Discovery for IPv6 RFC2080: RIPng for IPv6 * KAME-supplied route6d, bgpd and hroute6d support this. @@ -42,8 +38,7 @@ RFC2283: Multiprotocol Extensions for BGP-4 RFC2292: Advanced Sockets API for IPv6 * For supported library functions/kernel APIs, see sys/netinet6/ADVAPI. RFC2362: Protocol Independent Multicast-Sparse Mode (PIM-SM) - * RFC2362 defines packet formats for PIM-SM. draft-ietf-pim-ipv6-01.txt - is written based on this. + * RFC2362 defines the packet formats and the protcol of PIM-SM. RFC2373: IPv6 Addressing Architecture * KAME supports node required addresses, and conforms to the scope requirement. @@ -82,6 +77,13 @@ RFC2553: Basic Socket Interface Extensions for IPv6 - supported but turned off by default on KAME/NetBSD, - not supported on KAME/FreeBSD228, KAME/OpenBSD and KAME/BSDI3. see 1.12 in this document for details. +RFC2671: Extension Mechanisms for DNS (EDNS0) + * see USAGE for how to use it. + * not supported on kame/freebsd4 and kame/bsdi4. +RFC2673: Binary Labels in the Domain Name System + * KAME/bsdi4 supports A6, DNAME and binary label to some extent. + * KAME apps/bind8 repository has resolver library with partial A6, DNAME + and binary label support. RFC2675: IPv6 Jumbograms * See 1.7 in this document for details. RFC2710: Multicast Listener Discovery for IPv6 @@ -89,35 +91,74 @@ RFC2711: IPv6 router alert option RFC2732: Format for Literal IPv6 Addresses in URL's * The spec is implemented in programs that handle URLs (like freebsd ftpio(3) and fetch(1), or netbsd ftp(1)) -draft-ietf-ipngwg-router-renum-10: Router renumbering for IPv6 -draft-ietf-ipngwg-icmp-name-lookups-05: IPv6 Name Lookups Through ICMP -draft-ietf-pim-ipv6-03.txt: PIM for IPv6 - * pim6dd implements dense mode. pim6sd implements sparse mode. +RFC2766: Network Address Translation - Protocol Translation (NAT-PT) + * Section 4.2 is implemented by totd (see ports/totd, or pkgsrc/net/totd). +RFC2874: DNS Extensions to Support IPv6 Address Aggregation and Renumbering + * KAME/bsdi4 supports A6, DNAME and binary label to some extent. + * KAME apps/bind8 repository has resolver library with partial A6, DNAME + and binary label support. +RFC2893: Transition Mechanisms for IPv6 Hosts and Routers + * IPv4 compatible address is not supported. + * automatic tunneling (4.3) is not supported. + * "gif" interface implements IPv[46]-over-IPv[46] tunnel in a generic way, + and it covers "configured tunnel" described in the spec. + See 1.5 in this document for details. +RFC2894: Router renumbering for IPv6 +RFC3041: Privacy Extensions for Stateless Address Autoconfiguration in IPv6 +RFC3056: Connection of IPv6 Domains via IPv4 Clouds + * So-called "6to4". + * "stf" interface implements it. Be sure to read + draft-itojun-ipv6-transition-abuse-01.txt + below before configuring it, there can be security issues. +draft-ietf-ipngwg-icmp-name-lookups-07: IPv6 Name Lookups Through ICMP draft-ietf-dhc-dhcpv6-15.txt: DHCPv6 draft-ietf-dhc-dhcpv6exts-12.txt: Extensions for DHCPv6 * kame/dhcp6 has test implementation, which will not be compiled in default compilation. + * 15/12 drafts are not explicit about padding and string termination. + at IETF48, the author confirmed that there's no padding/termination + (and extensions can appear unaligned). our code follows the comment. draft-itojun-ipv6-tcp-to-anycast-00.txt: Disconnecting TCP connection toward IPv6 anycast address -draft-ietf-ipngwg-scopedaddr-format-02.txt: - An Extension of Format for IPv6 Scoped Addresses -draft-ietf-ngtrans-tcpudp-relay-01.txt: +draft-ietf-ipngwg-rfc2553bis-03.txt: + Basic Socket Interface Extensions for IPv6 (revised) +draft-ietf-ipngwg-rfc2292bis-02.txt: + Advanced Sockets API for IPv6 (revised) + * Some of the updates in the draft are not implemented yet. See + TODO.2292bis for more details. +draft-ietf-mobileip-ipv6-13.txt: Mobility Support in IPv6 + * See section 6. +draft-ietf-ngtrans-tcpudp-relay-04.txt: An IPv6-to-IPv4 transport relay translator * FAITH tcp relay translator (faithd) implements this. See 3.1 for more details. -draft-ietf-ngtrans-6to4-06.txt: - Connection of IPv6 Domains via IPv4 Clouds without Explicit Tunnels - * "stf" interface implements it. Be sure to read the next item before - configuring it, there are security issues. -http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt: - Possible abuse against IPv6 transition technologies - * KAME does not implement RFC1933 automatic tunnel. +draft-ietf-ipngwg-router-selection-01.txt: + Default Router Preferences and More-Specific Routes + * router-side only. +draft-ietf-ipngwg-scoping-arch-02.txt: + The architecture, text representation, and usage of IPv6 + scoped addresses. + * some part of the documentation (especially about the routing + model) is not supported yet. +draft-ietf-pim-sm-v2-new-02.txt + A revised version of RFC2362, which includes the IPv6 specific + packet format and protocol descriptions. +draft-ietf-dnsext-mdns-00.txt: Multicast DNS + * kame/mdnsd has test implementation, which will not be built in + default compilation. The draft will experience a major change in the + near future, so don't rely upon it. +draft-itojun-ipv6-transition-abuse-02.txt: + Possible abuse against IPv6 transition technologies (expired) + * KAME does not implement RFC1933/2893 automatic tunnel. * "stf" interface implements some address filters. Refer to stf(4) for details. Since there's no way to make 6to4 interface 100% secure, we do not include "stf" interface into GENERIC.v6 compilation. * kame/openbsd completely disables IPv4 mapped address support. * kame/netbsd makes IPv4 mapped address support off by default. - * See section 12.6 and 14 for more details. + * See section 1.12.6 and 1.14 for more details. +draft-itojun-ipv6-tclass-api-02.txt: Socket API for IPv6 traffic class field +draft-itojun-ipv6-flowlabel-api-01.txt: Socket API for IPv6 flow label field + * no consideration is made against the use of routing headers and such. 1.2 Neighbor Discovery @@ -145,7 +186,10 @@ Some of network drivers loop multicast packets back to themselves, even if instructed not to do so (especially in promiscuous mode). In such cases DAD may fail, because DAD engine sees inbound NS packet (actually from the node itself) and considers it as a sign of duplicate. -You may want to look at #if condition marked "heuristics" in +In this case, drivers should be corrected to honor IFF_SIMPLEX behavior. +For example, you may need to check source MAC address on a inbound packet, +and reject it if it is from the node itself. +You may also want to look at #if condition marked "heuristics" in sys/netinet6/nd6_nbr.c:nd6_dad_timer() as workaround (note that the code fragment in "heuristics" section is not spec conformant). @@ -218,84 +262,157 @@ upper-layer hints to be accepted. non-root process - after local discussion, it looks that hints are not that trustworthy even if they are from privileged processes) -1.3 Scope Index +If inbound ND packets carry invalid values, the KAME kernel will +drop these packet and increment statistics variable. See +"netstat -sn", icmp6 section. For detailed debugging session, you can +turn on syslog output from the kernel on errors, by turning on sysctl MIB +net.inet6.icmp6.nd6_debug. nd6_debug can be turned on at bootstrap +time, by defining ND6_DEBUG kernel compilation option (so you can +debug behavior during bootstrap). nd6_debug configuration should +only be used for test/debug purposes - for production environment, +nd6_debug must be set to 0. If you leave it to 1, malicious parties +can inject broken packet and fill up /var/log partition. + +1.3 Scope Zone Index IPv6 uses scoped addresses. It is therefore very important to -specify scope index (interface index for link-local address, or -site index for site-local address) with an IPv6 address. Without -scope index, a scoped IPv6 address is ambiguous to the kernel, and -the kernel will not be able to determine the outbound interface for a -packet. KAME code tries to address the issue in several ways. - -Site-local address is very vaguely defined in the specs, and both specification -and KAME code need tons of improvements to enable its actual use. -For example, it is still very unclear how we define a site, or how we resolve -hostnames in a site. There are work underway to define behavior of routers -at site border, however, we have almost no code for site boundary node support -(both forwarding nor routing) and we bet almost noone has. -We recommend, at this moment, you to use global addresses for experiments - -there are way too many pitfalls if you use site-local addresses. +specify the scope zone index (link index for a link-local address, or +site index for a site-local address) with an IPv6 address. Without a +zone index, a scoped IPv6 address is ambiguous to the kernel, and +the kernel would not be able to determine the outbound link for a +packet to the scoped address. KAME code tries to address the issue in +several ways. + +The entire architecture of scoped addresses is documented in +draft-ietf-ipngwg-scoping-arch-xx.txt. One non-trivial point of the +architecture is that the link scope is (theoretically) larger than the +interface scope. That is, two different interfaces can belong to a +same single link. However, in a normal operation, we can assume that +there is 1-to-1 relationship between links and interfaces. In +other words, we can usually put links and interfaces in the same scope +type. The current KAME implementation assumes the 1-to-1 +relationship. In particular, we use interface names such as "ne1" as +unique link identifiers. This would be much more human-readable and +intuitive than numeric identifiers, but please keep your mind on the +theoretical difference between links and interfaces. + +Site-local addresses are very vaguely defined in the specs, and both +the specification and the KAME code need tons of improvements to +enable its actual use. For example, it is still very unclear how we +define a site, or how we resolve host names in a site. There is work +underway to define behavior of routers at site border, but, we have +almost no code for site boundary node support (both forwarding nor +routing) and we bet almost noone has. We recommend, at this moment, +you to use global addresses for experiments - there are way too many +pitfalls if you use site-local addresses. 1.3.1 Kernel internal -In the kernel, the interface index for a link-local scope address is +In the kernel, the link index for a link-local scope address is embedded into the 2nd 16bit-word (the 3rd and 4th bytes) in the IPv6 address. For example, you may see something like: fe80:1::200:f8ff:fe01:6317 -in the routing table and interface address structure (struct -in6_ifaddr). The address above is a link-local unicast address -which belongs to a network interface whose interface identifier is 1. -The embedded index enables us to identify IPv6 link local -addresses over multiple interfaces effectively and with only a +in the routing table and the interface address structure (struct +in6_ifaddr). The address above is a link-local unicast address which +belongs to a network link whose link identifier is 1 (note that it +eqauls to the interface index by the assumption of our +implementation). The embedded index enables us to identify IPv6 +link-local addresses over multiple links effectively and with only a little code change. 1.3.2 Interaction with API -Ordinary userland applications should use the advanced API (RFC2292) -to specify scope index, or interface index. For the similar purpose, -the sin6_scope_id member in the sockaddr_in6 structure is defined in -RFC2553. However, the semantics for sin6_scope_id is rather vague. -If you care about portability of your application, we suggest you to -use the advanced API rather than sin6_scope_id. - -Routing daemons and configuration programs, like route6d and -ifconfig, will need to manipulate the "embedded" scope index. -These programs use routing sockets and ioctls (like SIOCGIFADDR_IN6) -and the kernel API will return IPv6 addresses with 2nd 16bit-word -filled in. The APIs are for manipulating kernel internal structure. -Programs that use these APIs have to be prepared about differences -in kernels anyway. - -getaddrinfo(3) and getnameinfo(3) are modified to support extended numeric -IPv6 syntax, as documented in draft-ietf-ipngwg-scopedaddr-format-xx.txt. -You can specify outgoing link, by using name of the outgoing interface -like "fe80::1%ne0". This way you will be able to specify link-local scoped -address without much trouble. -To use this extension in your program, you'll need to use getaddrinfo(3), -and getnameinfo(3) with NI_WITHSCOPEID. -The implementation currently assumes 1-to-1 relationship between a link and an -interface, which is stronger than what IPv6 specs say. -Other APIs like inet_pton(3) or getipnodebyname(3) are inherently unfriendly -with scoped addresses, since they are unable to annotate addresses with -scope identifier. +There are several candidates of API to deal with scoped addresses +without ambiguity. + +The IPV6_PKTINFO ancillary data type or socket option defined in the +advanced API (RFC2292 or draft-ietf-ipngwg-rfc2292bis-xx) can specify +the outgoing interface of a packet. Similarly, the IPV6_PKTINFO or +IPV6_RECVPKTINFO socket options tell kernel to pass the incoming +interface to user applications. + +These options are enough to disambiguate scoped addresses of an +incoming packet, because we can uniquely identify the corresponding +zone of the scoped address(es) by the incoming interface. However, +they are too strong for outgoing packets. For example, consider a +multi-sited node and suppose that more than one interface of the node +belongs to a same site. When we want to send a packet to the site, +we can only specify one of the interfaces for the outgoing packet with +these options; we cannot just say "send the packet to (one of the +interfaces of) the site." + +Another kind of candidates is to use the sin6_scope_id member in the +sockaddr_in6 structure, defined in RFC2553 and +draft-ietf-ipngwg-rfc2553bis-xx.txt. The KAME kernel interprets the +sin6_scope_id field properly in order to disambiguate scoped +addresses. For example, if an application passes a sockaddr_in6 +structure that has a non-zero sin6_scope_id value to the sendto(2) +system call, the kernel should send the packet to the appropriate zone +according to the sin6_scope_id field. Similarly, when the source or +the destination address of an incoming packet is a scoped one, the +kernel should detect the correct zone identifier based on the address +and the receiving interface, fill the identifier in the sin6_scope_id +field of a sockaddr_in6 structure, and then pass the packet to an +application via the recvfrom(2) system call, etc. + +However, the semantics of the sin6_scope_id is still vague and on the +way to standardization. Additionally, not so many operating systems +support the behavior above at this moment. + +In summary, +- If your target system is limited to KAME based ones (i.e. BSD + variants and KAME snaps), use the sin6_scope_id field assuming the + kernel behavior described above. +- Otherwise, (i.e. if your program should be portable on other systems + than BSDs) + + Use the advanced API to disambiguate scoped addresses of incoming + packets. + + To disambiguate scoped addresses of outgoing packets, + * if it is okay to just specify the outgoing interface, use the + advanced API. This would be the case, for example, when you + should only consider link-local addresses and your system + assumes 1-to-1 relationship between links and interfaces. + * otherwise, sorry but you lose. Please rush the IETF IPv6 + community into standardizing the semantics of the sin6_scope_id + field. + +Routing daemons and configuration programs, like route6d and ifconfig, +will need to manipulate the "embedded" zone index. These programs use +routing sockets and ioctls (like SIOCGIFADDR_IN6) and the kernel API +will return IPv6 addresses with the 2nd 16bit-word filled in. The +APIs are for manipulating kernel internal structure. Programs that +use these APIs have to be prepared about differences in kernels +anyway. + +getaddrinfo(3) and getnameinfo(3) support an extended numeric IPv6 +syntax, as documented in draft-ietf-ipngwg-rfc2553bis-xx.txt. You can +specify the outgoing link, by using the name of the outgoing interface +as the link, like "fe80::1%ne0" (again, note that we assume there is +1-to-1 relationship between links and interfaces.) This way you will +be able to specify a link-local scoped address without much trouble. + +Other APIs like inet_pton(3) and inet_ntop(3) are inherently +unfriendly with scoped addresses, since they are unable to annotate +addresses with zone identifier. 1.3.3 Interaction with users (command line) -Most of user applications now support an extended numeric IPv6 syntax, -as documented in draft-ietf-ipngwg-scopedaddr-format-xx.txt. In this -case, you can specify outgoing link, by using the name of the outgoing -interface like "fe80::1%ne0". This is the case for some management -tools such as route(8) or ndp(8). For example, to install the IPv6 -default route by hand, you can type like +Most of user applications now support the extended numeric IPv6 +syntax. In this case, you can specify outgoing link, by using the name +of the outgoing interface like "fe80::1%ne0" (sorry for the duplicated +notice, but please recall again that we assume 1-to-1 relationship +between links and interfaces). This is even the case for some +management tools such as route(8) or ndp(8). For example, to install +the IPv6 default route by hand, you can type like # route add -inet6 default fe80::9876:5432:1234:abcd%ne0 (Although we suggest you to run dynamic routing instead of static routes, in order to avoid configuration mistakes.) Some applications have command line options for specifying an appropriate zone of a scoped address (like "ping6 -I ne0 ff02::1" to -specify the outgoing interface). However, you can't always expect such -options. Thus, we recommend you to use the extended format described +specify the outgoing interface). However, you can't always expect such +options. Thus, we recommend you to use the extended format described above. In any case, when you specify a scoped address to the command line, @@ -401,12 +518,6 @@ To summarize the sysctl knob: 1 1 invalid, or experimental (out-of-scope of spec) -RFC2462 has validation rules against incoming RA prefix information option, -in 5.5.3 (e). This is to protect hosts from malicious (or misconfigured) -routers that advertise very short prefix lifetime. -There was an update from Jim Bound to ipngwg mailing list (look -for "(ipng 6712)" in the archive) and KAME implements Jim's update. - See 1.2 in the document for relationship between DAD and autoconfiguration. 1.4.3 DHCPv6 @@ -450,22 +561,25 @@ automatically assigned to the gif interface. KAME's source address selection takes care of the following conditions: - address scope -- prefix matching against the destination - outgoing interface - whether an address is deprecated +- whether an address is temporary (in terms of RFC 3041) +- prefix matching against the destination Roughly speaking, the selection policy is as follows: - always use an address that belongs to the same scope zone as the destination. - addresses that have equal or larger scope than the scope of the destination are preferred. -- if multiple addresses have the equal scope, one which is longest - prefix matching against the destination is preferred. - a deprecated address is not used in new communications if an alternate (non-deprecated) address is available and has sufficient scope. +- a temporary address (in terms of RFC 3041 privacy extension) are + preferred to a public address. - if none of above conditions tie-breaks, addresses assigned on the outgoing interface are preferred. +- if none of above conditions tie-breaks, one which is longest prefix + matching against the destination is preferred as the last resort. For instance, ::1 is selected for ff01::1, fe80::200:f8ff:fe01:6317%ne0 for fe80::2a0:24ff:feab:839b%ne0. @@ -484,47 +598,68 @@ The precise desripction of the algorithm is quite complicated. To describe the algorithm, we introduce the following notation: For a given destination D, - samescope(D): A set of addresses that have the same scope as D. - largerscope(D): A set of addresses that have a larger scope than D. - smallerscope(D): A set of addresses that have a smaller scope than D. + samescope(D): The set of addresses that have the same scope as D. + largerscope(D): The set of addresses that have a larger scope than D. + smallerscope(D): The set of addresses that have a smaller scope than D. For a given set of addresses A, - DEP(A): a set of deprecated addresses in A. + DEP(A): the set of deprecated addresses in A. nonDEP(A): A - DEP(A). +For a given set of addresses A, + tmp(A): the set of preferred temporary-autoconfigured or + manually-configure addresses in A. + Also, the algorithm assumes that the outgoing interface for the destination D is determined. We call the interface "I". The algorithm is as follows. Selection proceeds step by step as -described; For example, if an address is selected by item 1, item 2 or +described; For example, if an address is selected by item 1, item 2 and later are not considered at all. 0. If there is no address in the same scope zone as D, just give up; the packet will not be sent. - 1. If nonDEP(samescope(D)) is not empty, - choose a longest matching address against D. If more than one - address is longest matching, choose arbitrary one provided that - an address on I is always preferred. - 2. If nonDEP(largerscope(D)) is not empty, - choose an address that has the smallest scope. If more than one - address has the smallest scope, choose arbitrary one provided + 1. If we do not prefer temporary addresses, go to 3. + Otherwise, and if tmp(samescope(D)) is not empty, + then choose an address that is on the interface I. If every + address is on I, or every address is on a different interface + from I, choose an arbitrary one provided that an address longest + matching against D is always preferred. + 2. If tmp(largerscope(D)) is not empty, + then choose an address that has the smallest scope. If more than one + address has the smallest scope, choose an arbitrary one provided + that addresses on I are always preferred. + 3. If nonDEP(samescope(D)) is not empty, + then apply the same logic as of 1. + 4. If nonDEP(largerscope(D)) is not empty, + then apply the same logic as of 2. + 5. If we do not prefer temporary addresses, go to 7. + Otherwise, and if tmp(DEP(samescope(D))) is not empty, + then choose an address that is on the interface I. If every + address is on I, or every address is on a different interface + from I, choose an arbitrary one provided that an address longest + matching against D is always preferred. + 6. If tmp(DEP(largerscope(D))) is not empty, + then choose an address that has the smallest scope. If more than + one address has the smallest scope, choose an arbitrary one provided that an address on I is always preferred. - 3. If DEP(samescope(D)) is not empty, - choose a longest matching address against D. If more than one - address is longest matching, choose arbitrary one provided that - an address on I is always preferred. - 4. If DEP(largerscope(D)) is not empty, - choose an address that has the smallest scope. If more than one - address has the smallest scope, choose arbitrary one provided + 7. If DEP(samescope(D)) is not empty, + then apply the same logic as of 5. + 8. If DEP(largerscope(D)) is not empty, + then apply the same logic as of 6. + 9. If we do not prefer temporary addresses, go to 11. + Otherwise, and if tmp(nonDEP(smallerscope(D))) is not empty, + then choose an address that has the largest scope. If more than + one address has the largest scope, choose an arbitrary one provided that an address on I is always preferred. - 5. if nonDEP(smallerscope(D)) is not empty, - choose an address that has the largest scope. If more than one - address has the largest scope, choose arbitrary one provided - that an address on I is always preferred. - 6. if DEP(smallerscope(D)) is not empty, - choose an address that has the largest scope. If more than one - address has the largest scope, choose arbitrary one provided + 10. If tmp(DEP(smallerscope(D))) is not empty, + then choose an address that has the largest scope. If more than + one address has the largest scope, choose an arbitrary one provided that an address on I is always preferred. + 11. If nonDEP(smallerscope(D)) is not empty, + then apply the same logic as of 9. + 12. If DEP(smallerscope(D)) is not empty, + then apply the same logic as of 10. There exists a document about source address selection (draft-ietf-ipngwg-default-addr-select-xx.txt). KAME's algorithm @@ -622,6 +757,15 @@ overflow due to long function call chain. KAME sys/netinet6 code is carefully designed to avoid kernel stack overflow. Because of this, KAME sys/netinet6 code defines its own protocol switch structure, as "struct ip6protosw" (see netinet6/ip6protosw.h). + +In addition to this, we restrict the number of extension headers +(including the IPv6 header) in each incoming packet, in order to +prevent a DoS attack that tries to send packets with a massive number +of extension headers. The upper limit can be configured by the sysctl +value net.inet6.ip6.hdrnestlimit. In particular, if the value is 0, +the node will allow an arbitrary number of headers. As of writing this +document, the default value is 50. + IPv4 part (sys/netinet) remains untouched for compatibility. Because of this, if you receive IPsec-over-IPv4 packet with massive number of IPsec headers, kernel stack may blow up. IPsec-over-IPv6 is okay. @@ -823,6 +967,9 @@ and initiating side). AF_INET6 and AF_INET sockets are totally separated. Port number space is totally separate between AF_INET and AF_INET6 sockets. +It should be noted that KAME/BSDI3 and KAME/FreeBSD228 are not conformant +to RFC2553 section 3.7 and 3.8. It is due to code sharing reasons. + 1.12.2 KAME/FreeBSD[34]x KAME/FreeBSD3x and KAME/FreeBSD4x use shared tcp4/6 code (from @@ -840,7 +987,7 @@ Wildcard AF_INET6 socket grabs IPv4 connection if and only if the following conditions are satisfied: - there's no AF_INET socket that matches the IPv4 connection - the AF_INET6 socket is configured to accept IPv4 traffic, i.e. - getsockopt(IPV6_BINDV6ONLY) returns 0. + getsockopt(IPV6_V6ONLY) returns 0. (XXX need checking) @@ -859,15 +1006,19 @@ udp4/6 code (from sys/netinet/udp*). The implementation is made differently from KAME/FreeBSD[34]x. KAME/NetBSD uses separate inpcb/in6pcb structures, while KAME/FreeBSD[34]x uses merged inpcb structure. +It should be noted that the default configuration of KAME/NetBSD is not +conformant to RFC2553 section 3.8. It is intentionally turned off by default +for security reasons. + 1.12.3.1 KAME/NetBSD, listening side The platform can be configured to support IPv4 mapped address/special AF_INET6 wildcard bind (disabled by default). Kernel behavior can be summarized as follows: - default: special support code will be compiled in, but is disabled by - default. It can be controlled by sysctl (net.inet6.ip6.bindv6only), - or setsockopt(IPV6_BINDV6ONLY). -- add "INET6_BINDV6ONLY": No special support code for AF_INET6 wildcard socket + default. It can be controlled by sysctl (net.inet6.ip6.v6only), + or setsockopt(IPV6_V6ONLY). +- add "INET6_V6ONLY": No special support code for AF_INET6 wildcard socket will be compiled in. AF_INET6 sockets and AF_INET sockets are totally separate. The behavior is similar to what described in 1.12.1. @@ -881,7 +1032,7 @@ Wildcard AF_INET6 socket grabs IPv4 connection if and only if the following conditions are satisfied: - there's no AF_INET socket that matches the IPv4 connection - the AF_INET6 socket is configured to accept IPv4 traffic, i.e. - getsockopt(IPV6_BINDV6ONLY) returns 0. + getsockopt(IPV6_V6ONLY) returns 0. You cannot bind(2) with IPv4 mapped address. This is a workaround for port number duplicate and other twists. @@ -919,6 +1070,9 @@ KAME/BSDi4 supports connection initiation to IPv4 mapped address KAME/OpenBSD uses NRL-based TCP/UDP stack and inpcb source code, which was derived from NRL IPv6/IPsec stack. +It should be noted that KAME/OpenBSD is not conformant to RFC2553 section 3.7 +and 3.8. It is intentionally omitted for security reasons. + 1.12.5.1 KAME/OpenBSD, listening side KAME/OpenBSD disables special behavior on AF_INET6 wildcard bind for @@ -955,7 +1109,7 @@ mapped address or not. This adds many twists: use EPSV/EPRT or LPSV/LPRT; /*IPv6*/ else error; - Under SIIT environment, the correct code would be: + The correct code, with consideration to IPv4 mapped address, would be: if (sa_family == AF_INET) use EPSV/EPRT or PASV/PORT; /*IPv4*/ else if (sa_family == AF_INET6 && IPv4 mapped address) @@ -970,17 +1124,40 @@ mapped address or not. This adds many twists: - By enabling kernel support for IPv4 mapped address (outgoing direction), servers on the kernel can be hosed by IPv6 native packet that has IPv4 mapped address in IPv6 header source, and can generate unwanted IPv4 packets. - http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt - talks more about this scenario. + draft-itojun-ipv6-transition-abuse-01.txt talks more about this scenario. Due to the above twists, some of KAME userland programs has restrictions on the use of IPv4 mapped addresses: - rshd/rlogind do not accept connections from IPv4 mapped address. This is to avoid malicious use of IPv4 mapped address in IPv6 native packet, to bypass source-address based authentication. -- ftp/ftpd does not support SIIT environment. IPv4 mapped address will be - decoded in userland, and will be passed to AF_INET sockets - (SIIT client should pass IPv4 mapped address as is, to AF_INET6 sockets). +- ftp/ftpd assume that you are on dual stack network. IPv4 mapped address + will be decoded in userland, and will be passed to AF_INET sockets + (in other words, ftp/ftpd do not support SIIT environment). + +1.12.7 Interaction with SIIT translator + +SIIT translator is specified in RFC2765. KAME node cannot become a SIIT +translator box, nor SIIT end node (a node in SIIT cloud). + +To become a SIIT translator box, we need to put additional code for that. +We do not have the code in our tree at this moment. + +There are multiple reasons that we are unable to become SIIT end node. +(1) SIIT translators require end nodes in the SIIT cloud to be IPv6-only. +Since we are unable to compile INET-less kernel, we are unable to become +SIIT end node. (2) As presented in 1.12.6, some of our userland code assumes +dual stack network. (3) KAME stack filters out IPv6 packets with IPv4 +mapped address in the header, to secure non-SIIT case (which is much more +common). Effectively KAME node will reject any packets via SIIT translator +box. See section 1.14 for more detail about the last item. + +There are documentation issues too - SIIT document requires very strange +things. For example, SIIT document asks IPv6-only (meaning no IPv4 code) +node to be able to construct IPv4 IPsec headers. If a node knows how to +construct IPv4 IPsec headers, that is not an IPv6-only node, it is a dual-stack +node. The requirements imposed in SIIT document contradict with the other +part of the document itself. 1.13 sockaddr_storage @@ -1036,22 +1213,45 @@ or bypass security controls: IPv4 address (if they are in IPv6 native packet header, they are malicious) ::ffff:0.0.0.0/104 ::ffff:127.0.0.0/104 ::ffff:224.0.0.0/100 ::ffff:255.0.0.0/104 -- 6to4 prefix generated from unspecified/multicast/loopback/broadcast/private - IPv4 address +- 6to4 (RFC3056) prefix generated from unspecified/multicast/loopback/ + broadcast/private IPv4 address 2002:0000::/24 2002:7f00::/24 2002:e000::/24 2002:ff00::/24 2002:0a00::/24 2002:ac10::/28 2002:c0a8::/32 - -Also, since KAME does not support RFC1933 auto tunnels, seeing IPv4 compatible -is very rare. You should take caution if you see those on the wire. +- IPv4 compatible address that embeds unspecified/multicast/loopback/broadcast + IPv4 address (if they are in IPv6 native packet header, they are malicious). + Note that, since KAME doe snot support RFC1933/2893 auto tunnels, KAME nodes + are not vulnerable to these packets. + ::0.0.0.0/104 ::127.0.0.0/104 ::224.0.0.0/100 ::255.0.0.0/104 + +Also, since KAME does not support RFC1933/2893 auto tunnels, seeing IPv4 +compatible is very rare. You should take caution if you see those on the wire. + +If we see IPv6 packets with IPv4 mapped address (::ffff:0.0.0.0/96) in the +header in dual-stack environment (not in SIIT environment), they indicate +that someone is trying to inpersonate IPv4 peer. The packet should be dropped. + +IPv6 specifications do not talk very much about IPv6 unspecified address (::) +in the IPv6 source address field. Clarification is in progress. +Here are couple of comments: +- IPv6 unspecified address can be used in IPv6 source address field, if and + only if we have no legal source address for the node. The legal situations + include, but may not be limited to, (1) MLD while no IPv6 address is assigned + to the node and (2) DAD. +- If IPv6 TCP packet has IPv6 unspecified address, it is an attack attempt. + The form can be used as a trigger for TCP DoS attack. KAME code already + filters them out. +- The following examples are seemingly illegal. It seems that there's general + consensus among ipngwg for those. (1) mobile-ip6 home address option, + (2) offlink packets (so routers should not forward them). + KAME implmements (2) already. KAME code is carefully written to avoid such incidents. More specifically, KAME kernel will reject packets with certain source/dstination address in IPv6 base header, or IPv6 routing header. Also, KAME default configuration file is written carefully, to avoid those attacks. -http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt -talks about more about this. +draft-itojun-ipv6-transition-abuse-01.txt talks about more about this. 1.15 Node's required addresses @@ -1098,6 +1298,38 @@ like ff02::9 for RIPng. Users can join groups by using appropriate system calls like setsockopt(2). +1.16 Advanced API + +Current KAME kernel implements 2292bis API, documented in +draft-ietf-ipngwg-rfc2292bis-xx.txt. It also implements RFC2292 API, +for backward compatibility purposes with *BSD-integrated codebase. +KAME tree ships with 2292bis headers. +*BSD-integrated codebase implements either RFC2292, or 2292bis, API. +see "COVERAGE" document for detailed implementation status. + +Here are couple of issues to mention: +- *BSD-integrated binaries, compiled for RFC2292, will work on KAME kernel. + For example, OpenBSD 2.7 /sbin/rtsol will work on KAME/openbsd kernel. +- KAME binaries, compiled using 2292bis, will not work on *BSD-integrated + kenrel. For example, KAME /usr/local/v6/sbin/rtsol will not work on + OpenBSD 2.7 kernel. +- 2292bis API is not compatible with RFC2292 API. 2292bis #define symbols + conflict with RFC2292 symbols. Therefore, if you compile programs that + assume RFC2292 API, the compilation itself goes fine, however, the compiled + binary will not work correctly. The problem is not KAME issue, but API + issue. For example, Solaris 8 implements 2292bis API. If you compile + RFC2292-based code on Solaris 8, the binary can behave strange. + +There are few (or couple of) incompatible behavior in RFC2292 binary backward +compatibility support in KAME tree. To enumerate: +- Type 0 routing header lacks support for strict/loose bitmap. + Even if we see packets with "strict" bit set, those bits will not be made + visible to the userland. + Background: RFC2292 document is based on RFC1883 IPv6, and it uses + strict/loose bitmap. 2292bis document is based on RFC2460 IPv6, and it has + no strict/loose bitmap (it was removed from RFC2460). KAME tree obeys + RFC2460 IPv6, and lacks support for strict/loose bitmap. + 2. Network Drivers KAME requires three items to be added into the standard drivers: @@ -1228,7 +1460,16 @@ Here is a list of FreeBSD 3.x-RELEASE drivers and its conditions: More drivers will just simply work on KAME FreeBSD 3.x-RELEASE but have not been checked yet. -2.5 OpenBSD 2.x +2.5 FreeBSD 4.x-RELEASE + +Here is a list of FreeBSD 4.x-RELEASE drivers and its conditions: + + driver multicast + --- --- + (Ethernet) + lnc/vmware ok + +2.6 OpenBSD 2.x Here is a list of OpenBSD 2.x drivers and its conditions: @@ -1246,7 +1487,7 @@ Here is a list of OpenBSD 2.x drivers and its conditions: configuration. This happens with certain revision of chipset on the card. Should be fixed by now by workaround in sys/net/if.c, but still not sure. -2.6 BSD/OS 4.x +2.7 BSD/OS 4.x The following lists BSD/OS 4.x device drivers and its conditions: @@ -1306,11 +1547,11 @@ the connection will be relayed toward IPv4 destination 163.221.202.12. faithd must be invoked on FAITH-relay dual stack node. For more details, consult kame/kame/faithd/README and -draft-ietf-ngtrans-tcpudp-relay-01.txt. +draft-ietf-ngtrans-tcpudp-relay-04.txt. 3.2 IPv6-to-IPv4 header translator -# removed since it is not imported to FreeBSD-current +(to be written) 4. IPsec @@ -1324,6 +1565,9 @@ Note that KAME/OpenBSD does NOT include support for KAME IPsec code, as OpenBSD team has their home-brew IPsec stack and they have no plan to replace it. IPv6 support for IPsec is, therefore, lacking on KAME/OpenBSD. +http://www.netbsd.org/Documentation/network/ipsec/ has more information +including usage examples. + 4.1 Policy Management The kernel implements experimental policy management code. There are two way @@ -1383,10 +1627,8 @@ Tunnel mode works basically fine, but comes with the following restrictions: IPsec tunnel as pseudo interfaces. - Authentication model for AH tunnel must be revisited. We'll need to improve the policy management engine, eventually. -- Tunnelling for IPv6 IPsec is still incomplete. This is disabled by default. - If you need to perform experiments, add "options IPSEC_IPV6FWD" into - the kernel configuration file. Note that path MTU discovery does not work - across IPv6 IPsec tunnel gateway due to insufficient code. +- Path MTU discovery does not work across IPv6 IPsec tunnel gateway due to + insufficient code. AH specificaton does not talk much about "multiple AH on a packet" case. We incrementally compute AH checksum, from inside to outside. Also, we @@ -1401,6 +1643,16 @@ we do it incrementally. As a result, we get crypto checksums like below: Also note that AH3 has the smallest sequence number, and AH1 has the largest sequence number. +To avoid traffic analysis on shorter packets, ESP output logic supports +random length padding. By setting net.inet.ipsec.esp_randpad (or +net.inet6.ipsec6.esp_randpad) to positive value N, you can ask the kernel +to randomly pad packets shorter than N bytes, to random length smaller than +or equal to N. Note that N does not include ESP authentication data length. +Also note that the random padding is not included in TCP segment +size computation. Negative value will turn off the functionality. +Recommeded value for N is like 128, or 256. If you use a too big number +as N, you may experience inefficiency due to fragmented packtes. + 4.4 IPComp handling IPComp stands for IP payload compression protocol. This is aimed for @@ -1448,13 +1700,15 @@ Here are some points to be noted: The IPsec code in the kernel conforms (or, tries to conform) to the following standards: "old IPsec" specification documented in rfc182[5-9].txt - "new IPsec" specification documented in rfc240[1-6].txt, rfc241[01].txt, - rfc2451.txt and draft-mcdonald-simple-ipsec-api-01.txt (draft expired, - but you can take from ftp://ftp.kame.net/pub/internet-drafts/). - (NOTE: IKE specifications, rfc240[7-9].txt are implemented in userland, - as "racoon" IKE daemon) + "new IPsec" specification documented in: + rfc240[1-6].txt rfc241[01].txt rfc2451.txt + draft-mcdonald-simple-ipsec-api-01.txt + (expired, available in ftp://ftp.kame.net/pub/internet-drafts/) + draft-ietf-ipsec-ciph-aes-cbc-00.txt IPComp: RFC2393: IP Payload Compression Protocol (IPComp) +IKE specifications (rfc240[7-9].txt) are implemented in userland +as "racoon" IKE daemon. Currently supported algorithms are: old IPsec AH @@ -1472,6 +1726,9 @@ Currently supported algorithms are: keyed SHA1 with 96bit crypto checksum (no document) HMAC MD5 with 96bit crypto checksum (rfc2403.txt HMAC SHA1 with 96bit crypto checksum (rfc2404.txt) + HMAC SHA2-256 with 96bit crypto checksum (no document) + HMAC SHA2-384 with 96bit crypto checksum (no document) + HMAC SHA2-512 with 96bit crypto checksum (no document) new IPsec ESP null encryption (rfc2410.txt) DES-CBC with derived IV @@ -1480,7 +1737,9 @@ Currently supported algorithms are: 3DES-CBC with explicit IV (rfc2451.txt) BLOWFISH CBC (rfc2451.txt) CAST128 CBC (rfc2451.txt) - RC5 CBC (rfc2451.txt) + RIJNDAEL/AES CBC (draft-ietf-ipsec-ciph-aes-cbc-00.txt, + uses IANA-assigned protocol number) + TWOFISH CBC (draft-ietf-ipsec-ciph-aes-cbc-00.txt) each of the above can be combined with: ESP authentication with HMAC-MD5(96bit) ESP authentication with HMAC-SHA1(96bit) @@ -1560,26 +1819,104 @@ coverage for IPsec crypto algorithms documented in RFC (we do not cover algorithms with intellectual property issues, though). Here are (some of) platforms we have tested IPsec/IKE interoperability -in the past, in no particular order. Note that both ends (KAME and +in the past, no particular order. Note that both ends (KAME and others) may have modified their implementation, so use the following list just for reference purposes. - Altiga, Ashley-laurent (vpcom.com), Data Fellows (F-Secure), - BlueSteel, CISCO, Ericsson, ACC, Fitel, FreeS/WAN, HITACHI, IBM - AIX, IIJ, Intel, Microsoft WinNT, NAI PGPnet, - NIST (linux IPsec + plutoplus), Netscreen, OpenBSD isakmpd, Radguard, - RedCreek, Routerware, SSH, Secure Computing, Soliton, Toshiba, - TIS/NAI Gauntret, VPNet, Yamaha RT100i + ACC, allied-telesis, Altiga, Ashley-laurent (vpcom.com), BlueSteel, + CISCO IOS, Cryptek, Checkpoint FW-1, Data Fellows (F-Secure), + Ericsson, Fitel, FreeS/WAN, HiFn, HITACHI, IBM AIX, IIJ, Intel Canada, + Intel Packet Protect, MEW NetCocoon, MGCS, Microsoft WinNT/2000, + NAI PGPnet, NetLock, NIST (linux IPsec + plutoplus), NEC IX5000, + Netscreen, NxNetworks, OpenBSD isakmpd, Pivotal, Radguard, RapidStream, + RedCreek, Routerware, RSA, SSH (both IPv4/IPv6), Secure Computing, + Soliton, Sun Solaris8, TIS/NAI Gauntret, Toshiba, VPNet, + Yamaha RT series Here are (some of) platforms we have tested IPComp/IKE interoperability in the past, in no particular order. - IRE + IRE, SSH (both IPv4/IPv6), NetLock + +VPNC (vpnc.org) provides IPsec conformance tests, using KAME and OpenBSD +IPsec/IKE implementations. Their test results are available at +http://www.vpnc.org/conformance.html, and it may give you more idea +about which implementation interoperates with KAME IPsec/IKE implementation. 5. ALTQ -# removed since it is not imported to FreeBSD-current +KAME kit includes ALTQ 2.1 code, which supports FreeBSD2, FreeBSD3, +NetBSD and OpenBSD. For BSD/OS, ALTQ does not work. +ALTQ in KAME supports (or tries to support) IPv6. +(actually, ALTQ is developed on KAME repository since ALTQ 2.1 - Jan 2000) + +ALTQ occupies single character device number. For FreeBSD, it is officially +allocated. For OpenBSD and NetBSD, we use the number which is not +currently allocated (will eventually get an official number). +The character device is enabled for i386 architecture only. To enable and +compile ALTQ-ready kernel for other archititectures, take the following steps: +- assume that your architecture is FOOBAA. +- modify sys/arch/FOOBAA/FOOBAA/conf.c (or somewhere that defines cdevsw), + to include a line for ALTQ. look at sys/arch/i386/i386/conf.c for + example. The major number must be same as i386 case. +- copy kernel configuration file (like ALTQ.v6 or GENERIC.v6) from i386, + and modify accordingly. +- build a kernel. +- before building userland, change netbsd/{lib,usr.sbin,usr.bin}/Makefile + (or openbsd/foobaa) so that it will visit altq-related sub directories. 6. mobile-ip6 -# removed since it is not imported to FreeBSD-current +6.1 KAME node as correspondent node + +Default installation recognizes home address option (in destination +options header). No sub-options are supported. interaction with +IPsec, and/or 2292bis API, needs further study. + +6.2 KAME node as home agent/mobile node + +KAME kit includes Ericsson mobile-ip6 code. The integration is just started +(in Feb 2000), and we will need some more time to integrate it better. + +See kame/mip6config/{QUICKSTART,README_MIP6.txt} for more details. + +The Ericsson code implements revision 09 of the mobile-ip6 draft. There +are other implementations available: + NEC: http://www.6bone.nec.co.jp/mipv6/internal-dist/ (-13 draft) + SFC: http://neo.sfc.wide.ad.jp/~mip6/ (-13 draft) + +7. Coding style + +The KAME developers basically do not make a bother about coding +style. However, there is still some agreement on the style, in order +to make the distributed develoment smooth. + +- the tab character should be 8 columns wide (tabstops are at 8, 16, 24, ... + column). With vi, use ":set ts=8 sw=8". +- each line should be within 80 characters. +- keep a single open/close bracket in a comment such as in the following + line: + putchar('('); /* ) */ + without this, some vi users would have a hard time to match a pair of + brackets. Although this type of bracket seems clumsy and is even + harmful for some other type of vi users and Emacs users, the + agreement in the KAME developers is to allow it. +- add the following line to the head of every KAME-derived file: + /* (dollar)KAME(dollar) */ + where "(dollar)" is the dollar character ($), and around "$" are tabs. + (this is for C. For other language, you should use its own comment + line.) + Once commited to the CVS repository, this line will contain its + version number (see, for example, at the top of this file). This + would make it easy to report a bug. +- when creating a new file with the WIDE copyright, tap "make copyright.c" at + the top-level, and use copyright.c as a template. KAME RCS tag will be + included automatically. +- when editting a third-party package, keep its own coding style as + much as possible, even if the style does not follow the items above. + +When you want to contribute something to the KAME project, and if *you +do not mind* the agreement, it would be helpful for the project to +keep these rules. Note, however, that we would never intend to force +you to adopt our rules. We would rather regard your own style, +especially when you have a policy about the style. <end of IMPLEMENTATION> diff --git a/share/examples/IPv6/USAGE b/share/examples/IPv6/USAGE index 5a02037..d9191899 100644 --- a/share/examples/IPv6/USAGE +++ b/share/examples/IPv6/USAGE @@ -1,12 +1,12 @@ - USAGE - - KAME Project - http://www.kame.net/newsletter/ - $FreeBSD$ + USAGE + KAME Project + $KAME: USAGE,v 1.33 2000/11/22 10:22:57 itojun Exp $ + $FreeBSD$ This is a introduction of how to use the commands provided in the KAME kit. For more information, please refer to each man page. + <<<ifconfig>>> A link-local address is automatically assigned to each interface, when @@ -14,6 +14,11 @@ the interface becomes up for the first time. Even if you find an interface without a link-local address, do not panic. The link-local address will be assigned when it becomes up (with "ifconfig IF up"). +If you do not see a link-local address assigned to an interface on "ifconfig +up", the interface does not support IPv6 for some reasons - for example, +if the interface does not support link-layer multicast (IFF_MULTICAST is not +set), the interface cannot be used for IPv6. + Some network drivers allow an interface to become up even without a hardware address (for example, PCMCIA network cards). In such cases, it is possible that an interface has no link-local address even if the @@ -21,190 +26,187 @@ interface is up. If you see such situation, please disable the interface once and then re-enable it (i.e. do `ifconfig IF down; ifconfig IF up'). -Pseudo interfaces (like "gif" tunnel device) will borrow IPv6 interface -identifier (lowermost 64bit of the address) from EUI64/IEEE802 sources, -like ethernet cards. Pseudo interfaces will be able to get IPv6 link-local -address, if you have other "real" interface configured beforehand. -If you have no EUI64/IEEE802 sources on the node, you may need to configure -link-local address manually. Though we have last-resort code in the kernel, -which generates interface identifier from MD5(hostname), it may not suitable -for your usage (for example, if you configure same hostname on both sides -of gif tunnel, you will be doomed). +Pseudo interfaces (like "gif" tunnel device) will borrow IPv6 +interface identifier (lowermost 64bit of the address) from +EUI64/IEEE802 sources, like ethernet cards. Pseudo interfaces will be +able to get an IPv6 link-local address, if you have other "real" +interface configured beforehand. If you have no EUI64/IEEE802 sources +on the node, we have last-resort code in the kernel, which generates +interface identifier from MD5(hostname). MD5(hostname) may not be suitable +for your usage (for example, if you configure same hostname on both sides of +gif tunnel, you will be doomed), and if so, you may need to configure +link-local address manually. +See RFC2472 for more discussion on how to generate an interface ID for +pseudo interfaces. If you have a router announcing Router Advertisement, -global addresses will be assigned automatically. So, "ifconfig" is not -necessary for your *host*. (Please refer to "sysctl" section for configuring -a host to accept Router Advertisement.) +global addresses will be assigned automatically. So, neither +"ifconfig" nor "prefix" is necessary for your *host* (non-router node). +(Please refer to "sysctl" section for configuring a host to accept +Router Advertisement.) If you want to set up a router, you need to assign global addresses -for two or more interfaces by "ifconfig" or "prefix". (prefix command -is described at next section) +for two or more interfaces by "ifconfig" or "prefix" (prefix command +is described at next section). If you want to assign a global address by "ifconfig", don't forget to specify the "alias" argument to keep the link-local address. -# ifconfig de0 inet6 fec0:0:0:1000:200:f8ff:fe01:6317 alias +# ifconfig de0 inet6 3ffe:501:808:1:200:f8ff:fe01:6317 prefixlen 64 alias # ifconfig de0 de0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 - inet 172.16.202.12 netmask 0xffffff00 broadcast 172.16.202.255 - inet6 fe80::200:f8ff:fe01:6317%de0 prefixlen 64 - inet6 fec0:0:0:1000:200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:1000:: prefixlen 64 anycast - ether 00:00:f8:01:63:17 - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP + inet6 fe80::200:f8ff:fe01:6317%de0 prefixlen 64 scopeid 0x1 + inet 163.221.202.12 netmask 0xffffff00 broadcast 163.221.202.255 + inet6 3ffe:501:808:1:200:f8ff:fe01:6317 prefixlen 64 + ether 00:00:f8:01:63:17 + media: 100baseTX status: active See also "/etc/rc.network6" for actual examples. <<prefix>> -In IPv6 architecture, an IPv6 address of an interface can be generated -from a prefix assigned to it, and a link-dependent identifier for the -interface. Assigning a full IPv6 address by ifconfig is not -necessary anymore, because, user can only take care of prefix, by letting -system take care of interface identifier. +In the IPv6 architecture, an IPv6 address of an interface can be +generated from a prefix assigned to the interface, and a +link-dependent identifier for the interface. So assigning a full IPv6 +address by ifconfig is not necessary anymore, because user can only +take care of prefix, by letting system take care of interface +identifier. The newly added "prefix" command enables user to just assign prefixes for interfaces, and let your system automatically generate IPv6 addresses. Prefixes added by the "prefix" command is maintained in the kernel consistently with prefixes assigned by Router -Renumbering(in case of routers). - -But "prefix" command can only be used on router, because host should be -able to configure its addr automatically. Prefixes added by the "prefix" -command are maintained independently from prefixes assigned by -Router Advertisement. Those two type of prefixes should not coexist on -a machine at the same time, and when it happens, it is considered to be -miss configuration. +Advertisement (in case of hosts) and with prefixes assigned by Router +Renumbering (in case of routers). Manual assignment of prefixes or +change of prefix properties take precedence over ones assigned by +Router Advertisement or Router Renumbering. -Manual assignment of prefixes or change of prefix properties take -precedence over ones assigned by Router Renumbering. +prefix command works only on routers. -If you want to assign a prefix(and consequently an address) manually, do +If you want to assign a prefix (and consequently address) manually, do as follows: -# prefix de0 fec0:0:0:1000:: # ifconfig de0 de0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 - inet 172.16.202.12 netmask 0xffffff00 broadcast 172.16.202.255 - inet6 fe80:1::200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:1000:200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:1000:: prefixlen 64 anycast - ether 00:00:f8:01:63:17 - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP + inet6 fe80::200:f8ff:fe01:6317%de0 prefixlen 64 scopeid 0x1 + inet 163.221.202.12 netmask 0xffffff00 broadcast 163.221.202.255 + ether 00:00:f8:01:63:17 + media: 100baseTX status: active +# prefix de0 3ffe:501:808:1:: +# ifconfig de0 +de0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 + inet6 fe80::200:f8ff:fe01:6317%de0 prefixlen 64 scopeid 0x1 + inet 163.221.202.12 netmask 0xffffff00 broadcast 163.221.202.255 + inet6 3ffe:501:808:1:200:f8ff:fe01:6317 prefixlen 64 + ether 00:00:f8:01:63:17 + media: 100baseTX status: active -To check assigned prefix, use the "ndp" command. (See description of -ndp command about its usage) +To check assigned prefix, use the "ndp" command (See description of +ndp command about its usage). # ndp -p -fec0:0:0:1000::/64 if=de0 - flags=LA, vltime=2592000, pltime=604800, expire=Never +3ffe:501:808:1::/64 if=de0 + flags=LA, vltime=2592000, pltime=604800, expire=Never, origin=RR No advertising router The "prefix" command also has node internal prefix renumbering ability. -If you have multiple prefixes which have fec0:0:0:1000:/56 at the top, -and would like to renumber them to fec0:0:0:2000:/56, then use the +If you have multiple prefixes which have 3ffe:501:808:/48 at the top, +and would like to renumber them to 3ffe:501:4819:/48, then use the "prefix" command with the "matchpr" argument and the "usepr" argument. Suppose that current state of before renumbering as follows: # ifconfig de0 de0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 - inet 172.16.202.12 netmask 0xffffff00 broadcast 172.16.202.255 - inet6 fe80:1::200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:1000:200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:1000:: prefixlen 64 anycast - ether 00:00:f8:01:63:17 - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP - + inet6 fe80::200:f8ff:fe01:6317%de0 prefixlen 64 scopeid 0x1 + inet 163.221.202.12 netmask 0xffffff00 broadcast 163.221.202.255 + inet6 3ffe:501:808:1:200:f8ff:fe01:6317 prefixlen 64 + ether 00:00:f8:01:63:17 + media: 100baseTX status: active # ifconfig de1 de1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 - inet 172.16.203.12 netmask 0xffffff00 broadcast 172.16.203.255 - inet6 fe80:1::200:f8ff:fe55:7011 prefixlen 64 - inet6 fec0:0:0:1001:200:f8ff:fe55:7011 prefixlen 64 - inet6 fec0:0:0:1001:: prefixlen 64 anycast + inet6 fe80::200:f8ff:fe55:7011%de1 prefixlen 64 scopeid 0x2 + inet 163.221.203.12 netmask 0xffffff00 broadcast 163.221.203.255 + inet6 3ffe:501:808:2:200:f8ff:fe55:7011 prefixlen 64 ether 00:00:f8:55:70:11 - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP - + media: 100baseTX status: active # ndp -p -fec0:0:0:1000::/64 if=de0 - flags=LA, vltime=2592000, pltime=604800, expire=Never +3ffe:501:808:1::/64 if=de0 + flags=LA, vltime=2592000, pltime=604800, expire=Never, origin=RR No advertising router -fec0:0:0:1001::/64 if=de1 - flags=LA, vltime=2592000, pltime=604800, expire=Never +3ffe:501:808:2::/64 if=de1 + flags=LA, vltime=2592000, pltime=604800, expire=Never, origin=RR No advertising router Then do as follows: -# prefix -a matchpr fec0:0:0:1000:: mp_len 56 usepr fec0:0:0:2000:: up_uselen 56 change +# prefix -a matchpr 3ffe:501:808:: mp_len 48 usepr 3ffe:501:4819:: up_uselen 48 change If command is successful, prefixes and addresses will be renumbered as follows. # ifconfig de0 de0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 - inet 172.16.202.12 netmask 0xffffff00 broadcast 172.16.202.255 - inet6 fe80:1::200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:2000:200:f8ff:fe01:6317 prefixlen 64 - inet6 fec0:0:0:2000:: prefixlen 64 anycast - ether 00:00:f8:01:63:17 - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP + inet6 fe80::200:f8ff:fe01:6317%de0 prefixlen 64 scopeid 0x1 + inet 163.221.202.12 netmask 0xffffff00 broadcast 163.221.202.255 + inet6 3ffe:501:4819:1:200:f8ff:fe01:6317 prefixlen 64 + ether 00:00:f8:01:63:17 + media: 100baseTX status: active # ifconfig de1 de1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 - inet 172.16.203.12 netmask 0xffffff00 broadcast 172.16.203.255 - inet6 fe80:1::200:f8ff:fe55:7011 prefixlen 64 - inet6 fec0:0:0:2001:200:f8ff:fe55:7011 prefixlen 64 - inet6 fec0:0:0:2001:: prefixlen 64 anycast + inet6 fe80::200:f8ff:fe55:7011%de0 prefixlen 64 scopeid 0x2 + inet 163.221.203.12 netmask 0xffffff00 broadcast 163.221.203.255 + inet6 3ffe:501:4819:2:200:f8ff:fe55:7011 prefixlen 64 ether 00:00:f8:55:70:11 - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP + media: 100baseTX status: active # ndp -p -fec0:0:0:2000::/64 if=de0 - flags=LA, vltime=2592000, pltime=604800, expire=Never +3ffe:501:4819:1::/64 if=de0 + flags=LA, vltime=2592000, pltime=604800, expire=Never, origin=RR No advertising router -fec0:0:0:2001::/64 if=de1 - flags=LA, vltime=2592000, pltime=604800, expire=Never +3ffe:501:4819:2::/64 if=de1 + flags=LA, vltime=2592000, pltime=604800, expire=Never, origin=RR No advertising router See also "/etc/rc.network6" for actual examples. + <<<route>>> -If there is a router announcing Router Advertisement on the subnet, -you don't need to add a default route for your host by yourself. -(Please refer to "sysctl" section to accept Router Advertisement.) +If there is a router announcing Router Advertisement on a subnet, +you need not to add a default route for your host by hand +(Please refer to "sysctl" section to accept Router Advertisement). + +If you want to add a default route manually, do like: -If you want to add a default route manually, do as follows: +# route add -inet6 default fe80::200:a2ff:fe0e:7543%ed0 -# route add -inet6 default fe80::200:a2ff:fe0e:7543%de0 +"default" means ::/0. In other cases, if "prefixlen" is omitted, 64 +is assumed for "prefixlen" to get along with the aggregatable address. -"default" means ::/0. +Note that, in IPv6, a link-local address should be used as gateway +("fe80::200:a2ff:fe0e:7543%ed0" in the above). If you use global addresses, +ICMPv6 redirect will not work properly. Also note that we use a special form +of link-local address as gateway. See Section 1.3 of IMPLEMENTATION for +more details. +For ease of configuration we recommend you to avoid static routes and run +a routing daemon (route6d for example) instead. -Note that, in IPv6, link-local address should be used as gateway -("fe80::200:a2ff:fe0e:7543%de1" in the above). If you use global addresses, -icmp6 redirect may not work properly. For ease of configuration we recommend -you to avoid static routes and run a routing daemon (route6d for example) -instead. -<<<ping6>>> (This might be integrated into "ping" as "ping -6" in the future.) +<<<ping6>>> Reachability can be checked by "ping6". This "ping6" allows multicast for its argument. -% ping6 -I xl0 ff02::1 -or -% ping6 ff02::1%xl0 +% ping6 -n -I ed0 ff02::1 + +PING6(56=40+8+8 bytes) fe80::5254:ff:feda:cb7d --> ff02::1%ed0 +56 bytes from fe80::5254:ff:feda:cb7d%lo0, icmp_seq=0 hlim=64 time=0.25 ms +56 bytes from fe80::2a0:c9ff:fe84:ed6c%ed0, icmp_seq=0 hlim=64 time=1.333 ms(DUP!) +56 bytes from fe80::5254:ff:feda:d161%ed0, icmp_seq=0 hlim=64 time=1.459 ms(DUP!) +56 bytes from fe80::260:97ff:fec2:80bf%ed0, icmp_seq=0 hlim=64 time=1.538 ms(DUP!) +56 bytes from 3ffe:501:4819:2000:5054:ff:fedb:aa46, icmp_seq=0 hlim=255 time=1.615 ms(DUP!) -PING6(56=40+8+8 bytes) fe80::5254:ff:feda:cb7d --> ff02::1 -56 bytes from fe80::5254:ff:feda:cb7d, icmp_seq=0 hlim=64 time=0.25 ms -56 bytes from fe80::2a0:c9ff:fe84:ed6c, icmp_seq=0 hlim=64 time=1.333 ms(DUP!) -56 bytes from fe80::5254:ff:feda:d161, icmp_seq=0 hlim=64 time=1.459 ms(DUP!) -56 bytes from fe80::260:97ff:fec2:80bf, icmp_seq=0 hlim=64 time=1.538 ms(DUP!) <<<ping6 -w>>> @@ -212,13 +214,14 @@ Name resolution is possible by ICMPv6 node information query message. This is very convenient for link-local addresses whose host name cannot be resolved by DNS. Specify the "-w" option to "ping6". -% ping6 -I xl0 -w ff02::1 +% ping6 -n -I ed0 -w ff02::1 -64 bytes from fe80::5254:ff:feda:cb7d: fto.kame.net -67 bytes from fe80::5254:ff:feda:d161: banana.kame.net -69 bytes from fe80::2a0:c9ff:fe84:ebd9: paradise.kame.net -66 bytes from fe80::260:8ff:fe8b:447f: taroh.kame.net -66 bytes from fe80::2a0:c9ff:fe84:ed6c: ayame.kame.net +64 bytes from fe80::5254:ff:feda:cb7d%lo0: fto.kame.net +67 bytes from fe80::5254:ff:feda:d161%ed0: banana.kame.net +69 bytes from fe80::2a0:c9ff:fe84:ebd9%ed0: paradise.kame.net +66 bytes from fe80::260:8ff:fe8b:447f%ed0: taroh.kame.net +66 bytes from fe80::2a0:c9ff:fe84:ed6c%ed0: ayame.kame.net + <<<traceroute6>>> @@ -239,60 +242,59 @@ traceroute to tokyo.v6.wide.ad.jp (3ffe:501:0:401:200:e8ff:fed5:8923), 30 hops m 2 otemachi.v6.wide.ad.jp (3ffe:501:0:1802:260:97ff:feb6:7ff0) 27.345 ms 26.706 ms 26.563 ms 3 tokyo.v6.wide.ad.jp (3ffe:501:0:401:200:e8ff:fed5:8923) 26.329 ms 26.36 ms 28.63 ms + <<<ndp>>> To display the current Neighbor cache, use "ndp": % ndp -a Neighbor Linklayer Address Netif Expire St Flgs Prbs -nr60.v6.kame.net 0:60:97:c2:80:bf xl0 expired S R -fec0:0:0:1000:2c0:cff:fe10 0:c0:c:10:3a:53 xl0 permanent R -paradise.v6.kame.net 52:54:0:dc:52:17 xl0 expired S R -fe80:1::200:eff:fe49:f929 0:0:e:49:f9:29 xl0 expired S R -fe80:1::200:86ff:fe05:80da 0:0:86:5:80:da xl0 expired S -fe80:1::200:86ff:fe05:c2d8 0:0:86:5:c2:d8 xl0 9s R +nr60.v6.kame.net 0:60:97:c2:80:bf ed0 expired S R +3ffe:501:4819:2000:2c0:cff:fe 0:c0:c:10:3a:53 ed0 permanent R +paradise.v6.kame.net 52:54:0:dc:52:17 ed0 expired S R +fe80::200:eff:fe49:f929%ed0 0:0:e:49:f9:29 ed0 expired S R +fe80::200:86ff:fe05:80da%ed0 0:0:86:5:80:da ed0 expired S +fe80::200:86ff:fe05:c2d8%ed0 0:0:86:5:c2:d8 ed0 9s R -To flush the all NDP cache, execute the following by root. +To flush all of the NDP cache entries, execute the following as root. # ndp -c -To display the prefix list. +To display the prefix list: % ndp -p -fec0:0:0::1000::/64 if=xl0 - flags=LA, vltime=2592000, pltime=604800, expire=29d23h59m58s +3ffe:501:4819:2000::/64 if=ed0 + flags=LA, vltime=2592000, pltime=604800, expire=29d23h59m58s, origin=RA advertised by - fe80::5254:ff:fedc:5217 - fe80::260:97ff:fec2:80bf - fe80::200:eff:fe49:f929 + fe80::5254:ff:fedc:5217%ed0 (reachable) + fe80::260:97ff:fec2:80bf%ed0 (reachable) + fe80::200:eff:fe49:f929%ed0 (no neighbor state) -To display the default router list. +To display the default router list: % ndp -r -fe80::260:97ff:fec2:80bf if=xl0, flags=, expire=29m55s -fe80::5254:ff:fedc:5217 if=xl0, flags=, expire=29m7s -fe80::200:eff:fe49:f929 if=xl0, flags=, expire=28m47s +fe80::260:97ff:fec2:80bf if=ed0, flags=, expire=29m55s +fe80::5254:ff:fedc:5217 if=ed0, flags=, expire=29m7s +fe80::200:eff:fe49:f929 if=ed0, flags=, expire=28m47s + <<<rtsol>>> To generate a Router Solicitation message right now to get global addresses, use "rtsol". -# ifconfig xl0 -xl0: flags=8a43<UP,BROADCAST,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500 - inet6 fe80:2::2a0:24ff:feab:839b%xl0 prefixlen 64 - ether 0:a0:24:ab:83:9b - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP 100baseTX <hw-loopback> - -# rtsol xl0 -# ifconfig xl0 -xl0: flags=8a43<UP,BROADCAST,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500 - inet6 fe80:2::2a0:24ff:feab:839b%xl0 prefixlen 64 - inet6 fec0:0:0:1000:2a0:24ff:feab:839b prefixlen 64 - ether 0:a0:24:ab:83:9b - media: autoselect (10baseT/UTP) status: active - supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP 100baseTX <hw-loopback> +# ifconfig ef0 +ef0: flags=8863<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST> + link type ether 0:a0:24:ab:83:9b mtu 1500 speed 10Mbps + media 10baseT status active + inet6 fe80::2a0:24ff:feab:839b%ef0 prefixlen 64 scopeid 0x2 +# rtsol ef0 +# ifconfig ef0 +ef0: flags=8863<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST> + link type ether 0:a0:24:ab:83:9b mtu 1500 speed 10Mbps + media 10baseT status active + inet6 fe80::2a0:24ff:feab:839b%ef0 prefixlen 64 scopeid 0x2 + inet6 3ffe:501:4819:2000:2a0:24ff:feab:839b prefixlen 64 <<<rtsold>>> @@ -301,18 +303,23 @@ rtsold is a daemon version of rtsol. If you run KAME IPv6 on a laptop computer and frequently move with it, the daemon is useful since it watches the interface and sends router solicitations when the status of the interface changes. Note, however, that the feature is disabled by default. Please -add -m option at invocation of rtsold. +add -m option when invocation of rtsold. rtsold also supports multiple interfaces. For example, you can invoke the daemon as follows: + # rtsold -m ep0 cnw0 + <<<netstat>>> To see routing table: - + # netstat -nr -# netstat -nrl (long format with Ref and Use) +# netstat -nrl + long format with Ref and Use. Note that bsdi4 does not support the + -l option. You should use the -O option instead. + <<<sysctl>>> @@ -324,13 +331,14 @@ as follows: # sysctl -w net.inet6.ip6.accept_rtadv=1 + <<<gifconfig>>> "gif" interface enables you to perform IPv{4,6} over IPv{4,6} protocol tunneling. To use this interface, you must specify the outer IPv{4,6} address by using gifconfig, like: -# gifconfig gif0 172.16.198.61 172.16.11.21 +# gifconfig gif0 163.221.198.61 163.221.11.21 "ifconfig gif0" will configure the address pair used for inner IPv{4,6} header. @@ -345,15 +353,14 @@ The following example configures un-numbered IPv6-over-IPv4 tunnel: The following example configures numbered IPv6-over-IPv4 tunnel: # gifconfig gif0 10.0.0.1 10.0.0.1 netmask 255.255.255.0 -# ifconfig gif0 inet6 fec0:0:0:3000::1 fec0:0:0:3000::2 prefixlen 64 alias +# ifconfig gif0 inet6 3ffe:501:808:5::1 3ffe:501:808:5::2 prefixlen 64 alias IPv6 spec allows you to use point-to-point link without global IPv6 address assigned to the interface. Routing protocol (such as RIPng) uses link-local addresses only. If you are to configure IPv6-over-IPv4 tunnel, you need not to configure an address pair for inner IPv6 header. We suggest you to use the former example (un-numbered -IPv6-over-IPv4 tunnel) to connect to 6bone for simplicity, -for router to router connection. +IPv6-over-IPv4 tunnel) to connect to 6bone for simplicity. Note that it is so easy to make an infinite routing loop using gif interface, if you configure a tunnel using the same protocol family @@ -361,6 +368,16 @@ for inner and outer header (i.e. IPv4-over-IPv4). Refer to gifconfig(8) for more details. + +<<<6to4>>> + +WARNING: malicious party can abuse 6to4 relay routers/sites, read through +internet draft draft-itojun-ipv6-transition-abuse-xx.txt before configuring it. + +"stf" interface enables you to perform 6to4 IPv6-over-IPv4 encapsulation, +as documented in draft-ietf-ngtrans-6to4-06.txt. See stf(4) for details. + + <<<inetd>>> Inetd supports AF_INET and AF_INET6 sockets, with IPsec policy @@ -368,17 +385,18 @@ configuration support. Refer to inetd(8) for more details. + <<<IPsec>>> -The current KAME supports both transport mode and tunnel mode. -However, tunnel mode comes with some restrictions. -http://www.kame.net/newsletter/ has more comprehensive examples. +IPsec requires fairly complex configuration, so here we show transport +mode only. http://www.kame.net/newsletter/ has more comprehensive +examples. -Let's setup security association to deploy a secure channel between +Let us setup security association to deploy a secure channel between HOST A (10.2.3.4) and HOST B (10.6.7.8). Here we show a little complicated example. From HOST A to HOST B, only old AH is used. From HOST B to HOST A, new AH and new ESP are combined. - + Now we should choose algorithm to be used corresponding to "AH"/"new AH"/"ESP"/"new ESP". Please refer to the "setkey" man page to know algorithm names. Our choice is MD5 for AH, new-HMAC-SHA1 for new AH, @@ -389,7 +407,7 @@ length must be equal to 16 bytes for MD5, 20 for new-HMAC-SHA1, and 8 for new-DES-expIV. Now we choose "MYSECRETMYSECRET", "KAMEKAMEKAMEKAMEKAME", "PASSWORD", respectively. -OK, let's assign SPI (Security Parameter Index) for each protocol. +OK, let us assign SPI (Security Parameter Index) for each protocol. Please note that we need 3 SPIs for this secure channel since three security headers are produced (one for from HOST A to HOST B, two for from HOST B to HOST A). Please also note that SPI MUST be greater @@ -407,7 +425,7 @@ than or equal to 256. We choose, 1000, 2000, and 3000, respectively. (2.1) HOST A <------ HOST B <------ - (2.2) + (2.2) (2.1) PROTO=AH @@ -422,7 +440,7 @@ than or equal to 256. We choose, 1000, 2000, and 3000, respectively. KEY=PASSWORD SPI=3000 -Now, let's setup security association. Execute "setkey" on both HOST +Now, let us setup security association. Execute "setkey" on both HOST A and B: # setkey -c @@ -442,9 +460,8 @@ spdadd 10.2.3.4 10.6.7.8 any -P out ipsec At B: spdadd 10.6.7.8 10.2.3.4 any -P out ipsec - esp/transport/10.6.7.8-10.2.3.4/require ; -spdadd 10.6.7.8 10.2.3.4 any -P out ipsec - ah/transport/10.6.7.8-10.2.3.4/require ; + esp/transport//require + ah/transport//require ; ^D To utilize the security associations installed into the kernel, you @@ -454,7 +471,7 @@ the "ping" command has the -P option with parameter to enable AH and/or ESP. For example: % ping -P "out ipsec \ - ah/transport/10.0.1.1-10.0.2.2/use \ + ah/transport//use \ esp/tunnel/10.0.1.1-10.0.1.2/require" 10.0.2.2 If there are proper SAs, this policy specification causes ICMP packet @@ -467,165 +484,6 @@ to be AH transport mode inner ESP tunnel mode like below. ==================== AH ================== - -Another example using IPv6. - -ESP transport mode is recommended for TCP port number 110 between Host-A and -Host-B. - - ============ ESP ============ - | | - Host-A Host-B - fec0::10 -------------------- fec0::11 - -Encryption algorithm is blowfish-cbc whose key is "kamekame", and -authentication algorithm is hmac-sha1 whose key is "this is the test key". -Configuration at Host-A: - - # setkey -c <<EOF - 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" ; - EOF - -and at Host-B: - - # setkey -c <<EOF - spdadd fec0::11[110] fec0::10[any] tcp -P out ipsec - esp/transport/fec0::11-fec0::10/use ; - spdadd fec0::10[any] fec0::11[110] tcp -P in ipsec - esp/transport/fec0::10-fec0::11/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" ; - EOF - -Note the direction of SP. - - -Tunnel mode between two security gateways - -Security protocol is old AH tunnel mode, i.e. specified by RFC1826, with -keyed-md5 whose key is "this is the test" as authentication algorithm. - - ======= 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 - -Configuration at Gateway-A: - - # setkey -c <<EOF - 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 wild-card of mode of -security protocol. You can use this SA for both tunnel and transport mode. - -and at Gateway-B: - - # setkey -c <<EOF - 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 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" ; - - -Making SA bundle between two security gateways - -AH transport mode and ESP tunnel mode is required between Gateway-A and -Gateway-B. In this case, ESP tunnel mode is applied first, and AH transport -mode is next. - - ========== 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 - -Encryption algorithm is 3des-cbc, and authentication algorithm for ESP is -hmac-sha1. Authentication algorithm for AH is hmac-md5. -Configuration at Gateway-A: - - # setkey -c <<EOF - 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" ; - - -Making SAs with the different end - -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 - -Configuration at Host-A: - - # setkey -c <<EOF - 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:l::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" ; - <<<EDNS0>>> EDNS0 is defined in RFC2671. With EDNS0, the resolver library can tell DNS @@ -660,4 +518,12 @@ Caveats: - Some of our platforms do not use our extended resolver code in libinet6. See COVERAGE for detail. + +<<Further readings>> + +http://www.netbsd.org/Documentation/network/ipv6/ + Even if you are on non-netbsd operating system, the URL should be + useful. +http://www.kame.net/ + <end of USAGE> diff --git a/share/man/man4/faith.4 b/share/man/man4/faith.4 index 4ecc609..c87563c 100644 --- a/share/man/man4/faith.4 +++ b/share/man/man4/faith.4 @@ -1,3 +1,5 @@ +.\" $KAME: faith.4,v 1.9 2001/04/27 17:26:35 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" @@ -25,7 +27,6 @@ .\" 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 @@ -33,33 +34,31 @@ .Os .Sh NAME .Nm faith -.Nd -.Tn IPv6-to-IPv4 TCP -relay capturing interface +.Nd IPv6-to-IPv4 TCP relay capturing interface .Sh SYNOPSIS -.Cd "device faith 1" +.Cd "device faith" Op Ar count .Sh DESCRIPTION The .Nm -interface captures IPv6 TCP traffic -for implementing userland IPv6-to-IPv4 TCP relays +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 the routing table suggests to route it to the +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 the list of IPv6 interface addresses assigned to the router. -The packet will be captured by an IPv6 TCP socket if it has the +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. -As a result, +In result, .Nm -will let you divert IPv6 TCP traffic to some specific destination addresses. +will let you capture IPv6 TCP traffic to some specific destination addresses. Userland programs, such as -.Xr faithd 8 , +.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 2 @@ -68,33 +67,29 @@ and perform application-specific address mapping to relay IPv6 TCP to IPv4 TCP. .Pp The .Dv IN6P_FAITH -flag on an IPv6 TCP socket can be set by using +flag on IPv6 TCP socket can be set by using .Xr setsockopt 2 , -with -.Fa level -set to +with level equals to .Dv IPPROTO_IPV6 -and -.Fa optname -set to +and optname equals to .Dv IPv6_FAITH . .Pp -To handle error reports by ICMPv6 some of the ICMPv6 packets routed to the +To handle error reports by ICMPv6, some of ICMPv6 packets routed to .Nm -interface will need be delivered to IPv6 TCP as well. +interface will be delivered to IPv6 TCP, as well. .Pp To understand how .Nm -can be used take a look at the source code of +can be used, take a look at source code of .Xr faithd 8 . .Pp -As the +As .Nm -interface implements potentially dangerous operations, -great care must be taken when configuring the +interface implements potentially dangerous operation, +great care must be taken when configuring .Nm interface. -To avoid possible misuse the +To avoid possible misuse, .Xr sysctl 8 variable .Li net.inet6.ip6.keepfaith @@ -103,13 +98,12 @@ must be set to prior to the use of the interface. When .Li net.inet6.ip6.keepfaith -is set to +is .Li 0 , -no packets will be captured by the +no packet will be captured by .Nm interface. .Pp -The .Nm interface is intended to be used on routers, not on hosts. .\" @@ -117,13 +111,14 @@ interface is intended to be used on routers, not on hosts. .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 -.\" +.Rs +.%A Jun-ichiro itojun Hagino +.%A Kazu Yamamoto +.%T "An IPv6-to-IPv4 transport relay translator" +.%R internet draft +.%N draft-ietf-ngtrans-tcpudp-relay-04.txt +.%O work in progress material +.Re .Sh HISTORY -The FAITH IPv6-to-IPv4 TCP relay translator first appeared in +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 index a9cba1e..2d25c69 100644 --- a/share/man/man4/gif.4 +++ b/share/man/man4/gif.4 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: gif.4,v 1.17 2000/06/30 18:31:27 itojun Exp $ +.\" $KAME: gif.4,v 1.28 2001/05/18 13:15:56 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -44,7 +44,11 @@ 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. +is mainly based on RFC2893 IPv6-over-IPv4 configured tunnel. +On +.Nx , +.Nm +can also tunnel ISO traffic over IPv[46] using EON encapsulation. .Pp To use .Nm , @@ -70,79 +74,9 @@ Finally, use routing table to route the packets toward 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 Li 0.0.0.0 -or IPv6 unspecified address -.Pq Li 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 -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 @@ -155,7 +89,7 @@ interface flag. Without .Dv IFF_LINK1 , .Nm -will show a normal behavior, like described in RFC1933. +will show a normal behavior, like described in RFC2893. This can be summarized as follows: .Bl -tag -width "Ingress" -offset indent .It Ingress @@ -194,7 +128,7 @@ If outer ECN CE bit is enable ECN CE bit on the inner. .El .Pp -Note that the ECN friendly behavior violates RFC1933. +Note that the ECN friendly behavior violates RFC2893. This should be used in mutual agreement with the peer. .Pp .Ss Security @@ -206,10 +140,9 @@ performs martian filter and ingress filter against outer source address, on egress. Note that martian/ingress filters are no way complete. You may want to secure your node by using packet filters. -.Pp -As mentioned above, multi-destination mode -.Pq Dv IFF_LINK0 -is far less secure than bidirectional mode. +Ingress filter can be turned off by +.Dv IFF_LINK2 +bit. .\" .Sh SEE ALSO .Xr inet 4 , @@ -218,10 +151,10 @@ is far less secure than bidirectional mode. .Rs .%A R. Gilligan .%A E. Nordmark -.%B RFC1933 +.%B RFC2893 .%T Transition Mechanisms for IPv6 Hosts and Routers -.%D April 1996 -.%O ftp://ftp.isi.edu/in-notes/rfc1933.txt +.%D August 2000 +.%O ftp://ftp.isi.edu/in-notes/rfc2893.txt .Re .Rs .%A Sally Floyd @@ -256,7 +189,24 @@ Make sure to configure an address which belongs to your node. Otherwise, your node will not be able to receive packets from the peer, and your node will generate packets with a spoofed source address. .Pp -.Xr gif 4 -is an -.Dv IFF_POINTOPOINT -device, however, it supports NBMA behavior in multi-destination mode. +If the outer protocol is IPv4, +.Nm +does not try to perform path MTU discovery for the encapsulated packet +.Pq DF bit is set to 0 . +.Pp +If the outer protocol is IPv6, path MTU discovery for encapsulated packet +may affect communication over the interface. +The first bigger-than-pmtu packet may be lost. +To avoid the problem, you may want to set the interface MTU for +.Nm +to 1240 or smaller, when outer header is IPv6 and inner header is IPv4. +.Pp +.Nm +does not translate ICMP messages for outer header into inner header. +.Pp +In the past, +.Nm +had a multi-destination behavior, configurable via +.Dv IFF_LINK0 +flag. +The behavior was obsoleted and is no longer supported. diff --git a/share/man/man4/inet6.4 b/share/man/man4/inet6.4 index 3ba609e..62607ec 100644 --- a/share/man/man4/inet6.4 +++ b/share/man/man4/inet6.4 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: inet6.4,v 1.16 2000/07/05 08:18:42 itojun Exp $ +.\" $KAME: inet6.4,v 1.21 2001/04/05 01:00:18 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -74,7 +74,7 @@ as a discriminated union. .Pp Sockets bound to the .Nm -family utilize the following addressing structure, +family utilize the following addressing structure: .Bd -literal -offset indent struct sockaddr_in6 { u_int8_t sin6_len; @@ -95,34 +95,21 @@ which is equal to IPv6 address 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 specification defines scoped address, -like link-local or site-local address. +The IPv6 specification defines scoped addresses, +like link-local or site-local addresses. A scoped address is ambiguous to the kernel, -if it is specified without scope identifier. +if it is specified without a scope identifier. To manipulate scoped addresses properly from the userland, -programs must use advanced API defined in RFC2292. -Compact description on the advanced API is available in +programs must use the advanced API defined in RFC2292. +A compact description of the advanced API is available in .Xr ip6 4 . -If scoped addresses are specified without explicit scope, -the kernel may raise error. +If a scoped address is specified without an explicit scope, +the kernel may raise an error. Note that scoped addresses are not for daily use at this moment, -both from specification and implementation point of view. +both from a specification and an implementation point of view. .Pp -KAME implementation supports extended numeric IPv6 address notation +The KAME implementation supports an extended numeric IPv6 address notation for link-local addresses, like .Dq Li fe80::1%de0 @@ -133,7 +120,7 @@ on .Li de0 interface .Dc . -The notation is supported by +This notation is supported by .Xr getaddrinfo 3 and .Xr getnameinfo 3 . @@ -141,23 +128,23 @@ Some of normal userland programs, such as .Xr telnet 1 or .Xr ftp 1 , -are able to use the notation. +are able to use this notation. With special programs like .Xr ping6 8 , -you can specify outgoing interface by extra command line option +you can specify the outgoing interface by an extra command line option to disambiguate scoped addresses. .Pp Scoped addresses are handled specially in the kernel. -In the kernel structures like routing tables or interface structure, -scoped addresses will have its interface index embedded into the address. +In kernel structures like routing tables or interface structures, +a scoped address will have its interface index embedded into the address. Therefore, -the address on some of the kernel structure is not the same as that on the wire. -The embedded index will become visible on +the address in some kernel structures is not the same as that on the wire. +The embedded index will become visible through a .Dv PF_ROUTE socket, kernel memory accesses via .Xr kvm 3 -and some other occasions. +and on some other occasions. HOWEVER, users should never use the embedded form. For details please consult .Pa IMPLEMENTATION @@ -431,20 +418,20 @@ which initiates dynamic adaptation (default 128). The behavior of .Dv AF_INET6 TCP/UDP socket is documented in RFC2553. -Basically, it says as follows: +Basically, it says this: .Bl -bullet -compact .It -Specific bind on +A specific bind on an .Dv AF_INET6 socket .Po .Xr bind 2 -with address specified +with an address specified .Pc should accept IPv6 traffic to that address only. .It -If you perform wildcard bind -on +If you perform a wildcard bind +on an .Dv AF_INET6 socket .Po @@ -458,33 +445,33 @@ socket on that TCP/UDP port, IPv6 traffic as well as IPv4 traffic should be routed to that .Dv AF_INET6 socket. -IPv4 traffic should be seen as if it came from IPv6 address like +IPv4 traffic should be seen as if it came from an IPv6 address like .Li ::ffff:10.1.1.1 . -This is called IPv4 mapped address. +This is called an IPv4 mapped address. .It -If there are both wildcard bind +If there are both a wildcard bind .Dv AF_INET -socket and wildcard bind +socket and a wildcard bind .Dv AF_INET6 socket on one TCP/UDP port, they should behave separately. -IPv4 traffic should be routed to +IPv4 traffic should be routed to the .Dv AF_INET -socket and IPv6 should be routed to +socket and IPv6 should be routed to the .Dv AF_INET6 socket. .El .Pp -However, RFC2553 does not define the constraint between the order of +However, RFC2553 does not define the ordering constraint between calls to .Xr bind 2 , -nor how IPv4 TCP/UDP port number and IPv6 TCP/UDP port number -relate each other +nor how IPv4 TCP/UDP port numbers and IPv6 TCP/UDP port numbers +relate to each other .Po should they be integrated or separated .Pc . -Implemented behavior is very different across kernel to kernel. +Implemented behavior is very different from kernel to kernel. Therefore, it is unwise to rely too much upon the behavior of .Dv AF_INET6 -wildcard bind socket. +wildcard bind sockets. It is recommended to listen to two sockets, one for .Dv AF_INET and another for @@ -497,7 +484,7 @@ and are able to bypass access control, if the target node routes IPv4 traffic to .Dv AF_INET6 socket. -Users are advised to take caution handling connections +Users are advised to take care handling connections from IPv4 mapped address to .Dv AF_INET6 sockets. @@ -506,7 +493,7 @@ sockets. .\"KAME/NetBSD and KAME/OpenBSD .\"does not route IPv4 traffic to .\".Dv AF_INET6 -.\"socket. +.\"sockets. .\"Listen to two sockets if you want to accept both IPv4 and IPv6 traffic. .\"On KAME/NetBSD, IPv4 traffic may be routed with certain .\"per-socket/per-node configuration, however, it is not recommended. @@ -536,8 +523,8 @@ sockets. .Sh HISTORY The .Nm -protocol interface are defined in RFC2553 and RFC2292. -The implementation described herein appeared in WIDE/KAME project. +protocol interfaces are defined in RFC2553 and RFC2292. +The implementation described herein appeared in the WIDE/KAME project. .Sh BUGS The IPv6 support is subject to change as the Internet protocols develop. Users should not depend on details of the current implementation, diff --git a/share/man/man4/ip6.4 b/share/man/man4/ip6.4 index 920753e..9cd5631 100644 --- a/share/man/man4/ip6.4 +++ b/share/man/man4/ip6.4 @@ -1,6 +1,8 @@ +.\" $KAME: ip6.4,v 1.14 2001/02/26 09:31:39 itojun Exp $ +.\" .\" Copyright (C) 1999 WIDE Project. .\" All rights reserved. -.\" +.\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -12,7 +14,7 @@ .\" 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 @@ -56,7 +58,6 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" KAME $Id: ip6.4,v 1.7 2000/01/06 06:00:30 itojun Exp $ .\" $FreeBSD$ .\" .Dd March 13, 2000 @@ -241,14 +242,14 @@ int range = IPV6_PORTRANGE_LOW; /* see <netinet/in.h> */ setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, &range, sizeof(range)); .Ed .Pp -.Dv IPV6_BINDV6ONLY +.Dv IPV6_V6ONLY controls behavior of .Dv AF_INET6 wildcard listening socket. The following example sets the option to 1: .Bd -literal -offset indent int on = 1; -setsockopt(s, IPPROTO_IPV6, IPV6_BINDV6ONLY, &on, sizeof(on)); +setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); .Ed .Pp If set to 1, @@ -258,21 +259,20 @@ If set to 0, it will accept IPv4 traffic as well, as if it was from IPv4 mapped address like .Li ::ffff:10.1.1.1 . .\" RFC2553 defines the behavior when the variable is set to 0. -Note that if you set this to 0, -you need to care IPv4 access control also on the AF_INET6 socket. +Note that if you set it this to 0, +IPv4 access control gets much more complicated. For example, even if you have no listening .Dv AF_INET listening socket on port .Li X , -you will be accepting IPv4 traffic by +you will end up accepting IPv4 traffic by .Dv AF_INET6 listening socket on the same port. -.\"(net.inet6.ip6.bindv6only is not implemented yet.) -.\"The default value for this flag is copied at socket instantiation time, -.\"from -.\".Li net.inet6.ip6.bindv6only -.\".Xr sysctl 3 -.\"variable. +The default value for this flag is copied at socket instantiation time, +from +.Li net.inet6.ip6.v6only +.Xr sysctl 3 +variable. The option affects .Tn TCP and @@ -344,7 +344,7 @@ and .Dv IPV6_DSTOPTS . Similarly, .Xr inet6_rthdr_space 3 -and friends will help you parse ancillary data items for +and friends will help you parse ancillary data items for .Dv IPV6_RTHDR . .Pp .Dv IPV6_HOPOPTS @@ -686,12 +686,14 @@ The ancillary data items were improperly formed, or option name was unknown. .Sh STANDARDS Most of the socket options are defined in RFC2292 and/or RFC2553. -.Dv IPV6_PORTRANGE , -.Dv IPV6_BINDV6ONLY +.Pp +.Dv IPV6_V6ONLY +socket option is defined in draft-ietf-ipngwg-rfc2553bis-03. +.Dv IPV6_PORTRANGE +socket option and conflict resolution rule are not defined in the RFCs and should be considered implementation dependent. -However, KAME/NetBSD also supports them. .\" .Sh HISTORY The implementation is based on KAME stack diff --git a/share/man/man4/ipsec.4 b/share/man/man4/ipsec.4 index f5a81df..d9502e6 100644 --- a/share/man/man4/ipsec.4 +++ b/share/man/man4/ipsec.4 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: ipsec.4,v 1.13 2000/06/15 04:08:54 itojun Exp $ +.\" $KAME: ipsec.4,v 1.15 2001/04/05 01:00:45 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -213,7 +213,7 @@ The variable configures the kernel behavior on IPv4 IPsec tunnel encapsulation. If set to 0, DF bit on the outer IPv4 header will be cleared. 1 means that the outer DF bit is set regardless from the inner DF bit. 2 means that the DF bit is copied from the inner header to the outer. -The variable is supplied to conform to RFC2403 chapter 6.1. +The variable is supplied to conform to RFC2401 chapter 6.1. .It Li ipsec.ecn If set to non-zero, IPv4 IPsec tunnel encapsulation/decapsulation behavior will be friendly to ECN diff --git a/share/man/man4/kame.4 b/share/man/man4/kame.4 index fa68201..5493779 100644 --- a/share/man/man4/kame.4 +++ b/share/man/man4/kame.4 @@ -148,6 +148,11 @@ You also can check out the IPv6 and IPsec chapters in the handbook. Also check latest status of project at web page: .Pa http://www.kame.net/ . +.Po +Hope you can see a +.Dq Dancing Turtle +.Li :-) +.Pc .\" .Ss APIs introduced or modified .Xr if_indextoname 3 , diff --git a/share/man/man4/stf.4 b/share/man/man4/stf.4 index fdac049..c5f05e3 100644 --- a/share/man/man4/stf.4 +++ b/share/man/man4/stf.4 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: stf.4,v 1.24 2000/06/07 23:35:18 itojun Exp $ +.\" $KAME: stf.4,v 1.35 2001/05/02 06:24:49 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 6, 2000 +.Dd April 27, 2001 .Dt STF 4 .Os .Sh NAME @@ -45,7 +45,7 @@ interface supports .Dq 6to4 IPv6 in IPv4 encapsulation. It can tunnel IPv6 traffic over IPv4, as specified in -.Li draft-ietf-ngtrans-6to4-06.txt . +.Li RFC3056 . .Pp For ordinary nodes in 6to4 site, you do not need .Nm @@ -142,6 +142,9 @@ all of the directly connected subnets. .It Packets that does not pass ingress filtering. Outer IPv4 source address must meet the IPv4 topology on the routing table. +Ingress filter can be turned off by +.Dv IFF_LINK2 +bit. .It The same set of rules are appplied against the IPv4 address embedded into inner IPv6 address, if the IPv6 address matches 6to4 prefix. @@ -152,6 +155,16 @@ incoming IPv4 packet with IP protocol number 41, as necessary. It is also recommended to filter/audit encapsulated IPv6 packets as well. You may also want to run normal ingress filter against inner IPv6 address to avoid spoofing. +.Pp +By setting the +.Dv IFF_LINK0 +flag on the +.Nm +interface, it is possible to disable the input path, +making the direct attacks from the outside impossible. +Note, however, there are other security risks exist. +If you wish to use the configuration, +you must not advertise your 6to4 address to others. .\" .Sh EXAMPLES Note that @@ -175,28 +188,65 @@ It emits 6to4 packet only for IPv6 destination 2002:0901::/32 # ifconfig stf0 inet6 2002:0901:0203:0000:a00:5aff:fe38:6f86 \\ prefixlen 32 alias .Ed +.Pp +The following configuration uses the +.Nm +interface as an output-only device. +You need to have alternative IPv6 connectivity +.Pq other than 6to4 +to use this configuration. +For outbound traffic, you can reach other 6to4 networks efficiently via +.Nm stf . +For inbound traffic, you will not receive any 6to4-tunneled packets +.Pq less security drawbacks . +Be careful not to advertise your 6to4 prefix to others +.Pq Li 2002:8504:0506::/48 , +and not to use your 6to4 prefix as a source. +.Bd -literal +# ifconfig ne0 inet 133.4.5.6 netmask 0xffffff00 +# ifconfig stf0 inet6 2002:8504:0506:0000:a00:5aff:fe38:6f86 \\ + prefixlen 16 alias deprecated link0 +# route add -inet6 2002:: -prefixlen 16 ::1 +# route change -inet6 2002:: -prefixlen 16 ::1 -ifp stf0 +.Ed .\" .Sh SEE ALSO .Xr gif 4 , .Xr inet 4 , .Xr inet6 4 +.Pp +.Pa http://www.6bone.net/6bone_6to4.html .Rs .%A Brian Carpenter .%A Keith Moore -.%T "Connection of IPv6 Domains via IPv4 Clouds without Explicit Tunnels" -.%D June 2000 -.%N draft-ietf-ngtrans-6to4-06.txt -.%O work in progress +.%T "Connection of IPv6 Domains via IPv4 Clouds" +.%D February 2001 +.%R RFC +.%N 3056 .Re .Rs .%A Jun-ichiro itojun Hagino .%T "Possible abuse against IPv6 transition technologies" -.%D March 2000 -.%N draft-itojun-ipv6-transition-abuse-00.txt -.%O work in progress, http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt +.%D July 2000 +.%N draft-itojun-ipv6-transition-abuse-01.txt +.%O work in progress .Re .\" .Sh HISTORY The .Nm device first appeared in WIDE/KAME IPv6 stack. +.\" +.Sh BUGS +No more than one +.Nm +interface is allowed for a node, +and no more than one IPv6 interface address is allowed for an +.Nm +interface. +It is to avoid source address selection conflicts +between IPv6 layer and IPv4 layer, +and to cope with ingress filtering rule on the other side. +This is a feature to make +.Nm +work right for all occasions. diff --git a/sys/conf/files b/sys/conf/files index cb6a4a2..d39e829 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -163,19 +163,15 @@ contrib/ipfilter/netinet/ip_nat.c optional ipfilter inet contrib/ipfilter/netinet/ip_proxy.c optional ipfilter inet contrib/ipfilter/netinet/ip_state.c optional ipfilter inet contrib/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet -crypto/blowfish/bf_cbc.c optional ipsec ipsec_esp -crypto/blowfish/bf_cbc_m.c optional ipsec ipsec_esp crypto/blowfish/bf_enc.c optional ipsec ipsec_esp crypto/blowfish/bf_skey.c optional ipsec ipsec_esp crypto/cast128/cast128.c optional ipsec ipsec_esp -crypto/cast128/cast128_cbc.c optional ipsec ipsec_esp -crypto/des/des_3cbc.c optional ipsec ipsec_esp -crypto/des/des_cbc.c optional ipsec ipsec_esp crypto/des/des_ecb.c optional ipsec ipsec_esp crypto/des/des_setkey.c optional ipsec ipsec_esp -crypto/rc5/rc5.c optional ipsec ipsec_esp -crypto/rc5/rc5_cbc.c optional ipsec ipsec_esp +crypto/rijndael/rijndael-alg-fst.c optional ipsec ipsec_esp +crypto/rijndael/rijndael-api-fst.c optional ipsec ipsec_esp crypto/sha1.c optional ipsec +crypto/sha2/sha2.c optional ipsec ddb/db_access.c optional ddb ddb/db_break.c optional ddb ddb/db_command.c optional ddb @@ -1083,6 +1079,7 @@ netinet6/dest6.c optional inet6 netinet6/esp_core.c optional ipsec ipsec_esp netinet6/esp_input.c optional ipsec ipsec_esp netinet6/esp_output.c optional ipsec ipsec_esp +netinet6/esp_rijndael.c optional ipsec ipsec_esp netinet6/frag6.c optional inet6 netinet6/icmp6.c optional inet6 netinet6/in6.c optional inet6 @@ -1124,8 +1121,8 @@ netipx/ipx_usrreq.c optional ipx netipx/spx_debug.c optional ipx netipx/spx_usrreq.c optional ipx netkey/key.c optional ipsec -netkey/keydb.c optional ipsec netkey/key_debug.c optional ipsec +netkey/keydb.c optional ipsec netkey/keysock.c optional ipsec netnatm/natm.c optional natm netnatm/natm_pcb.c optional natm diff --git a/sys/crypto/blowfish/bf_cbc.c b/sys/crypto/blowfish/bf_cbc.c deleted file mode 100644 index 6eb6d3b..0000000 --- a/sys/crypto/blowfish/bf_cbc.c +++ /dev/null @@ -1,151 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: bf_cbc.c,v 1.3 2000/03/27 04:36:25 sumikawa Exp $ */ - -/* crypto/bf/bf_cbc.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@mincom.oz.au). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * 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 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 cryptographic software written by - * Eric Young (eay@mincom.oz.au)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 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. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include <crypto/blowfish/blowfish.h> -#include <crypto/blowfish/bf_locl.h> - -void BF_cbc_encrypt(in, out, length, ks, iv, encrypt) -unsigned char *in; -unsigned char *out; -long length; -BF_KEY *ks; -unsigned char *iv; -int encrypt; - { - register BF_LONG tin0,tin1; - register BF_LONG tout0,tout1,xor0,xor1; - register long l=length; - BF_LONG tin[2]; - - if (encrypt) - { - n2l(iv,tout0); - n2l(iv,tout1); - iv-=8; - for (l-=8; l>=0; l-=8) - { - n2l(in,tin0); - n2l(in,tin1); - tin0^=tout0; - tin1^=tout1; - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_ENCRYPT); - tout0=tin[0]; - tout1=tin[1]; - l2n(tout0,out); - l2n(tout1,out); - } - if (l != -8) - { - n2ln(in,tin0,tin1,l+8); - tin0^=tout0; - tin1^=tout1; - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_ENCRYPT); - tout0=tin[0]; - tout1=tin[1]; - l2n(tout0,out); - l2n(tout1,out); - } - l2n(tout0,iv); - l2n(tout1,iv); - } - else - { - n2l(iv,xor0); - n2l(iv,xor1); - iv-=8; - for (l-=8; l>=0; l-=8) - { - n2l(in,tin0); - n2l(in,tin1); - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_DECRYPT); - tout0=tin[0]^xor0; - tout1=tin[1]^xor1; - l2n(tout0,out); - l2n(tout1,out); - xor0=tin0; - xor1=tin1; - } - if (l != -8) - { - n2l(in,tin0); - n2l(in,tin1); - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_DECRYPT); - tout0=tin[0]^xor0; - tout1=tin[1]^xor1; - l2nn(tout0,tout1,out,l+8); - xor0=tin0; - xor1=tin1; - } - l2n(xor0,iv); - l2n(xor1,iv); - } - tin0=tin1=tout0=tout1=xor0=xor1=0; - tin[0]=tin[1]=0; - } - diff --git a/sys/crypto/blowfish/bf_cbc_m.c b/sys/crypto/blowfish/bf_cbc_m.c deleted file mode 100644 index 088adad..0000000 --- a/sys/crypto/blowfish/bf_cbc_m.c +++ /dev/null @@ -1,343 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: bf_cbc_m.c,v 1.4 2000/06/14 10:41:16 itojun Exp $ */ - -/* - * heavily modified to accept mbuf, by Jun-ichiro itojun Itoh - * <itojun@itojun.org>, 1997. - */ -/* crypto/bf/bf_cbc.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@mincom.oz.au). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * 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 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 cryptographic software written by - * Eric Young (eay@mincom.oz.au)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 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. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include <sys/param.h> -#include <sys/mbuf.h> -#include <sys/systm.h> - -#include <crypto/blowfish/blowfish.h> -#include <crypto/blowfish/bf_locl.h> - -#define panic(x) do { printf(x); return EINVAL; } while (0) - -int BF_cbc_encrypt_m(m0, skip, length, key, iv, mode) - struct mbuf *m0; - int skip; - int length; - BF_KEY *key; - unsigned char *iv; - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - register BF_LONG tin0, tin1; - register BF_LONG tout0, tout1; - BF_LONG tin[2]; - - /* sanity checks */ - if (m0->m_pkthdr.len < skip) { - printf("mbuf length < skip\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < length) { - printf("mbuf length < encrypt length\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - printf("mbuf length < skip + encrypt length\n"); - return EINVAL; - } - if (length % 8) { - printf("length is not multiple of 8\n"); - return EINVAL; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* initialize */ - tin0 = tin1 = tout0 = tout1 = 0; - tin[0] = tin[1] = 0; - - if (mode == BF_ENCRYPT) { - u_int8_t *in, *out; - - n2l(iv, tout0); - n2l(iv, tout1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - n2l(in, tin0); - n2l(in, tin1); - - tin0 ^= tout0; tin[0] = tin0; - tin1 ^= tout1; tin[1] = tin1; - BF_encrypt(tin, key, BF_ENCRYPT); - tout0 = tin[0]; l2n(tout0, out); - tout1 = tin[1]; l2n(tout1, out); - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } else if (mode == BF_DECRYPT) { - register BF_LONG xor0, xor1; - u_int8_t *in, *out; - - xor0 = xor1 = 0; - n2l(iv, xor0); - n2l(iv, xor1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - n2l(in, tin0); tin[0] = tin0; - n2l(in, tin1); tin[1] = tin1; - BF_encrypt(tin, key, BF_DECRYPT); - tout0 = tin[0] ^ xor0; - tout1 = tin[1] ^ xor1; - l2n(tout0, out); - l2n(tout1, out); - xor0 = tin0; - xor1 = tin1; - - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } - - return 0; -} diff --git a/sys/crypto/blowfish/bf_enc.c b/sys/crypto/blowfish/bf_enc.c index 6a3bef6..5edd6db 100644 --- a/sys/crypto/blowfish/bf_enc.c +++ b/sys/crypto/blowfish/bf_enc.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: bf_enc.c,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */ +/* $KAME: bf_enc.c,v 1.5 2000/09/18 21:21:19 itojun Exp $ */ /* crypto/bf/bf_enc.c */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) @@ -59,6 +59,7 @@ * [including the GNU Public Licence.] */ +#include <sys/types.h> #include <crypto/blowfish/blowfish.h> #include <crypto/blowfish/bf_locl.h> @@ -72,72 +73,71 @@ If you set BF_ROUNDS to some value other than 16 or 20, you will have to modify the code. #endif -void BF_encrypt(data,key,encrypt) -BF_LONG *data; -BF_KEY *key; -int encrypt; - { - register BF_LONG l,r,*p,*s; +/* XXX "data" is host endian */ +void +BF_encrypt(data, key, encrypt) + BF_LONG *data; + BF_KEY *key; + int encrypt; +{ + register BF_LONG l, r, *p, *s; - p=key->P; - s= &(key->S[0]); - l=data[0]; - r=data[1]; + p = key->P; + s= &key->S[0]; + l = data[0]; + r = data[1]; - if (encrypt) - { + if (encrypt) { l^=p[0]; - BF_ENC(r,l,s,p[ 1]); - BF_ENC(l,r,s,p[ 2]); - BF_ENC(r,l,s,p[ 3]); - BF_ENC(l,r,s,p[ 4]); - BF_ENC(r,l,s,p[ 5]); - BF_ENC(l,r,s,p[ 6]); - BF_ENC(r,l,s,p[ 7]); - BF_ENC(l,r,s,p[ 8]); - BF_ENC(r,l,s,p[ 9]); - BF_ENC(l,r,s,p[10]); - BF_ENC(r,l,s,p[11]); - BF_ENC(l,r,s,p[12]); - BF_ENC(r,l,s,p[13]); - BF_ENC(l,r,s,p[14]); - BF_ENC(r,l,s,p[15]); - BF_ENC(l,r,s,p[16]); + BF_ENC(r, l, s, p[ 1]); + BF_ENC(l, r, s, p[ 2]); + BF_ENC(r, l, s, p[ 3]); + BF_ENC(l, r, s, p[ 4]); + BF_ENC(r, l, s, p[ 5]); + BF_ENC(l, r, s, p[ 6]); + BF_ENC(r, l, s, p[ 7]); + BF_ENC(l, r, s, p[ 8]); + BF_ENC(r, l, s, p[ 9]); + BF_ENC(l, r, s, p[10]); + BF_ENC(r, l, s, p[11]); + BF_ENC(l, r, s, p[12]); + BF_ENC(r, l, s, p[13]); + BF_ENC(l, r, s, p[14]); + BF_ENC(r, l, s, p[15]); + BF_ENC(l, r, s, p[16]); #if BF_ROUNDS == 20 - BF_ENC(r,l,s,p[17]); - BF_ENC(l,r,s,p[18]); - BF_ENC(r,l,s,p[19]); - BF_ENC(l,r,s,p[20]); + BF_ENC(r, l, s, p[17]); + BF_ENC(l, r, s, p[18]); + BF_ENC(r, l, s, p[19]); + BF_ENC(l, r, s, p[20]); #endif - r^=p[BF_ROUNDS+1]; - } - else - { - l^=p[BF_ROUNDS+1]; + r ^= p[BF_ROUNDS + 1]; + } else { + l ^= p[BF_ROUNDS + 1]; #if BF_ROUNDS == 20 - BF_ENC(r,l,s,p[20]); - BF_ENC(l,r,s,p[19]); - BF_ENC(r,l,s,p[18]); - BF_ENC(l,r,s,p[17]); + BF_ENC(r, l, s, p[20]); + BF_ENC(l, r, s, p[19]); + BF_ENC(r, l, s, p[18]); + BF_ENC(l, r, s, p[17]); #endif - BF_ENC(r,l,s,p[16]); - BF_ENC(l,r,s,p[15]); - BF_ENC(r,l,s,p[14]); - BF_ENC(l,r,s,p[13]); - BF_ENC(r,l,s,p[12]); - BF_ENC(l,r,s,p[11]); - BF_ENC(r,l,s,p[10]); - BF_ENC(l,r,s,p[ 9]); - BF_ENC(r,l,s,p[ 8]); - BF_ENC(l,r,s,p[ 7]); - BF_ENC(r,l,s,p[ 6]); - BF_ENC(l,r,s,p[ 5]); - BF_ENC(r,l,s,p[ 4]); - BF_ENC(l,r,s,p[ 3]); - BF_ENC(r,l,s,p[ 2]); - BF_ENC(l,r,s,p[ 1]); - r^=p[0]; - } - data[1]=l&0xffffffff; - data[0]=r&0xffffffff; + BF_ENC(r, l, s, p[16]); + BF_ENC(l, r, s, p[15]); + BF_ENC(r, l, s, p[14]); + BF_ENC(l, r, s, p[13]); + BF_ENC(r, l, s, p[12]); + BF_ENC(l, r, s, p[11]); + BF_ENC(r, l, s, p[10]); + BF_ENC(l, r, s, p[ 9]); + BF_ENC(r, l, s, p[ 8]); + BF_ENC(l, r, s, p[ 7]); + BF_ENC(r, l, s, p[ 6]); + BF_ENC(l, r, s, p[ 5]); + BF_ENC(r, l, s, p[ 4]); + BF_ENC(l, r, s, p[ 3]); + BF_ENC(r, l, s, p[ 2]); + BF_ENC(l, r, s, p[ 1]); + r ^= p[0]; } + data[1] = l & 0xffffffff; + data[0] = r & 0xffffffff; +} diff --git a/sys/crypto/blowfish/bf_locl.h b/sys/crypto/blowfish/bf_locl.h index 07598d2..52585bb 100644 --- a/sys/crypto/blowfish/bf_locl.h +++ b/sys/crypto/blowfish/bf_locl.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: bf_locl.h,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */ +/* $KAME: bf_locl.h,v 1.5 2000/08/31 06:03:48 itojun Exp $ */ /* crypto/bf/bf_local.h */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) @@ -67,10 +67,10 @@ */ #undef c2l -#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \ - l|=((unsigned long)(*((c)++)))<< 8L, \ - l|=((unsigned long)(*((c)++)))<<16L, \ - l|=((unsigned long)(*((c)++)))<<24L) +#define c2l(c,l) (l =((BF_LONG)(*((c)++))) , \ + l|=((BF_LONG)(*((c)++)))<< 8L, \ + l|=((BF_LONG)(*((c)++)))<<16L, \ + l|=((BF_LONG)(*((c)++)))<<24L) /* NOTE - c is not incremented as per c2l */ #undef c2ln @@ -78,14 +78,14 @@ c+=n; \ l1=l2=0; \ switch (n) { \ - case 8: l2 =((unsigned long)(*(--(c))))<<24L; \ - case 7: l2|=((unsigned long)(*(--(c))))<<16L; \ - case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \ - case 5: l2|=((unsigned long)(*(--(c)))); \ - case 4: l1 =((unsigned long)(*(--(c))))<<24L; \ - case 3: l1|=((unsigned long)(*(--(c))))<<16L; \ - case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \ - case 1: l1|=((unsigned long)(*(--(c)))); \ + case 8: l2 =((BF_LONG)(*(--(c))))<<24L; \ + case 7: l2|=((BF_LONG)(*(--(c))))<<16L; \ + case 6: l2|=((BF_LONG)(*(--(c))))<< 8L; \ + case 5: l2|=((BF_LONG)(*(--(c)))); \ + case 4: l1 =((BF_LONG)(*(--(c))))<<24L; \ + case 3: l1|=((BF_LONG)(*(--(c))))<<16L; \ + case 2: l1|=((BF_LONG)(*(--(c))))<< 8L; \ + case 1: l1|=((BF_LONG)(*(--(c)))); \ } \ } @@ -116,14 +116,14 @@ c+=n; \ l1=l2=0; \ switch (n) { \ - case 8: l2 =((unsigned long)(*(--(c)))) ; \ - case 7: l2|=((unsigned long)(*(--(c))))<< 8; \ - case 6: l2|=((unsigned long)(*(--(c))))<<16; \ - case 5: l2|=((unsigned long)(*(--(c))))<<24; \ - case 4: l1 =((unsigned long)(*(--(c)))) ; \ - case 3: l1|=((unsigned long)(*(--(c))))<< 8; \ - case 2: l1|=((unsigned long)(*(--(c))))<<16; \ - case 1: l1|=((unsigned long)(*(--(c))))<<24; \ + case 8: l2 =((BF_LONG)(*(--(c)))) ; \ + case 7: l2|=((BF_LONG)(*(--(c))))<< 8; \ + case 6: l2|=((BF_LONG)(*(--(c))))<<16; \ + case 5: l2|=((BF_LONG)(*(--(c))))<<24; \ + case 4: l1 =((BF_LONG)(*(--(c)))) ; \ + case 3: l1|=((BF_LONG)(*(--(c))))<< 8; \ + case 2: l1|=((BF_LONG)(*(--(c))))<<16; \ + case 1: l1|=((BF_LONG)(*(--(c))))<<24; \ } \ } @@ -143,10 +143,10 @@ } #undef n2l -#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \ - l|=((unsigned long)(*((c)++)))<<16L, \ - l|=((unsigned long)(*((c)++)))<< 8L, \ - l|=((unsigned long)(*((c)++)))) +#define n2l(c,l) (l =((BF_LONG)(*((c)++)))<<24L, \ + l|=((BF_LONG)(*((c)++)))<<16L, \ + l|=((BF_LONG)(*((c)++)))<< 8L, \ + l|=((BF_LONG)(*((c)++)))) #undef l2n #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ @@ -161,9 +161,17 @@ * BF_PTR for sparc and MIPS/SGI * use nothing for Alpha and HP. */ -#if !defined(BF_PTR) && !defined(BF_PTR2) -#undef BF_PTR +#undef BF_PTR +#undef BF_PTR2 +#ifdef __NetBSD__ +#ifdef __i386__ +#define BF_PTR2 +#else +#ifdef __mips__ +#define BF_PTR +#endif #endif +#endif /*NetBSD*/ #define BF_M 0x3fc #define BF_0 22L diff --git a/sys/crypto/blowfish/bf_skey.c b/sys/crypto/blowfish/bf_skey.c index 5717c3f..4bbe036 100644 --- a/sys/crypto/blowfish/bf_skey.c +++ b/sys/crypto/blowfish/bf_skey.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: bf_skey.c,v 1.3 2000/03/27 04:36:27 sumikawa Exp $ */ +/* $KAME: bf_skey.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */ /* crypto/bf/bf_skey.c */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) @@ -66,58 +66,55 @@ #include <crypto/blowfish/bf_locl.h> #include <crypto/blowfish/bf_pi.h> -void BF_set_key(key,len,data) -BF_KEY *key; -int len; -unsigned char *data; - { +void +BF_set_key(key, len, data) + BF_KEY *key; + int len; + unsigned char *data; +{ int i; - BF_LONG *p,ri,in[2]; - unsigned char *d,*end; + BF_LONG *p, ri, in[2]; + unsigned char *d, *end; + memcpy((char *)key, (char *)&bf_init, sizeof(BF_KEY)); + p = key->P; - memcpy((char *)key,(char *)&bf_init,sizeof(BF_KEY)); - p=key->P; + if (len > ((BF_ROUNDS + 2) * 4)) + len = (BF_ROUNDS + 2) * 4; - if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4; - - d=data; + d = data; end= &(data[len]); - for (i=0; i<(BF_ROUNDS+2); i++) - { - ri= *(d++); - if (d >= end) d=data; - - ri<<=8; - ri|= *(d++); - if (d >= end) d=data; + for (i = 0; i < BF_ROUNDS + 2; i++) { + ri = *(d++); + if (d >= end) d = data; - ri<<=8; - ri|= *(d++); - if (d >= end) d=data; + ri <<= 8; + ri |= *(d++); + if (d >= end) d = data; - ri<<=8; - ri|= *(d++); - if (d >= end) d=data; + ri <<= 8; + ri |= *(d++); + if (d >= end) d = data; - p[i]^=ri; - } + ri <<= 8; + ri |= *(d++); + if (d >= end) d = data; - in[0]=0L; - in[1]=0L; - for (i=0; i<(BF_ROUNDS+2); i+=2) - { - BF_encrypt(in,key,BF_ENCRYPT); - p[i ]=in[0]; - p[i+1]=in[1]; - } + p[i] ^= ri; + } - p=key->S; - for (i=0; i<4*256; i+=2) - { - BF_encrypt(in,key,BF_ENCRYPT); - p[i ]=in[0]; - p[i+1]=in[1]; - } + in[0] = 0L; + in[1] = 0L; + for (i = 0; i < BF_ROUNDS + 2; i += 2) { + BF_encrypt(in, key, BF_ENCRYPT); + p[i ] = in[0]; + p[i+1] = in[1]; } + p = key->S; + for (i = 0; i < 4 * 256; i += 2) { + BF_encrypt(in, key, BF_ENCRYPT); + p[i ] = in[0]; + p[i+1] = in[1]; + } +} diff --git a/sys/crypto/blowfish/blowfish.h b/sys/crypto/blowfish/blowfish.h index c96b4ec..76605f8 100644 --- a/sys/crypto/blowfish/blowfish.h +++ b/sys/crypto/blowfish/blowfish.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: blowfish.h,v 1.4 2000/06/14 10:41:16 itojun Exp $ */ +/* $KAME: blowfish.h,v 1.10 2000/09/18 21:21:20 itojun Exp $ */ /* crypto/bf/blowfish.h */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) @@ -69,54 +69,19 @@ extern "C" { #define BF_ENCRYPT 1 #define BF_DECRYPT 0 -/* If you make this 'unsigned int' the pointer variants will work on - * the Alpha, otherwise they will not. Strangly using the '8 byte' - * BF_LONG and the default 'non-pointer' inner loop is the best configuration - * for the Alpha */ -#define BF_LONG unsigned long +/* must be 32bit quantity */ +#define BF_LONG u_int32_t #define BF_ROUNDS 16 #define BF_BLOCK 8 -typedef struct bf_key_st - { +typedef struct bf_key_st { BF_LONG P[BF_ROUNDS+2]; BF_LONG S[4*256]; - } BF_KEY; - -#ifndef NOPROTO - -void BF_set_key(BF_KEY *key, int len, unsigned char *data); -void BF_ecb_encrypt(unsigned char *in,unsigned char *out,BF_KEY *key, - int encrypt); -void BF_encrypt(BF_LONG *data,BF_KEY *key,int encrypt); -void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length, - BF_KEY *ks, unsigned char *iv, int encrypt); -void BF_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, - BF_KEY *schedule, unsigned char *ivec, int *num, int encrypt); -void BF_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, - BF_KEY *schedule, unsigned char *ivec, int *num); -char *BF_options(void); - -/* added by itojun */ -struct mbuf; -int BF_cbc_encrypt_m(struct mbuf *, int, int, BF_KEY *, unsigned char *, int); - -#else - -void BF_set_key(); -void BF_ecb_encrypt(); -void BF_encrypt(); -void BF_cbc_encrypt(); -void BF_cfb64_encrypt(); -void BF_ofb64_encrypt(); -char *BF_options(); - -/* added by itojun */ -void BF_cbc_encrypt_m(); - -#endif +} BF_KEY; +void BF_set_key __P((BF_KEY *, int, unsigned char *)); +void BF_encrypt __P((BF_LONG *, BF_KEY *, int)); #ifdef __cplusplus } #endif diff --git a/sys/crypto/cast128/cast128.c b/sys/crypto/cast128/cast128.c index 4df1be9..88873f2 100644 --- a/sys/crypto/cast128/cast128.c +++ b/sys/crypto/cast128/cast128.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: cast128.c,v 1.3 2000/03/27 04:36:29 sumikawa Exp $ */ +/* $KAME: cast128.c,v 1.4 2000/11/06 13:58:08 itojun Exp $ */ /* * heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp> diff --git a/sys/crypto/cast128/cast128.h b/sys/crypto/cast128/cast128.h index 019c2de..4057a1f 100644 --- a/sys/crypto/cast128/cast128.h +++ b/sys/crypto/cast128/cast128.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: cast128.h,v 1.4 2000/06/14 10:41:16 itojun Exp $ */ +/* $KAME: cast128.h,v 1.6 2000/09/18 20:59:20 itojun Exp $ */ /* * heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp> @@ -40,7 +40,6 @@ #define RFC2144_CAST_128_H #include <sys/param.h> -#include <sys/mbuf.h> #define CAST128_ENCRYPT 1 @@ -56,8 +55,5 @@ extern void cast128_encrypt_round12 __P((u_int8_t *, const u_int8_t *, u_int32_t *)); extern void cast128_decrypt_round12 __P((u_int8_t *, const u_int8_t *, u_int32_t *)); -extern int cast128_cbc_process __P((struct mbuf *, size_t, size_t, - u_int32_t *, u_int8_t *, size_t, int)); - #endif diff --git a/sys/crypto/cast128/cast128_cbc.c b/sys/crypto/cast128/cast128_cbc.c deleted file mode 100644 index e4725a9..0000000 --- a/sys/crypto/cast128/cast128_cbc.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: cast128_cbc.c,v 1.4 2000/06/14 10:41:17 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <crypto/cast128/cast128.h> - -#define panic(x) do { printf(x); return EINVAL; } while (0) - -int -cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode) - struct mbuf *m0; - size_t skip; - size_t length; - u_int32_t *subkey; - u_int8_t *iv; - size_t keylen; - int mode; -{ - struct mbuf *m; - u_int8_t inbuf[8], outbuf[8]; - size_t off; - - /* sanity check */ - if (m0->m_pkthdr.len < skip) { - printf("cast128_cbc_process: mbuf length < skip\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < length) { - printf("cast128_cbc_process: mbuf length < encrypt length\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - printf("cast128_cbc_process: " - "mbuf length < skip + encrypt length\n"); - return EINVAL; - } - if (length % 8) { - printf("cast128_cbc_process: length is not multiple of 8\n"); - return EINVAL; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("cast128_cbc_process: mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* copy iv into outbuf for XOR (encrypt) */ - bcopy(iv, outbuf, 8); - - /* - * encrypt/decrypt packet - */ - while (length > 0) { - int i; - - if (!m) - panic("cast128_cbc_process: mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them - * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *)+off, inbuf, 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p, *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = inbuf; - while (in - inbuf < 8) { - if (!p) { - panic("cast128_cbc_process: " - "mbuf chain?\n"); - } - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *); - else - p = NULL; - } - } - - /* encrypt/decrypt */ - switch (mode) { - case CAST128_ENCRYPT: - /* XOR */ - for (i = 0; i < 8; i++) - inbuf[i] ^= outbuf[i]; - - /* encrypt */ - if (keylen <= 80/8) - cast128_encrypt_round12(outbuf, inbuf, subkey); - else - cast128_encrypt_round16(outbuf, inbuf, subkey); - break; - - case CAST128_DECRYPT: - /* decrypt */ - if (keylen <= 80/8) - cast128_decrypt_round12(outbuf, inbuf, subkey); - else - cast128_decrypt_round16(outbuf, inbuf, subkey); - - /* XOR */ - for (i = 0; i < 8; i++) - outbuf[i] ^= iv[i]; - - /* copy inbuf into iv for next XOR */ - bcopy(inbuf, iv, 8); - break; - } - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(outbuf, mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(outbuf, mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && !m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p, *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = outbuf; - while (out - outbuf < 8) { - if (!p) { - panic("cast128_cbc_process: " - "mbuf chain?\n"); - } - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *); - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - - return 0; -} diff --git a/sys/crypto/des/des.h b/sys/crypto/des/des.h index 536f0c9..c21f972 100644 --- a/sys/crypto/des/des.h +++ b/sys/crypto/des/des.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: des.h,v 1.4 2000/06/14 10:41:17 itojun Exp $ */ +/* $KAME: des.h,v 1.7 2000/09/18 20:59:21 itojun Exp $ */ /* lib/des/des.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) @@ -55,11 +55,8 @@ extern "C" { #endif -/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a - * %20 speed up (longs are 8 bytes, int's are 4). */ -#ifndef DES_LONG -#define DES_LONG unsigned long -#endif +/* must be 32bit quantity */ +#define DES_LONG u_int32_t typedef unsigned char des_cblock[8]; typedef struct des_ks_struct @@ -83,196 +80,18 @@ typedef struct des_ks_struct #define DES_CBC_MODE 0 #define DES_PCBC_MODE 1 -#define des_ecb2_encrypt(i,o,k1,k2,e) \ - des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) - -#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ - des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) - -#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ - des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) - -#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ - des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) - -#define C_Block des_cblock -#define Key_schedule des_key_schedule -#ifdef KERBEROS -#define ENCRYPT DES_ENCRYPT -#define DECRYPT DES_DECRYPT -#endif -#define KEY_SZ DES_KEY_SZ -#define string_to_key des_string_to_key -#define read_pw_string des_read_pw_string -#define random_key des_random_key -#define pcbc_encrypt des_pcbc_encrypt -#define set_key des_set_key -#define key_sched des_key_sched -#define ecb_encrypt des_ecb_encrypt -#define cbc_encrypt des_cbc_encrypt -#define ncbc_encrypt des_ncbc_encrypt -#define xcbc_encrypt des_xcbc_encrypt -#define cbc_cksum des_cbc_cksum -#define quad_cksum des_quad_cksum - -/* For compatibility with the MIT lib - eay 20/05/92 */ -typedef des_key_schedule bit_64; -#define des_fixup_key_parity des_set_odd_parity -#define des_check_key_parity check_parity - extern int des_check_key; /* defaults to false */ -extern int des_rw_mode; /* defaults to DES_PCBC_MODE */ -/* The next line is used to disable full ANSI prototypes, if your - * compiler has problems with the prototypes, make sure this line always - * evaluates to true :-) */ -#if defined(MSDOS) || defined(__STDC__) -#undef NOPROTO -#endif -#ifndef NOPROTO -char *des_options(void); -void des_ecb3_encrypt(des_cblock *input,des_cblock *output, - des_key_schedule ks1,des_key_schedule ks2, - des_key_schedule ks3, int enc); -DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output, - long length,des_key_schedule schedule,des_cblock *ivec); -/* -void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec,int enc); -*/ -int des_cbc_encrypt(struct mbuf *, size_t, size_t, - des_key_schedule schedule,des_cblock *ivec, int enc); -void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec,int enc); -void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec, - des_cblock *inw,des_cblock *outw,int enc); -void des_3cbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule sk1,des_key_schedule sk2, - des_cblock *ivec1,des_cblock *ivec2,int enc); -extern int des_3cbc_process(struct mbuf *, size_t, size_t, - des_key_schedule *schedule, des_cblock *ivec, int mode); -void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits, - long length,des_key_schedule schedule,des_cblock *ivec,int enc); -void des_ecb_encrypt(des_cblock *input,des_cblock *output, - des_key_schedule ks,int enc); -void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc); -void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc); -void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, - long length, des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int enc); -void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out, - long length, des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int *num, int encrypt); -void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out, - long length, des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int *num); +char *des_options __P((void)); +void des_ecb_encrypt __P((des_cblock *, des_cblock *, + des_key_schedule, int)); +void des_encrypt __P((DES_LONG *, des_key_schedule, int)); +void des_encrypt2 __P((DES_LONG *, des_key_schedule, int)); -int des_enc_read(int fd,char *buf,int len,des_key_schedule sched, - des_cblock *iv); -int des_enc_write(int fd,char *buf,int len,des_key_schedule sched, - des_cblock *iv); -#ifdef PERL5 -char *des_crypt(const char *buf,const char *salt); -#else -/* some stupid compilers complain because I have declared char instead - * of const char */ -#if 1 -char *crypt(const char *buf,const char *salt); -#else -char *crypt(); -#endif -#endif -void des_ofb_encrypt(unsigned char *in,unsigned char *out, - int numbits,long length,des_key_schedule schedule,des_cblock *ivec); -void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec,int enc); -DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output, - long length,int out_count,des_cblock *seed); -void des_random_seed(des_cblock key); -void des_random_key(des_cblock ret); -int des_read_password(des_cblock *key,char *prompt,int verify); -int des_read_2passwords(des_cblock *key1,des_cblock *key2, - char *prompt,int verify); -int des_read_pw_string(char *buf,int length,char *prompt,int verify); -void des_set_odd_parity(des_cblock *key); -int des_is_weak_key(des_cblock *key); -int des_set_key(des_cblock *key,des_key_schedule schedule); -int des_key_sched(des_cblock *key,des_key_schedule schedule); -void des_string_to_key(char *str,des_cblock *key); -void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2); -void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, - des_key_schedule schedule, des_cblock *ivec, int *num, int enc); -void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, - des_key_schedule schedule, des_cblock *ivec, int *num); - -/* Extra functions from Mark Murray <mark@grondar.za> */ -/* -void des_cblock_print_file(des_cblock *cb, FILE *fp); -*/ -/* The following functions are not in the normal unix build or the - * SSLeay build. When using the SSLeay build, use RAND_seed() - * and RAND_bytes() instead. */ -int des_new_random_key(des_cblock *key); -void des_init_random_number_generator(des_cblock *key); -void des_set_random_generator_seed(des_cblock *key); -void des_set_sequence_number(des_cblock new_sequence_number); -void des_generate_random_block(des_cblock *block); - -#else - -char *des_options(); -void des_ecb3_encrypt(); -DES_LONG des_cbc_cksum(); -void des_cbc_encrypt(); -void des_ncbc_encrypt(); -void des_xcbc_encrypt(); -void des_3cbc_encrypt(); -void des_cfb_encrypt(); -void des_ede3_cfb64_encrypt(); -void des_ede3_ofb64_encrypt(); -void des_ecb_encrypt(); -void des_encrypt(); -void des_encrypt2(); -void des_ede3_cbc_encrypt(); -int des_enc_read(); -int des_enc_write(); -#ifdef PERL5 -char *des_crypt(); -#else -char *crypt(); -#endif -void des_ofb_encrypt(); -void des_pcbc_encrypt(); -DES_LONG des_quad_cksum(); -void des_random_seed(); -void des_random_key(); -int des_read_password(); -int des_read_2passwords(); -int des_read_pw_string(); -void des_set_odd_parity(); -int des_is_weak_key(); -int des_set_key(); -int des_key_sched(); -void des_string_to_key(); -void des_string_to_2keys(); -void des_cfb64_encrypt(); -void des_ofb64_encrypt(); - -/* Extra functions from Mark Murray <mark@grondar.za> */ -void des_cblock_print_file(); -/* The following functions are not in the normal unix build or the - * SSLeay build. When using the SSLeay build, use RAND_seed() - * and RAND_bytes() instead. */ -#ifdef FreeBSD -int des_new_random_key(); -void des_init_random_number_generator(); -void des_set_random_generator_seed(); -void des_set_sequence_number(); -void des_generate_random_block(); -#endif - -#endif +void des_set_odd_parity __P((des_cblock *)); +int des_is_weak_key __P((des_cblock *)); +int des_set_key __P((des_cblock *, des_key_schedule)); +int des_key_sched __P((des_cblock *, des_key_schedule)); #ifdef __cplusplus } diff --git a/sys/crypto/des/des_3cbc.c b/sys/crypto/des/des_3cbc.c deleted file mode 100644 index e675871..0000000 --- a/sys/crypto/des/des_3cbc.c +++ /dev/null @@ -1,250 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: des_3cbc.c,v 1.4 2000/06/14 10:41:17 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki - */ -#include <crypto/des/des_locl.h> - -#define panic(x) do { printf(x); return EINVAL; } while (0) - -int des_3cbc_process(m0, skip, length, schedule, ivec, mode) - struct mbuf *m0; - size_t skip; - size_t length; - des_key_schedule *schedule; - des_cblock (*ivec); - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - DES_LONG tin0, tin1; - DES_LONG tout0, tout1; - DES_LONG tin[2]; - DES_LONG xor0 = 0, xor1 = 0; - u_int8_t *iv; - u_int8_t *in, *out; - - /* sanity check */ - if (m0->m_pkthdr.len < skip) { - printf("des_3cbc_process: mbuf length < skip\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < length) { - printf("des_3cbc_process: mbuf length < encrypt length\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - printf("des_3cbc_process: mbuf length < " - "skip + encrypt length\n"); - return EINVAL; - } - if (length % 8) { - printf("des_3cbc_process: length(%lu) is not multiple of 8\n", - (u_long)length); - return EINVAL; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("des_3cbc_process: mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* initialize */ - tin0 = tin1 = tout0 = tout1 = 0; - tin[0] = tin[1] = 0; - - switch (mode) { - case DES_ENCRYPT: - iv = (u_int8_t *)ivec; - c2l(iv, tout0); - c2l(iv, tout1); - break; - case DES_DECRYPT: - xor0 = xor1 = 0; - iv = (u_int8_t *)ivec; - c2l(iv, xor0); - c2l(iv, xor1); - break; - } - - /* - * encrypt/decrypt packet - */ - while (length > 0) { - if (!m) - panic("des_3cbc_process: mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them - * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) { - panic("des_3cbc_process: " - "mbuf chain?\n"); - } - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - /* encrypt/decrypt */ - switch (mode) { - case DES_ENCRYPT: - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); - c2l(in, tin1); - - /* XOR */ - tin0 ^= tout0; tin[0] = tin0; - tin1 ^= tout1; tin[1] = tin1; - - des_encrypt((DES_LONG *)tin, schedule[0], DES_ENCRYPT); - des_encrypt((DES_LONG *)tin, schedule[1], DES_DECRYPT); - des_encrypt((DES_LONG *)tin, schedule[2], DES_ENCRYPT); - - tout0 = tin[0]; l2c(tout0, out); - tout1 = tin[1]; l2c(tout1, out); - break; - case DES_DECRYPT: - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); tin[0] = tin0; - c2l(in, tin1); tin[1] = tin1; - - des_encrypt((DES_LONG *)tin, schedule[2], DES_DECRYPT); - des_encrypt((DES_LONG *)tin, schedule[1], DES_ENCRYPT); - des_encrypt((DES_LONG *)tin, schedule[0], DES_DECRYPT); - - /* XOR */ - tout0 = tin[0] ^ xor0; - tout1 = tin[1] ^ xor1; - l2c(tout0, out); - l2c(tout1, out); - - /* for next iv */ - xor0 = tin0; - xor1 = tin1; - break; - } - - /* - * copy the output buffer int the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && !m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) { - panic("des_3cbc_process: " - "mbuf chain?\n"); - } - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - - return 0; -} - diff --git a/sys/crypto/des/des_cbc.c b/sys/crypto/des/des_cbc.c deleted file mode 100644 index 92de8f8..0000000 --- a/sys/crypto/des/des_cbc.c +++ /dev/null @@ -1,331 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: des_cbc.c,v 1.4 2000/06/14 10:41:17 itojun Exp $ */ - -/* - * heavily modified by Yoshifumi Nishida <nishida@sfc.wide.ad.jp>. - * then, completely rewrote by Jun-ichiro itojun Itoh <itojun@itojun.org>, - * 1997. - */ -/* crypto/des/cbc_enc.c */ -/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) - * All rights reserved. - * - * This file is part of an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL - * specification. This library and applications are - * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE - * as long as the following conditions are aheared to. - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. If this code is used in a product, - * Eric Young should be given attribution as the author of the parts used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * 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 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 Eric Young (eay@mincom.oz.au) - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 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. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include <crypto/des/des_locl.h> - -#define panic(x) do {printf(x); return EINVAL;} while (0) - -int des_cbc_encrypt(m0, skip, length, schedule, ivec, mode) - struct mbuf *m0; - size_t skip; - size_t length; - des_key_schedule schedule; - des_cblock (*ivec); - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - register DES_LONG tin0, tin1; - register DES_LONG tout0, tout1; - DES_LONG tin[2]; - u_int8_t *iv; - - /* sanity checks */ - if (m0->m_pkthdr.len < skip) { - printf("mbuf length < skip\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < length) { - printf("mbuf length < encrypt length\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - printf("mbuf length < skip + encrypt length\n"); - return EINVAL; - } - if (length % 8) { - printf("length is not multiple of 8\n"); - return EINVAL; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* initialize */ - tin0 = tin1 = tout0 = tout1 = 0; - tin[0] = tin[1] = 0; - - if (mode == DES_ENCRYPT) { - u_int8_t *in, *out; - - iv = (u_int8_t *)ivec; - c2l(iv, tout0); - c2l(iv, tout1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); - c2l(in, tin1); - - tin0 ^= tout0; tin[0] = tin0; - tin1 ^= tout1; tin[1] = tin1; - des_encrypt((DES_LONG *)tin, schedule, DES_ENCRYPT); - tout0 = tin[0]; l2c(tout0, out); - tout1 = tin[1]; l2c(tout1, out); - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } else if (mode == DES_DECRYPT) { - register DES_LONG xor0, xor1; - u_int8_t *in, *out; - - xor0 = xor1 = 0; - iv = (u_int8_t *)ivec; - c2l(iv, xor0); - c2l(iv, xor1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); tin[0] = tin0; - c2l(in, tin1); tin[1] = tin1; - des_encrypt((DES_LONG *)tin, schedule, DES_DECRYPT); - tout0 = tin[0] ^ xor0; - tout1 = tin[1] ^ xor1; - l2c(tout0, out); - l2c(tout1, out); - xor0 = tin0; - xor1 = tin1; - - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } - - return 0; -} diff --git a/sys/crypto/des/des_ecb.c b/sys/crypto/des/des_ecb.c index d828b91..aa1b22b 100644 --- a/sys/crypto/des/des_ecb.c +++ b/sys/crypto/des/des_ecb.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: des_ecb.c,v 1.3 2000/03/27 04:36:33 sumikawa Exp $ */ +/* $KAME: des_ecb.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */ /* crypto/des/ecb_enc.c */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) @@ -48,6 +48,8 @@ * [including the GNU Public Licence.] */ +#include <sys/param.h> +#include <sys/systm.h> #include <crypto/des/des_locl.h> #include <crypto/des/spr.h> diff --git a/sys/crypto/des/des_locl.h b/sys/crypto/des/des_locl.h index ae6e828..82486dc 100644 --- a/sys/crypto/des/des_locl.h +++ b/sys/crypto/des/des_locl.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: des_locl.h,v 1.4 2000/03/27 04:43:46 sumikawa Exp $ */ +/* $KAME: des_locl.h,v 1.6 2000/11/06 13:58:09 itojun Exp $ */ /* lib/des/des_locl.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) @@ -55,83 +55,17 @@ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ -#include <sys/param.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/systm.h> - #ifndef HEADER_DES_LOCL_H #define HEADER_DES_LOCL_H -#if defined(WIN32) || defined(WIN16) -#ifndef MSDOS -#define MSDOS -#endif -#endif - -/* -#include <stdio.h> -#include <stdlib.h> -#ifndef MSDOS -#include <unistd.h> -#endif -*/ #include <crypto/des/des.h> -/* the following is tweaked from a config script, that is why it is a - * protected undef/define */ -#ifndef DES_PTR #undef DES_PTR -#endif - -#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ -#include <stdlib.h> -#include <errno.h> -#include <time.h> -#include <io.h> -#ifndef RAND -#define RAND -#endif -#undef NOPROTO -#endif - -#if !defined(_KERNEL) && (defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)) -#ifndef __NetBSD__ -#include <string.h> -#endif -#endif - -#ifdef __NetBSD__ -#include <sys/systm.h> -#endif - -#ifndef RAND -#define RAND -#endif - -#ifdef linux -#undef RAND -#endif - -#ifdef MSDOS -#define getpid() 2 -#define RAND -#undef NOPROTO -#endif - -#if defined(NOCONST) -#define const -#endif #ifdef __STDC__ #undef NOPROTO #endif -#ifdef RAND -#define srandom(s) srand(s) -#define random rand -#endif - #define ITERATIONS 16 #define HALF_ITERATIONS 8 @@ -194,11 +128,7 @@ } \ } -#if defined(WIN32) -#define ROTATE(a,n) (_lrotr(a,n)) -#else #define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) -#endif /* The changes to this macro may help or hinder, depending on the * compiler and the achitecture. gcc2 always seems to do well :-). @@ -313,36 +243,3 @@ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ } #endif - - -/* -#define mbuf2char(i_mbuf, i_index, in) \ - { \ - register int i; \ - struct mbuf *m; \ - char *buf; \ - m = i_mbuf; \ - for (i = 0; i < 8; i ++){ \ - if (i_index + i == m->m_len){ \ - m = m->m_next; \ - } \ - buf = mtod(m, char *); \ - in[i] = *(buf + i); \ - } - - -#define char2mbuf(o_mbuf, o_index, out) \ - { \ - register int i; \ - struct mbuf *m; \ - char *buf; \ - m = o_mbuf; \ - for (i = 0; i < 8; i ++){ \ - if (i_index + i == m->m_len){ \ - m = m->m_next; \ - } \ - buf = mtod(m, char *); \ - *(buf + i) = out[i]; \ - } -*/ - diff --git a/sys/crypto/des/des_setkey.c b/sys/crypto/des/des_setkey.c index 48d13fc..2ddf8bd 100644 --- a/sys/crypto/des/des_setkey.c +++ b/sys/crypto/des/des_setkey.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: des_setkey.c,v 1.3 2000/03/27 04:36:33 sumikawa Exp $ */ +/* $KAME: des_setkey.c,v 1.5 2000/11/06 13:58:09 itojun Exp $ */ /* crypto/des/set_key.c */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) @@ -55,15 +55,13 @@ * 1.1 added norm_expand_bits * 1.0 First working version */ +#include <sys/param.h> +#include <sys/systm.h> #include <crypto/des/des_locl.h> #include <crypto/des/podd.h> #include <crypto/des/sk.h> -#ifndef NOPROTO -static int check_parity(des_cblock (*key)); -#else -static int check_parity(); -#endif +static int check_parity __P((des_cblock (*))); int des_check_key=0; diff --git a/sys/crypto/md5.c b/sys/crypto/md5.c index e827700..3351d41 100644 --- a/sys/crypto/md5.c +++ b/sys/crypto/md5.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: md5.c,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */ +/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. diff --git a/sys/crypto/rc5/rc5.c b/sys/crypto/rc5/rc5.c deleted file mode 100644 index 99a8ac6..0000000 --- a/sys/crypto/rc5/rc5.c +++ /dev/null @@ -1,219 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: rc5.c,v 1.3 2000/03/27 04:36:36 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include <crypto/rc5/rc5.h> - - -void -set_rc5_expandkey(e_key, key, keylen, rounds) - RC5_WORD *e_key; - u_int8_t *key; - size_t keylen; - int rounds; -{ - int i, j, k, LL, t, T; - RC5_WORD L[256/WW]; - RC5_WORD A, B; - - LL = (keylen + WW - 1) / WW; - - bzero(L, sizeof(RC5_WORD)*LL); - - for (i = 0; i < keylen; i++) { - t = (key[i] & 0xff) << (8*(i%4)); - L[i/WW] = L[i/WW] + t; - } - - T = 2 * (rounds + 1); - e_key[0] = Pw; - for (i = 1; i < T; i++) - e_key[i] = e_key[i-1] + Qw; - - i = j = 0; - A = B = 0; - if (LL > T) - k = 3 * LL; - else - k = 3 * T; - - for (; k > 0; k--) { - A = ROTL(e_key[i]+A+B, 3, W); - e_key[i] = A; - B = ROTL(L[j]+A+B, A+B, W); - L[j] = B; - - i = (i + 1) % T; - j = (j + 1) % LL; - } -} - - -/* - * - */ -void -rc5_encrypt_round16(out, in, e_key) - u_int8_t *out; - const u_int8_t *in; - const RC5_WORD *e_key; -{ - RC5_WORD A, B; - const RC5_WORD *e_keyA, *e_keyB; - - A = in[0] & 0xff; - A += (in[1] & 0xff) << 8; - A += (in[2] & 0xff) << 16; - A += (in[3] & 0xff) << 24; - B = in[4] & 0xff; - B += (in[5] & 0xff) << 8; - B += (in[6] & 0xff) << 16; - B += (in[7] & 0xff) << 24; - - e_keyA = e_key; - e_keyB = e_key + 1; - - A += *e_keyA; e_keyA += 2; - B += *e_keyB; e_keyB += 2; - - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 4 */ - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 8 */ - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 12 */ - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 16 */ - - out[0] = A & 0xff; - out[1] = (A >> 8) & 0xff; - out[2] = (A >> 16) & 0xff; - out[3] = (A >> 24) & 0xff; - out[4] = B & 0xff; - out[5] = (B >> 8) & 0xff; - out[6] = (B >> 16) & 0xff; - out[7] = (B >> 24) & 0xff; -} - - -/* - * - */ -void -rc5_decrypt_round16(out, in, e_key) - u_int8_t *out; - const u_int8_t *in; - const RC5_WORD *e_key; -{ - RC5_WORD A, B; - const RC5_WORD *e_keyA, *e_keyB; - - A = in[0] & 0xff; - A += (in[1] & 0xff) << 8; - A += (in[2] & 0xff) << 16; - A += (in[3] & 0xff) << 24; - B = in[4] & 0xff; - B += (in[5] & 0xff) << 8; - B += (in[6] & 0xff) << 16; - B += (in[7] & 0xff) << 24; - - e_keyA = e_key + 2*16; - e_keyB = e_key + 2*16 + 1; - - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 4 */ - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 8 */ - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 12 */ - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 16 */ - - B = B - *e_keyB; - A = A - *e_keyA; - - out[0] = A & 0xff; - out[1] = (A >> 8) & 0xff; - out[2] = (A >> 16) & 0xff; - out[3] = (A >> 24) & 0xff; - out[4] = B & 0xff; - out[5] = (B >> 8) & 0xff; - out[6] = (B >> 16) & 0xff; - out[7] = (B >> 24) & 0xff; -} - diff --git a/sys/crypto/rc5/rc5_cbc.c b/sys/crypto/rc5/rc5_cbc.c deleted file mode 100644 index 5972cc6..0000000 --- a/sys/crypto/rc5/rc5_cbc.c +++ /dev/null @@ -1,215 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: rc5_cbc.c,v 1.4 2000/06/14 10:41:17 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki - */ -#include <crypto/rc5/rc5.h> - -#define panic(x) do { printf(x); return EINVAL; } while (0) - -int -rc5_cbc_process(m0, skip, length, e_key, iv, mode) - struct mbuf *m0; - size_t skip; - size_t length; - RC5_WORD *e_key; - u_int8_t *iv; - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - - /* sanity check */ - if (m0->m_pkthdr.len < skip) { - printf("rc5_cbc_process: mbuf length < skip\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < length) { - printf("rc5_cbc_process: mbuf length < encrypt length\n"); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - printf("rc5_cbc_process: mbuf length < " - "skip + encrypt length\n"); - return EINVAL; - } - if (length % 8) { - printf("rc5_cbc_process: length(%lu)is not multipleof 8\n", - (u_long)length); - return EINVAL; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("rc5_cbc_process: mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* copy iv into outbuf for XOR (encrypt) */ - bcopy(iv, outbuf, 8); - - /* - * encrypt/decrypt packet - */ - while (length > 0) { - int i; - - if (!m) - panic("rc5_cbc_process: mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them - * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) { - panic("rc5_cbc_process: " - "mbuf chain?\n"); - } - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - /* encrypt/decrypt */ - switch (mode) { - case RC5_ENCRYPT: - /* XOR */ - for (i = 0; i < 8; i++) - inbuf[i] ^= outbuf[i]; - - /* encrypt */ - rc5_encrypt_round16(outbuf, inbuf, e_key); - break; - - case RC5_DECRYPT: - /* decrypt */ - rc5_decrypt_round16(outbuf, inbuf, e_key); - - /* XOR */ - for (i = 0; i < 8; i++) - outbuf[i] ^= iv[i]; - - /* copy inbuf into iv for next XOR */ - bcopy(inbuf, iv, 8); - break; - } - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && !m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) { - panic("rc5_cbc_process: " - "mbuf chain?\n"); - } - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - - return 0; -} - diff --git a/sys/crypto/rijndael/boxes-fst.dat b/sys/crypto/rijndael/boxes-fst.dat index 6315523..3fed9c0 100644 --- a/sys/crypto/rijndael/boxes-fst.dat +++ b/sys/crypto/rijndael/boxes-fst.dat @@ -1,6 +1,7 @@ -/* $KAME$ */ +/* $FreeBSD$ */ +/* $KAME: boxes-fst.dat,v 1.6 2001/05/27 00:23:22 itojun Exp $ */ -word8 S[256] = { +const word8 S[256] = { 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, @@ -20,7 +21,7 @@ word8 S[256] = { }; #ifdef INTERMEDIATE_VALUE_KAT -static word8 Si[256] = { +static const word8 Si[256] = { 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, @@ -40,7 +41,13 @@ static word8 Si[256] = { }; #endif /* INTERMEDIATE_VALUE_KAT */ -static word8 T1[256][4] = { +union xtab { + word32 xt32[256]; + word8 xt8[256][4]; +}; + +static const union xtab xT1 = { + .xt8 = { {0xc6,0x63,0x63,0xa5}, {0xf8,0x7c,0x7c,0x84}, {0xee,0x77,0x77,0x99}, {0xf6,0x7b,0x7b,0x8d}, {0xff,0xf2,0xf2,0x0d}, {0xd6,0x6b,0x6b,0xbd}, {0xde,0x6f,0x6f,0xb1}, {0x91,0xc5,0xc5,0x54}, {0x60,0x30,0x30,0x50}, {0x02,0x01,0x01,0x03}, {0xce,0x67,0x67,0xa9}, {0x56,0x2b,0x2b,0x7d}, @@ -105,9 +112,12 @@ static word8 T1[256][4] = { {0x65,0xbf,0xbf,0xda}, {0xd7,0xe6,0xe6,0x31}, {0x84,0x42,0x42,0xc6}, {0xd0,0x68,0x68,0xb8}, {0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11}, {0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a} + } }; +#define T1 xT1.xt8 -static word8 T2[256][4] = { +static const union xtab xT2 = { + .xt8 = { {0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b}, {0x0d,0xff,0xf2,0xf2}, {0xbd,0xd6,0x6b,0x6b}, {0xb1,0xde,0x6f,0x6f}, {0x54,0x91,0xc5,0xc5}, {0x50,0x60,0x30,0x30}, {0x03,0x02,0x01,0x01}, {0xa9,0xce,0x67,0x67}, {0x7d,0x56,0x2b,0x2b}, @@ -172,9 +182,12 @@ static word8 T2[256][4] = { {0xda,0x65,0xbf,0xbf}, {0x31,0xd7,0xe6,0xe6}, {0xc6,0x84,0x42,0x42}, {0xb8,0xd0,0x68,0x68}, {0xc3,0x82,0x41,0x41}, {0xb0,0x29,0x99,0x99}, {0x77,0x5a,0x2d,0x2d}, {0x11,0x1e,0x0f,0x0f}, {0xcb,0x7b,0xb0,0xb0}, {0xfc,0xa8,0x54,0x54}, {0xd6,0x6d,0xbb,0xbb}, {0x3a,0x2c,0x16,0x16} + } }; +#define T2 xT2.xt8 -static word8 T3[256][4] = { +static const union xtab xT3 = { + .xt8 = { {0x63,0xa5,0xc6,0x63}, {0x7c,0x84,0xf8,0x7c}, {0x77,0x99,0xee,0x77}, {0x7b,0x8d,0xf6,0x7b}, {0xf2,0x0d,0xff,0xf2}, {0x6b,0xbd,0xd6,0x6b}, {0x6f,0xb1,0xde,0x6f}, {0xc5,0x54,0x91,0xc5}, {0x30,0x50,0x60,0x30}, {0x01,0x03,0x02,0x01}, {0x67,0xa9,0xce,0x67}, {0x2b,0x7d,0x56,0x2b}, @@ -239,9 +252,12 @@ static word8 T3[256][4] = { {0xbf,0xda,0x65,0xbf}, {0xe6,0x31,0xd7,0xe6}, {0x42,0xc6,0x84,0x42}, {0x68,0xb8,0xd0,0x68}, {0x41,0xc3,0x82,0x41}, {0x99,0xb0,0x29,0x99}, {0x2d,0x77,0x5a,0x2d}, {0x0f,0x11,0x1e,0x0f}, {0xb0,0xcb,0x7b,0xb0}, {0x54,0xfc,0xa8,0x54}, {0xbb,0xd6,0x6d,0xbb}, {0x16,0x3a,0x2c,0x16} + } }; +#define T3 xT3.xt8 -static word8 T4[256][4] = { +static const union xtab xT4 = { + .xt8 = { {0x63,0x63,0xa5,0xc6}, {0x7c,0x7c,0x84,0xf8}, {0x77,0x77,0x99,0xee}, {0x7b,0x7b,0x8d,0xf6}, {0xf2,0xf2,0x0d,0xff}, {0x6b,0x6b,0xbd,0xd6}, {0x6f,0x6f,0xb1,0xde}, {0xc5,0xc5,0x54,0x91}, {0x30,0x30,0x50,0x60}, {0x01,0x01,0x03,0x02}, {0x67,0x67,0xa9,0xce}, {0x2b,0x2b,0x7d,0x56}, @@ -306,9 +322,12 @@ static word8 T4[256][4] = { {0xbf,0xbf,0xda,0x65}, {0xe6,0xe6,0x31,0xd7}, {0x42,0x42,0xc6,0x84}, {0x68,0x68,0xb8,0xd0}, {0x41,0x41,0xc3,0x82}, {0x99,0x99,0xb0,0x29}, {0x2d,0x2d,0x77,0x5a}, {0x0f,0x0f,0x11,0x1e}, {0xb0,0xb0,0xcb,0x7b}, {0x54,0x54,0xfc,0xa8}, {0xbb,0xbb,0xd6,0x6d}, {0x16,0x16,0x3a,0x2c} + } }; +#define T4 xT4.xt8 -static word8 T5[256][4] = { +static const union xtab xT5 = { + .xt8 = { {0x51,0xf4,0xa7,0x50}, {0x7e,0x41,0x65,0x53}, {0x1a,0x17,0xa4,0xc3}, {0x3a,0x27,0x5e,0x96}, {0x3b,0xab,0x6b,0xcb}, {0x1f,0x9d,0x45,0xf1}, {0xac,0xfa,0x58,0xab}, {0x4b,0xe3,0x03,0x93}, {0x20,0x30,0xfa,0x55}, {0xad,0x76,0x6d,0xf6}, {0x88,0xcc,0x76,0x91}, {0xf5,0x02,0x4c,0x25}, @@ -373,9 +392,12 @@ static word8 T5[256][4] = { {0x16,0x1d,0xc3,0x72}, {0xbc,0xe2,0x25,0x0c}, {0x28,0x3c,0x49,0x8b}, {0xff,0x0d,0x95,0x41}, {0x39,0xa8,0x01,0x71}, {0x08,0x0c,0xb3,0xde}, {0xd8,0xb4,0xe4,0x9c}, {0x64,0x56,0xc1,0x90}, {0x7b,0xcb,0x84,0x61}, {0xd5,0x32,0xb6,0x70}, {0x48,0x6c,0x5c,0x74}, {0xd0,0xb8,0x57,0x42} + } }; +#define T5 xT5.xt8 -static word8 T6[256][4] = { +static const union xtab xT6 = { + .xt8 = { {0x50,0x51,0xf4,0xa7}, {0x53,0x7e,0x41,0x65}, {0xc3,0x1a,0x17,0xa4}, {0x96,0x3a,0x27,0x5e}, {0xcb,0x3b,0xab,0x6b}, {0xf1,0x1f,0x9d,0x45}, {0xab,0xac,0xfa,0x58}, {0x93,0x4b,0xe3,0x03}, {0x55,0x20,0x30,0xfa}, {0xf6,0xad,0x76,0x6d}, {0x91,0x88,0xcc,0x76}, {0x25,0xf5,0x02,0x4c}, @@ -440,9 +462,12 @@ static word8 T6[256][4] = { {0x72,0x16,0x1d,0xc3}, {0x0c,0xbc,0xe2,0x25}, {0x8b,0x28,0x3c,0x49}, {0x41,0xff,0x0d,0x95}, {0x71,0x39,0xa8,0x01}, {0xde,0x08,0x0c,0xb3}, {0x9c,0xd8,0xb4,0xe4}, {0x90,0x64,0x56,0xc1}, {0x61,0x7b,0xcb,0x84}, {0x70,0xd5,0x32,0xb6}, {0x74,0x48,0x6c,0x5c}, {0x42,0xd0,0xb8,0x57} + } }; +#define T6 xT6.xt8 -static word8 T7[256][4] = { +static const union xtab xT7 = { + .xt8 = { {0xa7,0x50,0x51,0xf4}, {0x65,0x53,0x7e,0x41}, {0xa4,0xc3,0x1a,0x17}, {0x5e,0x96,0x3a,0x27}, {0x6b,0xcb,0x3b,0xab}, {0x45,0xf1,0x1f,0x9d}, {0x58,0xab,0xac,0xfa}, {0x03,0x93,0x4b,0xe3}, {0xfa,0x55,0x20,0x30}, {0x6d,0xf6,0xad,0x76}, {0x76,0x91,0x88,0xcc}, {0x4c,0x25,0xf5,0x02}, @@ -507,9 +532,12 @@ static word8 T7[256][4] = { {0xc3,0x72,0x16,0x1d}, {0x25,0x0c,0xbc,0xe2}, {0x49,0x8b,0x28,0x3c}, {0x95,0x41,0xff,0x0d}, {0x01,0x71,0x39,0xa8}, {0xb3,0xde,0x08,0x0c}, {0xe4,0x9c,0xd8,0xb4}, {0xc1,0x90,0x64,0x56}, {0x84,0x61,0x7b,0xcb}, {0xb6,0x70,0xd5,0x32}, {0x5c,0x74,0x48,0x6c}, {0x57,0x42,0xd0,0xb8} + } }; +#define T7 xT7.xt8 -static word8 T8[256][4] = { +static const union xtab xT8 = { + .xt8 = { {0xf4,0xa7,0x50,0x51}, {0x41,0x65,0x53,0x7e}, {0x17,0xa4,0xc3,0x1a}, {0x27,0x5e,0x96,0x3a}, {0xab,0x6b,0xcb,0x3b}, {0x9d,0x45,0xf1,0x1f}, {0xfa,0x58,0xab,0xac}, {0xe3,0x03,0x93,0x4b}, {0x30,0xfa,0x55,0x20}, {0x76,0x6d,0xf6,0xad}, {0xcc,0x76,0x91,0x88}, {0x02,0x4c,0x25,0xf5}, @@ -574,9 +602,11 @@ static word8 T8[256][4] = { {0x1d,0xc3,0x72,0x16}, {0xe2,0x25,0x0c,0xbc}, {0x3c,0x49,0x8b,0x28}, {0x0d,0x95,0x41,0xff}, {0xa8,0x01,0x71,0x39}, {0x0c,0xb3,0xde,0x08}, {0xb4,0xe4,0x9c,0xd8}, {0x56,0xc1,0x90,0x64}, {0xcb,0x84,0x61,0x7b}, {0x32,0xb6,0x70,0xd5}, {0x6c,0x5c,0x74,0x48}, {0xb8,0x57,0x42,0xd0} + } }; +#define T8 xT8.xt8 -static word8 S5[256] = { +static const word8 S5[256] = { 0x52,0x09,0x6a,0xd5, 0x30,0x36,0xa5,0x38, 0xbf,0x40,0xa3,0x9e, @@ -643,7 +673,8 @@ static word8 S5[256] = { 0x55,0x21,0x0c,0x7d }; -static word8 U1[256][4] = { +static const union xtab xU1 = { + .xt8 = { {0x00,0x00,0x00,0x00}, {0x0e,0x09,0x0d,0x0b}, {0x1c,0x12,0x1a,0x16}, {0x12,0x1b,0x17,0x1d}, {0x38,0x24,0x34,0x2c}, {0x36,0x2d,0x39,0x27}, {0x24,0x36,0x2e,0x3a}, {0x2a,0x3f,0x23,0x31}, {0x70,0x48,0x68,0x58}, {0x7e,0x41,0x65,0x53}, {0x6c,0x5a,0x72,0x4e}, {0x62,0x53,0x7f,0x45}, @@ -708,9 +739,12 @@ static word8 U1[256][4] = { {0xef,0x15,0xe8,0xe6}, {0xe1,0x1c,0xe5,0xed}, {0xf3,0x07,0xf2,0xf0}, {0xfd,0x0e,0xff,0xfb}, {0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f}, {0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3} + } }; +#define U1 xU1.xt8 -static word8 U2[256][4] = { +static const union xtab xU2 = { + .xt8 = { {0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17}, {0x2c,0x38,0x24,0x34}, {0x27,0x36,0x2d,0x39}, {0x3a,0x24,0x36,0x2e}, {0x31,0x2a,0x3f,0x23}, {0x58,0x70,0x48,0x68}, {0x53,0x7e,0x41,0x65}, {0x4e,0x6c,0x5a,0x72}, {0x45,0x62,0x53,0x7f}, @@ -775,9 +809,12 @@ static word8 U2[256][4] = { {0xe6,0xef,0x15,0xe8}, {0xed,0xe1,0x1c,0xe5}, {0xf0,0xf3,0x07,0xf2}, {0xfb,0xfd,0x0e,0xff}, {0x92,0xa7,0x79,0xb4}, {0x99,0xa9,0x70,0xb9}, {0x84,0xbb,0x6b,0xae}, {0x8f,0xb5,0x62,0xa3}, {0xbe,0x9f,0x5d,0x80}, {0xb5,0x91,0x54,0x8d}, {0xa8,0x83,0x4f,0x9a}, {0xa3,0x8d,0x46,0x97} + } }; +#define U2 xU2.xt8 -static word8 U3[256][4] = { +static const union xtab xU3 = { + .xt8 = { {0x00,0x00,0x00,0x00}, {0x0d,0x0b,0x0e,0x09}, {0x1a,0x16,0x1c,0x12}, {0x17,0x1d,0x12,0x1b}, {0x34,0x2c,0x38,0x24}, {0x39,0x27,0x36,0x2d}, {0x2e,0x3a,0x24,0x36}, {0x23,0x31,0x2a,0x3f}, {0x68,0x58,0x70,0x48}, {0x65,0x53,0x7e,0x41}, {0x72,0x4e,0x6c,0x5a}, {0x7f,0x45,0x62,0x53}, @@ -842,9 +879,12 @@ static word8 U3[256][4] = { {0xe8,0xe6,0xef,0x15}, {0xe5,0xed,0xe1,0x1c}, {0xf2,0xf0,0xf3,0x07}, {0xff,0xfb,0xfd,0x0e}, {0xb4,0x92,0xa7,0x79}, {0xb9,0x99,0xa9,0x70}, {0xae,0x84,0xbb,0x6b}, {0xa3,0x8f,0xb5,0x62}, {0x80,0xbe,0x9f,0x5d}, {0x8d,0xb5,0x91,0x54}, {0x9a,0xa8,0x83,0x4f}, {0x97,0xa3,0x8d,0x46} + } }; +#define U3 xU3.xt8 -static word8 U4[256][4] = { +static const union xtab xU4 = { + .xt8 = { {0x00,0x00,0x00,0x00}, {0x09,0x0d,0x0b,0x0e}, {0x12,0x1a,0x16,0x1c}, {0x1b,0x17,0x1d,0x12}, {0x24,0x34,0x2c,0x38}, {0x2d,0x39,0x27,0x36}, {0x36,0x2e,0x3a,0x24}, {0x3f,0x23,0x31,0x2a}, {0x48,0x68,0x58,0x70}, {0x41,0x65,0x53,0x7e}, {0x5a,0x72,0x4e,0x6c}, {0x53,0x7f,0x45,0x62}, @@ -909,8 +949,10 @@ static word8 U4[256][4] = { {0x15,0xe8,0xe6,0xef}, {0x1c,0xe5,0xed,0xe1}, {0x07,0xf2,0xf0,0xf3}, {0x0e,0xff,0xfb,0xfd}, {0x79,0xb4,0x92,0xa7}, {0x70,0xb9,0x99,0xa9}, {0x6b,0xae,0x84,0xbb}, {0x62,0xa3,0x8f,0xb5}, {0x5d,0x80,0xbe,0x9f}, {0x54,0x8d,0xb5,0x91}, {0x4f,0x9a,0xa8,0x83}, {0x46,0x97,0xa3,0x8d} + } }; +#define U4 xU4.xt8 -static word32 rcon[30] = { +static const word32 rcon[30] = { 0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; diff --git a/sys/crypto/rijndael/rijndael-alg-fst.c b/sys/crypto/rijndael/rijndael-alg-fst.c index 33d0d8a..ac9668e 100644 --- a/sys/crypto/rijndael/rijndael-alg-fst.c +++ b/sys/crypto/rijndael/rijndael-alg-fst.c @@ -1,4 +1,5 @@ -/* $KAME$ */ +/* $FreeBSD$ */ +/* $KAME: rijndael-alg-fst.c,v 1.7 2001/05/27 00:23:23 itojun Exp $ */ /* * rijndael-alg-fst.c v2.3 April '2000 @@ -14,6 +15,11 @@ #include <sys/cdefs.h> #include <sys/types.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else +#include <string.h> +#endif #include <crypto/rijndael/rijndael-alg-fst.h> #include <crypto/rijndael/rijndael_local.h> @@ -24,7 +30,11 @@ int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) * The number of calculations depends on keyBits and blockBits */ int j, r, t, rconpointer = 0; - word8 tk[MAXKC][4]; + union { + word8 x8[MAXKC][4]; + word32 x32[MAXKC]; + } xtk; +#define tk xtk.x8 int KC = ROUNDS - 6; for (j = KC-1; j >= 0; j--) { @@ -79,6 +89,7 @@ int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) } } return 0; +#undef tk } int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) { @@ -120,9 +131,21 @@ int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) { /** * Encrypt a single block. */ -int rijndaelEncrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { +int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { int r; - word8 temp[4][4]; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]); *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]); @@ -193,7 +216,12 @@ int rijndaelEncrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int R *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]); *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]); + memcpy(out, b, sizeof b /* XXX out */); + return 0; +#undef a +#undef b +#undef temp } #ifdef INTERMEDIATE_VALUE_KAT @@ -268,10 +296,22 @@ int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, /** * Decrypt a single block. */ -int rijndaelDecrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { +int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { int r; - word8 temp[4][4]; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + memcpy(a, in, sizeof a); + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]); *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]); *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]); @@ -341,7 +381,12 @@ int rijndaelDecrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int R *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]); *((word32*)(b+12)) ^= *((word32*)rk[0][3]); + memcpy(out, b, sizeof b /* XXX out */); + return 0; +#undef a +#undef b +#undef temp } diff --git a/sys/crypto/rijndael/rijndael-alg-fst.h b/sys/crypto/rijndael/rijndael-alg-fst.h index 6061bf4..5b22ef4c 100644 --- a/sys/crypto/rijndael/rijndael-alg-fst.h +++ b/sys/crypto/rijndael/rijndael-alg-fst.h @@ -1,4 +1,5 @@ -/* $KAME$ */ +/* $FreeBSD$ */ +/* $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $ */ /* * rijndael-alg-fst.h v2.3 April '2000 diff --git a/sys/crypto/rijndael/rijndael-api-fst.c b/sys/crypto/rijndael/rijndael-api-fst.c index 1a2de50..1eec694 100644 --- a/sys/crypto/rijndael/rijndael-api-fst.c +++ b/sys/crypto/rijndael/rijndael-api-fst.c @@ -1,4 +1,5 @@ -/* $KAME: $ */ +/* $FreeBSD$ */ +/* $KAME: rijndael-api-fst.c,v 1.10 2001/05/27 09:34:18 itojun Exp $ */ /* * rijndael-api-fst.c v2.3 April '2000 @@ -16,8 +17,12 @@ */ #include <sys/param.h> -#include <sys/systm.h> #include <sys/types.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else +#include <string.h> +#endif #include <crypto/rijndael/rijndael-alg-fst.h> #include <crypto/rijndael/rijndael-api-fst.h> #include <crypto/rijndael/rijndael_local.h> @@ -44,36 +49,16 @@ int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMate } if (keyMaterial != NULL) { - strncpy(key->keyMaterial, keyMaterial, keyLen/4); + bcopy(keyMaterial, key->keyMaterial, keyLen/8); } key->ROUNDS = keyLen/32 + 6; /* initialize key schedule: */ keyMat = key->keyMaterial; -#ifndef BINARY_KEY_MATERIAL - for (i = 0; i < key->keyLen/8; i++) { - int t, j; - - t = *keyMat++; - if ((t >= '0') && (t <= '9')) j = (t - '0') << 4; - else if ((t >= 'a') && (t <= 'f')) j = (t - 'a' + 10) << 4; - else if ((t >= 'A') && (t <= 'F')) j = (t - 'A' + 10) << 4; - else return BAD_KEY_MAT; - - t = *keyMat++; - if ((t >= '0') && (t <= '9')) j ^= (t - '0'); - else if ((t >= 'a') && (t <= 'f')) j ^= (t - 'a' + 10); - else if ((t >= 'A') && (t <= 'F')) j ^= (t - 'A' + 10); - else return BAD_KEY_MAT; - - k[i >> 2][i & 3] = (word8)j; - } -#else for (i = 0; i < key->keyLen/8; i++) { k[i >> 2][i & 3] = (word8)keyMat[i]; } -#endif /* ?BINARY_KEY_MATERIAL */ rijndaelKeySched(k, key->keySched, key->ROUNDS); if (direction == DIR_DECRYPT) { rijndaelKeyEncToDec(key->keySched, key->ROUNDS); @@ -89,28 +74,7 @@ int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) { return BAD_CIPHER_MODE; } if (IV != NULL) { -#ifndef BINARY_KEY_MATERIAL - int i; - for (i = 0; i < MAX_IV_SIZE; i++) { - int t, j; - - t = IV[2*i]; - if ((t >= '0') && (t <= '9')) j = (t - '0') << 4; - else if ((t >= 'a') && (t <= 'f')) j = (t - 'a' + 10) << 4; - else if ((t >= 'A') && (t <= 'F')) j = (t - 'A' + 10) << 4; - else return BAD_CIPHER_INSTANCE; - - t = IV[2*i+1]; - if ((t >= '0') && (t <= '9')) j ^= (t - '0'); - else if ((t >= 'a') && (t <= 'f')) j ^= (t - 'a' + 10); - else if ((t >= 'A') && (t <= 'F')) j ^= (t - 'A' + 10); - else return BAD_CIPHER_INSTANCE; - - cipher->IV[i] = (word8)j; - } -#else bcopy(IV, cipher->IV, MAX_IV_SIZE); -#endif /* ?BINARY_KEY_MATERIAL */ } else { bzero(cipher->IV, MAX_IV_SIZE); } diff --git a/sys/crypto/rijndael/rijndael-api-fst.h b/sys/crypto/rijndael/rijndael-api-fst.h index c98f3f4..a4ab920 100644 --- a/sys/crypto/rijndael/rijndael-api-fst.h +++ b/sys/crypto/rijndael/rijndael-api-fst.h @@ -1,4 +1,5 @@ -/* $KAME$ */ +/* $FreeBSD$ */ +/* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */ /* * rijndael-api-fst.h v2.3 April '2000 @@ -55,7 +56,11 @@ typedef struct { /* The following parameters are algorithm dependent, replace or add as necessary */ int ROUNDS; /* key-length-dependent number of rounds */ int blockLen; /* block length */ - u_int8_t keySched[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */ + union { + u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */ + u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4]; /* key schedule */ + } xKeySched; +#define keySched xKeySched.xkS8 } keyInstance; /* The structure for cipher information */ diff --git a/sys/crypto/rijndael/rijndael_local.h b/sys/crypto/rijndael/rijndael_local.h index 23e909c..a959b1b 100644 --- a/sys/crypto/rijndael/rijndael_local.h +++ b/sys/crypto/rijndael/rijndael_local.h @@ -9,5 +9,3 @@ typedef u_int32_t word32; #define MAXKC RIJNDAEL_MAXKC #define MAXROUNDS RIJNDAEL_MAXROUNDS - -#define BINARY_KEY_MATERIAL 1 diff --git a/sys/crypto/sha1.c b/sys/crypto/sha1.c index bbf20b8..b210b52 100644 --- a/sys/crypto/sha1.c +++ b/sys/crypto/sha1.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: sha1.c,v 1.4 2000/03/27 04:36:23 sumikawa Exp $ */ +/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. diff --git a/sys/crypto/sha2/sha2.c b/sys/crypto/sha2/sha2.c new file mode 100644 index 0000000..9b3a5c6 --- /dev/null +++ b/sys/crypto/sha2/sha2.c @@ -0,0 +1,1048 @@ +/* $FreeBSD$ */ +/* $KAME: sha2.c,v 1.6 2001/03/12 11:31:04 itojun Exp $ */ + +/* + * sha2.c + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford <me@aarongifford.com> + * + * Copyright 2000 Aaron D. Gifford. 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 copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/systm.h> +#include <machine/endian.h> +#include <crypto/sha2/sha2.h> + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + +#if defined(__bsdi__) || defined(__FreeBSD__) +#define assert(x) +#endif + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including <sys/types.h> (which in turn includes + * <machine/endian.h> where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +#else /* SHA2_USE_INTTYPES_H */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX*); +void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); + bzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace < SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + bzero(context, sizeof(context)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace < SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} + diff --git a/sys/crypto/sha2/sha2.h b/sys/crypto/sha2/sha2.h new file mode 100644 index 0000000..084faa7 --- /dev/null +++ b/sys/crypto/sha2/sha2.h @@ -0,0 +1,141 @@ +/* $FreeBSD$ */ +/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */ + +/* + * sha2.h + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford <me@aarongifford.com> + * + * Copyright 2000 Aaron D. Gifford. 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 copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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. + * + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include <inttypes.h> + * + * If you choose to use <inttypes.h> then please define: + * + * #define SHA2_USE_INTTYPES_H + * + * Or on the command line during compile: + * + * cc -DSHA2_USE_INTTYPES_H ... + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#else /* SHA2_USE_INTTYPES_H */ + +typedef struct _SHA256_CTX { + u_int32_t state[8]; + u_int64_t bitcount; + u_int8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#endif /* SHA2_USE_INTTYPES_H */ + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ + +void SHA256_Init __P((SHA256_CTX *)); +void SHA256_Update __P((SHA256_CTX*, const u_int8_t*, size_t)); +void SHA256_Final __P((u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*)); +char* SHA256_End __P((SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH])); +char* SHA256_Data __P((const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH])); + +void SHA384_Init __P((SHA384_CTX*)); +void SHA384_Update __P((SHA384_CTX*, const u_int8_t*, size_t)); +void SHA384_Final __P((u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*)); +char* SHA384_End __P((SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH])); +char* SHA384_Data __P((const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH])); + +void SHA512_Init __P((SHA512_CTX*)); +void SHA512_Update __P((SHA512_CTX*, const u_int8_t*, size_t)); +void SHA512_Final __P((u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*)); +char* SHA512_End __P((SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH])); +char* SHA512_Data __P((const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH])); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index 0e3b6a3..6223bad 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -209,6 +209,32 @@ pfctlinput(cmd, sa) (*pr->pr_ctlinput)(cmd, sa, (void *)0); } +void +pfctlinput2(cmd, sa, ctlparam) + int cmd; + struct sockaddr *sa; + void *ctlparam; +{ + struct domain *dp; + struct protosw *pr; + + if (!sa) + return; + for (dp = domains; dp; dp = dp->dom_next) { + /* + * the check must be made by xx_ctlinput() anyways, to + * make sure we use data item pointed to by ctlparam in + * correct way. the following check is made just for safety. + */ + if (dp->dom_family != sa->sa_family) + continue; + + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) + if (pr->pr_ctlinput) + (*pr->pr_ctlinput)(cmd, sa, ctlparam); + } +} + static void pfslowtimo(arg) void *arg; diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index df9db28..b30975b 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -570,15 +570,6 @@ m_freem(struct mbuf *m) if (m == NULL) return; do { - /* - * we do need to check non-first mbuf, since some of existing - * code does not call M_PREPEND properly. - * (example: call to bpf_mtap from drivers) - */ - if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.aux) { - m_freem(m->m_pkthdr.aux); - m->m_pkthdr.aux = NULL; - } MFREE(m, n); m = n; } while (m); diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c index b00bf7f..f2ce41f 100644 --- a/sys/kern/uipc_mbuf2.c +++ b/sys/kern/uipc_mbuf2.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: uipc_mbuf2.c,v 1.15 2000/02/22 14:01:37 itojun Exp $ */ +/* $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun Exp $ */ /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */ /* @@ -75,6 +75,9 @@ #include <sys/mbuf.h> #include <sys/mutex.h> +/* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */ +static struct mbuf *m_dup1 __P((struct mbuf *, int, int, int)); + /* * ensure that [off, off + len) is contiguous on the mbuf chain "m". * packet chain before "off" is kept untouched. @@ -125,20 +128,47 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp) } /* + * XXX: This code is flawed because it considers a "writable" mbuf + * data region to require all of the following: + * (i) mbuf _has_ to have M_EXT set; if it is just a regular + * mbuf, it is still not considered "writable." + * (ii) since mbuf has M_EXT, the ext_type _has_ to be + * EXT_CLUSTER. Anything else makes it non-writable. + * (iii) M_WRITABLE() must evaluate true. + * Ideally, the requirement should only be (iii). + * + * If we're writable, we're sure we're writable, because the ref. count + * cannot increase from 1, as that would require posession of mbuf + * n by someone else (which is impossible). However, if we're _not_ + * writable, we may eventually become writable )if the ref. count drops + * to 1), but we'll fail to notice it unless we re-evaluate + * M_WRITABLE(). For now, we only evaluate once at the beginning and + * live with this. + */ + /* + * XXX: This is dumb. If we're just a regular mbuf with no M_EXT, + * then we're not "writable," according to this code. + */ + writable = 0; + if ((n->m_flags & M_EXT) == 0 || + (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n))) + writable = 1; + + /* * the target data is on <n, off>. * if we got enough data on the mbuf "n", we're done. */ - if ((off == 0 || offp) && len <= n->m_len - off) + if ((off == 0 || offp) && len <= n->m_len - off && writable) goto ok; /* - * when len < n->m_len - off and off != 0, it is a special case. + * when len <= n->m_len - off and off != 0, it is a special case. * len bytes from <n, off> sits in single mbuf, but the caller does * not like the starting position (off). * chop the current mbuf into two pieces, set off to 0. */ - if (len < n->m_len - off) { - o = m_copym(n, off, n->m_len - off, M_DONTWAIT); + if (len <= n->m_len - off) { + o = m_dup1(n, off, n->m_len - off, M_DONTWAIT); if (o == NULL) { m_freem(m); return NULL; /* ENOBUFS */ @@ -175,33 +205,6 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp) * easy cases first. * we need to use m_copydata() to get data from <n->m_next, 0>. */ - /* - * XXX: This code is flawed because it considers a "writable" mbuf - * data region to require all of the following: - * (i) mbuf _has_ to have M_EXT set; if it is just a regular - * mbuf, it is still not considered "writable." - * (ii) since mbuf has M_EXT, the ext_type _has_ to be - * EXT_CLUSTER. Anything else makes it non-writable. - * (iii) M_WRITABLE() must evaluate true. - * Ideally, the requirement should only be (iii). - * - * If we're writable, we're sure we're writable, because the ref. count - * cannot increase from 1, as that would require posession of mbuf - * n by someone else (which is impossible). However, if we're _not_ - * writable, we may eventually become writable )if the ref. count drops - * to 1), but we'll fail to notice it unless we re-evaluate - * M_WRITABLE(). For now, we only evaluate once at the beginning and - * live with this. - */ - /* - * XXX: This is dumb. If we're just a regular mbuf with no M_EXT, - * then we're not "writable," according to this code. - */ - writable = 0; - if ((n->m_flags & M_EXT) && (n->m_ext.ext_type == EXT_CLUSTER) && - M_WRITABLE(n)) - writable = 1; - if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen && writable) { m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len); @@ -225,18 +228,17 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp) * on both end. */ MGET(o, M_DONTWAIT, m->m_type); - if (o == NULL) { - m_freem(m); - return NULL; /* ENOBUFS */ - } - if (len > MHLEN) { /* use MHLEN just for safety */ + if (o && len > MLEN) { MCLGET(o, M_DONTWAIT); if ((o->m_flags & M_EXT) == 0) { - m_freem(m); m_free(o); - return NULL; /* ENOBUFS */ + o = NULL; } } + if (!o) { + m_freem(m); + return NULL; /* ENOBUFS */ + } /* get hlen from <n, off> into <o, 0> */ o->m_len = hlen; bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen); @@ -265,12 +267,46 @@ ok: return n; } +static struct mbuf * +m_dup1(struct mbuf *m, int off, int len, int wait) +{ + struct mbuf *n; + int l; + int copyhdr; + + if (len > MCLBYTES) + return NULL; + if (off == 0 && (m->m_flags & M_PKTHDR) != 0) { + copyhdr = 1; + MGETHDR(n, wait, m->m_type); + l = MHLEN; + } else { + copyhdr = 0; + MGET(n, wait, m->m_type); + l = MLEN; + } + if (n && len > l) { + MCLGET(n, wait); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) + return NULL; + + if (copyhdr) + M_COPY_PKTHDR(n, m); + m_copydata(m, off, len, mtod(n, caddr_t)); + return n; +} + /* * pkthdr.aux chain manipulation. * we don't allow clusters at this moment. */ struct mbuf * -m_aux_add(struct mbuf *m, int af, int type) +m_aux_add2(struct mbuf *m, int af, int type, void *p) { struct mbuf *n; struct mauxtag *t; @@ -287,8 +323,10 @@ m_aux_add(struct mbuf *m, int af, int type) return NULL; t = mtod(n, struct mauxtag *); + bzero(t, sizeof(*t)); t->af = af; t->type = type; + t->p = p; n->m_data += sizeof(struct mauxtag); n->m_len = 0; n->m_next = m->m_pkthdr.aux; @@ -297,7 +335,7 @@ m_aux_add(struct mbuf *m, int af, int type) } struct mbuf * -m_aux_find(struct mbuf *m, int af, int type) +m_aux_find2(struct mbuf *m, int af, int type, void *p) { struct mbuf *n; struct mauxtag *t; @@ -307,12 +345,30 @@ m_aux_find(struct mbuf *m, int af, int type) for (n = m->m_pkthdr.aux; n; n = n->m_next) { t = (struct mauxtag *)n->m_dat; - if (t->af == af && t->type == type) + if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) { + printf("m_aux_find: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data); + continue; + } + if (t->af == af && t->type == type && t->p == p) return n; } return NULL; } +struct mbuf * +m_aux_find(struct mbuf *m, int af, int type) +{ + + return m_aux_find2(m, af, type, NULL); +} + +struct mbuf * +m_aux_add(struct mbuf *m, int af, int type) +{ + + return m_aux_add2(m, af, type, NULL); +} + void m_aux_delete(struct mbuf *m, struct mbuf *victim) { @@ -327,6 +383,12 @@ m_aux_delete(struct mbuf *m, struct mbuf *victim) while (n) { t = (struct mauxtag *)n->m_dat; next = n->m_next; + if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) { + printf("m_aux_delete: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data); + prev = n; + n = next; + continue; + } if (n == victim) { if (prev) prev->m_next = n->m_next; diff --git a/sys/net/if.c b/sys/net/if.c index f98d85e..f52d74d 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -269,7 +269,7 @@ if_detach(ifp) #endif /* INET */ #ifdef INET6 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { - in6_purgeaddr(ifa, ifp); + in6_purgeaddr(ifa); /* ifp_addrhead is already updated */ continue; } @@ -278,6 +278,16 @@ if_detach(ifp) IFAFREE(ifa); } +#ifdef INET6 + /* + * Remove all IPv6 kernel structs related to ifp. This should be done + * before removing routing entries below, since IPv6 interface direct + * routes are expected to be removed by the IPv6-specific kernel API. + * Otherwise, the kernel will detect some inconsistency and bark it. + */ + in6_ifdetach(ifp); +#endif + /* * Delete all remaining routes using this interface * Unfortuneatly the only way to do this is to slog through @@ -290,11 +300,6 @@ if_detach(ifp) (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); } -#ifdef INET6 - /* nuke all IPv6 kernel structs related to ifp */ - in6_ifdetach(ifp); -#endif - TAILQ_REMOVE(&ifnet, ifp, if_link); mtx_destroy(&ifp->if_snd.ifq_mtx); splx(s); @@ -897,6 +902,7 @@ ifioctl(so, cmd, data, p) #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif + case SIOCSLIFPHYADDR: case SIOCSIFMEDIA: case SIOCSIFGENERIC: error = suser(p); @@ -913,6 +919,9 @@ ifioctl(so, cmd, data, p) ifs = (struct ifstat *)data; ifs->ascii[0] = '\0'; + case SIOCGIFPSRCADDR: + case SIOCGIFPDSTADDR: + case SIOCGLIFPHYADDR: case SIOCGIFMEDIA: case SIOCGIFGENERIC: if (ifp->if_ioctl == 0) diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c index b28fecd..840b77b 100644 --- a/sys/net/if_faith.c +++ b/sys/net/if_faith.c @@ -1,3 +1,5 @@ +/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $ */ + /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -41,30 +43,58 @@ /* * Loopback interface driver for protocol testing and timing. */ +#include "opt_inet.h" +#include "opt_inet6.h" #include "faith.h" +#if NFAITH > 0 #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/mbuf.h> #include <sys/socket.h> +#include <sys/errno.h> #include <sys/sockio.h> +#include <sys/time.h> +#include <sys/queue.h> #include <net/if.h> #include <net/if_types.h> #include <net/netisr.h> #include <net/route.h> #include <net/bpf.h> +#include <net/if_faith.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#endif + +#include "bpf.h" +#define NBPFILTER NBPF #include <net/net_osdep.h> -extern int loioctl __P((struct ifnet *, u_long, caddr_t)); -extern int looutput __P((struct ifnet *ifp, - struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)); +static int faithioctl __P((struct ifnet *, u_long, caddr_t)); +int faithoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *)); +static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *)); void faithattach __P((void *)); PSEUDO_SET(faithattach, if_faith); + static struct ifnet faithif[NFAITH]; #define FAITHMTU 1500 @@ -74,8 +104,8 @@ void faithattach(faith) void *faith; { - register struct ifnet *ifp; - register int i; + struct ifnet *ifp; + int i; for (i = 0; i < NFAITH; i++) { ifp = &faithif[i]; @@ -85,13 +115,210 @@ faithattach(faith) ifp->if_mtu = FAITHMTU; /* LOOPBACK commented out to announce IPv6 routes to faith */ ifp->if_flags = /* IFF_LOOPBACK | */ IFF_MULTICAST; - ifp->if_ioctl = loioctl; - ifp->if_output = looutput; + ifp->if_ioctl = faithioctl; + ifp->if_output = faithoutput; ifp->if_type = IFT_FAITH; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_hdrlen = 0; ifp->if_addrlen = 0; if_attach(ifp); +#if NBPFILTER > 0 +#ifdef HAVE_OLD_BPF bpfattach(ifp, DLT_NULL, sizeof(u_int)); +#else + bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); +#endif +#endif + } +} + +int +faithoutput(ifp, m, dst, rt) + struct ifnet *ifp; + struct mbuf *m; + struct sockaddr *dst; + struct rtentry *rt; +{ + int isr; + struct ifqueue *ifq = 0; + + if ((m->m_flags & M_PKTHDR) == 0) + panic("faithoutput no HDR"); +#if NBPFILTER > 0 + /* BPF write needs to be handled specially */ + if (dst->sa_family == AF_UNSPEC) { + dst->sa_family = *(mtod(m, int *)); + m->m_len -= sizeof(int); + m->m_pkthdr.len -= sizeof(int); + m->m_data += sizeof(int); } + + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a faith header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + u_int32_t af = dst->sa_family; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + +#ifdef HAVE_OLD_BPF + bpf_mtap(ifp, &m0); +#else + bpf_mtap(ifp->if_bpf, &m0); +#endif + } +#endif + + if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { + m_freem(m); + return (rt->rt_flags & RTF_BLACKHOLE ? 0 : + rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + } + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + switch (dst->sa_family) { +#ifdef INET + case AF_INET: + ifq = &ipintrq; + isr = NETISR_IP; + break; +#endif +#ifdef INET6 + case AF_INET6: + ifq = &ip6intrq; + isr = NETISR_IPV6; + break; +#endif + default: + m_freem(m); + return EAFNOSUPPORT; + } + + /* XXX do we need more sanity checks? */ + + m->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + (void) IF_HANDOFF(ifq, m, NULL); + schednetisr(isr); + return (0); +} + +/* ARGSUSED */ +static void +faithrtrequest(cmd, rt, sa) + int cmd; + struct rtentry *rt; + struct sockaddr *sa; +{ + if (rt) { + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ + /* + * For optimal performance, the send and receive buffers + * should be at least twice the MTU plus a little more for + * overhead. + */ + rt->rt_rmx.rmx_recvpipe = + rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU; + } +} + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +static int +faithioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct ifaddr *ifa; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP | IFF_RUNNING; + ifa = (struct ifaddr *)data; + ifa->ifa_rtrequest = faithrtrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; /* XXX */ + break; + } + switch (ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: + break; +#endif +#ifdef INET6 + case AF_INET6: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + +#ifdef SIOCSIFMTU + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; +#endif + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + } + return (error); +} + +/* + * XXX could be slow + * XXX could be layer violation to call sys/net from sys/netinet6 + */ +int +faithprefix(in6) + struct in6_addr *in6; +{ + struct rtentry *rt; + struct sockaddr_in6 sin6; + int ret; + + if (ip6_keepfaith == 0) + return 0; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *in6; + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); + if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && + (rt->rt_ifp->if_flags & IFF_UP) != 0) + ret = 1; + else + ret = 0; + if (rt) + RTFREE(rt); + return ret; } +#endif /* NFAITH > 0 */ diff --git a/sys/net/if_faith.h b/sys/net/if_faith.h new file mode 100644 index 0000000..1e30bfb --- /dev/null +++ b/sys/net/if_faith.h @@ -0,0 +1,41 @@ +/* $FreeBSD$ */ +/* $KAME: if_faith.h,v 1.1 2000/07/26 05:49:21 itojun Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_FAITH_H_ +#define _NET_IF_FAITH_H_ + +#ifdef _KERNEL +struct in6_addr; +int faithprefix __P((struct in6_addr *)); +#endif + +#endif /* _NET_IF_FAITH_H_ */ diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 68031cb..465063c 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */ +/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -52,11 +52,11 @@ #include <net/route.h> #include <net/bpf.h> -#ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> -#include <netinet/in_var.h> #include <netinet/ip.h> +#ifdef INET +#include <netinet/in_var.h> #include <netinet/in_gif.h> #endif /* INET */ @@ -114,11 +114,11 @@ void gifattach(dummy) void *dummy; { - register struct gif_softc *sc; - register int i; + struct gif_softc *sc; + int i; ngif = NGIF; - gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); + gif = sc = malloc(ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); bzero(sc, ngif * sizeof(struct gif_softc)); for (i = 0; i < ngif; sc++, i++) { sc->gif_if.if_name = "gif"; @@ -148,6 +148,10 @@ gifattach(dummy) sc->gif_if.if_mtu = GIF_MTU; sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; +#if 0 + /* turn off ingress filter */ + sc->gif_if.if_flags |= IFF_LINK2; +#endif sc->gif_if.if_ioctl = gif_ioctl; sc->gif_if.if_output = gif_output; sc->gif_if.if_type = IFT_GIF; @@ -229,7 +233,7 @@ gif_output(ifp, m, dst, rt) struct sockaddr *dst; struct rtentry *rt; /* added in net2 */ { - register struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = (struct gif_softc*)ifp; int error = 0; static int called = 0; /* XXX: MUTEX */ @@ -268,7 +272,7 @@ gif_output(ifp, m, dst, rt) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = dst->sa_family; + u_int32_t af = dst->sa_family; m0.m_next = m; m0.m_len = 4; @@ -284,8 +288,11 @@ gif_output(ifp, m, dst, rt) ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; + /* inner AF-specific encapsulation */ + /* XXX should we check if our outer source is legal? */ + /* dispatch to output logic based on outer AF */ switch (sc->gif_psrc->sa_family) { #ifdef INET case AF_INET: @@ -300,11 +307,13 @@ gif_output(ifp, m, dst, rt) default: m_freem(m); error = ENETDOWN; + goto end; } end: called = 0; /* reset recursion counter */ - if (error) ifp->if_oerrors++; + if (error) + ifp->if_oerrors++; return error; } @@ -315,7 +324,7 @@ gif_input(m, af, gifp) struct ifnet *gifp; { int isr; - register struct ifqueue *ifq = 0; + struct ifqueue *ifq = 0; if (gifp == NULL) { /* just in case */ @@ -335,11 +344,11 @@ gif_input(m, af, gifp) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = AF_INET6; + u_int32_t af1 = af; m0.m_next = m; m0.m_len = 4; - m0.m_data = (char *)⁡ + m0.m_data = (char *)&af1; #ifdef HAVE_OLD_BPF bpf_mtap(gifp, &m0); @@ -435,13 +444,16 @@ gif_ioctl(ifp, cmd, data) #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif /* INET6 */ + case SIOCSLIFPHYADDR: switch (cmd) { +#ifdef INET case SIOCSIFPHYADDR: src = (struct sockaddr *) &(((struct in_aliasreq *)data)->ifra_addr); dst = (struct sockaddr *) &(((struct in_aliasreq *)data)->ifra_dstaddr); break; +#endif #ifdef INET6 case SIOCSIFPHYADDR_IN6: src = (struct sockaddr *) @@ -450,6 +462,66 @@ gif_ioctl(ifp, cmd, data) &(((struct in6_aliasreq *)data)->ifra_dstaddr); break; #endif + case SIOCSLIFPHYADDR: + src = (struct sockaddr *) + &(((struct if_laddrreq *)data)->addr); + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->dstaddr); + } + + /* sa_family must be equal */ + if (src->sa_family != dst->sa_family) + return EINVAL; + + /* validate sa_len */ + switch (src->sa_family) { +#ifdef INET + case AF_INET: + if (src->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (src->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + break; +#endif + default: + return EAFNOSUPPORT; + } + switch (dst->sa_family) { +#ifdef INET + case AF_INET: + if (dst->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (dst->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + break; +#endif + default: + return EAFNOSUPPORT; + } + + /* check sa_family looks sane for the cmd */ + switch (cmd) { + case SIOCSIFPHYADDR: + if (src->sa_family == AF_INET) + break; + return EAFNOSUPPORT; +#ifdef INET6 + case SIOCSIFPHYADDR_IN6: + if (src->sa_family == AF_INET6) + break; + return EAFNOSUPPORT; +#endif /* INET6 */ + case SIOCSLIFPHYADDR: + /* checks done in the above */ + break; } for (i = 0; i < ngif; i++) { @@ -493,41 +565,16 @@ gif_ioctl(ifp, cmd, data) #endif } - if (src->sa_family != dst->sa_family || - src->sa_len != dst->sa_len) { - error = EINVAL; - break; - } - switch (src->sa_family) { -#ifdef INET - case AF_INET: - size = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - size = sizeof(struct sockaddr_in6); - break; -#endif - default: - error = EAFNOSUPPORT; - goto bad; - } - if (src->sa_len != size) { - error = EINVAL; - break; - } - if (sc->gif_psrc) free((caddr_t)sc->gif_psrc, M_IFADDR); - sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); - bcopy((caddr_t)src, (caddr_t)sa, size); + sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); + bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); sc->gif_psrc = sa; if (sc->gif_pdst) free((caddr_t)sc->gif_pdst, M_IFADDR); - sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); - bcopy((caddr_t)dst, (caddr_t)sa, size); + sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); + bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); sc->gif_pdst = sa; ifp->if_flags |= IFF_RUNNING; @@ -548,7 +595,7 @@ gif_ioctl(ifp, cmd, data) free((caddr_t)sc->gif_pdst, M_IFADDR); sc->gif_pdst = NULL; } - /* change the IFF_UP flag as well? */ + /* change the IFF_{UP, RUNNING} flag as well? */ break; #endif @@ -561,25 +608,27 @@ gif_ioctl(ifp, cmd, data) goto bad; } src = sc->gif_psrc; - switch (sc->gif_psrc->sa_family) { + switch (cmd) { #ifdef INET - case AF_INET: + case SIOCGIFPSRCADDR: dst = &ifr->ifr_addr; - size = sizeof(struct sockaddr_in); + size = sizeof(ifr->ifr_addr); break; #endif /* INET */ #ifdef INET6 - case AF_INET6: + case SIOCGIFPSRCADDR_IN6: dst = (struct sockaddr *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(struct sockaddr_in6); + size = sizeof(((struct in6_ifreq *)data)->ifr_addr); break; #endif /* INET6 */ default: error = EADDRNOTAVAIL; goto bad; } - bcopy((caddr_t)src, (caddr_t)dst, size); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); break; case SIOCGIFPDSTADDR: @@ -591,25 +640,52 @@ gif_ioctl(ifp, cmd, data) goto bad; } src = sc->gif_pdst; - switch (sc->gif_pdst->sa_family) { + switch (cmd) { #ifdef INET - case AF_INET: + case SIOCGIFPDSTADDR: dst = &ifr->ifr_addr; - size = sizeof(struct sockaddr_in); + size = sizeof(ifr->ifr_addr); break; #endif /* INET */ #ifdef INET6 - case AF_INET6: + case SIOCGIFPDSTADDR_IN6: dst = (struct sockaddr *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(struct sockaddr_in6); + size = sizeof(((struct in6_ifreq *)data)->ifr_addr); break; #endif /* INET6 */ default: error = EADDRNOTAVAIL; goto bad; } - bcopy((caddr_t)src, (caddr_t)dst, size); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + break; + + case SIOCGLIFPHYADDR: + if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { + error = EADDRNOTAVAIL; + goto bad; + } + + /* copy src */ + src = sc->gif_psrc; + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->addr); + size = sizeof(((struct if_laddrreq *)data)->addr); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + + /* copy dst */ + src = sc->gif_pdst; + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->dstaddr); + size = sizeof(((struct if_laddrreq *)data)->dstaddr); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); break; case SIOCSIFFLAGS: diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index 3699286..3978e7b 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if_gif.h,v 1.13 2000/06/17 20:34:24 itojun Exp $ */ +/* $KAME: if_gif.h,v 1.17 2000/09/11 11:36:41 sumikawa Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -38,11 +38,9 @@ #define _NET_IF_GIF_H_ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #if defined(_KERNEL) && !defined(_LKM) #include "opt_inet.h" #endif -#endif #include <netinet/in.h> /* xxx sigh, why route have struct route instead of pointer? */ diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 0e9ac65..f8e11f7 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -58,6 +58,7 @@ #include <net/netisr.h> #include <net/route.h> #include <net/bpf.h> +#include <net/bpfdesc.h> #ifdef INET #include <netinet/in.h> @@ -236,6 +237,8 @@ looutput(ifp, m, dst, rt) m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); n->m_pkthdr = m->m_pkthdr; n->m_len = m->m_pkthdr.len; + n->m_pkthdr.aux = m->m_pkthdr.aux; + m->m_pkthdr.aux = (struct mbuf *)NULL; m_freem(m); m = n; } @@ -277,7 +280,7 @@ contiguousfail: int if_simloop(ifp, m, af, hlen) struct ifnet *ifp; - register struct mbuf *m; + struct mbuf *m; int af; int hlen; { @@ -300,17 +303,19 @@ if_simloop(ifp, m, af, hlen) if (ifp->if_bpf) { struct mbuf m0, *n = m; - /* - * We need to prepend the address family as - * a four byte field. Cons up a dummy header - * to pacify bpf. This is safe because bpf - * will only read from the mbuf (i.e., it won't - * try to free it or keep a pointer a to it). - */ - m0.m_next = m; - m0.m_len = 4; - m0.m_data = (char *)⁡ - n = &m0; + if (ifp->if_bpf->bif_dlt == DLT_NULL) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + n = &m0; + } bpf_mtap(ifp, n); } diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h index 84fede3..0c2a201 100644 --- a/sys/net/if_sppp.h +++ b/sys/net/if_sppp.h @@ -39,6 +39,7 @@ struct slcp { }; #define IDX_IPCP 1 /* idx into state table */ +#define IDX_IPV6CP 2 /* idx into state table */ struct sipcp { u_long opts; /* IPCP options to send (bitfield) */ @@ -46,6 +47,10 @@ struct sipcp { #define IPCP_HISADDR_SEEN 1 /* have seen his address already */ #define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ #define IPCP_MYADDR_SEEN 4 /* have seen his address already */ +#ifdef notdef +#define IPV6CP_MYIFID_DYN 2 /* my ifid is dynamically assigned */ +#endif +#define IPV6CP_MYIFID_SEEN 4 /* have seen his ifid already */ }; #define AUTHNAMELEN 32 @@ -62,8 +67,8 @@ struct sauth { u_char challenge[AUTHKEYLEN]; /* random challenge */ }; -#define IDX_PAP 2 -#define IDX_CHAP 3 +#define IDX_PAP 3 +#define IDX_CHAP 4 #define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ @@ -87,8 +92,8 @@ struct sppp { u_int pp_flags; /* sub modes */ u_short pp_alivecnt; /* keepalive packets counter */ u_short pp_loopcnt; /* loopback detection counter */ - u_long pp_seq; /* local sequence number */ - u_long pp_rseq; /* remote sequence number */ + u_long pp_seq[IDX_COUNT]; /* local sequence number */ + u_long pp_rseq[IDX_COUNT]; /* remote sequence number */ enum ppp_phase pp_phase; /* phase we're currently in */ int state[IDX_COUNT]; /* state machine */ u_char confid[IDX_COUNT]; /* id of last configuration request */ @@ -98,6 +103,7 @@ struct sppp { struct callout_handle pap_my_to_ch; /* PAP needs one more... */ struct slcp lcp; /* LCP params */ struct sipcp ipcp; /* IPCP params */ + struct sipcp ipv6cp; /* IPv6CP params */ struct sauth myauth; /* auth params, i'm peer */ struct sauth hisauth; /* auth params, i'm authenticator */ /* diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 6928c95..e489c58 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -135,10 +135,12 @@ #define PPP_ISO 0x0023 /* ISO OSI Protocol */ #define PPP_XNS 0x0025 /* Xerox NS Protocol */ #define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_IPV6 0x0057 /* Internet Protocol Version 6 */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ #define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define CONF_REQ 1 /* PPP configure request */ #define CONF_ACK 2 /* PPP configure acknowledge */ @@ -165,6 +167,9 @@ #define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ #define IPCP_OPT_ADDRESS 3 /* local IP address */ +#define IPV6CP_OPT_IFID 1 /* interface identifier */ +#define IPV6CP_OPT_COMPRESSION 2 /* IPv6 compression protocol */ + #define PAP_REQ 1 /* PAP name/password request */ #define PAP_ACK 2 /* PAP acknowledge */ #define PAP_NAK 3 /* PAP fail */ @@ -340,6 +345,21 @@ static void sppp_ipcp_tls(struct sppp *sp); static void sppp_ipcp_tlf(struct sppp *sp); static void sppp_ipcp_scr(struct sppp *sp); +static void sppp_ipv6cp_init(struct sppp *sp); +static void sppp_ipv6cp_up(struct sppp *sp); +static void sppp_ipv6cp_down(struct sppp *sp); +static void sppp_ipv6cp_open(struct sppp *sp); +static void sppp_ipv6cp_close(struct sppp *sp); +static void sppp_ipv6cp_TO(void *sp); +static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len); +static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); +static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); +static void sppp_ipv6cp_tlu(struct sppp *sp); +static void sppp_ipv6cp_tld(struct sppp *sp); +static void sppp_ipv6cp_tls(struct sppp *sp); +static void sppp_ipv6cp_tlf(struct sppp *sp); +static void sppp_ipv6cp_scr(struct sppp *sp); + static void sppp_pap_input(struct sppp *sp, struct mbuf *m); static void sppp_pap_init(struct sppp *sp); static void sppp_pap_open(struct sppp *sp); @@ -363,6 +383,9 @@ static const char *sppp_auth_type_name(u_short proto, u_char type); static const char *sppp_cp_type_name(u_char type); static const char *sppp_dotted_quad(u_long addr); static const char *sppp_ipcp_opt_name(u_char opt); +#ifdef INET6 +static const char *sppp_ipv6cp_opt_name(u_char opt); +#endif static const char *sppp_lcp_opt_name(u_char opt); static const char *sppp_phase_name(enum ppp_phase phase); static const char *sppp_proto_name(u_short proto); @@ -377,6 +400,15 @@ static void sppp_print_bytes(const u_char *p, u_short len); static void sppp_print_string(const char *p, u_short len); static void sppp_qflush(struct ifqueue *ifq); static void sppp_set_ip_addr(struct sppp *sp, u_long src); +#ifdef INET6 +static void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, + struct in6_addr *dst, struct in6_addr *srcmask); +#ifdef IPV6CP_MYIFID_DYN +static void sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src); +static void sppp_gen_ip6_addr(struct sppp *sp, const struct in6_addr *src); +#endif +static void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src); +#endif /* our control protocol descriptors */ static const struct cp lcp = { @@ -395,6 +427,20 @@ static const struct cp ipcp = { sppp_ipcp_scr }; +static const struct cp ipv6cp = { + PPP_IPV6CP, IDX_IPV6CP, +#ifdef INET6 /*don't run IPv6CP if there's no IPv6 support*/ + CP_NCP, +#else + 0, +#endif + "ipv6cp", + sppp_ipv6cp_up, sppp_ipv6cp_down, sppp_ipv6cp_open, sppp_ipv6cp_close, + sppp_ipv6cp_TO, sppp_ipv6cp_RCR, sppp_ipv6cp_RCN_rej, sppp_ipv6cp_RCN_nak, + sppp_ipv6cp_tlu, sppp_ipv6cp_tld, sppp_ipv6cp_tls, sppp_ipv6cp_tlf, + sppp_ipv6cp_scr +}; + static const struct cp pap = { PPP_PAP, IDX_PAP, CP_AUTH, "pap", sppp_null, sppp_null, sppp_pap_open, sppp_pap_close, @@ -414,6 +460,7 @@ static const struct cp chap = { static const struct cp *cps[IDX_COUNT] = { &lcp, /* IDX_LCP */ &ipcp, /* IDX_IPCP */ + &ipv6cp, /* IDX_IPV6CP */ &pap, /* IDX_PAP */ &chap, /* IDX_CHAP */ }; @@ -499,7 +546,7 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) h->address, h->control, ntohs(h->protocol)); if (sp->state[IDX_LCP] == STATE_OPENED) sppp_cp_send (sp, PPP_LCP, PROTO_REJ, - ++sp->pp_seq, m->m_pkthdr.len + 2, + ++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2, &h->protocol); ++ifp->if_noproto; goto drop; @@ -530,6 +577,20 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) } break; #endif +#ifdef INET6 + case PPP_IPV6CP: + if (sp->pp_phase == PHASE_NETWORK) + sppp_cp_input(&ipv6cp, sp, m); + m_freem (m); + return; + + case PPP_IPV6: + if (sp->state[IDX_IPV6CP] == STATE_OPENED) { + schednetisr (NETISR_IPV6); + inq = &ip6intrq; + } + break; +#endif #ifdef IPX case PPP_IPX: /* IPX IPXCP not implemented yet */ @@ -628,7 +689,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, { struct sppp *sp = (struct sppp*) ifp; struct ppp_header *h; - struct ifqueue *ifq; + struct ifqueue *ifq = NULL; int s, rv = 0; int debug = ifp->if_flags & IFF_DEBUG; @@ -652,7 +713,6 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, s = splimp(); } - ifq = &ifp->if_snd; #ifdef INET if (dst->sa_family == AF_INET) { /* XXX Check mbuf length here? */ @@ -699,6 +759,12 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, } #endif +#ifdef INET6 + if (dst->sa_family == AF_INET6) { + /* XXX do something tricky here? */ + } +#endif + /* * Prepend general data packet PPP header. For now, IP only. */ @@ -750,7 +816,18 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, if (sp->pp_mode == IFF_CISCO) h->protocol = htons (ETHERTYPE_IPV6); else { - goto nosupport; + /* + * Don't choke with an ENETDOWN early. It's + * possible that we just started dialing out, + * so don't drop the packet immediately. If + * we notice that we run out of buffer space + * below, we will however remember that we are + * not ready to carry IP packets, and return + * ENETDOWN, as opposed to ENOBUFS. + */ + h->protocol = htons(PPP_IPV6); + if (sp->state[IDX_IPV6CP] != STATE_OPENED) + rv = ENETDOWN; } break; #endif @@ -812,8 +889,8 @@ sppp_attach(struct ifnet *ifp) sp->pp_cpq.ifq_maxlen = 20; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; - sp->pp_seq = 0; - sp->pp_rseq = 0; + bzero(&sp->pp_seq[0], sizeof(sp->pp_seq)); + bzero(&sp->pp_rseq[0], sizeof(sp->pp_rseq)); sp->pp_phase = PHASE_DEAD; sp->pp_up = lcp.Up; sp->pp_down = lcp.Down; @@ -822,6 +899,7 @@ sppp_attach(struct ifnet *ifp) sppp_lcp_init(sp); sppp_ipcp_init(sp); + sppp_ipv6cp_init(sp); sppp_pap_init(sp); sppp_chap_init(sp); } @@ -1079,8 +1157,8 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m) break; case CISCO_KEEPALIVE_REQ: sp->pp_alivecnt = 0; - sp->pp_rseq = ntohl (h->par1); - if (sp->pp_seq == sp->pp_rseq) { + sp->pp_rseq[IDX_LCP] = ntohl (h->par1); + if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) { /* Local and remote sequence numbers are equal. * Probably, the line is in loopback mode. */ if (sp->pp_loopcnt >= MAXALIVECNT) { @@ -1096,9 +1174,9 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m) /* Generate new local sequence number */ #if defined(__FreeBSD__) && __FreeBSD__ >= 3 - sp->pp_seq = random(); + sp->pp_seq[IDX_LCP] = random(); #else - sp->pp_seq ^= time.tv_sec ^ time.tv_usec; + sp->pp_seq[IDX_LCP] ^= time.tv_sec ^ time.tv_usec; #endif break; } @@ -1574,8 +1652,8 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) if (debug) log(-1, SPP_FMT "%s send code-rej for 0x%x\n", SPP_ARGS(ifp), cp->name, h->type); - sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, - m->m_pkthdr.len, h); + sppp_cp_send(sp, cp->proto, CODE_REJ, + ++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h); ++ifp->if_ierrors; } } @@ -1730,7 +1808,8 @@ sppp_close_event(const struct cp *cp, struct sppp *sp) case STATE_ACK_RCVD: case STATE_ACK_SENT: sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; - sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); + sppp_cp_send(sp, cp->proto, TERM_REQ, + ++sp->pp_seq[cp->protoidx], 0, 0); sppp_cp_change_state(cp, sp, STATE_CLOSING); break; } @@ -1772,8 +1851,8 @@ sppp_to_event(const struct cp *cp, struct sppp *sp) switch (sp->state[cp->protoidx]) { case STATE_CLOSING: case STATE_STOPPING: - sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, - 0, 0); + sppp_cp_send(sp, cp->proto, TERM_REQ, + ++sp->pp_seq[cp->protoidx], 0, 0); TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, sp->ch[cp->protoidx]); break; @@ -1835,6 +1914,8 @@ sppp_lcp_init(struct sppp *sp) sp->lcp.magic = 0; sp->state[IDX_LCP] = STATE_INITIAL; sp->fail_counter[IDX_LCP] = 0; + sp->pp_seq[IDX_LCP] = 0; + sp->pp_rseq[IDX_LCP] = 0; sp->lcp.protos = 0; sp->lcp.mru = sp->lcp.their_mru = PP_MTU; @@ -2468,7 +2549,7 @@ sppp_lcp_scr(struct sppp *sp) opt[i++] = CHAP_MD5; } - sp->confid[IDX_LCP] = ++sp->pp_seq; + sp->confid[IDX_LCP] = ++sp->pp_seq[IDX_LCP]; sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); } @@ -2519,6 +2600,8 @@ sppp_ipcp_init(struct sppp *sp) sp->ipcp.flags = 0; sp->state[IDX_IPCP] = STATE_INITIAL; sp->fail_counter[IDX_IPCP] = 0; + sp->pp_seq[IDX_IPCP] = 0; + sp->pp_rseq[IDX_IPCP] = 0; #if defined(__FreeBSD__) && __FreeBSD__ >= 3 callout_handle_init(&sp->ch[IDX_IPCP]); #endif @@ -2894,13 +2977,516 @@ sppp_ipcp_scr(struct sppp *sp) opt[i++] = ouraddr; } - sp->confid[IDX_IPCP] = ++sp->pp_seq; + sp->confid[IDX_IPCP] = ++sp->pp_seq[IDX_IPCP]; sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); } /* *--------------------------------------------------------------------------* * * + * The IPv6CP implementation. * + * * + *--------------------------------------------------------------------------* + */ + +#ifdef INET6 +static void +sppp_ipv6cp_init(struct sppp *sp) +{ + sp->ipv6cp.opts = 0; + sp->ipv6cp.flags = 0; + sp->state[IDX_IPV6CP] = STATE_INITIAL; + sp->fail_counter[IDX_IPV6CP] = 0; + sp->pp_seq[IDX_IPV6CP] = 0; + sp->pp_rseq[IDX_IPV6CP] = 0; +#if defined(__NetBSD__) + callout_init(&sp->ch[IDX_IPV6CP]); +#endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + callout_handle_init(&sp->ch[IDX_IPV6CP]); +#endif +} + +static void +sppp_ipv6cp_up(struct sppp *sp) +{ + sppp_up_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_down(struct sppp *sp) +{ + sppp_down_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_open(struct sppp *sp) +{ + STDDCL; + struct in6_addr myaddr, hisaddr; + +#ifdef IPV6CP_MYIFID_DYN + sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN); +#else + sp->ipv6cp.flags &= ~IPV6CP_MYIFID_SEEN; +#endif + + sppp_get_ip6_addrs(sp, &myaddr, &hisaddr, 0); + /* + * If we don't have our address, this probably means our + * interface doesn't want to talk IPv6 at all. (This could + * be the case if somebody wants to speak only IPX, for + * example.) Don't open IPv6CP in this case. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) { + /* XXX this message should go away */ + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp_open(): no IPv6 interface\n", + SPP_ARGS(ifp)); + return; + } + + sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN; + sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID); + sppp_open_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_close(struct sppp *sp) +{ + sppp_close_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_TO(void *cookie) +{ + sppp_to_event(&ipv6cp, (struct sppp *)cookie); +} + +/* + * Analyze a configure request. Return true if it was agreeable, and + * caused action sca, false if it has been rejected or nak'ed, and + * caused action scn. (The return value is used to make the state + * transition decision in the state automaton.) + */ +static int +sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len) +{ + u_char *buf, *r, *p; + struct ifnet *ifp = &sp->pp_if; + int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; + struct in6_addr myaddr, desiredaddr, suggestaddr; + int ifidcount; + int type; + int collision, nohisaddr; + + len -= 4; + origlen = len; + /* + * Make sure to allocate a buf that can at least hold a + * conf-nak with an `address' option. We might need it below. + */ + buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT); + if (! buf) + return (0); + + /* pass 1: see if we can recognize them */ + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp parse opts:", + SPP_ARGS(ifp)); + p = (void*) (h+1); + ifidcount = 0; + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { + case IPV6CP_OPT_IFID: + if (len >= 10 && p[1] == 10 && ifidcount == 0) { + /* correctly formed address option */ + ifidcount++; + continue; + } + if (debug) + addlog(" [invalid]"); + break; +#ifdef notyet + case IPV6CP_OPT_COMPRESSION: + if (len >= 4 && p[1] >= 4) { + /* correctly formed compress option */ + continue; + } + if (debug) + addlog(" [invalid]"); + break; +#endif + default: + /* Others not supported. */ + if (debug) + addlog(" [rej]"); + break; + } + /* Add the option to rejected list. */ + bcopy (p, r, p[1]); + r += p[1]; + rlen += p[1]; + } + if (rlen) { + if (debug) + addlog(" send conf-rej\n"); + sppp_cp_send (sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf); + goto end; + } else if (debug) + addlog("\n"); + + /* pass 2: parse option values */ + sppp_get_ip6_addrs(sp, &myaddr, 0, 0); + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp parse opt values: ", + SPP_ARGS(ifp)); + p = (void*) (h+1); + len = origlen; + type = CONF_ACK; + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { +#ifdef notyet + case IPV6CP_OPT_COMPRESSION: + continue; +#endif + case IPV6CP_OPT_IFID: + bzero(&desiredaddr, sizeof(desiredaddr)); + bcopy(&p[2], &desiredaddr.s6_addr[8], 8); + collision = (bcmp(&desiredaddr.s6_addr[8], + &myaddr.s6_addr[8], 8) == 0); + nohisaddr = IN6_IS_ADDR_UNSPECIFIED(&desiredaddr); + + desiredaddr.s6_addr16[0] = htons(0xfe80); + desiredaddr.s6_addr16[1] = htons(sp->pp_if.if_index); + + if (!collision && !nohisaddr) { + /* no collision, hisaddr known - Conf-Ack */ + type = CONF_ACK; + + if (debug) { + addlog(" %s [%s]", + ip6_sprintf(&desiredaddr), + sppp_cp_type_name(type)); + } + continue; + } + + bzero(&suggestaddr, sizeof(&suggestaddr)); + if (collision && nohisaddr) { + /* collision, hisaddr unknown - Conf-Rej */ + type = CONF_REJ; + bzero(&p[2], 8); + } else { + /* + * - no collision, hisaddr unknown, or + * - collision, hisaddr known + * Conf-Nak, suggest hisaddr + */ + type = CONF_NAK; + sppp_suggest_ip6_addr(sp, &suggestaddr); + bcopy(&suggestaddr.s6_addr[8], &p[2], 8); + } + if (debug) + addlog(" %s [%s]", ip6_sprintf(&desiredaddr), + sppp_cp_type_name(type)); + break; + } + /* Add the option to nak'ed list. */ + bcopy (p, r, p[1]); + r += p[1]; + rlen += p[1]; + } + + if (rlen == 0 && type == CONF_ACK) { + if (debug) + addlog(" send %s\n", sppp_cp_type_name(type)); + sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, origlen, h+1); + } else { +#ifdef DIAGNOSTIC + if (type == CONF_ACK) + panic("IPv6CP RCR: CONF_ACK with non-zero rlen"); +#endif + + if (debug) { + addlog(" send %s suggest %s\n", + sppp_cp_type_name(type), ip6_sprintf(&suggestaddr)); + } + sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, rlen, buf); + } + + end: + free (buf, M_TEMP); + return (rlen == 0); +} + +/* + * Analyze the IPv6CP Configure-Reject option list, and adjust our + * negotiation. + */ +static void +sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) +{ + u_char *buf, *p; + struct ifnet *ifp = &sp->pp_if; + int debug = ifp->if_flags & IFF_DEBUG; + + len -= 4; + buf = malloc (len, M_TEMP, M_NOWAIT); + if (!buf) + return; + + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp rej opts:", + SPP_ARGS(ifp)); + + p = (void*) (h+1); + for (; len > 1 && p[1]; len -= p[1], p += p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { + case IPV6CP_OPT_IFID: + /* + * Peer doesn't grok address option. This is + * bad. XXX Should we better give up here? + */ + sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_IFID); + break; +#ifdef notyet + case IPV6CP_OPT_COMPRESS: + sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_COMPRESS); + break; +#endif + } + } + if (debug) + addlog("\n"); + free (buf, M_TEMP); + return; +} + +/* + * Analyze the IPv6CP Configure-NAK option list, and adjust our + * negotiation. + */ +static void +sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) +{ + u_char *buf, *p; + struct ifnet *ifp = &sp->pp_if; + int debug = ifp->if_flags & IFF_DEBUG; + struct in6_addr suggestaddr; + + len -= 4; + buf = malloc (len, M_TEMP, M_NOWAIT); + if (!buf) + return; + + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp nak opts:", + SPP_ARGS(ifp)); + + p = (void*) (h+1); + for (; len > 1 && p[1]; len -= p[1], p += p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { + case IPV6CP_OPT_IFID: + /* + * Peer doesn't like our local ifid. See + * if we can do something for him. We'll drop + * him our address then. + */ + if (len < 10 || p[1] != 10) + break; + bzero(&suggestaddr, sizeof(suggestaddr)); + suggestaddr.s6_addr16[0] = htons(0xfe80); + suggestaddr.s6_addr16[1] = htons(sp->pp_if.if_index); + bcopy(&p[2], &suggestaddr.s6_addr[8], 8); + + sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID); + if (debug) + addlog(" [suggestaddr %s]", + ip6_sprintf(&suggestaddr)); +#ifdef IPV6CP_MYIFID_DYN + /* + * When doing dynamic address assignment, + * we accept his offer. + */ + if (sp->ipv6cp.flags & IPV6CP_MYIFID_DYN) { + struct in6_addr lastsuggest; + /* + * If <suggested myaddr from peer> equals to + * <hisaddr we have suggested last time>, + * we have a collision. generate new random + * ifid. + */ + sppp_suggest_ip6_addr(&lastsuggest); + if (IN6_ARE_ADDR_EQUAL(&suggestaddr, + lastsuggest)) { + if (debug) + addlog(" [random]"); + sppp_gen_ip6_addr(sp, &suggestaddr); + } + sppp_set_ip6_addr(sp, &suggestaddr, 0); + if (debug) + addlog(" [agree]"); + sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN; + } +#else + /* + * Since we do not do dynamic address assignment, + * we ignore it and thus continue to negotiate + * our already existing value. This can possibly + * go into infinite request-reject loop. + * + * This is not likely because we normally use + * ifid based on MAC-address. + * If you have no ethernet card on the node, too bad. + * XXX should we use fail_counter? + */ +#endif + break; +#ifdef notyet + case IPV6CP_OPT_COMPRESS: + /* + * Peer wants different compression parameters. + */ + break; +#endif + } + } + if (debug) + addlog("\n"); + free (buf, M_TEMP); + return; +} +static void +sppp_ipv6cp_tlu(struct sppp *sp) +{ + /* we are up - notify isdn daemon */ + if (sp->pp_con) + sp->pp_con(sp); +} + +static void +sppp_ipv6cp_tld(struct sppp *sp) +{ +} + +static void +sppp_ipv6cp_tls(struct sppp *sp) +{ + /* indicate to LCP that it must stay alive */ + sp->lcp.protos |= (1 << IDX_IPV6CP); +} + +static void +sppp_ipv6cp_tlf(struct sppp *sp) +{ + +#if 0 /* need #if 0 to close IPv6CP properly */ + /* we no longer need LCP */ + sp->lcp.protos &= ~(1 << IDX_IPV6CP); + sppp_lcp_check_and_close(sp); +#endif +} + +static void +sppp_ipv6cp_scr(struct sppp *sp) +{ + char opt[10 /* ifid */ + 4 /* compression, minimum */]; + struct in6_addr ouraddr; + int i = 0; + + if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) { + sppp_get_ip6_addrs(sp, &ouraddr, 0, 0); + opt[i++] = IPV6CP_OPT_IFID; + opt[i++] = 10; + bcopy(&ouraddr.s6_addr[8], &opt[i], 8); + i += 8; + } + +#ifdef notyet + if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_COMPRESSION)) { + opt[i++] = IPV6CP_OPT_COMPRESSION; + opt[i++] = 4; + opt[i++] = 0; /* TBD */ + opt[i++] = 0; /* TBD */ + /* variable length data may follow */ + } +#endif + + sp->confid[IDX_IPV6CP] = ++sp->pp_seq[IDX_IPV6CP]; + sppp_cp_send(sp, PPP_IPV6CP, CONF_REQ, sp->confid[IDX_IPV6CP], i, &opt); +} +#else /*INET6*/ +static void sppp_ipv6cp_init(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_up(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_down(struct sppp *sp) +{ +} + + +static void sppp_ipv6cp_open(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_close(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_TO(void *sp) +{ +} + +static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len) +{ + return 0; +} + +static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) +{ +} + +static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) +{ +} + +static void sppp_ipv6cp_tlu(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_tld(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_tls(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_tlf(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_scr(struct sppp *sp) +{ +} +#endif /*INET6*/ + +/* + *--------------------------------------------------------------------------* + * * * The CHAP implementation. * * * *--------------------------------------------------------------------------* @@ -3213,6 +3799,8 @@ sppp_chap_init(struct sppp *sp) /* Chap doesn't have STATE_INITIAL at all. */ sp->state[IDX_CHAP] = STATE_CLOSED; sp->fail_counter[IDX_CHAP] = 0; + sp->pp_seq[IDX_CHAP] = 0; + sp->pp_rseq[IDX_CHAP] = 0; #if defined(__FreeBSD__) && __FreeBSD__ >= 3 callout_handle_init(&sp->ch[IDX_CHAP]); #endif @@ -3371,7 +3959,7 @@ sppp_chap_scr(struct sppp *sp) ch[3] = seed ^ random(); clen = AUTHKEYLEN; - sp->confid[IDX_CHAP] = ++sp->pp_seq; + sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP]; sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP], sizeof clen, (const char *)&clen, @@ -3544,6 +4132,8 @@ sppp_pap_init(struct sppp *sp) /* PAP doesn't have STATE_INITIAL at all. */ sp->state[IDX_PAP] = STATE_CLOSED; sp->fail_counter[IDX_PAP] = 0; + sp->pp_seq[IDX_PAP] = 0; + sp->pp_rseq[IDX_PAP] = 0; #if defined(__FreeBSD__) && __FreeBSD__ >= 3 callout_handle_init(&sp->ch[IDX_PAP]); callout_handle_init(&sp->pap_my_to_ch); @@ -3678,7 +4268,7 @@ sppp_pap_scr(struct sppp *sp) { u_char idlen, pwdlen; - sp->confid[IDX_PAP] = ++sp->pp_seq; + sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP]; pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); @@ -3824,11 +4414,11 @@ sppp_keepalive(void *dummy) if (sp->pp_alivecnt <= MAXALIVECNT) ++sp->pp_alivecnt; if (sp->pp_mode == IFF_CISCO) - sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, - sp->pp_rseq); + sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, + ++sp->pp_seq[IDX_LCP], sp->pp_rseq[IDX_LCP]); else if (sp->pp_phase >= PHASE_AUTHENTICATE) { long nmagic = htonl (sp->lcp.magic); - sp->lcp.echoid = ++sp->pp_seq; + sp->lcp.echoid = ++sp->pp_seq[IDX_LCP]; sppp_cp_send (sp, PPP_LCP, ECHO_REQ, sp->lcp.echoid, 4, &nmagic); } @@ -3957,8 +4547,154 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) } #endif } +} + +#ifdef INET6 +/* + * Get both IPv6 addresses. + */ +static void +sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst, + struct in6_addr *srcmask) +{ + struct ifnet *ifp = &sp->pp_if; + struct ifaddr *ifa; + struct sockaddr_in6 *si, *sm; + struct in6_addr ssrc, ddst; + + sm = NULL; + bzero(&ssrc, sizeof(ssrc)); + bzero(&ddst, sizeof(ddst)); + /* + * Pick the first link-local AF_INET6 address from the list, + * aliases don't make any sense on a p2p link anyway. + */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + for (ifa = ifp->if_addrhead.tqh_first, si = 0; + ifa; + ifa = ifa->ifa_link.tqe_next) +#elif defined(__NetBSD__) || defined (__OpenBSD__) + for (ifa = ifp->if_addrlist.tqh_first, si = 0; + ifa; + ifa = ifa->ifa_list.tqe_next) +#else + for (ifa = ifp->if_addrlist, si = 0; + ifa; + ifa = ifa->ifa_next) +#endif + if (ifa->ifa_addr->sa_family == AF_INET6) { + si = (struct sockaddr_in6 *)ifa->ifa_addr; + sm = (struct sockaddr_in6 *)ifa->ifa_netmask; + if (si && IN6_IS_ADDR_LINKLOCAL(&si->sin6_addr)) + break; + } + if (ifa) { + if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) { + bcopy(&si->sin6_addr, &ssrc, sizeof(ssrc)); + if (srcmask) { + bcopy(&sm->sin6_addr, srcmask, + sizeof(*srcmask)); + } + } + + si = (struct sockaddr_in6 *)ifa->ifa_dstaddr; + if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) + bcopy(&si->sin6_addr, &ddst, sizeof(ddst)); + } + + if (dst) + bcopy(&ddst, dst, sizeof(*dst)); + if (src) + bcopy(&ssrc, src, sizeof(*src)); } +#ifdef IPV6CP_MYIFID_DYN +/* + * Generate random ifid. + */ +static void +sppp_gen_ip6_addr(struct sppp *sp, struct in6_addr *addr) +{ + /* TBD */ +} + +/* + * Set my IPv6 address. Must be called at splimp. + */ +static void +sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src) +{ + STDDCL; + struct ifaddr *ifa; + struct sockaddr_in6 *sin6; + + /* + * Pick the first link-local AF_INET6 address from the list, + * aliases don't make any sense on a p2p link anyway. + */ + + sin6 = NULL; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + for (ifa = ifp->if_addrhead.tqh_first; + ifa; + ifa = ifa->ifa_link.tqe_next) +#elif defined(__NetBSD__) || defined (__OpenBSD__) + for (ifa = ifp->if_addrlist.tqh_first; + ifa; + ifa = ifa->ifa_list.tqe_next) +#else + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#endif + { + if (ifa->ifa_addr->sa_family == AF_INET6) + { + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + break; + } + } + + if (ifa && sin6) + { + int error; + struct sockaddr_in6 new_sin6 = *sin6; + + bcopy(src, &new_sin6.sin6_addr, sizeof(new_sin6.sin6_addr)); + error = in6_ifinit(ifp, ifatoia6(ifa), &new_sin6, 1); + if (debug && error) + { + log(LOG_DEBUG, SPP_FMT "sppp_set_ip6_addr: in6_ifinit " + " failed, error=%d\n", SPP_ARGS(ifp), error); + } + } +} +#endif + +/* + * Suggest a candidate address to be used by peer. + */ +static void +sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *suggest) +{ + struct in6_addr myaddr; + struct timeval tv; + + sppp_get_ip6_addrs(sp, &myaddr, 0, 0); + + myaddr.s6_addr[8] &= ~0x02; /* u bit to "local" */ + microtime(&tv); + if ((tv.tv_usec & 0xff) == 0 && (tv.tv_sec & 0xff) == 0) { + myaddr.s6_addr[14] ^= 0xff; + myaddr.s6_addr[15] ^= 0xff; + } else { + myaddr.s6_addr[14] ^= (tv.tv_usec & 0xff); + myaddr.s6_addr[15] ^= (tv.tv_sec & 0xff); + } + if (suggest) + bcopy(&myaddr, suggest, sizeof(myaddr)); +} +#endif /*INET6*/ + static int sppp_params(struct sppp *sp, u_long cmd, void *data) { @@ -4165,6 +4901,20 @@ sppp_ipcp_opt_name(u_char opt) return buf; } +#ifdef INET6 +static const char * +sppp_ipv6cp_opt_name(u_char opt) +{ + static char buf[12]; + switch (opt) { + case IPV6CP_OPT_IFID: return "ifid"; + case IPV6CP_OPT_COMPRESSION: return "compression"; + } + sprintf (buf, "0x%x", opt); + return buf; +} +#endif + static const char * sppp_state_name(int state) { @@ -4205,6 +4955,7 @@ sppp_proto_name(u_short proto) case PPP_IPCP: return "ipcp"; case PPP_PAP: return "pap"; case PPP_CHAP: return "chap"; + case PPP_IPV6CP: return "ipv6cp"; } snprintf(buf, sizeof(buf), "proto/0x%x", (unsigned)proto); return buf; diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index d6a6495..979e6c5 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if_stf.c,v 1.42 2000/08/15 07:24:23 itojun Exp $ */ +/* $KAME: if_stf.c,v 1.60 2001/05/03 14:51:47 itojun Exp $ */ /* * Copyright (C) 2000 WIDE Project. @@ -31,7 +31,7 @@ */ /* - * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt. + * 6to4 interface, based on RFC3056. * * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting. * There is no address mapping defined from IPv6 multicast address to IPv4 @@ -60,12 +60,13 @@ * ICMPv6: * - Redirects cannot be used due to the lack of link-local address. * - * Starting from 04 draft, the specification suggests how to construct - * link-local address for 6to4 interface. - * However, it seems to have no real use and does not help the above symptom - * much. Even if we assign link-locals to interface, we cannot really - * use link-local unicast/multicast on top of 6to4 cloud, and the above - * analysis does not change. + * stf interface does not have, and will not need, a link-local address. + * It seems to have no real benefit and does not help the above symptoms much. + * Even if we assign link-locals to interface, we cannot really + * use link-local unicast/multicast on top of 6to4 cloud (since there's no + * encapsulation defined for link-local address), and the above analysis does + * not change. RFC3056 does not mandate the assignment of link-local address + * either. * * 6to4 interface has security issues. Refer to * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt @@ -159,8 +160,10 @@ static int stf_encapcheck __P((const struct mbuf *, int, int, void *)); static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *)); static int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); -static int stf_checkaddr4 __P((struct in_addr *, struct ifnet *)); -static int stf_checkaddr6 __P((struct in6_addr *, struct ifnet *)); +static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *, + struct ifnet *)); +static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *, + struct ifnet *)); static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *)); static int stf_ioctl __P((struct ifnet *, u_long, caddr_t)); @@ -197,6 +200,10 @@ stfattach(dummy) sc->sc_if.if_ioctl = stf_ioctl; sc->sc_if.if_output = stf_output; sc->sc_if.if_type = IFT_STF; +#if 0 + /* turn off ingress filter */ + sc->sc_if.if_flags |= IFF_LINK2; +#endif sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; if_attach(&sc->sc_if); #if NBPFILTER > 0 @@ -230,6 +237,10 @@ stf_encapcheck(m, off, proto, arg) if ((sc->sc_if.if_flags & IFF_UP) == 0) return 0; + /* IFF_LINK0 means "no decapsulation" */ + if ((sc->sc_if.if_flags & IFF_LINK0) != 0) + return 0; + if (proto != IPPROTO_IPV6) return 0; @@ -317,6 +328,7 @@ stf_output(ifp, m, dst, rt) { struct stf_softc *sc; struct sockaddr_in6 *dst6; + struct in_addr *in4; struct sockaddr_in *dst4; u_int8_t tos; struct ip *ip; @@ -351,6 +363,19 @@ stf_output(ifp, m, dst, rt) ip6 = mtod(m, struct ip6_hdr *); tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + /* + * Pickup the right outer dst addr from the list of candidates. + * ip6_dst has priority as it may be able to give us shorter IPv4 hops. + */ + if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst)) + in4 = GET_V4(&ip6->ip6_dst); + else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr)) + in4 = GET_V4(&dst6->sin6_addr); + else { + m_freem(m); + return ENETUNREACH; + } + M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); @@ -362,12 +387,14 @@ stf_output(ifp, m, dst, rt) bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr), &ip->ip_src, sizeof(ip->ip_src)); - bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst)); + bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst)); ip->ip_p = IPPROTO_IPV6; ip->ip_ttl = ip_gif_ttl; /*XXX*/ ip->ip_len = m->m_pkthdr.len; /*host order*/ if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos); + else + ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos); dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst; if (dst4->sin_family != AF_INET || @@ -394,9 +421,10 @@ stf_output(ifp, m, dst, rt) } static int -stf_checkaddr4(in, ifp) +stf_checkaddr4(sc, in, inifp) + struct stf_softc *sc; struct in_addr *in; - struct ifnet *ifp; /* incoming interface */ + struct ifnet *inifp; /* incoming interface */ { struct in_ifaddr *ia4; @@ -427,7 +455,7 @@ stf_checkaddr4(in, ifp) /* * perform ingress filter */ - if (ifp) { + if (sc && (sc->sc_if.if_flags & IFF_LINK2) == 0 && inifp) { struct sockaddr_in sin; struct rtentry *rt; @@ -436,10 +464,14 @@ stf_checkaddr4(in, ifp) sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = *in; rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); - if (!rt) - return -1; - if (rt->rt_ifp != ifp) { - rtfree(rt); + if (!rt || rt->rt_ifp != inifp) { +#if 0 + log(LOG_WARNING, "%s: packet from 0x%x dropped " + "due to ingress filter\n", if_name(&sc->sc_if), + (u_int32_t)ntohl(sin.sin_addr.s_addr)); +#endif + if (rt) + rtfree(rt); return -1; } rtfree(rt); @@ -449,15 +481,16 @@ stf_checkaddr4(in, ifp) } static int -stf_checkaddr6(in6, ifp) +stf_checkaddr6(sc, in6, inifp) + struct stf_softc *sc; struct in6_addr *in6; - struct ifnet *ifp; /* incoming interface */ + struct ifnet *inifp; /* incoming interface */ { /* * check 6to4 addresses */ if (IN6_IS_ADDR_6TO4(in6)) - return stf_checkaddr4(GET_V4(in6), ifp); + return stf_checkaddr4(sc, GET_V4(in6), inifp); /* * reject anything that look suspicious. the test is implemented @@ -476,7 +509,7 @@ void in_stf_input(struct mbuf *m, ...) #else in_stf_input(m, va_alist) - register struct mbuf *m; + struct mbuf *m; #endif { int off, proto; @@ -514,8 +547,8 @@ in_stf_input(m, va_alist) * perform sanity check against outer src/dst. * for source, perform ingress filter as well. */ - if (stf_checkaddr4(&ip->ip_dst, NULL) < 0 || - stf_checkaddr4(&ip->ip_src, m->m_pkthdr.rcvif) < 0) { + if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 || + stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) { m_freem(m); return; } @@ -534,8 +567,8 @@ in_stf_input(m, va_alist) * perform sanity check against inner src/dst. * for source, perform ingress filter as well. */ - if (stf_checkaddr6(&ip6->ip6_dst, NULL) < 0 || - stf_checkaddr6(&ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { + if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 || + stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { m_freem(m); return; } @@ -543,6 +576,8 @@ in_stf_input(m, va_alist) itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if ((ifp->if_flags & IFF_LINK1) != 0) ip_ecn_egress(ECN_ALLOWED, &otos, &itos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &itos); ip6->ip6_flow &= ~htonl(0xff << 20); ip6->ip6_flow |= htonl((u_int32_t)itos << 20); @@ -558,7 +593,7 @@ in_stf_input(m, va_alist) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = AF_INET6; + u_int32_t af = AF_INET6; m0.m_next = m; m0.m_len = 4; @@ -594,11 +629,7 @@ static void stf_rtrequest(cmd, rt, sa) int cmd; struct rtentry *rt; -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 - struct rt_addrinfo *sa; -#else struct sockaddr *sa; -#endif { if (rt) diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c index 02000f6..ef3bb01 100644 --- a/sys/net/net_osdep.c +++ b/sys/net/net_osdep.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: net_osdep.c,v 1.4 2000/03/25 07:23:34 sumikawa Exp $ */ +/* $KAME: net_osdep.c,v 1.9 2001/04/06 09:22:05 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,6 +32,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> @@ -52,8 +53,15 @@ const char * if_name(ifp) struct ifnet *ifp; { - static char nam[IFNAMSIZ + 10]; /*enough?*/ +#define MAXNUMBUF 8 + static char nam[MAXNUMBUF][IFNAMSIZ + 10]; /*enough?*/ + static int ifbufround = 0; + char *cp; - snprintf(nam, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit); - return nam; + ifbufround = (ifbufround + 1) % MAXNUMBUF; + cp = nam[ifbufround]; + + snprintf(cp, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit); + return((const char *)cp); +#undef MAXNUMBUF } diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h index 3bb3c18..399dd31 100644 --- a/sys/net/net_osdep.h +++ b/sys/net/net_osdep.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: net_osdep.h,v 1.22 2000/08/15 07:23:10 itojun Exp $ */ +/* $KAME: net_osdep.h,v 1.44 2001/05/16 03:13:40 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -36,16 +36,40 @@ /* * OS dependencies: * + * - whether the IPv4 input routine convert the byte order of some fileds + * of the IP header (x: convert to the host byte order, s: strip the header + * length for possible reassembly) + * ip_len ip_id ip_off + * bsdi3: xs x x + * bsdi4: xs x + * FreeBSD: xs x + * NetBSD: x x + * OpenBSD: xs x x + * + * - ifa_ifwithaf() + * bsdi[34], netbsd, and openbsd define it in sys/net/if.c + * freebsd (all versions) does not have it. + * * - struct rt_addrinfo - * all *BSDs except bsdi4 only have two members; rti_addrs and rti_info[]. - * bsdi4 has additional members; rti_flags, rti_ifa, rti_ifp, and rti_rtm. + * bsdi4, netbsd 1.5R and beyond: rti_addrs, rti_info[], rti_flags, rti_ifa, + * rti_ifp, and rti_rtm. + * others: rti_addrs and rti_info[] only. + * + * - ifa->ifa_rtrequest + * bsdi4, netbsd 1.5R and beyond: rt_addrinfo * + * others: sockaddr * (note that sys/net/route.c:rtrequest() has an unsafe + * typecast code, from 4.3BSD-reno) * - * - side effects of rtrequest[1](RTM_DELETE) + * - side effects of rtrequest{,1}(RTM_DELETE) * BSDI[34]: delete all cloned routes underneath the route. * FreeBSD[234]: delete all protocol-cloned routes underneath the route. * note that cloned routes from an interface direct route * still remain. - * NetBSD, OpenBSD: no side effects. + * NetBSD: 1.5 have no side effects. KAME/netbsd15, and post-1.5R, have + * the same effects as of BSDI. + * OpenBSD: have no side effects. KAME/openbsd has the same effects as + * of BSDI (the change is not merged - yet). + * * - privileged process * NetBSD, FreeBSD 3 * struct proc *p; @@ -64,11 +88,13 @@ * needs to give struct proc * as argument * OpenBSD, BSDI [34], FreeBSD 2 * do not need struct proc * + * * - bpf: - * OpenBSD, NetBSD, BSDI [34] + * OpenBSD, NetBSD 1.5, BSDI [34] * need caddr_t * (= if_bpf **) and struct ifnet * - * FreeBSD 2, FreeBSD 3 + * FreeBSD 2, FreeBSD 3, NetBSD post-1.5N * need only struct ifnet * as argument + * * - struct ifnet * use queue.h? member names if name * --- --- --- @@ -77,34 +103,57 @@ * OpenBSD yes standard if_xname * NetBSD yes standard if_xname * BSDI [34] no old standard if_name+unit + * * - usrreq * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 * single function with PRU_xx, arguments are mbuf * FreeBSD 3 * separates functions, non-mbuf arguments + * * - {set,get}sockopt * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 * manipulation based on mbuf * FreeBSD 3 * non-mbuf manipulation using sooptcopy{in,out}() + * * - timeout() and untimeout() - * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 + * NetBSD 1.4.x, OpenBSD, BSDI [34], FreeBSD 2 * timeout() is a void function * FreeBSD 3 * timeout() is non-void, must keep returned value for untimeout() + * callout_xx is also available (sys/callout.h) + * NetBSD 1.5 + * timeout() is obsoleted, use callout_xx (sys/callout.h) + * OpenBSD 2.8 + * timeout_{add,set,del} is encouraged (sys/timeout.h) + * * - sysctl * NetBSD, OpenBSD * foo_sysctl() * BSDI [34] - * foo_sysctl() but with different style - * FreeBSD 2, FreeBSD 3 - * linker hack + * foo_sysctl() but with different style. sysctl_int_arr() takes + * care of most of the cases. + * FreeBSD + * linker hack. however, there are freebsd version differences + * (how wonderful!). + * on FreeBSD[23] function arg #define includes paren. + * int foo SYSCTL_HANDLER_ARGS; + * on FreeBSD4, function arg #define does not include paren. + * int foo(SYSCTL_HANDLER_ARGS); + * on some versions, forward reference to the tree is okay. + * on some versions, you need SYSCTL_DECL(). you need things + * like this. + * #ifdef SYSCTL_DECL + * SYSCTL_DECL(net_inet_ip6); + * #endif + * it is hard to share functions between freebsd and non-freebsd. * * - if_ioctl * NetBSD, FreeBSD 3, BSDI [34] * 2nd argument is u_long cmd * FreeBSD 2 * 2nd argument is int cmd + * * - if attach routines * NetBSD * void xxattach(int); @@ -115,6 +164,7 @@ * - ovbcopy() * in NetBSD 1.4 or later, ovbcopy() is not supplied in the kernel. * bcopy() is safe against overwrites. + * * - splnet() * NetBSD 1.4 or later requires splsoftnet(). * other operating systems use splnet(). @@ -125,7 +175,8 @@ * - struct ifnet for loopback interface * BSDI3: struct ifnet loif; * BSDI4: struct ifnet *loifp; - * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP]; + * NetBSD, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP]; + * OpenBSD 2.9: struct ifnet *lo0ifp; * * odd thing is that many of them refers loif as ifnet *loif, * not loif[NLOOP], from outside of if_loop.c. @@ -145,6 +196,12 @@ * FreeBSD4: struct ipprotosw in netinet/ipprotosw.h * others: struct protosw in sys/protosw.h * + * - protosw in general. + * NetBSD 1.5 has extra member for ipfilter (netbsd-current dropped + * it so it will go away in 1.6). + * NetBSD 1.5 requires PR_LISTEN flag bit with protocols that permit + * listen/accept (like tcp). + * * - header files with defopt (opt_xx.h) * FreeBSD3: opt_{inet,ipsec,ip6fw,altq}.h * FreeBSD4: opt_{inet,inet6,ipsec,ip6fw,altq}.h @@ -154,6 +211,23 @@ * - IN_MULTICAST/IN_CLASS[A-D] macro. * OpenBSD and NetBSD: net endian (kernel) or host endian (userland) * others: always host endian + * + * - (m->m_flags & M_EXT) != 0 does *not* mean that the max data length of + * the mbuf == MCLBYTES. + * + * - sys/kern/uipc_mbuf.c:m_dup() + * freebsd[34]: copies the whole mbuf chain. + * netbsd: similar arg with m_copym(). + * others: no m_dup(). + * + * - ifa_refcnt (struct ifaddr) management (IFAREF/IFAFREE). + * NetBSD 1.5: always use IFAREF whenever reference gets added. + * always use IFAFREE whenever reference gets freed. + * IFAFREE frees ifaddr when ifa_refcnt reaches 0. + * others: do not increase refcnt for ifp->if_addrlist and in_ifaddr. + * use IFAFREE once when ifaddr is disconnected from + * ifp->if_addrlist and in_ifaddr. IFAFREE frees ifaddr when + * ifa_refcnt goes negative. */ #ifndef __NET_NET_OSDEP_H_DEFINED_ @@ -165,6 +239,19 @@ extern const char *if_name __P((struct ifnet *)); #define HAVE_OLD_BPF +#define ifa_list ifa_link +#define if_addrlist if_addrhead +#define if_list if_link + +/* sys/net/if.h */ +#define IFAREF(ifa) do { ++(ifa)->ifa_refcnt; } while (0) + +#define WITH_CONVERT_AND_STRIP_IP_LEN + +#if 1 /* at this moment, all OSes do this */ +#define WITH_CONVERT_IP_OFF +#endif + /* * Deprecated. */ diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h index 4c41c80..f1c22ad 100644 --- a/sys/net/pfkeyv2.h +++ b/sys/net/pfkeyv2.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: pfkeyv2.h,v 1.17 2000/06/22 08:38:33 sakane Exp $ */ +/* $KAME: pfkeyv2.h,v 1.25 2001/03/12 08:34:06 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -73,7 +73,7 @@ you leave this credit intact on any copies of this file. #define SADB_X_SPDDUMP 18 #define SADB_X_SPDFLUSH 19 #define SADB_X_SPDSETIDX 20 -#define SADB_X_SPDEXPIRE 21 /* not yet */ +#define SADB_X_SPDEXPIRE 21 #define SADB_X_SPDDELETE2 22 /* by policy id */ #define SADB_MAX 22 @@ -298,22 +298,32 @@ struct sadb_x_ipsecrequest { #define SADB_SAFLAGS_PFS 1 -#define SADB_AALG_NONE 0 -#define SADB_AALG_MD5HMAC 1 /* 2 */ -#define SADB_AALG_SHA1HMAC 2 /* 3 */ -#define SADB_AALG_MD5 3 /* Keyed MD5 */ -#define SADB_AALG_SHA 4 /* Keyed SHA */ -#define SADB_AALG_NULL 5 /* null authentication */ -#define SADB_AALG_MAX 6 - -#define SADB_EALG_NONE 0 -#define SADB_EALG_DESCBC 1 /* 2 */ -#define SADB_EALG_3DESCBC 2 /* 3 */ -#define SADB_EALG_NULL 3 /* 11 */ -#define SADB_EALG_BLOWFISHCBC 4 -#define SADB_EALG_CAST128CBC 5 -#define SADB_EALG_RC5CBC 6 -#define SADB_EALG_MAX 7 +/* RFC2367 numbers - meets RFC2407 */ +#define SADB_AALG_NONE 0 +#define SADB_AALG_MD5HMAC 1 /*2*/ +#define SADB_AALG_SHA1HMAC 2 /*3*/ +#define SADB_AALG_MAX 8 +/* private allocations - based on RFC2407/IANA assignment */ +#define SADB_X_AALG_SHA2_256 6 /*5*/ +#define SADB_X_AALG_SHA2_384 7 /*6*/ +#define SADB_X_AALG_SHA2_512 8 /*7*/ +/* private allocations should use 249-255 (RFC2407) */ +#define SADB_X_AALG_MD5 3 /*249*/ /* Keyed MD5 */ +#define SADB_X_AALG_SHA 4 /*250*/ /* Keyed SHA */ +#define SADB_X_AALG_NULL 5 /*251*/ /* null authentication */ + +/* RFC2367 numbers - meets RFC2407 */ +#define SADB_EALG_NONE 0 +#define SADB_EALG_DESCBC 1 /*2*/ +#define SADB_EALG_3DESCBC 2 /*3*/ +#define SADB_EALG_NULL 3 /*11*/ +#define SADB_EALG_MAX 12 +/* private allocations - based on RFC2407/IANA assignment */ +#define SADB_X_EALG_CAST128CBC 5 /*6*/ +#define SADB_X_EALG_BLOWFISHCBC 4 /*7*/ +#define SADB_X_EALG_RIJNDAELCBC 12 +#define SADB_X_EALG_AES 12 +/* private allocations should use 249-255 (RFC2407) */ #if 1 /*nonstandard */ #define SADB_X_CALG_NONE 0 diff --git a/sys/net/ppp_defs.h b/sys/net/ppp_defs.h index ac86be2..be891ee 100644 --- a/sys/net/ppp_defs.h +++ b/sys/net/ppp_defs.h @@ -69,6 +69,8 @@ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ #define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ #define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#define PPP_IPV6 0x57 /* Internet Protocol version 6*/ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ /* * Values for FCS calculations. diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index dc4ae26..6588f56 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -573,9 +573,6 @@ rt_msg1(type, rtinfo) register struct sockaddr *sa; int len, dlen; - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == 0) - return (m); switch (type) { case RTM_DELADDR: @@ -595,8 +592,18 @@ rt_msg1(type, rtinfo) default: len = sizeof(struct rt_msghdr); } - if (len > MHLEN) + if (len > MCLBYTES) panic("rt_msg1"); + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m && len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + m = NULL; + } + } + if (m == 0) + return (m); m->m_pkthdr.len = m->m_len = len; m->m_pkthdr.rcvif = 0; rtm = mtod(m, struct rt_msghdr *); diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index 3625ee4..425495d 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: icmp6.h,v 1.18 2000/07/03 02:51:08 itojun Exp $ */ +/* $KAME: icmp6.h,v 1.46 2001/04/27 15:09:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -80,7 +80,7 @@ struct icmp6_hdr { u_int16_t icmp6_un_data16[2]; /* type-specific field */ u_int8_t icmp6_un_data8[4]; /* type-specific field */ } icmp6_dataun; -}; +} __attribute__((__packed__)); #define icmp6_data32 icmp6_dataun.icmp6_un_data32 #define icmp6_data16 icmp6_dataun.icmp6_un_data16 @@ -124,7 +124,10 @@ struct icmp6_hdr { #define MLD6_MTRACE_RESP 141 /* mtrace response(to sender) */ #define MLD6_MTRACE 142 /* mtrace messages */ -#define ICMP6_MAXTYPE 142 +#define ICMP6_HADISCOV_REQUEST 143 /* XXX To be defined */ +#define ICMP6_HADISCOV_REPLY 144 /* XXX To be defined */ + +#define ICMP6_MAXTYPE 144 #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ #define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */ @@ -146,7 +149,7 @@ struct icmp6_hdr { #define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */ #define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */ -#define ICMP6_NI_SUCESS 0 /* node information successful reply */ +#define ICMP6_NI_SUCCESS 0 /* node information successful reply */ #define ICMP6_NI_REFUSED 1 /* node information request is refused */ #define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */ @@ -164,7 +167,7 @@ struct icmp6_hdr { struct mld6_hdr { struct icmp6_hdr mld6_hdr; struct in6_addr mld6_addr; /* multicast address */ -}; +} __attribute__((__packed__)); #define mld6_type mld6_hdr.icmp6_type #define mld6_code mld6_hdr.icmp6_code @@ -179,7 +182,7 @@ struct mld6_hdr { struct nd_router_solicit { /* router solicitation */ struct icmp6_hdr nd_rs_hdr; /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_rs_type nd_rs_hdr.icmp6_type #define nd_rs_code nd_rs_hdr.icmp6_code @@ -191,7 +194,7 @@ struct nd_router_advert { /* router advertisement */ u_int32_t nd_ra_reachable; /* reachable time */ u_int32_t nd_ra_retransmit; /* retransmit timer */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_ra_type nd_ra_hdr.icmp6_type #define nd_ra_code nd_ra_hdr.icmp6_code @@ -200,13 +203,26 @@ struct nd_router_advert { /* router advertisement */ #define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] #define ND_RA_FLAG_MANAGED 0x80 #define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_HA 0x20 + +/* + * Router preference values based on draft-draves-ipngwg-router-selection-01. + * These are non-standard definitions. + */ +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ + +#define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */ +#define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */ +#define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */ +#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ + #define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] struct nd_neighbor_solicit { /* neighbor solicitation */ struct icmp6_hdr nd_ns_hdr; struct in6_addr nd_ns_target; /*target address */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_ns_type nd_ns_hdr.icmp6_type #define nd_ns_code nd_ns_hdr.icmp6_code @@ -217,7 +233,7 @@ struct nd_neighbor_advert { /* neighbor advertisement */ struct icmp6_hdr nd_na_hdr; struct in6_addr nd_na_target; /* target address */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_na_type nd_na_hdr.icmp6_type #define nd_na_code nd_na_hdr.icmp6_code @@ -240,7 +256,7 @@ struct nd_redirect { /* redirect */ struct in6_addr nd_rd_target; /* target address */ struct in6_addr nd_rd_dst; /* destination address */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_rd_type nd_rd_hdr.icmp6_type #define nd_rd_code nd_rd_hdr.icmp6_code @@ -251,13 +267,14 @@ struct nd_opt_hdr { /* Neighbor discovery option header */ u_int8_t nd_opt_type; u_int8_t nd_opt_len; /* followed by option specific data*/ -}; +} __attribute__((__packed__)); #define ND_OPT_SOURCE_LINKADDR 1 #define ND_OPT_TARGET_LINKADDR 2 #define ND_OPT_PREFIX_INFORMATION 3 #define ND_OPT_REDIRECTED_HEADER 4 #define ND_OPT_MTU 5 +#define ND_OPT_ROUTE_INFO 9 /* draft-draves-router-preference, not officially assigned yet */ struct nd_opt_prefix_info { /* prefix information */ u_int8_t nd_opt_pi_type; @@ -268,7 +285,7 @@ struct nd_opt_prefix_info { /* prefix information */ u_int32_t nd_opt_pi_preferred_time; u_int32_t nd_opt_pi_reserved2; struct in6_addr nd_opt_pi_prefix; -}; +} __attribute__((__packed__)); #define ND_OPT_PI_FLAG_ONLINK 0x80 #define ND_OPT_PI_FLAG_AUTO 0x40 @@ -279,15 +296,23 @@ struct nd_opt_rd_hdr { /* redirected header */ u_int16_t nd_opt_rh_reserved1; u_int32_t nd_opt_rh_reserved2; /* followed by IP header and data */ -}; +} __attribute__((__packed__)); struct nd_opt_mtu { /* MTU option */ u_int8_t nd_opt_mtu_type; u_int8_t nd_opt_mtu_len; u_int16_t nd_opt_mtu_reserved; u_int32_t nd_opt_mtu_mtu; -}; - +} __attribute__((__packed__)); + +struct nd_opt_route_info { /* route info */ + u_int8_t nd_opt_rti_type; + u_int8_t nd_opt_rti_len; + u_int8_t nd_opt_rti_prefixlen; + u_int8_t nd_opt_rti_flags; + u_int32_t nd_opt_rti_lifetime; + /* followed by prefix */ +} __attribute__((__packed__)); /* * icmp6 namelookup */ @@ -301,7 +326,7 @@ struct icmp6_namelookup { u_int8_t icmp6_nl_name[3]; #endif /* could be followed by options */ -}; +} __attribute__((__packed__)); /* * icmp6 node information @@ -310,7 +335,7 @@ struct icmp6_nodeinfo { struct icmp6_hdr icmp6_ni_hdr; u_int8_t icmp6_ni_nonce[8]; /* could be followed by reply data */ -}; +} __attribute__((__packed__)); #define ni_type icmp6_ni_hdr.icmp6_type #define ni_code icmp6_ni_hdr.icmp6_code @@ -320,8 +345,10 @@ struct icmp6_nodeinfo { #define NI_QTYPE_NOOP 0 /* NOOP */ #define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */ -#define NI_QTYPE_FQDN 2 /* FQDN */ -#define NI_QTYPE_NODEADDR 3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */ +#define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */ +#define NI_QTYPE_DNSNAME 2 /* DNS Name */ +#define NI_QTYPE_NODEADDR 3 /* Node Addresses */ +#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */ #if BYTE_ORDER == BIG_ENDIAN #define NI_SUPTYPE_FLAG_COMPRESS 0x1 @@ -371,7 +398,7 @@ struct ni_reply_fqdn { u_int32_t ni_fqdn_ttl; /* TTL */ u_int8_t ni_fqdn_namelen; /* length in octets of the FQDN */ u_int8_t ni_fqdn_name[3]; /* XXX: alignment */ -}; +} __attribute__((__packed__)); /* * Router Renumbering. as router-renum-08.txt @@ -382,13 +409,13 @@ struct icmp6_router_renum { /* router renumbering header */ u_int8_t rr_flags; u_int16_t rr_maxdelay; u_int32_t rr_reserved; -}; -#define ICMP6_RR_FLAGS_SEGNUM 0x80 -#define ICMP6_RR_FLAGS_TEST 0x40 -#define ICMP6_RR_FLAGS_REQRESULT 0x20 -#define ICMP6_RR_FLAGS_FORCEAPPLY 0x10 -#define ICMP6_RR_FLAGS_SPECSITE 0x08 -#define ICMP6_RR_FLAGS_PREVDONE 0x04 +} __attribute__((__packed__)); + +#define ICMP6_RR_FLAGS_TEST 0x80 +#define ICMP6_RR_FLAGS_REQRESULT 0x40 +#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20 +#define ICMP6_RR_FLAGS_SPECSITE 0x10 +#define ICMP6_RR_FLAGS_PREVDONE 0x08 #define rr_type rr_hdr.icmp6_type #define rr_code rr_hdr.icmp6_code @@ -404,7 +431,7 @@ struct rr_pco_match { /* match prefix part */ u_int8_t rpm_maxlen; u_int16_t rpm_reserved; struct in6_addr rpm_prefix; -}; +} __attribute__((__packed__)); #define RPM_PCO_ADD 1 #define RPM_PCO_CHANGE 2 @@ -420,7 +447,7 @@ struct rr_pco_use { /* use prefix part */ u_int32_t rpu_pltime; u_int32_t rpu_flags; struct in6_addr rpu_prefix; -}; +} __attribute__((__packed__)); #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80 #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40 @@ -438,13 +465,13 @@ struct rr_result { /* router renumbering result message */ u_int8_t rrr_matchedlen; u_int32_t rrr_ifid; struct in6_addr rrr_prefix; -}; +} __attribute__((__packed__)); #if BYTE_ORDER == BIG_ENDIAN #define ICMP6_RR_RESULT_FLAGS_OOB 0x0002 #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001 #elif BYTE_ORDER == LITTLE_ENDIAN -#define ICMP6_RR_RESULT_FLAGS_OOB 0x02 -#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x01 +#define ICMP6_RR_RESULT_FLAGS_OOB 0x0200 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 #endif /* @@ -534,6 +561,13 @@ struct icmp6stat { #define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option #define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect #define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown + u_quad_t icp6s_pmtuchg; /* path MTU changes */ + u_quad_t icp6s_nd_badopt; /* bad ND options */ + u_quad_t icp6s_badns; /* bad neighbor solicitation */ + u_quad_t icp6s_badna; /* bad neighbor advertisement */ + u_quad_t icp6s_badrs; /* bad router advertisement */ + u_quad_t icp6s_badra; /* bad router advertisement */ + u_quad_t icp6s_badredirect; /* bad redirect message */ }; /* @@ -542,7 +576,9 @@ struct icmp6stat { #define ICMPV6CTL_STATS 1 #define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */ #define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */ +#if 0 /*obsoleted*/ #define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */ +#endif #define ICMPV6CTL_ND6_PRUNE 6 #define ICMPV6CTL_ND6_DELAY 8 #define ICMPV6CTL_ND6_UMAXTRIES 9 @@ -552,7 +588,12 @@ struct icmp6stat { #define ICMPV6CTL_NODEINFO 13 #define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */ #define ICMPV6CTL_ND6_MAXNUDHINT 15 -#define ICMPV6CTL_MAXID 16 +#define ICMPV6CTL_MTUDISC_HIWAT 16 +#define ICMPV6CTL_MTUDISC_LOWAT 17 +#define ICMPV6CTL_ND6_DEBUG 18 +#define ICMPV6CTL_ND6_DRLIST 19 +#define ICMPV6CTL_ND6_PRLIST 20 +#define ICMPV6CTL_MAXID 21 #define ICMPV6CTL_NAMES { \ { 0, 0 }, \ @@ -560,7 +601,7 @@ struct icmp6stat { { "rediraccept", CTLTYPE_INT }, \ { "redirtimeout", CTLTYPE_INT }, \ { 0, 0 }, \ - { "errratelimit", CTLTYPE_INT }, \ + { 0, 0 }, \ { "nd6_prune", CTLTYPE_INT }, \ { 0, 0 }, \ { "nd6_delay", CTLTYPE_INT }, \ @@ -571,6 +612,11 @@ struct icmp6stat { { "nodeinfo", CTLTYPE_INT }, \ { "errppslimit", CTLTYPE_INT }, \ { "nd6_maxnudhint", CTLTYPE_INT }, \ + { "mtudisc_hiwat", CTLTYPE_INT }, \ + { "mtudisc_lowat", CTLTYPE_INT }, \ + { "nd6_debug", CTLTYPE_INT }, \ + { 0, 0 }, \ + { 0, 0 }, \ } #define RTF_PROBEMTU RTF_PROTO1 @@ -591,6 +637,9 @@ void icmp6_prepare __P((struct mbuf *)); void icmp6_redirect_input __P((struct mbuf *, int)); void icmp6_redirect_output __P((struct mbuf *, struct rtentry *)); +struct ip6ctlparam; +void icmp6_mtudisc_update __P((struct ip6ctlparam *, int)); + /* XXX: is this the right place for these macros? */ #define icmp6_ifstat_inc(ifp, tag) \ do { \ diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 95abe3f..170a343 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -51,11 +51,6 @@ #include <netinet/igmp_var.h> -#include "gif.h" -#if NGIF > 0 -#include <net/if_gif.h> -#endif - static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); static int in_mask2len __P((struct in_addr *)); @@ -200,21 +195,6 @@ in_control(so, cmd, data, ifp, p) int error, hostIsNew, maskIsNew, s; u_long i; -#if NGIF > 0 - if (ifp && ifp->if_type == IFT_GIF) { - switch (cmd) { - case SIOCSIFPHYADDR: - case SIOCDIFPHYADDR: - if (p && - (error = suser(p)) != 0) - return(error); - case SIOCGIFPSRCADDR: - case SIOCGIFPDSTADDR: - return gif_ioctl(ifp, cmd, data); - } - } -#endif - switch (cmd) { case SIOCALIFADDR: case SIOCDLIFADDR: @@ -713,6 +693,9 @@ in_ifinit(ifp, ia, sin, scrub) } if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) ia->ia_flags |= IFA_ROUTE; + /* XXX check if the subnet route points to the same interface */ + if (error == EEXIST) + error = 0; /* * If the interface supports multicast, join the "all hosts" diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 17955ad..5ad92e1 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in_gif.c,v 1.44 2000/08/15 07:24:24 itojun Exp $ */ +/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -88,7 +88,7 @@ in_gif_output(ifp, family, m, rt) struct mbuf *m; struct rtentry *rt; { - register struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = (struct gif_softc*)ifp; struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; @@ -146,29 +146,12 @@ in_gif_output(ifp, family, m, rt) bzero(&iphdr, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; - if (ifp->if_flags & IFF_LINK0) { - /* multi-destination mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else if (rt) { - if (family != AF_INET) { - m_freem(m); - return EINVAL; /*XXX*/ - } - iphdr.ip_dst = ((struct sockaddr_in *) - (rt->rt_gateway))->sin_addr; - } else { - m_freem(m); - return ENETUNREACH; - } - } else { - /* bidirectional configured tunnel mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else { - m_freem(m); - return ENETUNREACH; - } + /* bidirectional configured tunnel mode */ + if (sin_dst->sin_addr.s_addr != INADDR_ANY) + iphdr.ip_dst = sin_dst->sin_addr; + else { + m_freem(m); + return ENETUNREACH; } iphdr.ip_p = proto; /* version will be set in ip_output() */ @@ -176,6 +159,8 @@ in_gif_output(ifp, family, m, rt) iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); + else + ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); @@ -272,6 +257,8 @@ in_gif_input(m, va_alist) ip = mtod(m, struct ip *); if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos); break; } #endif @@ -290,6 +277,8 @@ in_gif_input(m, va_alist) itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos, &itos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &itos); ip6->ip6_flow &= ~htonl(0xff << 20); ip6->ip6_flow |= htonl((u_int32_t)itos << 20); break; @@ -335,10 +324,6 @@ gif_encapcheck4(m, off, proto, arg) addrmatch |= 1; if (dst->sin_addr.s_addr == ip.ip_src.s_addr) addrmatch |= 2; - else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 && - dst->sin_addr.s_addr == INADDR_ANY) { - addrmatch |= 2; /* we accept any source */ - } if (addrmatch != 3) return 0; @@ -359,7 +344,8 @@ gif_encapcheck4(m, off, proto, arg) } /* ingress filters on outer source */ - if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && + (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { struct sockaddr_in sin; struct rtentry *rt; @@ -368,15 +354,18 @@ gif_encapcheck4(m, off, proto, arg) sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = ip.ip_src; rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); - if (!rt) - return 0; - if (rt->rt_ifp != m->m_pkthdr.rcvif) { - rtfree(rt); + if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { +#if 0 + log(LOG_WARNING, "%s: packet from 0x%x dropped " + "due to ingress filter\n", if_name(&sc->gif_if), + (u_int32_t)ntohl(sin.sin_addr.s_addr)); +#endif + if (rt) + rtfree(rt); return 0; } rtfree(rt); } - /* prioritize: IFF_LINK0 mode is less preferred */ - return (sc->gif_if.if_flags & IFF_LINK0) ? 32 : 32 * 2; + return 32 * 2; } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b24b404..ba5f77f 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -151,14 +151,16 @@ in_pcballoc(so, pcbinfo, p) inp->inp_pcbinfo = pcbinfo; inp->inp_socket = so; #if defined(INET6) - if (ip6_mapped_addr_on) - inp->inp_flags &= ~IN6P_BINDV6ONLY; - else - inp->inp_flags |= IN6P_BINDV6ONLY; + if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on) + inp->inp_flags |= IN6P_IPV6_V6ONLY; #endif LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); pcbinfo->ipi_count++; so->so_pcb = (caddr_t)inp; +#ifdef INET6 + if (ip6_auto_flowlabel) + inp->inp_flags |= IN6P_AUTOFLOWLABEL; +#endif return (0); } @@ -234,9 +236,7 @@ in_pcbbind(inp, nam, p) (so->so_cred->cr_uid != t->inp_socket->so_cred->cr_uid)) { #if defined(INET6) - if ((inp->inp_flags & - IN6P_BINDV6ONLY) != 0 || - ntohl(sin->sin_addr.s_addr) != + if (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || ntohl(t->inp_laddr.s_addr) != INADDR_ANY || @@ -254,8 +254,7 @@ in_pcbbind(inp, nam, p) if (t && (reuseport & t->inp_socket->so_options) == 0) { #if defined(INET6) - if ((inp->inp_flags & IN6P_BINDV6ONLY) != 0 || - ntohl(sin->sin_addr.s_addr) != + if (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || ntohl(t->inp_laddr.s_addr) != INADDR_ANY || diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index f4abb4d..1ae93d2 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -226,25 +226,27 @@ struct inpcbinfo { /* XXX documentation, prefixes */ #define INP_RECVIF 0x80 /* receive incoming interface */ #define INP_MTUDISC 0x100 /* user can do MTU discovery */ #define INP_FAITH 0x200 /* accept FAITH'ed connections */ -#define IN6P_PKTINFO 0x010000 -#define IN6P_HOPLIMIT 0x020000 -#define IN6P_NEXTHOP 0x040000 -#define IN6P_HOPOPTS 0x080000 -#define IN6P_DSTOPTS 0x100000 -#define IN6P_RTHDR 0x200000 -#define IN6P_BINDV6ONLY 0x400000 + +#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */ + +#define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */ +#define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */ +#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */ +#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */ +#define IN6P_RTHDR 0x100000 /* receive routing header */ +#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */ +#define IN6P_AUTOFLOWLABEL 0x800000 /* attach flowlabel automatically */ +#define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */ + #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ INP_RECVIF|\ - IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_NEXTHOP|\ - IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR) - -#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR) + IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\ + IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\ + IN6P_AUTOFLOWLABEL) +#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\ + IN6P_AUTOFLOWLABEL) /* for KAME src sync over BSD*'s */ -#define IN6P_RECVOPTS INP_RECVOPTS -#define IN6P_RECVRETOPTS INP_RECVRETOPTS -#define IN6P_RECVDSTADDR INP_RECVDSTADDR -#define IN6P_HDRINCL INP_HDRINCL #define IN6P_HIGHPORT INP_HIGHPORT #define IN6P_LOWPORT INP_LOWPORT #define IN6P_ANONPORT INP_ANONPORT diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 02e6313..4c07a04 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -75,6 +75,7 @@ #ifdef IPSEC_ESP #include <netinet6/esp.h> #endif +#include <netinet6/ipcomp.h> #endif /* IPSEC */ #include "gif.h" @@ -125,19 +126,19 @@ struct ipprotosw inetsw[] = { 0, 0, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, icmp_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, igmp_input, 0, 0, rip_ctloutput, 0, igmp_init, igmp_fasttimo, igmp_slowtimo, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, rsvp_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, @@ -158,19 +159,25 @@ struct ipprotosw inetsw[] = { &nousrreqs }, #endif +{ SOCK_RAW, &inetdomain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR, + ipcomp4_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, #endif /* IPSEC */ -{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap4_input, 0, 0, rip_ctloutput, 0, encap_init, 0, 0, 0, - &nousrreqs + &rip_usrreqs }, # ifdef INET6 -{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap4_input, 0, 0, rip_ctloutput, 0, - 0, 0, 0, 0, - &nousrreqs + encap_init, 0, 0, 0, + &rip_usrreqs }, #endif #ifdef IPDIVERT @@ -182,7 +189,7 @@ struct ipprotosw inetsw[] = { }, #endif #ifdef IPXIP -{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, ipxip_input, 0, ipxip_ctlinput, 0, 0, 0, 0, 0, 0, @@ -190,7 +197,7 @@ struct ipprotosw inetsw[] = { }, #endif #ifdef NSIP -{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, idpip_input, 0, nsip_ctlinput, 0, 0, 0, 0, 0, 0, diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h index 77d1ab6..ec2c216 100644 --- a/sys/netinet/ip6.h +++ b/sys/netinet/ip6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6.h,v 1.9 2000/07/02 21:01:32 itojun Exp $ */ +/* $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -85,7 +85,7 @@ struct ip6_hdr { } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ -}; +} __attribute__((__packed__)); #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow @@ -106,18 +106,20 @@ struct ip6_hdr { #define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */ #endif /* LITTLE_ENDIAN */ #endif +#if 1 /* ECN bits proposed by Sally Floyd */ #define IP6TOS_CE 0x01 /* congestion experienced */ #define IP6TOS_ECT 0x02 /* ECN-capable transport */ +#endif /* * Extension Headers */ struct ip6_ext { - u_char ip6e_nxt; - u_char ip6e_len; -}; + u_int8_t ip6e_nxt; + u_int8_t ip6e_len; +} __attribute__((__packed__)); /* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ @@ -125,7 +127,7 @@ struct ip6_hbh { u_int8_t ip6h_nxt; /* next header */ u_int8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ -}; +} __attribute__((__packed__)); /* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ @@ -133,20 +135,28 @@ struct ip6_dest { u_int8_t ip6d_nxt; /* next header */ u_int8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ -}; +} __attribute__((__packed__)); /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 */ #define IP6OPT_PADN 0x01 /* 00 0 00001 */ #define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ -#define IP6OPT_JUMBO_LEN 6 -#define IP6OPT_RTALERT 0x05 /* 00 0 00101 */ +#define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */ +#define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */ +#define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */ + #define IP6OPT_RTALERT_LEN 4 #define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ #define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ #define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ #define IP6OPT_MINLEN 2 +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + #define IP6OPT_TYPE(o) ((o) & 0xC0) #define IP6OPT_TYPE_SKIP 0x00 #define IP6OPT_TYPE_DISCARD 0x40 @@ -155,6 +165,8 @@ struct ip6_dest { #define IP6OPT_MUTABLE 0x20 +#define IP6OPT_JUMBO_LEN 6 + /* Routing header */ struct ip6_rthdr { u_int8_t ip6r_nxt; /* next header */ @@ -162,7 +174,7 @@ struct ip6_rthdr { u_int8_t ip6r_type; /* routing type */ u_int8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ -}; +} __attribute__((__packed__)); /* Type 0 Routing header */ struct ip6_rthdr0 { @@ -173,7 +185,7 @@ struct ip6_rthdr0 { u_int8_t ip6r0_reserved; /* reserved field */ u_int8_t ip6r0_slmap[3]; /* strict/loose bit map */ struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */ -}; +} __attribute__((__packed__)); /* Fragment header */ struct ip6_frag { @@ -181,7 +193,7 @@ struct ip6_frag { u_int8_t ip6f_reserved; /* reserved field */ u_int16_t ip6f_offlg; /* offset, reserved, and flag */ u_int32_t ip6f_ident; /* identification */ -}; +} __attribute__((__packed__)); #if BYTE_ORDER == BIG_ENDIAN #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c index 047f82e..3abc3b6 100644 --- a/sys/netinet/ip_ecn.c +++ b/sys/netinet/ip_ecn.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip_ecn.c,v 1.7 2000/05/05 11:00:56 sumikawa Exp $ */ +/* $KAME: ip_ecn.c,v 1.11 2001/05/03 16:09:29 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -43,16 +43,10 @@ #include <sys/mbuf.h> #include <sys/errno.h> -#ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#endif - #ifdef INET6 -#ifndef INET -#include <netinet/in.h> -#endif #include <netinet/ip6.h> #endif @@ -63,17 +57,17 @@ /* * modify outer ECN (TOS) field on ingress operation (tunnel encapsulation). - * call it after you've done the default initialization/copy for the outer. */ void ip_ecn_ingress(mode, outer, inner) int mode; u_int8_t *outer; - u_int8_t *inner; + const u_int8_t *inner; { if (!outer || !inner) panic("NULL pointer passed to ip_ecn_ingress"); + *outer = *inner; switch (mode) { case ECN_ALLOWED: /* ECN allowed */ *outer &= ~IPTOS_CE; @@ -88,12 +82,11 @@ ip_ecn_ingress(mode, outer, inner) /* * modify inner ECN (TOS) field on egress operation (tunnel decapsulation). - * call it after you've done the default initialization/copy for the inner. */ void ip_ecn_egress(mode, outer, inner) int mode; - u_int8_t *outer; + const u_int8_t *outer; u_int8_t *inner; { if (!outer || !inner) @@ -115,14 +108,13 @@ void ip6_ecn_ingress(mode, outer, inner) int mode; u_int32_t *outer; - u_int32_t *inner; + const u_int32_t *inner; { u_int8_t outer8, inner8; if (!outer || !inner) panic("NULL pointer passed to ip6_ecn_ingress"); - outer8 = (ntohl(*outer) >> 20) & 0xff; inner8 = (ntohl(*inner) >> 20) & 0xff; ip_ecn_ingress(mode, &outer8, &inner8); *outer &= ~htonl(0xff << 20); @@ -132,7 +124,7 @@ ip6_ecn_ingress(mode, outer, inner) void ip6_ecn_egress(mode, outer, inner) int mode; - u_int32_t *outer; + const u_int32_t *outer; u_int32_t *inner; { u_int8_t outer8, inner8; @@ -141,7 +133,6 @@ ip6_ecn_egress(mode, outer, inner) panic("NULL pointer passed to ip6_ecn_egress"); outer8 = (ntohl(*outer) >> 20) & 0xff; - inner8 = (ntohl(*inner) >> 20) & 0xff; ip_ecn_egress(mode, &outer8, &inner8); *inner &= ~htonl(0xff << 20); *inner |= htonl((u_int32_t)inner8 << 20); diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h index 6445d0f..9aca731 100644 --- a/sys/netinet/ip_ecn.h +++ b/sys/netinet/ip_ecn.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */ +/* $KAME: ip_ecn.h,v 1.6 2001/05/03 14:51:48 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -35,11 +35,15 @@ * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt */ +#if defined(_KERNEL) && !defined(_LKM) +#include "opt_inet.h" +#endif + #define ECN_ALLOWED 1 /* ECN allowed */ #define ECN_FORBIDDEN 0 /* ECN forbidden */ #define ECN_NOCARE (-1) /* no consideration to ECN */ #ifdef _KERNEL -extern void ip_ecn_ingress __P((int, u_int8_t *, u_int8_t *)); -extern void ip_ecn_egress __P((int, u_int8_t *, u_int8_t *)); +extern void ip_ecn_ingress __P((int, u_int8_t *, const u_int8_t *)); +extern void ip_ecn_egress __P((int, const u_int8_t *, u_int8_t *)); #endif diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c index 7d623ea..7463300 100644 --- a/sys/netinet/ip_encap.c +++ b/sys/netinet/ip_encap.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip_encap.c,v 1.36 2000/06/17 20:34:24 itojun Exp $ */ +/* $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -67,6 +67,7 @@ #include <sys/mbuf.h> #include <sys/errno.h> #include <sys/protosw.h> +#include <sys/queue.h> #include <net/if.h> #include <net/route.h> @@ -100,12 +101,21 @@ static int mask_match __P((const struct encaptab *, const struct sockaddr *, const struct sockaddr *)); static void encap_fillarg __P((struct mbuf *, const struct encaptab *)); +#ifndef LIST_HEAD_INITIALIZER /* rely upon BSS initialization */ LIST_HEAD(, encaptab) encaptab; +#else +LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); +#endif void encap_init() { + static int initialized = 0; + + if (initialized) + return; + initialized++; #if 0 /* * we cannot use LIST_INIT() here, since drivers may want to call @@ -118,6 +128,7 @@ encap_init() #endif } +#ifdef INET void #if __STDC__ encap4_input(struct mbuf *m, ...) @@ -221,6 +232,7 @@ encap4_input(m, va_alist) /* last resort: inject to raw socket */ rip_input(m, off, proto); } +#endif #ifdef INET6 int diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index ddb95f0..7e8c722 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -296,15 +296,6 @@ icmp_input(m, off, proto) icp->icmp_code); #endif -#ifdef IPSEC - /* drop it if it does not match the policy */ - /* XXX Is there meaning of check in here ? */ - if (ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto freeit; - } -#endif - /* * Message type specific processing. */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 7cd8568..3cf13cf 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -350,6 +350,16 @@ ip_input(struct mbuf *m) } ip = mtod(m, struct ip *); } + + /* 127/8 must not appear on wire - RFC1122 */ + if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || + (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { + ipstat.ips_badaddr++; + goto bad; + } + } + if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); } else { @@ -393,15 +403,10 @@ tooshort: m_adj(m, ip->ip_len - m->m_pkthdr.len); } - /* - * Don't accept packets with a loopback destination address - * unless they arrived via the loopback interface. - */ - if ((ntohl(ip->ip_dst.s_addr) & IN_CLASSA_NET) == - (IN_LOOPBACKNET << IN_CLASSA_NSHIFT) && - (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { - goto bad; - } +#ifdef IPSEC + if (ipsec_gethist(m, NULL)) + goto pass; +#endif /* * IpHack's section. @@ -796,6 +801,19 @@ found: } #endif +#ifdef IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto bad; + } +#endif + /* * Switch out to protocol's input routine. */ @@ -1189,6 +1207,10 @@ ip_dooptions(m) */ case IPOPT_LSRR: case IPOPT_SSRR: + if (optlen < IPOPT_OFFSET + sizeof(*cp)) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; @@ -1308,12 +1330,21 @@ nosourcerouting: case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; - if (ipt->ipt_len < 5) + if (ipt->ipt_len < 4 || ipt->ipt_len > 40) { + code = (u_char *)&ipt->ipt_len - (u_char *)ip; goto bad; + } + if (ipt->ipt_ptr < 5) { + code = (u_char *)&ipt->ipt_ptr - (u_char *)ip; + goto bad; + } if (ipt->ipt_ptr > ipt->ipt_len - (int)sizeof(int32_t)) { - if (++ipt->ipt_oflw == 0) + if (++ipt->ipt_oflw == 0) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); @@ -1324,8 +1355,11 @@ nosourcerouting: case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr - 1 + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) + sizeof(struct in_addr) > ipt->ipt_len) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } ipaddr.sin_addr = dst; ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, m->m_pkthdr.rcvif); @@ -1338,8 +1372,11 @@ nosourcerouting: case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr - 1 + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) + sizeof(struct in_addr) > ipt->ipt_len) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } (void)memcpy(&ipaddr.sin_addr, sin, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) @@ -1348,6 +1385,9 @@ nosourcerouting: break; default: + /* XXX can't take &ipt->ipt_flg */ + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip + 1; goto bad; } ntime = iptime(); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 1025e37..10de694 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -95,6 +95,7 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); u_short ip_id; static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); +static struct ifnet *ip_multicast_if __P((struct in_addr *, int *)); static void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); static int ip_getmoptions @@ -177,7 +178,7 @@ ip_output(m0, opt, ro, flags, imo) m0 = m = m->m_next ; #ifdef IPSEC so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif ip = mtod(m, struct ip *); hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; @@ -188,7 +189,7 @@ ip_output(m0, opt, ro, flags, imo) #endif #ifdef IPSEC so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif #ifdef DIAGNOSTIC @@ -430,6 +431,133 @@ ip_output(m0, opt, ro, flags, imo) } sendit: +#ifdef IPSEC + /* get SP for this packet */ + if (so == NULL) + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); + else + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); + + if (sp == NULL) { + ipsecstat.out_inval++; + goto bad; + } + + error = 0; + + /* check policy */ + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + /* + * This packet is just discarded. + */ + ipsecstat.out_polvio++; + goto bad; + + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_NONE: + /* no need to do IPsec. */ + goto skip_ipsec; + + case IPSEC_POLICY_IPSEC: + if (sp->req == NULL) { + /* acquire a policy */ + error = key_spdacquire(sp); + goto bad; + } + break; + + case IPSEC_POLICY_ENTRUST: + default: + printf("ip_output: Invalid policy found. %d\n", sp->policy); + } + { + struct ipsec_output_state state; + bzero(&state, sizeof(state)); + state.m = m; + if (flags & IP_ROUTETOIF) { + state.ro = &iproute; + bzero(&iproute, sizeof(iproute)); + } else + state.ro = ro; + state.dst = (struct sockaddr *)dst; + + ip->ip_sum = 0; + + /* + * XXX + * delayed checksums are not currently compatible with IPsec + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + + HTONS(ip->ip_len); + HTONS(ip->ip_off); + + error = ipsec4_output(&state, sp, flags); + + m = state.m; + if (flags & IP_ROUTETOIF) { + /* + * if we have tunnel mode SA, we may need to ignore + * IP_ROUTETOIF. + */ + if (state.ro != &iproute || state.ro->ro_rt != NULL) { + flags &= ~IP_ROUTETOIF; + ro = state.ro; + } + } else + ro = state.ro; + dst = (struct sockaddr_in *)state.dst; + if (error) { + /* mbuf is already reclaimed in ipsec4_output. */ + m0 = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("ip4_output (ipsec): error code %d\n", error); + /*fall through*/ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; + } + goto bad; + } + } + + /* be sure to update variables that are affected by ipsec4_output() */ + ip = mtod(m, struct ip *); +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + if (ro->ro_rt == NULL) { + if ((flags & IP_ROUTETOIF) == 0) { + printf("ip_output: " + "can't update route after IPsec processing\n"); + error = EHOSTUNREACH; /*XXX*/ + goto bad; + } + } else { + ia = ifatoia(ro->ro_rt->rt_ifa); + ifp = ro->ro_rt->rt_ifp; + } + + /* make it flipped, again. */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); +skip_ipsec: +#endif /*IPSEC*/ + /* * IpHack's section. * - Xlate: translate packet's addr/port (NAT). @@ -661,134 +789,6 @@ sendit: } pass: -#ifdef IPSEC - /* get SP for this packet */ - if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); - else - sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); - - if (sp == NULL) { - ipsecstat.out_inval++; - goto bad; - } - - error = 0; - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - /* - * This packet is just discarded. - */ - ipsecstat.out_polvio++; - goto bad; - - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - /* no need to do IPsec. */ - goto skip_ipsec; - - case IPSEC_POLICY_IPSEC: - if (sp->req == NULL) { - /* XXX should be panic ? */ - printf("ip_output: No IPsec request specified.\n"); - error = EINVAL; - goto bad; - } - break; - - case IPSEC_POLICY_ENTRUST: - default: - printf("ip_output: Invalid policy found. %d\n", sp->policy); - } - { - struct ipsec_output_state state; - bzero(&state, sizeof(state)); - state.m = m; - if (flags & IP_ROUTETOIF) { - state.ro = &iproute; - bzero(&iproute, sizeof(iproute)); - } else - state.ro = ro; - state.dst = (struct sockaddr *)dst; - - ip->ip_sum = 0; - - /* - * XXX - * delayed checksums are not currently compatible with IPsec - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - in_delayed_cksum(m); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } - - HTONS(ip->ip_len); - HTONS(ip->ip_off); - - error = ipsec4_output(&state, sp, flags); - - m = state.m; - if (flags & IP_ROUTETOIF) { - /* - * if we have tunnel mode SA, we may need to ignore - * IP_ROUTETOIF. - */ - if (state.ro != &iproute || state.ro->ro_rt != NULL) { - flags &= ~IP_ROUTETOIF; - ro = state.ro; - } - } else - ro = state.ro; - dst = (struct sockaddr_in *)state.dst; - if (error) { - /* mbuf is already reclaimed in ipsec4_output. */ - m0 = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("ip4_output (ipsec): error code %d\n", error); - /*fall through*/ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; - } - goto bad; - } - } - - /* be sure to update variables that are affected by ipsec4_output() */ - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - if (ro->ro_rt == NULL) { - if ((flags & IP_ROUTETOIF) == 0) { - printf("ip_output: " - "can't update route after IPsec processing\n"); - error = EHOSTUNREACH; /*XXX*/ - goto bad; - } - } else { - ia = ifatoia(ro->ro_rt->rt_ifa); - ifp = ro->ro_rt->rt_ifp; - } - - /* make it flipped, again. */ - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); -skip_ipsec: -#endif /*IPSEC*/ - m->m_pkthdr.csum_flags |= CSUM_IP; sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist; if (sw_csum & CSUM_DELAY_DATA) { @@ -820,6 +820,11 @@ skip_ipsec: ia->ia_ifa.if_obytes += m->m_pkthdr.len; } +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); +#endif + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); goto done; @@ -946,6 +951,10 @@ sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); +#endif if (error == 0) { /* Record statistics for this interface address. */ ia->ia_ifa.if_opackets++; @@ -1480,6 +1489,33 @@ bad: * transmission, and one (IP_MULTICAST_TTL) totally duplicates a * standard option (IP_TTL). */ + +/* + * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. + */ +static struct ifnet * +ip_multicast_if(a, ifindexp) + struct in_addr *a; + int *ifindexp; +{ + int ifindex; + struct ifnet *ifp; + + if (ifindexp) + *ifindexp = 0; + if (ntohl(a->s_addr) >> 24 == 0) { + ifindex = ntohl(a->s_addr) & 0xffffff; + if (ifindex < 0 || if_index < ifindex) + return NULL; + ifp = ifindex2ifnet[ifindex]; + if (ifindexp) + *ifindexp = ifindex; + } else { + INADDR_TO_IFP(*a, ifp); + } + return ifp; +} + /* * Set the IP multicast options in response to user setsockopt(). */ @@ -1496,6 +1532,7 @@ ip_setmoptions(sopt, imop) struct ip_moptions *imo = *imop; struct route ro; struct sockaddr_in *dst; + int ifindex; int s; if (imo == NULL) { @@ -1510,6 +1547,7 @@ ip_setmoptions(sopt, imop) return (ENOBUFS); *imop = imo; imo->imo_multicast_ifp = NULL; + imo->imo_multicast_addr.s_addr = INADDR_ANY; imo->imo_multicast_vif = -1; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; @@ -1555,13 +1593,17 @@ ip_setmoptions(sopt, imop) * it supports multicasting. */ s = splimp(); - INADDR_TO_IFP(addr, ifp); + ifp = ip_multicast_if(&addr, &ifindex); if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { splx(s); error = EADDRNOTAVAIL; break; } imo->imo_multicast_ifp = ifp; + if (ifindex) + imo->imo_multicast_addr = addr; + else + imo->imo_multicast_addr.s_addr = INADDR_ANY; splx(s); break; @@ -1648,7 +1690,7 @@ ip_setmoptions(sopt, imop) rtfree(ro.ro_rt); } else { - INADDR_TO_IFP(mreq.imr_interface, ifp); + ifp = ip_multicast_if(&mreq.imr_interface, NULL); } /* @@ -1716,7 +1758,7 @@ ip_setmoptions(sopt, imop) if (mreq.imr_interface.s_addr == INADDR_ANY) ifp = NULL; else { - INADDR_TO_IFP(mreq.imr_interface, ifp); + ifp = ip_multicast_if(&mreq.imr_interface, NULL); if (ifp == NULL) { error = EADDRNOTAVAIL; splx(s); @@ -1798,7 +1840,10 @@ ip_getmoptions(sopt, imo) case IP_MULTICAST_IF: if (imo == NULL || imo->imo_multicast_ifp == NULL) addr.s_addr = INADDR_ANY; - else { + else if (imo->imo_multicast_addr.s_addr) { + /* return the value user has set */ + addr = imo->imo_multicast_addr; + } else { IFP_TO_IA(imo->imo_multicast_ifp, ia); addr.s_addr = (ia == NULL) ? INADDR_ANY : IA_SIN(ia)->sin_addr.s_addr; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 6354d84..b318a1c 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -37,6 +37,8 @@ #ifndef _NETINET_IP_VAR_H_ #define _NETINET_IP_VAR_H_ +#include <sys/queue.h> + /* * Overlay for ip header used by other protocols (tcp, udp). */ @@ -86,6 +88,7 @@ struct ipoption { */ struct ip_moptions { struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ + struct in_addr imo_multicast_addr; /* ifindex/addr on MULTICAST_IF */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ u_short imo_num_memberships; /* no. memberships this socket */ @@ -122,6 +125,7 @@ struct ipstat { u_long ips_toolong; /* ip length > max ip packet size */ u_long ips_notmember; /* multicasts for unregistered grps */ u_long ips_nogif; /* no match gif found */ + u_long ips_badaddr; /* invalid address on header */ }; #ifdef _KERNEL diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 4fdcf95..32c909a 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -137,6 +137,15 @@ rip_input(m, off, proto) continue; if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (n && ipsec4_in_reject_so(n, last->inp_socket)) { + m_freem(n); + ipsecstat.in_polvio++; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if (n) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) @@ -155,6 +164,15 @@ rip_input(m, off, proto) } last = inp; } +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (last && ipsec4_in_reject_so(m, last->inp_socket)) { + m_freem(m); + ipsecstat.in_polvio++; + ipstat.ips_delivered--; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if (last) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) @@ -168,9 +186,9 @@ rip_input(m, off, proto) sorwakeup(last->inp_socket); } else { m_freem(m); - ipstat.ips_noproto++; - ipstat.ips_delivered--; - } + ipstat.ips_noproto++; + ipstat.ips_delivered--; + } } /* @@ -232,7 +250,10 @@ rip_output(m, so, dst) } #ifdef IPSEC - ipsec_setsocket(m, so); + if (ipsec_setsocket(m, so) != 0) { + m_freem(m); + return ENOBUFS; + } #endif /*IPSEC*/ return (ip_output(m, inp->inp_options, &inp->inp_route, flags, diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 34c2006..3554dae 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -305,6 +305,7 @@ tcp6_input(mp, offp, proto) int *offp, proto; { register struct mbuf *m = *mp; + struct in6_ifaddr *ia6; IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE); @@ -312,7 +313,8 @@ tcp6_input(mp, offp, proto) * draft-itojun-ipv6-tcp-to-anycast * better place to put this in? */ - if (m->m_flags & M_ANYCAST6) { + ia6 = ip6_getdstifaddr(m); + if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) { struct ip6_hdr *ip6; ip6 = mtod(m, struct ip6_hdr *); @@ -379,6 +381,19 @@ tcp_input(m, off0, proto) goto drop; } th = (struct tcphdr *)((caddr_t)ip6 + off0); + + /* + * Be proactive about unspecified IPv6 address in source. + * As we use all-zero to indicate unbounded/unconnected pcb, + * unspecified IPv6 address can be used to confuse us. + * + * Note that packets with unspecified IPv6 destination is + * already dropped in ip6_input. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + /* XXX stat */ + goto drop; + } } else #endif /* INET6 */ { @@ -627,18 +642,6 @@ findpcb: else tiwin = th->th_win; -#ifdef INET6 - /* save packet options if user wanted */ - if (isipv6 && inp->in6p_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, &inp->in6p_options, ip6, m); - } - /* else, should also do ip_srcroute() here? */ -#endif /* INET6 */ - so = inp->inp_socket; if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { #ifdef TCPDEBUG @@ -683,6 +686,50 @@ findpcb: goto drop; } #endif + +#ifdef INET6 + /* + * If deprecated address is forbidden, + * we do not accept SYN to deprecated interface + * address to prevent any new inbound connection from + * getting established. + * When we do not accept SYN, we send a TCP RST, + * with deprecated source address (instead of dropping + * it). We compromise it as it is much better for peer + * to send a RST, and RST will be the final packet + * for the exchange. + * + * If we do not forbid deprecated addresses, we accept + * the SYN packet. RFC2462 does not suggest dropping + * SYN in this case. + * If we decipher RFC2462 5.5.4, it says like this: + * 1. use of deprecated addr with existing + * communication is okay - "SHOULD continue to be + * used" + * 2. use of it with new communication: + * (2a) "SHOULD NOT be used if alternate address + * with sufficient scope is available" + * (2b) nothing mentioned otherwise. + * Here we fall into (2b) case as we have no choice in + * our source address selection - we must obey the peer. + * + * The wording in RFC2462 is confusing, and there are + * multiple description text for deprecated address + * handling - worse, they are not exactly the same. + * I believe 5.5.4 is the best one, so we follow 5.5.4. + */ + if (isipv6 && !ip6_use_deprecated) { + struct in6_ifaddr *ia6; + + if ((ia6 = ip6_getdstifaddr(m)) && + (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { + tp = NULL; + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + } +#endif + so2 = sonewconn(so, 0); if (so2 == 0) { /* @@ -731,10 +778,8 @@ findpcb: if (isipv6) inp->in6p_laddr = ip6->ip6_dst; else { - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { - inp->inp_vflag &= ~INP_IPV6; - inp->inp_vflag |= INP_IPV4; - } + inp->inp_vflag &= ~INP_IPV6; + inp->inp_vflag |= INP_IPV4; #endif /* INET6 */ inp->inp_laddr = ip->ip_dst; #ifdef INET6 @@ -779,21 +824,25 @@ findpcb: #endif #ifdef INET6 if (isipv6) { - /* - * inherit socket options from the listening - * socket. - */ + /* + * Inherit socket options from the listening + * socket. + * Note that in6p_inputopts are not (even + * should not be) copied, since it stores + * previously received options and is used to + * detect if each new option is different than + * the previous one and hence should be passed + * to a user. + * If we copied in6p_inputopts, a user would + * not be able to receive options just after + * calling the accept system call. + */ inp->inp_flags |= oinp->inp_flags & INP_CONTROLOPTS; - if (inp->inp_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, - &inp->in6p_options, - ip6, m); - } + if (oinp->in6p_outputopts) + inp->in6p_outputopts = + ip6_copypktopts(oinp->in6p_outputopts, + M_NOWAIT); } else #endif /* INET6 */ inp->inp_options = ip_srcroute(); diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 286b420..a2a2cf3 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -376,7 +376,7 @@ send: * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. - * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MCLBYTES */ optlen = 0; #ifdef INET6 @@ -823,7 +823,11 @@ send: /* TODO: IPv6 IP6TOS_ECT bit on */ #ifdef IPSEC - ipsec_setsocket(m, so); + if (ipsec_setsocket(m, so) != 0) { + m_freem(m); + error = ENOBUFS; + goto out; + } #endif /*IPSEC*/ error = ip6_output(m, tp->t_inpcb->in6p_outputopts, diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 34c2006..3554dae 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -305,6 +305,7 @@ tcp6_input(mp, offp, proto) int *offp, proto; { register struct mbuf *m = *mp; + struct in6_ifaddr *ia6; IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE); @@ -312,7 +313,8 @@ tcp6_input(mp, offp, proto) * draft-itojun-ipv6-tcp-to-anycast * better place to put this in? */ - if (m->m_flags & M_ANYCAST6) { + ia6 = ip6_getdstifaddr(m); + if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) { struct ip6_hdr *ip6; ip6 = mtod(m, struct ip6_hdr *); @@ -379,6 +381,19 @@ tcp_input(m, off0, proto) goto drop; } th = (struct tcphdr *)((caddr_t)ip6 + off0); + + /* + * Be proactive about unspecified IPv6 address in source. + * As we use all-zero to indicate unbounded/unconnected pcb, + * unspecified IPv6 address can be used to confuse us. + * + * Note that packets with unspecified IPv6 destination is + * already dropped in ip6_input. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + /* XXX stat */ + goto drop; + } } else #endif /* INET6 */ { @@ -627,18 +642,6 @@ findpcb: else tiwin = th->th_win; -#ifdef INET6 - /* save packet options if user wanted */ - if (isipv6 && inp->in6p_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, &inp->in6p_options, ip6, m); - } - /* else, should also do ip_srcroute() here? */ -#endif /* INET6 */ - so = inp->inp_socket; if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { #ifdef TCPDEBUG @@ -683,6 +686,50 @@ findpcb: goto drop; } #endif + +#ifdef INET6 + /* + * If deprecated address is forbidden, + * we do not accept SYN to deprecated interface + * address to prevent any new inbound connection from + * getting established. + * When we do not accept SYN, we send a TCP RST, + * with deprecated source address (instead of dropping + * it). We compromise it as it is much better for peer + * to send a RST, and RST will be the final packet + * for the exchange. + * + * If we do not forbid deprecated addresses, we accept + * the SYN packet. RFC2462 does not suggest dropping + * SYN in this case. + * If we decipher RFC2462 5.5.4, it says like this: + * 1. use of deprecated addr with existing + * communication is okay - "SHOULD continue to be + * used" + * 2. use of it with new communication: + * (2a) "SHOULD NOT be used if alternate address + * with sufficient scope is available" + * (2b) nothing mentioned otherwise. + * Here we fall into (2b) case as we have no choice in + * our source address selection - we must obey the peer. + * + * The wording in RFC2462 is confusing, and there are + * multiple description text for deprecated address + * handling - worse, they are not exactly the same. + * I believe 5.5.4 is the best one, so we follow 5.5.4. + */ + if (isipv6 && !ip6_use_deprecated) { + struct in6_ifaddr *ia6; + + if ((ia6 = ip6_getdstifaddr(m)) && + (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { + tp = NULL; + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + } +#endif + so2 = sonewconn(so, 0); if (so2 == 0) { /* @@ -731,10 +778,8 @@ findpcb: if (isipv6) inp->in6p_laddr = ip6->ip6_dst; else { - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { - inp->inp_vflag &= ~INP_IPV6; - inp->inp_vflag |= INP_IPV4; - } + inp->inp_vflag &= ~INP_IPV6; + inp->inp_vflag |= INP_IPV4; #endif /* INET6 */ inp->inp_laddr = ip->ip_dst; #ifdef INET6 @@ -779,21 +824,25 @@ findpcb: #endif #ifdef INET6 if (isipv6) { - /* - * inherit socket options from the listening - * socket. - */ + /* + * Inherit socket options from the listening + * socket. + * Note that in6p_inputopts are not (even + * should not be) copied, since it stores + * previously received options and is used to + * detect if each new option is different than + * the previous one and hence should be passed + * to a user. + * If we copied in6p_inputopts, a user would + * not be able to receive options just after + * calling the accept system call. + */ inp->inp_flags |= oinp->inp_flags & INP_CONTROLOPTS; - if (inp->inp_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, - &inp->in6p_options, - ip6, m); - } + if (oinp->in6p_outputopts) + inp->in6p_outputopts = + ip6_copypktopts(oinp->in6p_outputopts, + M_NOWAIT); } else #endif /* INET6 */ inp->inp_options = ip_srcroute(); diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 3857b75..06849be 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -443,7 +443,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); #endif #ifdef IPSEC - ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL); + if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { + m_freem(m); + return; + } #endif #ifdef INET6 if (isipv6) { @@ -1020,13 +1023,17 @@ tcp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct tcphdr *thp; struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; int off; + struct tcp_portonly { + u_int16_t th_sport; + u_int16_t th_dport; + } *thp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -1042,56 +1049,36 @@ tcp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; off = 0; /* fool gcc */ + sa6_src = &sa6_any; } - /* - * Translate addresses into internal form. - * Sa check if it is AF_INET6 is done at the top of this funciton. - */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(th)) + if (m->m_pkthdr.len < off + sizeof(*thp)) return; - if (m->m_len < off + sizeof(th)) { - /* - * this should be rare case - * because now MINCLSIZE is "(MHLEN + 1)", - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(th), (caddr_t)&th); - thp = &th; - } else - thp = (struct tcphdr *)(mtod(m, caddr_t) + off); - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport, - &s, thp->th_sport, cmd, notify); + bzero(&th, sizeof(th)); + m_copydata(m, off, sizeof(*thp), (caddr_t)&th); + + in6_pcbnotify(&tcb, sa, th.th_dport, + (struct sockaddr *)ip6cp->ip6c_src, + th.th_sport, cmd, notify); } else - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr, + in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src, 0, cmd, notify); } #endif /* INET6 */ @@ -1323,9 +1310,12 @@ tcp_rtlookup6(inp) if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { - ro6->ro_dst.sin6_family = AF_INET6; - ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst); - ro6->ro_dst.sin6_addr = inp->in6p_faddr; + struct sockaddr_in6 *dst6; + + dst6 = (struct sockaddr_in6 *)&ro6->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(ro6->ro_dst); + dst6->sin6_addr = inp->in6p_faddr; rtalloc((struct route *)ro6); rt = ro6->ro_rt; } @@ -1376,6 +1366,7 @@ ipsec_hdrsiz_tcp(tp) sizeof(struct ip)); bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, sizeof(struct tcphdr)); + ip->ip_vhl = IP_VHL_BORING; hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 3857b75..06849be 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -443,7 +443,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); #endif #ifdef IPSEC - ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL); + if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { + m_freem(m); + return; + } #endif #ifdef INET6 if (isipv6) { @@ -1020,13 +1023,17 @@ tcp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct tcphdr *thp; struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; int off; + struct tcp_portonly { + u_int16_t th_sport; + u_int16_t th_dport; + } *thp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -1042,56 +1049,36 @@ tcp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; off = 0; /* fool gcc */ + sa6_src = &sa6_any; } - /* - * Translate addresses into internal form. - * Sa check if it is AF_INET6 is done at the top of this funciton. - */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(th)) + if (m->m_pkthdr.len < off + sizeof(*thp)) return; - if (m->m_len < off + sizeof(th)) { - /* - * this should be rare case - * because now MINCLSIZE is "(MHLEN + 1)", - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(th), (caddr_t)&th); - thp = &th; - } else - thp = (struct tcphdr *)(mtod(m, caddr_t) + off); - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport, - &s, thp->th_sport, cmd, notify); + bzero(&th, sizeof(th)); + m_copydata(m, off, sizeof(*thp), (caddr_t)&th); + + in6_pcbnotify(&tcb, sa, th.th_dport, + (struct sockaddr *)ip6cp->ip6c_src, + th.th_sport, cmd, notify); } else - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr, + in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src, 0, cmd, notify); } #endif /* INET6 */ @@ -1323,9 +1310,12 @@ tcp_rtlookup6(inp) if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { - ro6->ro_dst.sin6_family = AF_INET6; - ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst); - ro6->ro_dst.sin6_addr = inp->in6p_faddr; + struct sockaddr_in6 *dst6; + + dst6 = (struct sockaddr_in6 *)&ro6->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(ro6->ro_dst); + dst6->sin6_addr = inp->in6p_faddr; rtalloc((struct route *)ro6); rt = ro6->ro_rt; } @@ -1376,6 +1366,7 @@ ipsec_hdrsiz_tcp(tp) sizeof(struct ip)); bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, sizeof(struct tcphdr)); + ip->ip_vhl = IP_VHL_BORING; hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 25834d4..aea92c0 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -240,8 +240,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) } inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { - + if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr)) inp->inp_vflag |= INP_IPV4; else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { @@ -292,7 +291,8 @@ tcp6_usr_listen(struct socket *so, struct proc *p) COMMON_START(); if (inp->inp_lport == 0) { inp->inp_vflag &= ~INP_IPV4; - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) + if (ip6_mapped_addr_on && + (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) inp->inp_vflag |= INP_IPV4; error = in6_pcbbind(inp, (struct sockaddr *)0, p); } @@ -361,10 +361,13 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) goto out; } - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0 && - IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { + if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { struct sockaddr_in sin; + if (!ip6_mapped_addr_on || + (inp->inp_flags & IN6P_IPV6_V6ONLY)) + return(EINVAL); + in6_sin6_2_sin(&sin, sin6p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 350a384..d546b1f 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -392,8 +392,7 @@ udp_input(m, off, proto) #endif ip_savecontrol(inp, &opts, ip, m); } - iphlen += sizeof(struct udphdr); - m_adj(m, iphlen); + m_adj(m, iphlen + sizeof(struct udphdr)); #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); @@ -744,7 +743,10 @@ udp_output(inp, m, addr, control, p) udpstat.udps_opackets++; #ifdef IPSEC - ipsec_setsocket(m, inp->inp_socket); + if (ipsec_setsocket(m, inp->inp_socket) != 0) { + error = ENOBUFS; + goto release; + } #endif /*IPSEC*/ error = ip_output(m, inp->inp_options, &inp->inp_route, (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), diff --git a/sys/netinet6/ah.h b/sys/netinet6/ah.h index 3c7d0a6..0846466 100644 --- a/sys/netinet6/ah.h +++ b/sys/netinet6/ah.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ah.h,v 1.10 2000/07/02 13:23:33 itojun Exp $ */ +/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,7 +37,9 @@ #ifndef _NETINET6_AH_H_ #define _NETINET6_AH_H_ -struct secasvar; +#if defined(_KERNEL) && !defined(_LKM) +#include "opt_inet.h" +#endif struct ah { u_int8_t ah_nxt; /* Next Header */ @@ -56,6 +58,9 @@ struct newah { /* variable size, 32bit bound*/ /* Authentication data */ }; +#ifdef _KERNEL +struct secasvar; + struct ah_algorithm_state { struct secasvar *sav; void* foo; /*per algorithm data - maybe*/ @@ -74,8 +79,7 @@ struct ah_algorithm { #define AH_MAXSUMSIZE 16 -#ifdef _KERNEL -extern struct ah_algorithm ah_algorithms[]; +extern const struct ah_algorithm *ah_algorithm_lookup __P((int)); /* cksum routines */ extern int ah_hdrlen __P((struct secasvar *)); @@ -84,7 +88,7 @@ extern size_t ah_hdrsiz __P((struct ipsecrequest *)); extern void ah4_input __P((struct mbuf *, ...)); extern int ah4_output __P((struct mbuf *, struct ipsecrequest *)); extern int ah4_calccksum __P((struct mbuf *, caddr_t, size_t, - struct ah_algorithm *, struct secasvar *)); + const struct ah_algorithm *, struct secasvar *)); #endif /*_KERNEL*/ #endif /*_NETINET6_AH_H_*/ diff --git a/sys/netinet6/ah6.h b/sys/netinet6/ah6.h index 4010f13..ead07bf 100644 --- a/sys/netinet6/ah6.h +++ b/sys/netinet6/ah6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ah.h,v 1.10 2000/07/02 13:23:33 itojun Exp $ */ +/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -44,7 +44,9 @@ extern int ah6_input __P((struct mbuf **, int *, int)); extern int ah6_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *)); extern int ah6_calccksum __P((struct mbuf *, caddr_t, size_t, - struct ah_algorithm *, struct secasvar *)); + const struct ah_algorithm *, struct secasvar *)); + +extern void ah6_ctlinput __P((int, struct sockaddr *, void *)); #endif #endif /*_NETINET6_AH6_H_*/ diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c index 477de51..5c7afaf 100644 --- a/sys/netinet6/ah_core.c +++ b/sys/netinet6/ah_core.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ah_core.c,v 1.35 2000/06/14 11:14:03 itojun Exp $ */ +/* $KAME: ah_core.c,v 1.44 2001/03/12 11:24:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -34,6 +34,8 @@ * RFC1826/2402 authentication header. */ +/* TODO: have shared routines for hmac-* algorithms */ + #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" @@ -82,6 +84,7 @@ #include <netkey/keydb.h> #include <sys/md5.h> #include <crypto/sha1.h> +#include <crypto/sha2/sha2.h> #include <net/net_osdep.h> @@ -90,8 +93,7 @@ static int ah_sumsiz_1216 __P((struct secasvar *)); static int ah_sumsiz_zero __P((struct secasvar *)); static int ah_none_mature __P((struct secasvar *)); -static int ah_none_init __P((struct ah_algorithm_state *, - struct secasvar *)); +static int ah_none_init __P((struct ah_algorithm_state *, struct secasvar *)); static void ah_none_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_none_result __P((struct ah_algorithm_state *, caddr_t)); static int ah_keyed_md5_mature __P((struct secasvar *)); @@ -118,25 +120,84 @@ static int ah_hmac_sha1_init __P((struct ah_algorithm_state *, static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, caddr_t)); +static int ah_hmac_sha2_256_mature __P((struct secasvar *)); +static int ah_hmac_sha2_256_init __P((struct ah_algorithm_state *, + struct secasvar *)); +static void ah_hmac_sha2_256_loop __P((struct ah_algorithm_state *, caddr_t, + size_t)); +static void ah_hmac_sha2_256_result __P((struct ah_algorithm_state *, caddr_t)); +static int ah_hmac_sha2_384_mature __P((struct secasvar *)); +static int ah_hmac_sha2_384_init __P((struct ah_algorithm_state *, + struct secasvar *)); +static void ah_hmac_sha2_384_loop __P((struct ah_algorithm_state *, caddr_t, + size_t)); +static void ah_hmac_sha2_384_result __P((struct ah_algorithm_state *, caddr_t)); +static int ah_hmac_sha2_512_mature __P((struct secasvar *)); +static int ah_hmac_sha2_512_init __P((struct ah_algorithm_state *, + struct secasvar *)); +static void ah_hmac_sha2_512_loop __P((struct ah_algorithm_state *, caddr_t, + size_t)); +static void ah_hmac_sha2_512_result __P((struct ah_algorithm_state *, caddr_t)); + +static void ah_update_mbuf __P((struct mbuf *, int, int, + const struct ah_algorithm *, struct ah_algorithm_state *)); + +const struct ah_algorithm * +ah_algorithm_lookup(idx) + int idx; +{ + /* checksum algorithms */ + static struct ah_algorithm ah_algorithms[] = { + { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5", + ah_hmac_md5_init, ah_hmac_md5_loop, + ah_hmac_md5_result, }, + { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, "hmac-sha1", + ah_hmac_sha1_init, ah_hmac_sha1_loop, + ah_hmac_sha1_result, }, + { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5", + ah_keyed_md5_init, ah_keyed_md5_loop, + ah_keyed_md5_result, }, + { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, "keyed-sha1", + ah_keyed_sha1_init, ah_keyed_sha1_loop, + ah_keyed_sha1_result, }, + { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none", + ah_none_init, ah_none_loop, ah_none_result, }, + { ah_sumsiz_1216, ah_hmac_sha2_256_mature, 256, 256, + "hmac-sha2-256", + ah_hmac_sha2_256_init, ah_hmac_sha2_256_loop, + ah_hmac_sha2_256_result, }, + { ah_sumsiz_1216, ah_hmac_sha2_384_mature, 384, 384, + "hmac-sha2-384", + ah_hmac_sha2_384_init, ah_hmac_sha2_384_loop, + ah_hmac_sha2_384_result, }, + { ah_sumsiz_1216, ah_hmac_sha2_512_mature, 512, 512, + "hmac-sha2-512", + ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop, + ah_hmac_sha2_512_result, }, + }; + + switch (idx) { + case SADB_AALG_MD5HMAC: + return &ah_algorithms[0]; + case SADB_AALG_SHA1HMAC: + return &ah_algorithms[1]; + case SADB_X_AALG_MD5: + return &ah_algorithms[2]; + case SADB_X_AALG_SHA: + return &ah_algorithms[3]; + case SADB_X_AALG_NULL: + return &ah_algorithms[4]; + case SADB_X_AALG_SHA2_256: + return &ah_algorithms[5]; + case SADB_X_AALG_SHA2_384: + return &ah_algorithms[6]; + case SADB_X_AALG_SHA2_512: + return &ah_algorithms[7]; + default: + return NULL; + } +} -static void ah_update_mbuf __P((struct mbuf *, int, int, struct ah_algorithm *, - struct ah_algorithm_state *)); - -/* checksum algorithms */ -/* NOTE: The order depends on SADB_AALG_x in net/pfkeyv2.h */ -struct ah_algorithm ah_algorithms[] = { - { 0, 0, 0, 0, 0, 0, }, - { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5", - ah_hmac_md5_init, ah_hmac_md5_loop, ah_hmac_md5_result, }, - { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, "hmac-sha1", - ah_hmac_sha1_init, ah_hmac_sha1_loop, ah_hmac_sha1_result, }, - { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5", - ah_keyed_md5_init, ah_keyed_md5_loop, ah_keyed_md5_result, }, - { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, "keyed-sha1", - ah_keyed_sha1_init, ah_keyed_sha1_loop, ah_keyed_sha1_result, }, - { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none", - ah_none_init, ah_none_loop, ah_none_result, }, -}; static int ah_sumsiz_1216(sav) @@ -297,13 +358,19 @@ static int ah_keyed_sha1_mature(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_keyed_sha1_mature: unsupported algorithm.\n")); + return 1; + } + if (sav->key_auth->sadb_key_bits < algo->keymin || algo->keymax < sav->key_auth->sadb_key_bits) { ipseclog((LOG_ERR, @@ -385,7 +452,7 @@ ah_keyed_sha1_loop(state, addr, len) panic("ah_keyed_sha1_loop: what?"); ctxt = (SHA1_CTX *)state->foo; - SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len); + SHA1Update(ctxt, (caddr_t)addr, (size_t)len); } static void @@ -414,13 +481,19 @@ static int ah_hmac_md5_mature(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_hmac_md5_mature: unsupported algorithm.\n")); + return 1; + } + if (sav->key_auth->sadb_key_bits < algo->keymin || algo->keymax < sav->key_auth->sadb_key_bits) { ipseclog((LOG_ERR, @@ -532,13 +605,19 @@ static int ah_hmac_sha1_mature(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_hmac_sha1_mature: unsupported algorithm.\n")); + return 1; + } + if (sav->key_auth->sadb_key_bits < algo->keymin || algo->keymax < sav->key_auth->sadb_key_bits) { ipseclog((LOG_ERR, @@ -579,7 +658,7 @@ ah_hmac_sha1_init(state, sav) /* compress the key if necessery */ if (64 < _KEYLEN(state->sav->key_auth)) { SHA1Init(ctxt); - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), + SHA1Update(ctxt, _KEYBUF(state->sav->key_auth), _KEYLEN(state->sav->key_auth)); SHA1Final(&tk[0], ctxt); key = &tk[0]; @@ -616,7 +695,7 @@ ah_hmac_sha1_loop(state, addr, len) panic("ah_hmac_sha1_loop: what?"); ctxt = (SHA1_CTX *)(((u_char *)state->foo) + 128); - SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len); + SHA1Update(ctxt, (caddr_t)addr, (size_t)len); } static void @@ -640,7 +719,7 @@ ah_hmac_sha1_result(state, addr) SHA1Init(ctxt); SHA1Update(ctxt, opad, 64); - SHA1Update(ctxt, (u_int8_t *)&digest[0], sizeof(digest)); + SHA1Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); SHA1Final((caddr_t)&digest[0], ctxt); bcopy(&digest[0], (void *)addr, HMACSIZE); @@ -648,6 +727,404 @@ ah_hmac_sha1_result(state, addr) free(state->foo, M_TEMP); } +static int +ah_hmac_sha2_256_mature(sav) + struct secasvar *sav; +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: unsupported algorithm.\n")); + return 1; + } + + if (sav->key_auth->sadb_key_bits < algo->keymin || + algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_256_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + u_char *ipad; + u_char *opad; + SHA256_CTX *ctxt; + u_char tk[SHA256_DIGEST_LENGTH]; + u_char *key; + size_t keylen; + size_t i; + + if (!state) + panic("ah_hmac_sha2_256_init: what?"); + + state->sav = sav; + state->foo = (void *)malloc(64 + 64 + sizeof(SHA256_CTX), + M_TEMP, M_NOWAIT); + if (!state->foo) + return ENOBUFS; + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA256_CTX *)(opad + 64); + + /* compress the key if necessery */ + if (64 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA256_Init(ctxt); + SHA256_Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA256_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; + } else { + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 64); + bzero(opad, 64); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA256_Init(ctxt); + SHA256_Update(ctxt, ipad, 64); + + return 0; +} + +static void +ah_hmac_sha2_256_loop(state, addr, len) + struct ah_algorithm_state *state; + caddr_t addr; + size_t len; +{ + SHA256_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_256_loop: what?"); + + ctxt = (SHA256_CTX *)(((u_char *)state->foo) + 128); + SHA256_Update(ctxt, (caddr_t)addr, (size_t)len); +} + +static void +ah_hmac_sha2_256_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[SHA256_DIGEST_LENGTH]; + u_char *ipad; + u_char *opad; + SHA256_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_256_result: what?"); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA256_CTX *)(opad + 64); + + SHA256_Final((caddr_t)&digest[0], ctxt); + + bzero(ctxt, sizeof(*ctxt)); + SHA256_Init(ctxt); + SHA256_Update(ctxt, opad, 64); + SHA256_Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA256_Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + free(state->foo, M_TEMP); +} + +static int +ah_hmac_sha2_384_mature(sav) + struct secasvar *sav; +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: unsupported algorithm.\n")); + return 1; + } + + if (sav->key_auth->sadb_key_bits < algo->keymin || + algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_384_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + u_char *ipad; + u_char *opad; + SHA384_CTX *ctxt; + u_char tk[SHA384_DIGEST_LENGTH]; + u_char *key; + size_t keylen; + size_t i; + + if (!state) + panic("ah_hmac_sha2_384_init: what?"); + + state->sav = sav; + state->foo = (void *)malloc(64 + 64 + sizeof(SHA384_CTX), + M_TEMP, M_NOWAIT); + if (!state->foo) + return ENOBUFS; + bzero(state->foo, 64 + 64 + sizeof(SHA384_CTX)); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA384_CTX *)(opad + 64); + + /* compress the key if necessery */ + if (64 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA384_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; + } else { + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 64); + bzero(opad, 64); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, ipad, 64); + + return 0; +} + +static void +ah_hmac_sha2_384_loop(state, addr, len) + struct ah_algorithm_state *state; + caddr_t addr; + size_t len; +{ + SHA384_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_384_loop: what?"); + + ctxt = (SHA384_CTX *)(((u_char *)state->foo) + 128); + SHA384_Update(ctxt, (caddr_t)addr, (size_t)len); +} + +static void +ah_hmac_sha2_384_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[SHA384_DIGEST_LENGTH]; + u_char *ipad; + u_char *opad; + SHA384_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_384_result: what?"); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA384_CTX *)(opad + 64); + + SHA384_Final((caddr_t)&digest[0], ctxt); + + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, opad, 64); + SHA384_Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA384_Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + free(state->foo, M_TEMP); +} + +static int +ah_hmac_sha2_512_mature(sav) + struct secasvar *sav; +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: unsupported algorithm.\n")); + return 1; + } + + if (sav->key_auth->sadb_key_bits < algo->keymin || + algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_512_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + u_char *ipad; + u_char *opad; + SHA512_CTX *ctxt; + u_char tk[SHA512_DIGEST_LENGTH]; + u_char *key; + size_t keylen; + size_t i; + + if (!state) + panic("ah_hmac_sha2_512_init: what?"); + + state->sav = sav; + state->foo = (void *)malloc(64 + 64 + sizeof(SHA512_CTX), + M_TEMP, M_NOWAIT); + if (!state->foo) + return ENOBUFS; + bzero(state->foo, 64 + 64 + sizeof(SHA512_CTX)); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA512_CTX *)(opad + 64); + + /* compress the key if necessery */ + if (64 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA512_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; + } else { + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 64); + bzero(opad, 64); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, ipad, 64); + + return 0; +} + +static void +ah_hmac_sha2_512_loop(state, addr, len) + struct ah_algorithm_state *state; + caddr_t addr; + size_t len; +{ + SHA512_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_512_loop: what?"); + + ctxt = (SHA512_CTX *)(((u_char *)state->foo) + 128); + SHA512_Update(ctxt, (caddr_t)addr, (size_t)len); +} + +static void +ah_hmac_sha2_512_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[SHA512_DIGEST_LENGTH]; + u_char *ipad; + u_char *opad; + SHA512_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_512_result: what?"); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA512_CTX *)(opad + 64); + + SHA512_Final((caddr_t)&digest[0], ctxt); + + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, opad, 64); + SHA512_Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA512_Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + free(state->foo, M_TEMP); +} + /*------------------------------------------------------------*/ /* @@ -658,7 +1135,7 @@ ah_update_mbuf(m, off, len, algo, algos) struct mbuf *m; int off; int len; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; struct ah_algorithm_state *algos; { struct mbuf *n; @@ -695,6 +1172,7 @@ ah_update_mbuf(m, off, len, algo, algos) } } +#ifdef INET /* * Go generate the checksum. This function won't modify the mbuf chain * except AH itself. @@ -707,7 +1185,7 @@ ah4_calccksum(m, ahdat, len, algo, sav) struct mbuf *m; caddr_t ahdat; size_t len; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; struct secasvar *sav; { int off; @@ -935,6 +1413,7 @@ fail: m_free(n); return error; } +#endif #ifdef INET6 /* @@ -949,7 +1428,7 @@ ah6_calccksum(m, ahdat, len, algo, sav) struct mbuf *m; caddr_t ahdat; size_t len; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; struct secasvar *sav; { int newoff, off; diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c index b0489d1..070883e 100644 --- a/sys/netinet6/ah_input.c +++ b/sys/netinet6/ah_input.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ah_input.c,v 1.29 2000/05/29 08:33:53 itojun Exp $ */ +/* $KAME: ah_input.c,v 1.59 2001/05/16 04:01:27 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -66,7 +66,9 @@ #ifdef INET6 #include <netinet/ip6.h> #include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> #include <netinet/icmp6.h> +#include <netinet6/ip6protosw.h> #endif #include <netinet6/ipsec.h> @@ -107,16 +109,16 @@ ah4_input(m, va_alist) struct ip *ip; struct ah *ah; u_int32_t spi; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t siz; size_t siz1; u_char *cksum; struct secasvar *sav = NULL; u_int16_t nxt; size_t hlen; - int s; int off, proto; va_list ap; + size_t stripsiz = 0; va_start(ap, m); off = va_arg(ap, int); @@ -175,16 +177,16 @@ ah4_input(m, va_alist) ipsecstat.in_badspi++; goto fail; } - if (sav->alg_auth == SADB_AALG_NONE) { + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { ipseclog((LOG_DEBUG, "IPv4 AH input: " - "unspecified authentication algorithm for spi %u\n", + "unsupported authentication algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto fail; } - algo = &ah_algorithms[sav->alg_auth]; - siz = (*algo->sumsiz)(sav); siz1 = ((siz + 3) & ~(4 - 1)); @@ -284,29 +286,23 @@ ah4_input(m, va_alist) goto fail; } - { -#if 1 /* * some of IP header fields are flipped to the host endian. * convert them back to network endian. VERY stupid. */ ip->ip_len = htons(ip->ip_len + hlen); ip->ip_off = htons(ip->ip_off); -#endif if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { free(cksum, M_TEMP); ipsecstat.in_inval++; goto fail; } ipsecstat.in_ahhist[sav->alg_auth]++; -#if 1 /* * flip them back. */ ip->ip_len = ntohs(ip->ip_len) - hlen; ip->ip_off = ntohs(ip->ip_off); -#endif - } { caddr_t sumpos = NULL; @@ -397,7 +393,14 @@ ah4_input(m, va_alist) } /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) { + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) { /* * strip off all the headers that precedes AH. * IP xx AH IP' payload -> IP' payload @@ -405,17 +408,9 @@ ah4_input(m, va_alist) * XXX more sanity checks * XXX relationship with gif? */ - size_t stripsiz = 0; u_int8_t tos; tos = ip->ip_tos; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } m_adj(m, off + stripsiz); if (m->m_len < sizeof(*ip)) { m = m_pullup(m, sizeof(*ip)); @@ -469,6 +464,11 @@ ah4_input(m, va_alist) #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { + ipsecstat.in_nomem++; + goto fail; + } if (! IF_HANDOFF(&ipintrq, m, NULL)) { ipsecstat.in_inval++; @@ -482,15 +482,6 @@ ah4_input(m, va_alist) /* * strip off AH. */ - size_t stripsiz = 0; - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } ip = mtod(m, struct ip *); #ifndef PULLDOWN_TEST @@ -548,10 +539,19 @@ ah4_input(m, va_alist) /* forget about IP hdr checksum, the check has already been passed */ key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { + ipsecstat.in_nomem++; + goto fail; + } - if (nxt != IPPROTO_DONE) + if (nxt != IPPROTO_DONE) { + if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto fail; + } (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); - else + } else m_freem(m); m = NULL; } @@ -587,12 +587,13 @@ ah6_input(mp, offp, proto) struct ip6_hdr *ip6; struct ah *ah; u_int32_t spi; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t siz; size_t siz1; u_char *cksum; struct secasvar *sav = NULL; u_int16_t nxt; + size_t stripsiz = 0; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); @@ -601,7 +602,7 @@ ah6_input(mp, offp, proto) IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); if (ah == NULL) { ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); - ipsecstat.in_inval++; + ipsec6stat.in_inval++; return IPPROTO_DONE; } #endif @@ -637,16 +638,16 @@ ah6_input(mp, offp, proto) ipsec6stat.in_badspi++; goto fail; } - if (sav->alg_auth == SADB_AALG_NONE) { + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { ipseclog((LOG_DEBUG, "IPv6 AH input: " - "unspecified authentication algorithm for spi %u\n", + "unsupported authentication algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto fail; } - algo = &ah_algorithms[sav->alg_auth]; - siz = (*algo->sumsiz)(sav); siz1 = ((siz + 3) & ~(4 - 1)); @@ -685,7 +686,7 @@ ah6_input(mp, offp, proto) sizeof(struct ah) + sizoff + siz1); if (ah == NULL) { ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); - ipsecstat.in_inval++; + ipsec6stat.in_inval++; m = NULL; goto fail; } @@ -808,7 +809,14 @@ ah6_input(mp, offp, proto) } /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) { + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) { /* * strip off all the headers that precedes AH. * IP6 xx AH IP6' payload -> IP6' payload @@ -816,17 +824,9 @@ ah6_input(mp, offp, proto) * XXX more sanity checks * XXX relationship with gif? */ - size_t stripsiz = 0; u_int32_t flowinfo; /*net endian*/ flowinfo = ip6->ip6_flow; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } m_adj(m, off + stripsiz); if (m->m_len < sizeof(*ip6)) { /* @@ -870,6 +870,11 @@ ah6_input(mp, offp, proto) #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { + ipsec6stat.in_nomem++; + goto fail; + } if (! IF_HANDOFF(&ip6intrq, m, NULL)) { ipsec6stat.in_inval++; @@ -883,7 +888,6 @@ ah6_input(mp, offp, proto) /* * strip off AH. */ - size_t stripsiz = 0; char *prvnxtp; /* @@ -894,14 +898,6 @@ ah6_input(mp, offp, proto) prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ *prvnxtp = nxt; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } - ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST /* @@ -945,6 +941,10 @@ ah6_input(mp, offp, proto) ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { + ipsec6stat.in_nomem++; + goto fail; + } } *offp = off; @@ -968,4 +968,92 @@ fail: m_freem(m); return IPPROTO_DONE; } + +void +ah6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + const struct newah *ahp; + struct newah ah; + struct secasvar *sav; + struct ip6_hdr *ip6; + struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + int off; + struct sockaddr_in6 sa6_src, sa6_dst; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + if ((unsigned)cmd >= PRC_NCMDS) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + + if (ip6) { + /* + * XXX: We assume that when ip6 is non NULL, + * M and OFF are valid. + */ + + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(ah)) + return; + + if (m->m_len < off + sizeof(ah)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(ah), (caddr_t)&ah); + ahp = &ah; + } else + ahp = (struct newah *)(mtod(m, caddr_t) + off); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + + /* + * Check to see if we have a valid SA corresponding to + * the address in the ICMP message payload. + */ + sav = key_allocsa(AF_INET6, + (caddr_t)&sa6_src.sin6_addr, + (caddr_t)&sa6_dst.sin6_addr, + IPPROTO_AH, ahp->ah_spi); + if (sav) { + if (sav->state == SADB_SASTATE_MATURE || + sav->state == SADB_SASTATE_DYING) + valid++; + key_freesav(sav); + } + + /* XXX Further validation? */ + + /* + * Depending on the value of "valid" and routing table + * size (mtudisc_{hi,lo}wat), we will: + * - recalcurate the new MTU and create the + * corresponding routing entry, or + * - ignore the MTU change notification. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + } + + /* we normally notify single pcb here */ + } else { + /* we normally notify any pcb here */ + } +} #endif /* INET6 */ diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c index 59263cd..983ecab 100644 --- a/sys/netinet6/ah_output.c +++ b/sys/netinet6/ah_output.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ah_output.c,v 1.22 2000/07/03 13:23:28 itojun Exp $ */ +/* $KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -76,7 +76,9 @@ #include <net/net_osdep.h> +#ifdef INET static struct in_addr *ah4_finaldst __P((struct mbuf *)); +#endif /* * compute AH header size. @@ -87,7 +89,7 @@ size_t ah_hdrsiz(isr) struct ipsecrequest *isr; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t hdrsiz; /* sanity check */ @@ -104,7 +106,7 @@ ah_hdrsiz(isr) goto estimate; /* we need transport mode AH. */ - algo = &ah_algorithms[isr->sav->alg_auth]; + algo = ah_algorithm_lookup(isr->sav->alg_auth); if (!algo) goto estimate; @@ -131,6 +133,7 @@ ah_hdrsiz(isr) return sizeof(struct newah) + 16; } +#ifdef INET /* * Modify the packet so that it includes the authentication data. * The mbuf passed must start with IPv4 header. @@ -144,7 +147,7 @@ ah4_output(m, isr) struct ipsecrequest *isr; { struct secasvar *sav = isr->sav; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; u_int32_t spi; u_char *ahdrpos; u_char *ahsumpos = NULL; @@ -171,7 +174,14 @@ ah4_output(m, isr) return EINVAL; } - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + ipsecstat.out_inval++; + m_freem(m); + return EINVAL; + } spi = sav->spi; /* @@ -314,16 +324,19 @@ ah4_output(m, isr) return 0; } +#endif /* Calculate AH length */ int ah_hdrlen(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; int plen, ahlen; - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) + return 0; if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ @@ -351,7 +364,7 @@ ah6_output(m, nexthdrp, md, isr) struct mbuf *mprev; struct mbuf *mah; struct secasvar *sav = isr->sav; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; u_int32_t spi; u_char *ahsumpos = NULL; size_t plen; /*AH payload size in bytes*/ @@ -414,7 +427,14 @@ ah6_output(m, nexthdrp, md, isr) return EINVAL; } - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + ipsec6stat.out_inval++; + m_freem(m); + return EINVAL; + } spi = sav->spi; /* @@ -447,7 +467,7 @@ ah6_output(m, nexthdrp, md, isr) ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + ipsec6stat.out_inval++; m_freem(m); return EINVAL; } @@ -479,6 +499,7 @@ ah6_output(m, nexthdrp, md, isr) } #endif +#ifdef INET /* * Find the final destination if there is loose/strict source routing option. * Returns NULL if there's no source routing options. @@ -564,3 +585,4 @@ ah4_finaldst(m) } return NULL; } +#endif diff --git a/sys/netinet6/dest6.c b/sys/netinet6/dest6.c index 8d3987c..8ecde86 100644 --- a/sys/netinet6/dest6.c +++ b/sys/netinet6/dest6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: dest6.c,v 1.12 2000/05/05 11:00:57 sumikawa Exp $ */ +/* $KAME: dest6.c,v 1.27 2001/03/29 05:34:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,12 +35,14 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/domain.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/errno.h> #include <sys/time.h> +#include <sys/kernel.h> #include <net/if.h> #include <net/route.h> @@ -59,10 +61,13 @@ dest6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto; { - register struct mbuf *m = *mp; + struct mbuf *m = *mp; int off = *offp, dstoptlen, optlen; struct ip6_dest *dstopts; u_int8_t *opt; + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); /* validation of the length of the header */ #ifndef PULLDOWN_TEST @@ -102,19 +107,21 @@ dest6_input(mp, offp, proto) case IP6OPT_PADN: optlen = *(opt + 1) + 2; break; - default: /* unknown option */ - if ((optlen = ip6_unknown_opt(opt, m, - opt-mtod(m, u_int8_t *))) == -1) - return(IPPROTO_DONE); - optlen += 2; - break; + + default: /* unknown option */ + optlen = ip6_unknown_opt(opt, m, + opt - mtod(m, u_int8_t *)); + if (optlen == -1) + return (IPPROTO_DONE); + optlen += 2; + break; } } *offp = off; - return(dstopts->ip6d_nxt); + return (dstopts->ip6d_nxt); bad: m_freem(m); - return(IPPROTO_DONE); + return (IPPROTO_DONE); } diff --git a/sys/netinet6/esp.h b/sys/netinet6/esp.h index 95deec3..6f794a8 100644 --- a/sys/netinet6/esp.h +++ b/sys/netinet6/esp.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: esp.h,v 1.8 2000/07/02 13:23:33 itojun Exp $ */ +/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,7 +37,9 @@ #ifndef _NETINET6_ESP_H_ #define _NETINET6_ESP_H_ -struct secasvar; +#if defined(_KERNEL) && !defined(_LKM) +#include "opt_inet.h" +#endif struct esp { u_int32_t esp_spi; /* ESP */ @@ -67,35 +69,41 @@ struct esptail { /*variable size, 32bit bound*/ /* Authentication data (new IPsec)*/ }; -struct esp_algorithm_state { - struct secasvar *sav; - void* foo; /*per algorithm data - maybe*/ -}; +#ifdef _KERNEL +struct secasvar; -/* XXX yet to be defined */ struct esp_algorithm { size_t padbound; /* pad boundary, in byte */ + int ivlenval; /* iv length, in byte */ int (*mature) __P((struct secasvar *)); int keymin; /* in bits */ int keymax; /* in bits */ + int (*schedlen) __P((const struct esp_algorithm *)); const char *name; - int (*ivlen) __P((struct secasvar *)); + int (*ivlen) __P((const struct esp_algorithm *, struct secasvar *)); int (*decrypt) __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); int (*encrypt) __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); + /* not supposed to be called directly */ + int (*schedule) __P((const struct esp_algorithm *, struct secasvar *)); + int (*blockdecrypt) __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); + int (*blockencrypt) __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); }; -#ifdef _KERNEL -extern struct esp_algorithm esp_algorithms[]; +extern const struct esp_algorithm *esp_algorithm_lookup __P((int)); +extern int esp_max_ivlen __P((void)); /* crypt routines */ extern int esp4_output __P((struct mbuf *, struct ipsecrequest *)); extern void esp4_input __P((struct mbuf *, ...)); extern size_t esp_hdrsiz __P((struct ipsecrequest *)); -#endif /*_KERNEL*/ +extern int esp_schedule __P((const struct esp_algorithm *, struct secasvar *)); extern int esp_auth __P((struct mbuf *, size_t, size_t, struct secasvar *, u_char *)); +#endif /*_KERNEL*/ #endif /*_NETINET6_ESP_H_*/ diff --git a/sys/netinet6/esp6.h b/sys/netinet6/esp6.h index 5d2f984..d774d24 100644 --- a/sys/netinet6/esp6.h +++ b/sys/netinet6/esp6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: esp.h,v 1.8 2000/07/02 13:23:33 itojun Exp $ */ +/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -41,6 +41,8 @@ extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *)); extern int esp6_input __P((struct mbuf **, int *, int)); + +extern void esp6_ctlinput __P((int, struct sockaddr *, void *)); #endif /*_KERNEL*/ #endif /*_NETINET6_ESP6_H_*/ diff --git a/sys/netinet6/esp_core.c b/sys/netinet6/esp_core.c index e5f8ec5..0319255 100644 --- a/sys/netinet6/esp_core.c +++ b/sys/netinet6/esp_core.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: esp_core.c,v 1.15 2000/06/14 10:41:18 itojun Exp $ */ +/* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,6 +35,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/domain.h> #include <sys/protosw.h> @@ -66,87 +67,181 @@ #ifdef INET6 #include <netinet6/esp6.h> #endif +#include <netinet6/esp_rijndael.h> #include <net/pfkeyv2.h> #include <netkey/keydb.h> +#include <netkey/key.h> #include <crypto/des/des.h> #include <crypto/blowfish/blowfish.h> #include <crypto/cast128/cast128.h> -#include <crypto/rc5/rc5.h> #include <net/net_osdep.h> static int esp_null_mature __P((struct secasvar *)); -static int esp_null_ivlen __P((struct secasvar *)); static int esp_null_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); static int esp_null_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); static int esp_descbc_mature __P((struct secasvar *)); -static int esp_descbc_ivlen __P((struct secasvar *)); -static int esp_descbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_descbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); +static int esp_descbc_ivlen __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_des_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_des_schedlen __P((const struct esp_algorithm *)); +static int esp_des_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_des_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); static int esp_cbc_mature __P((struct secasvar *)); -static int esp_blowfish_cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_blowfish_cbc_encrypt __P((struct mbuf *, size_t, - size_t, struct secasvar *, struct esp_algorithm *, int)); -static int esp_blowfish_cbc_ivlen __P((struct secasvar *)); -static int esp_cast128cbc_ivlen __P((struct secasvar *)); -static int esp_cast128cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_cast128cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_3descbc_ivlen __P((struct secasvar *)); -static int esp_3descbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_3descbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_rc5cbc_ivlen __P((struct secasvar *)); -static int esp_rc5cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_rc5cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static void esp_increment_iv __P((struct secasvar *)); -static caddr_t mbuf_find_offset __P((struct mbuf *, size_t, size_t)); - -/* NOTE: The order depends on SADB_EALG_x in netkey/keyv2.h */ -struct esp_algorithm esp_algorithms[] = { - { 0, 0, 0, 0, 0, 0, 0, }, - { 8, esp_descbc_mature, 64, 64, "des-cbc", - esp_descbc_ivlen, esp_descbc_decrypt, esp_descbc_encrypt, }, - { 8, esp_cbc_mature, 192, 192, "3des-cbc", - esp_3descbc_ivlen, esp_3descbc_decrypt, esp_3descbc_encrypt, }, - { 1, esp_null_mature, 0, 2048, "null", - esp_null_ivlen, esp_null_decrypt, esp_null_encrypt, }, - { 8, esp_cbc_mature, 40, 448, "blowfish-cbc", - esp_blowfish_cbc_ivlen, esp_blowfish_cbc_decrypt, - esp_blowfish_cbc_encrypt, }, - { 8, esp_cbc_mature, 40, 128, "cast128-cbc", - esp_cast128cbc_ivlen, esp_cast128cbc_decrypt, - esp_cast128cbc_encrypt, }, - { 8, esp_cbc_mature, 40, 2040, "rc5-cbc", - esp_rc5cbc_ivlen, esp_rc5cbc_decrypt, esp_rc5cbc_encrypt, }, +static int esp_blowfish_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_blowfish_schedlen __P((const struct esp_algorithm *)); +static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_cast128_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_cast128_schedlen __P((const struct esp_algorithm *)); +static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_cast128_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_3des_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_3des_schedlen __P((const struct esp_algorithm *)); +static int esp_3des_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_3des_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_common_ivlen __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_cbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, const struct esp_algorithm *, int)); +static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, const struct esp_algorithm *, int)); + +#define MAXIVLEN 16 + +static const struct esp_algorithm esp_algorithms[] = { + { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen, + "des-cbc", + esp_descbc_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_des_schedule, + esp_des_blockdecrypt, esp_des_blockencrypt, }, + { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen, + "3des-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_3des_schedule, + esp_3des_blockdecrypt, esp_3des_blockencrypt, }, + { 1, 0, esp_null_mature, 0, 2048, 0, "null", + esp_common_ivlen, esp_null_decrypt, + esp_null_encrypt, NULL, }, + { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_blowfish_schedule, + esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, }, + { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen, + "cast128-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_cast128_schedule, + esp_cast128_blockdecrypt, esp_cast128_blockencrypt, }, + { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen, + "rijndael-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_rijndael_schedule, + esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt }, }; -/* - * mbuf assumption: foo_encrypt() assumes that IV part is placed in a single - * mbuf, not across multiple mbufs. - */ +const struct esp_algorithm * +esp_algorithm_lookup(idx) + int idx; +{ -static int -esp_null_mature(sav) + switch (idx) { + case SADB_EALG_DESCBC: + return &esp_algorithms[0]; + case SADB_EALG_3DESCBC: + return &esp_algorithms[1]; + case SADB_EALG_NULL: + return &esp_algorithms[2]; + case SADB_X_EALG_BLOWFISHCBC: + return &esp_algorithms[3]; + case SADB_X_EALG_CAST128CBC: + return &esp_algorithms[4]; + case SADB_X_EALG_RIJNDAELCBC: + return &esp_algorithms[5]; + default: + return NULL; + } +} + +int +esp_max_ivlen() +{ + int idx; + int ivlen; + + ivlen = 0; + for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]); + idx++) { + if (esp_algorithms[idx].ivlenval > ivlen) + ivlen = esp_algorithms[idx].ivlenval; + } + + return ivlen; +} + +int +esp_schedule(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; { - /* anything is okay */ - return 0; + int error; + + /* check for key length */ + if (_KEYBITS(sav->key_enc) < algo->keymin || + _KEYBITS(sav->key_enc) > algo->keymax) { + ipseclog((LOG_ERR, + "esp_schedule %s: unsupported key length %d: " + "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax)); + return EINVAL; + } + + /* already allocated */ + if (sav->sched && sav->schedlen != 0) + return 0; + /* no schedule necessary */ + if (!algo->schedule || !algo->schedlen) + return 0; + + sav->schedlen = (*algo->schedlen)(algo); + if (sav->schedlen < 0) + return EINVAL; + sav->sched = malloc(sav->schedlen, M_SECA, M_DONTWAIT); + if (!sav->sched) { + sav->schedlen = 0; + return ENOBUFS; + } + + error = (*algo->schedule)(algo, sav); + if (error) { + ipseclog((LOG_ERR, "esp_schedule %s: error %d\n", + algo->name, error)); + free(sav->sched, M_SECA); + sav->sched = NULL; + sav->schedlen = 0; + } + return error; } static int -esp_null_ivlen(sav) +esp_null_mature(sav) struct secasvar *sav; { + + /* anything is okay */ return 0; } @@ -155,9 +250,10 @@ esp_null_decrypt(m, off, sav, algo, ivlen) struct mbuf *m; size_t off; /* offset to ESP header */ struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { + return 0; /* do nothing */ } @@ -167,9 +263,10 @@ esp_null_encrypt(m, off, plen, sav, algo, ivlen) size_t off; /* offset to ESP header */ size_t plen; /* payload length (to be encrypted) */ struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { + return 0; /* do nothing */ } @@ -177,7 +274,7 @@ static int esp_descbc_mature(sav) struct secasvar *sav; { - struct esp_algorithm *algo; + const struct esp_algorithm *algo; if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) { ipseclog((LOG_ERR, "esp_cbc_mature: " @@ -189,9 +286,16 @@ esp_descbc_mature(sav) ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n")); return 1; } - algo = &esp_algorithms[sav->alg_enc]; - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { + + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { + ipseclog((LOG_ERR, + "esp_descbc_mature: unsupported algorithm.\n")); + return 1; + } + + if (_KEYBITS(sav->key_enc) < algo->keymin || + _KEYBITS(sav->key_enc) > algo->keymax) { ipseclog((LOG_ERR, "esp_descbc_mature: invalid key length %d.\n", _KEYBITS(sav->key_enc))); @@ -199,7 +303,7 @@ esp_descbc_mature(sav) } /* weak key check */ - if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))) { + if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) { ipseclog((LOG_ERR, "esp_descbc_mature: weak key was passed.\n")); return 1; @@ -209,246 +313,69 @@ esp_descbc_mature(sav) } static int -esp_descbc_ivlen(sav) +esp_descbc_ivlen(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; { - if (sav && (sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) - return 4; - if (sav && !(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) - return 4; - else + if (!sav) return 8; + if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) + return 4; + if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) + return 4; + return 8; } static int -esp_descbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; +esp_des_schedlen(algo) + const struct esp_algorithm *algo; { - size_t ivoff = 0; - size_t bodyoff = 0; - u_int8_t *iv; - size_t plen; - u_int8_t tiv[8]; - int derived; - int error; - - derived = 0; - /* sanity check */ - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_descbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_descbc_decrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - * This draft has been deleted, but you can get from - * ftp://ftp.kame.net/pub/internet-drafts/. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - if (ivlen == 4) { - iv = &tiv[0]; - m_copydata(m, ivoff, 4, &tiv[0]); - m_copydata(m, ivoff, 4, &tiv[4]); - tiv[4] ^= 0xff; - tiv[5] ^= 0xff; - tiv[6] ^= 0xff; - tiv[7] ^= 0xff; - } else if (ivlen == 8) { - iv = &tiv[0]; - m_copydata(m, ivoff, 8, &tiv[0]); - } else { - ipseclog((LOG_ERR, "esp_descbc_decrypt: unsupported ivlen %d\n", - ivlen)); - return EINVAL; - } - - plen = m->m_pkthdr.len; - if (plen < bodyoff) - panic("esp_descbc_decrypt: too short packet: len=%lu", - (u_long)plen); - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_descbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - - { - int deserr; - des_key_schedule ks; - - deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks); - if (deserr != 0) { - ipseclog((LOG_ERR, - "esp_descbc_decrypt: key error %d\n", deserr)); - return EINVAL; - } - - error = des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, - DES_DECRYPT); - - /* for safety */ - bzero(&ks, sizeof(des_key_schedule)); - } - - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); - - return error; + return sizeof(des_key_schedule); } static int -esp_descbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be decrypted) */ +esp_des_schedule(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; { - size_t ivoff = 0; - size_t bodyoff = 0; - u_int8_t *iv; - u_int8_t tiv[8]; - int derived; - int error; - - derived = 0; - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_descbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_descbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_descbc_encrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); + if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc), + *(des_key_schedule *)sav->sched)) return EINVAL; - } - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - * This draft has been deleted, see above. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - * This draft has been deleted, see above. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - if (ivlen == 4) { - if (!derived) { - bcopy(sav->iv, &tiv[0], 4); - bcopy(sav->iv, &tiv[4], 4); - tiv[4] ^= 0xff; - tiv[5] ^= 0xff; - tiv[6] ^= 0xff; - tiv[7] ^= 0xff; - bcopy(&tiv[0], iv, 4); - iv = &tiv[0]; - } else { - bcopy(iv, &tiv[0], 4); - bcopy(iv, &tiv[4], 4); - tiv[4] ^= 0xff; - tiv[5] ^= 0xff; - tiv[6] ^= 0xff; - tiv[7] ^= 0xff; - iv = &tiv[0]; - } - } else if (ivlen == 8) - bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); - else { - ipseclog((LOG_ERR, - "esp_descbc_encrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - { - int deserr; - des_key_schedule ks; - - deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks); - if (deserr != 0) { - ipseclog((LOG_ERR, - "esp_descbc_encrypt: key error %d\n", deserr)); - return EINVAL; - } - - error = des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, - DES_ENCRYPT); + else + return 0; +} - /* for safety */ - bzero(&ks, sizeof(des_key_schedule)); - } +static int +esp_des_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ - esp_increment_iv(sav); + /* assumption: d has a good alignment */ + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + *(des_key_schedule *)sav->sched, DES_DECRYPT); + return 0; +} - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); +static int +esp_des_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ - return error; + /* assumption: d has a good alignment */ + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + *(des_key_schedule *)sav->sched, DES_ENCRYPT); + return 0; } static int @@ -456,7 +383,7 @@ esp_cbc_mature(sav) struct secasvar *sav; { int keylen; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; if (sav->flags & SADB_X_EXT_OLD) { ipseclog((LOG_ERR, @@ -470,31 +397,47 @@ esp_cbc_mature(sav) } if (!sav->key_enc) { + ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n")); + return 1; + } + + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { ipseclog((LOG_ERR, - "esp_cbc_mature: no key is given.\n")); + "esp_cbc_mature %s: unsupported algorithm.\n", algo->name)); return 1; } - algo = &esp_algorithms[sav->alg_enc]; + keylen = sav->key_enc->sadb_key_bits; if (keylen < algo->keymin || algo->keymax < keylen) { - ipseclog((LOG_ERR, "esp_cbc_mature: invalid key length %d.\n", - sav->key_enc->sadb_key_bits)); + ipseclog((LOG_ERR, + "esp_cbc_mature %s: invalid key length %d.\n", + algo->name, sav->key_enc->sadb_key_bits)); return 1; } switch (sav->alg_enc) { case SADB_EALG_3DESCBC: /* weak key check */ - if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc)) - || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 8)) - || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 16))) { + if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) || + des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) || + des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) { ipseclog((LOG_ERR, - "esp_cbc_mature: weak key was passed.\n")); + "esp_cbc_mature %s: weak key was passed.\n", + algo->name)); return 1; } break; - case SADB_EALG_BLOWFISHCBC: - case SADB_EALG_CAST128CBC: - case SADB_EALG_RC5CBC: + case SADB_X_EALG_BLOWFISHCBC: + case SADB_X_EALG_CAST128CBC: + break; + case SADB_X_EALG_RIJNDAELCBC: + /* allows specific key sizes only */ + if (!(keylen == 128 || keylen == 192 || keylen == 256)) { + ipseclog((LOG_ERR, + "esp_cbc_mature %s: invalid key length %d.\n", + algo->name, keylen)); + return 1; + } break; } @@ -502,694 +445,596 @@ esp_cbc_mature(sav) } static int -esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; +esp_blowfish_schedlen(algo) + const struct esp_algorithm *algo; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - u_int8_t tiv[8]; - size_t plen; - static BF_KEY key; /* made static to avoid kernel stack overflow */ - int s; - int error; - - /* sanity check */ - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - iv = &tiv[0]; - m_copydata(m, ivoff, 8, &tiv[0]); - - plen = m->m_pkthdr.len; - if (plen < bodyoff) - panic("esp_blowfish_cbc_decrypt: too short packet: len=%lu", - (u_long)plen); - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_blowfish_cbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - -#ifdef __NetBSD__ - s = splsoftnet(); /* XXX correct? */ -#else - s = splnet(); /* XXX correct? */ -#endif - - BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc)); - error = BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT); - - /* for safety */ - bzero(&key, sizeof(BF_KEY)); - splx(s); - - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); - - return error; + return sizeof(BF_KEY); } static int -esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be decrypted) */ +esp_blowfish_schedule(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - static BF_KEY key; /* made static to avoid kernel stack overflow */ - int s; - int error; - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_blowfish_cbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - - bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); - -#ifdef __NetBSD__ - s = splsoftnet(); /* XXX correct? */ -#else - s = splnet(); /* XXX correct? */ -#endif - - BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc)); - error = BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT); - - /* for safety */ - bzero(&key, sizeof(BF_KEY)); - - splx(s); - - esp_increment_iv(sav); - - return error; + BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc), + _KEYBUF(sav->key_enc)); + return 0; } static int -esp_blowfish_cbc_ivlen(sav) +esp_blowfish_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; { - return 8; + /* HOLY COW! BF_encrypt() takes values in host byteorder */ + BF_LONG t[2]; + + bcopy(s, t, sizeof(t)); + t[0] = ntohl(t[0]); + t[1] = ntohl(t[1]); + BF_encrypt(t, (BF_KEY *)sav->sched, BF_DECRYPT); + t[0] = htonl(t[0]); + t[1] = htonl(t[1]); + bcopy(t, d, sizeof(t)); + return 0; } static int -esp_cast128cbc_ivlen(sav) +esp_blowfish_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; { - return 8; + /* HOLY COW! BF_encrypt() takes values in host byteorder */ + BF_LONG t[2]; + + bcopy(s, t, sizeof(t)); + t[0] = ntohl(t[0]); + t[1] = ntohl(t[1]); + BF_encrypt(t, (BF_KEY *)sav->sched, BF_ENCRYPT); + t[0] = htonl(t[0]); + t[1] = htonl(t[1]); + bcopy(t, d, sizeof(t)); + return 0; } static int -esp_cast128cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; +esp_cast128_schedlen(algo) + const struct esp_algorithm *algo; { - size_t ivoff; - size_t bodyoff; - u_int8_t iv[8]; - size_t plen; - int error; - /* sanity check */ - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_cast128cbc_decrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_cast128cbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_cast128cbc_decrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + return sizeof(u_int32_t) * 32; +} - /* copy mbuf's IV into iv */ - m_copydata(m, ivoff, 8, iv); +static int +esp_cast128_schedule(algo, sav) + const struct esp_algorithm *algo; + struct secasvar *sav; +{ - plen = m->m_pkthdr.len; - if (plen < bodyoff) { - panic("esp_cast128cbc_decrypt: too short packet: len=%lu\n", - (u_long)plen); - } - plen -= bodyoff; + set_cast128_subkey((u_int32_t *)sav->sched, _KEYBUF(sav->key_enc)); + return 0; +} - if (plen % 8) { - ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } +static int +esp_cast128_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ - /* decrypt */ - { - u_int8_t key[16]; - u_int32_t subkey[32]; + if (_KEYLEN(sav->key_enc) <= 80 / 8) + cast128_decrypt_round12(d, s, (u_int32_t *)sav->sched); + else + cast128_decrypt_round16(d, s, (u_int32_t *)sav->sched); + return 0; +} - bzero(key, sizeof(key)); - bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc)); +static int +esp_cast128_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ - set_cast128_subkey(subkey, key); - error = cast128_cbc_process(m, bodyoff, plen, subkey, iv, - _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT); + if (_KEYLEN(sav->key_enc) <= 80 / 8) + cast128_encrypt_round12(d, s, (u_int32_t *)sav->sched); + else + cast128_encrypt_round16(d, s, (u_int32_t *)sav->sched); + return 0; +} - /* for safety */ - bzero(subkey, sizeof(subkey)); - bzero(key, sizeof(key)); - } +static int +esp_3des_schedlen(algo) + const struct esp_algorithm *algo; +{ - return error; + return sizeof(des_key_schedule) * 3; } static int -esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; +esp_3des_schedule(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; int error; + des_key_schedule *p; + int i; + char *k; - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; + p = (des_key_schedule *)sav->sched; + k = _KEYBUF(sav->key_enc); + for (i = 0; i < 3; i++) { + error = des_key_sched((des_cblock *)(k + 8 * i), p[i]); + if (error) + return EINVAL; } - if (_KEYBITS(sav->key_enc) < algo->keymin - || _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_cast128cbc_encrypt: unsupported key length %d: " - "needs %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_cast128cbc_encrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_cast128cbc_encrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - - bcopy(sav->iv, iv, ivlen); - - /* encrypt */ - { - u_int8_t key[16]; - u_int32_t subkey[32]; - - bzero(key, sizeof(key)); - bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc)); - - set_cast128_subkey(subkey, key); - error = cast128_cbc_process(m, bodyoff, plen, subkey, iv, - _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT); - - /* for safety */ - bzero(subkey, sizeof(subkey)); - bzero(key, sizeof(key)); - } + return 0; +} - esp_increment_iv(sav); +static int +esp_3des_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + des_key_schedule *p; + + /* assumption: d has a good alignment */ + p = (des_key_schedule *)sav->sched; + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_DECRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_ENCRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_DECRYPT); + return 0; +} - return error; +static int +esp_3des_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + des_key_schedule *p; + + /* assumption: d has a good alignment */ + p = (des_key_schedule *)sav->sched; + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_ENCRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_DECRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_ENCRYPT); + return 0; } static int -esp_3descbc_ivlen(sav) +esp_common_ivlen(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; { - return 8; + + if (!algo) + panic("esp_common_ivlen: unknown algorithm"); + return algo->ivlenval; } static int -esp_3descbc_decrypt(m, off, sav, algo, ivlen) +esp_cbc_decrypt(m, off, sav, algo, ivlen) struct mbuf *m; size_t off; struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - size_t plen; - u_int8_t tiv[8]; + struct mbuf *s; + struct mbuf *d, *d0, *dp; + int soff, doff; /*offset from the head of chain, to head of this mbuf */ + int sn, dn; /*offset from the head of the mbuf, to meat */ + size_t ivoff, bodyoff; + u_int8_t iv[MAXIVLEN], *ivp; + u_int8_t sbuf[MAXIVLEN], *sp; + u_int8_t *p, *q; + struct mbuf *scut; + int scutoff; + int i; + int blocklen; + int derived; - /* sanity check */ - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); + if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " + "unsupported ivlen %d\n", algo->name, ivlen)); + m_freem(m); return EINVAL; } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_3descbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_3descbc_decrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - iv = &tiv[0]; - m_copydata(m, ivoff, 8, &tiv[0]); - plen = m->m_pkthdr.len; - if (plen < bodyoff) - panic("esp_3descbc_decrypt: too short packet: len=%lu", - (u_long)plen); + /* assumes blocklen == padbound */ + blocklen = algo->padbound; - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: " - "payload length must be multiple of 8\n")); +#ifdef DIAGNOSTIC + if (blocklen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " + "unsupported blocklen %d\n", algo->name, blocklen)); + m_freem(m); return EINVAL; } +#endif - /* decrypt packet */ - { - int deserr[3]; - des_key_schedule ks[3]; - - deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc),ks[0]); - deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]); - deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]); - if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: key error %d/%d/%d\n", - deserr[0], deserr[1], deserr[2])); - return EINVAL; + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + ivlen; + derived = 0; + } else { + /* RFC 2406 */ + if (sav->flags & SADB_X_EXT_DERIV) { + /* + * draft-ietf-ipsec-ciph-des-derived-00.txt + * uses sequence number field as IV field. + */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); + ivlen = sizeof(u_int32_t); + derived = 1; + } else { + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + derived = 0; + } } - des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT); - - /* for safety */ - bzero(ks[0], sizeof(des_key_schedule)*3); - } + /* grab iv */ + m_copydata(m, ivoff, ivlen, iv); - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); - - return 0; -} - -static int -esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; -{ - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); + /* extend iv */ + if (ivlen == blocklen) + ; + else if (ivlen == 4 && blocklen == 8) { + bcopy(&iv[0], &iv[4], 4); + iv[4] ^= 0xff; + iv[5] ^= 0xff; + iv[6] ^= 0xff; + iv[7] ^= 0xff; + } else { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported ivlen/blocklen: %d %d\n", + algo->name, ivlen, blocklen)); + m_freem(m); return EINVAL; } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_3descbc_encrypt: unsupported ESP version\n")); + + if (m->m_pkthdr.len < bodyoff) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n", + algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); + m_freem(m); return EINVAL; } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_3descbc_encrypt: unsupported ivlen %d\n", ivlen)); + if ((m->m_pkthdr.len - bodyoff) % blocklen) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " + "payload length must be multiple of %d\n", + algo->name, blocklen)); + m_freem(m); return EINVAL; } - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + s = m; + d = d0 = dp = NULL; + soff = doff = sn = dn = 0; + ivp = sp = NULL; - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - - bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); - - /* encrypt packet */ - { - int deserr[3]; - des_key_schedule ks[3]; + /* skip bodyoff */ + while (soff < bodyoff) { + if (soff + s->m_len > bodyoff) { + sn = bodyoff - soff; + break; + } - deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks[0]); - deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]); - deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]); - if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: key error %d/%d/%d\n", - deserr[0], deserr[1], deserr[2])); - return EINVAL; + soff += s->m_len; + s = s->m_next; } + scut = s; + scutoff = sn; - des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT); - - /* for safety */ - bzero(ks[0], sizeof(des_key_schedule)*3); - } + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; - esp_increment_iv(sav); - - return 0; -} + while (soff < m->m_pkthdr.len) { + /* source */ + if (sn + blocklen <= s->m_len) { + /* body is continuous */ + sp = mtod(s, u_int8_t *) + sn; + } else { + /* body is non-continuous */ + m_copydata(s, sn, blocklen, sbuf); + sp = sbuf; + } -static int -esp_rc5cbc_ivlen(sav) - struct secasvar *sav; -{ - return 8; -} + /* destination */ + if (!d || dn + blocklen > d->m_len) { + if (d) + dp = d; + MGET(d, M_DONTWAIT, MT_DATA); + i = m->m_pkthdr.len - (soff + sn); + if (d && i > MLEN) { + MCLGET(d, M_DONTWAIT); + if ((d->m_flags & M_EXT) == 0) { + m_free(d); + d = NULL; + } + } + if (!d) { + m_freem(m); + if (d0) + m_freem(d0); + return ENOBUFS; + } + if (!d0) + d0 = d; + if (dp) + dp->m_next = d; + d->m_len = 0; + d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; + if (d->m_len > i) + d->m_len = i; + dn = 0; + } -static int -esp_rc5cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; -{ - size_t ivoff; - size_t bodyoff; - u_int8_t iv[8]; - size_t plen; - int error; + /* decrypt */ + (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); - /* sanity check */ - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if ((_KEYBITS(sav->key_enc) < 40) || (_KEYBITS(sav->key_enc) > 2040)) { - ipseclog((LOG_ERR, - "esp_rc5cbc_decrypt: unsupported key length %d: " - "need 40 to 2040 bit\n", _KEYBITS(sav->key_enc))); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_rc5cbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: unsupported ivlen %d\n", - ivlen)); - return EINVAL; - } + /* xor */ + p = ivp ? ivp : iv; + q = mtod(d, u_int8_t *) + dn; + for (i = 0; i < blocklen; i++) + q[i] ^= p[i]; - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + /* next iv */ + if (sp == sbuf) { + bcopy(sbuf, iv, blocklen); + ivp = NULL; + } else + ivp = sp; - /* copy mbuf's IV into iv */ - m_copydata(m, ivoff, 8, iv); + sn += blocklen; + dn += blocklen; - plen = m->m_pkthdr.len; - if (plen < bodyoff) { - panic("esp_rc5cbc_decrypt: too short packet: len=%lu", - (u_long)plen); - } - plen -= bodyoff; + /* find the next source block */ + while (s && sn >= s->m_len) { + sn -= s->m_len; + soff += s->m_len; + s = s->m_next; + } - if (plen % 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; } - /* decrypt */ - { - RC5_WORD e_key[34]; + m_freem(scut->m_next); + scut->m_len = scutoff; + scut->m_next = d0; - set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc), - _KEYBITS(sav->key_enc) / 8, 16); - error = rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT); + /* just in case */ + bzero(iv, sizeof(iv)); + bzero(sbuf, sizeof(sbuf)); - /* for safety */ - bzero(e_key, sizeof(e_key)); - } - - return error; + return 0; } static int -esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen) +esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) struct mbuf *m; size_t off; size_t plen; struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - int error; + struct mbuf *s; + struct mbuf *d, *d0, *dp; + int soff, doff; /*offset from the head of chain, to head of this mbuf */ + int sn, dn; /*offset from the head of the mbuf, to meat */ + size_t ivoff, bodyoff; + u_int8_t iv[MAXIVLEN], *ivp; + u_int8_t sbuf[MAXIVLEN], *sp; + u_int8_t *p, *q; + struct mbuf *scut; + int scutoff; + int i; + int blocklen; + int derived; - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: " - "payload length must be multiple of 8\n")); + if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported ivlen %d\n", algo->name, ivlen)); + m_freem(m); return EINVAL; } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); + + /* assumes blocklen == padbound */ + blocklen = algo->padbound; + +#ifdef DIAGNOSTIC + if (blocklen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported blocklen %d\n", algo->name, blocklen)); + m_freem(m); return EINVAL; } - if (_KEYBITS(sav->key_enc) < algo->keymin - || _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_rc5cbc_encrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); +#endif + + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + ivlen; + derived = 0; + } else { + /* RFC 2406 */ + if (sav->flags & SADB_X_EXT_DERIV) { + /* + * draft-ietf-ipsec-ciph-des-derived-00.txt + * uses sequence number field as IV field. + */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); + ivlen = sizeof(u_int32_t); + derived = 1; + } else { + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + derived = 0; + } + } + + /* put iv into the packet. if we are in derived mode, use seqno. */ + if (derived) + m_copydata(m, ivoff, ivlen, iv); + else { + bcopy(sav->iv, iv, ivlen); + /* maybe it is better to overwrite dest, not source */ + m_copyback(m, ivoff, ivlen, iv); + } + + /* extend iv */ + if (ivlen == blocklen) + ; + else if (ivlen == 4 && blocklen == 8) { + bcopy(&iv[0], &iv[4], 4); + iv[4] ^= 0xff; + iv[5] ^= 0xff; + iv[6] ^= 0xff; + iv[7] ^= 0xff; + } else { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported ivlen/blocklen: %d %d\n", + algo->name, ivlen, blocklen)); + m_freem(m); return EINVAL; } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_rc5cbc_encrypt: unsupported ESP version\n")); + + if (m->m_pkthdr.len < bodyoff) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n", + algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); + m_freem(m); return EINVAL; } - if (ivlen != 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: unsupported ivlen %d\n", - ivlen)); + if ((m->m_pkthdr.len - bodyoff) % blocklen) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "payload length must be multiple of %lu\n", + algo->name, (unsigned long)algo->padbound)); + m_freem(m); return EINVAL; } - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + s = m; + d = d0 = dp = NULL; + soff = doff = sn = dn = 0; + ivp = sp = NULL; - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); + /* skip bodyoff */ + while (soff < bodyoff) { + if (soff + s->m_len > bodyoff) { + sn = bodyoff - soff; + break; + } - bcopy(sav->iv, iv, ivlen); + soff += s->m_len; + s = s->m_next; + } + scut = s; + scutoff = sn; - /* encrypt */ - { - RC5_WORD e_key[34]; + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; - set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc), - _KEYBITS(sav->key_enc) / 8, 16); - error = rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT); + while (soff < m->m_pkthdr.len) { + /* source */ + if (sn + blocklen <= s->m_len) { + /* body is continuous */ + sp = mtod(s, u_int8_t *) + sn; + } else { + /* body is non-continuous */ + m_copydata(s, sn, blocklen, sbuf); + sp = sbuf; + } - /* for safety */ - bzero(e_key, sizeof(e_key)); - } + /* destination */ + if (!d || dn + blocklen > d->m_len) { + if (d) + dp = d; + MGET(d, M_DONTWAIT, MT_DATA); + i = m->m_pkthdr.len - (soff + sn); + if (d && i > MLEN) { + MCLGET(d, M_DONTWAIT); + if ((d->m_flags & M_EXT) == 0) { + m_free(d); + d = NULL; + } + } + if (!d) { + m_freem(m); + if (d0) + m_freem(d0); + return ENOBUFS; + } + if (!d0) + d0 = d; + if (dp) + dp->m_next = d; + d->m_len = 0; + d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; + if (d->m_len > i) + d->m_len = i; + dn = 0; + } - esp_increment_iv(sav); + /* xor */ + p = ivp ? ivp : iv; + q = sp; + for (i = 0; i < blocklen; i++) + q[i] ^= p[i]; - return error; -} + /* encrypt */ + (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); -/* - * increment iv. - */ -static void -esp_increment_iv(sav) - struct secasvar *sav; -{ - u_int8_t *x; - u_int8_t y; - int i; + /* next iv */ + ivp = mtod(d, u_int8_t *) + dn; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) - y = time.tv_sec & 0xff; -#else - y = time_second & 0xff; -#endif - if (!y) y++; - x = (u_int8_t *)sav->iv; - for (i = 0; i < sav->ivlen; i++) { - *x = (*x + y) & 0xff; - x++; - } -} + sn += blocklen; + dn += blocklen; -static caddr_t -mbuf_find_offset(m, off, len) - struct mbuf *m; - size_t off; - size_t len; -{ - struct mbuf *n; - size_t cnt; - - if (m->m_pkthdr.len < off || m->m_pkthdr.len < off + len) - return (caddr_t)NULL; - cnt = 0; - for (n = m; n; n = n->m_next) { - if (cnt + n->m_len <= off) { - cnt += n->m_len; - continue; + /* find the next source block */ + while (s && sn >= s->m_len) { + sn -= s->m_len; + soff += s->m_len; + s = s->m_next; } - if (cnt <= off && off < cnt + n->m_len - && cnt <= off + len && off + len <= cnt + n->m_len) { - return mtod(n, caddr_t) + off - cnt; - } else - return (caddr_t)NULL; + + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; } - return (caddr_t)NULL; + + m_freem(scut->m_next); + scut->m_len = scutoff; + scut->m_next = d0; + + /* just in case */ + bzero(iv, sizeof(iv)); + bzero(sbuf, sizeof(sbuf)); + + key_sa_stir_iv(sav); + + return 0; } /*------------------------------------------------------------*/ @@ -1207,7 +1052,7 @@ esp_auth(m0, skip, length, sav, sum) size_t off; struct ah_algorithm_state s; u_char sumbuf[AH_MAXSUMSIZE]; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t siz; int error; @@ -1233,7 +1078,8 @@ esp_auth(m0, skip, length, sav, sum) ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n")); return EINVAL; } - if (!sav->alg_auth) { + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { ipseclog((LOG_ERR, "esp_auth: bad ESP auth algorithm passed: %d\n", sav->alg_auth)); @@ -1243,7 +1089,6 @@ esp_auth(m0, skip, length, sav, sum) m = m0; off = 0; - algo = &ah_algorithms[sav->alg_auth]; siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1)); if (sizeof(sumbuf) < siz) { ipseclog((LOG_DEBUG, diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c index 4d4344b..4542f13 100644 --- a/sys/netinet6/esp_input.c +++ b/sys/netinet6/esp_input.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: esp_input.c,v 1.25 2000/05/08 08:04:30 itojun Exp $ */ +/* $KAME: esp_input.c,v 1.55 2001/03/23 08:08:47 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,8 +64,10 @@ #ifdef INET6 #include <netinet/ip6.h> +#include <netinet6/in6_pcb.h> #include <netinet6/ip6_var.h> #include <netinet/icmp6.h> +#include <netinet6/ip6protosw.h> #endif #include <netinet6/ipsec.h> @@ -82,11 +84,7 @@ #endif #include <netkey/key.h> #include <netkey/keydb.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <machine/stdarg.h> @@ -94,14 +92,14 @@ #define IPLEN_FLIPPED -#ifdef INET -#include <netinet/ipprotosw.h> -extern struct ipprotosw inetsw[]; - #define ESPMAXLEN \ (sizeof(struct esp) < sizeof(struct newesp) \ ? sizeof(struct newesp) : sizeof(struct esp)) +#ifdef INET +#include <netinet/ipprotosw.h> +extern struct ipprotosw inetsw[]; + void #if __STDC__ esp4_input(struct mbuf *m, ...) @@ -118,7 +116,7 @@ esp4_input(m, va_alist) struct secasvar *sav = NULL; size_t taillen; u_int16_t nxt; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; size_t hlen; size_t esplen; @@ -178,16 +176,15 @@ esp4_input(m, va_alist) ipsecstat.in_badspi++; goto bad; } - if (sav->alg_enc == SADB_EALG_NONE) { + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { ipseclog((LOG_DEBUG, "IPv4 ESP input: " - "unspecified encryption algorithm for spi %u\n", + "unsupported encryption algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto bad; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ - /* check if we have proper ivlen information */ ivlen = sav->ivlen; if (ivlen < 0) { @@ -201,7 +198,8 @@ esp4_input(m, va_alist) && (sav->alg_auth && sav->key_auth))) goto noreplaycheck; - if (sav->alg_auth == SADB_AALG_NULL) + if (sav->alg_auth == SADB_X_AALG_NULL || + sav->alg_auth == SADB_AALG_NONE) goto noreplaycheck; /* @@ -221,10 +219,12 @@ esp4_input(m, va_alist) { u_char sum0[AH_MAXSUMSIZE]; u_char sum[AH_MAXSUMSIZE]; - struct ah_algorithm *sumalgo; + const struct ah_algorithm *sumalgo; size_t siz; - sumalgo = &ah_algorithms[sav->alg_auth]; + sumalgo = ah_algorithm_lookup(sav->alg_auth); + if (!sumalgo) + goto noreplaycheck; siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); if (AH_MAXSUMSIZE < siz) { ipseclog((LOG_DEBUG, @@ -303,22 +303,30 @@ noreplaycheck: } } - { + /* + * pre-compute and cache intermediate key + */ + if (esp_schedule(algo, sav) != 0) { + ipsecstat.in_inval++; + goto bad; + } + /* * decrypt the packet. */ if (!algo->decrypt) panic("internal error: no decrypt function"); if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { - ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); + /* m is already freed */ + m = NULL; + ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n", + ipsec_logsastr(sav))); ipsecstat.in_inval++; goto bad; } ipsecstat.in_esphist[sav->alg_enc]++; m->m_flags |= M_DECRYPTED; - } /* * find the trailer of the ESP. @@ -347,7 +355,7 @@ noreplaycheck: #endif /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec4_tunnel_validate(ip, nxt, sav)) { + if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { /* * strip off all the headers that precedes ESP header. * IP4 xx ESP IP4' payload -> IP4' payload @@ -387,6 +395,11 @@ noreplaycheck: #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { + ipsecstat.in_nomem++; + goto bad; + } if (! IF_HANDOFF(&ipintrq, m, NULL)) { ipsecstat.in_inval++; @@ -421,10 +434,19 @@ noreplaycheck: ip->ip_p = nxt; key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { + ipsecstat.in_nomem++; + goto bad; + } - if (nxt != IPPROTO_DONE) + if (nxt != IPPROTO_DONE) { + if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto bad; + } (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); - else + } else m_freem(m); m = NULL; } @@ -464,10 +486,9 @@ esp6_input(mp, offp, proto) struct secasvar *sav = NULL; size_t taillen; u_int16_t nxt; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; size_t esplen; - int s; /* sanity check for alignment. */ if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { @@ -518,16 +539,15 @@ esp6_input(mp, offp, proto) ipsec6stat.in_badspi++; goto bad; } - if (sav->alg_enc == SADB_EALG_NONE) { + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { ipseclog((LOG_DEBUG, "IPv6 ESP input: " - "unspecified encryption algorithm for spi %u\n", + "unsupported encryption algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto bad; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ - /* check if we have proper ivlen information */ ivlen = sav->ivlen; if (ivlen < 0) { @@ -541,7 +561,8 @@ esp6_input(mp, offp, proto) && (sav->alg_auth && sav->key_auth))) goto noreplaycheck; - if (sav->alg_auth == SADB_AALG_NULL) + if (sav->alg_auth == SADB_X_AALG_NULL || + sav->alg_auth == SADB_AALG_NONE) goto noreplaycheck; /* @@ -561,10 +582,12 @@ esp6_input(mp, offp, proto) { u_char sum0[AH_MAXSUMSIZE]; u_char sum[AH_MAXSUMSIZE]; - struct ah_algorithm *sumalgo; + const struct ah_algorithm *sumalgo; size_t siz; - sumalgo = &ah_algorithms[sav->alg_auth]; + sumalgo = ah_algorithm_lookup(sav->alg_auth); + if (!sumalgo) + goto noreplaycheck; siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); if (AH_MAXSUMSIZE < siz) { ipseclog((LOG_DEBUG, @@ -643,13 +666,23 @@ noreplaycheck: ip6 = mtod(m, struct ip6_hdr *); /*set it again just in case*/ /* + * pre-compute and cache intermediate key + */ + if (esp_schedule(algo, sav) != 0) { + ipsec6stat.in_inval++; + goto bad; + } + + /* * decrypt the packet. */ if (!algo->decrypt) panic("internal error: no decrypt function"); if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { - ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); + /* m is already freed */ + m = NULL; + ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n", + ipsec_logsastr(sav))); ipsec6stat.in_inval++; goto bad; } @@ -680,7 +713,7 @@ noreplaycheck: ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen); /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec6_tunnel_validate(ip6, nxt, sav)) { + if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { /* * strip off all the headers that precedes ESP header. * IP6 xx ESP IP6' payload -> IP6' payload @@ -728,6 +761,11 @@ noreplaycheck: #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { + ipsec6stat.in_nomem++; + goto bad; + } if (! IF_HANDOFF(&ip6intrq, m, NULL)) { ipsec6stat.in_inval++; @@ -778,10 +816,60 @@ noreplaycheck: m->m_pkthdr.len += n->m_pkthdr.len; } +#ifndef PULLDOWN_TEST + /* + * KAME requires that the packet to be contiguous on the + * mbuf. We need to make that sure. + * this kind of code should be avoided. + * XXX other conditions to avoid running this part? + */ + if (m->m_len != m->m_pkthdr.len) { + struct mbuf *n = NULL; + int maxlen; + + MGETHDR(n, M_DONTWAIT, MT_HEADER); + maxlen = MHLEN; + if (n) + M_COPY_PKTHDR(n, m); + if (n && m->m_pkthdr.len > maxlen) { + MCLGET(n, M_DONTWAIT); + maxlen = MCLBYTES; + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) { + printf("esp6_input: mbuf allocation failed\n"); + goto bad; + } + + if (m->m_pkthdr.len <= maxlen) { + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_len = m->m_pkthdr.len; + n->m_pkthdr.len = m->m_pkthdr.len; + n->m_next = NULL; + m_freem(m); + } else { + m_copydata(m, 0, maxlen, mtod(n, caddr_t)); + m_adj(m, maxlen); + n->m_len = maxlen; + n->m_pkthdr.len = m->m_pkthdr.len; + n->m_next = m; + m->m_flags &= ~M_PKTHDR; + } + m = n; + } +#endif + ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { + ipsec6stat.in_nomem++; + goto bad; + } } *offp = off; @@ -805,4 +893,108 @@ bad: m_freem(m); return IPPROTO_DONE; } + +void +esp6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + const struct newesp *espp; + struct newesp esp; + struct ip6ctlparam *ip6cp = NULL, ip6cp1; + struct secasvar *sav; + struct ip6_hdr *ip6; + struct mbuf *m; + int off; + struct sockaddr_in6 sa6_src, sa6_dst; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + if ((unsigned)cmd >= PRC_NCMDS) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + + if (ip6) { + /* + * Notify the error to all possible sockets via pfctlinput2. + * Since the upper layer information (such as protocol type, + * source and destination ports) is embedded in the encrypted + * data and might have been cut, we can't directly call + * an upper layer ctlinput function. However, the pcbnotify + * function will consider source and destination addresses + * as well as the flow info value, and may be able to find + * some PCB that should be notified. + * Although pfctlinput2 will call esp6_ctlinput(), there is + * no possibility of an infinite loop of function calls, + * because we don't pass the inner IPv6 header. + */ + bzero(&ip6cp1, sizeof(ip6cp1)); + ip6cp1.ip6c_src = ip6cp->ip6c_src; + pfctlinput2(cmd, sa, (void *)&ip6cp1); + + /* + * Then go to special cases that need ESP header information. + * XXX: We assume that when ip6 is non NULL, + * M and OFF are valid. + */ + + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(esp)) + return; + + if (m->m_len < off + sizeof(esp)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(esp), (caddr_t)&esp); + espp = &esp; + } else + espp = (struct newesp*)(mtod(m, caddr_t) + off); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + + /* + * Check to see if we have a valid SA corresponding to + * the address in the ICMP message payload. + */ + sav = key_allocsa(AF_INET6, + (caddr_t)&sa6_src.sin6_addr, + (caddr_t)&sa6_dst, IPPROTO_ESP, + espp->esp_spi); + if (sav) { + if (sav->state == SADB_SASTATE_MATURE || + sav->state == SADB_SASTATE_DYING) + valid++; + key_freesav(sav); + } + + /* XXX Further validation? */ + + /* + * Depending on the value of "valid" and routing table + * size (mtudisc_{hi,lo}wat), we will: + * - recalcurate the new MTU and create the + * corresponding routing entry, or + * - ignore the MTU change notification. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + } + } else { + /* we normally notify any pcb here */ + } +} #endif /* INET6 */ diff --git a/sys/netinet6/esp_output.c b/sys/netinet6/esp_output.c index 8d505ae..7770b78 100644 --- a/sys/netinet6/esp_output.c +++ b/sys/netinet6/esp_output.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: esp_output.c,v 1.22 2000/07/03 13:23:28 itojun Exp $ */ +/* $KAME: esp_output.c,v 1.43 2001/03/01 07:10:45 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -90,7 +90,8 @@ esp_hdrsiz(isr) struct ipsecrequest *isr; { struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; + const struct ah_algorithm *aalgo; size_t ivlen; size_t authlen; size_t hdrsiz; @@ -111,7 +112,7 @@ esp_hdrsiz(isr) goto estimate; /* we need transport mode ESP. */ - algo = &esp_algorithms[sav->alg_enc]; + algo = esp_algorithm_lookup(sav->alg_enc); if (!algo) goto estimate; ivlen = sav->ivlen; @@ -130,8 +131,9 @@ esp_hdrsiz(isr) hdrsiz = sizeof(struct esp) + ivlen + 9; } else { /* RFC 2406 */ - if (sav->replay && sav->alg_auth && sav->key_auth) - authlen = (*ah_algorithms[sav->alg_auth].sumsiz)(sav); + aalgo = ah_algorithm_lookup(sav->alg_auth); + if (aalgo && sav->replay && sav->key_auth) + authlen = (aalgo->sumsiz)(sav); else authlen = 0; hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen; @@ -143,12 +145,12 @@ esp_hdrsiz(isr) /* * ASSUMING: * sizeof(struct newesp) > sizeof(struct esp). - * 8 = ivlen for CBC mode (RFC2451). + * esp_max_ivlen() = max ivlen for CBC mode * 9 = (maximum padding length without random padding length) * + (Pad Length field) + (Next Header field). * 16 = maximum ICV we support. */ - return sizeof(struct newesp) + 8 + 9 + 16; + return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16; } /* @@ -184,7 +186,7 @@ esp_output(m, nexthdrp, md, isr, af) struct esp *esp; struct esptail *esptail; struct secasvar *sav = isr->sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; u_int32_t spi; u_int8_t nxt = 0; size_t plen; /*payload length to be encrypted*/ @@ -193,16 +195,19 @@ esp_output(m, nexthdrp, md, isr, af) int afnumber; size_t extendsiz; int error = 0; + struct ipsecstat *stat; switch (af) { #ifdef INET case AF_INET: afnumber = 4; + stat = &ipsecstat; break; #endif #ifdef INET6 case AF_INET6: afnumber = 6; + stat = &ipsec6stat; break; #endif default: @@ -225,28 +230,31 @@ esp_output(m, nexthdrp, md, isr, af) (u_int32_t)ntohl(ip->ip_dst.s_addr), (u_int32_t)ntohl(sav->spi))); ipsecstat.out_inval++; - m_freem(m); - return EINVAL; + break; } #endif /*INET*/ #ifdef INET6 case AF_INET6: - { - struct ip6_hdr *ip6; - - ip6 = mtod(m, struct ip6_hdr *); ipseclog((LOG_DEBUG, "esp6_output: internal error: " "sav->replay is null: SPI=%u\n", (u_int32_t)ntohl(sav->spi))); ipsec6stat.out_inval++; - m_freem(m); - return EINVAL; - } + break; #endif /*INET6*/ + default: + panic("esp_output: should not reach here"); } + m_freem(m); + return EINVAL; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { + ipseclog((LOG_ERR, "esp_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + m_freem(m); + return EINVAL; + } spi = sav->spi; ivlen = sav->ivlen; /* should be okey */ @@ -331,7 +339,7 @@ esp_output(m, nexthdrp, md, isr, af) * before: IP ... payload * after: IP ... ESP IV payload */ - if (M_LEADINGSPACE(md) < esphlen) { + if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) { MGET(n, M_DONTWAIT, MT_DATA); if (!n) { m_freem(m); @@ -386,7 +394,7 @@ esp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + stat->out_inval++; m_freem(m); return EINVAL; } @@ -402,7 +410,6 @@ esp_output(m, nexthdrp, md, isr, af) { /* * find the last mbuf. make some room for ESP trailer. - * XXX new-esp authentication data */ #ifdef INET struct ip *ip = NULL; @@ -410,6 +417,7 @@ esp_output(m, nexthdrp, md, isr, af) size_t padbound; u_char *extend; int i; + int randpadmax; if (algo->padbound) padbound = algo->padbound; @@ -423,13 +431,62 @@ esp_output(m, nexthdrp, md, isr, af) if (extendsiz == 1) extendsiz = padbound + 1; + /* random padding */ + switch (af) { +#ifdef INET + case AF_INET: + randpadmax = ip4_esp_randpad; + break; +#endif +#ifdef INET6 + case AF_INET6: + randpadmax = ip6_esp_randpad; + break; +#endif + default: + randpadmax = -1; + break; + } + if (randpadmax < 0 || plen + extendsiz >= randpadmax) + ; + else { + int n; + + /* round */ + randpadmax = (randpadmax / padbound) * padbound; + n = (randpadmax - plen + extendsiz) / padbound; + + if (n > 0) + n = (random() % n) * padbound; + else + n = 0; + + /* + * make sure we do not pad too much. + * MLEN limitation comes from the trailer attachment + * code below. + * 256 limitation comes from sequential padding. + * also, the 1-octet length field in ESP trailer imposes + * limitation (but is less strict than sequential padding + * as length field do not count the last 2 octets). + */ + if (extendsiz + n <= MLEN && extendsiz + n < 256) + extendsiz += n; + } + +#ifdef DIAGNOSTIC + if (extendsiz > MLEN || extendsiz >= 256) + panic("extendsiz too big in esp_output"); +#endif + n = m; while (n->m_next) n = n->m_next; /* - * if M_EXT, the external part may be shared among - * two consequtive TCP packets. + * if M_EXT, the external mbuf data may be shared among + * two consequtive TCP packets, and it may be unsafe to use the + * trailing space. */ if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) { extend = mtod(n, u_char *) + n->m_len; @@ -455,8 +512,7 @@ esp_output(m, nexthdrp, md, isr, af) } switch (sav->flags & SADB_X_EXT_PMASK) { case SADB_X_EXT_PRAND: - for (i = 0; i < extendsiz; i++) - extend[i] = random() & 0xff; + key_randomfill(extend, extendsiz); break; case SADB_X_EXT_PZERO: bzero(extend, extendsiz); @@ -499,26 +555,25 @@ esp_output(m, nexthdrp, md, isr, af) } /* + * pre-compute and cache intermediate key + */ + error = esp_schedule(algo, sav); + if (error) { + m_freem(m); + stat->out_inval++; + goto fail; + } + + /* * encrypt the packet, based on security association * and the algorithm specified. */ if (!algo->encrypt) panic("internal error: no encrypt function"); if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) { + /* m is already freed */ ipseclog((LOG_ERR, "packet encryption failure\n")); - m_freem(m); - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + stat->out_inval++; error = EINVAL; goto fail; } @@ -530,16 +585,23 @@ esp_output(m, nexthdrp, md, isr, af) goto noantireplay; if (!sav->key_auth) goto noantireplay; - if (!sav->alg_auth) + if (sav->key_auth == SADB_AALG_NONE) goto noantireplay; + { + const struct ah_algorithm *aalgo; u_char authbuf[AH_MAXSUMSIZE]; struct mbuf *n; u_char *p; size_t siz; +#ifdef INET struct ip *ip; +#endif - siz = (((*ah_algorithms[sav->alg_auth].sumsiz)(sav) + 3) & ~(4 - 1)); + aalgo = ah_algorithm_lookup(sav->alg_auth); + if (!aalgo) + goto noantireplay; + siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1); if (AH_MAXSUMSIZE < siz) panic("assertion failed for AH_MAXSUMSIZE"); @@ -547,18 +609,7 @@ esp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_ERR, "ESP checksum generation failure\n")); m_freem(m); error = EINVAL; - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + stat->out_inval++; goto fail; } @@ -619,32 +670,9 @@ noantireplay: if (!m) { ipseclog((LOG_ERR, "NULL mbuf after encryption in esp%d_output", afnumber)); - } else { - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_success++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_success++; - break; -#endif - } - } - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_esphist[sav->alg_enc]++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_esphist[sav->alg_enc]++; - break; -#endif - } + } else + stat->out_success++; + stat->out_esphist[sav->alg_enc]++; key_sa_recordxfer(sav, m); return 0; diff --git a/sys/netinet6/esp_rijndael.c b/sys/netinet6/esp_rijndael.c new file mode 100644 index 0000000..5b0e5fa --- /dev/null +++ b/sys/netinet6/esp_rijndael.c @@ -0,0 +1,116 @@ +/* $FreeBSD$ */ +/* $KAME: esp_rijndael.c,v 1.4 2001/03/02 05:53:05 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/queue.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet6/ipsec.h> +#include <netinet6/esp.h> +#include <netinet6/esp_rijndael.h> + +#include <crypto/rijndael/rijndael.h> + +#include <net/net_osdep.h> + +/* as rijndael uses assymetric scheduled keys, we need to do it twice. */ +int +esp_rijndael_schedlen(algo) + const struct esp_algorithm *algo; +{ + + return sizeof(keyInstance) * 2; +} + +int +esp_rijndael_schedule(algo, sav) + const struct esp_algorithm *algo; + struct secasvar *sav; +{ + keyInstance *k; + + k = (keyInstance *)sav->sched; + if (rijndael_makeKey(&k[0], DIR_DECRYPT, _KEYLEN(sav->key_enc) * 8, + _KEYBUF(sav->key_enc)) < 0) + return -1; + if (rijndael_makeKey(&k[1], DIR_ENCRYPT, _KEYLEN(sav->key_enc) * 8, + _KEYBUF(sav->key_enc)) < 0) + return -1; + return 0; +} + +int +esp_rijndael_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + cipherInstance c; + keyInstance *p; + + /* does not take advantage of CBC mode support */ + bzero(&c, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_ECB, NULL) < 0) + return -1; + p = (keyInstance *)sav->sched; + if (rijndael_blockDecrypt(&c, &p[0], s, algo->padbound * 8, d) < 0) + return -1; + return 0; +} + +int +esp_rijndael_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + cipherInstance c; + keyInstance *p; + + /* does not take advantage of CBC mode support */ + bzero(&c, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_ECB, NULL) < 0) + return -1; + p = (keyInstance *)sav->sched; + if (rijndael_blockEncrypt(&c, &p[1], s, algo->padbound * 8, d) < 0) + return -1; + return 0; +} diff --git a/sys/crypto/rc5/rc5.h b/sys/netinet6/esp_rijndael.h index ae2339b..0c40d78 100644 --- a/sys/crypto/rc5/rc5.h +++ b/sys/netinet6/esp_rijndael.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: rc5.h,v 1.4 2000/06/14 10:41:17 itojun Exp $ */ +/* $KAME: esp_rijndael.h,v 1.1 2000/09/20 18:15:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -30,58 +30,10 @@ * SUCH DAMAGE. */ -#ifndef _RFC2040_RC5_H_ -#define _RFC2040_RC5_H_ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> - -/* - * if RC5_WORD change, W also may be changed. - */ -typedef u_int32_t RC5_WORD; - -#define W (32) -#define WW (W / 8) -#define ROT_MASK (W - 1) -#define BB ((2 * W) / 8) - -#define SHLL(x, s) ((RC5_WORD)((x) << ((s)&ROT_MASK))) -#define SHLR(x, s, w) ((RC5_WORD)((x) >> ((w)-((s)&ROT_MASK)))) -#define SHRL(x, s, w) ((RC5_WORD)((x) << ((w)-((s)&ROT_MASK)))) -#define SHRR(x, s) ((RC5_WORD)((x) >> ((s)&ROT_MASK))) - -#define ROTL(x, s, w) ((RC5_WORD)(SHLL((x), (s))|SHLR((x), (s), (w)))) -#define ROTR(x, s, w) ((RC5_WORD)(SHRL((x), (s), (w))|SHRR((x), (s)))) - -#define P16 0xb7e1 -#define Q16 0x9e37 -#define P32 0xb7e15163 -#define Q32 0x9e3779b9 -#define P64 0xb7e151628aed2a6b -#define Q64 0x9e3779b97f4a7c15 - -#if W == 16 -#define Pw P16 -#define Qw Q16 -#elif W == 32 -#define Pw P32 -#define Qw Q32 -#elif W == 64 -#define Pw P64 -#define Qw Q64 -#endif - -#define RC5_ENCRYPT 1 -#define RC5_DECRYPT 0 - -extern void set_rc5_expandkey __P((RC5_WORD *, u_int8_t *, size_t, int)); -extern void rc5_encrypt_round16 __P((u_int8_t *, const u_int8_t *, - const RC5_WORD *)); -extern void rc5_decrypt_round16 __P((u_int8_t *, const u_int8_t *, - const RC5_WORD *)); -extern int rc5_cbc_process __P((struct mbuf *, size_t, size_t, RC5_WORD *, - u_int8_t *, int)); - -#endif +int esp_rijndael_schedlen __P((const struct esp_algorithm *)); +int esp_rijndael_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +int esp_rijndael_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +int esp_rijndael_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index ea4e6ca..dbf9279 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: frag6.c,v 1.24 2000/03/25 07:23:41 sumikawa Exp $ */ +/* $KAME: frag6.c,v 1.31 2001/05/17 13:45:34 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -66,6 +66,7 @@ static void frag6_insque __P((struct ip6q *, struct ip6q *)); static void frag6_remque __P((struct ip6q *)); static void frag6_freef __P((struct ip6q *)); +/* XXX we eventually need splreass6, or some real semaphore */ int frag6_doing_reass; u_int frag6_nfragpackets; struct ip6q ip6q; /* ip6 reassemble queue */ @@ -206,6 +207,8 @@ frag6_input(mp, offp, proto) /* offset now points to data portion */ offset += sizeof(struct ip6_frag); + frag6_doing_reass = 1; + for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) if (ip6f->ip6f_ident == q6->ip6q_ident && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && @@ -217,7 +220,6 @@ frag6_input(mp, offp, proto) * the first fragment to arrive, create a reassembly queue. */ first_frag = 1; - frag6_nfragpackets++; /* * Enforce upper bound on number of fragmented packets @@ -225,11 +227,11 @@ frag6_input(mp, offp, proto) * If maxfrag is 0, never accept fragments. * If maxfrag is -1, accept all fragments without limitation. */ - if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) { - ip6stat.ip6s_fragoverflow++; - in6_ifstat_inc(dstifp, ifs6_reass_fail); - frag6_freef(ip6q.ip6q_prev); - } + if (ip6_maxfragpackets < 0) + ; + else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) + goto dropfrag; + frag6_nfragpackets++; q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE, M_DONTWAIT); if (q6 == NULL) @@ -274,6 +276,7 @@ frag6_input(mp, offp, proto) icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); + frag6_doing_reass = 0; return(IPPROTO_DONE); } } @@ -281,6 +284,7 @@ frag6_input(mp, offp, proto) icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); + frag6_doing_reass = 0; return(IPPROTO_DONE); } /* @@ -531,6 +535,7 @@ insert: in6_ifstat_inc(dstifp, ifs6_reass_fail); ip6stat.ip6s_fragdropped++; m_freem(m); + frag6_doing_reass = 0; return IPPROTO_DONE; } @@ -620,7 +625,7 @@ frag6_remque(p6) } /* - * IP timer processing; + * IPv6 reassembling timer processing; * if a timer expires on a reassembly * queue, discard it. */ @@ -629,9 +634,6 @@ frag6_slowtimo() { struct ip6q *q6; int s = splnet(); -#if 0 - extern struct route_in6 ip6_forward_rt; -#endif frag6_doing_reass = 1; q6 = ip6q.ip6q_next; @@ -650,7 +652,8 @@ frag6_slowtimo() * (due to the limit being lowered), drain off * enough to get down to the new limit. */ - while (frag6_nfragpackets > (u_int)ip6_maxfragpackets) { + while (frag6_nfragpackets > (u_int)ip6_maxfragpackets && + ip6q.ip6q_prev) { ip6stat.ip6s_fragoverflow++; /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(ip6q.ip6q_prev); diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 9dca71e..4ea9a3a 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: icmp6.c,v 1.119 2000/07/03 14:16:46 itojun Exp $ */ +/* $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -71,6 +71,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> @@ -99,16 +100,45 @@ #ifdef IPSEC #include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif #include <netkey/key.h> #endif #include "faith.h" +#if defined(NFAITH) && 0 < NFAITH +#include <net/if_faith.h> +#endif #include <net/net_osdep.h> +#ifdef HAVE_NRL_INPCB +/* inpcb members */ +#define in6pcb inpcb +#define in6p_laddr inp_laddr6 +#define in6p_faddr inp_faddr6 +#define in6p_icmp6filt inp_icmp6filt +#define in6p_route inp_route +#define in6p_socket inp_socket +#define in6p_flags inp_flags +#define in6p_moptions inp_moptions6 +#define in6p_outputopts inp_outputopts6 +#define in6p_ip6 inp_ipv6 +#define in6p_flowinfo inp_flowinfo +#define in6p_sp inp_sp +#define in6p_next inp_next +#define in6p_prev inp_prev +/* macro names */ +#define sotoin6pcb sotoinpcb +/* function names */ +#define in6_pcbdetach in_pcbdetach +#define in6_rtchange in_rtchange + +/* + * for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from + * others... + */ +#define in6p_ip6_nxt inp_ipv6.ip6_nxt +#endif + extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; extern u_char ip6_protox[]; @@ -116,34 +146,33 @@ extern u_char ip6_protox[]; struct icmp6stat icmp6stat; extern struct inpcbhead ripcb; -extern struct timeval icmp6errratelim; -static struct timeval icmp6errratelim_last; extern int icmp6errppslim; static int icmp6errpps_count = 0; +static struct timeval icmp6errppslim_last; extern int icmp6_nodeinfo; static void icmp6_errcount __P((struct icmp6errstat *, int, int)); static int icmp6_rip6_input __P((struct mbuf **, int)); -static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *, - struct mbuf *)); static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); static const char *icmp6_redirect_diag __P((struct in6_addr *, struct in6_addr *, struct in6_addr *)); -#ifndef HAVE_RATECHECK -static int ratecheck __P((struct timeval *, struct timeval *)); +#ifndef HAVE_PPSRATECHECK +static int ppsratecheck __P((struct timeval *, int *, int)); #endif static struct mbuf *ni6_input __P((struct mbuf *, int)); static struct mbuf *ni6_nametodns __P((const char *, int, int)); static int ni6_dnsmatch __P((const char *, int, const char *, int)); static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, - struct ifnet **)); + struct ifnet **, char *)); static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, struct ifnet *, int)); +static int icmp6_notify_error __P((struct mbuf *, int, int, int)); #ifdef COMPAT_RFC1885 static struct route_in6 icmp6_reflect_rt; #endif + void icmp6_init() { @@ -155,7 +184,7 @@ icmp6_errcount(stat, type, code) struct icmp6errstat *stat; int type, code; { - switch(type) { + switch (type) { case ICMP6_DST_UNREACH: switch (code) { case ICMP6_DST_UNREACH_NOROUTE: @@ -179,7 +208,7 @@ icmp6_errcount(stat, type, code) stat->icp6errs_packet_too_big++; return; case ICMP6_TIME_EXCEEDED: - switch(code) { + switch (code) { case ICMP6_TIME_EXCEED_TRANSIT: stat->icp6errs_time_exceed_transit++; return; @@ -189,7 +218,7 @@ icmp6_errcount(stat, type, code) } break; case ICMP6_PARAM_PROB: - switch(code) { + switch (code) { case ICMP6_PARAMPROB_HEADER: stat->icp6errs_paramprob_header++; return; @@ -318,7 +347,7 @@ icmp6_error(m, type, code, param) if (m && m->m_len < preplen) m = m_pullup(m, preplen); if (m == NULL) { - printf("ENOBUFS in icmp6_error %d\n", __LINE__); + nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__)); return; } @@ -336,6 +365,15 @@ icmp6_error(m, type, code, param) icmp6->icmp6_code = code; icmp6->icmp6_pptr = htonl((u_int32_t)param); + /* + * icmp6_reflect() is designed to be in the input path. + * icmp6_error() can be called from both input and outut path, + * and if we are in output path rcvif could contain bogus value. + * clear m->m_pkthdr.rcvif for safety, we should have enough scope + * information in ip header (nip6). + */ + m->m_pkthdr.rcvif = NULL; + icmp6stat.icp6s_outhist[type]++; icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/ @@ -362,7 +400,6 @@ icmp6_input(mp, offp, proto) int off = *offp; int icmp6len = m->m_pkthdr.len - *offp; int code, sum, noff; - struct sockaddr_in6 icmp6src; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE); @@ -395,17 +432,15 @@ icmp6_input(mp, offp, proto) code = icmp6->icmp6_code; if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 checksum error(%d|%x) %s\n", - icmp6->icmp6_type, - sum, - ip6_sprintf(&ip6->ip6_src)); + icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src))); icmp6stat.icp6s_checksum++; goto freeit; } #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + if (faithprefix(&ip6->ip6_dst)) { /* * Deliver very specific ICMP6 type only. * This is important to deilver TOOBIG. Otherwise PMTUD @@ -422,21 +457,12 @@ icmp6_input(mp, offp, proto) } #endif -#ifdef IPSEC - /* drop it if it does not match the default policy */ - if (ipsec6_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto freeit; - } -#endif - icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg); if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK) icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); switch (icmp6->icmp6_type) { - case ICMP6_DST_UNREACH: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach); switch (code) { @@ -530,9 +556,6 @@ icmp6_input(mp, offp, proto) * always copy the length we specified. */ if (maxlen >= MCLBYTES) { -#ifdef DIAGNOSTIC - printf("MCLBYTES too small\n"); -#endif /* Give up remote */ m_freem(n0); break; @@ -648,13 +671,13 @@ icmp6_input(mp, offp, proto) u_char *p; int maxlen, maxhlen; + if ((icmp6_nodeinfo & 5) != 5) + break; + if (code != 0) goto badcode; maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4; if (maxlen >= MCLBYTES) { -#ifdef DIAGNOSTIC - printf("MCLBYTES too small\n"); -#endif /* Give up remote */ break; } @@ -670,6 +693,7 @@ icmp6_input(mp, offp, proto) /* Give up remote */ break; } + n->m_pkthdr.rcvif = NULL; n->m_len = 0; maxhlen = M_TRAILINGSPACE(n) - maxlen; if (maxhlen > hostnamelen) @@ -794,10 +818,11 @@ icmp6_input(mp, offp, proto) break; default: - printf("icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", - icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst), - m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0); + nd6log((LOG_DEBUG, + "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", + icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), + m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0)); if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { /* ICMPv6 error: MUST deliver it by spec... */ code = PRC_NCMDS; @@ -807,32 +832,63 @@ icmp6_input(mp, offp, proto) break; } deliver: - if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { - icmp6stat.icp6s_tooshort++; - goto freeit; + if (icmp6_notify_error(m, off, icmp6len, code)) { + /* In this case, m should've been freed. */ + return(IPPROTO_DONE); } + break; + + badcode: + icmp6stat.icp6s_badcode++; + break; + + badlen: + icmp6stat.icp6s_badlen++; + break; + } + + /* deliver the packet to appropriate sockets */ + icmp6_rip6_input(&m, *offp); + + return IPPROTO_DONE; + + freeit: + m_freem(m); + return IPPROTO_DONE; +} + +static int +icmp6_notify_error(m, off, icmp6len, code) + struct mbuf *m; + int off, icmp6len; +{ + struct icmp6_hdr *icmp6; + struct ip6_hdr *eip6; + u_int32_t notifymtu; + struct sockaddr_in6 icmp6src, icmp6dst; + + if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { + icmp6stat.icp6s_tooshort++; + goto freeit; + } #ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, - sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), - IPPROTO_DONE); - icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); + IP6_EXTHDR_CHECK(m, off, + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), + -1); + icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); #else - IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, - sizeof(*icmp6) + sizeof(struct ip6_hdr)); - if (icmp6 == NULL) { - icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; - } + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, + sizeof(*icmp6) + sizeof(struct ip6_hdr)); + if (icmp6 == NULL) { + icmp6stat.icp6s_tooshort++; + return(-1); + } #endif - bzero(&icmp6src, sizeof(icmp6src)); - icmp6src.sin6_len = sizeof(struct sockaddr_in6); - icmp6src.sin6_family = AF_INET6; - icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; + eip6 = (struct ip6_hdr *)(icmp6 + 1); - /* Detect the upper level protocol */ - { + /* Detect the upper level protocol */ + { void (*ctlfunc) __P((int, struct sockaddr *, void *)); - struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1); u_int8_t nxt = eip6->ip6_nxt; int eoff = off + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr); @@ -847,22 +903,22 @@ icmp6_input(mp, offp, proto) while (1) { /* XXX: should avoid inf. loop explicitly? */ struct ip6_ext *eh; - switch(nxt) { + switch (nxt) { case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: case IPPROTO_AH: #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(struct ip6_ext), - IPPROTO_DONE); + -1); eh = (struct ip6_ext *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(eh, struct ip6_ext *, m, - eoff, sizeof(*eh)); + eoff, sizeof(*eh)); if (eh == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif @@ -883,15 +939,15 @@ icmp6_input(mp, offp, proto) */ #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth), - IPPROTO_DONE); + -1); rth = (struct ip6_rthdr *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m, - eoff, sizeof(*rth)); + eoff, sizeof(*rth)); if (rth == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif rthlen = (rth->ip6r_len + 1) << 3; @@ -909,7 +965,7 @@ icmp6_input(mp, offp, proto) #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + rthlen, - IPPROTO_DONE); + -1); rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(rth0, @@ -917,7 +973,7 @@ icmp6_input(mp, offp, proto) eoff, rthlen); if (rth0 == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif /* just ignore a bogus header */ @@ -932,15 +988,15 @@ icmp6_input(mp, offp, proto) #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(struct ip6_frag), - IPPROTO_DONE); + -1); fh = (struct ip6_frag *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(fh, struct ip6_frag *, m, - eoff, sizeof(*fh)); + eoff, sizeof(*fh)); if (fh == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif /* @@ -967,69 +1023,114 @@ icmp6_input(mp, offp, proto) goto notify; } } - notify: + notify: #ifndef PULLDOWN_TEST icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); #else IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, - sizeof(*icmp6) + sizeof(struct ip6_hdr)); + sizeof(*icmp6) + sizeof(struct ip6_hdr)); if (icmp6 == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); + } +#endif + + eip6 = (struct ip6_hdr *)(icmp6 + 1); + bzero(&icmp6dst, sizeof(icmp6dst)); + icmp6dst.sin6_len = sizeof(struct sockaddr_in6); + icmp6dst.sin6_family = AF_INET6; + if (finaldst == NULL) + icmp6dst.sin6_addr = eip6->ip6_dst; + else + icmp6dst.sin6_addr = *finaldst; + icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &icmp6dst.sin6_addr); +#ifndef SCOPEDROUTING + if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst, + NULL, NULL)) { + /* should be impossbile */ + nd6log((LOG_DEBUG, + "icmp6_notify_error: in6_embedscope failed\n")); + goto freeit; + } +#endif + + /* + * retrieve parameters from the inner IPv6 header, and convert + * them into sockaddr structures. + */ + bzero(&icmp6src, sizeof(icmp6src)); + icmp6src.sin6_len = sizeof(struct sockaddr_in6); + icmp6src.sin6_family = AF_INET6; + icmp6src.sin6_addr = eip6->ip6_src; + icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &icmp6src.sin6_addr); +#ifndef SCOPEDROUTING + if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src, + NULL, NULL)) { + /* should be impossbile */ + nd6log((LOG_DEBUG, + "icmp6_notify_error: in6_embedscope failed\n")); + goto freeit; } #endif + icmp6src.sin6_flowinfo = + (eip6->ip6_flow & IPV6_FLOWLABEL_MASK); + + if (finaldst == NULL) + finaldst = &eip6->ip6_dst; + ip6cp.ip6c_m = m; + ip6cp.ip6c_icmp6 = icmp6; + ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); + ip6cp.ip6c_off = eoff; + ip6cp.ip6c_finaldst = finaldst; + ip6cp.ip6c_src = &icmp6src; + ip6cp.ip6c_nxt = nxt; + if (icmp6type == ICMP6_PACKET_TOO_BIG) { - if (finaldst == NULL) - finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; - icmp6_mtudisc_update(finaldst, icmp6, m); + notifymtu = ntohl(icmp6->icmp6_mtu); + ip6cp.ip6c_cmdarg = (void *)¬ifymtu; + icmp6_mtudisc_update(&ip6cp, 1); /*XXX*/ } ctlfunc = (void (*) __P((int, struct sockaddr *, void *))) (inet6sw[ip6_protox[nxt]].pr_ctlinput); if (ctlfunc) { - ip6cp.ip6c_m = m; - ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); - ip6cp.ip6c_off = eoff; - (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp); + (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst, + &ip6cp); } - } - break; - - badcode: - icmp6stat.icp6s_badcode++; - break; - - badlen: - icmp6stat.icp6s_badlen++; - break; } + return(0); -#ifdef HAVE_NRL_INPCB - rip6_input(&m, offp, IPPROTO_ICMPV6); -#else - icmp6_rip6_input(&m, *offp); -#endif - return IPPROTO_DONE; - - freeit: + freeit: m_freem(m); - return IPPROTO_DONE; + return(-1); } -static void -icmp6_mtudisc_update(dst, icmp6, m) - struct in6_addr *dst; - struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */ - struct mbuf *m; /* currently unused but added for scoped addrs */ +void +icmp6_mtudisc_update(ip6cp, validated) + struct ip6ctlparam *ip6cp; + int validated; { + struct in6_addr *dst = ip6cp->ip6c_finaldst; + struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6; + struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */ u_int mtu = ntohl(icmp6->icmp6_mtu); struct rtentry *rt = NULL; struct sockaddr_in6 sin6; + if (!validated) + return; + bzero(&sin6, sizeof(sin6)); sin6.sin6_family = PF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *dst; + /* XXX normally, this won't happen */ + if (IN6_IS_ADDR_LINKLOCAL(dst)) { + sin6.sin6_addr.s6_addr16[1] = + htons(m->m_pkthdr.rcvif->if_index); + } /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */ rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_CLONING | RTF_PRCLONING); @@ -1041,6 +1142,7 @@ icmp6_mtudisc_update(dst, icmp6, m) rt->rt_rmx.rmx_locks |= RTV_MTU; } else if (mtu < rt->rt_ifp->if_mtu && rt->rt_rmx.rmx_mtu > mtu) { + icmp6stat.icp6s_pmtuchg++; rt->rt_rmx.rmx_mtu = mtu; } } @@ -1049,19 +1151,17 @@ icmp6_mtudisc_update(dst, icmp6, m) } /* - * Process a Node Information Query packet, (roughly) based on - * draft-ietf-ipngwg-icmp-name-lookups-05. + * Process a Node Information Query packet, based on + * draft-ietf-ipngwg-icmp-name-lookups-07. * * Spec incompatibilities: * - IPv6 Subject address handling * - IPv4 Subject address handling support missing * - Proxy reply (answer even if it's not for me) - * - "Supported Qtypes" support missing * - joins NI group address at in6_ifattach() time only, does not cope * with hostname changes by sethostname(3) */ #define hostnamelen strlen(hostname) - static struct mbuf * ni6_input(m, off) struct mbuf *m; @@ -1075,10 +1175,12 @@ ni6_input(m, off) struct ni_reply_fqdn *fqdn; int addrs; /* for NI_QTYPE_NODEADDR */ struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ - struct sockaddr_in6 sin6; + struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */ + struct sockaddr_in6 sin6_d; /* XXX: we should retrieve this from m_aux */ struct ip6_hdr *ip6; int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ - char *subj; + char *subj = NULL; + struct in6_ifaddr *ia6 = NULL; ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST @@ -1094,81 +1196,40 @@ ni6_input(m, off) /* * Validate IPv6 destination address. * - * We accept packets with the following IPv6 destination address: - * - Responder's unicast/anycast address, - * - link-local multicast address - * This is a violation to last paragraph in icmp-name-lookups-05 - * page 4, which restricts IPv6 destination address of a query to: - * - Responder's unicast/anycast address, - * - NI group address for a name belongs to the Responder, or - * - NI group address for a name for which the Responder is providing - * proxy service. - * (note: NI group address is a link-local multicast address) - * - * We allow any link-local multicast address, since "ping6 -w ff02::1" - * has been really useful for us debugging our network. Also this is - * still questionable if the restriction in spec buy us security at all, - * since RFC2463 permits echo packet to multicast destination. - * Even if we forbid NI query to ff02::1, we can effectively get the - * same result as "ping6 -w ff02::1" by the following steps: - * - run "ping6 ff02::1", then - * - run "ping6 -w" for all addresses replied. + * The Responder must discard the Query without further processing + * unless it is one of the Responder's unicast or anycast addresses, or + * a link-local scope multicast address which the Responder has joined. + * [icmp-name-lookups-07, Section 4.] */ bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); /* XXX scopeid */ - if (ifa_ifwithaddr((struct sockaddr *)&sin6)) - ; /*unicast/anycast, fine*/ - else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) - ; /*violates spec slightly, see above*/ + if ((ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)&sin6)) != NULL) { + /* unicast/anycast, fine */ + if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (icmp6_nodeinfo & 4) == 0) { + nd6log((LOG_DEBUG, "ni6_input: ignore node info to " + "a temporary address in %s:%d", + __FILE__, __LINE__)); + goto bad; + } + } else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) + ; /* link-local multicast, fine */ else goto bad; - /* guess reply length */ - qtype = ntohs(ni6->ni_qtype); - switch (qtype) { - case NI_QTYPE_NOOP: - break; /* no reply data */ - case NI_QTYPE_SUPTYPES: - goto bad; /* xxx: to be implemented */ - break; - case NI_QTYPE_FQDN: - /* XXX will append a mbuf */ - replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); - break; - case NI_QTYPE_NODEADDR: - addrs = ni6_addrs(ni6, m, &ifp); - if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES) - replylen = MCLBYTES; /* XXX: we'll truncate later */ - break; - default: - /* - * XXX: We must return a reply with the ICMP6 code - * `unknown Qtype' in this case. However we regard the case - * as an FQDN query for backward compatibility. - * Older versions set a random value to this field, - * so it rarely varies in the defined qtypes. - * But the mechanism is not reliable... - * maybe we should obsolete older versions. - */ - qtype = NI_QTYPE_FQDN; - /* XXX will append a mbuf */ - replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); - oldfqdn++; - break; - } - /* validate query Subject field. */ + qtype = ntohs(ni6->ni_qtype); subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo); switch (qtype) { case NI_QTYPE_NOOP: case NI_QTYPE_SUPTYPES: - if (subjlen != 0) - goto bad; - break; - + /* 07 draft */ + if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0) + break; + /* FALLTHROUGH */ case NI_QTYPE_FQDN: case NI_QTYPE_NODEADDR: switch (ni6->ni_code) { @@ -1180,10 +1241,15 @@ ni6_input(m, off) * backward compatibility - try to accept 03 draft * format, where no Subject is present. */ - if (subjlen == 0) { + if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 && + subjlen == 0) { oldfqdn++; break; } +#if ICMP6_NI_SUBJ_IPV6 != 0 + if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6) + goto bad; +#endif if (subjlen != sizeof(sin6.sin6_addr)) goto bad; @@ -1191,8 +1257,8 @@ ni6_input(m, off) /* * Validate Subject address. * - * Not sure what exactly does "address belongs to the - * node" mean in the spec, is it just unicast, or what? + * Not sure what exactly "address belongs to the node" + * means in the spec, is it just unicast, or what? * * At this moment we consider Subject address as * "belong to the node" if the Subject address equals @@ -1205,23 +1271,24 @@ ni6_input(m, off) /* m_pulldown instead of copy? */ m_copydata(m, off + sizeof(struct icmp6_nodeinfo), subjlen, (caddr_t)&sin6.sin6_addr); - /* XXX kame scope hack */ - if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) { -#ifdef FAKE_LOOPBACK_IF - if ((m->m_flags & M_PKTHDR) != 0 && - m->m_pkthdr.rcvif) { - sin6.sin6_addr.s6_addr16[1] = - htons(m->m_pkthdr.rcvif->if_index); - } -#else - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { - sin6.sin6_addr.s6_addr16[1] = - ip6->ip6_dst.s6_addr16[1]; - } + sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &sin6.sin6_addr); +#ifndef SCOPEDROUTING + in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL); #endif - } - if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr)) + bzero(&sin6_d, sizeof(sin6_d)); + sin6_d.sin6_family = AF_INET6; /* not used, actually */ + sin6_d.sin6_len = sizeof(sin6_d); /* ditto */ + sin6_d.sin6_addr = ip6->ip6_dst; + sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &ip6->ip6_dst); +#ifndef SCOPEDROUTING + in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL); +#endif + subj = (char *)&sin6; + if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d)) break; + /* * XXX if we are to allow other cases, we should really * be careful about scope here. @@ -1259,18 +1326,60 @@ ni6_input(m, off) n = NULL; break; - case ICMP6_NI_SUBJ_IPV4: /* xxx: to be implemented? */ + case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */ default: goto bad; } break; + } + + /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */ + switch (qtype) { + case NI_QTYPE_FQDN: + if ((icmp6_nodeinfo & 1) == 0) + goto bad; + break; + case NI_QTYPE_NODEADDR: + if ((icmp6_nodeinfo & 2) == 0) + goto bad; + break; + } + /* guess reply length */ + switch (qtype) { + case NI_QTYPE_NOOP: + break; /* no reply data */ + case NI_QTYPE_SUPTYPES: + replylen += sizeof(u_int32_t); + break; + case NI_QTYPE_FQDN: + /* XXX will append an mbuf */ + replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); + break; + case NI_QTYPE_NODEADDR: + addrs = ni6_addrs(ni6, m, &ifp, subj); + if ((replylen += addrs * (sizeof(struct in6_addr) + + sizeof(u_int32_t))) > MCLBYTES) + replylen = MCLBYTES; /* XXX: will truncate pkt later */ + break; default: - /* should never be here due to "switch (qtype)" above */ - goto bad; + /* + * XXX: We must return a reply with the ICMP6 code + * `unknown Qtype' in this case. However we regard the case + * as an FQDN query for backward compatibility. + * Older versions set a random value to this field, + * so it rarely varies in the defined qtypes. + * But the mechanism is not reliable... + * maybe we should obsolete older versions. + */ + qtype = NI_QTYPE_FQDN; + /* XXX will append an mbuf */ + replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); + oldfqdn++; + break; } - /* allocate a mbuf to reply. */ + /* allocate an mbuf to reply. */ MGETHDR(n, M_DONTWAIT, m->m_type); if (n == NULL) { m_freem(m); @@ -1279,10 +1388,10 @@ ni6_input(m, off) M_COPY_PKTHDR(n, m); /* just for recvif */ if (replylen > MHLEN) { if (replylen > MCLBYTES) { - /* - * XXX: should we try to allocate more? But MCLBYTES is - * probably much larger than IPV6_MMTU... - */ + /* + * XXX: should we try to allocate more? But MCLBYTES + * is probably much larger than IPV6_MMTU... + */ goto bad; } MCLGET(n, M_DONTWAIT); @@ -1300,12 +1409,21 @@ ni6_input(m, off) /* qtype dependent procedure */ switch (qtype) { case NI_QTYPE_NOOP: + nni6->ni_code = ICMP6_NI_SUCCESS; nni6->ni_flags = 0; break; case NI_QTYPE_SUPTYPES: - goto bad; /* xxx: to be implemented */ + { + u_int32_t v; + nni6->ni_code = ICMP6_NI_SUCCESS; + nni6->ni_flags = htons(0x0000); /* raw bitmap */ + /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */ + v = (u_int32_t)htonl(0x0000000f); + bcopy(&v, nni6 + 1, sizeof(u_int32_t)); break; + } case NI_QTYPE_FQDN: + nni6->ni_code = ICMP6_NI_SUCCESS; fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo)); @@ -1326,12 +1444,10 @@ ni6_input(m, off) { int lenlim, copied; - if (n->m_flags & M_EXT) - lenlim = MCLBYTES - sizeof(struct ip6_hdr) - - sizeof(struct icmp6_nodeinfo); - else - lenlim = MHLEN - sizeof(struct ip6_hdr) - - sizeof(struct icmp6_nodeinfo); + nni6->ni_code = ICMP6_NI_SUCCESS; + n->m_pkthdr.len = n->m_len = + sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); + lenlim = M_TRAILINGSPACE(n); copied = ni6_store_addrs(ni6, nni6, ifp, lenlim); /* XXX: reset mbuf length */ n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + @@ -1343,7 +1459,6 @@ ni6_input(m, off) } nni6->ni_type = ICMP6_NI_REPLY; - nni6->ni_code = ICMP6_NI_SUCESS; m_freem(m); return(n); @@ -1455,6 +1570,7 @@ ni6_nametodns(name, namelen, old) /* * check if two DNS-encoded string matches. takes care of truncated * form (with \0\0 at the end). no compression support. + * XXX upper/lowercase match (see RFC2065) */ static int ni6_dnsmatch(a, alen, b, blen) @@ -1521,16 +1637,34 @@ ni6_dnsmatch(a, alen, b, blen) * calculate the number of addresses to be returned in the node info reply. */ static int -ni6_addrs(ni6, m, ifpp) +ni6_addrs(ni6, m, ifpp, subj) struct icmp6_nodeinfo *ni6; struct mbuf *m; struct ifnet **ifpp; + char *subj; { - register struct ifnet *ifp; - register struct in6_ifaddr *ifa6; - register struct ifaddr *ifa; - struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct ifnet *ifp; + struct in6_ifaddr *ifa6; + struct ifaddr *ifa; + struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */ int addrs = 0, addrsofif, iffound = 0; + int niflags = ni6->ni_flags; + + if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) { + switch (ni6->ni_code) { + case ICMP6_NI_SUBJ_IPV6: + if (subj == NULL) /* must be impossible... */ + return(0); + subj_ip6 = (struct sockaddr_in6 *)subj; + break; + default: + /* + * XXX: we only support IPv6 subject address for + * this Qtype. + */ + return(0); + } + } for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { @@ -1542,8 +1676,8 @@ ni6_addrs(ni6, m, ifpp) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) && - IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, + if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 && + IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr, &ifa6->ia_addr.sin6_addr)) iffound = 1; @@ -1552,36 +1686,41 @@ ni6_addrs(ni6, m, ifpp) * Node Information proxy, since they represent * addresses of IPv4-only nodes, which perforce do * not implement this protocol. - * [icmp-name-lookups-05] + * [icmp-name-lookups-07, Section 5.4] * So we don't support NI_NODEADDR_FLAG_COMPAT in * this function at this moment. */ - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) - continue; /* we need only unicast addresses */ - - if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL | - NI_NODEADDR_FLAG_SITELOCAL | - NI_NODEADDR_FLAG_GLOBAL)) == 0) - continue; - /* What do we have to do about ::1? */ - switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { - case IPV6_ADDR_SCOPE_LINKLOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) - addrsofif++; + switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { + case IPV6_ADDR_SCOPE_LINKLOCAL: + if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_SITELOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) - addrsofif++; + case IPV6_ADDR_SCOPE_SITELOCAL: + if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) + continue; + break; + case IPV6_ADDR_SCOPE_GLOBAL: + if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_GLOBAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) - addrsofif++; - break; - default: - continue; + default: + continue; + } + + /* + * check if anycast is okay. + * XXX: just experimental. not in the spec. + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && + (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) + continue; /* we need only unicast addresses */ + if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (icmp6_nodeinfo & 4) == 0) { + continue; } + addrsofif++; /* count the address */ } if (iffound) { *ifpp = ifp; @@ -1600,82 +1739,139 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) struct ifnet *ifp0; int resid; { - register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); - register struct in6_ifaddr *ifa6; - register struct ifaddr *ifa; - int docopy, copied = 0; + struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); + struct in6_ifaddr *ifa6; + struct ifaddr *ifa; + struct ifnet *ifp_dep = NULL; + int copied = 0, allow_deprecated = 0; u_char *cp = (u_char *)(nni6 + 1); + int niflags = ni6->ni_flags; + u_int32_t ltime; - if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL)) + if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL)) return(0); /* needless to copy */ + again: + for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) { for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { - docopy = 0; - if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) { - /* just experimental. not in the spec. */ - if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) - docopy = 1; - else - continue; - } - else { /* unicast address */ - if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) - continue; - else - docopy = 1; + if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 && + allow_deprecated == 0) { + /* + * prefererred address should be put before + * deprecated addresses. + */ + + /* record the interface for later search */ + if (ifp_dep == NULL) + ifp_dep = ifp; + + continue; } + else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 && + allow_deprecated != 0) + continue; /* we now collect deprecated addrs */ /* What do we have to do about ::1? */ - switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { - case IPV6_ADDR_SCOPE_LINKLOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) - docopy = 1; + switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { + case IPV6_ADDR_SCOPE_LINKLOCAL: + if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) + continue; + break; + case IPV6_ADDR_SCOPE_SITELOCAL: + if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_SITELOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) - docopy = 1; + case IPV6_ADDR_SCOPE_GLOBAL: + if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_GLOBAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) - docopy = 1; - break; - default: - continue; + default: + continue; } - if (docopy) { - if (resid < sizeof(struct in6_addr)) { - /* - * We give up much more copy. - * Set the truncate flag and return. - */ - nni6->ni_flags |= - NI_NODEADDR_FLAG_TRUNCATE; - return(copied); - } - bcopy(&ifa6->ia_addr.sin6_addr, cp, - sizeof(struct in6_addr)); - /* XXX: KAME link-local hack; remove ifindex */ - if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) - ((struct in6_addr *)cp)->s6_addr16[1] = 0; - cp += sizeof(struct in6_addr); - resid -= sizeof(struct in6_addr); - copied += sizeof(struct in6_addr); + /* + * check if anycast is okay. + * XXX: just experimental. not in the spec. + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && + (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) + continue; + if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (icmp6_nodeinfo & 4) == 0) { + continue; } + + /* now we can copy the address */ + if (resid < sizeof(struct in6_addr) + + sizeof(u_int32_t)) { + /* + * We give up much more copy. + * Set the truncate flag and return. + */ + nni6->ni_flags |= + NI_NODEADDR_FLAG_TRUNCATE; + return(copied); + } + + /* + * Set the TTL of the address. + * The TTL value should be one of the following + * according to the specification: + * + * 1. The remaining lifetime of a DHCP lease on the + * address, or + * 2. The remaining Valid Lifetime of a prefix from + * which the address was derived through Stateless + * Autoconfiguration. + * + * Note that we currently do not support stateful + * address configuration by DHCPv6, so the former + * case can't happen. + */ + if (ifa6->ia6_lifetime.ia6t_expire == 0) + ltime = ND6_INFINITE_LIFETIME; + else { + if (ifa6->ia6_lifetime.ia6t_expire > + time_second) + ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second); + else + ltime = 0; + } + + bcopy(<ime, cp, sizeof(u_int32_t)); + cp += sizeof(u_int32_t); + + /* copy the address itself */ + bcopy(&ifa6->ia_addr.sin6_addr, cp, + sizeof(struct in6_addr)); + /* XXX: KAME link-local hack; remove ifindex */ + if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) + ((struct in6_addr *)cp)->s6_addr16[1] = 0; + cp += sizeof(struct in6_addr); + + resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t)); + copied += (sizeof(struct in6_addr) + + sizeof(u_int32_t)); } if (ifp0) /* we need search only on the specified IF */ break; } + if (allow_deprecated == 0 && ifp_dep != NULL) { + ifp = ifp_dep; + allow_deprecated = 1; + + goto again; + } + return(copied); } @@ -1688,8 +1884,8 @@ icmp6_rip6_input(mp, off) int off; { struct mbuf *m = *mp; - register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - register struct in6pcb *in6p; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct in6pcb *in6p; struct in6pcb *last = NULL; struct sockaddr_in6 rip6src; struct icmp6_hdr *icmp6; @@ -1714,8 +1910,12 @@ icmp6_rip6_input(mp, off) LIST_FOREACH(in6p, &ripcb, inp_list) { - if ((in6p->inp_vflag & INP_IPV6) == NULL) + if ((in6p->inp_vflag & INP_IPV6) == 0) + continue; +#ifdef HAVE_NRL_INPCB + if (!(in6p->in6p_flags & INP_IPV6)) continue; +#endif if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) continue; if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && @@ -1740,8 +1940,9 @@ icmp6_rip6_input(mp, off) n, opts) == 0) { /* should notify about lost packet */ m_freem(n); - if (opts) + if (opts) { m_freem(opts); + } } else sorwakeup(last->in6p_socket); opts = NULL; @@ -1755,7 +1956,7 @@ icmp6_rip6_input(mp, off) /* strip intermediate headers */ m_adj(m, off); if (sbappendaddr(&last->in6p_socket->so_rcv, - (struct sockaddr *)&rip6src, m, opts) == 0) { + (struct sockaddr *)&rip6src, m, opts) == 0) { m_freem(m); if (opts) m_freem(opts); @@ -1784,6 +1985,7 @@ icmp6_reflect(m, off) int plen; int type, code; struct ifnet *outif = NULL; + struct sockaddr_in6 sa6_src, sa6_dst; #ifdef COMPAT_RFC1885 int mtu = IPV6_MMTU; struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst; @@ -1791,9 +1993,10 @@ icmp6_reflect(m, off) /* too short to reflect */ if (off < sizeof(struct ip6_hdr)) { - printf("sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", - (u_long)off, (u_long)sizeof(struct ip6_hdr), - __FILE__, __LINE__); + nd6log((LOG_DEBUG, + "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", + (u_long)off, (u_long)sizeof(struct ip6_hdr), + __FILE__, __LINE__)); goto bad; } @@ -1840,12 +2043,24 @@ icmp6_reflect(m, off) */ ip6->ip6_dst = ip6->ip6_src; - /* XXX hack for link-local addresses */ - if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] = - htons(m->m_pkthdr.rcvif->if_index); - if (IN6_IS_ADDR_LINKLOCAL(&t)) - t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* + * XXX: make sure to embed scope zone information, using + * already embedded IDs or the received interface (if any). + * Note that rcvif may be NULL. + * TODO: scoped routing case (XXX). + */ + bzero(&sa6_src, sizeof(sa6_src)); + sa6_src.sin6_family = AF_INET6; + sa6_src.sin6_len = sizeof(sa6_src); + sa6_src.sin6_addr = ip6->ip6_dst; + in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif); + in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL); + bzero(&sa6_dst, sizeof(sa6_dst)); + sa6_dst.sin6_family = AF_INET6; + sa6_dst.sin6_len = sizeof(sa6_dst); + sa6_dst.sin6_addr = t; + in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif); + in6_embedscope(&t, &sa6_dst, NULL, NULL); #ifdef COMPAT_RFC1885 /* @@ -1902,19 +2117,27 @@ icmp6_reflect(m, off) src = &t; } - if (src == 0) + if (src == 0) { + int e; + struct route_in6 ro; + /* * This case matches to multicasts, our anycast, or unicasts - * that we do not own. Select a source address which has the - * same scope. - * XXX: for (non link-local) multicast addresses, this might - * not be a good choice. + * that we do not own. Select a source address based on the + * source address of the erroneous packet. */ - if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0) - src = &IA6_SIN6(ia)->sin6_addr; - - if (src == 0) - goto bad; + bzero(&ro, sizeof(ro)); + src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e); + if (ro.ro_rt) + RTFREE(ro.ro_rt); /* XXX: we could use this */ + if (src == NULL) { + nd6log((LOG_DEBUG, + "icmp6_reflect: source can't be determined: " + "dst=%s, error=%d\n", + ip6_sprintf(&sa6_src.sin6_addr), e)); + goto bad; + } + } ip6->ip6_src = *src; @@ -1925,20 +2148,21 @@ icmp6_reflect(m, off) if (m->m_pkthdr.rcvif) { /* XXX: This may not be the outgoing interface */ ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim; - } + } else + ip6->ip6_hlim = ip6_defhlim; icmp6->icmp6_cksum = 0; icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), plen); /* - * xxx option handling + * XXX option handling */ m->m_flags &= ~(M_BCAST|M_MCAST); #ifdef IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif /*IPSEC*/ #ifdef COMPAT_RFC1885 @@ -1961,9 +2185,6 @@ icmp6_fasttimo() { mld6_fasttimeo(); - - /* reset ICMPv6 pps limit */ - icmp6errpps_count = 0; } static const char * @@ -1980,7 +2201,7 @@ icmp6_redirect_diag(src6, dst6, tgt6) void icmp6_redirect_input(m, off) - register struct mbuf *m; + struct mbuf *m; int off; { struct ifnet *ifp = m->m_pkthdr.rcvif; @@ -2028,17 +2249,17 @@ icmp6_redirect_input(m, off) /* validation */ if (!IN6_IS_ADDR_LINKLOCAL(&src6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect sent from %s rejected; " - "must be from linklocal\n", ip6_sprintf(&src6)); - goto freeit; + "must be from linklocal\n", ip6_sprintf(&src6))); + goto bad; } if (ip6->ip6_hlim != 255) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect sent from %s rejected; " "hlim=%d (must be 255)\n", - ip6_sprintf(&src6), ip6->ip6_hlim); - goto freeit; + ip6_sprintf(&src6), ip6->ip6_hlim)); + goto bad; } { /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */ @@ -2053,41 +2274,41 @@ icmp6_redirect_input(m, off) if (rt) { if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; no route " "with inet6 gateway found for redirect dst: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); RTFREE(rt); - goto freeit; + goto bad; } gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr); if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "not equal to gw-for-src=%s (must be same): " "%s\n", ip6_sprintf(gw6), - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); RTFREE(rt); - goto freeit; + goto bad; } } else { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "no route found for redirect dst: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } RTFREE(rt); rt = NULL; } if (IN6_IS_ADDR_MULTICAST(&reddst6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "redirect dst must be unicast: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } is_router = is_onlink = 0; @@ -2096,20 +2317,21 @@ icmp6_redirect_input(m, off) if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) is_onlink = 1; /* on-link destination case */ if (!is_router && !is_onlink) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "neither router case nor onlink case: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } /* validation passed */ icmp6len -= sizeof(*nd_rd); nd6_option_init(nd_rd + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "icmp6_redirect_input: " + nd6log((LOG_INFO, "icmp6_redirect_input: " "invalid ND option, rejected: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + /* nd6_options have incremented stats */ goto freeit; } @@ -2124,11 +2346,12 @@ icmp6_redirect_input(m, off) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "icmp6_redirect_input: lladdrlen mismatch for %s " "(if %d, icmp6 packet %d): %s\n", ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2, - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } /* RFC 2461 8.3 */ @@ -2171,6 +2394,11 @@ icmp6_redirect_input(m, off) freeit: m_freem(m); + return; + + bad: + icmp6stat.icp6s_badredirect++; + m_freem(m); } void @@ -2235,7 +2463,9 @@ icmp6_redirect_output(m0, rt) MCLGET(m, M_DONTWAIT); if (!m) goto fail; - maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; + m->m_pkthdr.rcvif = NULL; + m->m_len = 0; + maxlen = M_TRAILINGSPACE(m); maxlen = min(IPV6_MMTU, maxlen); /* just for safety */ if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + @@ -2440,7 +2670,7 @@ noredhdropt:; /* send the packet to outside... */ #ifdef IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif /*IPSEC*/ ip6_output(m, NULL, NULL, 0, NULL, &outif); if (outif) { @@ -2458,11 +2688,13 @@ fail: m_freem(m0); } +#ifdef HAVE_NRL_INPCB +#define sotoin6pcb sotoinpcb +#define in6pcb inpcb +#define in6p_icmp6filt inp_icmp6filt +#endif /* * ICMPv6 socket option processing. - * - * NOTE: for OSes that use NRL inpcb (bsdi4/openbsd), do not forget to modify - * sys/netinet6/raw_ipv6.c:rip6_ctloutput(). */ int icmp6_ctloutput(so, sopt) @@ -2471,7 +2703,7 @@ icmp6_ctloutput(so, sopt) { int error = 0; int optlen; - register struct inpcb *inp = sotoinpcb(so); + struct inpcb *inp = sotoinpcb(so); int level, op, optname; if (sopt) { @@ -2481,11 +2713,12 @@ icmp6_ctloutput(so, sopt) optlen = sopt->sopt_valsize; } else level = op = optname = optlen = 0; + if (level != IPPROTO_ICMPV6) { return EINVAL; } - switch(op) { + switch (op) { case PRCO_SETOPT: switch (optname) { case ICMP6_FILTER: @@ -2533,42 +2766,79 @@ icmp6_ctloutput(so, sopt) return(error); } +#ifdef HAVE_NRL_INPCB +#undef sotoin6pcb +#undef in6pcb +#undef in6p_icmp6filt +#endif + +#ifndef HAVE_PPSRATECHECK +#ifndef timersub +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif -#ifndef HAVE_RATECHECK /* - * ratecheck() returns true if it is okay to send. We return - * true if it is not okay to send. + * ppsratecheck(): packets (or events) per second limitation. */ static int -ratecheck(last, limit) - struct timeval *last; - struct timeval *limit; +ppsratecheck(lasttime, curpps, maxpps) + struct timeval *lasttime; + int *curpps; + int maxpps; /* maximum pps allowed */ { - struct timeval tp; - struct timeval nextsend; + struct timeval tv, delta; + int s, rv; - microtime(&tp); - tp.tv_sec = time_second; + s = splclock(); + microtime(&tv); + splx(s); - /* rate limit */ - if (last->tv_sec != 0 || last->tv_usec != 0) { - nextsend.tv_sec = last->tv_sec + limit->tv_sec; - nextsend.tv_usec = last->tv_usec + limit->tv_usec; - nextsend.tv_sec += (nextsend.tv_usec / 1000000); - nextsend.tv_usec %= 1000000; - - if (nextsend.tv_sec == tp.tv_sec && nextsend.tv_usec <= tp.tv_usec) - ; - else if (nextsend.tv_sec <= tp.tv_sec) - ; - else { - /* The packet is subject to rate limit */ - return 0; - } - } + timersub(&tv, lasttime, &delta); + + /* + * check for 0,0 is so that the message will be seen at least once. + * if more than one second have passed since the last update of + * lasttime, reset the counter. + * + * we do increment *curpps even in *curpps < maxpps case, as some may + * try to use *curpps for stat purposes as well. + */ + if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || + delta.tv_sec >= 1) { + *lasttime = tv; + *curpps = 0; + rv = 1; + } else if (maxpps < 0) + rv = 1; + else if (*curpps < maxpps) + rv = 1; + else + rv = 0; + +#if 1 /*DIAGNOSTIC?*/ + /* be careful about wrap-around */ + if (*curpps + 1 > *curpps) + *curpps = *curpps + 1; +#else + /* + * assume that there's not too many calls to this function. + * not sure if the assumption holds, as it depends on *caller's* + * behavior, not the behavior of this function. + * IMHO it is wrong to make assumption on the caller's behavior, + * so the above #if is #if 1, not #ifdef DIAGNOSTIC. + */ + *curpps = *curpps + 1; +#endif - *last = tp; - return 1; + return (rv); } #endif @@ -2578,14 +2848,6 @@ ratecheck(last, limit) * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate * limitation. * - * There are two limitations defined: - * - pps limit: ICMPv6 error packet cannot exceed defined packet-per-second. - * we measure it every 0.2 second, since fasttimo works every 0.2 second. - * - rate limit: ICMPv6 error packet cannot appear more than once per - * defined interval. - * In any case, if we perform rate limitation, we'll see jitter in the ICMPv6 - * error packets. - * * XXX per-destination/type check necessary? */ static int @@ -2599,13 +2861,8 @@ icmp6_ratelimit(dst, type, code) ret = 0; /*okay to send*/ /* PPS limit */ - icmp6errpps_count++; - if (icmp6errppslim && icmp6errpps_count > icmp6errppslim / 5) { - /* The packet is subject to pps limit */ - ret++; - } - - if (!ratecheck(&icmp6errratelim_last, &icmp6errratelim)) { + if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count, + icmp6errppslim)) { /* The packet is subject to rate limit */ ret++; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 5f51cef..1fd566b 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6.c,v 1.99 2000/07/11 17:00:58 jinmei Exp $ */ +/* $KAME: in6.c,v 1.187 2001/05/24 07:43:59 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -88,6 +88,11 @@ #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet/if_ether.h> +#ifndef SCOPEDROUTING +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#endif #include <netinet6/nd6.h> #include <netinet/ip6.h> @@ -96,6 +101,9 @@ #include <netinet6/ip6_mroute.h> #include <netinet6/in6_ifattach.h> #include <netinet6/scope6_var.h> +#ifndef SCOPEDROUTING +#include <netinet6/in6_pcb.h> +#endif #include "gif.h" #if NGIF > 0 @@ -124,103 +132,105 @@ const struct in6_addr in6mask64 = IN6MASK64; const struct in6_addr in6mask96 = IN6MASK96; const struct in6_addr in6mask128 = IN6MASK128; +const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6, + 0, 0, IN6ADDR_ANY_INIT, 0}; + static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); +static int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *, + struct sockaddr_in6 *, int)); +static void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *)); struct in6_multihead in6_multihead; /* XXX BSS initialization */ /* - * Check if the loopback entry will be automatically generated. - * if 0 returned, will not be automatically generated. - * if 1 returned, will be automatically generated. - */ -static int -in6_is_ifloop_auto(struct ifaddr *ifa) -{ -#define SIN6(s) ((struct sockaddr_in6 *)s) - /* - * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT), - * or netmask is all0 or all1, then cloning will not happen, - * then we can't rely on its loopback entry generation. - */ - if ((ifa->ifa_flags & RTF_CLONING) == 0 || - (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) || - (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6) - && - IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr, - &in6mask128)) || - ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0) - return 0; - else - return 1; -#undef SIN6 -} - -/* * Subroutine for in6_ifaddloop() and in6_ifremloop(). * This routine does actual work. */ static void in6_ifloop_request(int cmd, struct ifaddr *ifa) { - struct sockaddr_in6 lo_sa; struct sockaddr_in6 all1_sa; - struct rtentry *nrt = NULL, **nrtp = NULL; + struct rtentry *nrt = NULL; + int e; - bzero(&lo_sa, sizeof(lo_sa)); bzero(&all1_sa, sizeof(all1_sa)); - lo_sa.sin6_family = AF_INET6; - lo_sa.sin6_len = sizeof(struct sockaddr_in6); - all1_sa = lo_sa; - lo_sa.sin6_addr = in6addr_loopback; + all1_sa.sin6_family = AF_INET6; + all1_sa.sin6_len = sizeof(struct sockaddr_in6); all1_sa.sin6_addr = in6mask128; - + /* - * So we add or remove static loopback entry, here. - * This request for deletion could fail, e.g. when we remove - * an address right after adding it. + * We specify the address itself as the gateway, and set the + * RTF_LLINFO flag, so that the corresponding host route would have + * the flag, and thus applications that assume traditional behavior + * would be happy. Note that we assume the caller of the function + * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest, + * which changes the outgoing interface to the loopback interface. */ - if (cmd == RTM_ADD) - nrtp = &nrt; - rtrequest(cmd, ifa->ifa_addr, - (struct sockaddr *)&lo_sa, - (struct sockaddr *)&all1_sa, - RTF_UP|RTF_HOST, nrtp); + e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, + (struct sockaddr *)&all1_sa, + RTF_UP|RTF_HOST|RTF_LLINFO, &nrt); + if (e != 0) { + log(LOG_ERR, "in6_ifloop_request: " + "%s operation failed for %s (errno=%d)\n", + cmd == RTM_ADD ? "ADD" : "DELETE", + ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr), + e); + } /* * Make sure rt_ifa be equal to IFA, the second argument of the * function. - * We need this because when we refer rt_ifa->ia6_flags in ip6_input, - * we assume that the rt_ifa points to the address instead of the - * loopback address. + * We need this because when we refer to rt_ifa->ia6_flags in + * ip6_input, we assume that the rt_ifa points to the address instead + * of the loopback address. */ if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) { IFAFREE(nrt->rt_ifa); - ifa->ifa_refcnt++; + IFAREF(ifa); nrt->rt_ifa = ifa; } - if (nrt) - nrt->rt_refcnt--; + + /* + * Report the addition/removal of the address to the routing socket. + * XXX: since we called rtinit for a p2p interface with a destination, + * we end up reporting twice in such a case. Should we rather + * omit the second report? + */ + if (nrt) { + rt_newaddrmsg(cmd, ifa, e, nrt); + if (cmd == RTM_DELETE) { + if (nrt->rt_refcnt <= 0) { + /* XXX: we should free the entry ourselves. */ + nrt->rt_refcnt++; + rtfree(nrt); + } + } else { + /* the cmd must be RTM_ADD here */ + nrt->rt_refcnt--; + } + } } /* - * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). - * Because, KAME needs loopback rtentry for ownaddr check in - * ip6_input(). + * Add ownaddr as loopback rtentry. We previously add the route only if + * necessary (ex. on a p2p link). However, since we now manage addresses + * separately from prefixes, we should always add the route. We can't + * rely on the cloning mechanism from the corresponding interface route + * any more. */ static void in6_ifaddloop(struct ifaddr *ifa) { - if (!in6_is_ifloop_auto(ifa)) { - struct rtentry *rt; - - /* If there is no loopback entry, allocate one. */ - rt = rtalloc1(ifa->ifa_addr, 0, 0); - if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) - in6_ifloop_request(RTM_ADD, ifa); - if (rt) - rt->rt_refcnt--; - } + struct rtentry *rt; + + /* If there is no loopback entry, allocate one. */ + rt = rtalloc1(ifa->ifa_addr, 0, 0); + if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || + (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) + in6_ifloop_request(RTM_ADD, ifa); + if (rt) + rt->rt_refcnt--; } /* @@ -231,28 +241,48 @@ static void in6_ifremloop(struct ifaddr *ifa) { struct in6_ifaddr *ia; + struct rtentry *rt; int ia_count = 0; /* - * All BSD variants except BSD/OS do not remove cloned routes + * Some of BSD variants do not remove cloned routes * from an interface direct route, when removing the direct route - * (see commens in net/net_osdep.h). - * So we should remove the route corresponding to the deleted address + * (see comments in net/net_osdep.h). Even for variants that do remove + * cloned routes, they could fail to remove the cloned routes when + * we handle multple addresses that share a common prefix. + * So, we should remove the route corresponding to the deleted address * regardless of the result of in6_is_ifloop_auto(). */ - if (1) - { - /* If only one ifa for the loopback entry, delete it. */ - for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), - &ia->ia_addr.sin6_addr)) { - ia_count++; - if (ia_count > 1) - break; - } + + /* + * Delete the entry only if exact one ifa exists. More than one ifa + * can exist if we assign a same single address to multiple + * (probably p2p) interfaces. + * XXX: we should avoid such a configuration in IPv6... + */ + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { + ia_count++; + if (ia_count > 1) + break; } - if (ia_count == 1) + } + + if (ia_count == 1) { + /* + * Before deleting, check if a corresponding loopbacked host + * route surely exists. With this check, we can avoid to + * delete an interface direct route whose destination is same + * as the address being removed. This can happen when remofing + * a subnet-router anycast address on an interface attahced + * to a shared medium. + */ + rt = rtalloc1(ifa->ifa_addr, 0, 0); + if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 && + (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { + rt->rt_refcnt--; in6_ifloop_request(RTM_DELETE, ifa); + } } } @@ -281,22 +311,40 @@ in6_ifindex2scopeid(idx) } int -in6_mask2len(mask) +in6_mask2len(mask, lim0) struct in6_addr *mask; + u_char *lim0; { - int x, y; - - for (x = 0; x < sizeof(*mask); x++) { - if (mask->s6_addr8[x] != 0xff) + int x = 0, y; + u_char *lim = lim0, *p; + + if (lim0 == NULL || + lim0 - (u_char *)mask > sizeof(*mask)) /* ignore the scope_id part */ + lim = (u_char *)mask + sizeof(*mask); + for (p = (u_char *)mask; p < lim; x++, p++) { + if (*p != 0xff) break; } y = 0; - if (x < sizeof(*mask)) { + if (p < lim) { for (y = 0; y < 8; y++) { - if ((mask->s6_addr8[x] & (0x80 >> y)) == 0) + if ((*p & (0x80 >> y)) == 0) break; } } + + /* + * when the limit pointer is given, do a stricter check on the + * remaining bits. + */ + if (p < lim) { + if (y != 0 && (*p & (0x00ff >> y)) != 0) + return(-1); + for (p = p + 1; p < lim; p++) + if (*p != 0) + return(-1); + } + return x * 8 + y; } @@ -326,36 +374,14 @@ in6_control(so, cmd, data, ifp, p) struct proc *p; { struct in6_ifreq *ifr = (struct in6_ifreq *)data; - struct in6_ifaddr *ia = NULL, *oia; + struct in6_ifaddr *ia = NULL; struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; - struct sockaddr_in6 oldaddr; -#ifdef COMPAT_IN6IFIOCTL - struct sockaddr_in6 net; -#endif - int error = 0, hostIsNew, prefixIsNew; - int newifaddr; int privileged; privileged = 0; if (p == NULL || !suser(p)) privileged++; - /* - * xxx should prevent processes for link-local addresses? - */ -#if NGIF > 0 - if (ifp && ifp->if_type == IFT_GIF) { - switch (cmd) { - case SIOCSIFPHYADDR_IN6: - if (!privileged) - return(EPERM); - /*fall through*/ - case SIOCGIFPSRCADDR_IN6: - case SIOCGIFPDSTADDR_IN6: - return gif_ioctl(ifp, cmd, data); - } - } -#endif switch (cmd) { case SIOCGETSGCNT_IN6: case SIOCGETMIFCNT_IN6: @@ -374,6 +400,7 @@ in6_control(so, cmd, data, ifp, p) if (!privileged) return(EPERM); /*fall through*/ + case OSIOCGIFINFO_IN6: case SIOCGIFINFO_IN6: case SIOCGDRLST_IN6: case SIOCGPRLST_IN6: @@ -388,13 +415,11 @@ in6_control(so, cmd, data, ifp, p) case SIOCAIFPREFIX_IN6: case SIOCCIFPREFIX_IN6: case SIOCSGIFPREFIX_IN6: - if (!privileged) - return(EPERM); - /*fall through*/ case SIOCGIFPREFIX_IN6: - if (ip6_forwarding == 0) - return(EPERM); - return(in6_prefix_ioctl(so, cmd, data, ifp)); + log(LOG_NOTICE, + "prefix ioctls are now invalidated. " + "please use ifconfig.\n"); + return(EOPNOTSUPP); } switch(cmd) { @@ -430,12 +455,12 @@ in6_control(so, cmd, data, ifp, p) if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { if (sa6->sin6_addr.s6_addr16[1] == 0) { - /* interface ID is not embedded by the user */ + /* link ID is not embedded by the user */ sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index); } else if (sa6->sin6_addr.s6_addr16[1] != htons(ifp->if_index)) { - return(EINVAL); /* ifid is contradict */ + return(EINVAL); /* link ID contradicts */ } if (sa6->sin6_scope_id) { if (sa6->sin6_scope_id != @@ -448,92 +473,39 @@ in6_control(so, cmd, data, ifp, p) } switch (cmd) { + case SIOCSIFADDR_IN6: + case SIOCSIFDSTADDR_IN6: + case SIOCSIFNETMASK_IN6: + /* + * Since IPv6 allows a node to assign multiple addresses + * on a single interface, SIOCSIFxxx ioctls are not suitable + * and should be unused. + */ + /* we decided to obsolete this command (20000704) */ + return(EINVAL); case SIOCDIFADDR_IN6: /* - * for IPv4, we look for existing in6_ifaddr here to allow + * for IPv4, we look for existing in_ifaddr here to allow * "ifconfig if0 delete" to remove first IPv4 address on the * interface. For IPv6, as the spec allow multiple interface * address from the day one, we consider "remove the first one" - * semantics to be not preferrable. + * semantics to be not preferable. */ if (ia == NULL) return(EADDRNOTAVAIL); /* FALLTHROUGH */ case SIOCAIFADDR_IN6: - case SIOCSIFADDR_IN6: -#ifdef COMPAT_IN6IFIOCTL - case SIOCSIFDSTADDR_IN6: - case SIOCSIFNETMASK_IN6: /* - * Since IPv6 allows a node to assign multiple addresses - * on a single interface, SIOCSIFxxx ioctls are not suitable - * and should be unused. + * We always require users to specify a valid IPv6 address for + * the corresponding operation. */ -#endif - if (ifra->ifra_addr.sin6_family != AF_INET6) + if (ifra->ifra_addr.sin6_family != AF_INET6 || + ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) return(EAFNOSUPPORT); if (!privileged) return(EPERM); - if (ia == NULL) { - ia = (struct in6_ifaddr *) - malloc(sizeof(*ia), M_IFADDR, M_WAITOK); - if (ia == NULL) - return (ENOBUFS); - bzero((caddr_t)ia, sizeof(*ia)); - /* Initialize the address and masks */ - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - ia->ia_addr.sin6_family = AF_INET6; - ia->ia_addr.sin6_len = sizeof(ia->ia_addr); -#if 1 - if (ifp->if_flags & IFF_POINTOPOINT) { - ia->ia_ifa.ifa_dstaddr - = (struct sockaddr *)&ia->ia_dstaddr; - ia->ia_dstaddr.sin6_family = AF_INET6; - ia->ia_dstaddr.sin6_len = sizeof(ia->ia_dstaddr); - } else { - ia->ia_ifa.ifa_dstaddr = NULL; - bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); - } -#else /* always initilize by NULL */ - ia->ia_ifa.ifa_dstaddr = NULL; - bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); -#endif - ia->ia_ifa.ifa_netmask - = (struct sockaddr *)&ia->ia_prefixmask; - - ia->ia_ifp = ifp; - if ((oia = in6_ifaddr) != NULL) { - for ( ; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - /* gain a refcnt for the link from in6_ifaddr */ - ia->ia_ifa.ifa_refcnt++; - TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, - ifa_list); - /* gain another refcnt for the link from if_addrlist */ - ia->ia_ifa.ifa_refcnt++; - - newifaddr = 1; - } else - newifaddr = 0; - - if (cmd == SIOCAIFADDR_IN6) { - /* sanity for overflow - beware unsigned */ - struct in6_addrlifetime *lt; - lt = &ifra->ifra_lifetime; - if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME - && lt->ia6t_vltime + time_second < time_second) { - return EINVAL; - } - if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME - && lt->ia6t_pltime + time_second < time_second) { - return EINVAL; - } - } break; case SIOCGIFADDR_IN6: @@ -618,42 +590,6 @@ in6_control(so, cmd, data, ifp, p) *icmp6_ifstat[ifp->if_index]; break; -#ifdef COMPAT_IN6IFIOCTL /* should be unused */ - case SIOCSIFDSTADDR_IN6: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - return(EINVAL); - oldaddr = ia->ia_dstaddr; - ia->ia_dstaddr = ifr->ifr_dstaddr; - - /* link-local index check */ - if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { - if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { - /* interface ID is not embedded by the user */ - ia->ia_dstaddr.sin6_addr.s6_addr16[1] - = htons(ifp->if_index); - } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - ia->ia_dstaddr = oldaddr; - return(EINVAL); /* ifid is contradict */ - } - } - - if (ifp->if_ioctl && (error = (ifp->if_ioctl) - (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { - ia->ia_dstaddr = oldaddr; - return(error); - } - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; - if (ia->ia_flags & IFA_ROUTE) { - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); - ia->ia_ifa.ifa_dstaddr = - (struct sockaddr *)&ia->ia_dstaddr; - rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); - } - break; - -#endif case SIOCGIFALIFETIME_IN6: ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; break; @@ -673,129 +609,400 @@ in6_control(so, cmd, data, ifp, p) ia->ia6_lifetime.ia6t_preferred = 0; break; - case SIOCSIFADDR_IN6: - error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1); -#if 0 + case SIOCAIFADDR_IN6: + { + int i, error = 0; + struct nd_prefix pr0, *pr; + + /* + * first, make or update the interface address structure, + * and link it to the list. + */ + if ((error = in6_update_ifa(ifp, ifra, ia)) != 0) + return(error); + /* - * the code chokes if we are to assign multiple addresses with - * the same address prefix (rtinit() will return EEXIST, which - * is not fatal actually). we will get memory leak if we - * don't do it. - * -> we may want to hide EEXIST from rtinit(). + * then, make the prefix on-link on the interface. + * XXX: we'd rather create the prefix before the address, but + * we need at least one address to install the corresponding + * interface route, so we configure the address first. */ - undo: - if (error && newifaddr) { - TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); - /* release a refcnt for the link from if_addrlist */ - IFAFREE(&ia->ia_ifa); - - oia = ia; - if (oia == (ia = in6_ifaddr)) - in6_ifaddr = ia->ia_next; - else { - while (ia->ia_next && (ia->ia_next != oia)) - ia = ia->ia_next; - if (ia->ia_next) - ia->ia_next = oia->ia_next; - else { - printf("Didn't unlink in6_ifaddr " - "from list\n"); + + /* + * convert mask to prefix length (prefixmask has already + * been validated in in6_update_ifa(). + */ + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_ifp = ifp; + pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, + NULL); + if (pr0.ndpr_plen == 128) + break; /* we don't need to install a host route. */ + pr0.ndpr_prefix = ifra->ifra_addr; + pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr; + /* apply the mask for safety. */ + for (i = 0; i < 4; i++) { + pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= + ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; + } + /* + * XXX: since we don't have enough APIs, we just set inifinity + * to lifetimes. They can be overridden by later advertised + * RAs (when accept_rtadv is non 0), but we'd rather intend + * such a behavior. + */ + pr0.ndpr_raf_onlink = 1; /* should be configurable? */ + pr0.ndpr_raf_auto = + ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); + pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; + pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; + + /* add the prefix if there's one. */ + if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { + /* + * nd6_prelist_add will install the corresponding + * interface route. + */ + if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) + return(error); + if (pr == NULL) { + log(LOG_ERR, "nd6_prelist_add succedded but " + "no prefix\n"); + return(EINVAL); /* XXX panic here? */ + } + } + if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) + == NULL) { + /* XXX: this should not happen! */ + log(LOG_ERR, "in6_control: addition succeeded, but" + " no ifaddr\n"); + } else { + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && + ia->ia6_ndpr == NULL) { /* new autoconfed addr */ + ia->ia6_ndpr = pr; + pr->ndpr_refcnt++; + + /* + * If this is the first autoconf address from + * the prefix, create a temporary address + * as well (when specified). + */ + if (ip6_use_tempaddr && + pr->ndpr_refcnt == 1) { + int e; + if ((e = in6_tmpifadd(ia, 1)) != 0) { + log(LOG_NOTICE, "in6_control: " + "failed to create a " + "temporary address, " + "errno=%d\n", + e); + } } } - /* release another refcnt for the link from in6_ifaddr */ - IFAFREE(&oia->ia_ifa); + + /* + * this might affect the status of autoconfigured + * addresses, that is, this address might make + * other addresses detached. + */ + pfxlist_onlink_check(); } -#endif - return error; + break; + } -#ifdef COMPAT_IN6IFIOCTL /* XXX should be unused */ - case SIOCSIFNETMASK_IN6: - ia->ia_prefixmask = ifr->ifr_addr; - bzero(&net, sizeof(net)); - net.sin6_len = sizeof(struct sockaddr_in6); - net.sin6_family = AF_INET6; - net.sin6_port = htons(0); - net.sin6_flowinfo = htonl(0); - net.sin6_addr.s6_addr32[0] - = ia->ia_addr.sin6_addr.s6_addr32[0] & - ia->ia_prefixmask.sin6_addr.s6_addr32[0]; - net.sin6_addr.s6_addr32[1] - = ia->ia_addr.sin6_addr.s6_addr32[1] & - ia->ia_prefixmask.sin6_addr.s6_addr32[1]; - net.sin6_addr.s6_addr32[2] - = ia->ia_addr.sin6_addr.s6_addr32[2] & - ia->ia_prefixmask.sin6_addr.s6_addr32[2]; - net.sin6_addr.s6_addr32[3] - = ia->ia_addr.sin6_addr.s6_addr32[3] & - ia->ia_prefixmask.sin6_addr.s6_addr32[3]; - ia->ia_net = net; + case SIOCDIFADDR_IN6: + { + int i = 0; + struct nd_prefix pr0, *pr; + + /* + * If the address being deleted is the only one that owns + * the corresponding prefix, expire the prefix as well. + * XXX: theoretically, we don't have to warry about such + * relationship, since we separate the address management + * and the prefix management. We do this, however, to provide + * as much backward compatibility as possible in terms of + * the ioctl operation. + */ + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_ifp = ifp; + pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, + NULL); + if (pr0.ndpr_plen == 128) + goto purgeaddr; + pr0.ndpr_prefix = ia->ia_addr; + pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr; + for (i = 0; i < 4; i++) { + pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= + ia->ia_prefixmask.sin6_addr.s6_addr32[i]; + } + /* + * The logic of the following condition is a bit complicated. + * We expire the prefix when + * 1. the address obeys autoconfiguration and it is the + * only owner of the associated prefix, or + * 2. the address does not obey autoconf and there is no + * other owner of the prefix. + */ + if ((pr = nd6_prefix_lookup(&pr0)) != NULL && + (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && + pr->ndpr_refcnt == 1) || + ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 && + pr->ndpr_refcnt == 0))) { + pr->ndpr_expire = 1; /* XXX: just for expiration */ + } + + purgeaddr: + in6_purgeaddr(&ia->ia_ifa); break; -#endif + } - case SIOCAIFADDR_IN6: - prefixIsNew = 0; - hostIsNew = 1; + default: + if (ifp == NULL || ifp->if_ioctl == 0) + return(EOPNOTSUPP); + return((*ifp->if_ioctl)(ifp, cmd, data)); + } + + return(0); +} + +/* + * Update parameters of an IPv6 interface address. + * If necessary, a new entry is created and linked into address chains. + * This function is separated from in6_control(). + * XXX: should this be performed under splnet()? + */ +int +in6_update_ifa(ifp, ifra, ia) + struct ifnet *ifp; + struct in6_aliasreq *ifra; + struct in6_ifaddr *ia; +{ + int error = 0, hostIsNew = 0, plen = -1; + struct in6_ifaddr *oia; + struct sockaddr_in6 dst6; + struct in6_addrlifetime *lt; - if (ifra->ifra_addr.sin6_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr, - &ia->ia_addr.sin6_addr)) - hostIsNew = 0; + /* Validate parameters */ + if (ifp == NULL || ifra == NULL) /* this maybe redundant */ + return(EINVAL); - /* Validate address families: */ + /* + * The destination address for a p2p link must have a family + * of AF_UNSPEC or AF_INET6. + */ + if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && + ifra->ifra_dstaddr.sin6_family != AF_INET6 && + ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) + return(EAFNOSUPPORT); + /* + * validate ifra_prefixmask. don't check sin6_family, netmask + * does not carry fields other than sin6_len. + */ + if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) + return(EINVAL); + /* + * Because the IPv6 address architecture is classless, we require + * users to specify a (non 0) prefix length (mask) for a new address. + * We also require the prefix (when specified) mask is valid, and thus + * reject a non-consecutive mask. + */ + if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) + return(EINVAL); + if (ifra->ifra_prefixmask.sin6_len != 0) { + plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, + (u_char *)&ifra->ifra_prefixmask + + ifra->ifra_prefixmask.sin6_len); + if (plen <= 0) + return(EINVAL); + } + else { /* - * The destination address for a p2p link must have a family - * of AF_UNSPEC or AF_INET6. + * In this case, ia must not be NULL. We just use its prefix + * length. */ - if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && - ifra->ifra_dstaddr.sin6_family != AF_INET6 && - ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) - return(EAFNOSUPPORT); + plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); + } + /* + * If the destination address on a p2p interface is specified, + * and the address is a scoped one, validate/set the scope + * zone identifier. + */ + dst6 = ifra->ifra_dstaddr; + if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) && + (dst6.sin6_family == AF_INET6)) { + int scopeid; + +#ifndef SCOPEDROUTING + if ((error = in6_recoverscope(&dst6, + &ifra->ifra_dstaddr.sin6_addr, + ifp)) != 0) + return(error); +#endif + scopeid = in6_addr2scopeid(ifp, &dst6.sin6_addr); + if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */ + dst6.sin6_scope_id = scopeid; + else if (dst6.sin6_scope_id != scopeid) + return(EINVAL); /* scope ID mismatch. */ +#ifndef SCOPEDROUTING + if ((error = in6_embedscope(&dst6.sin6_addr, &dst6, NULL, NULL)) + != 0) + return(error); + dst6.sin6_scope_id = 0; /* XXX */ +#endif + } + /* + * The destination address can be specified only for a p2p or a + * loopback interface. If specified, the corresponding prefix length + * must be 128. + */ + if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { + if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { + /* XXX: noisy message */ + log(LOG_INFO, "in6_update_ifa: a destination can be " + "specified for a p2p or a loopback IF only\n"); + return(EINVAL); + } + if (plen != 128) { + /* + * The following message seems noisy, but we dare to + * add it for diagnosis. + */ + log(LOG_INFO, "in6_update_ifa: prefixlen must be 128 " + "when dstaddr is specified\n"); + return(EINVAL); + } + } + /* lifetime consistency check */ + lt = &ifra->ifra_lifetime; + if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME + && lt->ia6t_vltime + time_second < time_second) { + return EINVAL; + } + if (lt->ia6t_vltime == 0) { /* - * The prefixmask must have a family of AF_UNSPEC or AF_INET6. + * the following log might be noisy, but this is a typical + * configuration mistake or a tool's bug. */ - if (ifra->ifra_prefixmask.sin6_family != AF_INET6 && - ifra->ifra_prefixmask.sin6_family != AF_UNSPEC) - return(EAFNOSUPPORT); + log(LOG_INFO, + "in6_update_ifa: valid lifetime is 0 for %s\n", + ip6_sprintf(&ifra->ifra_addr.sin6_addr)); + } + if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME + && lt->ia6t_pltime + time_second < time_second) { + return EINVAL; + } - if (ifra->ifra_prefixmask.sin6_len) { - in6_ifscrub(ifp, ia); - ia->ia_prefixmask = ifra->ifra_prefixmask; - prefixIsNew = 1; + /* + * If this is a new address, allocate a new ifaddr and link it + * into chains. + */ + if (ia == NULL) { + hostIsNew = 1; + ia = (struct in6_ifaddr *) + malloc(sizeof(*ia), M_IFADDR, M_WAITOK); + if (ia == NULL) + return (ENOBUFS); + bzero((caddr_t)ia, sizeof(*ia)); + /* Initialize the address and masks */ + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + ia->ia_addr.sin6_family = AF_INET6; + ia->ia_addr.sin6_len = sizeof(ia->ia_addr); + if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { + /* + * XXX: some functions expect that ifa_dstaddr is not + * NULL for p2p interfaces. + */ + ia->ia_ifa.ifa_dstaddr + = (struct sockaddr *)&ia->ia_dstaddr; + } else { + ia->ia_ifa.ifa_dstaddr = NULL; } - if ((ifp->if_flags & IFF_POINTOPOINT) && - (ifra->ifra_dstaddr.sin6_family == AF_INET6)) { - in6_ifscrub(ifp, ia); - oldaddr = ia->ia_dstaddr; - ia->ia_dstaddr = ifra->ifra_dstaddr; - /* link-local index check: should be a separate function? */ - if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { - if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { - /* - * interface ID is not embedded by - * the user - */ - ia->ia_dstaddr.sin6_addr.s6_addr16[1] - = htons(ifp->if_index); - } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - ia->ia_dstaddr = oldaddr; - return(EINVAL); /* ifid is contradict */ - } - } - prefixIsNew = 1; /* We lie; but effect's the same */ + ia->ia_ifa.ifa_netmask + = (struct sockaddr *)&ia->ia_prefixmask; + + ia->ia_ifp = ifp; + if ((oia = in6_ifaddr) != NULL) { + for ( ; oia->ia_next; oia = oia->ia_next) + continue; + oia->ia_next = ia; + } else + in6_ifaddr = ia; + + TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, + ifa_list); + } + + /* set prefix mask */ + if (ifra->ifra_prefixmask.sin6_len) { + /* + * We prohibit changing the prefix length of an existing + * address, because + * + such an operation should be rare in IPv6, and + * + the operation would confuse prefix management. + */ + if (ia->ia_prefixmask.sin6_len && + in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { + log(LOG_INFO, "in6_update_ifa: the prefix length of an" + " existing (%s) address should not be changed\n", + ip6_sprintf(&ia->ia_addr.sin6_addr)); + error = EINVAL; + goto unlink; } - if (hostIsNew || prefixIsNew) { - error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0); -#if 0 - if (error) - goto undo; -#endif + ia->ia_prefixmask = ifra->ifra_prefixmask; + } + + /* + * If a new destination address is specified, scrub the old one and + * install the new destination. Note that the interface must be + * p2p or loopback (see the check above.) + */ + if (dst6.sin6_family == AF_INET6 && + !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, + &ia->ia_dstaddr.sin6_addr)) { + int e; + + if ((ia->ia_flags & IFA_ROUTE) != 0 && + (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) + != 0) { + log(LOG_ERR, "in6_update_ifa: failed to remove " + "a route to the old destination: %s\n", + ip6_sprintf(&ia->ia_addr.sin6_addr)); + /* proceed anyway... */ } - if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) { - int error_local = 0; + else + ia->ia_flags &= ~IFA_ROUTE; + ia->ia_dstaddr = dst6; + } + /* reset the interface and routing table appropriately. */ + if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) + goto unlink; + + /* + * Beyond this point, we should call in6_purgeaddr upon an error, + * not just go to unlink. + */ + +#if 0 /* disable this mechanism for now */ + /* update prefix list */ + if (hostIsNew && + (ifra->ifra_flags & IN6_IFF_NOPFX) == 0) { /* XXX */ + int iilen; + + iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - plen; + if ((error = in6_prefix_add_ifid(iilen, ia)) != 0) { + in6_purgeaddr((struct ifaddr *)ia); + return(error); + } + } +#endif + + if ((ifp->if_flags & IFF_MULTICAST) != 0) { + struct sockaddr_in6 mltaddr, mltmask; + struct in6_multi *in6m; + + if (hostIsNew) { /* * join solicited multicast addr for new host id */ @@ -808,98 +1015,182 @@ in6_control(so, cmd, data, ifp, p) llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error_local); - if (error == 0) - error = error_local; + (void)in6_addmulti(&llsol, ifp, &error); + if (error != 0) { + log(LOG_WARNING, + "in6_update_ifa: addmulti failed for " + "%s on %s (errno=%d)\n", + ip6_sprintf(&llsol), if_name(ifp), + error); + in6_purgeaddr((struct ifaddr *)ia); + return(error); + } } - ia->ia6_flags = ifra->ifra_flags; - ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ - - ia->ia6_lifetime = ifra->ifra_lifetime; - /* for sanity */ - if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { - ia->ia6_lifetime.ia6t_expire = - time_second + ia->ia6_lifetime.ia6t_vltime; - } else - ia->ia6_lifetime.ia6t_expire = 0; - if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { - ia->ia6_lifetime.ia6t_preferred = - time_second + ia->ia6_lifetime.ia6t_pltime; - } else - ia->ia6_lifetime.ia6t_preferred = 0; + bzero(&mltmask, sizeof(mltmask)); + mltmask.sin6_len = sizeof(struct sockaddr_in6); + mltmask.sin6_family = AF_INET6; + mltmask.sin6_addr = in6mask32; /* - * make sure to initialize ND6 information. this is to - * workaround issues with interfaces with IPv6 addresses, - * which have never brought # up. we are assuming that it is - * safe to nd6_ifattach multiple times. + * join link-local all-nodes address */ - nd6_ifattach(ifp); + bzero(&mltaddr, sizeof(mltaddr)); + mltaddr.sin6_len = sizeof(struct sockaddr_in6); + mltaddr.sin6_family = AF_INET6; + mltaddr.sin6_addr = in6addr_linklocal_allnodes; + mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); + + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m == NULL) { + rtrequest(RTM_ADD, + (struct sockaddr *)&mltaddr, + (struct sockaddr *)&ia->ia_addr, + (struct sockaddr *)&mltmask, + RTF_UP|RTF_CLONING, /* xxx */ + (struct rtentry **)0); + (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); + if (error != 0) { + log(LOG_WARNING, + "in6_update_ifa: addmulti failed for " + "%s on %s (errno=%d)\n", + ip6_sprintf(&mltaddr.sin6_addr), + if_name(ifp), error); + } + } /* - * Perform DAD, if needed. - * XXX It may be of use, if we can administratively - * disable DAD. + * join node information group address */ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: -#if 0 - case IFT_ATM: - case IFT_SLIP: - case IFT_PPP: -#endif - { - ia->ia6_flags |= IN6_IFF_TENTATIVE; - nd6_dad_start((struct ifaddr *)ia, NULL); +#define hostnamelen strlen(hostname) + if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) + == 0) { + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m == NULL && ia != NULL) { + (void)in6_addmulti(&mltaddr.sin6_addr, + ifp, &error); + if (error != 0) { + log(LOG_WARNING, "in6_update_ifa: " + "addmulti failed for " + "%s on %s (errno=%d)\n", + ip6_sprintf(&mltaddr.sin6_addr), + if_name(ifp), error); + } } - break; -#ifdef IFT_DUMMY - case IFT_DUMMY: -#endif - case IFT_FAITH: - case IFT_GIF: - case IFT_LOOP: - default: - break; } +#undef hostnamelen - if (hostIsNew) { - int iilen; - int error_local = 0; - - iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - - in6_mask2len(&ia->ia_prefixmask.sin6_addr); - error_local = in6_prefix_add_ifid(iilen, ia); - if (error == 0) - error = error_local; + /* + * join node-local all-nodes address, on loopback. + * XXX: since "node-local" is obsoleted by interface-local, + * we have to join the group on every interface with + * some interface-boundary restriction. + */ + if (ifp->if_flags & IFF_LOOPBACK) { + struct in6_addr loop6 = in6addr_loopback; + ia = in6ifa_ifpwithaddr(ifp, &loop6); + + mltaddr.sin6_addr = in6addr_nodelocal_allnodes; + + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m == NULL && ia != NULL) { + rtrequest(RTM_ADD, + (struct sockaddr *)&mltaddr, + (struct sockaddr *)&ia->ia_addr, + (struct sockaddr *)&mltmask, + RTF_UP, + (struct rtentry **)0); + (void)in6_addmulti(&mltaddr.sin6_addr, ifp, + &error); + if (error != 0) { + log(LOG_WARNING, "in6_update_ifa: " + "addmulti failed for %s on %s " + "(errno=%d)\n", + ip6_sprintf(&mltaddr.sin6_addr), + if_name(ifp), error); + } + } } + } - return(error); + ia->ia6_flags = ifra->ifra_flags; + ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ + ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ + + ia->ia6_lifetime = ifra->ifra_lifetime; + /* for sanity */ + if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { + ia->ia6_lifetime.ia6t_expire = + time_second + ia->ia6_lifetime.ia6t_vltime; + } else + ia->ia6_lifetime.ia6t_expire = 0; + if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { + ia->ia6_lifetime.ia6t_preferred = + time_second + ia->ia6_lifetime.ia6t_pltime; + } else + ia->ia6_lifetime.ia6t_preferred = 0; - case SIOCDIFADDR_IN6: - in6_purgeaddr(&ia->ia_ifa, ifp); - break; + /* + * make sure to initialize ND6 information. this is to workaround + * issues with interfaces with IPv6 addresses, which have never brought + * up. We are assuming that it is safe to nd6_ifattach multiple times. + */ + nd6_ifattach(ifp); - default: - if (ifp == NULL || ifp->if_ioctl == 0) - return(EOPNOTSUPP); - return((*ifp->if_ioctl)(ifp, cmd, data)); + /* + * Perform DAD, if needed. + * XXX It may be of use, if we can administratively + * disable DAD. + */ + if (in6if_do_dad(ifp) && (ifra->ifra_flags & IN6_IFF_NODAD) == 0) { + ia->ia6_flags |= IN6_IFF_TENTATIVE; + nd6_dad_start((struct ifaddr *)ia, NULL); } - return(0); + + return(error); + + unlink: + /* + * XXX: if a change of an existing address failed, keep the entry + * anyway. + */ + if (hostIsNew) + in6_unlink_ifa(ia, ifp); + return(error); } void -in6_purgeaddr(ifa, ifp) +in6_purgeaddr(ifa) struct ifaddr *ifa; - struct ifnet *ifp; { - struct in6_ifaddr *oia, *ia = (void *) ifa; - int plen; + struct ifnet *ifp = ifa->ifa_ifp; + struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; - in6_ifscrub(ifp, ia); + /* stop DAD processing */ + nd6_dad_stop(ifa); + + /* + * delete route to the destination of the address being purged. + * The interface must be p2p or loopback in this case. + */ + if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { + int e; + + if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) + != 0) { + log(LOG_ERR, "in6_purgeaddr: failed to remove " + "a route to the p2p destination: %s on %s, " + "errno=%d\n", + ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp), + e); + /* proceed anyway... */ + } + else + ia->ia_flags &= ~IFA_ROUTE; + } + + /* Remove ownaddr's loopback rtentry, if it exists. */ + in6_ifremloop(&(ia->ia_ifa)); if (ifp->if_flags & IFF_MULTICAST) { /* @@ -921,9 +1212,19 @@ in6_purgeaddr(ifa, ifp) in6_delmulti(in6m); } + in6_unlink_ifa(ia, ifp); +} + +static void +in6_unlink_ifa(ia, ifp) + struct in6_ifaddr *ia; + struct ifnet *ifp; +{ + int plen, iilen; + struct in6_ifaddr *oia; + int s = splnet(); + TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); - /* release a refcnt for the link from if_addrlist */ - IFAFREE(&ia->ia_ifa); oia = ia; if (oia == (ia = in6_ifaddr)) @@ -933,45 +1234,61 @@ in6_purgeaddr(ifa, ifp) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; - else - printf("Didn't unlink in6_ifaddr from list\n"); + else { + /* search failed */ + printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n"); + } } - { - int iilen; - plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr); + if (oia->ia6_ifpr) { /* check for safety */ + plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr, NULL); iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - plen; in6_prefix_remove_ifid(iilen, oia); } /* - * Check if we have another address that has the same prefix of - * the purged address. If we have one, reinstall the corresponding - * interface route. + * When an autoconfigured address is being removed, release the + * reference to the base prefix. Also, since the release might + * affect the status of other (detached) addresses, call + * pfxlist_onlink_check(). */ - for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - int e; - - if (in6_are_prefix_equal(&ia->ia_addr.sin6_addr, - &oia->ia_addr.sin6_addr, plen)) { - if ((e = rtinit(&(ia->ia_ifa), (int)RTM_ADD, - ia->ia_flags)) == 0) { - ia->ia_flags |= IFA_ROUTE; - break; - } - else { - log(LOG_NOTICE, - "in6_purgeaddr: failed to add an interface" - " route for %s/%d on %s, errno = %d\n", - ip6_sprintf(&ia->ia_addr.sin6_addr), - plen, if_name(ia->ia_ifp), e); - /* still trying */ - } + if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { + if (oia->ia6_ndpr == NULL) { + log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " + "%p has no prefix\n", oia); + } else { + oia->ia6_ndpr->ndpr_refcnt--; + oia->ia6_flags &= ~IN6_IFF_AUTOCONF; + oia->ia6_ndpr = NULL; } + + pfxlist_onlink_check(); } - - /* release another refcnt for the link from in6_ifaddr */ + + /* + * release another refcnt for the link from in6_ifaddr. + * Note that we should decrement the refcnt at least once for all *BSD. + */ IFAFREE(&oia->ia_ifa); + + splx(s); +} + +void +in6_purgeif(ifp) + struct ifnet *ifp; +{ + struct ifaddr *ifa, *nifa; + + for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) + { + nifa = TAILQ_NEXT(ifa, ifa_list); + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + in6_purgeaddr(ifa); + } + + in6_ifdetach(ifp); } /* @@ -1107,7 +1424,6 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) } } - ifra.ifra_prefixmask.sin6_family = AF_INET6; ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); @@ -1159,7 +1475,17 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) continue; if (!cmp) break; + bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); +#ifndef SCOPEDROUTING + /* + * XXX: this is adhoc, but is necessary to allow + * a user to specify fe80::/64 (not /10) for a + * link-local address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&candidate)) + candidate.s6_addr16[1] = 0; +#endif candidate.s6_addr32[0] &= mask.s6_addr32[0]; candidate.s6_addr32[1] &= mask.s6_addr32[1]; candidate.s6_addr32[2] &= mask.s6_addr32[2]; @@ -1172,17 +1498,38 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) ia = ifa2ia6(ifa); if (cmd == SIOCGLIFADDR) { +#ifndef SCOPEDROUTING + struct sockaddr_in6 *s6; +#endif + /* fill in the if_laddrreq structure */ bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); - +#ifndef SCOPEDROUTING /* XXX see above */ + s6 = (struct sockaddr_in6 *)&iflr->addr; + if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { + s6->sin6_addr.s6_addr16[1] = 0; + s6->sin6_scope_id = + in6_addr2scopeid(ifp, &s6->sin6_addr); + } +#endif if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { bcopy(&ia->ia_dstaddr, &iflr->dstaddr, ia->ia_dstaddr.sin6_len); +#ifndef SCOPEDROUTING /* XXX see above */ + s6 = (struct sockaddr_in6 *)&iflr->dstaddr; + if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { + s6->sin6_addr.s6_addr16[1] = 0; + s6->sin6_scope_id = + in6_addr2scopeid(ifp, + &s6->sin6_addr); + } +#endif } else bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); iflr->prefixlen = - in6_mask2len(&ia->ia_prefixmask.sin6_addr); + in6_mask2len(&ia->ia_prefixmask.sin6_addr, + NULL); iflr->flags = ia->ia6_flags; /*XXX*/ @@ -1218,96 +1565,73 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) } /* - * Delete any existing route for an interface. - */ -void -in6_ifscrub(ifp, ia) - register struct ifnet *ifp; - register struct in6_ifaddr *ia; -{ - if ((ia->ia_flags & IFA_ROUTE) == 0) - return; - if (ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); - else - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); - ia->ia_flags &= ~IFA_ROUTE; - - /* Remove ownaddr's loopback rtentry, if it exists. */ - in6_ifremloop(&(ia->ia_ifa)); -} - -/* * Initialize an interface's intetnet6 address * and routing table entry. */ -int -in6_ifinit(ifp, ia, sin6, scrub) +static int +in6_ifinit(ifp, ia, sin6, newhost) struct ifnet *ifp; struct in6_ifaddr *ia; struct sockaddr_in6 *sin6; - int scrub; + int newhost; { - struct sockaddr_in6 oldaddr; - int error, flags = RTF_UP; + int error = 0, plen, ifacount = 0; int s = splimp(); + struct ifaddr *ifa; - oldaddr = ia->ia_addr; - ia->ia_addr = *sin6; /* * Give the interface a chance to initialize * if this is its first address, * and to validate the address if necessary. */ - if (ifp->if_ioctl && - (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) + { + if (ifa->ifa_addr == NULL) + continue; /* just for safety */ + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ifacount++; + } + + ia->ia_addr = *sin6; + + if (ifacount <= 1 && ifp->if_ioctl && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { splx(s); - ia->ia_addr = oldaddr; return(error); } + splx(s); - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - break; - case IFT_PPP: - ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - break; - } + ia->ia_ifa.ifa_metric = ifp->if_metric; + + /* we could do in(6)_socktrim here, but just omit it at this moment. */ - splx(s); - if (scrub) { - ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; - in6_ifscrub(ifp, ia); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - } - /* xxx - * in_socktrim - */ /* - * Add route for the network. + * Special case: + * If the destination address is specified for a point-to-point + * interface, install a route to the destination as an interface + * direct route. */ - ia->ia_ifa.ifa_metric = ifp->if_metric; - if (ifp->if_flags & IFF_LOOPBACK) { - ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; - flags |= RTF_HOST; - } else if (ifp->if_flags & IFF_POINTOPOINT) { - if (ia->ia_dstaddr.sin6_family != AF_INET6) - return(0); - flags |= RTF_HOST; - } - if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) + plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ + if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { + if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, + RTF_UP | RTF_HOST)) != 0) + return(error); ia->ia_flags |= IFA_ROUTE; - /* XXX check if the subnet route points to the same interface */ - if (error == EEXIST) - error = 0; + } + if (plen < 128) { + /* + * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). + */ + ia->ia_ifa.ifa_flags |= RTF_CLONING; + } /* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */ - in6_ifaddloop(&(ia->ia_ifa)); + if (newhost) { + /* set the rtrequest function to create llinfo */ + ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; + in6_ifaddloop(&(ia->ia_ifa)); + } return(error); } @@ -1318,8 +1642,8 @@ in6_ifinit(ifp, ia, sin6, scrub) */ struct in6_multi * in6_addmulti(maddr6, ifp, errorp) - register struct in6_addr *maddr6; - register struct ifnet *ifp; + struct in6_addr *maddr6; + struct ifnet *ifp; int *errorp; { struct in6_multi *in6m; @@ -1408,7 +1732,7 @@ in6ifa_ifpforlinklocal(ifp, ignoreflags) struct ifnet *ifp; int ignoreflags; { - register struct ifaddr *ifa; + struct ifaddr *ifa; TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { @@ -1436,7 +1760,7 @@ in6ifa_ifpwithaddr(ifp, addr) struct ifnet *ifp; struct in6_addr *addr; { - register struct ifaddr *ifa; + struct ifaddr *ifa; TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { @@ -1458,13 +1782,13 @@ static char digits[] = "0123456789abcdef"; static int ip6round = 0; char * ip6_sprintf(addr) -register struct in6_addr *addr; + const struct in6_addr *addr; { static char ip6buf[8][48]; - register int i; - register char *cp; - register u_short *a = (u_short *)addr; - register u_char *d; + int i; + char *cp; + u_short *a = (u_short *)addr; + u_char *d; int dcolon = 0; ip6round = (ip6round + 1) & 7; @@ -1522,6 +1846,27 @@ in6_localaddr(in6) return (0); } +int +in6_is_addr_deprecated(sa6) + struct sockaddr_in6 *sa6; +{ + struct in6_ifaddr *ia; + + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, + &sa6->sin6_addr) && +#ifdef SCOPEDROUTING + ia->ia_addr.sin6_scope_id == sa6->sin6_scope_id && +#endif + (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) + return(1); /* true */ + + /* XXX: do we still have to go thru the rest of the list? */ + } + + return(0); /* false */ +} + /* * return length of part which dst and src are equal * hard coding... @@ -1602,8 +1947,8 @@ in6_prefixlen2mask(maskp, len) */ struct in6_ifaddr * in6_ifawithscope(oifp, dst) - register struct ifnet *oifp; - register struct in6_addr *dst; + struct ifnet *oifp; + struct in6_addr *dst; { int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0; int blen = -1; @@ -1612,7 +1957,9 @@ in6_ifawithscope(oifp, dst) struct in6_ifaddr *ifa_best = NULL; if (oifp == NULL) { +#if 0 printf("in6_ifawithscope: output interface is not specified\n"); +#endif return(NULL); } @@ -1675,13 +2022,20 @@ in6_ifawithscope(oifp, dst) * Also, if the current address has a smaller scope * than dst, ignore it unless ifa_best also has a * smaller scope. + * Consequently, after the two if-clause below, + * the followings must be satisfied: + * (scope(src) < scope(dst) && + * scope(best) < scope(dst)) + * OR + * (scope(best) >= scope(dst) && + * scope(src) >= scope(dst)) */ if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 && IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0) - goto replace; + goto replace; /* (A) */ if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 && IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0) - continue; + continue; /* (B) */ /* * A deprecated address SHOULD NOT be used in new @@ -1710,7 +2064,8 @@ in6_ifawithscope(oifp, dst) /* * A non-deprecated address is always preferred * to a deprecated one regardless of scopes and - * address matching. + * address matching (Note invariants ensured by the + * conditions (A) and (B) above.) */ if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) && (((struct in6_ifaddr *)ifa)->ia6_flags & @@ -1718,6 +2073,37 @@ in6_ifawithscope(oifp, dst) goto replace; /* + * When we use temporary addresses described in + * RFC 3041, we prefer temporary addresses to + * public autoconf addresses. Again, note the + * invariants from (A) and (B). Also note that we + * don't have any preference between static addresses + * and autoconf addresses (despite of whether or not + * the latter is temporary or public.) + */ + if (ip6_use_tempaddr) { + struct in6_ifaddr *ifat; + + ifat = (struct in6_ifaddr *)ifa; + if ((ifa_best->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == IN6_IFF_AUTOCONF && + (ifat->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) { + goto replace; + } + if ((ifa_best->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY) && + (ifat->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == IN6_IFF_AUTOCONF) { + continue; + } + } + + /* * At this point, we have two cases: * 1. we are looking at a non-deprecated address, * and ifa_best is also non-deprecated. @@ -1743,64 +2129,68 @@ in6_ifawithscope(oifp, dst) * Smaller scopes are the last resort. * - A deprecated address is chosen only when we have * no address that has an enough scope, but is - * prefered to any addresses of smaller scopes. - * - Longest address match against dst is considered - * only for addresses that has the same scope of dst. + * prefered to any addresses of smaller scopes + * (this must be already done above.) + * - addresses on the outgoing I/F are preferred to + * ones on other interfaces if none of above + * tiebreaks. In the table below, the column "bI" + * means if the best_ifa is on the outgoing + * interface, and the column "sI" means if the ifa + * is on the outgoing interface. * - If there is no other reasons to choose one, - * addresses on the outgoing I/F are preferred. + * longest address match against dst is considered. * * The precise decision table is as follows: - * dscopecmp bscopecmp matchcmp outI/F | replace? - * !equal equal N/A Yes | Yes (1) - * !equal equal N/A No | No (2) - * larger larger N/A N/A | No (3) - * larger smaller N/A N/A | Yes (4) - * smaller larger N/A N/A | Yes (5) - * smaller smaller N/A N/A | No (6) - * equal smaller N/A N/A | Yes (7) - * equal larger (already done) - * equal equal larger N/A | Yes (8) - * equal equal smaller N/A | No (9) - * equal equal equal Yes | Yes (a) - * eaual eqaul equal No | No (b) + * dscopecmp bscopecmp match bI oI | replace? + * N/A equal N/A Y N | No (1) + * N/A equal N/A N Y | Yes (2) + * N/A equal larger N/A | Yes (3) + * N/A equal !larger N/A | No (4) + * larger larger N/A N/A | No (5) + * larger smaller N/A N/A | Yes (6) + * smaller larger N/A N/A | Yes (7) + * smaller smaller N/A N/A | No (8) + * equal smaller N/A N/A | Yes (9) + * equal larger (already done at A above) */ dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope); bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope); - if (dscopecmp && bscopecmp == 0) { - if (oifp == ifp) /* (1) */ + if (bscopecmp == 0) { + struct ifnet *bifp = ifa_best->ia_ifp; + + if (bifp == oifp && ifp != oifp) /* (1) */ + continue; + if (bifp != oifp && ifp == oifp) /* (2) */ + goto replace; + + /* + * Both bifp and ifp are on the outgoing + * interface, or both two are on a different + * interface from the outgoing I/F. + * now we need address matching against dst + * for tiebreaking. + */ + tlen = in6_matchlen(IFA_IN6(ifa), dst); + matchcmp = tlen - blen; + if (matchcmp > 0) /* (3) */ goto replace; - continue; /* (2) */ + continue; /* (4) */ } if (dscopecmp > 0) { - if (bscopecmp > 0) /* (3) */ + if (bscopecmp > 0) /* (5) */ continue; - goto replace; /* (4) */ + goto replace; /* (6) */ } if (dscopecmp < 0) { - if (bscopecmp > 0) /* (5) */ + if (bscopecmp > 0) /* (7) */ goto replace; - continue; /* (6) */ + continue; /* (8) */ } /* now dscopecmp must be 0 */ if (bscopecmp < 0) - goto replace; /* (7) */ - - /* - * At last both dscopecmp and bscopecmp must be 0. - * We need address matching against dst for - * tiebreaking. - */ - tlen = in6_matchlen(IFA_IN6(ifa), dst); - matchcmp = tlen - blen; - if (matchcmp > 0) /* (8) */ - goto replace; - if (matchcmp < 0) /* (9) */ - continue; - if (oifp == ifp) /* (a) */ - goto replace; - continue; /* (b) */ + goto replace; /* (9) */ replace: ifa_best = (struct in6_ifaddr *)ifa; @@ -1837,8 +2227,8 @@ in6_ifawithscope(oifp, dst) */ struct in6_ifaddr * in6_ifawithifp(ifp, dst) - register struct ifnet *ifp; - register struct in6_addr *dst; + struct ifnet *ifp; + struct in6_addr *dst; { int dst_scope = in6_addrscope(dst), blen = -1, tlen; struct ifaddr *ifa; @@ -1943,6 +2333,43 @@ in6_if_up(ifp) } } +int +in6if_do_dad(ifp) + struct ifnet *ifp; +{ + if ((ifp->if_flags & IFF_LOOPBACK) != 0) + return(0); + + switch (ifp->if_type) { +#ifdef IFT_DUMMY + case IFT_DUMMY: +#endif + case IFT_FAITH: + /* + * These interfaces do not have the IFF_LOOPBACK flag, + * but loop packets back. We do not have to do DAD on such + * interfaces. We should even omit it, because loop-backed + * NS would confuse the DAD procedure. + */ + return(0); + default: + /* + * Our DAD routine requires the interface up and running. + * However, some interfaces can be up before the RUNNING + * status. Additionaly, users may try to assign addresses + * before the interface becomes up (or running). + * We simply skip DAD in such a case as a work around. + * XXX: we should rather mark "tentative" on such addresses, + * and do DAD after the interface becomes ready. + */ + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)) + return(0); + + return(1); + } +} + /* * Calculate max IPv6 MTU through all the interfaces and store it * to in6_maxmtu. diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 1159e52..168d1df 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6.h,v 1.48 2000/06/26 15:55:32 itojun Exp $ */ +/* $KAME: in6.h,v 1.89 2001/05/27 13:28:35 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -66,21 +66,19 @@ */ #ifndef __KAME_NETINET_IN_H_INCLUDED_ -#error "do not include netinet6/in6.h directly, include netinet/in.h" +#error "do not include netinet6/in6.h directly, include netinet/in.h. see RFC2553" #endif #ifndef _NETINET6_IN6_H_ #define _NETINET6_IN6_H_ -#ifndef _XOPEN_SOURCE -#include <sys/queue.h> -#endif - /* * Identification of the network protocol stack + * for *BSD-current/release: http://www.kame.net/dev/cvsweb.cgi/kame/COVERAGE + * has the table of implementation/integration differences. */ #define __KAME__ -#define __KAME_VERSION "20000701/FreeBSD-current" +#define __KAME_VERSION "20010528/FreeBSD" /* * Local port number conventions: @@ -148,7 +146,7 @@ struct sockaddr_in6 { u_int16_t sin6_port; /* Transport layer port # (in_port_t)*/ u_int32_t sin6_flowinfo; /* IP6 flow information */ struct in6_addr sin6_addr; /* IP6 address */ - u_int32_t sin6_scope_id; /* intface scope id */ + u_int32_t sin6_scope_id; /* scope zone index */ }; /* @@ -167,6 +165,8 @@ struct sockaddr_in6 { #endif #ifdef _KERNEL +extern const struct sockaddr_in6 sa6_any; + extern const struct in6_addr in6mask0; extern const struct in6_addr in6mask32; extern const struct in6_addr in6mask64; @@ -238,41 +238,49 @@ extern const struct in6_addr in6addr_linklocal_allrouters; (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0) #endif +#ifdef _KERNEL /* non standard */ +/* see if two addresses are equal in a scope-conscious manner. */ +#define SA6_ARE_ADDR_EQUAL(a, b) \ + (((a)->sin6_scope_id == 0 || (b)->sin6_scope_id == 0 || \ + ((a)->sin6_scope_id == (b)->sin6_scope_id)) && \ + (bcmp(&(a)->sin6_addr, &(b)->sin6_addr, sizeof(struct in6_addr)) == 0)) +#endif + /* * Unspecified */ #define IN6_IS_ADDR_UNSPECIFIED(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) == 0)) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == 0)) /* * Loopback */ #define IN6_IS_ADDR_LOOPBACK(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) == ntohl(1))) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(1))) /* * IPv4 compatible */ #define IN6_IS_ADDR_V4COMPAT(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) != 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) != ntohl(1))) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != ntohl(1))) /* * Mapped */ #define IN6_IS_ADDR_V4MAPPED(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) /* * KAME Scope Values @@ -350,13 +358,27 @@ extern const struct in6_addr in6addr_linklocal_allrouters; #endif /* - * KAME Scope + * Wildcard Socket */ +#if 0 /*pre-RFC2553*/ +#define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a) +#endif + #ifdef _KERNEL /*nonstandard*/ +/* + * KAME Scope + */ #define IN6_IS_SCOPE_LINKLOCAL(a) \ ((IN6_IS_ADDR_LINKLOCAL(a)) || \ (IN6_IS_ADDR_MC_LINKLOCAL(a))) -#endif + +#define IFA6_IS_DEPRECATED(a) \ + ((a)->ia6_lifetime.ia6t_preferred != 0 && \ + (a)->ia6_lifetime.ia6t_preferred < time_second) +#define IFA6_IS_INVALID(a) \ + ((a)->ia6_lifetime.ia6t_expire != 0 && \ + (a)->ia6_lifetime.ia6t_expire < time_second) +#endif /* _KERNEL */ /* * IP6 route structure @@ -389,26 +411,34 @@ struct route_in6 { #define IPV6_LEAVE_GROUP 13 /* ip6_mreq; leave a group membership */ #define IPV6_PORTRANGE 14 /* int; range to choose for unspec port */ #define ICMP6_FILTER 18 /* icmp6_filter; icmp6 filter */ -#define IPV6_PKTINFO 19 /* bool; send/rcv if, src/dst addr */ +/* RFC2292 options */ +#define IPV6_PKTINFO 19 /* bool; send/recv if, src/dst addr */ #define IPV6_HOPLIMIT 20 /* bool; hop limit */ #define IPV6_NEXTHOP 21 /* bool; next hop addr */ #define IPV6_HOPOPTS 22 /* bool; hop-by-hop option */ #define IPV6_DSTOPTS 23 /* bool; destination option */ #define IPV6_RTHDR 24 /* bool; routing header */ #define IPV6_PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */ + #define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */ -#define IPV6_BINDV6ONLY 27 /* bool; only bind INET6 at null bind */ +#define IPV6_V6ONLY 27 /* bool; only bind INET6 at wildcard bind */ +#ifndef _KERNEL +#define IPV6_BINDV6ONLY IPV6_V6ONLY +#endif -/* for IPsec */ +#if 1 /*IPSEC*/ #define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */ +#endif #define IPV6_FAITH 29 /* bool; accept FAITH'ed connections */ -/* for IPV6FIREWALL */ +#if 1 /*IPV6FIREWALL*/ #define IPV6_FW_ADD 30 /* add a firewall rule to chain */ #define IPV6_FW_DEL 31 /* delete a firewall rule from chain */ #define IPV6_FW_FLUSH 32 /* flush firewall rule chain */ #define IPV6_FW_ZERO 33 /* clear single/all firewall counter(s) */ #define IPV6_FW_GET 34 /* get entire firewall rule chain */ +#endif + /* to define items, should talk with KAME guys first, for *BSD compatibility */ #define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */ @@ -528,39 +558,44 @@ struct in6_pktinfo { #define IPV6CTL_KAME_VERSION 20 #define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */ #define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */ +#if 0 /*obsolete*/ #define IPV6CTL_MAPPED_ADDR 23 -#ifdef notdef /*__NetBSD__ - reserved, don't delete*/ -#define IPV6CTL_BINDV6ONLY 24 #endif +#define IPV6CTL_V6ONLY 24 #define IPV6CTL_RTEXPIRE 25 /* cloned route expiration time */ #define IPV6CTL_RTMINEXPIRE 26 /* min value for expiration time */ #define IPV6CTL_RTMAXCACHE 27 /* trigger level for dynamic expire */ + +#define IPV6CTL_USETEMPADDR 32 /* use temporary addresses (RFC3041) */ +#define IPV6CTL_TEMPPLTIME 33 /* preferred lifetime for tmpaddrs */ +#define IPV6CTL_TEMPVLTIME 34 /* valid lifetime for tmpaddrs */ +#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */ +#define IPV6CTL_RIP6STATS 36 /* raw_ip6 stats */ + /* New entries should be added here from current IPV6CTL_MAXID value. */ /* to define items, should talk with KAME guys first, for *BSD compatibility */ -#define IPV6CTL_MAXID 28 +#define IPV6CTL_MAXID 37 + #endif /* !_XOPEN_SOURCE */ /* * Redefinition of mbuf flags */ -#define M_ANYCAST6 M_PROTO1 -#define M_AUTHIPHDR M_PROTO2 -#define M_DECRYPTED M_PROTO3 -#define M_LOOP M_PROTO4 -#define M_AUTHIPDGM M_PROTO5 +#define M_AUTHIPHDR M_PROTO2 +#define M_DECRYPTED M_PROTO3 +#define M_LOOP M_PROTO4 +#define M_AUTHIPDGM M_PROTO5 #ifdef _KERNEL -struct cmsghdr; -struct mbuf; -struct ifnet; +struct cmsghdr; int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t)); int in6_localaddr __P((struct in6_addr *)); int in6_addrscope __P((struct in6_addr *)); struct in6_ifaddr *in6_ifawithscope __P((struct ifnet *, struct in6_addr *)); struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *)); -extern void in6_if_up __P((struct ifnet *)); -struct sockaddr; +extern void in6_if_up __P((struct ifnet *)); +struct sockaddr; void in6_sin6_2_sin __P((struct sockaddr_in *sin, struct sockaddr_in6 *sin6)); @@ -569,33 +604,51 @@ void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin, void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam)); void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam)); -#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) -#define sin6tosa(sin6) ((struct sockaddr *)(sin6)) -#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) +#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) +#define sin6tosa(sin6) ((struct sockaddr *)(sin6)) +#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) #endif /* _KERNEL */ __BEGIN_DECLS struct cmsghdr; -extern int inet6_option_space __P((int)); -extern int inet6_option_init __P((void *, struct cmsghdr **, int)); -extern int inet6_option_append __P((struct cmsghdr *, const u_int8_t *, - int, int)); -extern u_int8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int)); -extern int inet6_option_next __P((const struct cmsghdr *, u_int8_t **)); -extern int inet6_option_find __P((const struct cmsghdr *, u_int8_t **, - int)); - -extern size_t inet6_rthdr_space __P((int, int)); -extern struct cmsghdr *inet6_rthdr_init __P((void *, int)); -extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *, - u_int)); -extern int inet6_rthdr_lasthop __P((struct cmsghdr *, u_int)); -extern int inet6_rthdr_segments __P((const struct cmsghdr *)); -extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int)); -extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int)); -extern int inet6_rthdr_reverse __P((const struct cmsghdr *, - struct cmsghdr *)); +extern int inet6_option_space __P((int)); +extern int inet6_option_init __P((void *, struct cmsghdr **, int)); +extern int inet6_option_append __P((struct cmsghdr *, const u_int8_t *, + int, int)); +extern u_int8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int)); +extern int inet6_option_next __P((const struct cmsghdr *, u_int8_t **)); +extern int inet6_option_find __P((const struct cmsghdr *, u_int8_t **, int)); + +extern size_t inet6_rthdr_space __P((int, int)); +extern struct cmsghdr *inet6_rthdr_init __P((void *, int)); +extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *, + unsigned int)); +extern int inet6_rthdr_lasthop __P((struct cmsghdr *, unsigned int)); +#if 0 /* not implemented yet */ +extern int inet6_rthdr_reverse __P((const struct cmsghdr *, struct cmsghdr *)); +#endif +extern int inet6_rthdr_segments __P((const struct cmsghdr *)); +extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int)); +extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int)); + +extern int inet6_opt_init __P((void *, size_t)); +extern int inet6_opt_append __P((void *, size_t, int, u_int8_t, + size_t, u_int8_t, void **)); +extern int inet6_opt_finish __P((void *, size_t, int)); +extern int inet6_opt_set_val __P((void *, size_t, void *, int)); + +extern int inet6_opt_next __P((void *, size_t, int, u_int8_t *, + size_t *, void **)); +extern int inet6_opt_find __P((void *, size_t, int, u_int8_t, + size_t *, void **)); +extern int inet6_opt_get_val __P((void *, size_t, void *, int)); +extern size_t inet6_rth_space __P((int, int)); +extern void *inet6_rth_init __P((void *, int, int, int)); +extern int inet6_rth_add __P((void *, const struct in6_addr *)); +extern int inet6_rth_reverse __P((const void *, void *)); +extern int inet6_rth_segments __P((const void *)); +extern struct in6_addr *inet6_rth_getaddr __P((const void *, int)); __END_DECLS #endif /* !_NETINET6_IN6_H_ */ diff --git a/sys/netinet6/in6_cksum.c b/sys/netinet6/in6_cksum.c index db564cf..fbd95cb 100644 --- a/sys/netinet6/in6_cksum.c +++ b/sys/netinet6/in6_cksum.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_cksum.c,v 1.9 2000/09/09 15:33:31 itojun Exp $ */ +/* $KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -92,13 +92,13 @@ int in6_cksum(m, nxt, off, len) - register struct mbuf *m; + struct mbuf *m; u_int8_t nxt; u_int32_t off, len; { - register u_int16_t *w; - register int sum = 0; - register int mlen = 0; + u_int16_t *w; + int sum = 0; + int mlen = 0; int byte_swapped = 0; #if 0 int srcifid = 0, dstifid = 0; diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index c8c1450..57bec0e 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_gif.c,v 1.37 2000/06/17 20:34:25 itojun Exp $ */ +/* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -30,10 +30,6 @@ * SUCH DAMAGE. */ -/* - * in6_gif.c - */ - #include "opt_inet.h" #include "opt_inet6.h" @@ -43,6 +39,10 @@ #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/errno.h> +#include <sys/queue.h> +#include <sys/syslog.h> + +#include <sys/malloc.h> #include <net/if.h> #include <net/route.h> @@ -148,34 +148,19 @@ in6_gif_output(ifp, family, m, rt) ip6->ip6_nxt = proto; ip6->ip6_hlim = ip6_gif_hlim; ip6->ip6_src = sin6_src->sin6_addr; - if (ifp->if_flags & IFF_LINK0) { - /* multi-destination mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else if (rt) { - if (family != AF_INET6) { - m_freem(m); - return EINVAL; /*XXX*/ - } - ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; - } else { - m_freem(m); - return ENETUNREACH; - } - } else { - /* bidirectional configured tunnel mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else { - m_freem(m); - return ENETUNREACH; - } + /* bidirectional configured tunnel mode */ + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) + ip6->ip6_dst = sin6_dst->sin6_addr; + else { + m_freem(m); + return ENETUNREACH; } - if (ifp->if_flags & IFF_LINK1) { - otos = 0; + if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); - ip6->ip6_flow |= htonl((u_int32_t)otos << 20); - } + else + ip_ecn_ingress(ECN_NOCARE, &otos, &itos); + ip6->ip6_flow &= ~ntohl(0xff00000); + ip6->ip6_flow |= htonl((u_int32_t)otos << 20); if (dst->sin6_family != sin6_dst->sin6_family || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { @@ -262,6 +247,8 @@ int in6_gif_input(mp, offp, proto) ip = mtod(m, struct ip *); if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); + else + ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos); break; } #endif /* INET */ @@ -278,6 +265,8 @@ int in6_gif_input(mp, offp, proto) ip6 = mtod(m, struct ip6_hdr *); if (gifp->if_flags & IFF_LINK1) ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow); + else + ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow); break; } #endif @@ -321,17 +310,14 @@ gif_encapcheck6(m, off, proto, arg) addrmatch |= 1; if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src)) addrmatch |= 2; - else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 && - IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) { - addrmatch |= 2; /* we accept any source */ - } if (addrmatch != 3) return 0; /* martian filters on outer source - done in ip6_input */ /* ingress filters on outer source */ - if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && + (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { struct sockaddr_in6 sin6; struct rtentry *rt; @@ -341,15 +327,18 @@ gif_encapcheck6(m, off, proto, arg) sin6.sin6_addr = ip6.ip6_src; /* XXX scopeid */ rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); - if (!rt) - return 0; - if (rt->rt_ifp != m->m_pkthdr.rcvif) { - rtfree(rt); + if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { +#if 0 + log(LOG_WARNING, "%s: packet from %s dropped " + "due to ingress filter\n", if_name(&sc->gif_if), + ip6_sprintf(&sin6.sin6_addr)); +#endif + if (rt) + rtfree(rt); return 0; } rtfree(rt); } - /* prioritize: IFF_LINK0 mode is less preferred */ - return (sc->gif_if.if_flags & IFF_LINK0) ? 128 : 128 * 2; + return 128 * 2; } diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index c839d01..516826d 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_ifattach.c,v 1.67 2000/10/01 10:51:54 itojun Exp $ */ +/* $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -36,6 +36,7 @@ #include <sys/socket.h> #include <sys/sockio.h> #include <sys/kernel.h> +#include <sys/syslog.h> #include <sys/md5.h> #include <net/if.h> @@ -49,6 +50,7 @@ #include <netinet/ip6.h> #include <netinet6/ip6_var.h> +#include <netinet6/in6_var.h> #include <netinet6/in6_ifattach.h> #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> @@ -62,13 +64,20 @@ size_t in6_ifstatmax = 0; size_t icmp6_ifstatmax = 0; unsigned long in6_maxmtu = 0; +#ifdef IP6_AUTO_LINKLOCAL +int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; +#else +int ip6_auto_linklocal = 1; /* enable by default */ +#endif + +struct callout in6_tmpaddrtimer_ch; + static int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); +static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *)); static int get_hw_ifid __P((struct ifnet *, struct in6_addr *)); static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *)); -static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *)); static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *)); static int in6_ifattach_loopback __P((struct ifnet *)); -static int nigroup __P((struct ifnet *, const char *, int, struct in6_addr *)); #define EUI64_GBIT 0x01 #define EUI64_UBIT 0x02 @@ -122,6 +131,90 @@ get_rand_ifid(ifp, in6) return 0; } +static int +generate_tmp_ifid(seed0, seed1, ret) + u_int8_t *seed0, *ret; + const u_int8_t *seed1; +{ + MD5_CTX ctxt; + u_int8_t seed[16], digest[16], nullbuf[8]; + u_int32_t val32; + struct timeval tv; + + /* If there's no hisotry, start with a random seed. */ + bzero(nullbuf, sizeof(nullbuf)); + if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { + int i; + + for (i = 0; i < 2; i++) { + microtime(&tv); + val32 = random() ^ tv.tv_usec; + bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); + } + } else + bcopy(seed0, seed, 8); + + /* copy the right-most 64-bits of the given address */ + /* XXX assumption on the size of IFID */ + bcopy(seed1, &seed[8], 8); + + if (0) { /* for debugging purposes only */ + int i; + + printf("generate_tmp_ifid: new randomized ID from: "); + for (i = 0; i < 16; i++) + printf("%02x", seed[i]); + printf(" "); + } + + /* generate 16 bytes of pseudo-random value. */ + bzero(&ctxt, sizeof(ctxt)); + MD5Init(&ctxt); + MD5Update(&ctxt, seed, sizeof(seed)); + MD5Final(digest, &ctxt); + + /* + * RFC 3041 3.2.1. (3) + * Take the left-most 64-bits of the MD5 digest and set bit 6 (the + * left-most bit is numbered 0) to zero. + */ + bcopy(digest, ret, 8); + ret[0] &= ~EUI64_UBIT; + + /* + * XXX: we'd like to ensure that the generated value is not zero + * for simplicity. If the caclculated digest happens to be zero, + * use a random non-zero value as the last resort. + */ + if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { + log(LOG_INFO, + "generate_tmp_ifid: computed MD5 value is zero.\n"); + + microtime(&tv); + val32 = random() ^ tv.tv_usec; + val32 = 1 + (val32 % (0xffffffff - 1)); + } + + /* + * RFC 3041 3.2.1. (4) + * Take the rightmost 64-bits of the MD5 digest and save them in + * stable storage as the history value to be used in the next + * iteration of the algorithm. + */ + bcopy(&digest[8], seed0, 8); + + if (0) { /* for debugging purposes only */ + int i; + + printf("to: "); + for (i = 0; i < 16; i++) + printf("%02x", digest[i]); + printf("\n"); + } + + return 0; +} + /* * Get interface identifier for the specified interface. * XXX assumes single sockaddr_dl (AF_LINK address) per an interface @@ -165,7 +258,14 @@ found: case IFT_ETHER: case IFT_FDDI: case IFT_ATM: + case IFT_IEEE1394: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif /* IEEE802/EUI64 cases - what others? */ + /* IEEE1394 uses 16byte length address starting with EUI64 */ + if (addrlen > 8) + addrlen = 8; /* look at IEEE802/EUI64 only */ if (addrlen != 8 && addrlen != 6) @@ -217,7 +317,7 @@ found: case IFT_STF: #endif /* - * mech-06 says: "SHOULD use IPv4 address as ifid source". + * RFC2893 says: "SHOULD use IPv4 address as ifid source". * however, IPv4 address is not very suitable as unique * identifier source (can be renumbered). * we don't do this. @@ -262,19 +362,15 @@ get_ifid(ifp0, altifp, in6) /* first, try to get it from the interface itself */ if (get_hw_ifid(ifp0, in6) == 0) { -#ifdef ND6_DEBUG - printf("%s: got interface identifier from itself\n", - if_name(ifp0)); -#endif + nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", + if_name(ifp0))); goto success; } /* try secondary EUI64 source. this basically is for ATM PVC */ if (altifp && get_hw_ifid(altifp, in6) == 0) { -#ifdef ND6_DEBUG - printf("%s: got interface identifier from %s\n", - if_name(ifp0), if_name(altifp)); -#endif + nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", + if_name(ifp0), if_name(altifp))); goto success; } @@ -291,21 +387,18 @@ get_ifid(ifp0, altifp, in6) * globally unique */ if (IFID_UNIVERSAL(in6)) { - -#ifdef ND6_DEBUG - printf("%s: borrow interface identifier from %s\n", - if_name(ifp0), if_name(ifp)); -#endif + nd6log((LOG_DEBUG, + "%s: borrow interface identifier from %s\n", + if_name(ifp0), if_name(ifp))); goto success; } } /* last resort: get from random number source */ if (get_rand_ifid(ifp, in6) == 0) { -#ifdef ND6_DEBUG - printf("%s: interface identifier generated by random number\n", - if_name(ifp0)); -#endif + nd6log((LOG_DEBUG, + "%s: interface identifier generated by random number\n", + if_name(ifp0))); goto success; } @@ -313,223 +406,152 @@ get_ifid(ifp0, altifp, in6) return -1; success: -#ifdef ND6_DEBUG - printf("%s: ifid: " + nd6log((LOG_INFO, "%s: ifid: " "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], - in6->s6_addr[14], in6->s6_addr[15]); -#endif + in6->s6_addr[14], in6->s6_addr[15])); return 0; } -/* - * configure IPv6 interface address. XXX code duplicated with in.c - */ static int -in6_ifattach_addaddr(ifp, ia) +in6_ifattach_linklocal(ifp, altifp) struct ifnet *ifp; - struct in6_ifaddr *ia; + struct ifnet *altifp; /* secondary EUI64 source */ { - struct in6_ifaddr *oia; - struct ifaddr *ifa; - int error; - int rtflag; - struct in6_addr llsol; - - /* - * initialize if_addrlist, if we are the very first one - */ - ifa = TAILQ_FIRST(&ifp->if_addrlist); - if (ifa == NULL) { - TAILQ_INIT(&ifp->if_addrlist); - } + struct in6_ifaddr *ia; + struct in6_aliasreq ifra; + struct nd_prefix pr0; + int i, error; /* - * link the interface address to global list + * configure link-local address. */ - TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); - /* gain a refcnt for the link from if_addrlist */ - ia->ia_ifa.ifa_refcnt++; + bzero(&ifra, sizeof(ifra)); /* - * Also link into the IPv6 address chain beginning with in6_ifaddr. - * kazu opposed it, but itojun & jinmei wanted. + * in6_update_ifa() does not use ifra_name, but we accurately set it + * for safety. */ - if ((oia = in6_ifaddr) != NULL) { - for (; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - /* gain another refcnt for the link from in6_ifaddr */ - ia->ia_ifa.ifa_refcnt++; + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - /* - * give the interface a chance to initialize, in case this - * is the first address to be added. - */ - if (ifp->if_ioctl != NULL) { - int s; - s = splimp(); - error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); - splx(s); - } else - error = 0; - if (error) { - switch (error) { - case EAFNOSUPPORT: - printf("%s: IPv6 not supported\n", if_name(ifp)); - break; - default: - printf("%s: SIOCSIFADDR error %d\n", if_name(ifp), - error); - break; + ifra.ifra_addr.sin6_family = AF_INET6; + ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); +#ifdef SCOPEDROUTING + ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0 +#else + ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */ +#endif + ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; + ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); + } else { + if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { + nd6log((LOG_ERR, + "%s: no ifid available\n", if_name(ifp))); + return -1; } - - /* undo changes */ - TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); - IFAFREE(&ia->ia_ifa); - if (oia) - oia->ia_next = ia->ia_next; - else - in6_ifaddr = ia->ia_next; - IFAFREE(&ia->ia_ifa); - return -1; } +#ifdef SCOPEDROUTING + ifra.ifra_addr.sin6_scope_id = + in6_addr2scopeid(ifp, &ifra.ifra_addr.sin6_addr); +#endif - /* configure link-layer address resolution */ - rtflag = 0; - if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128)) - rtflag = RTF_HOST; - else { - switch (ifp->if_type) { - case IFT_LOOP: -#ifdef IFT_STF - case IFT_STF: + ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_prefixmask.sin6_family = AF_INET6; + ifra.ifra_prefixmask.sin6_addr = in6mask64; +#ifdef SCOPEDROUTING + /* take into accound the sin6_scope_id field for routing */ + ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff; #endif - rtflag = 0; - break; - default: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - rtflag = RTF_CLONING; - break; - } - } + /* link-local addresses should NEVER expire. */ + ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; - /* add route to the interface. */ - { - int e; - - e = rtrequest(RTM_ADD, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&ia->ia_prefixmask, - RTF_UP | rtflag, - (struct rtentry **)0); - if (e) { - printf("in6_ifattach_addaddr: rtrequest failed. errno = %d\n", e); - } - } - ia->ia_flags |= IFA_ROUTE; + /* + * Do not let in6_update_ifa() do DAD, since we need a random delay + * before sending an NS at the first time the inteface becomes up. + * Instead, in6_if_up() will start DAD with a proper random delay. + */ + ifra.ifra_flags |= IN6_IFF_NODAD; - if ((rtflag & RTF_CLONING) != 0 && - (ifp->if_flags & IFF_MULTICAST) != 0) { + /* + * Now call in6_update_ifa() to do a bunch of procedures to configure + * a link-local address. We can set NULL to the 3rd argument, because + * we know there's no other link-local address on the interface. + */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { /* - * join solicited multicast address + * XXX: When the interface does not support IPv6, this call + * would fail in the SIOCSIFADDR ioctl. I believe the + * notification is rather confusing in this case, so just + * supress it. (jinmei@kame.net 20010130) */ - bzero(&llsol, sizeof(llsol)); - llsol.s6_addr16[0] = htons(0xff02); - llsol.s6_addr16[1] = htons(ifp->if_index); - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; - llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error); - - /* XXX should we run DAD on other interface types? */ - switch (ifp->if_type) { -#if 1 - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: -#else - default: -#endif - /* mark the address TENTATIVE, if needed. */ - ia->ia6_flags |= IN6_IFF_TENTATIVE; - /* nd6_dad_start() will be called in in6_if_up */ - } + if (error != EAFNOSUPPORT) + log(LOG_NOTICE, "in6_ifattach_linklocal: failed to " + "configure a link-local address on %s " + "(errno=%d)\n", + if_name(ifp), error); + return(-1); } - return 0; -} - -static int -in6_ifattach_linklocal(ifp, altifp) - struct ifnet *ifp; - struct ifnet *altifp; /*secondary EUI64 source*/ -{ - struct in6_ifaddr *ia; - /* - * configure link-local address + * Adjust ia6_flags so that in6_if_up will perform DAD. + * XXX: Some P2P interfaces seem not to send packets just after + * becoming up, so we skip p2p interfaces for safety. */ - ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK); - bzero((caddr_t)ia, sizeof(*ia)); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - if (ifp->if_flags & IFF_POINTOPOINT) - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; - else - ia->ia_ifa.ifa_dstaddr = NULL; - ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; - ia->ia_ifp = ifp; - - bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); - ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_prefixmask.sin6_family = AF_INET6; -#ifdef SCOPEDROUTING - /* take into accound the sin6_scope_id field for routing */ - ia->ia_prefixmask.sin6_scope_id = 0xffffffff; -#endif - ia->ia_prefixmask.sin6_addr = in6mask64; - - /* just in case */ - bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); - ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_dstaddr.sin6_family = AF_INET6; - - bzero(&ia->ia_addr, sizeof(ia->ia_addr)); - ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_addr.sin6_family = AF_INET6; - ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); - ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); - ia->ia_addr.sin6_addr.s6_addr32[1] = 0; - if (ifp->if_flags & IFF_LOOPBACK) { - ia->ia_addr.sin6_addr.s6_addr32[2] = 0; - ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1); - } else { - if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) { -#ifdef ND6_DEBUG - printf("%s: no ifid available\n", if_name(ifp)); -#endif - free(ia, M_IFADDR); - return -1; - } + ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ +#ifdef DIAGNOSTIC + if (!ia) { + panic("ia == NULL in in6_ifattach_linklocal"); + /*NOTREACHED*/ } -#ifdef SCOPEDROUTING - ia->ia_addr.sin6_scope_id = in6_addr2scopeid(ifp, - &ia->ia_addr.sin6_addr); #endif + if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) { + ia->ia6_flags &= ~IN6_IFF_NODAD; + ia->ia6_flags |= IN6_IFF_TENTATIVE; + } - ia->ia_ifa.ifa_metric = ifp->if_metric; - - if (in6_ifattach_addaddr(ifp, ia) != 0) { - /* ia will be freed on failure */ - return -1; + /* + * Make the link-local prefix (fe80::/64%link) as on-link. + * Since we'd like to manage prefixes separately from addresses, + * we make an ND6 prefix structure for the link-local prefix, + * and add it to the prefix list as a never-expire prefix. + * XXX: this change might affect some existing code base... + */ + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_ifp = ifp; + /* this should be 64 at this moment. */ + pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); + pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr; + pr0.ndpr_prefix = ifra.ifra_addr; + /* apply the mask for safety. (nd6_prelist_add will apply it again) */ + for (i = 0; i < 4; i++) { + pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= + in6mask64.s6_addr32[i]; + } + /* + * Initialize parameters. The link-local prefix must always be + * on-link, and its lifetimes never expire. + */ + pr0.ndpr_raf_onlink = 1; + pr0.ndpr_raf_auto = 1; /* probably meaningless */ + pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; + pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; + /* + * Since there is no other link-local addresses, nd6_prefix_lookup() + * probably returns NULL. However, we cannot always expect the result. + * For example, if we first remove the (only) existing link-local + * address, and then reconfigure another one, the prefix is still + * valid with referring to the old link-local address. + */ + if (nd6_prefix_lookup(&pr0) == NULL) { + if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) + return(error); } return 0; @@ -539,47 +561,52 @@ static int in6_ifattach_loopback(ifp) struct ifnet *ifp; /* must be IFT_LOOP */ { - struct in6_ifaddr *ia; + struct in6_aliasreq ifra; + int error; + + bzero(&ifra, sizeof(ifra)); /* - * configure link-local address + * in6_update_ifa() does not use ifra_name, but we accurately set it + * for safety. */ - ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK); - bzero((caddr_t)ia, sizeof(*ia)); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; - ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; - ia->ia_ifp = ifp; - - bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); - ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_prefixmask.sin6_family = AF_INET6; - ia->ia_prefixmask.sin6_addr = in6mask128; + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + + ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_prefixmask.sin6_family = AF_INET6; + ifra.ifra_prefixmask.sin6_addr = in6mask128; /* * Always initialize ia_dstaddr (= broadcast address) to loopback - * address, to make getifaddr happier. - * - * For BSDI, it is mandatory. The BSDI version of - * ifa_ifwithroute() rejects to add a route to the loopback - * interface. Even for other systems, loopback looks somewhat - * special. + * address. Follows IPv4 practice - see in_ifinit(). */ - bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); - ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_dstaddr.sin6_family = AF_INET6; - ia->ia_dstaddr.sin6_addr = in6addr_loopback; + ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_dstaddr.sin6_family = AF_INET6; + ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; - bzero(&ia->ia_addr, sizeof(ia->ia_addr)); - ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_addr.sin6_family = AF_INET6; - ia->ia_addr.sin6_addr = in6addr_loopback; + ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_addr.sin6_family = AF_INET6; + ifra.ifra_addr.sin6_addr = in6addr_loopback; - ia->ia_ifa.ifa_metric = ifp->if_metric; + /* the loopback address should NEVER expire. */ + ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; - if (in6_ifattach_addaddr(ifp, ia) != 0) { - /* ia will be freed on failure */ - return -1; + /* we don't need to perfrom DAD on loopback interfaces. */ + ifra.ifra_flags |= IN6_IFF_NODAD; + + /* skip registration to the prefix list. XXX should be temporary. */ + ifra.ifra_flags |= IN6_IFF_NOPFX; + + /* + * We can set NULL to the 3rd arg. See comments in + * in6_ifattach_linklocal(). + */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + log(LOG_ERR, "in6_ifattach_loopback: failed to configure " + "the loopback address on %s (errno=%d)\n", + if_name(ifp), error); + return(-1); } return 0; @@ -591,17 +618,19 @@ in6_ifattach_loopback(ifp) * * when ifp == NULL, the caller is responsible for filling scopeid. */ -static int -nigroup(ifp, name, namelen, in6) +int +in6_nigroup(ifp, name, namelen, in6) struct ifnet *ifp; const char *name; int namelen; struct in6_addr *in6; { const char *p; + u_char *q; MD5_CTX ctxt; u_int8_t digest[16]; char l; + char n[64]; /* a single label must not exceed 63 chars */ if (!namelen || !name) return -1; @@ -609,16 +638,21 @@ nigroup(ifp, name, namelen, in6) p = name; while (p && *p && *p != '.' && p - name < namelen) p++; - if (p - name > 63) + if (p - name > sizeof(n) - 1) return -1; /*label too long*/ l = p - name; + strncpy(n, name, l); + n[(int)l] = '\0'; + for (q = n; *q; q++) { + if ('A' <= *q && *q <= 'Z') + *q = *q - 'A' + 'a'; + } /* generate 8 bytes of pseudo-random value. */ bzero(&ctxt, sizeof(ctxt)); MD5Init(&ctxt); MD5Update(&ctxt, &l, sizeof(l)); - /* LINTED const cast */ - MD5Update(&ctxt, (void *)name, p - name); + MD5Update(&ctxt, n, l); MD5Final(digest, &ctxt); bzero(in6, sizeof(*in6)); @@ -644,15 +678,21 @@ in6_nigroup_attach(name, namelen) bzero(&mltaddr, sizeof(mltaddr)); mltaddr.sin6_family = AF_INET6; mltaddr.sin6_len = sizeof(struct sockaddr_in6); - if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) + if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) return; for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); - if (!in6m) - (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); + if (!in6m) { + if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) { + nd6log((LOG_ERR, "%s: failed to join %s " + "(errno=%d)\n", if_name(ifp), + ip6_sprintf(&mltaddr.sin6_addr), + error)); + } + } } } @@ -668,7 +708,7 @@ in6_nigroup_detach(name, namelen) bzero(&mltaddr, sizeof(mltaddr)); mltaddr.sin6_family = AF_INET6; mltaddr.sin6_len = sizeof(struct sockaddr_in6); - if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) + if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) return; for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) @@ -691,13 +731,16 @@ in6_ifattach(ifp, altifp) struct ifnet *altifp; /* secondary EUI64 source */ { static size_t if_indexlim = 8; - struct sockaddr_in6 mltaddr; - struct sockaddr_in6 mltmask; - struct sockaddr_in6 gate; - struct sockaddr_in6 mask; struct in6_ifaddr *ia; struct in6_addr in6; - int hostnamelen = strlen(hostname); + + /* some of the interfaces are inherently not IPv6 capable */ + switch (ifp->if_type) { +#ifdef IFT_BRIDGE /*OpenBSD 2.8*/ + case IFT_BRIDGE: + return; +#endif + } /* * We have some arrays that should be indexed by if_index. @@ -763,134 +806,41 @@ in6_ifattach(ifp, altifp) * usually, we require multicast capability to the interface */ if ((ifp->if_flags & IFF_MULTICAST) == 0) { - printf("%s: not multicast capable, IPv6 not enabled\n", + log(LOG_INFO, "in6_ifattach: " + "%s is not multicast capable, IPv6 not enabled\n", if_name(ifp)); return; } /* - * assign link-local address, if there's none - */ - ia = in6ifa_ifpforlinklocal(ifp, 0); - if (ia == NULL) { - if (in6_ifattach_linklocal(ifp, altifp) != 0) - return; - ia = in6ifa_ifpforlinklocal(ifp, 0); - - if (ia == NULL) { - printf("%s: failed to add link-local address\n", - if_name(ifp)); - - /* we can't initialize multicasts without link-local */ - goto statinit; - } - } - - if (ifp->if_flags & IFF_POINTOPOINT) { - /* - * route local address to loopback - */ - bzero(&gate, sizeof(gate)); - gate.sin6_len = sizeof(struct sockaddr_in6); - gate.sin6_family = AF_INET6; - gate.sin6_addr = in6addr_loopback; - bzero(&mask, sizeof(mask)); - mask.sin6_len = sizeof(struct sockaddr_in6); - mask.sin6_family = AF_INET6; - mask.sin6_addr = in6mask64; - rtrequest(RTM_ADD, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&gate, - (struct sockaddr *)&mask, - RTF_UP|RTF_HOST, - (struct rtentry **)0); - } - - /* - * assign loopback address for loopback interface - * XXX multiple loopback interface case + * assign loopback address for loopback interface. + * XXX multiple loopback interface case. */ - in6 = in6addr_loopback; - if (ifp->if_flags & IFF_LOOPBACK) { + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + in6 = in6addr_loopback; if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { if (in6_ifattach_loopback(ifp) != 0) return; } } -#ifdef DIAGNOSTIC - if (!ia) { - panic("ia == NULL in in6_ifattach"); - /*NOTREACHED*/ - } -#endif - /* - * join multicast + * assign a link-local address, if there's none. */ - if (ifp->if_flags & IFF_MULTICAST) { - int error; /* not used */ - struct in6_multi *in6m; - - bzero(&mltmask, sizeof(mltmask)); - mltmask.sin6_len = sizeof(struct sockaddr_in6); - mltmask.sin6_family = AF_INET6; - mltmask.sin6_addr = in6mask32; - - /* - * join link-local all-nodes address - */ - bzero(&mltaddr, sizeof(mltaddr)); - mltaddr.sin6_len = sizeof(struct sockaddr_in6); - mltaddr.sin6_family = AF_INET6; - mltaddr.sin6_addr = in6addr_linklocal_allnodes; - mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); - - IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); - if (in6m == NULL) { - rtrequest(RTM_ADD, - (struct sockaddr *)&mltaddr, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&mltmask, - RTF_UP|RTF_CLONING, /* xxx */ - (struct rtentry **)0); - (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); - } - - /* - * join node information group address - */ - if (nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) - == 0) { - IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); - if (in6m == NULL && ia != NULL) { - (void)in6_addmulti(&mltaddr.sin6_addr, - ifp, &error); - } - } - - if (ifp->if_flags & IFF_LOOPBACK) { - in6 = in6addr_loopback; - ia = in6ifa_ifpwithaddr(ifp, &in6); - /* - * join node-local all-nodes address, on loopback - */ - mltaddr.sin6_addr = in6addr_nodelocal_allnodes; - - IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); - if (in6m == NULL && ia != NULL) { - rtrequest(RTM_ADD, - (struct sockaddr *)&mltaddr, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&mltmask, - RTF_UP, - (struct rtentry **)0); - (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); + if (ip6_auto_linklocal) { + ia = in6ifa_ifpforlinklocal(ifp, 0); + if (ia == NULL) { + if (in6_ifattach_linklocal(ifp, altifp) == 0) { + /* linklocal address assigned */ + } else { + /* failed to assign linklocal address. bark? */ } } } -statinit:; +#ifdef IFT_STF /* XXX */ +statinit: +#endif /* update dynamically. */ if (in6_maxmtu < ifp->if_mtu) @@ -913,6 +863,8 @@ statinit:; /* * NOTE: in6_ifdetach() does not support loopback if at this moment. + * We don't need this function in bsdi, because interfaces are never removed + * from the ifnet list in bsdi. */ void in6_ifdetach(ifp) @@ -938,7 +890,7 @@ in6_ifdetach(ifp) next = ifa->ifa_list.tqe_next; if (ifa->ifa_addr->sa_family != AF_INET6) continue; - in6_purgeaddr(ifa, ifp); + in6_purgeaddr(ifa); } /* undo everything done by in6_ifattach(), just in case */ @@ -979,11 +931,11 @@ in6_ifdetach(ifp) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; -#ifdef ND6_DEBUG - else - printf("%s: didn't unlink in6ifaddr from " - "list\n", if_name(ifp)); -#endif + else { + nd6log((LOG_ERR, + "%s: didn't unlink in6ifaddr from " + "list\n", if_name(ifp))); + } } IFAFREE(&oia->ia_ifa); @@ -998,7 +950,14 @@ in6_ifdetach(ifp) in6m = NULL; } - /* remove neighbor management table */ + /* + * remove neighbor management table. we call it twice just to make + * sure we nuke everything. maybe we need just one call. + * XXX: since the first call did not release addresses, some prefixes + * might remain. We should call nd6_purge() again to release the + * prefixes after removing all addresses above. + * (Or can we just delay calling nd6_purge until at this point?) + */ nd6_purge(ifp); /* remove route to link-local allnodes multicast (ff02::1) */ @@ -1014,3 +973,60 @@ in6_ifdetach(ifp) rtfree(rt); } } + +void +in6_get_tmpifid(ifp, retbuf, baseid, generate) + struct ifnet *ifp; + u_int8_t *retbuf; + const u_int8_t *baseid; + int generate; +{ + u_int8_t nullbuf[8]; + struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; + + bzero(nullbuf, sizeof(nullbuf)); + if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { + /* we've never created a random ID. Create a new one. */ + generate = 1; + } + + if (generate) { + bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); + + /* generate_tmp_ifid will update seedn and buf */ + (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, + ndi->randomid); + } + bcopy(ndi->randomid, retbuf, 8); +} + +void +in6_tmpaddrtimer(ignored_arg) + void *ignored_arg; +{ + int i; + struct nd_ifinfo *ndi; + u_int8_t nullbuf[8]; + int s = splnet(); + + callout_reset(&in6_tmpaddrtimer_ch, + (ip6_temp_preferred_lifetime - ip6_desync_factor - + ip6_temp_regen_advance) * hz, + in6_tmpaddrtimer, NULL); + + bzero(nullbuf, sizeof(nullbuf)); + for (i = 1; i < if_index + 1; i++) { + ndi = &nd_ifinfo[i]; + if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { + /* + * We've been generating a random ID on this interface. + * Create a new one. + */ + (void)generate_tmp_ifid(ndi->randomseed0, + ndi->randomseed1, + ndi->randomid); + } + } + + splx(s); +} diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h index 4f82e41..fa4434f 100644 --- a/sys/netinet6/in6_ifattach.h +++ b/sys/netinet6/in6_ifattach.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_ifattach.h,v 1.10 2000/05/27 02:57:05 itojun Exp $ */ +/* $KAME: in6_ifattach.h,v 1.14 2001/02/08 12:48:39 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -38,6 +38,9 @@ void in6_nigroup_attach __P((const char *, int)); void in6_nigroup_detach __P((const char *, int)); void in6_ifattach __P((struct ifnet *, struct ifnet *)); void in6_ifdetach __P((struct ifnet *)); +void in6_get_tmpifid __P((struct ifnet *, u_int8_t *, const u_int8_t *, int)); +void in6_tmpaddrtimer __P((void *)); +int in6_nigroup __P((struct ifnet *, const char *, int, struct in6_addr *)); #endif /* _KERNEL */ #endif /* _NETINET6_IN6_IFATTACH_H_ */ diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 67409be..9175a65 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_pcb.c,v 1.8 2000/06/09 00:37:02 itojun Exp $ */ +/* $KAME: in6_pcb.c,v 1.31 2001/05/21 05:45:10 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -66,6 +66,8 @@ * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 */ +#include "opt_inet.h" +#include "opt_inet6.h" #include "opt_ipsec.h" #include <sys/param.h> @@ -99,12 +101,19 @@ #include <netinet6/in6_pcb.h> #include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include <net/if_faith.h> +#endif #ifdef IPSEC #include <netinet6/ipsec.h> -#include <netinet6/ah.h> +#ifdef INET6 #include <netinet6/ipsec6.h> +#endif +#include <netinet6/ah.h> +#ifdef INET6 #include <netinet6/ah6.h> +#endif #include <netkey/key.h> #endif /* IPSEC */ @@ -165,11 +174,12 @@ in6_pcbbind(inp, nam, p) /* * XXX: bind to an anycast address might accidentally * cause sending a packet with anycast source address. + * We should allow to bind to a deprecated address, since + * the application dare to use it. */ if (ia && ((struct in6_ifaddr *)ia)->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| - IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { + (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) { return(EADDRNOTAVAIL); } } @@ -193,7 +203,7 @@ in6_pcbbind(inp, nam, p) (so->so_cred->cr_uid != t->inp_socket->so_cred->cr_uid)) return (EADDRINUSE); - if (ip6_mapped_addr_on != 0 && + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct sockaddr_in sin; @@ -215,7 +225,7 @@ in6_pcbbind(inp, nam, p) lport, wild); if (t && (reuseport & t->inp_socket->so_options) == 0) return(EADDRINUSE); - if (ip6_mapped_addr_on != 0 && + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct sockaddr_in sin; @@ -247,7 +257,6 @@ in6_pcbbind(inp, nam, p) return (EAGAIN); } } - inp->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/ return(0); } @@ -270,7 +279,6 @@ in6_pcbladdr(inp, nam, plocal_addr6) struct in6_addr **plocal_addr6; { register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; - struct in6_pktinfo *pi; struct ifnet *ifp = NULL; int error = 0; @@ -361,15 +369,11 @@ in6_pcbconnect(inp, nam, p) } inp->in6p_faddr = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; - /* - * xxx kazu flowlabel is necessary for connect? - * but if this line is missing, the garbage value remains. - */ - inp->in6p_flowinfo = sin6->sin6_flowinfo; - if ((inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) == 0 && - ip6_auto_flowlabel != 0) + /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ + inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; + if (inp->in6p_flags & IN6P_AUTOFLOWLABEL) inp->in6p_flowinfo |= - (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); + (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); in_pcbrehash(inp); return (0); @@ -521,11 +525,14 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) } if (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0) { + struct sockaddr_in6 *dst6; + /* No route yet, so try to acquire one */ bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); - ro->ro_dst.sin6_family = AF_INET6; - ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro->ro_dst.sin6_addr = *dst; + dst6 = (struct sockaddr_in6 *)&ro->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_addr = *dst; if (IN6_IS_ADDR_MULTICAST(dst)) { ro->ro_rt = rtalloc1(&((struct route *)ro) ->ro_dst, 0, 0UL); @@ -584,6 +591,8 @@ in6_pcbdisconnect(inp) { bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr)); inp->inp_fport = 0; + /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ + inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; in_pcbrehash(inp); if (inp->inp_socket->so_state & SS_NOFDREF) in6_pcbdetach(inp); @@ -604,20 +613,13 @@ in6_pcbdetach(inp) in_pcbremlists(inp); sotoinpcb(so) = 0; sofree(so); + if (inp->in6p_options) m_freem(inp->in6p_options); - if (inp->in6p_outputopts) { - if (inp->in6p_outputopts->ip6po_rthdr && - inp->in6p_outputopts->ip6po_route.ro_rt) - RTFREE(inp->in6p_outputopts->ip6po_route.ro_rt); - if (inp->in6p_outputopts->ip6po_m) - (void)m_free(inp->in6p_outputopts->ip6po_m); - free(inp->in6p_outputopts, M_IP6OPT); - } + ip6_freepcbopts(inp->in6p_outputopts); + ip6_freemoptions(inp->in6p_moptions); if (inp->in6p_route.ro_rt) rtfree(inp->in6p_route.ro_rt); - ip6_freemoptions(inp->in6p_moptions); - /* Check and free IPv4 related resources in case of mapped addr */ if (inp->inp_options) (void)m_free(inp->inp_options); @@ -761,27 +763,33 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) * Must be called at splnet. */ void -in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) +in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, notify) struct inpcbhead *head; - struct sockaddr *dst; + struct sockaddr *dst, *src; u_int fport_arg, lport_arg; - struct in6_addr *laddr6; int cmd; void (*notify) __P((struct inpcb *, int)); { struct inpcb *inp, *ninp; - struct in6_addr faddr6; + struct sockaddr_in6 sa6_src, *sa6_dst; u_short fport = fport_arg, lport = lport_arg; + u_int32_t flowinfo; int errno, s; - int do_rtchange = (notify == in6_rtchange); if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6) return; - faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr; - if (IN6_IS_ADDR_UNSPECIFIED(&faddr6)) + + sa6_dst = (struct sockaddr_in6 *)dst; + if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr)) return; /* + * note that src can be NULL when we get notify by local fragmentation. + */ + sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src; + flowinfo = sa6_src.sin6_flowinfo; + + /* * Redirects go to all references to the destination, * and use in6_rtchange to invalidate the route cache. * Dead host indications: also use in6_rtchange to invalidate @@ -792,44 +800,45 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { fport = 0; lport = 0; - bzero((caddr_t)laddr6, sizeof(*laddr6)); + bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr)); - do_rtchange = 1; + if (cmd != PRC_HOSTDEAD) + notify = in6_rtchange; } errno = inet6ctlerrmap[cmd]; s = splnet(); for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { ninp = LIST_NEXT(inp, inp_list); - if ((inp->inp_vflag & INP_IPV6) == NULL) + if ((inp->inp_vflag & INP_IPV6) == 0) continue; - if (do_rtchange) { - /* - * Since a non-connected PCB might have a cached route, - * we always call in6_rtchange without matching - * the PCB to the src/dst pair. - * - * XXX: we assume in6_rtchange does not free the PCB. - */ - if (IN6_ARE_ADDR_EQUAL(&inp->in6p_route.ro_dst.sin6_addr, - &faddr6)) - in6_rtchange(inp, errno); - - if (notify == in6_rtchange) - continue; /* there's nothing to do any more */ - } - - if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &faddr6) || - inp->inp_socket == 0 || - (lport && inp->inp_lport != lport) || - (!IN6_IS_ADDR_UNSPECIFIED(laddr6) && - !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr6)) || - (fport && inp->inp_fport != fport)) + /* + * Detect if we should notify the error. If no source and + * destination ports are specifed, but non-zero flowinfo and + * local address match, notify the error. This is the case + * when the error is delivered with an encrypted buffer + * by ESP. Otherwise, just compare addresses and ports + * as usual. + */ + if (lport == 0 && fport == 0 && flowinfo && + inp->inp_socket != NULL && + flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) && + IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr)) + goto do_notify; + else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, + &sa6_dst->sin6_addr) || + inp->inp_socket == 0 || + (lport && inp->inp_lport != lport) || + (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && + !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, + &sa6_src.sin6_addr)) || + (fport && inp->inp_fport != fport)) continue; + do_notify: if (notify) - (*notify)(inp, errno); + (*notify)(inp, errno); } splx(s); } @@ -990,6 +999,13 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) struct inpcbhead *head; register struct inpcb *inp; u_short fport = fport_arg, lport = lport_arg; + int faith; + +#if defined(NFAITH) && NFAITH > 0 + faith = faithprefix(laddr); +#else + faith = 0; +#endif /* * First look for an exact match. @@ -1020,11 +1036,8 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) continue; if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && inp->inp_lport == lport) { -#if defined(NFAITH) && NFAITH > 0 - if (ifp && ifp->if_type == IFT_FAITH && - (inp->inp_flags & INP_FAITH) == 0) + if (faith && (inp->inp_flags & INP_FAITH) == 0) continue; -#endif if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) return (inp); diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index 2ea3107..15cd033 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_pcb.h,v 1.5 2000/07/03 06:19:53 itojun Exp $ */ +/* $KAME: in6_pcb.h,v 1.13 2001/02/06 09:16:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -90,7 +90,7 @@ struct inpcb * struct in6_addr *, u_int, struct in6_addr *, u_int, int, struct ifnet *)); void in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *, - u_int, struct in6_addr *, u_int, int, + u_int, struct sockaddr *, u_int, int, void (*)(struct inpcb *, int))); void in6_rtchange __P((struct inpcb *, int)); int in6_setpeeraddr __P((struct socket *so, struct sockaddr **nam)); @@ -105,11 +105,6 @@ struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *, int in6_selecthlim __P((struct in6pcb *, struct ifnet *)); int in6_pcbsetport __P((struct in6_addr *, struct inpcb *, struct proc *)); void init_sin6 __P((struct sockaddr_in6 *sin6, struct mbuf *m)); - -int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *, - struct inpcb *, struct ifnet **)); -int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *, - struct ifnet *)); #endif /* _KERNEL */ #endif /* !_NETINET6_IN6_PCB_H_ */ diff --git a/sys/netinet6/in6_prefix.c b/sys/netinet6/in6_prefix.c index 1eaea50..e3325f9 100644 --- a/sys/netinet6/in6_prefix.c +++ b/sys/netinet6/in6_prefix.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_prefix.c,v 1.30 2000/06/12 14:53:17 jinmei Exp $ */ +/* $KAME: in6_prefix.c,v 1.47 2001/03/25 08:41:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -88,6 +88,8 @@ static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid"); struct rr_prhead rr_prefix; +struct callout in6_rr_timer_ch; + #include <net/net_osdep.h> static void add_each_addr __P((struct socket *so, struct rr_prefix *rpp, @@ -399,7 +401,7 @@ assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen); /* link to ia, and put into list */ rap->ra_addr = ia; - rap->ra_addr->ia_ifa.ifa_refcnt++; + IFAREF(&rap->ra_addr->ia_ifa); #if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */ ia->ia6_ifpr = rp2ifpr(rpp); #endif @@ -465,7 +467,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) if (ifpr == NULL) { struct rr_prefix rp; struct socket so; - int pplen = (plen == 128) ? 64 : plen; + int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */ /* allocate a prefix for ia, with default properties */ @@ -514,11 +516,11 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) if (rap != NULL) { if (rap->ra_addr == NULL) { rap->ra_addr = ia; - rap->ra_addr->ia_ifa.ifa_refcnt++; + IFAREF(&rap->ra_addr->ia_ifa); } else if (rap->ra_addr != ia) { /* There may be some inconsistencies between addrs. */ log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix" - "has already another ia %p(%s) on its ifid list\n", + " already has another ia %p(%s) on its ifid list\n", ip6_sprintf(IA6_IN6(ia)), plen, rap->ra_addr, ip6_sprintf(IA6_IN6(rap->ra_addr))); @@ -599,6 +601,14 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen); /* don't care ifra_flags for now */ + /* + * XXX: if we did this with finite lifetime values, the lifetimes would + * decrese in time and never incremented. + * we should need more clarifications on the prefix mechanism... + */ + ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime; + ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime; + ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr); if (ia6 != NULL) { if (ia6->ia6_ifpr == NULL) { @@ -606,7 +616,7 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) if (rap->ra_addr) IFAFREE(&rap->ra_addr->ia_ifa); rap->ra_addr = ia6; - rap->ra_addr->ia_ifa.ifa_refcnt++; + IFAREF(&rap->ra_addr->ia_ifa); ia6->ia6_ifpr = rp2ifpr(rpp); return; } @@ -614,7 +624,7 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) if (rap->ra_addr) IFAFREE(&rap->ra_addr->ia_ifa); rap->ra_addr = ia6; - rap->ra_addr->ia_ifa.ifa_refcnt++; + IFAREF(&rap->ra_addr->ia_ifa); return; } /* @@ -627,24 +637,26 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) * Or, completely duplicated prefixes? * log it and return. */ - log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" - "%s/%d failed because there is already another addr %s/%d\n", + log(LOG_ERR, + "in6_prefix.c: add_each_addr: addition of an addr %s/%d " + "failed because there is already another addr %s/%d\n", ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, ip6_sprintf(IA6_IN6(ia6)), - in6_mask2len(&ia6->ia_prefixmask.sin6_addr)); + in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL)); return; } /* propagate ANYCAST flag if it is set for ancestor addr */ if (rap->ra_flags.anycast != 0) ifra.ifra_flags |= IN6_IFF_ANYCAST; error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp, - curproc); - if (error != 0) + curproc); + if (error != 0) { log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" "%s/%d failed because in6_control failed for error %d\n", ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, error); return; + } /* * link beween this addr and the prefix will be done @@ -957,8 +969,10 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin) s = splnet(); rap = LIST_FIRST(&rpp->rp_addrhead); - if (rap == NULL) + if (rap == NULL) { + splx(s); break; + } LIST_REMOVE(rap, ra_entry); splx(s); if (rap->ra_addr == NULL) { @@ -967,7 +981,7 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin) } rap->ra_addr->ia6_ifpr = NULL; - in6_purgeaddr(&rap->ra_addr->ia_ifa, rpp->rp_ifp); + in6_purgeaddr(&rap->ra_addr->ia_ifa); IFAFREE(&rap->ra_addr->ia_ifa); free(rap, M_RR_ADDR); } @@ -1166,7 +1180,8 @@ in6_rr_timer(void *ignored_arg) int s; struct rr_prefix *rpp; - timeout(in6_rr_timer, (caddr_t)0, ip6_rr_prune * hz); + callout_reset(&in6_rr_timer_ch, ip6_rr_prune * hz, + in6_rr_timer, NULL); s = splnet(); /* expire */ diff --git a/sys/netinet6/in6_prefix.h b/sys/netinet6/in6_prefix.h index 2ce18db..3ae6a63 100644 --- a/sys/netinet6/in6_prefix.h +++ b/sys/netinet6/in6_prefix.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_prefix.h,v 1.6 2000/03/25 07:23:45 sumikawa Exp $ */ +/* $KAME: in6_prefix.h,v 1.10 2001/02/08 16:30:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project. @@ -30,6 +30,8 @@ * SUCH DAMAGE. */ +#include <sys/callout.h> + struct rr_prefix { struct ifprefix rp_ifpr; LIST_ENTRY(rr_prefix) rp_entry; @@ -85,4 +87,5 @@ LIST_HEAD(rr_prhead, rr_prefix); extern struct rr_prhead rr_prefix; void in6_rr_timer __P((void *)); +extern struct callout in6_rr_timer_ch; int delete_each_prefix __P((struct rr_prefix *rpp, u_char origin)); diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index b221f8a..e73e4bb 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_proto.c,v 1.64 2000/06/20 16:20:27 itojun Exp $ */ +/* $KAME: in6_proto.c,v 1.91 2001/05/27 13:28:35 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -99,25 +99,31 @@ #include <netinet/udp.h> #include <netinet/udp_var.h> #include <netinet6/tcp6_var.h> - +#include <netinet6/raw_ip6.h> #include <netinet6/udp6_var.h> - #include <netinet6/pim6_var.h> - #include <netinet6/nd6.h> #include <netinet6/in6_prefix.h> #ifdef IPSEC #include <netinet6/ipsec.h> +#ifdef INET6 #include <netinet6/ipsec6.h> +#endif #include <netinet6/ah.h> +#ifdef INET6 #include <netinet6/ah6.h> +#endif #ifdef IPSEC_ESP #include <netinet6/esp.h> +#ifdef INET6 #include <netinet6/esp6.h> #endif +#endif #include <netinet6/ipcomp.h> +#ifdef INET6 #include <netinet6/ipcomp6.h> +#endif #endif /*IPSEC*/ #include <netinet6/ip6protosw.h> @@ -136,6 +142,9 @@ extern struct domain inet6domain; static struct pr_usrreqs nousrreqs; +#define PR_LISTEN 0 +#define PR_ABRTACPTDIS 0 + struct ip6protosw inet6sw[] = { { 0, &inet6domain, IPPROTO_IPV6, 0, 0, 0, 0, 0, @@ -143,30 +152,30 @@ struct ip6protosw inet6sw[] = { ip6_init, 0, frag6_slowtimo, frag6_drain, &nousrreqs, }, -{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC | PR_ADDR, +{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR, udp6_input, 0, udp6_ctlinput, ip6_ctloutput, 0, 0, 0, 0, 0, &udp6_usrreqs, }, -{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD, +{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN, tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput, 0, -#ifdef INET /* don't call timeout routines twice */ - tcp_init, 0, 0, tcp_drain, +#ifdef INET /* don't call initialization and timeout routines twice */ + 0, 0, 0, tcp_drain, #else tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, #endif &tcp6_usrreqs, }, -{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR, +{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR, rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput, 0, 0, 0, 0, 0, &rip6_usrreqs }, -{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC | PR_ADDR, - icmp6_input, rip6_output, 0, rip6_ctloutput, +{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + icmp6_input, rip6_output, rip6_ctlinput, rip6_ctloutput, 0, icmp6_init, icmp6_fasttimo, 0, 0, &rip6_usrreqs @@ -191,15 +200,17 @@ struct ip6protosw inet6sw[] = { }, #ifdef IPSEC { SOCK_RAW, &inet6domain, IPPROTO_AH, PR_ATOMIC|PR_ADDR, - ah6_input, 0, 0, 0, + ah6_input, 0, 0, 0, 0, 0, 0, 0, 0, &nousrreqs, }, #ifdef IPSEC_ESP { SOCK_RAW, &inet6domain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR, - esp6_input, 0, 0, 0, - 0, + esp6_input, 0, + esp6_ctlinput, + 0, + 0, 0, 0, 0, 0, &nousrreqs, }, @@ -212,34 +223,30 @@ struct ip6protosw inet6sw[] = { }, #endif /* IPSEC */ #ifdef INET -{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap6_input, rip6_output, 0, rip6_ctloutput, 0, - 0, 0, 0, 0, + encap_init, 0, 0, 0, &rip6_usrreqs }, #endif /*INET*/ -{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, - encap6_input, rip6_output, 0, rip6_ctloutput, +{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + encap6_input, rip6_output, 0, rip6_ctloutput, 0, -#ifndef INET encap_init, 0, 0, 0, -#else - 0, 0, 0, 0, -#endif &rip6_usrreqs }, -{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR, - pim6_input, rip6_output, 0, rip6_ctloutput, +{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + pim6_input, rip6_output, 0, rip6_ctloutput, 0, 0, 0, 0, 0, &rip6_usrreqs }, /* raw wildcard */ -{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR, +{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC|PR_ADDR, rip6_input, rip6_output, 0, rip6_ctloutput, - 0, 0, - 0, 0, 0, + 0, + 0, 0, 0, 0, &rip6_usrreqs }, }; @@ -300,7 +307,7 @@ int ip6_gif_hlim = 0; int ip6_use_deprecated = 1; /* allow deprecated addr (RFC2462 5.5.4) */ int ip6_rr_prune = 5; /* router renumbering prefix * walk list every 5 sec. */ -int ip6_mapped_addr_on = 1; +int ip6_v6only = 0; u_int32_t ip6_id = 0UL; int ip6_keepfaith = 0; @@ -328,84 +335,8 @@ u_long rip6_recvspace = RIPV6RCVQ; /* ICMPV6 parameters */ int icmp6_rediraccept = 1; /* accept and process redirects */ int icmp6_redirtimeout = 10 * 60; /* 10 minutes */ -struct timeval icmp6errratelim = { 0, 0 }; /* no ratelimit */ int icmp6errppslim = 100; /* 100pps */ -int icmp6_nodeinfo = 1; /* enable/disable NI response */ - -#ifdef TCP6 -/* TCP on IP6 parameters */ -int tcp6_sendspace = 1024 * 8; -int tcp6_recvspace = 1024 * 8; -int tcp6_mssdflt = TCP6_MSS; -int tcp6_rttdflt = TCP6TV_SRTTDFLT / PR_SLOWHZ; -int tcp6_do_rfc1323 = 1; -int tcp6_conntimeo = TCP6TV_KEEP_INIT; /* initial connection timeout */ -int tcp6_43maxseg = 0; -int tcp6_pmtu = 0; - -/* - * Parameters for keepalive option. - * Connections for which SO_KEEPALIVE is set will be probed - * after being idle for a time of tcp6_keepidle (in units of PR_SLOWHZ). - * Starting at that time, the connection is probed at intervals - * of tcp6_keepintvl (same units) until a response is received - * or until tcp6_keepcnt probes have been made, at which time - * the connection is dropped. Note that a tcp6_keepidle value - * under 2 hours is nonconformant with RFC-1122, Internet Host Requirements. - */ -int tcp6_keepidle = TCP6TV_KEEP_IDLE; /* time before probing idle */ -int tcp6_keepintvl = TCP6TV_KEEPINTVL; /* interval betwn idle probes */ -int tcp6_keepcnt = TCP6TV_KEEPCNT; /* max idle probes */ -int tcp6_maxpersistidle = TCP6TV_KEEP_IDLE; /* max idle time in persist */ - -#ifndef INET_SERVER -#define TCP6_LISTEN_HASH_SIZE 17 -#define TCP6_CONN_HASH_SIZE 97 -#define TCP6_SYN_HASH_SIZE 293 -#define TCP6_SYN_BUCKET_SIZE 35 -#else -#define TCP6_LISTEN_HASH_SIZE 97 -#define TCP6_CONN_HASH_SIZE 9973 -#define TCP6_SYN_HASH_SIZE 997 -#define TCP6_SYN_BUCKET_SIZE 35 -#endif -int tcp6_listen_hash_size = TCP6_LISTEN_HASH_SIZE; -int tcp6_conn_hash_size = TCP6_CONN_HASH_SIZE; -struct tcp6_hash_list tcp6_listen_hash[TCP6_LISTEN_HASH_SIZE], - tcp6_conn_hash[TCP6_CONN_HASH_SIZE]; - -int tcp6_syn_cache_size = TCP6_SYN_HASH_SIZE; -int tcp6_syn_cache_limit = TCP6_SYN_HASH_SIZE*TCP6_SYN_BUCKET_SIZE; -int tcp6_syn_bucket_limit = 3*TCP6_SYN_BUCKET_SIZE; -struct syn_cache_head6 tcp6_syn_cache[TCP6_SYN_HASH_SIZE]; -struct syn_cache_head6 *tcp6_syn_cache_first; -int tcp6_syn_cache_interval = 8; /* runs timer every 4 seconds */ -int tcp6_syn_cache_timeo = TCP6TV_KEEP_INIT; - -/* - * Parameters for computing a desirable data segment size - * given an upper bound (either interface MTU, or peer's MSS option)_. - * As applications tend to use a buffer size that is a multiple - * of kilobytes, try for something that divides evenly. However, - * do not round down too much. - * - * Round segment size down to a multiple of TCP6_ROUNDSIZE if this - * does not result in lowering by more than (size/TCP6_ROUNDFRAC). - * For example, round 536 to 512. Older versions of the system - * effectively used MCLBYTES (1K or 2K) as TCP6_ROUNDSIZE, with - * a value of 1 for TCP6_ROUNDFRAC (eliminating its effect). - * We round to a multiple of 256 for SLIP. - */ -#ifndef TCP6_ROUNDSIZE -#define TCP6_ROUNDSIZE 256 /* round to multiple of 256 */ -#endif -#ifndef TCP6_ROUNDFRAC -#define TCP6_ROUNDFRAC 10 /* round down at most N/10, or 10% */ -#endif - -int tcp6_roundsize = TCP6_ROUNDSIZE; -int tcp6_roundfrac = TCP6_ROUNDFRAC; -#endif /*TCP6*/ +int icmp6_nodeinfo = 3; /* enable/disable NI response */ /* UDP on IP6 parameters */ int udp6_sendspace = 9216; /* really max datagram size */ @@ -429,76 +360,44 @@ SYSCTL_NODE(_net_inet6, IPPROTO_ESP, ipsec6, CTLFLAG_RW, 0, "IPSEC6"); /* net.inet6.ip6 */ static int -sysctl_ip6_forwarding(SYSCTL_HANDLER_ARGS) +sysctl_ip6_temppltime(SYSCTL_HANDLER_ARGS) { int error = 0; - int old_ip6_forwarding; - int changed; + int old; error = SYSCTL_OUT(req, arg1, sizeof(int)); if (error || !req->newptr) return (error); - old_ip6_forwarding = ip6_forwarding; + old = ip6_temp_preferred_lifetime; error = SYSCTL_IN(req, arg1, sizeof(int)); - if (error != 0) - return (error); - changed = (ip6_forwarding ? 1 : 0) ^ (old_ip6_forwarding ? 1 : 0); - if (changed == 0) - return (error); - /* - * XXX while host->router removes prefix got from RA, - * router->host case nukes all the prefixes managed by in6_prefix.c - * (both RR and static). therefore, switching from host->router->host - * will remove statically configured addresses/prefixes. - * not sure if it is intended behavior or not. - */ - if (ip6_forwarding != 0) { /* host becomes router */ - int s = splnet(); - struct nd_prefix *pr, *next; - - for (pr = nd_prefix.lh_first; pr; pr = next) { - next = pr->ndpr_next; - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); - prelist_remove(pr); - } - splx(s); - } else { /* router becomes host */ - while(!LIST_EMPTY(&rr_prefix)) - delete_each_prefix(LIST_FIRST(&rr_prefix), - PR_ORIG_KERNEL); + if (ip6_temp_preferred_lifetime < + ip6_desync_factor + ip6_temp_regen_advance) { + ip6_temp_preferred_lifetime = old; + return(EINVAL); } - - return (error); + return(error); } static int -sysctl_icmp6_ratelimit (SYSCTL_HANDLER_ARGS) +sysctl_ip6_tempvltime(SYSCTL_HANDLER_ARGS) { - int rate_usec, error, s; - - /* - * The sysctl specifies the rate in usec-between-icmp, - * so we must convert from/to a timeval. - */ - rate_usec = (icmp6errratelim.tv_sec * 1000000) + - icmp6errratelim.tv_usec; - error = sysctl_handle_int(oidp, &rate_usec, 0, req); - if (error) + int error = 0; + int old; + + error = SYSCTL_OUT(req, arg1, sizeof(int)); + if (error || !req->newptr) return (error); - if (rate_usec < 0) - return (EINVAL); - s = splnet(); - icmp6errratelim.tv_sec = rate_usec / 1000000; - icmp6errratelim.tv_usec = rate_usec % 1000000; - splx(s); - - return (0); + old = ip6_temp_valid_lifetime; + error = SYSCTL_IN(req, arg1, sizeof(int)); + if (ip6_temp_valid_lifetime < ip6_temp_preferred_lifetime) { + ip6_temp_preferred_lifetime = old; + return(EINVAL); + } + return(error); } -SYSCTL_OID(_net_inet6_ip6, IPV6CTL_FORWARDING, forwarding, - CTLTYPE_INT|CTLFLAG_RW, &ip6_forwarding, 0, sysctl_ip6_forwarding, - "I", ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_FORWARDING, + forwarding, CTLFLAG_RW, &ip6_forwarding, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_SENDREDIRECTS, redirect, CTLFLAG_RW, &ip6_sendredirects, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFHLIM, @@ -527,8 +426,20 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEPRECATED, use_deprecated, CTLFLAG_RW, &ip6_use_deprecated, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RR_PRUNE, rr_prune, CTLFLAG_RW, &ip6_rr_prune, 0, ""); -SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAPPED_ADDR, - mapped_addr, CTLFLAG_RW, &ip6_mapped_addr_on, 0, ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USETEMPADDR, + use_tempaddr, CTLFLAG_RW, &ip6_use_tempaddr, 0, ""); +SYSCTL_OID(_net_inet6_ip6, IPV6CTL_TEMPPLTIME, temppltime, + CTLTYPE_INT|CTLFLAG_RW, &ip6_temp_preferred_lifetime, 0, + sysctl_ip6_temppltime, "I", ""); +SYSCTL_OID(_net_inet6_ip6, IPV6CTL_TEMPVLTIME, tempvltime, + CTLTYPE_INT|CTLFLAG_RW, &ip6_temp_valid_lifetime, 0, + sysctl_ip6_tempvltime, "I", ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_V6ONLY, + v6only, CTLFLAG_RW, &ip6_v6only, 0, ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL, + auto_linklocal, CTLFLAG_RW, &ip6_auto_linklocal, 0, ""); +SYSCTL_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD, + &rip6stat, rip6stat, ""); /* net.inet6.icmp6 */ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT, @@ -537,9 +448,6 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRTIMEOUT, redirtimeout, CTLFLAG_RW, &icmp6_redirtimeout, 0, ""); SYSCTL_STRUCT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats, CTLFLAG_RD, &icmp6stat, icmp6stat, ""); -SYSCTL_PROC(_net_inet6_icmp6, ICMPV6CTL_ERRRATELIMIT, - errratelimit, CTLTYPE_INT|CTLFLAG_RW, - 0, sizeof(int), sysctl_icmp6_ratelimit, "I", ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PRUNE, nd6_prune, CTLFLAG_RW, &nd6_prune, 0, ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_DELAY, @@ -556,3 +464,5 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, errppslimit, CTLFLAG_RW, &icmp6errppslim, 0, ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MAXNUDHINT, nd6_maxnudhint, CTLFLAG_RW, &nd6_maxnudhint, 0, ""); +SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_DEBUG, + nd6_debug, CTLFLAG_RW, &nd6_debug, 0, ""); diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 14f72d2..a56cfe2 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_rmx.c,v 1.7 2000/04/06 08:30:43 sumikawa Exp $ */ +/* $KAME: in6_rmx.c,v 1.10 2001/05/24 05:44:58 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -146,23 +146,6 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, } } - /* - * We also specify a send and receive pipe size for every - * route added, to help TCP a bit. TCP doesn't actually - * want a true pipe size, which would be prohibitive in memory - * costs and is hard to compute anyway; it simply uses these - * values to size its buffers. So, we fill them in with the - * same values that TCP would have used anyway, and allow the - * installing program or the link layer to override these values - * as it sees fit. This will hopefully allow TCP more - * opportunities to save its ssthresh value. - */ - if (!rt->rt_rmx.rmx_sendpipe && !(rt->rt_rmx.rmx_locks & RTV_SPIPE)) - rt->rt_rmx.rmx_sendpipe = tcp_sendspace; - - if (!rt->rt_rmx.rmx_recvpipe && !(rt->rt_rmx.rmx_locks & RTV_RPIPE)) - rt->rt_rmx.rmx_recvpipe = tcp_recvspace; - if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_ifp) rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 765a692..7bf28d2 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_src.c,v 1.27 2000/06/21 08:07:13 itojun Exp $ */ +/* $KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -70,6 +70,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> @@ -97,9 +98,9 @@ #include <net/net_osdep.h> /* - * Return an IPv6 address, which is the most appropriate for given + * Return an IPv6 address, which is the most appropriate for a given * destination and user specified options. - * If necessary, this function lookups the routing table and return + * If necessary, this function lookups the routing table and returns * an entry to the caller for later use. */ struct in6_addr * @@ -241,12 +242,15 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) } if (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0) { + struct sockaddr_in6 *sa6; + /* No route yet, so try to acquire one */ bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); - ro->ro_dst.sin6_family = AF_INET6; - ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro->ro_dst.sin6_addr = *dst; - ro->ro_dst.sin6_scope_id = dstsock->sin6_scope_id; + sa6 = (struct sockaddr_in6 *)&ro->ro_dst; + sa6->sin6_family = AF_INET6; + sa6->sin6_len = sizeof(struct sockaddr_in6); + sa6->sin6_addr = *dst; + sa6->sin6_scope_id = dstsock->sin6_scope_id; if (IN6_IS_ADDR_MULTICAST(dst)) { ro->ro_rt = rtalloc1(&((struct route *)ro) ->ro_dst, 0, 0UL); @@ -529,15 +533,8 @@ in6_recoverscope(sin6, in6, ifp) /* sanity check */ if (scopeid < 0 || if_index < scopeid) return ENXIO; -#ifndef FAKE_LOOPBACK_IF - if (ifp && (ifp->if_flags & IFF_LOOPBACK) == 0 && - ifp->if_index != scopeid) { - return ENXIO; - } -#else if (ifp && ifp->if_index != scopeid) return ENXIO; -#endif sin6->sin6_addr.s6_addr16[1] = 0; sin6->sin6_scope_id = scopeid; } @@ -545,3 +542,15 @@ in6_recoverscope(sin6, in6, ifp) return 0; } + +/* + * just clear the embedded scope identifer. + * XXX: currently used for bsdi4 only as a supplement function. + */ +void +in6_clearscope(addr) + struct in6_addr *addr; +{ + if (IN6_IS_SCOPE_LINKLOCAL(addr)) + addr->s6_addr16[1] = 0; +} diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index f2f644e..bb5abc9 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in6_var.h,v 1.33 2000/05/17 05:07:26 jinmei Exp $ */ +/* $KAME: in6_var.h,v 1.56 2001/03/29 05:34:31 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -102,8 +102,12 @@ struct in6_ifaddr { struct in6_ifaddr *ia_next; /* next in6 list of IP6 addresses */ int ia6_flags; - struct in6_addrlifetime ia6_lifetime; /* NULL = infty */ + struct in6_addrlifetime ia6_lifetime; struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */ + + struct nd_prefix *ia6_ndpr; /* back pointer to the ND prefix + * (for autoconfigured addresses only) + */ }; /* @@ -380,7 +384,10 @@ struct in6_rrenumreq { #define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist) #define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_prlist) -#define SIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ndireq) +#ifdef _KERNEL +#define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq) +#endif +#define SIOCGIFINFO_IN6 _IOWR('i', 108, struct in6_ndireq) #define SIOCSNDFLUSH_IN6 _IOWR('i', 77, struct in6_ifreq) #define SIOCGNBRINFO_IN6 _IOWR('i', 78, struct in6_nbrinfo) #define SIOCSPFXFLUSH_IN6 _IOWR('i', 79, struct in6_ifreq) @@ -419,6 +426,14 @@ struct in6_rrenumreq { #define IN6_IFF_DUPLICATED 0x04 /* DAD detected duplicate */ #define IN6_IFF_DETACHED 0x08 /* may be detached from the link */ #define IN6_IFF_DEPRECATED 0x10 /* deprecated address */ +#define IN6_IFF_NODAD 0x20 /* don't perform DAD on this address + * (used only at first SIOC* call) + */ +#define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */ +#define IN6_IFF_TEMPORARY 0x80 /* temporary (anonymous) address. */ +#define IN6_IFF_NOPFX 0x8000 /* skip kernel prefix management. + * XXX: this should be temporary. + */ /* do not input/output */ #define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED) @@ -516,7 +531,7 @@ struct in6_multistep { /* struct ifnet *ifp; */ \ /* struct in6_multi *in6m; */ \ do { \ - register struct ifmultiaddr *ifma; \ + struct ifmultiaddr *ifma; \ TAILQ_FOREACH(ifma, &(ifp)->if_multiaddrs, ifma_link) { \ if (ifma->ifma_addr->sa_family == AF_INET6 \ && IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifma->ifma_addr)->sin6_addr, \ @@ -549,18 +564,19 @@ do { \ IN6_NEXT_MULTI((step), (in6m)); \ } while(0) -int in6_ifinit __P((struct ifnet *, - struct in6_ifaddr *, struct sockaddr_in6 *, int)); struct in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *, int *)); void in6_delmulti __P((struct in6_multi *)); -void in6_ifscrub __P((struct ifnet *, struct in6_ifaddr *)); extern int in6_ifindex2scopeid __P((int)); -extern int in6_mask2len __P((struct in6_addr *)); +extern int in6_mask2len __P((struct in6_addr *, u_char *)); extern void in6_len2mask __P((struct in6_addr *, int)); int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); -void in6_purgeaddr __P((struct ifaddr *, struct ifnet *)); +int in6_update_ifa __P((struct ifnet *, struct in6_aliasreq *, + struct in6_ifaddr *)); +void in6_purgeaddr __P((struct ifaddr *)); +int in6if_do_dad __P((struct ifnet *)); +void in6_purgeif __P((struct ifnet *)); void in6_savemkludge __P((struct in6_ifaddr *)); void in6_setmaxmtu __P((void)); void in6_restoremkludge __P((struct in6_ifaddr *, struct ifnet *)); @@ -568,7 +584,7 @@ void in6_purgemkludge __P((struct ifnet *)); struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *, int)); struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *, struct in6_addr *)); -char *ip6_sprintf __P((struct in6_addr *)); +char *ip6_sprintf __P((const struct in6_addr *)); int in6_addr2scopeid __P((struct ifnet *, struct in6_addr *)); int in6_matchlen __P((struct in6_addr *, struct in6_addr *)); int in6_are_prefix_equal __P((struct in6_addr *p1, struct in6_addr *p2, @@ -579,6 +595,14 @@ int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data, int in6_prefix_add_ifid __P((int iilen, struct in6_ifaddr *ia)); void in6_prefix_remove_ifid __P((int iilen, struct in6_ifaddr *ia)); void in6_purgeprefix __P((struct ifnet *)); + +int in6_is_addr_deprecated __P((struct sockaddr_in6 *)); +struct inpcb; +int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *, + struct inpcb *, struct ifnet **)); +int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *, + struct ifnet *)); +void in6_clearscope __P((struct in6_addr *)); #endif /* _KERNEL */ #endif /* _NETINET6_IN6_VAR_H_ */ diff --git a/sys/netinet6/ip6_ecn.h b/sys/netinet6/ip6_ecn.h index e8dd11f..4107cf0 100644 --- a/sys/netinet6/ip6_ecn.h +++ b/sys/netinet6/ip6_ecn.h @@ -36,6 +36,6 @@ */ #ifdef _KERNEL -extern void ip6_ecn_ingress __P((int, u_int32_t *, u_int32_t *)); -extern void ip6_ecn_egress __P((int, u_int32_t *, u_int32_t *)); +extern void ip6_ecn_ingress __P((int, u_int32_t *, const u_int32_t *)); +extern void ip6_ecn_egress __P((int, const u_int32_t *, u_int32_t *)); #endif diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 2664ccb..444cd2c 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_forward.c,v 1.43 2000/07/16 07:50:49 itojun Exp $ */ +/* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,12 +37,14 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/domain.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/errno.h> #include <sys/time.h> +#include <sys/kernel.h> #include <sys/syslog.h> #include <net/if.h> @@ -50,15 +52,22 @@ #include <netinet/in.h> #include <netinet/in_var.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> #include <netinet/ip_var.h> +#include <netinet6/in6_var.h> #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet/icmp6.h> #include <netinet6/nd6.h> +#include <netinet/in_pcb.h> + #ifdef IPSEC #include <netinet6/ipsec.h> +#ifdef INET6 #include <netinet6/ipsec6.h> +#endif #include <netkey/key.h> #endif /* IPSEC */ @@ -87,8 +96,8 @@ ip6_forward(m, srcrt) int srcrt; { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - register struct sockaddr_in6 *dst; - register struct rtentry *rt; + struct sockaddr_in6 *dst; + struct rtentry *rt; int error, type = 0, code = 0; struct mbuf *mcopy = NULL; struct ifnet *origifp; /* maybe unnecessary */ @@ -111,8 +120,15 @@ ip6_forward(m, srcrt) } #endif /*IPSEC*/ + /* + * Do not forward packets to multicast destination (should be handled + * by ip6_mforward(). + * Do not forward packets with unspecified source. It was discussed + * in July 2000, on ipngwg mailing list. + */ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || - IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { + IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || + IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { ip6stat.ip6s_cantforward++; /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ if (ip6_log_time + ip6_log_interval < time_second) { @@ -150,7 +166,8 @@ ip6_forward(m, srcrt) #ifdef IPSEC /* get a security policy for this packet */ - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING, + &error); if (sp == NULL) { ipsec6stat.out_inval++; ip6stat.ip6s_cantforward++; @@ -238,10 +255,6 @@ ip6_forward(m, srcrt) error = ipsec6_output_tunnel(&state, sp, 0); m = state.m; -#if 0 /* XXX allocate a route (ro, dst) again later */ - ro = (struct route_in6 *)state.ro; - dst = (struct sockaddr_in6 *)state.dst; -#endif key_freesp(sp); if (error) { @@ -275,7 +288,7 @@ ip6_forward(m, srcrt) skip_ipsec: #endif /* IPSEC */ - dst = &ip6_forward_rt.ro_dst; + dst = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst; if (!srcrt) { /* * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst @@ -293,7 +306,7 @@ ip6_forward(m, srcrt) if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; - /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute); if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); @@ -315,7 +328,7 @@ ip6_forward(m, srcrt) rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; - /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute); if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); @@ -410,8 +423,25 @@ ip6_forward(m, srcrt) * modified by a redirect. */ if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && - (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) + (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { + if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) { + /* + * If the incoming interface is equal to the outgoing + * one, and the link attached to the interface is + * point-to-point, then it will be highly probable + * that a routing loop occurs. Thus, we immediately + * drop the packet and send an ICMPv6 error message. + * + * type/code is based on suggestion by Rich Draves. + * not sure if it is the best pick. + */ + icmp6_error(mcopy, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADDR, 0); + m_freem(m); + return; + } type = ND_REDIRECT; + } /* * Check with the firewall... @@ -432,8 +462,8 @@ ip6_forward(m, srcrt) * destinaion can appear, if the originating node just sends the * packet to us (without address resolution for the destination). * Since both icmp6_error and icmp6_redirect_output fill the embedded - * link identifiers, we can do this stuff after make a copy for - * returning error. + * link identifiers, we can do this stuff after making a copy for + * returning an error. */ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { /* @@ -459,34 +489,21 @@ ip6_forward(m, srcrt) if_name(rt->rt_ifp)); } - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])]; - else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])]; - else - origifp = rt->rt_ifp; + /* we can just use rcvif in forwarding. */ + origifp = m->m_pkthdr.rcvif; } else origifp = rt->rt_ifp; -#ifndef FAKE_LOOPBACK_IF - if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) -#else - if (1) +#ifndef SCOPEDROUTING + /* + * clear embedded scope identifiers if necessary. + * in6_clearscope will touch the addresses only when necessary. + */ + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); #endif - { - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - ip6->ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] = 0; - } -#ifdef OLDIP6OUTPUT - error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, - (struct sockaddr *)dst, - ip6_forward_rt.ro_rt); -#else error = nd6_output(rt->rt_ifp, origifp, m, dst, rt); -#endif if (error) { in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard); ip6stat.ip6s_cantforward++; diff --git a/sys/netinet6/ip6_fw.c b/sys/netinet6/ip6_fw.c index ae1c0f1..f0245cf 100644 --- a/sys/netinet6/ip6_fw.c +++ b/sys/netinet6/ip6_fw.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_fw.c,v 1.15 2000/07/02 14:17:37 itojun Exp $ */ +/* $KAME: ip6_fw.c,v 1.21 2001/01/24 01:25:32 itojun Exp $ */ /* * Copyright (c) 1993 Daniel Boulet @@ -87,7 +87,7 @@ LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain; SYSCTL_DECL(_net_inet6_ip6); SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, enable, CTLFLAG_RW, - &ip6_fw_enable, 0, "Enable ip6fw"); + &ip6_fw_enable, 0, "Enable ip6fw"); SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw6_debug, 0, ""); SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw6_verbose, 0, ""); SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, ""); @@ -479,7 +479,7 @@ ip6_fw_chk(struct ip6_hdr **pip6, } #endif /* IP6FW_DIVERT_RESTART */ for (; chain; chain = LIST_NEXT(chain, chain)) { - register struct ip6_fw *const f = chain->rule; + struct ip6_fw *const f = chain->rule; if (oif) { /* Check direction outbound */ @@ -758,7 +758,8 @@ got_match: flags = TH_RST|TH_ACK; } bcopy(&ti, ip6, sizeof(ti)); - m_freem(*m); + tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1), + *m, ack, seq, flags); *m = NULL; break; } @@ -1064,7 +1065,7 @@ ip6_fw_ctl(int stage, struct mbuf **mm) } } for (; fcp; fcp = fcp->chain.le_next) { - memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule)); + bcopy(fcp->rule, m->m_data, sizeof *(fcp->rule)); m->m_len = sizeof *(fcp->rule); m->m_next = m_get(M_TRYWAIT, MT_DATA); /* XXX */ if (!m->m_next) { @@ -1204,7 +1205,7 @@ static int ip6fw_modevent(module_t mod, int type, void *unused) { int s; - + switch (type) { case MOD_LOAD: s = splnet(); @@ -1225,7 +1226,7 @@ ip6fw_modevent(module_t mod, int type, void *unused) free(fcp->rule, M_IP6FW); free(fcp, M_IP6FW); } - + splx(s); printf("IPv6 firewall unloaded\n"); return 0; diff --git a/sys/netinet6/ip6_fw.h b/sys/netinet6/ip6_fw.h index bcd1a03..2298804 100644 --- a/sys/netinet6/ip6_fw.h +++ b/sys/netinet6/ip6_fw.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_fw.h,v 1.3 2000/04/06 08:30:44 sumikawa Exp $ */ +/* $KAME: ip6_fw.h,v 1.7 2001/01/24 01:25:33 itojun Exp $ */ /* * Copyright (c) 1993 Daniel Boulet diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 4745347..4b10d8e 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_input.c,v 1.95 2000/07/02 07:49:37 jinmei Exp $ */ +/* $KAME: ip6_input.c,v 1.194 2001/05/27 13:28:35 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -73,6 +73,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/domain.h> #include <sys/protosw.h> @@ -108,6 +109,13 @@ #include <netinet6/nd6.h> #include <netinet6/in6_prefix.h> +#ifdef IPSEC +#include <netinet6/ipsec.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#endif +#endif + #include <netinet6/ip6_fw.h> #include <netinet6/ip6protosw.h> @@ -124,11 +132,16 @@ u_char ip6_protox[IPPROTO_MAX]; static int ip6qmaxlen = IFQ_MAXLEN; struct in6_ifaddr *in6_ifaddr; +extern struct callout in6_tmpaddrtimer_ch; + int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ const int int6intrq_present = 1; +int ip6_ours_check_algorithm; + + /* firewall hooks */ ip6_fw_chk_t *ip6_fw_chk_ptr; ip6_fw_ctl_t *ip6_fw_ctl_ptr; @@ -137,12 +150,14 @@ int ip6_fw_enable = 1; struct ip6stat ip6stat; static void ip6_init2 __P((void *)); +static struct mbuf *ip6_setdstifaddr __P((struct mbuf *, struct in6_ifaddr *)); static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); #ifdef PULLDOWN_TEST static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int)); #endif + /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. @@ -150,10 +165,14 @@ static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int)); void ip6_init() { - register struct ip6protosw *pr; - register int i; + struct ip6protosw *pr; + int i; struct timeval tv; +#ifdef DIAGNOSTIC + if (sizeof(struct protosw) != sizeof(struct ip6protosw)) + panic("sizeof(protosw) != sizeof(ip6protosw)"); +#endif pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == 0) panic("ip6_init"); @@ -175,6 +194,8 @@ ip6_init() */ microtime(&tv); ip6_flow_seq = random() ^ tv.tv_usec; + microtime(&tv); + ip6_desync_factor = (random() ^ tv.tv_usec) % MAX_TEMP_DESYNC_FACTOR; } static void @@ -189,9 +210,18 @@ ip6_init2(dummy) in6_ifattach(&loif[0], NULL); /* nd6_timer_init */ - timeout(nd6_timer, (caddr_t)0, hz); + callout_init(&nd6_timer_ch, 0); + callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); + /* router renumbering prefix list maintenance */ - timeout(in6_rr_timer, (caddr_t)0, hz); + callout_init(&in6_rr_timer_ch, 0); + callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL); + + /* timer for regeneranation of temporary addresses randomize ID */ + callout_reset(&in6_tmpaddrtimer_ch, + (ip6_temp_preferred_lifetime - ip6_desync_factor - + ip6_temp_regen_advance) * hz, + in6_tmpaddrtimer, NULL); } /* cheat */ @@ -247,6 +277,11 @@ ip6_input(m) #endif /* + * make sure we don't have onion peering information into m_aux. + */ + ip6_delaux(m); + + /* * mbuf statistics by kazu */ if (m->m_flags & M_EXT) { @@ -255,15 +290,17 @@ ip6_input(m) else ip6stat.ip6s_mext1++; } else { +#define M2MMAX (sizeof(ip6stat.ip6s_m2m)/sizeof(ip6stat.ip6s_m2m[0])) if (m->m_next) { if (m->m_flags & M_LOOP) { ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/ - } else if (m->m_pkthdr.rcvif->if_index <= 31) + } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; else ip6stat.ip6s_m2m[0]++; } else ip6stat.ip6s_m1++; +#undef M2MMAX } in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); @@ -360,20 +397,42 @@ ip6_input(m) } /* - * Scope check + * Check against address spoofing/corruption. */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { + /* + * XXX: "badscope" is not very suitable for a multicast source. + */ + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } + if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || + IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) && + (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { ip6stat.ip6s_badscope++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } - /* - * Don't check IPv4 mapped address here. SIIT assumes that - * routers would forward IPv6 native packets with IPv4 mapped - * address normally. + * The following check is not documented in specs. A malicious + * party may be able to use IPv4 mapped addr to confuse tcp/udp stack + * and bypass security checks (act as if it was from 127.0.0.1 by using + * IPv6 src ::ffff:127.0.0.1). Be cautious. + * + * This check chokes if we are in an SIIT cloud. As none of BSDs + * support IPv4-less kernel compilation, we cannot support SIIT + * environment at all. So, it makes more sense for us to reject any + * malicious packets for non-SIIT environment, than try to do a + * partical support for SIIT environment. */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } #if 0 /* * Reject packets with IPv4 compatible addresses (auto tunnel). @@ -389,105 +448,52 @@ ip6_input(m) goto bad; } #endif - if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || - IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { - if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { - struct in6_ifaddr *ia6; - - if ((ia6 = in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, - &ip6->ip6_dst)) != NULL) { - ia6->ia_ifa.if_ipackets++; - ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; - } else { - /* - * The packet is looped back, but we do not - * have the destination address for some - * reason. - * XXX: should we return an icmp6 error? - */ - goto bad; - } - ours = 1; - deliverifp = m->m_pkthdr.rcvif; - goto hbhcheck; - } else { + + /* drop packets if interface ID portion is already filled */ + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) && + ip6->ip6_src.s6_addr16[1]) { + ip6stat.ip6s_badscope++; + goto bad; + } + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst) && + ip6->ip6_dst.s6_addr16[1]) { ip6stat.ip6s_badscope++; - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } } -#ifndef FAKE_LOOPBACK_IF - if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) -#else - if (1) -#endif - { - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - ip6->ip6_src.s6_addr16[1] - = htons(m->m_pkthdr.rcvif->if_index); - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] - = htons(m->m_pkthdr.rcvif->if_index); - } + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) + ip6->ip6_src.s6_addr16[1] + = htons(m->m_pkthdr.rcvif->if_index); + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) + ip6->ip6_dst.s6_addr16[1] + = htons(m->m_pkthdr.rcvif->if_index); +#if 0 /* this case seems to be unnecessary. (jinmei, 20010401) */ /* - * XXX we need this since we do not have "goto ours" hack route - * for some of our ifaddrs on loopback interface. - * we should correct it by changing in6_ifattach to install - * "goto ours" hack route. + * We use rt->rt_ifp to determine if the address is ours or not. + * If rt_ifp is lo0, the address is ours. + * The problem here is, rt->rt_ifp for fe80::%lo0/64 is set to lo0, + * so any address under fe80::%lo0/64 will be mistakenly considered + * local. The special case is supplied to handle the case properly + * by actually looking at interface addresses + * (using in6ifa_ifpwithaddr). */ - if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0) { - if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { - struct in6_ifaddr *ia6; -#ifndef FAKE_LOOPBACK_IF - int deliverifid; - - /* - * Get the "real" delivered interface, which should be - * embedded in the second 16 bits of the destination - * address. We can probably trust the value, but we - * add validation for the value just for safety. - */ - deliverifid = ntohs(ip6->ip6_dst.s6_addr16[1]); - if (deliverifid > 0 && deliverifid <= if_index) { - deliverifp = ifindex2ifnet[deliverifid]; - - /* - * XXX: fake the rcvif to the real interface. - * Since m_pkthdr.rcvif should be lo0 (or a - * variant), it would confuse scope handling - * code later. - */ - m->m_pkthdr.rcvif = deliverifp; - } - else { - /* - * Last resort; just use rcvif. - * XXX: the packet would be discarded by the - * succeeding check. - */ - deliverifp = m->m_pkthdr.rcvif; - } -#else - deliverifp = m->m_pkthdr.rcvif; -#endif - if ((ia6 = in6ifa_ifpwithaddr(deliverifp, - &ip6->ip6_dst)) != NULL) { - ia6->ia_ifa.if_ipackets++; - ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; - } else { - /* - * We do not have the link-local address - * specified as the destination. - * XXX: should we return an icmp6 error? - */ - goto bad; - } - ours = 1; - goto hbhcheck; + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0 && + IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { + if (!in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, &ip6->ip6_dst)) { + icmp6_error(m, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADDR, 0); + /* m is already freed */ + return; } + + ours = 1; + deliverifp = m->m_pkthdr.rcvif; + goto hbhcheck; } +#endif /* * Multicast check @@ -516,12 +522,21 @@ ip6_input(m) /* * Unicast check */ + switch (ip6_ours_check_algorithm) { + default: + /* + * XXX: I intentionally broke our indentation rule here, + * since this switch-case is just for measurement and + * therefore should soon be removed. + */ if (ip6_forward_rt.ro_rt != NULL && (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, - &ip6_forward_rt.ro_dst.sin6_addr)) + &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr)) ip6stat.ip6s_forward_cachehit++; else { + struct sockaddr_in6 *dst6; + if (ip6_forward_rt.ro_rt) { /* route is down or destination is different */ ip6stat.ip6s_forward_cachemiss++; @@ -530,9 +545,10 @@ ip6_input(m) } bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6)); - ip6_forward_rt.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ip6_forward_rt.ro_dst.sin6_family = AF_INET6; - ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst; + dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; #ifdef SCOPEDROUTING ip6_forward_rt.ro_dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_dst); @@ -551,10 +567,27 @@ ip6_input(m) * route to the loopback interface for the destination of the packet. * But we think it's even useful in some situations, e.g. when using * a special daemon which wants to intercept the packet. + * + * XXX: some OSes automatically make a cloned route for the destination + * of an outgoing packet. If the outgoing interface of the packet + * is a loopback one, the kernel would consider the packet to be + * accepted, even if we have no such address assinged on the interface. + * We check the cloned flag of the route entry to reject such cases, + * assuming that route entries for our own addresses are not made by + * cloning (it should be true because in6_addloop explicitly installs + * the host route). However, we might have to do an explicit check + * while it would be less efficient. Or, should we rather install a + * reject route for such a case? */ if (ip6_forward_rt.ro_rt && (ip6_forward_rt.ro_rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && +#ifdef RTF_WASCLONED + !(ip6_forward_rt.ro_rt->rt_flags & RTF_WASCLONED) && +#endif +#ifdef RTF_CLONED + !(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) && +#endif #if 0 /* * The check below is redundant since the comparison of @@ -562,13 +595,17 @@ ip6_input(m) * already done through looking up the routing table. */ IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, - &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && + &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) #endif ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { struct in6_ifaddr *ia6 = (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa; - if (ia6->ia6_flags & IN6_IFF_ANYCAST) - m->m_flags |= M_ANYCAST6; + + /* + * record address information into m_aux. + */ + (void)ip6_setdstifaddr(m, ia6); + /* * packets to a tentative, duplicated, or somehow invalid * address must not be accepted. @@ -577,22 +614,21 @@ ip6_input(m) /* this address is ready */ ours = 1; deliverifp = ia6->ia_ifp; /* correct? */ - /* Count the packet in the ip address stats */ ia6->ia_ifa.if_ipackets++; ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; - goto hbhcheck; } else { /* address is not ready, so discard the packet. */ - log(LOG_INFO, - "ip6_input: packet to an unready address %s->%s", + nd6log((LOG_INFO, + "ip6_input: packet to an unready address %s->%s\n", ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst)); + ip6_sprintf(&ip6->ip6_dst))); goto bad; } } + } /* XXX indentation (see above) */ /* * FAITH(Firewall Aided Internet Translator) @@ -621,6 +657,27 @@ ip6_input(m) hbhcheck: /* + * record address information into m_aux, if we don't have one yet. + * note that we are unable to record it, if the address is not listed + * as our interface address (e.g. multicast addresses, addresses + * within FAITH prefixes and such). + */ + if (deliverifp && !ip6_getdstifaddr(m)) { + struct in6_ifaddr *ia6; + + ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); + if (ia6) { + if (!ip6_setdstifaddr(m, ia6)) { + /* + * XXX maybe we should drop the packet here, + * as we could not provide enough information + * to the upper layers. + */ + } + } + } + + /* * Process Hop-by-Hop options header if it's contained. * m may be modified in ip6_hopopts_input(). * If a JumboPayload option is included, plen will also be modified. @@ -749,6 +806,7 @@ ip6_input(m) ip6stat.ip6s_delivered++; in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; + while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { ip6stat.ip6s_toomanyhdr++; @@ -765,6 +823,35 @@ ip6_input(m) goto bad; } +#if 0 + /* + * do we need to do it for every header? yeah, other + * functions can play with it (like re-allocate and copy). + */ + mhist = ip6_addaux(m); + if (mhist && M_TRAILINGSPACE(mhist) >= sizeof(nxt)) { + hist = mtod(mhist, caddr_t) + mhist->m_len; + bcopy(&nxt, hist, sizeof(nxt)); + mhist->m_len += sizeof(nxt); + } else { + ip6stat.ip6s_toomanyhdr++; + goto bad; + } +#endif + +#ifdef IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && + ipsec6_in_reject(m, NULL)) { + ipsec6stat.in_polvio++; + goto bad; + } +#endif + nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; @@ -773,6 +860,36 @@ ip6_input(m) } /* + * set/grab in6_ifaddr correspond to IPv6 destination address. + * XXX backward compatibility wrapper + */ +static struct mbuf * +ip6_setdstifaddr(m, ia6) + struct mbuf *m; + struct in6_ifaddr *ia6; +{ + struct mbuf *n; + + n = ip6_addaux(m); + if (n) + mtod(n, struct ip6aux *)->ip6a_dstia6 = ia6; + return n; /* NULL if failed to set */ +} + +struct in6_ifaddr * +ip6_getdstifaddr(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = ip6_findaux(m); + if (n) + return mtod(n, struct ip6aux *)->ip6a_dstia6; + else + return NULL; +} + +/* * Hop-by-Hop options header processing. If a valid jumbo payload option is * included, the real payload length will be stored in plenp. */ @@ -783,7 +900,7 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp) struct mbuf **mp; int *offp; { - register struct mbuf *m = *mp; + struct mbuf *m = *mp; int off = *offp, hbhlen; struct ip6_hbh *hbh; u_int8_t *opt; @@ -829,6 +946,10 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp) * This function is separate from ip6_hopopts_input() in order to * handle a case where the sending node itself process its hop-by-hop * options header. In such a case, the function is called from ip6_output(). + * + * The function assumes that hbh header is located right after the IPv6 header + * (RFC2460 p7), opthead is pointer into data content in m, and opthead to + * opthead + hbhlen is located in continuous memory region. */ int ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) @@ -843,58 +964,62 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) u_int8_t *opt = opthead; u_int16_t rtalert_val; u_int32_t jumboplen; + const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { - switch(*opt) { - case IP6OPT_PAD1: - optlen = 1; - break; - case IP6OPT_PADN: - if (hbhlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - optlen = *(opt + 1) + 2; - break; - case IP6OPT_RTALERT: - /* XXX may need check for alignment */ - if (hbhlen < IP6OPT_RTALERT_LEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) - /* XXX: should we discard the packet? */ - log(LOG_ERR, "length of router alert opt is inconsitent(%d)", - *(opt + 1)); - optlen = IP6OPT_RTALERT_LEN; - bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); - *rtalertp = ntohs(rtalert_val); - break; - case IP6OPT_JUMBO: + switch (*opt) { + case IP6OPT_PAD1: + optlen = 1; + break; + case IP6OPT_PADN: + if (hbhlen < IP6OPT_MINLEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + optlen = *(opt + 1) + 2; + break; + case IP6OPT_RTALERT: + /* XXX may need check for alignment */ + if (hbhlen < IP6OPT_RTALERT_LEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { + /* XXX stat */ + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 1 - opthead); + return(-1); + } + optlen = IP6OPT_RTALERT_LEN; + bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); + *rtalertp = ntohs(rtalert_val); + break; + case IP6OPT_JUMBO: /* XXX may need check for alignment */ if (hbhlen < IP6OPT_JUMBO_LEN) { ip6stat.ip6s_toosmall++; goto bad; } - if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) - /* XXX: should we discard the packet? */ - log(LOG_ERR, "length of jumbopayload opt " - "is inconsistent(%d)", - *(opt + 1)); + if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { + /* XXX stat */ + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 1 - opthead); + return(-1); + } optlen = IP6OPT_JUMBO_LEN; /* * IPv6 packets that have non 0 payload length - * must not contain a jumbo paylod option. + * must not contain a jumbo payload option. */ ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_plen) { ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt - opthead); + erroff + opt - opthead); return(-1); } @@ -918,9 +1043,7 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt + 2 - opthead); + erroff + opt + 2 - opthead); return(-1); } #endif @@ -932,26 +1055,23 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt + 2 - opthead); + erroff + opt + 2 - opthead); return(-1); } *plenp = jumboplen; break; - default: /* unknown option */ - if (hbhlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - if ((optlen = ip6_unknown_opt(opt, m, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt - opthead)) == -1) - return(-1); - optlen += 2; - break; + default: /* unknown option */ + if (hbhlen < IP6OPT_MINLEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + optlen = ip6_unknown_opt(opt, m, + erroff + opt - opthead); + if (optlen == -1) + return(-1); + optlen += 2; + break; } } @@ -976,26 +1096,26 @@ ip6_unknown_opt(optp, m, off) { struct ip6_hdr *ip6; - switch(IP6OPT_TYPE(*optp)) { - case IP6OPT_TYPE_SKIP: /* ignore the option */ - return((int)*(optp + 1)); - case IP6OPT_TYPE_DISCARD: /* silently discard */ - m_freem(m); - return(-1); - case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ - ip6stat.ip6s_badoptions++; - icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); - return(-1); - case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ - ip6stat.ip6s_badoptions++; - ip6 = mtod(m, struct ip6_hdr *); - if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || - (m->m_flags & (M_BCAST|M_MCAST))) - m_freem(m); - else - icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_OPTION, off); - return(-1); + switch (IP6OPT_TYPE(*optp)) { + case IP6OPT_TYPE_SKIP: /* ignore the option */ + return((int)*(optp + 1)); + case IP6OPT_TYPE_DISCARD: /* silently discard */ + m_freem(m); + return(-1); + case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ + ip6stat.ip6s_badoptions++; + icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); + return(-1); + case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ + ip6stat.ip6s_badoptions++; + ip6 = mtod(m, struct ip6_hdr *); + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || + (m->m_flags & (M_BCAST|M_MCAST))) + m_freem(m); + else + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_OPTION, off); + return(-1); } m_freem(m); /* XXX: NOTREACHED */ @@ -1004,50 +1124,44 @@ ip6_unknown_opt(optp, m, off) /* * Create the "control" list for this pcb. + * The function will not modify mbuf chain at all. * + * with KAME mbuf chain restriction: * The routine will be called from upper layer handlers like tcp6_input(). * Thus the routine assumes that the caller (tcp6_input) have already * called IP6_EXTHDR_CHECK() and all the extension headers are located in the * very first mbuf on the mbuf chain. - * We may want to add some infinite loop prevention or sanity checks for safety. - * (This applies only when you are using KAME mbuf chain restriction, i.e. - * you are using IP6_EXTHDR_CHECK() not m_pulldown()) */ void ip6_savecontrol(in6p, mp, ip6, m) - register struct in6pcb *in6p; - register struct mbuf **mp; - register struct ip6_hdr *ip6; - register struct mbuf *m; + struct inpcb *in6p; + struct mbuf **mp; + struct ip6_hdr *ip6; + struct mbuf *m; { struct proc *p = curproc; /* XXX */ - int privileged; + int privileged = 0; + int rthdr_exist = 0; + - privileged = 0; if (p && !suser(p)) - privileged++; + privileged++; - if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { +#ifdef SO_TIMESTAMP + if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) { struct timeval tv; microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), - SCM_TIMESTAMP, SOL_SOCKET); - if (*mp) + SCM_TIMESTAMP, SOL_SOCKET); + if (*mp) { mp = &(*mp)->m_next; + } } - -#ifdef noyet - /* options were tossed above */ - if (in6p->in6p_flags & IN6P_RECVOPTS) - /* broken */ - /* ip6_srcroute doesn't do what we want here, need to fix */ - if (in6p->in6p_flags & IPV6P_RECVRETOPTS) - /* broken */ #endif /* RFC 2292 sec. 5 */ - if (in6p->in6p_flags & IN6P_PKTINFO) { + if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) { struct in6_pktinfo pi6; bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr)) @@ -1061,14 +1175,14 @@ ip6_savecontrol(in6p, mp, ip6, m) if (*mp) mp = &(*mp)->m_next; } - if (in6p->in6p_flags & IN6P_HOPLIMIT) { + + if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) { int hlim = ip6->ip6_hlim & 0xff; *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } - /* IN6P_NEXTHOP - for outgoing packet only */ /* * IPV6_HOPOPTS socket option. We require super-user privilege @@ -1076,7 +1190,7 @@ ip6_savecontrol(in6p, mp, ip6, m) * be some hop-by-hop options which can be returned to normal user. * See RFC 2292 section 6. */ - if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { + if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary @@ -1087,22 +1201,25 @@ ip6_savecontrol(in6p, mp, ip6, m) struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { struct ip6_hbh *hbh; - int hbhlen; + int hbhlen = 0; +#ifdef PULLDOWN_TEST + struct mbuf *ext; +#endif #ifndef PULLDOWN_TEST hbh = (struct ip6_hbh *)(ip6 + 1); hbhlen = (hbh->ip6h_len + 1) << 3; #else - IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, - sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); - if (hbh == NULL) { + ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), + ip6->ip6_nxt); + if (ext == NULL) { ip6stat.ip6s_tooshort++; return; } + hbh = mtod(ext, struct ip6_hbh *); hbhlen = (hbh->ip6h_len + 1) << 3; - IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, - sizeof(struct ip6_hdr), hbhlen); - if (hbh == NULL) { + if (hbhlen != ext->m_len) { + m_freem(ext); ip6stat.ip6s_tooshort++; return; } @@ -1112,19 +1229,53 @@ ip6_savecontrol(in6p, mp, ip6, m) * XXX: We copy whole the header even if a jumbo * payload option is included, which option is to * be removed before returning in the RFC 2292. - * But it's too painful operation... + * Note: this constraint is removed in 2292bis. */ *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, IPV6_HOPOPTS, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; +#ifdef PULLDOWN_TEST + m_freem(ext); +#endif } } /* IPV6_DSTOPTS and IPV6_RTHDR socket options */ - if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) { + if ((in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) { + int proto, off, nxt; + + /* + * go through the header chain to see if a routing header is + * contained in the packet. We need this information to store + * destination options headers (if any) properly. + * XXX: performance issue. We should record this info when + * processing extension headers in incoming routine. + * (todo) use m_aux? + */ + proto = IPPROTO_IPV6; + off = 0; + nxt = -1; + while (1) { + int newoff; + + newoff = ip6_nexthdr(m, off, proto, &nxt); + if (newoff < 0) + break; + if (newoff < off) /* invalid, check for safety */ + break; + if ((proto = nxt) == IPPROTO_ROUTING) { + rthdr_exist = 1; + break; + } + off = newoff; + } + } + + if ((in6p->in6p_flags & + (IN6P_RTHDR | IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);; + int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); /* * Search for destination options headers or routing @@ -1133,95 +1284,172 @@ ip6_savecontrol(in6p, mp, ip6, m) * Note that the order of the headers remains in * the chain of ancillary data. */ - while(1) { /* is explicit loop prevention necessary? */ - struct ip6_ext *ip6e; + while (1) { /* is explicit loop prevention necessary? */ + struct ip6_ext *ip6e = NULL; int elen; +#ifdef PULLDOWN_TEST + struct mbuf *ext = NULL; +#endif + + /* + * if it is not an extension header, don't try to + * pull it from the chain. + */ + switch (nxt) { + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_HOPOPTS: + case IPPROTO_AH: /* is it possible? */ + break; + default: + goto loopend; + } #ifndef PULLDOWN_TEST + if (off + sizeof(*ip6e) > m->m_len) + goto loopend; ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; + if (off + elen > m->m_len) + goto loopend; #else - IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, - sizeof(struct ip6_ext)); - if (ip6e == NULL) { + ext = ip6_pullexthdr(m, off, nxt); + if (ext == NULL) { ip6stat.ip6s_tooshort++; return; } + ip6e = mtod(ext, struct ip6_ext *); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; - IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen); - if (ip6e == NULL) { + if (elen != ext->m_len) { + m_freem(ext); ip6stat.ip6s_tooshort++; return; } #endif - switch(nxt) { - case IPPROTO_DSTOPTS: - if (!in6p->in6p_flags & IN6P_DSTOPTS) - break; - - /* - * We also require super-user privilege for - * the option. - * See the comments on IN6_HOPOPTS. - */ - if (!privileged) - break; - - *mp = sbcreatecontrol((caddr_t)ip6e, elen, - IPV6_DSTOPTS, - IPPROTO_IPV6); - if (*mp) - mp = &(*mp)->m_next; - break; - - case IPPROTO_ROUTING: - if (!in6p->in6p_flags & IN6P_RTHDR) - break; - - *mp = sbcreatecontrol((caddr_t)ip6e, elen, - IPV6_RTHDR, - IPPROTO_IPV6); - if (*mp) - mp = &(*mp)->m_next; - break; - - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMPV6: - default: - /* - * stop search if we encounter an upper - * layer protocol headers. - */ - goto loopend; - - case IPPROTO_HOPOPTS: - case IPPROTO_AH: /* is it possible? */ - break; + switch (nxt) { + case IPPROTO_DSTOPTS: + if ((in6p->in6p_flags & IN6P_DSTOPTS) == 0) + break; + + /* + * We also require super-user privilege for + * the option. + * See the comments on IN6_HOPOPTS. + */ + if (!privileged) + break; + + *mp = sbcreatecontrol((caddr_t)ip6e, elen, + IPV6_DSTOPTS, + IPPROTO_IPV6); + if (*mp) + mp = &(*mp)->m_next; + break; + case IPPROTO_ROUTING: + if (!in6p->in6p_flags & IN6P_RTHDR) + break; + + *mp = sbcreatecontrol((caddr_t)ip6e, elen, + IPV6_RTHDR, + IPPROTO_IPV6); + if (*mp) + mp = &(*mp)->m_next; + break; + case IPPROTO_HOPOPTS: + case IPPROTO_AH: /* is it possible? */ + break; + + default: + /* + * other cases have been filtered in the above. + * none will visit this case. here we supply + * the code just in case (nxt overwritten or + * other cases). + */ +#ifdef PULLDOWN_TEST + m_freem(ext); +#endif + goto loopend; + } /* proceed with the next header. */ off += elen; nxt = ip6e->ip6e_nxt; + ip6e = NULL; +#ifdef PULLDOWN_TEST + m_freem(ext); + ext = NULL; +#endif } loopend: + ; } - if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { - /* to be done */ + +} + +#ifdef PULLDOWN_TEST +/* + * pull single extension header from mbuf chain. returns single mbuf that + * contains the result, or NULL on error. + */ +static struct mbuf * +ip6_pullexthdr(m, off, nxt) + struct mbuf *m; + size_t off; + int nxt; +{ + struct ip6_ext ip6e; + size_t elen; + struct mbuf *n; + +#ifdef DIAGNOSTIC + switch (nxt) { + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_HOPOPTS: + case IPPROTO_AH: /* is it possible? */ + break; + default: + printf("ip6_pullexthdr: invalid nxt=%d\n", nxt); + } +#endif + + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxt == IPPROTO_AH) + elen = (ip6e.ip6e_len + 2) << 2; + else + elen = (ip6e.ip6e_len + 1) << 3; + + MGET(n, M_DONTWAIT, MT_DATA); + if (n && elen >= MLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } } - if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) { - /* to be done */ + if (!n) + return NULL; + + n->m_len = 0; + if (elen >= M_TRAILINGSPACE(n)) { + m_free(n); + return NULL; } - /* IN6P_RTHDR - to be done */ + m_copydata(m, off, elen, mtod(n, caddr_t)); + n->m_len = elen; + return n; } +#endif /* * Get pointer to the previous header followed by the header @@ -1253,7 +1481,7 @@ ip6_get_prevhdr(m, off) while (len < off) { ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); - switch(nxt) { + switch (nxt) { case IPPROTO_FRAGMENT: len += sizeof(struct ip6_frag); break; @@ -1382,6 +1610,55 @@ ip6_lasthdr(m, off, proto, nxtp) } } +struct mbuf * +ip6_addaux(m) + struct mbuf *m; +{ + struct mbuf *n; + +#ifdef DIAGNOSTIC + if (sizeof(struct ip6aux) > MHLEN) + panic("assumption failed on sizeof(ip6aux)"); +#endif + n = m_aux_find(m, AF_INET6, -1); + if (n) { + if (n->m_len < sizeof(struct ip6aux)) { + printf("conflicting use of ip6aux"); + return NULL; + } + } else { + n = m_aux_add(m, AF_INET6, -1); + n->m_len = sizeof(struct ip6aux); + bzero(mtod(n, caddr_t), n->m_len); + } + return n; +} + +struct mbuf * +ip6_findaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET6, -1); + if (n && n->m_len < sizeof(struct ip6aux)) { + printf("conflicting use of ip6aux"); + n = NULL; + } + return n; +} + +void +ip6_delaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET6, -1); + if (n) + m_aux_delete(m, n); +} + /* * System control for IP6 */ diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 82b0d4b..2be8796 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_mroute.c,v 1.33 2000/10/19 02:23:43 jinmei Exp $ */ +/* $KAME: ip6_mroute.c,v 1.46 2001/04/04 05:17:30 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -50,6 +50,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/callout.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> @@ -143,7 +144,6 @@ static mifi_t nummifs = 0; static mifi_t reg_mif_num = (mifi_t)-1; static struct pim6stat pim6stat; -static struct callout_handle expire_upcalls_ch; /* * one-back cache used by ipip_input to locate a tunnel's mif @@ -165,7 +165,7 @@ static int pim6; */ #define MF6CFIND(o, g, rt) do { \ - register struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \ + struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \ rt = NULL; \ mrt6stat.mrt6s_mfc_lookups++; \ while (_rt) { \ @@ -187,7 +187,7 @@ static int pim6; * Borrowed from Van Jacobson's scheduling code */ #define TV_DELTA(a, b, delta) do { \ - register int xxs; \ + int xxs; \ \ delta = (a).tv_usec - (b).tv_usec; \ if ((xxs = (a).tv_sec - (b).tv_sec)) { \ @@ -221,6 +221,8 @@ static int del_m6if __P((mifi_t *)); static int add_m6fc __P((struct mf6cctl *)); static int del_m6fc __P((struct mf6cctl *)); +static struct callout expire_upcalls_ch; + /* * Handle MRT setsockopt commands to modify the multicast routing tables. */ @@ -241,33 +243,33 @@ ip6_mrouter_set(so, sopt) return (error); switch (sopt->sopt_name) { - case MRT6_INIT: + case MRT6_INIT: #ifdef MRT6_OINIT - case MRT6_OINIT: + case MRT6_OINIT: #endif - error = ip6_mrouter_init(so, m, sopt->sopt_name); - break; - case MRT6_DONE: - error = ip6_mrouter_done(); - break; - case MRT6_ADD_MIF: - error = add_m6if(mtod(m, struct mif6ctl *)); - break; - case MRT6_DEL_MIF: - error = del_m6if(mtod(m, mifi_t *)); - break; - case MRT6_ADD_MFC: - error = add_m6fc(mtod(m, struct mf6cctl *)); - break; - case MRT6_DEL_MFC: - error = del_m6fc(mtod(m, struct mf6cctl *)); - break; - case MRT6_PIM: - error = set_pim6(mtod(m, int *)); - break; - default: - error = EOPNOTSUPP; - break; + error = ip6_mrouter_init(so, m, sopt->sopt_name); + break; + case MRT6_DONE: + error = ip6_mrouter_done(); + break; + case MRT6_ADD_MIF: + error = add_m6if(mtod(m, struct mif6ctl *)); + break; + case MRT6_DEL_MIF: + error = del_m6if(mtod(m, mifi_t *)); + break; + case MRT6_ADD_MFC: + error = add_m6fc(mtod(m, struct mf6cctl *)); + break; + case MRT6_DEL_MFC: + error = del_m6fc(mtod(m, struct mf6cctl *)); + break; + case MRT6_PIM: + error = set_pim6(mtod(m, int *)); + break; + default: + error = EOPNOTSUPP; + break; } (void)m_freem(m); @@ -302,20 +304,20 @@ mrt6_ioctl(cmd, data) int cmd; caddr_t data; { - int error = 0; - - switch (cmd) { - case SIOCGETSGCNT_IN6: - return(get_sg_cnt((struct sioc_sg_req6 *)data)); - break; /* for safety */ - case SIOCGETMIFCNT_IN6: - return(get_mif6_cnt((struct sioc_mif_req6 *)data)); - break; /* for safety */ - default: - return (EINVAL); - break; - } - return error; + int error = 0; + + switch (cmd) { + case SIOCGETSGCNT_IN6: + return(get_sg_cnt((struct sioc_sg_req6 *)data)); + break; /* for safety */ + case SIOCGETMIFCNT_IN6: + return(get_mif6_cnt((struct sioc_mif_req6 *)data)); + break; /* for safety */ + default: + return (EINVAL); + break; + } + return error; } /* @@ -323,9 +325,9 @@ mrt6_ioctl(cmd, data) */ static int get_sg_cnt(req) - register struct sioc_sg_req6 *req; + struct sioc_sg_req6 *req; { - register struct mf6c *rt; + struct mf6c *rt; int s; s = splnet(); @@ -349,9 +351,9 @@ get_sg_cnt(req) */ static int get_mif6_cnt(req) - register struct sioc_mif_req6 *req; + struct sioc_mif_req6 *req; { - register mifi_t mifi = req->mifi; + mifi_t mifi = req->mifi; if (mifi >= nummifs) return EINVAL; @@ -415,8 +417,8 @@ ip6_mrouter_init(so, m, cmd) pim6 = 0;/* used for stubbing out/in pim stuff */ - expire_upcalls_ch = - timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); + callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, + expire_upcalls, NULL); #ifdef MRT6DEBUG if (mrt6debug) @@ -478,7 +480,7 @@ ip6_mrouter_done() pim6 = 0; /* used to stub out/in pim specific code */ - untimeout(expire_upcalls, (caddr_t)NULL, expire_upcalls_ch); + callout_stop(&expire_upcalls_ch); /* * Free all multicast forwarding cache entries. @@ -528,9 +530,9 @@ static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; */ static int add_m6if(mifcp) - register struct mif6ctl *mifcp; + struct mif6ctl *mifcp; { - register struct mif6 *mifp; + struct mif6 *mifp; struct ifnet *ifp; int error, s; #ifdef notyet @@ -605,8 +607,8 @@ static int del_m6if(mifip) mifi_t *mifip; { - register struct mif6 *mifp = mif6table + *mifip; - register mifi_t mifi; + struct mif6 *mifp = mif6table + *mifip; + mifi_t mifi; struct ifnet *ifp; int s; @@ -659,7 +661,7 @@ add_m6fc(mfccp) struct mf6c *rt; u_long hash; struct rtdetq *rte; - register u_short nstl; + u_short nstl; int s; MF6CFIND(mfccp->mf6cc_origin.sin6_addr, @@ -809,11 +811,11 @@ add_m6fc(mfccp) */ static void collate(t) - register struct timeval *t; + struct timeval *t; { - register u_long d; - register struct timeval tp; - register u_long delta; + u_long d; + struct timeval tp; + u_long delta; GET_TIME(tp); @@ -912,13 +914,13 @@ socket_send(s, mm, src) int ip6_mforward(ip6, ifp, m) - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; struct ifnet *ifp; struct mbuf *m; { - register struct mf6c *rt; - register struct mif6 *mifp; - register struct mbuf *mm; + struct mf6c *rt; + struct mif6 *mifp; + struct mbuf *mm; int s; mifi_t mifi; @@ -977,10 +979,10 @@ ip6_mforward(ip6, ifp, m) * send message to routing daemon */ - register struct mbuf *mb0; - register struct rtdetq *rte; - register u_long hash; -/* register int i, npkts;*/ + struct mbuf *mb0; + struct rtdetq *rte; + u_long hash; +/* int i, npkts;*/ #ifdef UPCALL_TIMING struct timeval tp; @@ -1144,7 +1146,7 @@ ip6_mforward(ip6, ifp, m) } else { /* determine if q has overflowed */ struct rtdetq **p; - register int npkts = 0; + int npkts = 0; for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next) if (++npkts > MAX_UPQ6) { @@ -1227,8 +1229,8 @@ expire_upcalls(unused) } } splx(s); - expire_upcalls_ch = - timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); + callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, + expire_upcalls, NULL); } /* @@ -1236,14 +1238,14 @@ expire_upcalls(unused) */ static int ip6_mdq(m, ifp, rt) - register struct mbuf *m; - register struct ifnet *ifp; - register struct mf6c *rt; + struct mbuf *m; + struct ifnet *ifp; + struct mf6c *rt; { - register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - register mifi_t mifi, iif; - register struct mif6 *mifp; - register int plen = m->m_pkthdr.len; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + mifi_t mifi, iif; + struct mif6 *mifp; + int plen = m->m_pkthdr.len; /* * Macro to send packet on mif. Since RSVP packets don't get counted on @@ -1290,7 +1292,7 @@ ip6_mdq(m, ifp, rt) static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; - register struct mbuf *mm; + struct mbuf *mm; struct mrt6msg *im; #ifdef MRT6_OINIT struct omrt6msg *oim; @@ -1319,6 +1321,7 @@ ip6_mdq(m, ifp, rt) case MRT6_INIT: im = mtod(mm, struct mrt6msg *); im->im6_msgtype = MRT6MSG_WRONGMIF; + im->im6_mbz = 0; break; default: m_freem(mm); @@ -1408,12 +1411,13 @@ phyint_send(ip6, mifp, m) struct mif6 *mifp; struct mbuf *m; { - register struct mbuf *mb_copy; + struct mbuf *mb_copy; struct ifnet *ifp = mifp->m6_ifp; int error = 0; - int s = splnet(); - static struct route_in6 ro6; + int s = splnet(); /* needs to protect static "ro" below. */ + static struct route_in6 ro; struct in6_multi *in6m; + struct sockaddr_in6 *dst6; /* * Make a new reference to the packet; make sure that @@ -1424,8 +1428,10 @@ phyint_send(ip6, mifp, m) if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr))) mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr)); - if (mb_copy == NULL) + if (mb_copy == NULL) { + splx(s); return; + } /* set MCAST flag to the outgoing packet */ mb_copy->m_flags |= M_MCAST; @@ -1443,7 +1449,7 @@ phyint_send(ip6, mifp, m) /* XXX: ip6_output will override ip6->ip6_hlim */ im6o.im6o_multicast_hlim = ip6->ip6_hlim; im6o.im6o_multicast_loop = 1; - error = ip6_output(mb_copy, NULL, &ro6, + error = ip6_output(mb_copy, NULL, &ro, IPV6_FORWARDING, &im6o, NULL); #ifdef MRT6DEBUG @@ -1459,63 +1465,62 @@ phyint_send(ip6, mifp, m) * If we belong to the destination multicast group * on the outgoing interface, loop back a copy. */ + dst6 = (struct sockaddr_in6 *)&ro.ro_dst; IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m); if (in6m != NULL) { - ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro6.ro_dst.sin6_family = AF_INET6; - ro6.ro_dst.sin6_addr = ip6->ip6_dst; - ip6_mloopback(ifp, m, &ro6.ro_dst); + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; + ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst); } /* * Put the packet into the sending queue of the outgoing interface * if it would fit in the MTU of the interface. */ if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) { - ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro6.ro_dst.sin6_family = AF_INET6; - ro6.ro_dst.sin6_addr = ip6->ip6_dst; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; /* * We just call if_output instead of nd6_output here, since * we need no ND for a multicast forwarded packet...right? */ error = (*ifp->if_output)(ifp, mb_copy, - (struct sockaddr *)&ro6.ro_dst, - NULL); + (struct sockaddr *)&ro.ro_dst, NULL); #ifdef MRT6DEBUG if (mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, "phyint_send on mif %d err %d\n", mifp - mif6table, error); #endif - } - else { + } else { #ifdef MULTICAST_PMTUD icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); - return; #else #ifdef MRT6DEBUG if (mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, - "phyint_send: packet too big on %s%u o %s g %s" + "phyint_send: packet too big on %s o %s g %s" " size %d(discarded)\n", - ifp->if_name, ifp->if_unit, + if_name(ifp), ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), mb_copy->m_pkthdr.len); #endif /* MRT6DEBUG */ m_freem(mb_copy); /* simply discard the packet */ - return; #endif } + + splx(s); } static int register_send(ip6, mif, m) - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; struct mif6 *mif; - register struct mbuf *m; + struct mbuf *m; { - register struct mbuf *mm; - register int i, len = m->m_pkthdr.len; + struct mbuf *mm; + int i, len = m->m_pkthdr.len; static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; struct mrt6msg *im6; @@ -1530,6 +1535,7 @@ register_send(ip6, mif, m) MGETHDR(mm, M_DONTWAIT, MT_HEADER); if (mm == NULL) return ENOBUFS; + mm->m_pkthdr.rcvif = NULL; mm->m_data += max_linkhdr; mm->m_len = sizeof(struct ip6_hdr); @@ -1568,8 +1574,8 @@ register_send(ip6, mif, m) log(LOG_WARNING, "register_send: ip_mrouter socket queue full\n"); #endif - ++mrt6stat.mrt6s_upq_sockfull; - return ENOBUFS; + ++mrt6stat.mrt6s_upq_sockfull; + return ENOBUFS; } return 0; } @@ -1586,21 +1592,21 @@ pim6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto; { - register struct pim *pim; /* pointer to a pim struct */ - register struct ip6_hdr *ip6; - register int pimlen; + struct pim *pim; /* pointer to a pim struct */ + struct ip6_hdr *ip6; + int pimlen; struct mbuf *m = *mp; - int minlen; + int minlen; int off = *offp; ++pim6stat.pim6s_rcv_total; - ip6 = mtod(m, struct ip6_hdr *); - pimlen = m->m_pkthdr.len - *offp; + ip6 = mtod(m, struct ip6_hdr *); + pimlen = m->m_pkthdr.len - *offp; - /* - * Validate lengths - */ + /* + * Validate lengths + */ if (pimlen < PIM_MINLEN) { ++pim6stat.pim6s_rcv_tooshort; #ifdef MRT6DEBUG @@ -1736,6 +1742,18 @@ pim6_input(mp, offp, proto) ip6_sprintf(&eip6->ip6_dst), ntohs(eip6->ip6_plen)); #endif + + /* verify the version number of the inner packet */ + if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + ++pim6stat.pim6s_rcv_badregisters; +#ifdef MRT6DEBUG + log(LOG_DEBUG, "pim6_input: invalid IP version (%d) " + "of the inner packet\n", + (eip6->ip6_vfc & IPV6_VERSION)); +#endif + m_freem(m); + return(IPPROTO_NONE); + } /* verify the inner packet is destined to a mcast group */ if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) { @@ -1781,7 +1799,7 @@ pim6_input(mp, offp, proto) #endif rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, - dst.sin6_family, NULL); + dst.sin6_family, NULL); /* prepare the register head to send to the mrouting daemon */ m = mcp; diff --git a/sys/netinet6/ip6_mroute.h b/sys/netinet6/ip6_mroute.h index 34ec538..7871150 100644 --- a/sys/netinet6/ip6_mroute.h +++ b/sys/netinet6/ip6_mroute.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_mroute.h,v 1.10 2000/05/19 02:38:53 itojun Exp $ */ +/* $KAME: ip6_mroute.h,v 1.17 2001/02/10 02:05:52 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -79,7 +79,7 @@ typedef u_short mifi_t; /* type of a mif index */ #define IF_SETSIZE 256 #endif -typedef long if_mask; +typedef u_int32_t if_mask; #define NIFBITS (sizeof(if_mask) * NBBY) /* bits per mask */ #ifndef howmany @@ -87,7 +87,7 @@ typedef long if_mask; #endif typedef struct if_set { - fd_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)]; + if_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)]; } if_set; #define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS))) diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 4176bc4..928f3d3 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_output.c,v 1.115 2000/07/03 13:23:28 itojun Exp $ */ +/* $KAME: ip6_output.c,v 1.180 2001/05/21 05:37:50 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -89,6 +89,7 @@ #include <netinet/in.h> #include <netinet/in_var.h> +#include <netinet6/in6_var.h> #include <netinet/ip6.h> #include <netinet/icmp6.h> #include <netinet6/ip6_var.h> @@ -103,10 +104,10 @@ #include <netkey/key.h> #endif /* IPSEC */ -#include <net/net_osdep.h> - #include <netinet6/ip6_fw.h> +#include <net/net_osdep.h> + #include <netinet6/ip6protosw.h> static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options"); @@ -138,6 +139,22 @@ extern u_char ip6_protox[IPPROTO_MAX]; * This function may modify ver and hlim only. * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. + * + * type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and + * nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one, + * which is rt_rmx.rmx_mtu. + * + * If MIP6 is active it will have to add a Home Address option to DH1 if + * the mobile node is roaming or a Routing Header type 0 if there exist + * a Binding Cache entry for the destination node or a BU option to DH2 + * if the mobile node initiates communication and no BUL entry exist. + * The only way to do this is to allocate new memory, copy the user data + * to the new buffer and then add the Home Address option, BU option and + * routing header type 0 respectively. MIP6 will set two flags in "struct + * pktopts" to restore the original contents once ip6_output is completed. + * To make this work, make sure that function exit is made through label + * alldone. + * */ int ip6_output(m0, opt, ro, flags, im6o, ifpp) @@ -175,7 +192,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) /* for AH processing. stupid to have "socket" variable in IP layer... */ so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); ip6 = mtod(m, struct ip6_hdr *); #endif /* IPSEC */ @@ -419,13 +436,13 @@ skip_ipsec2:; struct ip6_rthdr0 *rh0; finaldst = ip6->ip6_dst; - switch(rh->ip6r_type) { + switch (rh->ip6r_type) { case IPV6_RTHDR_TYPE_0: rh0 = (struct ip6_rthdr0 *)rh; ip6->ip6_dst = rh0->ip6r0_addr[0]; bcopy((caddr_t)&rh0->ip6r0_addr[1], - (caddr_t)&rh0->ip6r0_addr[0], - sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1) + (caddr_t)&rh0->ip6r0_addr[0], + sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1) ); rh0->ip6r0_addr[rh0->ip6r0_segleft - 1] = finaldst; break; @@ -745,7 +762,7 @@ skip_ipsec2:; u_int32_t ifmtu = nd_ifinfo[ifp->if_index].linkmtu; mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu; - if (mtu > ifmtu) { + if (mtu > ifmtu || mtu == 0) { /* * The MTU on the route is larger than the MTU on * the interface! This shouldn't happen, unless the @@ -753,6 +770,9 @@ skip_ipsec2:; * interface was brought up. Change the MTU in the * route to match the interface MTU (as long as the * field isn't locked). + * + * if MTU on the route is 0, we need to fix the MTU. + * this case happens with path MTU discovery timeouts. */ mtu = ifmtu; if ((ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0) @@ -762,6 +782,12 @@ skip_ipsec2:; mtu = nd_ifinfo[ifp->if_index].linkmtu; } + /* + * advanced API (IPV6_USE_MIN_MTU) overrides mtu setting + */ + if ((flags & IPV6_MINMTU) != 0 && mtu > IPV6_MMTU) + mtu = IPV6_MMTU; + /* Fake scoped addresses */ if ((ifp->if_flags & IFF_LOOPBACK) != 0) { /* @@ -776,34 +802,44 @@ skip_ipsec2:; * field of the structure here. * We rely on the consistency between two scope zone ids * of source add destination, which should already be assured - * Larger scopes than link will be supported in the near + * larger scopes than link will be supported in the near * future. */ + origifp = NULL; if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])]; else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])]; - else + /* + * XXX: origifp can be NULL even in those two cases above. + * For example, if we remove the (only) link-local address + * from the loopback interface, and try to send a link-local + * address without link-id information. Then the source + * address is ::1, and the destination address is the + * link-local address with its s6_addr16[1] being zero. + * What is worse, if the packet goes to the loopback interface + * by a default rejected route, the null pointer would be + * passed to looutput, and the kernel would hang. + * The following last resort would prevent such disaster. + */ + if (origifp == NULL) origifp = ifp; } else origifp = ifp; -#ifndef FAKE_LOOPBACK_IF - if ((ifp->if_flags & IFF_LOOPBACK) == 0) -#else - if (1) +#ifndef SCOPEDROUTING + /* + * clear embedded scope identifiers if necessary. + * in6_clearscope will touch the addresses only when necessary. + */ + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); #endif - { - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - ip6->ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] = 0; - } /* * Check with the firewall... */ - if (ip6_fw_enable && ip6_fw_chk_ptr) { + if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; m->m_pkthdr.rcvif = NULL; /*XXX*/ /* If ipfw says divert, we have to just drop packet */ @@ -823,11 +859,14 @@ skip_ipsec2:; * (RFC 2460, section 4.) */ if (exthdrs.ip6e_hbh) { - struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, - struct ip6_hbh *); + struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *); u_int32_t dummy1; /* XXX unused */ u_int32_t dummy2; /* XXX unused */ +#ifdef DIAGNOSTIC + if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len) + panic("ip6e_hbh is not continuous"); +#endif /* * XXX: if we have to send an ICMPv6 error to the sender, * we need the M_LOOP flag since icmp6_error() expects @@ -889,12 +928,15 @@ skip_ipsec2:; #endif ) { - /* Record statistics for this interface address. */ - if (ia && !(flags & IPV6_FORWARDING)) { - ia->ia_ifa.if_opackets++; - ia->ia_ifa.if_obytes += m->m_pkthdr.len; - } - + /* Record statistics for this interface address. */ + if (ia && !(flags & IPV6_FORWARDING)) { + ia->ia_ifa.if_opackets++; + ia->ia_ifa.if_obytes += m->m_pkthdr.len; + } +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); +#endif error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); goto done; } else if (mtu < IPV6_MMTU) { @@ -923,6 +965,7 @@ skip_ipsec2:; hlen = unfragpartlen; if (mtu > IPV6_MAXPACKET) mtu = IPV6_MAXPACKET; + len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7; if (len < 8) { error = EMSGSIZE; @@ -962,6 +1005,7 @@ skip_ipsec2:; ip6stat.ip6s_odropped++; goto sendorfree; } + m->m_pkthdr.rcvif = NULL; m->m_flags = m0->m_flags & M_COPYFLAGS; *mnext = m; mnext = &m->m_nextpkt; @@ -1011,12 +1055,15 @@ sendorfree: m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) { - /* Record statistics for this interface address. */ - if (ia) { - ia->ia_ifa.if_opackets++; - ia->ia_ifa.if_obytes += m->m_pkthdr.len; - } - + /* Record statistics for this interface address. */ + if (ia) { + ia->ia_ifa.if_opackets++; + ia->ia_ifa.if_obytes += m->m_pkthdr.len; + } +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); +#endif error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); } else m_freem(m); @@ -1090,6 +1137,7 @@ ip6_insert_jumboopt(exthdrs, plen) { struct mbuf *mopt; u_char *optbuf; + u_int32_t v; #define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */ @@ -1112,18 +1160,42 @@ ip6_insert_jumboopt(exthdrs, plen) mopt = exthdrs->ip6e_hbh; if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) { - caddr_t oldoptp = mtod(mopt, caddr_t); + /* + * XXX assumption: + * - exthdrs->ip6e_hbh is not referenced from places + * other than exthdrs. + * - exthdrs->ip6e_hbh is not an mbuf chain. + */ int oldoptlen = mopt->m_len; + struct mbuf *n; - if (mopt->m_flags & M_EXT) - return(ENOBUFS); /* XXX */ - MCLGET(mopt, M_DONTWAIT); - if ((mopt->m_flags & M_EXT) == 0) + /* + * XXX: give up if the whole (new) hbh header does + * not fit even in an mbuf cluster. + */ + if (oldoptlen + JUMBOOPTLEN > MCLBYTES) return(ENOBUFS); - bcopy(oldoptp, mtod(mopt, caddr_t), oldoptlen); - optbuf = mtod(mopt, caddr_t) + oldoptlen; - mopt->m_len = oldoptlen + JUMBOOPTLEN; + /* + * As a consequence, we must always prepare a cluster + * at this point. + */ + MGET(n, M_DONTWAIT, MT_DATA); + if (n) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } + } + if (!n) + return(ENOBUFS); + n->m_len = oldoptlen + JUMBOOPTLEN; + bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t), + oldoptlen); + optbuf = mtod(n, caddr_t) + oldoptlen; + m_freem(mopt); + mopt = exthdrs->ip6e_hbh = n; } else { optbuf = mtod(mopt, u_char *) + mopt->m_len; mopt->m_len += JUMBOOPTLEN; @@ -1142,7 +1214,8 @@ ip6_insert_jumboopt(exthdrs, plen) /* fill in the option. */ optbuf[2] = IP6OPT_JUMBO; optbuf[3] = 4; - *(u_int32_t *)&optbuf[4] = htonl(plen + JUMBOOPTLEN); + v = (u_int32_t)htonl(plen + JUMBOOPTLEN); + bcopy(&v, &optbuf[4], sizeof(u_int32_t)); /* finally, adjust the packet header length */ exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN; @@ -1206,7 +1279,7 @@ ip6_ctloutput(so, sopt) struct sockopt *sopt; { int privileged; - register struct inpcb *in6p = sotoinpcb(so); + struct inpcb *in6p = sotoinpcb(so); int error, optval; int level, op, optname; int optlen; @@ -1227,93 +1300,131 @@ ip6_ctloutput(so, sopt) if (level == IPPROTO_IPV6) { switch (op) { + case SOPT_SET: switch (optname) { case IPV6_PKTOPTIONS: - { + { struct mbuf *m; error = soopt_getm(sopt, &m); /* XXX */ - if (error != 0) + if (error != NULL) break; error = soopt_mcopyin(sopt, m); /* XXX */ - if (error != 0) - break; - return (ip6_pcbopts(&in6p->in6p_outputopts, - m, so, sopt)); - } - case IPV6_HOPOPTS: - case IPV6_DSTOPTS: - if (!privileged) { - error = EPERM; + if (error != NULL) break; - } - /* fall through */ + error = ip6_pcbopts(&in6p->in6p_outputopts, + m, so, sopt); + m_freem(m); /* XXX */ + break; + } + + /* + * Use of some Hop-by-Hop options or some + * Destination options, might require special + * privilege. That is, normal applications + * (without special privilege) might be forbidden + * from setting certain options in outgoing packets, + * and might never see certain options in received + * packets. [RFC 2292 Section 6] + * KAME specific note: + * KAME prevents non-privileged users from sending or + * receiving ANY hbh/dst options in order to avoid + * overhead of parsing options in the kernel. + */ case IPV6_UNICAST_HOPS: - case IPV6_PKTINFO: - case IPV6_HOPLIMIT: - case IPV6_RTHDR: case IPV6_CHECKSUM: case IPV6_FAITH: - case IPV6_BINDV6ONLY: - if (optlen != sizeof(int)) + + case IPV6_V6ONLY: + if (optlen != sizeof(int)) { error = EINVAL; - else { - error = sooptcopyin(sopt, &optval, - sizeof optval, sizeof optval); - if (error) - break; - switch (optname) { - - case IPV6_UNICAST_HOPS: - if (optval < -1 || optval >= 256) - error = EINVAL; - else { - /* -1 = kernel default */ - in6p->in6p_hops = optval; - if ((in6p->in6p_vflag & - INP_IPV4) != 0) - in6p->inp_ip_ttl = optval; - } - break; + break; + } + error = sooptcopyin(sopt, &optval, + sizeof optval, sizeof optval); + if (error) + break; + switch (optname) { + + case IPV6_UNICAST_HOPS: + if (optval < -1 || optval >= 256) + error = EINVAL; + else { + /* -1 = kernel default */ + in6p->in6p_hops = optval; + + if ((in6p->in6p_vflag & + INP_IPV4) != 0) + in6p->inp_ip_ttl = optval; + } + break; #define OPTSET(bit) \ +do { \ if (optval) \ - in6p->in6p_flags |= bit; \ + in6p->in6p_flags |= (bit); \ else \ - in6p->in6p_flags &= ~bit; - - case IPV6_PKTINFO: - OPTSET(IN6P_PKTINFO); - break; - - case IPV6_HOPLIMIT: - OPTSET(IN6P_HOPLIMIT); - break; - - case IPV6_HOPOPTS: - OPTSET(IN6P_HOPOPTS); - break; - - case IPV6_DSTOPTS: - OPTSET(IN6P_DSTOPTS); - break; + in6p->in6p_flags &= ~(bit); \ +} while (0) +#define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0) - case IPV6_RTHDR: - OPTSET(IN6P_RTHDR); - break; + case IPV6_CHECKSUM: + in6p->in6p_cksum = optval; + break; - case IPV6_CHECKSUM: - in6p->in6p_cksum = optval; - break; + case IPV6_FAITH: + OPTSET(IN6P_FAITH); + break; - case IPV6_FAITH: - OPTSET(IN6P_FAITH); - break; + case IPV6_V6ONLY: + /* + * XXX: BINDV6ONLY should be integrated + * into V6ONLY. + */ + OPTSET(IN6P_BINDV6ONLY); + OPTSET(IN6P_IPV6_V6ONLY); + break; + } + break; - case IPV6_BINDV6ONLY: - OPTSET(IN6P_BINDV6ONLY); - break; - } + case IPV6_PKTINFO: + case IPV6_HOPLIMIT: + case IPV6_HOPOPTS: + case IPV6_DSTOPTS: + case IPV6_RTHDR: + /* RFC 2292 */ + if (optlen != sizeof(int)) { + error = EINVAL; + break; + } + error = sooptcopyin(sopt, &optval, + sizeof optval, sizeof optval); + if (error) + break; + switch (optname) { + case IPV6_PKTINFO: + OPTSET(IN6P_PKTINFO); + break; + case IPV6_HOPLIMIT: + OPTSET(IN6P_HOPLIMIT); + break; + case IPV6_HOPOPTS: + /* + * Check super-user privilege. + * See comments for IPV6_RECVHOPOPTS. + */ + if (!privileged) + return(EPERM); + OPTSET(IN6P_HOPOPTS); + break; + case IPV6_DSTOPTS: + if (!privileged) + return(EPERM); + OPTSET(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */ + break; + case IPV6_RTHDR: + OPTSET(IN6P_RTHDR); + break; } break; #undef OPTSET @@ -1393,7 +1504,7 @@ ip6_ctloutput(so, sopt) m_freem(m); } break; -#endif /* IPSEC */ +#endif /* KAME IPSEC */ case IPV6_FW_ADD: case IPV6_FW_DEL: @@ -1405,11 +1516,9 @@ ip6_ctloutput(so, sopt) if (ip6_fw_ctl_ptr == NULL) return EINVAL; - if ((error = soopt_getm(sopt, &m)) - != 0) /* XXX */ + if (error = soopt_getm(sopt, &m)) /* XXX */ break; - if ((error = soopt_mcopyin(sopt, m)) - != 0) /* XXX */ + if (error = soopt_mcopyin(sopt, m)) /* XXX */ break; error = (*ip6_fw_ctl_ptr)(optname, mp); m = *mp; @@ -1433,20 +1542,11 @@ ip6_ctloutput(so, sopt) sopt->sopt_valsize = 0; break; - case IPV6_HOPOPTS: - case IPV6_DSTOPTS: - if (!privileged) { - error = EPERM; - break; - } - /* fall through */ case IPV6_UNICAST_HOPS: - case IPV6_PKTINFO: - case IPV6_HOPLIMIT: - case IPV6_RTHDR: case IPV6_CHECKSUM: + case IPV6_FAITH: - case IPV6_BINDV6ONLY: + case IPV6_V6ONLY: case IPV6_PORTRANGE: switch (optname) { @@ -1454,28 +1554,6 @@ ip6_ctloutput(so, sopt) optval = in6p->in6p_hops; break; -#define OPTBIT(bit) (in6p->in6p_flags & bit ? 1 : 0) - - case IPV6_PKTINFO: - optval = OPTBIT(IN6P_PKTINFO); - break; - - case IPV6_HOPLIMIT: - optval = OPTBIT(IN6P_HOPLIMIT); - break; - - case IPV6_HOPOPTS: - optval = OPTBIT(IN6P_HOPOPTS); - break; - - case IPV6_DSTOPTS: - optval = OPTBIT(IN6P_DSTOPTS); - break; - - case IPV6_RTHDR: - optval = OPTBIT(IN6P_RTHDR); - break; - case IPV6_CHECKSUM: optval = in6p->in6p_cksum; break; @@ -1484,14 +1562,14 @@ ip6_ctloutput(so, sopt) optval = OPTBIT(IN6P_FAITH); break; - case IPV6_BINDV6ONLY: + case IPV6_V6ONLY: + /* XXX: see the setopt case. */ optval = OPTBIT(IN6P_BINDV6ONLY); break; case IPV6_PORTRANGE: { int flags; - flags = in6p->in6p_flags; if (flags & IN6P_HIGHPORT) optval = IPV6_PORTRANGE_HIGH; @@ -1506,6 +1584,40 @@ ip6_ctloutput(so, sopt) sizeof optval); break; + case IPV6_PKTINFO: + case IPV6_HOPLIMIT: + case IPV6_HOPOPTS: + case IPV6_RTHDR: + case IPV6_DSTOPTS: + if (optname == IPV6_HOPOPTS || + optname == IPV6_DSTOPTS || + !privileged) + return(EPERM); + switch (optname) { + case IPV6_PKTINFO: + optval = OPTBIT(IN6P_PKTINFO); + break; + case IPV6_HOPLIMIT: + optval = OPTBIT(IN6P_HOPLIMIT); + break; + case IPV6_HOPOPTS: + if (!privileged) + return(EPERM); + optval = OPTBIT(IN6P_HOPOPTS); + break; + case IPV6_RTHDR: + optval = OPTBIT(IN6P_RTHDR); + break; + case IPV6_DSTOPTS: + if (!privileged) + return(EPERM); + optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); + break; + } + error = sooptcopyout(sopt, &optval, + sizeof optval); + break; + case IPV6_MULTICAST_IF: case IPV6_MULTICAST_HOPS: case IPV6_MULTICAST_LOOP: @@ -1543,10 +1655,11 @@ ip6_ctloutput(so, sopt) error = ipsec6_get_policy(in6p, req, len, mp); if (error == 0) error = soopt_mcopyout(sopt, m); /*XXX*/ - m_freem(m); + if (error == 0 && m) + m_freem(m); break; } -#endif /* IPSEC */ +#endif /* KAME IPSEC */ case IPV6_FW_GET: { @@ -1555,6 +1668,8 @@ ip6_ctloutput(so, sopt) if (ip6_fw_ctl_ptr == NULL) { + if (m) + (void)m_free(m); return EINVAL; } error = (*ip6_fw_ctl_ptr)(optname, mp); @@ -1578,29 +1693,33 @@ ip6_ctloutput(so, sopt) } /* - * Set up IP6 options in pcb for insertion in output packets. - * Store in mbuf with pointer in pcbopt, adding pseudo-option - * with destination address if source routed. + * Set up IP6 options in pcb for insertion in output packets or + * specifying behavior of outgoing packets. */ static int ip6_pcbopts(pktopt, m, so, sopt) struct ip6_pktopts **pktopt; - register struct mbuf *m; + struct mbuf *m; struct socket *so; struct sockopt *sopt; { - register struct ip6_pktopts *opt = *pktopt; + struct ip6_pktopts *opt = *pktopt; int error = 0; struct proc *p = sopt->sopt_p; int priv = 0; /* turn off any old options. */ if (opt) { - if (opt->ip6po_m) - (void)m_free(opt->ip6po_m); +#ifdef DIAGNOSTIC + if (opt->ip6po_pktinfo || opt->ip6po_nexthop || + opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || + opt->ip6po_rhinfo.ip6po_rhi_rthdr) + printf("ip6_pcbopts: all specified options are cleared.\n"); +#endif + ip6_clearpktopts(opt, 1, -1); } else opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK); - *pktopt = 0; + *pktopt = NULL; if (!m || m->m_len == 0) { /* @@ -1608,16 +1727,14 @@ ip6_pcbopts(pktopt, m, so, sopt) */ if (opt) free(opt, M_IP6OPT); - if (m) - (void)m_free(m); return(0); } /* set options specified by user. */ if (p && !suser(p)) priv = 1; - if ((error = ip6_setpktoptions(m, opt, priv)) != 0) { - (void)m_free(m); + if ((error = ip6_setpktoptions(m, opt, priv, 1)) != 0) { + ip6_clearpktopts(opt, 1, -1); /* XXX: discard all options */ return(error); } *pktopt = opt; @@ -1625,6 +1742,140 @@ ip6_pcbopts(pktopt, m, so, sopt) } /* + * initialize ip6_pktopts. beware that there are non-zero default values in + * the struct. + */ +void +init_ip6pktopts(opt) + struct ip6_pktopts *opt; +{ + + bzero(opt, sizeof(*opt)); + opt->ip6po_hlim = -1; /* -1 means default hop limit */ +} + +void +ip6_clearpktopts(pktopt, needfree, optname) + struct ip6_pktopts *pktopt; + int needfree, optname; +{ + if (pktopt == NULL) + return; + + if (optname == -1) { + if (needfree && pktopt->ip6po_pktinfo) + free(pktopt->ip6po_pktinfo, M_IP6OPT); + pktopt->ip6po_pktinfo = NULL; + } + if (optname == -1) + pktopt->ip6po_hlim = -1; + if (optname == -1) { + if (needfree && pktopt->ip6po_nexthop) + free(pktopt->ip6po_nexthop, M_IP6OPT); + pktopt->ip6po_nexthop = NULL; + } + if (optname == -1) { + if (needfree && pktopt->ip6po_hbh) + free(pktopt->ip6po_hbh, M_IP6OPT); + pktopt->ip6po_hbh = NULL; + } + if (optname == -1) { + if (needfree && pktopt->ip6po_dest1) + free(pktopt->ip6po_dest1, M_IP6OPT); + pktopt->ip6po_dest1 = NULL; + } + if (optname == -1) { + if (needfree && pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) + free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); + pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL; + if (pktopt->ip6po_route.ro_rt) { + RTFREE(pktopt->ip6po_route.ro_rt); + pktopt->ip6po_route.ro_rt = NULL; + } + } + if (optname == -1) { + if (needfree && pktopt->ip6po_dest2) + free(pktopt->ip6po_dest2, M_IP6OPT); + pktopt->ip6po_dest2 = NULL; + } +} + +#define PKTOPT_EXTHDRCPY(type) \ +do {\ + if (src->type) {\ + int hlen =\ + (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\ + dst->type = malloc(hlen, M_IP6OPT, canwait);\ + if (dst->type == NULL && canwait == M_NOWAIT)\ + goto bad;\ + bcopy(src->type, dst->type, hlen);\ + }\ +} while (0) + +struct ip6_pktopts * +ip6_copypktopts(src, canwait) + struct ip6_pktopts *src; + int canwait; +{ + struct ip6_pktopts *dst; + + if (src == NULL) { + printf("ip6_clearpktopts: invalid argument\n"); + return(NULL); + } + + dst = malloc(sizeof(*dst), M_IP6OPT, canwait); + if (dst == NULL && canwait == M_NOWAIT) + goto bad; + bzero(dst, sizeof(*dst)); + + dst->ip6po_hlim = src->ip6po_hlim; + if (src->ip6po_pktinfo) { + dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo), + M_IP6OPT, canwait); + if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT) + goto bad; + *dst->ip6po_pktinfo = *src->ip6po_pktinfo; + } + if (src->ip6po_nexthop) { + dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len, + M_IP6OPT, canwait); + if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT) + goto bad; + bcopy(src->ip6po_nexthop, dst->ip6po_nexthop, + src->ip6po_nexthop->sa_len); + } + PKTOPT_EXTHDRCPY(ip6po_hbh); + PKTOPT_EXTHDRCPY(ip6po_dest1); + PKTOPT_EXTHDRCPY(ip6po_dest2); + PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */ + return(dst); + + bad: + printf("ip6_copypktopts: copy failed"); + if (dst->ip6po_pktinfo) free(dst->ip6po_pktinfo, M_IP6OPT); + if (dst->ip6po_nexthop) free(dst->ip6po_nexthop, M_IP6OPT); + if (dst->ip6po_hbh) free(dst->ip6po_hbh, M_IP6OPT); + if (dst->ip6po_dest1) free(dst->ip6po_dest1, M_IP6OPT); + if (dst->ip6po_dest2) free(dst->ip6po_dest2, M_IP6OPT); + if (dst->ip6po_rthdr) free(dst->ip6po_rthdr, M_IP6OPT); + return(NULL); +} +#undef PKTOPT_EXTHDRCPY + +void +ip6_freepcbopts(pktopt) + struct ip6_pktopts *pktopt; +{ + if (pktopt == NULL) + return; + + ip6_clearpktopts(pktopt, 1, -1); + + free(pktopt, M_IP6OPT); +} + +/* * Set the IP6 multicast options in response to user setsockopt(). */ static int @@ -1670,7 +1921,7 @@ ip6_setmoptions(optname, im6op, m) error = EINVAL; break; } - ifindex = *(mtod(m, u_int *)); + bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex)); if (ifindex < 0 || if_index < ifindex) { error = ENXIO; /* XXX EINVAL? */ break; @@ -1693,7 +1944,7 @@ ip6_setmoptions(optname, im6op, m) error = EINVAL; break; } - optval = *(mtod(m, u_int *)); + bcopy(mtod(m, u_int *), &optval, sizeof(optval)); if (optval < -1 || optval >= 256) error = EINVAL; else if (optval == -1) @@ -1708,8 +1959,12 @@ ip6_setmoptions(optname, im6op, m) * Set the loopback flag for outgoing multicast packets. * Must be zero or one. */ - if (m == NULL || m->m_len != sizeof(u_int) || - (loop = *(mtod(m, u_int *))) > 1) { + if (m == NULL || m->m_len != sizeof(u_int)) { + error = EINVAL; + break; + } + bcopy(mtod(m, u_int *), &loop, sizeof(loop)); + if (loop > 1) { error = EINVAL; break; } @@ -1915,8 +2170,8 @@ ip6_setmoptions(optname, im6op, m) static int ip6_getmoptions(optname, im6o, mp) int optname; - register struct ip6_moptions *im6o; - register struct mbuf **mp; + struct ip6_moptions *im6o; + struct mbuf **mp; { u_int *hlim, *loop, *ifindex; @@ -1961,7 +2216,7 @@ ip6_getmoptions(optname, im6o, mp) */ void ip6_freemoptions(im6o) - register struct ip6_moptions *im6o; + struct ip6_moptions *im6o; { struct in6_multi_mship *imm; @@ -1981,18 +2236,17 @@ ip6_freemoptions(im6o) * Set IPv6 outgoing packet options based on advanced API. */ int -ip6_setpktoptions(control, opt, priv) +ip6_setpktoptions(control, opt, priv, needcopy) struct mbuf *control; struct ip6_pktopts *opt; - int priv; + int priv, needcopy; { - register struct cmsghdr *cm = 0; + struct cmsghdr *cm = 0; if (control == 0 || opt == 0) return(EINVAL); - bzero(opt, sizeof(*opt)); - opt->ip6po_hlim = -1; /* -1 means to use default hop limit */ + init_ip6pktopts(opt); /* * XXX: Currently, we assume all the optional information is stored @@ -2001,21 +2255,31 @@ ip6_setpktoptions(control, opt, priv) if (control->m_next) return(EINVAL); - opt->ip6po_m = control; - - for (; control->m_len; control->m_data += ALIGN(cm->cmsg_len), - control->m_len -= ALIGN(cm->cmsg_len)) { + for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len), + control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { cm = mtod(control, struct cmsghdr *); if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len) return(EINVAL); if (cm->cmsg_level != IPPROTO_IPV6) continue; - switch(cm->cmsg_type) { + /* + * XXX should check if RFC2292 API is mixed with 2292bis API + */ + switch (cm->cmsg_type) { case IPV6_PKTINFO: if (cm->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo))) return(EINVAL); - opt->ip6po_pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm); + if (needcopy) { + /* XXX: Is it really WAITOK? */ + opt->ip6po_pktinfo = + malloc(sizeof(struct in6_pktinfo), + M_IP6OPT, M_WAITOK); + bcopy(CMSG_DATA(cm), opt->ip6po_pktinfo, + sizeof(struct in6_pktinfo)); + } else + opt->ip6po_pktinfo = + (struct in6_pktinfo *)CMSG_DATA(cm); if (opt->ip6po_pktinfo->ipi6_ifindex && IN6_IS_ADDR_LINKLOCAL(&opt->ip6po_pktinfo->ipi6_addr)) opt->ip6po_pktinfo->ipi6_addr.s6_addr16[1] = @@ -2026,8 +2290,13 @@ ip6_setpktoptions(control, opt, priv) return(ENXIO); } + /* + * Check if the requested source address is indeed a + * unicast address assigned to the node, and can be + * used as the packet's source address. + */ if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) { - struct ifaddr *ia; + struct in6_ifaddr *ia6; struct sockaddr_in6 sin6; bzero(&sin6, sizeof(sin6)); @@ -2035,19 +2304,10 @@ ip6_setpktoptions(control, opt, priv) sin6.sin6_family = AF_INET6; sin6.sin6_addr = opt->ip6po_pktinfo->ipi6_addr; - ia = ifa_ifwithaddr(sin6tosa(&sin6)); - if (ia == NULL || - (opt->ip6po_pktinfo->ipi6_ifindex && - (ia->ifa_ifp->if_index != - opt->ip6po_pktinfo->ipi6_ifindex))) { - return(EADDRNOTAVAIL); - } - /* - * Check if the requested source address is - * indeed a unicast address assigned to the - * node. - */ - if (IN6_IS_ADDR_MULTICAST(&opt->ip6po_pktinfo->ipi6_addr)) + ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(sin6tosa(&sin6)); + if (ia6 == NULL || + (ia6->ia6_flags & (IN6_IFF_ANYCAST | + IN6_IFF_NOTREADY)) != 0) return(EADDRNOTAVAIL); } break; @@ -2064,66 +2324,120 @@ ip6_setpktoptions(control, opt, priv) case IPV6_NEXTHOP: if (!priv) return(EPERM); + if (cm->cmsg_len < sizeof(u_char) || + /* check if cmsg_len is large enough for sa_len */ cm->cmsg_len < CMSG_LEN(*CMSG_DATA(cm))) return(EINVAL); - opt->ip6po_nexthop = (struct sockaddr *)CMSG_DATA(cm); - + if (needcopy) { + opt->ip6po_nexthop = + malloc(*CMSG_DATA(cm), + M_IP6OPT, M_WAITOK); + bcopy(CMSG_DATA(cm), + opt->ip6po_nexthop, + *CMSG_DATA(cm)); + } else + opt->ip6po_nexthop = + (struct sockaddr *)CMSG_DATA(cm); break; case IPV6_HOPOPTS: + { + struct ip6_hbh *hbh; + int hbhlen; + if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_hbh))) return(EINVAL); - opt->ip6po_hbh = (struct ip6_hbh *)CMSG_DATA(cm); - if (cm->cmsg_len != - CMSG_LEN((opt->ip6po_hbh->ip6h_len + 1) << 3)) + hbh = (struct ip6_hbh *)CMSG_DATA(cm); + hbhlen = (hbh->ip6h_len + 1) << 3; + if (cm->cmsg_len != CMSG_LEN(hbhlen)) return(EINVAL); + + if (needcopy) { + opt->ip6po_hbh = + malloc(hbhlen, M_IP6OPT, M_WAITOK); + bcopy(hbh, opt->ip6po_hbh, hbhlen); + } else + opt->ip6po_hbh = hbh; break; + } case IPV6_DSTOPTS: + { + struct ip6_dest *dest, **newdest; + int destlen; + if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_dest))) return(EINVAL); + dest = (struct ip6_dest *)CMSG_DATA(cm); + destlen = (dest->ip6d_len + 1) << 3; + if (cm->cmsg_len != CMSG_LEN(destlen)) + return(EINVAL); - /* - * If there is no routing header yet, the destination - * options header should be put on the 1st part. - * Otherwise, the header should be on the 2nd part. - * (See RFC 2460, section 4.1) + /* + * The old advacned API is ambiguous on this + * point. Our approach is to determine the + * position based according to the existence + * of a routing header. Note, however, that + * this depends on the order of the extension + * headers in the ancillary data; the 1st part + * of the destination options header must + * appear before the routing header in the + * ancillary data, too. + * RFC2292bis solved the ambiguity by + * introducing separate cmsg types. */ - if (opt->ip6po_rthdr == NULL) { - opt->ip6po_dest1 = - (struct ip6_dest *)CMSG_DATA(cm); - if (cm->cmsg_len != - CMSG_LEN((opt->ip6po_dest1->ip6d_len + 1) - << 3)) - return(EINVAL); - } else { - opt->ip6po_dest2 = - (struct ip6_dest *)CMSG_DATA(cm); - if (cm->cmsg_len != - CMSG_LEN((opt->ip6po_dest2->ip6d_len + 1) - << 3)) - return(EINVAL); - } + if (opt->ip6po_rthdr == NULL) + newdest = &opt->ip6po_dest1; + else + newdest = &opt->ip6po_dest2; + + if (needcopy) { + *newdest = malloc(destlen, M_IP6OPT, M_WAITOK); + bcopy(dest, *newdest, destlen); + } else + *newdest = dest; + break; + } case IPV6_RTHDR: + { + struct ip6_rthdr *rth; + int rthlen; + if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_rthdr))) return(EINVAL); - opt->ip6po_rthdr = (struct ip6_rthdr *)CMSG_DATA(cm); - if (cm->cmsg_len != - CMSG_LEN((opt->ip6po_rthdr->ip6r_len + 1) << 3)) + rth = (struct ip6_rthdr *)CMSG_DATA(cm); + rthlen = (rth->ip6r_len + 1) << 3; + if (cm->cmsg_len != CMSG_LEN(rthlen)) return(EINVAL); - switch(opt->ip6po_rthdr->ip6r_type) { + + switch (rth->ip6r_type) { case IPV6_RTHDR_TYPE_0: - if (opt->ip6po_rthdr->ip6r_segleft == 0) + /* must contain one addr */ + if (rth->ip6r_len == 0) + return(EINVAL); + /* length must be even */ + if (rth->ip6r_len % 2) + return(EINVAL); + if (rth->ip6r_len / 2 != rth->ip6r_segleft) return(EINVAL); break; default: - return(EINVAL); + return(EINVAL); /* not supported */ } + + if (needcopy) { + opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, + M_WAITOK); + bcopy(rth, opt->ip6po_rthdr, rthlen); + } else + opt->ip6po_rthdr = rth; + break; + } default: return(ENOPROTOOPT); @@ -2142,8 +2456,8 @@ ip6_setpktoptions(control, opt, priv) void ip6_mloopback(ifp, m, dst) struct ifnet *ifp; - register struct mbuf *m; - register struct sockaddr_in6 *dst; + struct mbuf *m; + struct sockaddr_in6 *dst; { struct mbuf *copym; struct ip6_hdr *ip6; @@ -2171,18 +2485,15 @@ ip6_mloopback(ifp, m, dst) } #endif -#ifndef FAKE_LOOPBACK_IF - if ((ifp->if_flags & IFF_LOOPBACK) == 0) -#else - if (1) + ip6 = mtod(copym, struct ip6_hdr *); +#ifndef SCOPEDROUTING + /* + * clear embedded scope identifiers if necessary. + * in6_clearscope will touch the addresses only when necessary. + */ + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); #endif - { - ip6 = mtod(copym, struct ip6_hdr *); - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - ip6->ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] = 0; - } (void)if_simloop(ifp, copym, dst->sin6_family, NULL); } @@ -2236,10 +2547,11 @@ ip6_optlen(in6p) (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0) len += elen(in6p->in6p_outputopts->ip6po_hbh); - len += elen(in6p->in6p_outputopts->ip6po_dest1); + if (in6p->in6p_outputopts->ip6po_rthdr) + /* dest1 is valid with rthdr only */ + len += elen(in6p->in6p_outputopts->ip6po_dest1); len += elen(in6p->in6p_outputopts->ip6po_rthdr); len += elen(in6p->in6p_outputopts->ip6po_dest2); return len; #undef elen } - diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 234b2e9..dea9c07 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */ +/* $KAME: ip6_var.h,v 1.62 2001/05/03 14:51:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -129,15 +129,29 @@ struct ip6po_rhinfo { struct ip6_pktopts { struct mbuf *ip6po_m; /* Pointer to mbuf storing the data */ - int ip6po_hlim; /* Hoplimit for outgoing packets */ - struct in6_pktinfo *ip6po_pktinfo; /* Outgoing IF/address information */ - struct sockaddr *ip6po_nexthop; /* Next-hop address */ + int ip6po_hlim; /* Hoplimit for outgoing packets */ + + /* Outgoing IF/address information */ + struct in6_pktinfo *ip6po_pktinfo; + + struct sockaddr *ip6po_nexthop; /* Next-hop address */ + struct ip6_hbh *ip6po_hbh; /* Hop-by-Hop options header */ - struct ip6_dest *ip6po_dest1; /* Destination options header(1st part) */ - struct ip6po_rhinfo ip6po_rhinfo; /* Routing header related info. */ - struct ip6_dest *ip6po_dest2; /* Destination options header(2nd part) */ + + /* Destination options header (before a routing header) */ + struct ip6_dest *ip6po_dest1; + + /* Routing header related info. */ + struct ip6po_rhinfo ip6po_rhinfo; + + /* Destination options header (after a routing header) */ + struct ip6_dest *ip6po_dest2; }; +/* + * Control options for incoming packets + */ + struct ip6stat { u_quad_t ip6s_total; /* total packets received */ u_quad_t ip6s_tooshort; /* packet too short */ @@ -200,6 +214,37 @@ struct ip6stat { }; #ifdef _KERNEL +/* + * IPv6 onion peeling state. + * it will be initialized when we come into ip6_input(). + * XXX do not make it a kitchen sink! + */ +struct ip6aux { + u_int32_t ip6a_flags; +#define IP6A_SWAP 0x01 /* swapped home/care-of on packet */ +#define IP6A_HASEEN 0x02 /* HA was present */ +#define IP6A_BRUID 0x04 /* BR Unique Identifier was present */ +#define IP6A_RTALERTSEEN 0x08 /* rtalert present */ + + /* ip6.ip6_src */ + struct in6_addr ip6a_careof; /* care-of address of the peer */ + struct in6_addr ip6a_home; /* home address of the peer */ + u_int16_t ip6a_bruid; /* BR unique identifier */ + + /* ip6.ip6_dst */ + struct in6_ifaddr *ip6a_dstia6; /* my ifaddr that matches ip6_dst */ + + /* rtalert */ + u_int16_t ip6a_rtalert; /* rtalert option value */ + + /* + * decapsulation history will be here. + * with IPsec it may not be accurate. + */ +}; +#endif + +#ifdef _KERNEL /* flags passed to ip6_output as last parameter */ #define IPV6_DADOUTPUT 0x01 /* DAD */ #define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */ @@ -215,7 +260,8 @@ extern int ip6_gif_hlim; /* Hop limit for gif encap packet */ extern int ip6_use_deprecated; /* allow deprecated addr as source */ extern int ip6_rr_prune; /* router renumbering prefix * walk list every 5 sec. */ -extern int ip6_mapped_addr_on; +#define ip6_mapped_addr_on (!ip6_v6only) +extern int ip6_v6only; extern struct socket *ip6_mrouter; /* multicast routing daemon */ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ @@ -231,6 +277,14 @@ extern int ip6_dad_count; /* DupAddrDetectionTransmits */ extern u_int32_t ip6_flow_seq; extern int ip6_auto_flowlabel; +extern int ip6_auto_linklocal; + +extern int ip6_anonportmin; /* minimum ephemeral port */ +extern int ip6_anonportmax; /* maximum ephemeral port */ +extern int ip6_lowportmin; /* minimum reserved port */ +extern int ip6_lowportmax; /* maximum reserved port */ + +extern int ip6_use_tempaddr; /* whether to use temporary addresses. */ extern struct pr_usrreqs rip6_usrreqs; struct sockopt; @@ -239,29 +293,41 @@ struct inpcb; int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt)); +struct in6_ifaddr; void ip6_init __P((void)); void ip6intr __P((void)); void ip6_input __P((struct mbuf *)); +struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *)); +void ip6_freepcbopts __P((struct ip6_pktopts *)); void ip6_freemoptions __P((struct ip6_moptions *)); int ip6_unknown_opt __P((u_int8_t *, struct mbuf *, int)); char * ip6_get_prevhdr __P((struct mbuf *, int)); int ip6_nexthdr __P((struct mbuf *, int, int, int *)); int ip6_lasthdr __P((struct mbuf *, int, int, int *)); + +struct mbuf *ip6_addaux __P((struct mbuf *)); +struct mbuf *ip6_findaux __P((struct mbuf *)); +void ip6_delaux __P((struct mbuf *)); + int ip6_mforward __P((struct ip6_hdr *, struct ifnet *, struct mbuf *)); int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *, u_int32_t *)); void ip6_savecontrol __P((struct inpcb *, struct mbuf **, struct ip6_hdr *, - struct mbuf *)); + struct mbuf *)); +void ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *, + u_int32_t *)); int ip6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); void ip6_forward __P((struct mbuf *, int)); void ip6_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in6 *)); int ip6_output __P((struct mbuf *, struct ip6_pktopts *, - struct route_in6 *, int, + struct route_in6 *, + int, struct ip6_moptions *, struct ifnet **)); int ip6_ctloutput __P((struct socket *, struct sockopt *sopt)); -int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int)); +void init_ip6pktopts __P((struct ip6_pktopts *)); +int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int, int)); void ip6_clearpktopts __P((struct ip6_pktopts *, int, int)); struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int)); int ip6_optlen __P((struct inpcb *)); diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h index bd89793..c2f38fc 100644 --- a/sys/netinet6/ip6protosw.h +++ b/sys/netinet6/ip6protosw.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6protosw.h,v 1.11 2000/10/03 09:59:35 jinmei Exp $ */ +/* $KAME: ip6protosw.h,v 1.22 2001/02/08 18:02:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -87,16 +87,38 @@ struct socket; struct domain; struct proc; struct ip6_hdr; +struct icmp6_hdr; +struct in6_addr; struct pr_usrreqs; /* * argument type for the last arg of pr_ctlinput(). * should be consulted only with AF_INET6 family. + * + * IPv6 ICMP IPv6 [exthdrs] finalhdr paylaod + * ^ ^ ^ ^ + * | | ip6c_ip6 ip6c_off + * | ip6c_icmp6 + * ip6c_m + * + * ip6c_finaldst usually points to ip6c_ip6->ip6_dst. if the original + * (internal) packet carries a routing header, it may point the final + * dstination address in the routing header. + * + * ip6c_src: ip6c_ip6->ip6_src + scope info + flowlabel in ip6c_ip6 + * (beware of flowlabel, if you try to compare it against others) + * ip6c_dst: ip6c_finaldst + scope info */ struct ip6ctlparam { struct mbuf *ip6c_m; /* start of mbuf chain */ + struct icmp6_hdr *ip6c_icmp6; /* icmp6 header of target packet */ struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */ int ip6c_off; /* offset of the target proto header */ + struct sockaddr_in6 *ip6c_src; /* srcaddr w/ additional info */ + struct sockaddr_in6 *ip6c_dst; /* (final) dstaddr w/ additional info */ + struct in6_addr *ip6c_finaldst; /* final destination address */ + void *ip6c_cmdarg; /* control command dependent data */ + u_int8_t ip6c_nxt; /* final next header field */ }; struct ip6protosw { diff --git a/sys/netinet6/ipcomp.h b/sys/netinet6/ipcomp.h index dea5ea8..08d62da 100644 --- a/sys/netinet6/ipcomp.h +++ b/sys/netinet6/ipcomp.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */ +/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -37,6 +37,10 @@ #ifndef _NETINET6_IPCOMP_H_ #define _NETINET6_IPCOMP_H_ +#if defined(_KERNEL) && !defined(_LKM) +#include "opt_inet.h" +#endif + struct ipcomp { u_int8_t comp_nxt; /* Next Header */ u_int8_t comp_flags; /* reserved, must be zero */ @@ -59,7 +63,7 @@ struct ipcomp_algorithm { }; struct ipsecrequest; -extern struct ipcomp_algorithm ipcomp_algorithms[]; +extern const struct ipcomp_algorithm *ipcomp_algorithm_lookup __P((int)); extern void ipcomp4_input __P((struct mbuf *, ...)); extern int ipcomp4_output __P((struct mbuf *, struct ipsecrequest *)); #endif /*KERNEL*/ diff --git a/sys/netinet6/ipcomp6.h b/sys/netinet6/ipcomp6.h index 553c8df..4a1046a 100644 --- a/sys/netinet6/ipcomp6.h +++ b/sys/netinet6/ipcomp6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */ +/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c index 1eee253..ec031f6 100644 --- a/sys/netinet6/ipcomp_core.c +++ b/sys/netinet6/ipcomp_core.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipcomp_core.c,v 1.12 2000/05/05 11:01:01 sumikawa Exp $ */ +/* $KAME: ipcomp_core.c,v 1.24 2000/10/23 04:24:22 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -85,13 +85,20 @@ static int deflate_window_out = -12; static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */ static int deflate_memlevel = MAX_MEM_LEVEL; -struct ipcomp_algorithm ipcomp_algorithms[] = { - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, +static const struct ipcomp_algorithm ipcomp_algorithms[] = { { deflate_compress, deflate_decompress, 90 }, - { NULL, NULL, 90 }, }; +const struct ipcomp_algorithm * +ipcomp_algorithm_lookup(idx) + int idx; +{ + + if (idx == SADB_X_CALG_DEFLATE) + return &ipcomp_algorithms[0]; + return NULL; +} + static void * deflate_alloc(aux, items, siz) void *aux; @@ -99,7 +106,7 @@ deflate_alloc(aux, items, siz) u_int siz; { void *ptr; - MALLOC(ptr, void *, items * siz, M_TEMP, M_NOWAIT); + ptr = malloc(items * siz, M_TEMP, M_NOWAIT); return ptr; } @@ -108,7 +115,7 @@ deflate_free(aux, ptr) void *aux; void *ptr; { - FREE(ptr, M_TEMP); + free(ptr, M_TEMP); } static int @@ -120,12 +127,47 @@ deflate_common(m, md, lenp, mode) { struct mbuf *mprev; struct mbuf *p; - struct mbuf *n, *n0 = NULL, **np; + struct mbuf *n = NULL, *n0 = NULL, **np; z_stream zs; int error = 0; int zerror; size_t offset; - int firsttime, final, flush; + +#define MOREBLOCK() \ +do { \ + /* keep the reply buffer into our chain */ \ + if (n) { \ + n->m_len = zs.total_out - offset; \ + offset = zs.total_out; \ + *np = n; \ + np = &n->m_next; \ + n = NULL; \ + } \ + \ + /* get a fresh reply buffer */ \ + MGET(n, M_DONTWAIT, MT_DATA); \ + if (n) { \ + MCLGET(n, M_DONTWAIT); \ + } \ + if (!n) { \ + error = ENOBUFS; \ + goto fail; \ + } \ + n->m_len = 0; \ + n->m_len = M_TRAILINGSPACE(n); \ + n->m_next = NULL; \ + /* \ + * if this is the first reply buffer, reserve \ + * region for ipcomp header. \ + */ \ + if (*np == NULL) { \ + n->m_len -= sizeof(struct ipcomp); \ + n->m_data += sizeof(struct ipcomp); \ + } \ + \ + zs.next_out = mtod(n, u_int8_t *); \ + zs.avail_out = n->m_len; \ +} while (0) for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) ; @@ -148,113 +190,107 @@ deflate_common(m, md, lenp, mode) n0 = n = NULL; np = &n0; offset = 0; - firsttime = 1; - final = 0; - flush = Z_NO_FLUSH; zerror = 0; p = md; - while (1) { - /* - * first time, we need to setup the buffer before calling - * compression function. - */ - if (firsttime) - firsttime = 0; - else { - zerror = mode ? inflate(&zs, flush) - : deflate(&zs, flush); - } + while (p && p->m_len == 0) { + p = p->m_next; + } + /* input stream and output stream are available */ + while (p && zs.avail_in == 0) { /* get input buffer */ if (p && zs.avail_in == 0) { zs.next_in = mtod(p, u_int8_t *); zs.avail_in = p->m_len; p = p->m_next; - if (!p) { - final = 1; - flush = Z_PARTIAL_FLUSH; + while (p && p->m_len == 0) { + p = p->m_next; } } /* get output buffer */ if (zs.next_out == NULL || zs.avail_out == 0) { - /* keep the reply buffer into our chain */ - if (n) { - n->m_len = zs.total_out - offset; - offset = zs.total_out; - *np = n; - np = &n->m_next; - } + MOREBLOCK(); + } - /* get a fresh reply buffer */ - MGET(n, M_DONTWAIT, MT_DATA); - if (n) { - MCLGET(n, M_DONTWAIT); - } - if (!n) { - error = ENOBUFS; - goto fail; - } - n->m_len = 0; - n->m_len = M_TRAILINGSPACE(n); - n->m_next = NULL; - /* - * if this is the first reply buffer, reserve - * region for ipcomp header. - */ - if (*np == NULL) { - n->m_len -= sizeof(struct ipcomp); - n->m_data += sizeof(struct ipcomp); + zerror = mode ? inflate(&zs, Z_NO_FLUSH) + : deflate(&zs, Z_NO_FLUSH); + + if (zerror == Z_STREAM_END) + ; /*once more.*/ + else if (zerror == Z_OK) { + /* inflate: Z_OK can indicate the end of decode */ + if (mode && !p && zs.avail_out != 0) + goto terminate; + else + ; /*once more.*/ + } else { + if (zs.msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_NO_FLUSH): %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs.msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_NO_FLUSH): unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); } + mode ? inflateEnd(&zs) : deflateEnd(&zs); + error = EINVAL; + goto fail; + } + } - zs.next_out = mtod(n, u_int8_t *); - zs.avail_out = n->m_len; + if (zerror == Z_STREAM_END) + goto terminate; + + /* termination */ + while (1) { + /* get output buffer */ + if (zs.next_out == NULL || zs.avail_out == 0) { + MOREBLOCK(); } - if (zerror == Z_OK) { - /* - * to terminate deflate/inflate process, we need to - * call {in,de}flate() with different flushing methods. - * - * deflate() needs at least one Z_PARTIAL_FLUSH, - * then use Z_FINISH until we get to the end. - * (if we use Z_FLUSH without Z_PARTIAL_FLUSH, deflate() - * will assume contiguous single output buffer, and that - * is not what we want) - * inflate() does not care about flushing method, but - * needs output buffer until it gets to the end. - * - * the most outer loop will be terminated with - * Z_STREAM_END. - */ - if (final == 1) { - /* reached end of mbuf chain */ - if (mode == 0) - final = 2; - else - final = 3; - } else if (final == 2) { - /* terminate deflate case */ - flush = Z_FINISH; - } else if (final == 3) { - /* terminate inflate case */ - ; - } - } else if (zerror == Z_STREAM_END) + zerror = mode ? inflate(&zs, Z_FINISH) + : deflate(&zs, Z_FINISH); + + if (zerror == Z_STREAM_END) break; + else if (zerror == Z_OK) + ; /*once more.*/ else { - ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error")); + if (zs.msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_FINISH): %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs.msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_FINISH): unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); + } + mode ? inflateEnd(&zs) : deflateEnd(&zs); error = EINVAL; goto fail; } } + +terminate: zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs); if (zerror != Z_OK) { - ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error")); + if (zs.msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflateEnd: %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs.msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflateEnd: unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); + } error = EINVAL; goto fail; } @@ -264,6 +300,7 @@ deflate_common(m, md, lenp, mode) offset = zs.total_out; *np = n; np = &n->m_next; + n = NULL; } /* switch the mbuf to the new one */ @@ -276,9 +313,12 @@ deflate_common(m, md, lenp, mode) fail: if (m) m_freem(m); + if (n) + m_freem(n); if (n0) m_freem(n0); return error; +#undef MOREBLOCK } static int diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c index da0184c..0a6e2f5 100644 --- a/sys/netinet6/ipcomp_input.c +++ b/sys/netinet6/ipcomp_input.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipcomp_input.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */ +/* $KAME: ipcomp_input.c,v 1.25 2001/03/01 09:12:09 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -95,9 +95,10 @@ ipcomp4_input(m, va_alist) va_dcl #endif { + struct mbuf *md; struct ip *ip; struct ipcomp *ipcomp; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ u_int16_t nxt; size_t hlen; @@ -112,42 +113,23 @@ ipcomp4_input(m, va_alist) proto = va_arg(ap, int); va_end(ap); - if (off + sizeof(struct ipcomp) > MHLEN) { - /*XXX the restriction should be relaxed*/ + if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) { ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " - "(header too long)\n")); + "(packet too short)\n")); ipsecstat.in_inval++; goto fail; } - if (m->m_len < off + sizeof(struct ipcomp)) { - m = m_pullup(m, off + sizeof(struct ipcomp)); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 IPComp input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_nomem++; - goto fail; - } - } else if (m->m_len > off + sizeof(struct ipcomp)) { - /* chop header part from the packet header chain */ - struct mbuf *n; - MGETHDR(n, M_DONTWAIT, MT_HEADER); - if (!n) { - ipsecstat.in_nomem++; - goto fail; - } - M_COPY_PKTHDR(n, m); - MH_ALIGN(n, off + sizeof(struct ipcomp)); - n->m_len = off + sizeof(struct ipcomp); - bcopy(mtod(m, caddr_t), mtod(n, caddr_t), - off + sizeof(struct ipcomp)); - m_adj(m, off + sizeof(struct ipcomp)); - m->m_flags &= ~M_PKTHDR; - n->m_next = m; - m = n; - } + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); + if (!m) { + m = NULL; /*already freed*/ + ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " + "(pulldown failure)\n")); + ipsecstat.in_inval++; + goto fail; + } + ipcomp = mtod(md, struct ipcomp *); ip = mtod(m, struct ip *); - ipcomp = (struct ipcomp *)(((caddr_t)ip) + off); nxt = ipcomp->comp_nxt; #ifdef _IP_VHL hlen = IP_VHL_HL(ip->ip_vhl) << 2; @@ -167,10 +149,7 @@ ipcomp4_input(m, va_alist) /* other parameters to look at? */ } } - if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL) - algo = &ipcomp_algorithms[cpi]; - else - algo = NULL; + algo = ipcomp_algorithm_lookup(cpi); if (!algo) { ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n", cpi)); @@ -180,7 +159,8 @@ ipcomp4_input(m, va_alist) /* chop ipcomp header */ ipcomp = NULL; - m->m_len -= sizeof(struct ipcomp); + md->m_data += sizeof(struct ipcomp); + md->m_len -= sizeof(struct ipcomp); m->m_pkthdr.len -= sizeof(struct ipcomp); #ifdef IPLEN_FLIPPED ip->ip_len -= sizeof(struct ipcomp); @@ -237,13 +217,22 @@ ipcomp4_input(m, va_alist) if (sav) { key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { + ipsecstat.in_nomem++; + goto fail; + } key_freesav(sav); sav = NULL; } - if (nxt != IPPROTO_DONE) + if (nxt != IPPROTO_DONE) { + if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto fail; + } (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); - else + } else m_freem(m); m = NULL; @@ -268,66 +257,30 @@ ipcomp6_input(mp, offp, proto) struct mbuf *m, *md; int off; struct ip6_hdr *ip6; - struct mbuf *ipcompm; struct ipcomp *ipcomp; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ u_int16_t nxt; int error; size_t newlen; struct secasvar *sav = NULL; + char *prvnxtp; m = *mp; off = *offp; - IP6_EXTHDR_CHECK(m, off, sizeof(struct ipcomp), IPPROTO_DONE); - - { - int skip; - struct mbuf *n; - struct mbuf *p, *q; - size_t l; - - skip = off; - for (n = m; n && skip > 0; n = n->m_next) { - if (n->m_len <= skip) { - skip -= n->m_len; - continue; - } - break; - } - if (!n) { - ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); - ipsecstat.in_inval++; - goto fail; - } - if (n->m_len < skip + sizeof(struct ipcomp)) { - ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); - ipsecstat.in_inval++; + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); + if (!m) { + m = NULL; /*already freed*/ + ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed " + "(pulldown failure)\n")); + ipsec6stat.in_inval++; goto fail; } + ipcomp = mtod(md, struct ipcomp *); ip6 = mtod(m, struct ip6_hdr *); - ipcompm = n; - ipcomp = (struct ipcomp *)(mtod(n, caddr_t) + skip); - if (n->m_len > skip + sizeof(struct ipcomp)) { - /* split mbuf to ease the following steps*/ - l = n->m_len - (skip + sizeof(struct ipcomp)); - p = m_copym(n, skip + sizeof(struct ipcomp), l , M_DONTWAIT); - if (!p) { - ipsecstat.in_nomem++; - goto fail; - } - for (q = p; q && q->m_next; q = q->m_next) - ; - q->m_next = n->m_next; - n->m_next = p; - n->m_len -= l; - md = p; - } else - md = n->m_next; - } - nxt = ipcomp->comp_nxt; + cpi = ntohs(ipcomp->comp_cpi); if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { @@ -340,10 +293,7 @@ ipcomp6_input(mp, offp, proto) /* other parameters to look at? */ } } - if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL) - algo = &ipcomp_algorithms[cpi]; - else - algo = NULL; + algo = ipcomp_algorithm_lookup(cpi); if (!algo) { ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; " "dropping the packet for simplicity\n", cpi)); @@ -351,7 +301,13 @@ ipcomp6_input(mp, offp, proto) goto fail; } - newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp); + /* chop ipcomp header */ + ipcomp = NULL; + md->m_data += sizeof(struct ipcomp); + md->m_len -= sizeof(struct ipcomp); + m->m_pkthdr.len -= sizeof(struct ipcomp); + + newlen = m->m_pkthdr.len - off; error = (*algo->decompress)(m, md, &newlen); if (error != 0) { if (error == EINVAL) @@ -362,7 +318,7 @@ ipcomp6_input(mp, offp, proto) goto fail; } ipsec6stat.in_comphist[cpi]++; - m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen; + m->m_pkthdr.len = off + newlen; /* * returning decompressed packet onto icmp is meaningless. @@ -370,25 +326,21 @@ ipcomp6_input(mp, offp, proto) */ m->m_flags |= M_DECRYPTED; - { - char *prvnxtp; - - /* chop IPComp header */ + /* update next header field */ prvnxtp = ip6_get_prevhdr(m, off); *prvnxtp = nxt; - ipcompm->m_len -= sizeof(struct ipcomp); - ipcompm->m_pkthdr.len -= sizeof(struct ipcomp); - /* adjust payload length */ - ip6 = mtod(m, struct ip6_hdr *); - if (((m->m_pkthdr.len - sizeof(struct ip6_hdr)) & ~0xffff) != 0) - ip6->ip6_plen = 0; /*now a jumbogram*/ - else - ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); - } + /* + * no need to adjust payload length, as all the IPv6 protocols + * look at m->m_pkthdr.len + */ if (sav) { key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { + ipsec6stat.in_nomem++; + goto fail; + } key_freesav(sav); sav = NULL; } diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c index 265700e..b82840a 100644 --- a/sys/netinet6/ipcomp_output.c +++ b/sys/netinet6/ipcomp_output.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipcomp_output.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */ +/* $KAME: ipcomp_output.c,v 1.23 2001/01/23 08:59:37 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -87,7 +87,7 @@ static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *, /* * Modify the packet so that the payload is compressed. * The mbuf (m) must start with IPv4 or IPv6 header. - * On failure, free the given mbuf and return NULL. + * On failure, free the given mbuf and return non-zero. * * on invocation: * m nexthdrp md @@ -112,25 +112,29 @@ ipcomp_output(m, nexthdrp, md, isr, af) { struct mbuf *n; struct mbuf *md0; + struct mbuf *mcopy; struct mbuf *mprev; struct ipcomp *ipcomp; struct secasvar *sav = isr->sav; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ size_t plen0, plen; /*payload length to be compressed*/ size_t compoff; int afnumber; int error = 0; + struct ipsecstat *stat; switch (af) { #ifdef INET case AF_INET: afnumber = 4; + stat = &ipsecstat; break; #endif #ifdef INET6 case AF_INET6: afnumber = 6; + stat = &ipsec6stat; break; #endif default: @@ -139,9 +143,9 @@ ipcomp_output(m, nexthdrp, md, isr, af) } /* grab parameters */ - if ((ntohl(sav->spi) & ~0xffff) != 0 || sav->alg_enc >= IPCOMP_MAX - || ipcomp_algorithms[sav->alg_enc].compress == NULL) { - ipsecstat.out_inval++; + algo = ipcomp_algorithm_lookup(sav->alg_enc); + if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) { + stat->out_inval++; m_freem(m); return EINVAL; } @@ -149,7 +153,6 @@ ipcomp_output(m, nexthdrp, md, isr, af) cpi = sav->alg_enc; else cpi = ntohl(sav->spi) & 0xffff; - algo = &ipcomp_algorithms[sav->alg_enc]; /*XXX*/ /* compute original payload length */ plen = 0; @@ -161,11 +164,21 @@ ipcomp_output(m, nexthdrp, md, isr, af) return 0; /* - * keep the original data packet, so that we can backout - * our changes when compression is not necessary. + * retain the original packet for two purposes: + * (1) we need to backout our changes when compression is not necessary. + * (2) byte lifetime computation should use the original packet. + * see RFC2401 page 23. + * compromise two m_copym(). we will be going through every byte of + * the payload during compression process anyways. */ + mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT); + if (mcopy == NULL) { + error = ENOBUFS; + return 0; + } md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT); if (md0 == NULL) { + m_freem(mcopy); error = ENOBUFS; return 0; } @@ -177,26 +190,17 @@ ipcomp_output(m, nexthdrp, md, isr, af) if (mprev == NULL || mprev->m_next != md) { ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n", afnumber)); - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + stat->out_inval++; m_freem(m); m_freem(md0); + m_freem(mcopy); return EINVAL; } mprev->m_next = NULL; if ((md = ipsec_copypkt(md)) == NULL) { m_freem(m); m_freem(md0); + m_freem(mcopy); error = ENOBUFS; goto fail; } @@ -207,33 +211,12 @@ ipcomp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_ERR, "packet compression failure\n")); m = NULL; m_freem(md0); - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + m_freem(mcopy); + stat->out_inval++; error = EINVAL; goto fail; } - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_comphist[sav->alg_enc]++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_comphist[sav->alg_enc]++; - break; -#endif - } + stat->out_comphist[sav->alg_enc]++; md = mprev->m_next; /* @@ -242,13 +225,17 @@ ipcomp_output(m, nexthdrp, md, isr, af) */ if (plen0 < plen) { m_freem(md); + m_freem(mcopy); mprev->m_next = md0; return 0; } - /* no need to backout change beyond here */ + /* + * no need to backout change beyond here. + */ m_freem(md0); md0 = NULL; + m->m_pkthdr.len -= plen0; m->m_pkthdr.len += plen; @@ -341,47 +328,14 @@ ipcomp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_DEBUG, "NULL mbuf after compression in ipcomp%d_output", afnumber)); - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } - } else { - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_success++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_success++; - break; -#endif - } + stat->out_inval++; } -#if 0 - switch (af) { -#ifdef INET - case AF_INET: - ipsecstat.out_esphist[sav->alg_enc]++; - break; -#endif -#ifdef INET6 - case AF_INET6: - ipsec6stat.out_esphist[sav->alg_enc]++; - break; -#endif - } -#endif - key_sa_recordxfer(sav, m); + stat->out_success++; + + /* compute byte lifetime against original packet */ + key_sa_recordxfer(sav, mcopy); + m_freem(mcopy); + return 0; fail: diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c index b8a2447..3cb835d 100644 --- a/sys/netinet6/ipsec.c +++ b/sys/netinet6/ipsec.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipsec.c,v 1.66 2000/06/15 04:08:54 itojun Exp $ */ +/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -67,9 +67,11 @@ #ifdef INET6 #include <netinet6/ip6_ecn.h> #endif +#include <netinet/tcp.h> +#include <netinet/udp.h> -#ifdef INET6 #include <netinet/ip6.h> +#ifdef INET6 #include <netinet6/ip6_var.h> #endif #include <netinet/in_pcb.h> @@ -97,25 +99,12 @@ #endif #include <netkey/key.h> #include <netkey/keydb.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <machine/in_cksum.h> #include <net/net_osdep.h> -#ifdef HAVE_NRL_INPCB -#define in6pcb inpcb -#define in6p_sp inp_sp -#define in6p_fport inp_fport -#define in6p_lport inp_lport -#define in6p_socket inp_socket -#define sotoin6pcb(so) ((struct inpcb *)(so)->so_pcb) -#endif - #ifdef IPSEC_DEBUG int ipsec_debug = 1; #else @@ -132,11 +121,14 @@ int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; int ip4_ah_net_deflev = IPSEC_LEVEL_USE; struct secpolicy ip4_def_policy; int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ +int ip4_esp_randpad = -1; +#ifdef SYSCTL_DECL SYSCTL_DECL(_net_inet_ipsec); #ifdef INET6 SYSCTL_DECL(_net_inet6_ipsec6); #endif +#endif /* net.inet.ipsec */ SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS, @@ -161,6 +153,8 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); +SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, + esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); #ifdef INET6 struct ipsecstat ipsec6stat; @@ -170,6 +164,7 @@ int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; int ip6_ah_net_deflev = IPSEC_LEVEL_USE; struct secpolicy ip6_def_policy; int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ +int ip6_esp_randpad = -1; /* net.inet6.ipsec6 */ SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, @@ -188,16 +183,22 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); +SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, + esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); #endif /* INET6 */ static int ipsec_setspidx_mbuf - __P((struct secpolicyindex *, u_int, u_int, struct mbuf *)); -static void ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); -static void ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); + __P((struct secpolicyindex *, u_int, u_int, struct mbuf *, int)); +static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); +#ifdef INET6 +static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); +#endif +static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); +static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); +static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); #ifdef INET6 -static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *)); -static void ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); -static void ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); +static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); +static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); #endif static struct inpcbpolicy *ipsec_newpcbpolicy __P((void)); static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); @@ -208,14 +209,21 @@ static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); static void vshiftl __P((unsigned char *, int, int)); static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *)); static size_t ipsec_hdrsiz __P((struct secpolicy *)); +#ifdef INET static struct mbuf *ipsec4_splithdr __P((struct mbuf *)); +#endif #ifdef INET6 static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); #endif +#ifdef INET static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); +#endif #ifdef INET6 static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); #endif +static struct mbuf *ipsec_addaux __P((struct mbuf *)); +static struct mbuf *ipsec_findaux __P((struct mbuf *)); +static void ipsec_optaux __P((struct mbuf *, struct mbuf *)); /* * For OUTBOUND packet having a socket. Searching SPD for packet, @@ -247,19 +255,29 @@ ipsec4_getpolicybysock(m, dir, so, error) switch (so->so_proto->pr_domain->dom_family) { case AF_INET: /* set spidx in pcb */ - ipsec4_setspidx_inpcb(m, sotoinpcb(so)); - pcbsp = sotoinpcb(so)->inp_sp; + *error = ipsec4_setspidx_inpcb(m, sotoinpcb(so)); break; #ifdef INET6 case AF_INET6: /* set spidx in pcb */ - ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); - pcbsp = sotoin6pcb(so)->in6p_sp; + *error = ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); break; #endif default: panic("ipsec4_getpolicybysock: unsupported address family\n"); } + if (*error) + return NULL; + switch (so->so_proto->pr_domain->dom_family) { + case AF_INET: + pcbsp = sotoinpcb(so)->inp_sp; + break; +#ifdef INET6 + case AF_INET6: + pcbsp = sotoin6pcb(so)->in6p_sp; + break; +#endif + } /* sanity check */ if (pcbsp == NULL) @@ -404,7 +422,8 @@ ipsec4_getpolicybyaddr(m, dir, flag, error) bzero(&spidx, sizeof(spidx)); /* make a index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m); + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m, + (flag & IP_FORWARDING) ? 0 : 1); if (*error != 0) return NULL; @@ -460,6 +479,11 @@ ipsec6_getpolicybysock(m, dir, so, error) if (m == NULL || so == NULL || error == NULL) panic("ipsec6_getpolicybysock: NULL pointer was passed.\n"); +#ifdef DIAGNOSTIC + if (so->so_proto->pr_domain->dom_family != AF_INET6) + panic("ipsec6_getpolicybysock: socket domain != inet6\n"); +#endif + /* set spidx in pcb */ ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); @@ -615,7 +639,8 @@ ipsec6_getpolicybyaddr(m, dir, flag, error) bzero(&spidx, sizeof(spidx)); /* make a index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m); + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m, + (flag & IP_FORWARDING) ? 0 : 1); if (*error != 0) return NULL; @@ -656,302 +681,286 @@ ipsec6_getpolicybyaddr(m, dir, flag, error) * other: failure, and set errno. */ int -ipsec_setspidx_mbuf(spidx, dir, family, m) +ipsec_setspidx_mbuf(spidx, dir, family, m, needport) struct secpolicyindex *spidx; u_int dir, family; struct mbuf *m; + int needport; { + int error; /* sanity check */ if (spidx == NULL || m == NULL) panic("ipsec_setspidx_mbuf: NULL pointer was passed.\n"); - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: begin\n"); kdebug_mbuf(m)); - - /* initialize */ bzero(spidx, sizeof(*spidx)); + error = ipsec_setspidx(m, spidx, needport); + if (error) + goto bad; spidx->dir = dir; - { - /* sanity check for packet length. */ - struct mbuf *n; - int tlen; - - tlen = 0; - for (n = m; n; n = n->m_next) - tlen += n->m_len; - if (m->m_pkthdr.len != tlen) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "total of m_len(%d) != pkthdr.len(%d), " - "ignored.\n", - tlen, m->m_pkthdr.len)); - goto bad; - } - } + return 0; - switch (family) { - case AF_INET: - { - struct ip *ip; - struct ip ipbuf; - struct sockaddr_in *sin; + bad: + /* XXX initialize */ + bzero(spidx, sizeof(*spidx)); + return EINVAL; +} - /* sanity check 1 for minimum ip header length */ - if (m->m_pkthdr.len < sizeof(struct ip)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "pkthdr.len(%d) < sizeof(struct ip), " - "ignored.\n", - m->m_pkthdr.len)); - goto bad; - } +static int +ipsec4_setspidx_inpcb(m, pcb) + struct mbuf *m; + struct inpcb *pcb; +{ + struct secpolicyindex *spidx; + int error; - /* - * get IPv4 header packet. usually the mbuf is contiguous - * and we need no copies. - */ - if (m->m_len >= sizeof(*ip)) - ip = mtod(m, struct ip *); - else { - m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); - ip = &ipbuf; - } + /* sanity check */ + if (pcb == NULL) + panic("ipsec4_setspidx_inpcb: no PCB found.\n"); + if (pcb->inp_sp == NULL) + panic("ipsec4_setspidx_inpcb: no inp_sp found.\n"); + if (pcb->inp_sp->sp_out == NULL || pcb->inp_sp->sp_in == NULL) + panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n"); - /* XXX some more checks on IPv4 header. */ + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); - sin = (struct sockaddr_in *)&spidx->src; - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - bcopy(&ip->ip_src, &sin->sin_addr, sizeof(sin->sin_addr)); - sin->sin_port = IPSEC_PORT_ANY; + spidx = &pcb->inp_sp->sp_in->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_INBOUND; - sin = (struct sockaddr_in *)&spidx->dst; - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(sin->sin_addr)); - sin->sin_port = IPSEC_PORT_ANY; + spidx = &pcb->inp_sp->sp_out->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_OUTBOUND; - spidx->prefs = spidx->prefd = sizeof(struct in_addr) << 3; + return 0; - spidx->ul_proto = ip->ip_p; - break; - } +bad: + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); + return error; +} #ifdef INET6 - case AF_INET6: - { - struct ip6_hdr *ip6; - struct ip6_hdr ip6buf; - struct sockaddr_in6 *sin6; +static int +ipsec6_setspidx_in6pcb(m, pcb) + struct mbuf *m; + struct in6pcb *pcb; +{ + struct secpolicyindex *spidx; + int error; - /* sanity check 1 for minimum ip header length */ - if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "pkthdr.len(%d) < sizeof(struct ip6_hdr), " - "ignored.\n", - m->m_pkthdr.len)); - goto bad; - } + /* sanity check */ + if (pcb == NULL) + panic("ipsec6_setspidx_in6pcb: no PCB found.\n"); + if (pcb->in6p_sp == NULL) + panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n"); + if (pcb->in6p_sp->sp_out == NULL || pcb->in6p_sp->sp_in == NULL) + panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n"); - /* - * get IPv6 header packet. usually the mbuf is contiguous - * and we need no copies. - */ - if (m->m_len >= sizeof(*ip6)) - ip6 = mtod(m, struct ip6_hdr *); - else { - m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); - ip6 = &ip6buf; - } + bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); - /* some more checks on IPv4 header. */ - if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "wrong ip version on packet " - "(expected IPv6), ignored.\n")); - goto bad; - } + spidx = &pcb->in6p_sp->sp_in->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_INBOUND; - sin6 = (struct sockaddr_in6 *)&spidx->src; - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(*sin6); - bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); - sin6->sin6_port = IPSEC_PORT_ANY; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { - /* fix scope id for comparing SPD */ - sin6->sin6_addr.s6_addr16[1] = 0; - sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); - } + spidx = &pcb->in6p_sp->sp_out->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_OUTBOUND; - sin6 = (struct sockaddr_in6 *)&spidx->dst; - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(*sin6); - bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); - sin6->sin6_port = IPSEC_PORT_ANY; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { - /* fix scope id for comparing SPD */ - sin6->sin6_addr.s6_addr16[1] = 0; - sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); - } + return 0; - spidx->prefs = spidx->prefd = sizeof(struct in6_addr) << 3; +bad: + bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + return error; +} +#endif - ipsec6_get_ulp(m, spidx); - break; - } -#endif /* INET6 */ - default: - panic("ipsec_secsecidx: no supported family passed.\n"); - } +/* + * configure security policy index (src/dst/proto/sport/dport) + * by looking at the content of mbuf. + * the caller is responsible for error recovery (like clearing up spidx). + */ +static int +ipsec_setspidx(m, spidx, needport) + struct mbuf *m; + struct secpolicyindex *spidx; + int needport; +{ + struct ip *ip = NULL; + struct ip ipbuf; + u_int v; + struct mbuf *n; + int len; + int error; - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: end\n"); - kdebug_secpolicyindex(spidx)); + if (m == NULL) + panic("ipsec_setspidx: m == 0 passed.\n"); - return 0; + /* + * validate m->m_pkthdr.len. we see incorrect length if we + * mistakenly call this function with inconsistent mbuf chain + * (like 4.4BSD tcp/udp processing). XXX should we panic here? + */ + len = 0; + for (n = m; n; n = n->m_next) + len += n->m_len; + if (m->m_pkthdr.len != len) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "total of m_len(%d) != pkthdr.len(%d), " + "ignored.\n", + len, m->m_pkthdr.len)); + return EINVAL; + } - bad: - /* XXX initialize */ - bzero(spidx, sizeof(*spidx)); - return EINVAL; -} + if (m->m_pkthdr.len < sizeof(struct ip)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "pkthdr.len(%d) < sizeof(struct ip), ignored.\n", + m->m_pkthdr.len)); + return EINVAL; + } + if (m->m_len >= sizeof(*ip)) + ip = mtod(m, struct ip *); + else { + m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); + ip = &ipbuf; + } +#ifdef _IP_VHL + v = _IP_VHL_V(ip->ip_vhl); +#else + v = ip->ip_v; +#endif + switch (v) { + case 4: + error = ipsec4_setspidx_ipaddr(m, spidx); + if (error) + return error; + ipsec4_get_ulp(m, spidx, needport); + return 0; #ifdef INET6 -/* - * Get upper layer protocol number and port number if there. - * Assumed all extension headers are in single mbuf. - */ -#include <netinet/tcp.h> -#include <netinet/udp.h> + case 6: + if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "pkthdr.len(%d) < sizeof(struct ip6_hdr), " + "ignored.\n", m->m_pkthdr.len)); + return EINVAL; + } + error = ipsec6_setspidx_ipaddr(m, spidx); + if (error) + return error; + ipsec6_get_ulp(m, spidx, needport); + return 0; +#endif + default: + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "unknown IP version %u, ignored.\n", v)); + return EINVAL; + } +} + static void -ipsec6_get_ulp(m, spidx) +ipsec4_get_ulp(m, spidx, needport) struct mbuf *m; struct secpolicyindex *spidx; + int needport; { - int off, nxt; + struct ip ip; + struct ip6_ext ip6e; + u_int8_t nxt; + int off; + struct tcphdr th; + struct udphdr uh; /* sanity check */ if (m == NULL) - panic("ipsec6_get_ulp: NULL pointer was passed.\n"); - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); + panic("ipsec4_get_ulp: NULL pointer was passed.\n"); + if (m->m_pkthdr.len < sizeof(ip)) + panic("ipsec4_get_ulp: too short\n"); /* set default */ spidx->ul_proto = IPSEC_ULPROTO_ANY; - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; + ((struct sockaddr_in *)&spidx->src)->sin_port = IPSEC_PORT_ANY; + ((struct sockaddr_in *)&spidx->dst)->sin_port = IPSEC_PORT_ANY; - nxt = -1; - off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); - if (off < 0 || m->m_pkthdr.len < off) + m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); + /* ip_input() flips it into host endian XXX need more checking */ + if (ip.ip_off & (IP_MF | IP_OFFMASK)) return; - switch (nxt) { - case IPPROTO_TCP: - spidx->ul_proto = nxt; - if (off + sizeof(struct tcphdr) <= m->m_pkthdr.len) { - struct tcphdr th; + nxt = ip.ip_p; +#ifdef _IP_VHL + off = _IP_VHL_HL(ip->ip_vhl) << 2; +#else + off = ip.ip_hl << 2; +#endif + while (off < m->m_pkthdr.len) { + switch (nxt) { + case IPPROTO_TCP: + spidx->ul_proto = nxt; + if (!needport) + return; + if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) + return; m_copydata(m, off, sizeof(th), (caddr_t)&th); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = + ((struct sockaddr_in *)&spidx->src)->sin_port = th.th_sport; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = + ((struct sockaddr_in *)&spidx->dst)->sin_port = th.th_dport; - } - break; - case IPPROTO_UDP: - spidx->ul_proto = nxt; - if (off + sizeof(struct udphdr) <= m->m_pkthdr.len) { - struct udphdr uh; + return; + case IPPROTO_UDP: + spidx->ul_proto = nxt; + if (!needport) + return; + if (off + sizeof(struct udphdr) > m->m_pkthdr.len) + return; m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = + ((struct sockaddr_in *)&spidx->src)->sin_port = uh.uh_sport; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = + ((struct sockaddr_in *)&spidx->dst)->sin_port = uh.uh_dport; + return; + case IPPROTO_AH: + if (m->m_pkthdr.len > off + sizeof(ip6e)) + return; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + off += (ip6e.ip6e_len + 2) << 2; + nxt = ip6e.ip6e_nxt; + break; + case IPPROTO_ICMP: + default: + /* XXX intermediate headers??? */ + spidx->ul_proto = nxt; + return; } - break; - case IPPROTO_ICMPV6: - spidx->ul_proto = nxt; - break; - default: - break; } } -#endif - -static void -ipsec4_setspidx_inpcb(m, pcb) - struct mbuf *m; - struct inpcb *pcb; -{ - struct secpolicyindex *spidx; - struct sockaddr_in *sin1, *sin2; - - /* sanity check */ - if (pcb == NULL) - panic("ipsec4_setspidx_inpcb: no PCB found.\n"); - if (pcb->inp_sp == NULL) - panic("ipsec4_setspidx_inpcb: no inp_sp found.\n"); - if (pcb->inp_sp->sp_out ==NULL || pcb->inp_sp->sp_in == NULL) - panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n"); - - bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); - bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); - - spidx = &pcb->inp_sp->sp_in->spidx; - spidx->dir = IPSEC_DIR_INBOUND; - sin1 = (struct sockaddr_in *)&spidx->src; - sin2 = (struct sockaddr_in *)&spidx->dst; - sin1->sin_len = sin2->sin_len = sizeof(struct sockaddr_in); - sin1->sin_family = sin2->sin_family = AF_INET; - spidx->prefs = sizeof(struct in_addr) << 3; - spidx->prefd = sizeof(struct in_addr) << 3; - spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; - sin1->sin_port = pcb->inp_fport; - sin2->sin_port = pcb->inp_lport; - ipsec4_setspidx_ipaddr(m, spidx); - - spidx = &pcb->inp_sp->sp_out->spidx; - spidx->dir = IPSEC_DIR_OUTBOUND; - sin1 = (struct sockaddr_in *)&spidx->src; - sin2 = (struct sockaddr_in *)&spidx->dst; - sin1->sin_len = sin2->sin_len = sizeof(struct sockaddr_in); - sin1->sin_family = sin2->sin_family = AF_INET; - spidx->prefs = sizeof(struct in_addr) << 3; - spidx->prefd = sizeof(struct in_addr) << 3; - spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; - sin1->sin_port = pcb->inp_lport; - sin2->sin_port = pcb->inp_fport; - ipsec4_setspidx_ipaddr(m, spidx); - - return; -} -static void +/* assumes that m is sane */ +static int ipsec4_setspidx_ipaddr(m, spidx) struct mbuf *m; struct secpolicyindex *spidx; { struct ip *ip = NULL; struct ip ipbuf; - - /* sanity check 1 for minimum ip header length */ - if (m == NULL) - panic("ipsec4_setspidx_ipaddr: m == 0 passed.\n"); - - if (m->m_pkthdr.len < sizeof(struct ip)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec4_setspidx_ipaddr: " - "pkthdr.len(%d) < sizeof(struct ip), " - "ignored.\n", - m->m_pkthdr.len)); - return; - } + struct sockaddr_in *sin; if (m->m_len >= sizeof(*ip)) ip = mtod(m, struct ip *); @@ -960,64 +969,81 @@ ipsec4_setspidx_ipaddr(m, spidx) ip = &ipbuf; } - bcopy(&ip->ip_src, &((struct sockaddr_in *)&spidx->src)->sin_addr, - sizeof(ip->ip_src)); - bcopy(&ip->ip_dst, &((struct sockaddr_in *)&spidx->dst)->sin_addr, - sizeof(ip->ip_dst)); + sin = (struct sockaddr_in *)&spidx->src; + bzero(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_src, &sin->sin_addr, sizeof(ip->ip_src)); + spidx->prefs = sizeof(struct in_addr) << 3; - return; + sin = (struct sockaddr_in *)&spidx->dst; + bzero(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)); + spidx->prefd = sizeof(struct in_addr) << 3; + return 0; } #ifdef INET6 static void -ipsec6_setspidx_in6pcb(m, pcb) +ipsec6_get_ulp(m, spidx, needport) struct mbuf *m; - struct in6pcb *pcb; -{ struct secpolicyindex *spidx; - struct sockaddr_in6 *sin1, *sin2; + int needport; +{ + int off, nxt; + struct tcphdr th; + struct udphdr uh; /* sanity check */ - if (pcb == NULL) - panic("ipsec6_setspidx_in6pcb: no PCB found.\n"); - if (pcb->in6p_sp == NULL) - panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n"); - if (pcb->in6p_sp->sp_out ==NULL || pcb->in6p_sp->sp_in == NULL) - panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n"); + if (m == NULL) + panic("ipsec6_get_ulp: NULL pointer was passed.\n"); - bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); - bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); - spidx = &pcb->in6p_sp->sp_in->spidx; - spidx->dir = IPSEC_DIR_INBOUND; - sin1 = (struct sockaddr_in6 *)&spidx->src; - sin2 = (struct sockaddr_in6 *)&spidx->dst; - sin1->sin6_len = sin2->sin6_len = sizeof(struct sockaddr_in6); - sin1->sin6_family = sin2->sin6_family = AF_INET6; - spidx->prefs = sizeof(struct in6_addr) << 3; - spidx->prefd = sizeof(struct in6_addr) << 3; - spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; - sin1->sin6_port = pcb->in6p_fport; - sin2->sin6_port = pcb->in6p_lport; - ipsec6_setspidx_ipaddr(m, spidx); + /* set default */ + spidx->ul_proto = IPSEC_ULPROTO_ANY; + ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; + ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; - spidx = &pcb->in6p_sp->sp_out->spidx; - spidx->dir = IPSEC_DIR_OUTBOUND; - sin1 = (struct sockaddr_in6 *)&spidx->src; - sin2 = (struct sockaddr_in6 *)&spidx->dst; - sin1->sin6_len = sin2->sin6_len = sizeof(struct sockaddr_in6); - sin1->sin6_family = sin2->sin6_family = AF_INET6; - spidx->prefs = sizeof(struct in6_addr) << 3; - spidx->prefd = sizeof(struct in6_addr) << 3; - spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; - sin1->sin6_port = pcb->in6p_lport; - sin2->sin6_port = pcb->in6p_fport; - ipsec6_setspidx_ipaddr(m, spidx); + nxt = -1; + off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); + if (off < 0 || m->m_pkthdr.len < off) + return; - return; + switch (nxt) { + case IPPROTO_TCP: + spidx->ul_proto = nxt; + if (!needport) + break; + if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) + break; + m_copydata(m, off, sizeof(th), (caddr_t)&th); + ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; + ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; + break; + case IPPROTO_UDP: + spidx->ul_proto = nxt; + if (!needport) + break; + if (off + sizeof(struct udphdr) > m->m_pkthdr.len) + break; + m_copydata(m, off, sizeof(uh), (caddr_t)&uh); + ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; + ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; + break; + case IPPROTO_ICMPV6: + default: + /* XXX intermediate headers??? */ + spidx->ul_proto = nxt; + break; + } } -static void +/* assumes that m is sane */ +static int ipsec6_setspidx_ipaddr(m, spidx) struct mbuf *m; struct secpolicyindex *spidx; @@ -1026,19 +1052,6 @@ ipsec6_setspidx_ipaddr(m, spidx) struct ip6_hdr ip6buf; struct sockaddr_in6 *sin6; - /* sanity check 1 for minimum ip header length */ - if (m == NULL) - panic("ipsec6_setspidx_in6pcb: m == 0 passed.\n"); - - if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec6_setspidx_ipaddr: " - "pkthdr.len(%d) < sizeof(struct ip6_hdr), " - "ignored.\n", - m->m_pkthdr.len)); - return; - } - if (m->m_len >= sizeof(*ip6)) ip6 = mtod(m, struct ip6_hdr *); else { @@ -1046,29 +1059,29 @@ ipsec6_setspidx_ipaddr(m, spidx) ip6 = &ip6buf; } - if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "wrong ip version on packet " - "(expected IPv6), ignored.\n")); - return; - } - sin6 = (struct sockaddr_in6 *)&spidx->src; + bzero(sin6, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { sin6->sin6_addr.s6_addr16[1] = 0; sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); } + spidx->prefs = sizeof(struct in6_addr) << 3; sin6 = (struct sockaddr_in6 *)&spidx->dst; + bzero(sin6, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { sin6->sin6_addr.s6_addr16[1] = 0; sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); } + spidx->prefd = sizeof(struct in6_addr) << 3; - return; + return 0; } #endif @@ -1628,6 +1641,8 @@ ipsec_in_reject(sp, m) need_conf = 0; need_icv = 0; + /* XXX should compare policy against ipsec header history */ + for (isr = sp->req; isr != NULL; isr = isr->next) { /* get current level */ @@ -1653,7 +1668,8 @@ ipsec_in_reject(sp, m) case IPPROTO_IPCOMP: /* * we don't really care, as IPcomp document says that - * we shouldn't compress small packets + * we shouldn't compress small packets, IPComp policy + * should always be treated as being in "use" level. */ break; } @@ -1717,12 +1733,10 @@ ipsec4_in_reject(m, inp) { if (inp == NULL) return ipsec4_in_reject_so(m, NULL); - else { - if (inp->inp_socket) - return ipsec4_in_reject_so(m, inp->inp_socket); - else - panic("ipsec4_in_reject: invalid inpcb/socket"); - } + if (inp->inp_socket) + return ipsec4_in_reject_so(m, inp->inp_socket); + else + panic("ipsec4_in_reject: invalid inpcb/socket"); } #ifdef INET6 @@ -1771,12 +1785,10 @@ ipsec6_in_reject(m, in6p) { if (in6p == NULL) return ipsec6_in_reject_so(m, NULL); - else { - if (in6p->in6p_socket) - return ipsec6_in_reject_so(m, in6p->in6p_socket); - else - panic("ipsec6_in_reject: invalid in6p/socket"); - } + if (in6p->in6p_socket) + return ipsec6_in_reject_so(m, in6p->in6p_socket); + else + panic("ipsec6_in_reject: invalid in6p/socket"); } #endif @@ -2054,6 +2066,7 @@ ipsec4_encapsulate(m, sav) &ip->ip_src, sizeof(ip->ip_src)); bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)); + ip->ip_ttl = IPDEFTTL; /* XXX Should ip_src be updated later ? */ @@ -2133,6 +2146,7 @@ ipsec6_encapsulate(m, sav) &ip6->ip6_src, sizeof(ip6->ip6_src)); bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.dst)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); + ip6->ip6_hlim = IPV6_DEFHLIM; /* XXX Should ip6_src be updated later ? */ @@ -2345,11 +2359,11 @@ ipsec4_logpacketstr(ip, spi) snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); while (p && *p) p++; - snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d", + snprintf(p, sizeof(buf) - (p - buf), "src=%u.%u.%u.%u", s[0], s[1], s[2], s[3]); while (p && *p) p++; - snprintf(p, sizeof(buf) - (p - buf), " dst=%d.%d.%d.%d", + snprintf(p, sizeof(buf) - (p - buf), " dst=%u.%u.%u.%u", d[0], d[1], d[2], d[3]); while (p && *p) p++; @@ -2454,6 +2468,7 @@ ipsec_dumpmbuf(m) printf("---\n"); } +#ifdef INET /* * IPsec output logic for IPv4. */ @@ -2500,6 +2515,8 @@ ipsec4_output(state, sp, flags) /* make SA index for search proper SA */ ip = mtod(state->m, struct ip *); bcopy(&isr->saidx, &saidx, sizeof(saidx)); + saidx.mode = isr->saidx.mode; + saidx.reqid = isr->saidx.reqid; sin = (struct sockaddr_in *)&saidx.src; if (sin->sin_len == 0) { sin->sin_len = sizeof(*sin); @@ -2595,7 +2612,7 @@ ipsec4_output(state, sp, flags) && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 || dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) { RTFREE(state->ro->ro_rt); - bzero((caddr_t)state->ro, sizeof (*state->ro)); + state->ro->ro_rt = NULL; } if (state->ro->ro_rt == 0) { dst4->sin_family = AF_INET; @@ -2672,6 +2689,7 @@ bad: state->m = NULL; return error; } +#endif #ifdef INET6 /* @@ -2720,6 +2738,8 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) /* make SA index for search proper SA */ ip6 = mtod(state->m, struct ip6_hdr *); bcopy(&isr->saidx, &saidx, sizeof(saidx)); + saidx.mode = isr->saidx.mode; + saidx.reqid = isr->saidx.reqid; sin6 = (struct sockaddr_in6 *)&saidx.src; if (sin6->sin6_len == 0) { sin6->sin6_len = sizeof(*sin6); @@ -2757,6 +2777,18 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) */ ipsec6stat.out_nosa++; error = ENOENT; + + /* + * Notify the fact that the packet is discarded + * to ourselves. I believe this is better than + * just silently discarding. (jinmei@kame.net) + * XXX: should we restrict the error to TCP packets? + * XXX: should we directly notify sockets via + * pfctlinputs? + */ + icmp6_error(state->m, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADMIN, 0); + state->m = NULL; /* icmp6_error freed the mbuf */ goto bad; } @@ -2951,7 +2983,7 @@ ipsec6_output_tunnel(state, sp, flags) && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) { RTFREE(state->ro->ro_rt); - bzero((caddr_t)state->ro, sizeof (*state->ro)); + state->ro->ro_rt = NULL; } if (state->ro->ro_rt == 0) { bzero(dst6, sizeof(*dst6)); @@ -3030,6 +3062,7 @@ bad: } #endif /*INET6*/ +#ifdef INET /* * Chop IP header and option off from the payload. */ @@ -3071,6 +3104,7 @@ ipsec4_splithdr(m) } return m; } +#endif #ifdef INET6 static struct mbuf * @@ -3111,38 +3145,89 @@ ipsec6_splithdr(m) /* validate inbound IPsec tunnel packet. */ int -ipsec4_tunnel_validate(ip, nxt0, sav) - struct ip *ip; +ipsec4_tunnel_validate(m, off, nxt0, sav) + struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ + int off; u_int nxt0; struct secasvar *sav; { u_int8_t nxt = nxt0 & 0xff; struct sockaddr_in *sin; + struct sockaddr_in osrc, odst, isrc, idst; int hlen; + struct secpolicy *sp; + struct ip *oip; +#ifdef DIAGNOSTIC + if (m->m_len < sizeof(struct ip)) + panic("too short mbuf on ipsec4_tunnel_validate"); +#endif if (nxt != IPPROTO_IPV4) return 0; + if (m->m_pkthdr.len < off + sizeof(struct ip)) + return 0; + /* do not decapsulate if the SA is for transport mode only */ + if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) + return 0; + + oip = mtod(m, struct ip *); #ifdef _IP_VHL - hlen = _IP_VHL_HL(ip->ip_vhl) << 2; + hlen = _IP_VHL_HL(oip->ip_vhl) << 2; #else - hlen = ip->ip_hl << 2; + hlen = oip->ip_hl << 2; #endif if (hlen != sizeof(struct ip)) return 0; - switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) { - case AF_INET: - sin = (struct sockaddr_in *)&sav->sah->saidx.dst; - if (bcmp(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)) != 0) - return 0; - break; -#ifdef INET6 - case AF_INET6: - /* should be supported, but at this moment we don't. */ - /*FALLTHROUGH*/ -#endif - default: + + /* AF_INET6 should be supported, but at this moment we don't. */ + sin = (struct sockaddr_in *)&sav->sah->saidx.dst; + if (sin->sin_family != AF_INET) return 0; - } + if (bcmp(&oip->ip_dst, &sin->sin_addr, sizeof(oip->ip_dst)) != 0) + return 0; + + /* XXX slow */ + bzero(&osrc, sizeof(osrc)); + bzero(&odst, sizeof(odst)); + bzero(&isrc, sizeof(isrc)); + bzero(&idst, sizeof(idst)); + osrc.sin_family = odst.sin_family = isrc.sin_family = idst.sin_family = + AF_INET; + osrc.sin_len = odst.sin_len = isrc.sin_len = idst.sin_len = + sizeof(struct sockaddr_in); + osrc.sin_addr = oip->ip_src; + odst.sin_addr = oip->ip_dst; + m_copydata(m, off + offsetof(struct ip, ip_src), sizeof(isrc.sin_addr), + (caddr_t)&isrc.sin_addr); + m_copydata(m, off + offsetof(struct ip, ip_dst), sizeof(idst.sin_addr), + (caddr_t)&idst.sin_addr); + + /* + * RFC2401 5.2.1 (b): (assume that we are using tunnel mode) + * - if the inner destination is multicast address, there can be + * multiple permissible inner source address. implementation + * may want to skip verification of inner source address against + * SPD selector. + * - if the inner protocol is ICMP, the packet may be an error report + * from routers on the other side of the VPN cloud (R in the + * following diagram). in this case, we cannot verify inner source + * address against SPD selector. + * me -- gw === gw -- R -- you + * + * we consider the first bullet to be users responsibility on SPD entry + * configuration (if you need to encrypt multicast traffic, set + * the source range of SPD selector to 0.0.0.0/0, or have explicit + * address ranges for possible senders). + * the second bullet is not taken care of (yet). + * + * therefore, we do not do anything special about inner source. + */ + + sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, + (struct sockaddr *)&isrc, (struct sockaddr *)&idst); + if (!sp) + return 0; + key_freesp(sp); return 1; } @@ -3150,28 +3235,64 @@ ipsec4_tunnel_validate(ip, nxt0, sav) #ifdef INET6 /* validate inbound IPsec tunnel packet. */ int -ipsec6_tunnel_validate(ip6, nxt0, sav) - struct ip6_hdr *ip6; +ipsec6_tunnel_validate(m, off, nxt0, sav) + struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ + int off; u_int nxt0; struct secasvar *sav; { u_int8_t nxt = nxt0 & 0xff; struct sockaddr_in6 *sin6; + struct sockaddr_in6 osrc, odst, isrc, idst; + struct secpolicy *sp; + struct ip6_hdr *oip6; +#ifdef DIAGNOSTIC + if (m->m_len < sizeof(struct ip6_hdr)) + panic("too short mbuf on ipsec6_tunnel_validate"); +#endif if (nxt != IPPROTO_IPV6) return 0; - switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) { - case AF_INET6: - sin6 = ((struct sockaddr_in6 *)&sav->sah->saidx.dst); - if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6->sin6_addr)) - return 0; - break; - case AF_INET: - /* should be supported, but at this moment we don't. */ - /*FALLTHROUGH*/ - default: + if (m->m_pkthdr.len < off + sizeof(struct ip6_hdr)) + return 0; + /* do not decapsulate if the SA is for transport mode only */ + if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) + return 0; + + oip6 = mtod(m, struct ip6_hdr *); + /* AF_INET should be supported, but at this moment we don't. */ + sin6 = (struct sockaddr_in6 *)&sav->sah->saidx.dst; + if (sin6->sin6_family != AF_INET6) + return 0; + if (!IN6_ARE_ADDR_EQUAL(&oip6->ip6_dst, &sin6->sin6_addr)) return 0; - } + + /* XXX slow */ + bzero(&osrc, sizeof(osrc)); + bzero(&odst, sizeof(odst)); + bzero(&isrc, sizeof(isrc)); + bzero(&idst, sizeof(idst)); + osrc.sin6_family = odst.sin6_family = isrc.sin6_family = + idst.sin6_family = AF_INET6; + osrc.sin6_len = odst.sin6_len = isrc.sin6_len = idst.sin6_len = + sizeof(struct sockaddr_in6); + osrc.sin6_addr = oip6->ip6_src; + odst.sin6_addr = oip6->ip6_dst; + m_copydata(m, off + offsetof(struct ip6_hdr, ip6_src), + sizeof(isrc.sin6_addr), (caddr_t)&isrc.sin6_addr); + m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst), + sizeof(idst.sin6_addr), (caddr_t)&idst.sin6_addr); + + /* + * regarding to inner source address validation, see a long comment + * in ipsec4_tunnel_validate. + */ + + sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, + (struct sockaddr *)&isrc, (struct sockaddr *)&idst); + if (!sp) + return 0; + key_freesp(sp); return 1; } @@ -3235,7 +3356,7 @@ ipsec_copypkt(m) */ remain = n->m_len; copied = 0; - while(1) { + while (1) { int len; struct mbuf *mn; @@ -3265,6 +3386,7 @@ ipsec_copypkt(m) MGETHDR(mn, M_DONTWAIT, MT_HEADER); if (mn == NULL) goto fail; + mn->m_pkthdr.rcvif = NULL; mm->m_next = mn; mm = mn; } @@ -3288,27 +3410,78 @@ ipsec_copypkt(m) return(NULL); } +static struct mbuf * +ipsec_addaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET, IPPROTO_ESP); + if (!n) + n = m_aux_add(m, AF_INET, IPPROTO_ESP); + if (!n) + return n; /* ENOBUFS */ + n->m_len = sizeof(struct socket *); + bzero(mtod(n, void *), n->m_len); + return n; +} + +static struct mbuf * +ipsec_findaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET, IPPROTO_ESP); +#ifdef DIAGNOSTIC + if (n && n->m_len < sizeof(struct socket *)) + panic("invalid ipsec m_aux"); +#endif + return n; +} + void +ipsec_delaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET, IPPROTO_ESP); + if (n) + m_aux_delete(m, n); +} + +/* if the aux buffer is unnecessary, nuke it. */ +static void +ipsec_optaux(m, n) + struct mbuf *m; + struct mbuf *n; +{ + + if (!n) + return; + if (n->m_len == sizeof(struct socket *) && !*mtod(n, struct socket **)) + ipsec_delaux(m); +} + +int ipsec_setsocket(m, so) struct mbuf *m; struct socket *so; { struct mbuf *n; - n = m_aux_find(m, AF_INET, IPPROTO_ESP); - if (so && !n) - n = m_aux_add(m, AF_INET, IPPROTO_ESP); - if (n) { - if (so) { - *mtod(n, struct socket **) = so; - /* - * XXX think again about it when we put decryption - * histrory into aux mbuf - */ - n->m_len = sizeof(struct socket *); - } else - m_aux_delete(m, n); - } + /* if so == NULL, don't insist on getting the aux mbuf */ + if (so) { + n = ipsec_addaux(m); + if (!n) + return ENOBUFS; + } else + n = ipsec_findaux(m); + if (n && n->m_len >= sizeof(struct socket *)) + *mtod(n, struct socket **) = so; + ipsec_optaux(m, n); + return 0; } struct socket * @@ -3317,9 +3490,66 @@ ipsec_getsocket(m) { struct mbuf *n; - n = m_aux_find(m, AF_INET, IPPROTO_ESP); + n = ipsec_findaux(m); if (n && n->m_len >= sizeof(struct socket *)) return *mtod(n, struct socket **); else return NULL; } + +int +ipsec_addhist(m, proto, spi) + struct mbuf *m; + int proto; + u_int32_t spi; +{ + struct mbuf *n; + struct ipsec_history *p; + + n = ipsec_addaux(m); + if (!n) + return ENOBUFS; + if (M_TRAILINGSPACE(n) < sizeof(*p)) + return ENOSPC; /*XXX*/ + p = (struct ipsec_history *)(mtod(n, caddr_t) + n->m_len); + n->m_len += sizeof(*p); + bzero(p, sizeof(*p)); + p->ih_proto = proto; + p->ih_spi = spi; + return 0; +} + +struct ipsec_history * +ipsec_gethist(m, lenp) + struct mbuf *m; + int *lenp; +{ + struct mbuf *n; + int l; + + n = ipsec_findaux(m); + if (!n) + return NULL; + l = n->m_len; + if (sizeof(struct socket *) > l) + return NULL; + if ((l - sizeof(struct socket *)) % sizeof(struct ipsec_history)) + return NULL; + /* XXX does it make more sense to divide by sizeof(ipsec_history)? */ + if (lenp) + *lenp = l - sizeof(struct socket *); + return (struct ipsec_history *) + (mtod(n, caddr_t) + sizeof(struct socket *)); +} + +void +ipsec_clearhist(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = ipsec_findaux(m); + if ((n) && n->m_len > sizeof(struct socket *)) + n->m_len = sizeof(struct socket *); + ipsec_optaux(m, n); +} diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h index 80be10c..33cef87 100644 --- a/sys/netinet6/ipsec.h +++ b/sys/netinet6/ipsec.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipsec.h,v 1.33 2000/06/19 14:31:49 sakane Exp $ */ +/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,6 +37,11 @@ #ifndef _NETINET6_IPSEC_H_ #define _NETINET6_IPSEC_H_ +#if defined(_KERNEL) && !defined(_LKM) && !defined(KLD_MODULE) +#include "opt_inet.h" +#include "opt_ipsec.h" +#endif + #include <net/pfkeyv2.h> #include <netkey/keydb.h> @@ -79,6 +84,18 @@ struct secpolicy { struct ipsecrequest *req; /* pointer to the ipsec request tree, */ /* if policy == IPSEC else this value == NULL.*/ + + /* + * lifetime handler. + * the policy can be used without limitiation if both lifetime and + * validtime are zero. + * "lifetime" is passed by sadb_lifetime.sadb_lifetime_addtime. + * "validtime" is passed by sadb_lifetime.sadb_lifetime_usetime. + */ + long created; /* time created the policy */ + long lastused; /* updated every when kernel sends a packet */ + long lifetime; /* duration of the lifetime of this policy */ + long validtime; /* duration this policy is valid without use */ }; /* Request for IPsec */ @@ -107,7 +124,7 @@ struct secspacq { struct secpolicyindex spidx; - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ int count; /* for lifetime */ /* XXX: here is mbuf place holder to be sent ? */ }; @@ -137,9 +154,9 @@ struct secspacq { /* Policy level */ /* - * IPSEC, ENTRUST and BYPASS are allowd for setsockopt() in PCB, - * DISCARD, IPSEC and NONE are allowd for setkey() in SPD. - * DISCARD and NONE are allowd for system default. + * IPSEC, ENTRUST and BYPASS are allowed for setsockopt() in PCB, + * DISCARD, IPSEC and NONE are allowed for setkey() in SPD. + * DISCARD and NONE are allowed for system default. */ #define IPSEC_POLICY_DISCARD 0 /* discarding packet */ #define IPSEC_POLICY_NONE 1 /* through IPsec engine */ @@ -216,7 +233,8 @@ struct ipsecstat { #define IPSECCTL_DFBIT 10 #define IPSECCTL_ECN 11 #define IPSECCTL_DEBUG 12 -#define IPSECCTL_MAXID 13 +#define IPSECCTL_ESP_RANDPAD 13 +#define IPSECCTL_MAXID 14 #define IPSECCTL_NAMES { \ { 0, 0 }, \ @@ -232,6 +250,7 @@ struct ipsecstat { { "dfbit", CTLTYPE_INT }, \ { "ecn", CTLTYPE_INT }, \ { "debug", CTLTYPE_INT }, \ + { "esp_randpad", CTLTYPE_INT }, \ } #define IPSEC6CTL_NAMES { \ @@ -248,6 +267,7 @@ struct ipsecstat { { 0, 0 }, \ { "ecn", CTLTYPE_INT }, \ { "debug", CTLTYPE_INT }, \ + { "esp_randpad", CTLTYPE_INT }, \ } #ifdef _KERNEL @@ -257,6 +277,11 @@ struct ipsec_output_state { struct sockaddr *dst; }; +struct ipsec_history { + int ih_proto; + u_int32_t ih_spi; +}; + extern int ipsec_debug; extern struct ipsecstat ipsecstat; @@ -269,6 +294,7 @@ extern int ip4_ah_cleartos; extern int ip4_ah_offsetmask; extern int ip4_ipsec_dfbit; extern int ip4_ipsec_ecn; +extern int ip4_esp_randpad; #define ipseclog(x) do { if (ipsec_debug) log x; } while (0) @@ -307,10 +333,15 @@ extern void ipsec_dumpmbuf __P((struct mbuf *)); extern int ipsec4_output __P((struct ipsec_output_state *, struct secpolicy *, int)); -extern int ipsec4_tunnel_validate __P((struct ip *, u_int, struct secasvar *)); +extern int ipsec4_tunnel_validate __P((struct mbuf *, int, u_int, + struct secasvar *)); extern struct mbuf *ipsec_copypkt __P((struct mbuf *)); -extern void ipsec_setsocket __P((struct mbuf *, struct socket *)); +extern void ipsec_delaux __P((struct mbuf *)); +extern int ipsec_setsocket __P((struct mbuf *, struct socket *)); extern struct socket *ipsec_getsocket __P((struct mbuf *)); +extern int ipsec_addhist __P((struct mbuf *, int, u_int32_t)); +extern struct ipsec_history *ipsec_gethist __P((struct mbuf *, int *)); +extern void ipsec_clearhist __P((struct mbuf *)); #endif /*_KERNEL*/ #ifndef _KERNEL @@ -318,7 +349,7 @@ extern caddr_t ipsec_set_policy __P((char *, int)); extern int ipsec_get_policylen __P((caddr_t)); extern char *ipsec_dump_policy __P((caddr_t, char *)); -extern char *ipsec_strerror __P((void)); +extern const char *ipsec_strerror __P((void)); #endif /*!_KERNEL*/ #endif /*_NETINET6_IPSEC_H_*/ diff --git a/sys/netinet6/ipsec6.h b/sys/netinet6/ipsec6.h index 383c125..e9b8a2c 100644 --- a/sys/netinet6/ipsec6.h +++ b/sys/netinet6/ipsec6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ipsec.h,v 1.33 2000/06/19 14:31:49 sakane Exp $ */ +/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -48,6 +48,7 @@ extern int ip6_esp_net_deflev; extern int ip6_ah_trans_deflev; extern int ip6_ah_net_deflev; extern int ip6_ipsec_ecn; +extern int ip6_esp_randpad; extern struct secpolicy *ipsec6_getpolicybysock __P((struct mbuf *, u_int, struct socket *, int *)); @@ -64,6 +65,8 @@ extern int ipsec6_get_policy __P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp)); extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *)); +struct tcp6cb; + extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); struct ip6_hdr; @@ -73,7 +76,7 @@ extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *, struct mbuf *, struct secpolicy *, int, int *)); extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, struct secpolicy *, int)); -extern int ipsec6_tunnel_validate __P((struct ip6_hdr *, u_int, +extern int ipsec6_tunnel_validate __P((struct mbuf *, int, u_int, struct secasvar *)); #endif /*_KERNEL*/ diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 4739856..27b8480 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: mld6.c,v 1.19 2000/05/05 11:01:03 sumikawa Exp $ */ +/* $KAME: mld6.c,v 1.27 2001/04/04 05:17:30 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -129,9 +129,8 @@ mld6_init() hbh_buf[5] = IP6OPT_RTALERT_LEN - 2; bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t)); + init_ip6pktopts(&ip6_opts); ip6_opts.ip6po_hbh = hbh; - /* We will specify the hoplimit by a multicast option. */ - ip6_opts.ip6po_hlim = -1; } void @@ -192,31 +191,34 @@ mld6_input(m, off) struct ifmultiaddr *ifma; int timer; /* timer value in the MLD query header */ +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),); + mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh)); + if (mldh == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } +#endif + /* source address validation */ + ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */ if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { log(LOG_ERR, - "mld6_input: src %s is not link-local\n", - ip6_sprintf(&ip6->ip6_src)); + "mld6_input: src %s is not link-local (grp=%s)\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&mldh->mld6_addr)); /* * spec (RFC2710) does not explicitly * specify to discard the packet from a non link-local * source address. But we believe it's expected to do so. + * XXX: do we have to allow :: as source? */ m_freem(m); return; } -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),); - mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off); -#else - IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh)); - if (mldh == NULL) { - icmp6stat.icp6s_tooshort++; - return; - } -#endif - /* * In the MLD6 specification, there are 3 states and a flag. * @@ -234,7 +236,7 @@ mld6_input(m, off) break; if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) && - !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) + !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) break; /* print error or log stat? */ if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) mldh->mld6_addr.s6_addr16[1] = @@ -343,7 +345,7 @@ mld6_input(m, off) void mld6_fasttimeo() { - register struct in6_multi *in6m; + struct in6_multi *in6m; struct in6_multistep step; int s; @@ -408,6 +410,7 @@ mld6_sendpkt(in6m, type, dst) } mh->m_next = md; + mh->m_pkthdr.rcvif = NULL; mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr); mh->m_len = sizeof(struct ip6_hdr); MH_ALIGN(mh, sizeof(struct ip6_hdr)); @@ -455,16 +458,16 @@ mld6_sendpkt(in6m, type, dst) ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif); if (outif) { icmp6_ifstat_inc(outif, ifs6_out_msg); - switch(type) { - case MLD6_LISTENER_QUERY: - icmp6_ifstat_inc(outif, ifs6_out_mldquery); - break; - case MLD6_LISTENER_REPORT: - icmp6_ifstat_inc(outif, ifs6_out_mldreport); - break; - case MLD6_LISTENER_DONE: - icmp6_ifstat_inc(outif, ifs6_out_mlddone); - break; + switch (type) { + case MLD6_LISTENER_QUERY: + icmp6_ifstat_inc(outif, ifs6_out_mldquery); + break; + case MLD6_LISTENER_REPORT: + icmp6_ifstat_inc(outif, ifs6_out_mldreport); + break; + case MLD6_LISTENER_DONE: + icmp6_ifstat_inc(outif, ifs6_out_mlddone); + break; } } } diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 833e902..270550b 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */ +/* $KAME: nd6.c,v 1.144 2001/05/24 07:44:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -43,6 +43,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/callout.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> @@ -53,6 +54,7 @@ #include <sys/errno.h> #include <sys/syslog.h> #include <sys/queue.h> +#include <sys/sysctl.h> #include <net/if.h> #include <net/if_dl.h> @@ -84,12 +86,19 @@ int nd6_delay = 5; /* delay first probe time 5 second */ int nd6_umaxtries = 3; /* maximum unicast query */ int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ +int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ +#ifdef ND6_DEBUG +int nd6_debug = 1; +#else +int nd6_debug = 0; +#endif + /* for debugging? */ static int nd6_inuse, nd6_allocated; @@ -103,6 +112,11 @@ int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; static struct sockaddr_in6 all1_sa; static void nd6_slowtimo __P((void *)); +static int regen_tmpaddr __P((struct in6_ifaddr *)); + +struct callout nd6_slowtimo_ch; +struct callout nd6_timer_ch; +extern struct callout in6_tmpaddrtimer_ch; void nd6_init() @@ -126,7 +140,8 @@ nd6_init() nd6_init_done = 1; /* start timer */ - timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); + callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, + nd6_slowtimo, NULL); } void @@ -192,22 +207,30 @@ nd6_setmtu(ifp) u_long oldmaxmtu = ndi->maxmtu; u_long oldlinkmtu = ndi->linkmtu; - switch(ifp->if_type) { - case IFT_ARCNET: /* XXX MTU handling needs more work */ - ndi->maxmtu = MIN(60480, ifp->if_mtu); - break; - case IFT_ETHER: - ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); - break; - case IFT_FDDI: - ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); - break; - case IFT_ATM: - ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); - break; - default: - ndi->maxmtu = ifp->if_mtu; - break; + switch (ifp->if_type) { + case IFT_ARCNET: /* XXX MTU handling needs more work */ + ndi->maxmtu = MIN(60480, ifp->if_mtu); + break; + case IFT_ETHER: + ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); + break; + case IFT_FDDI: + ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); + break; + case IFT_ATM: + ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); + break; + case IFT_IEEE1394: /* XXX should be IEEE1394MTU(1500) */ + ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); + break; +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: /* XXX should be IEEE80211MTU(1500) */ + ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); + break; +#endif + default: + ndi->maxmtu = ifp->if_mtu; + break; } if (oldmaxmtu != ndi->maxmtu) { @@ -329,6 +352,7 @@ nd6_options(ndopts) * Message validation requires that all included * options have a length that is greater than zero. */ + icmp6stat.icp6s_nd_badopt++; bzero(ndopts, sizeof(*ndopts)); return -1; } @@ -342,8 +366,9 @@ nd6_options(ndopts) case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { - printf("duplicated ND6 option found " - "(type=%d)\n", nd_opt->nd_opt_type); + nd6log((LOG_INFO, + "duplicated ND6 option found (type=%d)\n", + nd_opt->nd_opt_type)); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] @@ -363,16 +388,16 @@ nd6_options(ndopts) * Unknown options must be silently ignored, * to accomodate future extension to the protocol. */ - log(LOG_DEBUG, + nd6log((LOG_DEBUG, "nd6_options: unsupported option %d - " - "option ignored\n", nd_opt->nd_opt_type); + "option ignored\n", nd_opt->nd_opt_type)); } skip1: i++; if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; - printf("too many loop in nd opt\n"); + nd6log((LOG_INFO, "too many loop in nd opt\n")); break; } @@ -391,18 +416,21 @@ nd6_timer(ignored_arg) void *ignored_arg; { int s; - register struct llinfo_nd6 *ln; - register struct nd_defrouter *dr; - register struct nd_prefix *pr; + struct llinfo_nd6 *ln; + struct nd_defrouter *dr; + struct nd_prefix *pr; + struct ifnet *ifp; + struct in6_ifaddr *ia6, *nia6; + struct in6_addrlifetime *lt6; s = splnet(); - timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); + callout_reset(&nd6_timer_ch, nd6_prune * hz, + nd6_timer, NULL); ln = llinfo_nd6.ln_next; /* XXX BSD/OS separates this code -- itojun */ while (ln && ln != &llinfo_nd6) { struct rtentry *rt; - struct ifnet *ifp; struct sockaddr_in6 *dst; struct llinfo_nd6 *next = ln->ln_next; /* XXX: used for the DELAY case only: */ @@ -458,17 +486,22 @@ nd6_timer(ignored_arg) ICMP6_DST_UNREACH_ADDR, 0); ln->ln_hold = NULL; } - nd6_free(rt); + next = nd6_free(rt); } break; case ND6_LLINFO_REACHABLE: - if (ln->ln_expire) + if (ln->ln_expire) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } break; - /* - * ND6_LLINFO_STALE state requires nothing for timer - * routine. - */ + + case ND6_LLINFO_STALE: + /* Garbage Collection(RFC 2461 5.3) */ + if (ln->ln_expire) + next = nd6_free(rt); + break; + case ND6_LLINFO_DELAY: if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { /* We need NUD */ @@ -479,8 +512,10 @@ nd6_timer(ignored_arg) nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); - } else + } else { ln->ln_state = ND6_LLINFO_STALE; /* XXX */ + ln->ln_expire = time_second + nd6_gctimer; + } break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { @@ -490,17 +525,14 @@ nd6_timer(ignored_arg) nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { - nd6_free(rt); + next = nd6_free(rt); } break; - case ND6_LLINFO_WAITDELETE: - nd6_free(rt); - break; } ln = next; } - /* expire */ + /* expire default router list */ dr = TAILQ_FIRST(&nd_defrouter); while (dr) { if (dr->expire && dr->expire < time_second) { @@ -512,28 +544,82 @@ nd6_timer(ignored_arg) dr = TAILQ_NEXT(dr, dr_entry); } } - pr = nd_prefix.lh_first; - while (pr) { - struct in6_ifaddr *ia6; - struct in6_addrlifetime *lt6; - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - - if (ia6) { - /* check address lifetime */ - lt6 = &ia6->ia6_lifetime; - if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) - ia6->ia6_flags |= IN6_IFF_DEPRECATED; - if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); - /* xxx ND_OPT_PI_FLAG_ONLINK processing */ + /* + * expire interface addresses. + * in the past the loop was inside prefix expiry processing. + * However, from a stricter speci-confrmance standpoint, we should + * rather separate address lifetimes and prefix lifetimes. + */ + addrloop: + for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { + nia6 = ia6->ia_next; + /* check address lifetime */ + lt6 = &ia6->ia6_lifetime; + if (IFA6_IS_INVALID(ia6)) { + int regen = 0; + + /* + * If the expiring address is temporary, try + * regenerating a new one. This would be useful when + * we suspended a laptop PC, then turned on after a + * period that could invalidate all temporary + * addresses. Although we may have to restart the + * loop (see below), it must be after purging the + * address. Otherwise, we'd see an infinite loop of + * regeneration. + */ + if (ip6_use_tempaddr && + (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { + if (regen_tmpaddr(ia6) == 0) + regen = 1; } + + in6_purgeaddr(&ia6->ia_ifa); + + if (regen) + goto addrloop; /* XXX: see below */ + } else if (IFA6_IS_DEPRECATED(ia6)) { + int oldflags = ia6->ia6_flags; + + ia6->ia6_flags |= IN6_IFF_DEPRECATED; + + /* + * If a temporary address has just become deprecated, + * regenerate a new one if possible. + */ + if (ip6_use_tempaddr && + (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (oldflags & IN6_IFF_DEPRECATED) == 0) { + + if (regen_tmpaddr(ia6) == 0) { + /* + * A new temporary address is + * generated. + * XXX: this means the address chain + * has changed while we are still in + * the loop. Although the change + * would not cause disaster (because + * it's not an addition, but a + * deletion,) we'd rather restart the + * loop just for safety. Or does this + * significantly reduce performance?? + */ + goto addrloop; + } + } + } else if (IFA6_IS_DEPRECATED(ia6)) { + /* + * A new RA might have made a deprecated address + * preferred. + */ + ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; } + } + /* expire prefix list */ + pr = nd_prefix.lh_first; + while (pr) { /* * check prefix lifetime. * since pltime is just for autoconf, pltime processing for @@ -543,15 +629,17 @@ nd6_timer(ignored_arg) * can use the old prefix information to validate the * next prefix information to come. See prelist_update() * for actual validation. + * + * I don't think such an offset is necessary. + * (jinmei@kame.net, 20010130). */ - if (pr->ndpr_expire - && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { + if (pr->ndpr_expire && pr->ndpr_expire < time_second) { struct nd_prefix *t; t = pr->ndpr_next; /* * address expiration and prefix expiration are - * separate. NEVER perform in6_ifdel here. + * separate. NEVER perform in6_purgeaddr here. */ prelist_remove(pr); @@ -562,6 +650,70 @@ nd6_timer(ignored_arg) splx(s); } +static int +regen_tmpaddr(ia6) + struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ +{ + struct ifaddr *ifa; + struct ifnet *ifp; + struct in6_ifaddr *public_ifa6 = NULL; + + ifp = ia6->ia_ifa.ifa_ifp; + for (ifa = ifp->if_addrlist.tqh_first; ifa; + ifa = ifa->ifa_list.tqe_next) + { + struct in6_ifaddr *it6; + + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + it6 = (struct in6_ifaddr *)ifa; + + /* ignore no autoconf addresses. */ + if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + /* ignore autoconf addresses with different prefixes. */ + if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) + continue; + + /* + * Now we are looking at an autoconf address with the same + * prefix as ours. If the address is temporary and is still + * preferred, do not create another one. It would be rare, but + * could happen, for example, when we resume a laptop PC after + * a long period. + */ + if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + !IFA6_IS_DEPRECATED(it6)) { + public_ifa6 = NULL; + break; + } + + /* + * This is a public autoconf address that has the same prefix + * as ours. If it is preferred, keep it. We can't break the + * loop here, because there may be a still-preferred temporary + * address with the prefix. + */ + if (!IFA6_IS_DEPRECATED(it6)) + public_ifa6 = it6; + } + + if (public_ifa6 != NULL) { + int e; + + if ((e = in6_tmpifadd(public_ifa6, 0)) != 0) { + log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" + " tmp addr,errno=%d\n", e); + return(-1); + } + return(0); + } + + return(-1); +} + /* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. @@ -594,8 +746,14 @@ nd6_purge(ifp) for (pr = nd_prefix.lh_first; pr; pr = npr) { npr = pr->ndpr_next; if (pr->ndpr_ifp == ifp) { - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); + /* + * Previously, pr->ndpr_addr is removed as well, + * but I strongly believe we don't have to do it. + * nd6_purge() is only called from in6_ifdetach(), + * which removes all the associated interface addresses + * by itself. + * (jinmei@kame.net 20010129) + */ prelist_remove(pr); } } @@ -626,30 +784,7 @@ nd6_purge(ifp) rt->rt_gateway->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)rt->rt_gateway; if (sdl->sdl_index == ifp->if_index) - nd6_free(rt); - } - ln = nln; - } - - /* - * Neighbor cache entry for interface route will be retained - * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it. - */ - ln = llinfo_nd6.ln_next; - while (ln && ln != &llinfo_nd6) { - struct rtentry *rt; - struct sockaddr_dl *sdl; - - nln = ln->ln_next; - rt = ln->ln_rt; - if (rt && rt->rt_gateway && - rt->rt_gateway->sa_family == AF_LINK) { - sdl = (struct sockaddr_dl *)rt->rt_gateway; - if (sdl->sdl_index == ifp->if_index) { - rtrequest(RTM_DELETE, rt_key(rt), - (struct sockaddr *)0, rt_mask(rt), 0, - (struct rtentry **)0); - } + nln = nd6_free(rt); } ln = nln; } @@ -757,7 +892,7 @@ nd6_is_addr_neighbor(addr, ifp) struct sockaddr_in6 *addr; struct ifnet *ifp; { - register struct ifaddr *ifa; + struct ifaddr *ifa; int i; #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) @@ -807,26 +942,25 @@ nd6_is_addr_neighbor(addr, ifp) /* * Free an nd6 llinfo entry. */ -void +struct llinfo_nd6 * nd6_free(rt) struct rtentry *rt; { - struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; - struct sockaddr_dl *sdl; + struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; struct nd_defrouter *dr; /* - * Clear all destination cache entries for the neighbor. - * XXX: is it better to restrict this to hosts? + * we used to have pfctlinput(PRC_HOSTDEAD) here. + * even though it is not harmful, it was not really necessary. */ - pfctlinput(PRC_HOSTDEAD, rt_key(rt)); if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ int s; s = splnet(); dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, rt->rt_ifp); + if (ln->ln_router || dr) { /* * rt6_flush must be called whether or not the neighbor @@ -852,6 +986,14 @@ nd6_free(rt) */ ln->ln_state = ND6_LLINFO_INCOMPLETE; + /* + * Since defrouter_select() does not affect the + * on-link determination and MIP6 needs the check + * before the default router selection, we perform + * the check now. + */ + pfxlist_onlink_check(); + if (dr == TAILQ_FIRST(&nd_defrouter)) { /* * It is used as the current default router, @@ -865,22 +1007,27 @@ nd6_free(rt) defrouter_select(); } - pfxlist_onlink_check(); } splx(s); } - if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_alen = 0; - ln->ln_state = ND6_LLINFO_WAITDELETE; - ln->ln_asked = 0; - rt->rt_flags &= ~RTF_REJECT; - return; - } + /* + * Before deleting the entry, remember the next entry as the + * return value. We need this because pfxlist_onlink_check() above + * might have freed other entries (particularly the old next entry) as + * a side effect (XXX). + */ + next = ln->ln_next; + /* + * Detach the route from the routing tree and the list of neighbor + * caches, and disable the route entry not to be used in already + * cached routes. + */ rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); + + return(next); } /* @@ -935,103 +1082,6 @@ nd6_nud_hint(rt, dst6, force) nd_ifinfo[rt->rt_ifp->if_index].reachable; } -#ifdef OLDIP6OUTPUT -/* - * Resolve an IP6 address into an ethernet address. If success, - * desten is filled in. If there is no entry in ndptab, - * set one up and multicast a solicitation for the IP6 address. - * Hold onto this mbuf and resend it once the address - * is finally resolved. A return value of 1 indicates - * that desten has been filled in and the packet should be sent - * normally; a 0 return indicates that the packet has been - * taken over here, either now or for later transmission. - */ -int -nd6_resolve(ifp, rt, m, dst, desten) - struct ifnet *ifp; - struct rtentry *rt; - struct mbuf *m; - struct sockaddr *dst; - u_char *desten; -{ - struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; - struct sockaddr_dl *sdl; - - if (m->m_flags & M_MCAST) { - switch (ifp->if_type) { - case IFT_ETHER: - case IFT_FDDI: - ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, - desten); - return(1); - break; - case IFT_ARCNET: - *desten = 0; - return(1); - break; - default: - m_freem(m); - return(0); - } - } - if (rt && (rt->rt_flags & RTF_LLINFO) != 0) - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - else { - if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - } - if (!ln || !rt) { - log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", - ip6_sprintf(&(SIN6(dst)->sin6_addr))); - m_freem(m); - return(0); - } - sdl = SDL(rt->rt_gateway); - /* - * Ckeck the address family and length is valid, the address - * is resolved; otherwise, try to resolve. - */ - if (ln->ln_state >= ND6_LLINFO_REACHABLE - && sdl->sdl_family == AF_LINK - && sdl->sdl_alen != 0) { - bcopy(LLADDR(sdl), desten, sdl->sdl_alen); - if (ln->ln_state == ND6_LLINFO_STALE) { - ln->ln_asked = 0; - ln->ln_state = ND6_LLINFO_DELAY; - ln->ln_expire = time_second + nd6_delay; - } - return(1); - } - /* - * There is an ndp entry, but no ethernet address - * response yet. Replace the held mbuf with this - * latest one. - * - * XXX Does the code conform to rate-limiting rule? - * (RFC 2461 7.2.2) - */ - if (ln->ln_state == ND6_LLINFO_WAITDELETE || - ln->ln_state == ND6_LLINFO_NOSTATE) - ln->ln_state = ND6_LLINFO_INCOMPLETE; - if (ln->ln_hold) - m_freem(ln->ln_hold); - ln->ln_hold = m; - if (ln->ln_expire) { - rt->rt_flags &= ~RTF_REJECT; - if (ln->ln_asked < nd6_mmaxtries && - ln->ln_expire < time_second) { - ln->ln_asked++; - ln->ln_expire = time_second + - nd_ifinfo[ifp->if_index].retrans / 1000; - nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), - ln, 0); - } - } - /* Do not free mbuf chain here as it is queued in llinfo_nd6 */ - return(0); -} -#endif /* OLDIP6OUTPUT */ - void nd6_rtrequest(req, rt, sa) int req; @@ -1047,6 +1097,17 @@ nd6_rtrequest(req, rt, sa) if (rt->rt_flags & RTF_GATEWAY) return; + if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { + /* + * This is probably an interface direct route for a link + * which does not need neighbor caches (e.g. fe80::%lo0/64). + * We do not need special treatment below for such a route. + * Moreover, the RTF_LLINFO flag which would be set below + * would annoy the ndp(8) command. + */ + return; + } + switch (req) { case RTM_ADD: /* @@ -1072,7 +1133,7 @@ nd6_rtrequest(req, rt, sa) ln->ln_expire = time_second; #if 1 if (ln && ln->ln_expire == 0) { - /* cludge for desktops */ + /* kludge for desktops */ #if 0 printf("nd6_request: time.tv_sec is zero; " "treat it as 1\n"); @@ -1093,10 +1154,10 @@ nd6_rtrequest(req, rt, sa) * (7.2.6 paragraph 4), however, it also says that we * SHOULD provide a mechanism to prevent multicast NA storm. * we don't have anything like it right now. - * note that the mechanism need a mutual agreement + * note that the mechanism needs a mutual agreement * between proxies, which means that we need to implement - * a new protocol, or new kludge. - * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA. + * a new protocol, or a new kludge. + * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. * we need to check ip6forwarding before sending it. * (or should we allow proxy ND configuration only for * routers? there's no mention about proxy ND from hosts) @@ -1112,7 +1173,7 @@ nd6_rtrequest(req, rt, sa) #endif /* FALLTHROUGH */ case RTM_RESOLVE: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { + if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { /* * Address resolution isn't necessary for a point to * point link, so we can skip this test for a p2p link. @@ -1120,7 +1181,8 @@ nd6_rtrequest(req, rt, sa) if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, - "nd6_rtrequest: bad gateway value\n"); + "nd6_rtrequest: bad gateway value: %s\n", + if_name(ifp)); break; } SDL(gate)->sdl_type = ifp->if_type; @@ -1192,7 +1254,7 @@ nd6_rtrequest(req, rt, sa) */ if (ifa != rt->rt_ifa) { IFAFREE(rt->rt_ifa); - ifa->ifa_refcnt++; + IFAREF(ifa); rt->rt_ifa = ifa; } } @@ -1213,10 +1275,11 @@ nd6_rtrequest(req, rt, sa) llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error); - if (error) - printf( -"nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); + if (!in6_addmulti(&llsol, ifp, &error)) { + nd6log((LOG_ERR, "%s: failed to join " + "%s (errno=%d)\n", if_name(ifp), + ip6_sprintf(&llsol), error)); + } } } break; @@ -1253,65 +1316,6 @@ nd6_rtrequest(req, rt, sa) } } -void -nd6_p2p_rtrequest(req, rt, sa) - int req; - struct rtentry *rt; - struct sockaddr *sa; /* xxx unused */ -{ - struct sockaddr *gate = rt->rt_gateway; - static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct ifnet *ifp = rt->rt_ifp; - struct ifaddr *ifa; - - if (rt->rt_flags & RTF_GATEWAY) - return; - - switch (req) { - case RTM_ADD: - /* - * There is no backward compatibility :) - * - * if ((rt->rt_flags & RTF_HOST) == 0 && - * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) - * rt->rt_flags |= RTF_CLONING; - */ - if (rt->rt_flags & RTF_CLONING) { - /* - * Case 1: This route should come from - * a route to interface. - */ - rt_setgate(rt, rt_key(rt), - (struct sockaddr *)&null_sdl); - gate = rt->rt_gateway; - SDL(gate)->sdl_type = ifp->if_type; - SDL(gate)->sdl_index = ifp->if_index; - break; - } - /* Announce a new entry if requested. */ - if (rt->rt_flags & RTF_ANNOUNCE) - nd6_na_output(ifp, - &SIN6(rt_key(rt))->sin6_addr, - &SIN6(rt_key(rt))->sin6_addr, - ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, - 1, NULL); - /* FALLTHROUGH */ - case RTM_RESOLVE: - /* - * check if rt_key(rt) is one of my address assigned - * to the interface. - */ - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, - &SIN6(rt_key(rt))->sin6_addr); - if (ifa) { - if (nd6_useloopback) { - rt->rt_ifp = &loif[0]; /*XXX*/ - } - } - break; - } -} - int nd6_ioctl(cmd, data, ifp) u_long cmd; @@ -1331,6 +1335,9 @@ nd6_ioctl(cmd, data, ifp) switch (cmd) { case SIOCGDRLST_IN6: + /* + * obsolete API, use sysctl under net.inet6.icmp6 + */ bzero(drl, sizeof(*drl)); s = splnet(); dr = TAILQ_FIRST(&nd_defrouter); @@ -1356,6 +1363,9 @@ nd6_ioctl(cmd, data, ifp) break; case SIOCGPRLST_IN6: /* + * obsolete API, use sysctl under net.inet6.icmp6 + */ + /* * XXX meaning of fields, especialy "raflags", is very * differnet between RA prefix list and RR/static prefix list. * how about separating ioctls into two? @@ -1367,7 +1377,8 @@ nd6_ioctl(cmd, data, ifp) struct nd_pfxrouter *pfr; int j; - prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; + (void)in6_embedscope(&prl->prefix[i].prefix, + &pr->ndpr_prefix, NULL, NULL); prl->prefix[i].raflags = pr->ndpr_raf; prl->prefix[i].prefixlen = pr->ndpr_plen; prl->prefix[i].vltime = pr->ndpr_vltime; @@ -1377,7 +1388,7 @@ nd6_ioctl(cmd, data, ifp) pfr = pr->ndpr_advrtrs.lh_first; j = 0; - while(pfr) { + while (pfr) { if (j < DRLSTSIZ) { #define RTRADDR prl->prefix[i].advrtr[j] RTRADDR = pfr->router->rtaddr; @@ -1408,7 +1419,8 @@ nd6_ioctl(cmd, data, ifp) rpp = LIST_NEXT(rpp, rp_entry)) { if (i >= PRLSTSIZ) break; - prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; + (void)in6_embedscope(&prl->prefix[i].prefix, + &pr->ndpr_prefix, NULL, NULL); prl->prefix[i].raflags = rpp->rp_raf; prl->prefix[i].prefixlen = rpp->rp_plen; prl->prefix[i].vltime = rpp->rp_vltime; @@ -1423,6 +1435,22 @@ nd6_ioctl(cmd, data, ifp) splx(s); break; + case OSIOCGIFINFO_IN6: + if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { + error = EINVAL; + break; + } + ndi->ndi.linkmtu = nd_ifinfo[ifp->if_index].linkmtu; + ndi->ndi.maxmtu = nd_ifinfo[ifp->if_index].maxmtu; + ndi->ndi.basereachable = + nd_ifinfo[ifp->if_index].basereachable; + ndi->ndi.reachable = nd_ifinfo[ifp->if_index].reachable; + ndi->ndi.retrans = nd_ifinfo[ifp->if_index].retrans; + ndi->ndi.flags = nd_ifinfo[ifp->if_index].flags; + ndi->ndi.recalctm = nd_ifinfo[ifp->if_index].recalctm; + ndi->ndi.chlim = nd_ifinfo[ifp->if_index].chlim; + ndi->ndi.receivedra = nd_ifinfo[ifp->if_index].receivedra; + break; case SIOCGIFINFO_IN6: if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { error = EINVAL; @@ -1456,9 +1484,24 @@ nd6_ioctl(cmd, data, ifp) s = splnet(); for (pr = nd_prefix.lh_first; pr; pr = next) { + struct in6_ifaddr *ia, *ia_next; + next = pr->ndpr_next; - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); + + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; /* XXX */ + + /* do we really have to remove addresses as well? */ + for (ia = in6_ifaddr; ia; ia = ia_next) { + /* ia might be removed. keep the next ptr. */ + ia_next = ia->ia_next; + + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + if (ia->ia6_ndpr == pr) + in6_purgeaddr(&ia->ia_ifa); + } prelist_remove(pr); } splx(s); @@ -1577,14 +1620,18 @@ nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) rt = nd6_lookup(from, 1, ifp); is_newentry = 1; - } else + } else { + /* do nothing if static ndp is set */ + if (rt->rt_flags & RTF_STATIC) + return NULL; is_newentry = 0; + } if (!rt) return NULL; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: - nd6_free(rt); + (void)nd6_free(rt); return NULL; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; @@ -1647,12 +1694,15 @@ fail: ln->ln_state = newstate; if (ln->ln_state == ND6_LLINFO_STALE) { - rt->rt_flags &= ~RTF_REJECT; + /* + * XXX: since nd6_output() below will cause + * state tansition to DELAY and reset the timer, + * we must set the timer now, although it is actually + * meaningless. + */ + ln->ln_expire = time_second + nd6_gctimer; + if (ln->ln_hold) { -#ifdef OLDIP6OUTPUT - (*ifp->if_output)(ifp, ln->ln_hold, - rt_key(rt), rt); -#else /* * we assume ifp is not a p2p here, so just * set the 2nd argument as the 1st one. @@ -1660,8 +1710,7 @@ fail: nd6_output(ifp, ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); -#endif - ln->ln_hold = 0; + ln->ln_hold = NULL; } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ @@ -1742,10 +1791,11 @@ nd6_slowtimo(ignored_arg) void *ignored_arg; { int s = splnet(); - register int i; - register struct nd_ifinfo *nd6if; + int i; + struct nd_ifinfo *nd6if; - timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); + callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, + nd6_slowtimo, NULL); for (i = 1; i < if_index + 1; i++) { if (!nd_ifinfo || i >= nd_ifinfo_indexlim) continue; @@ -1768,14 +1818,14 @@ nd6_slowtimo(ignored_arg) #define senderr(e) { error = (e); goto bad;} int nd6_output(ifp, origifp, m0, dst, rt0) - register struct ifnet *ifp; + struct ifnet *ifp; struct ifnet *origifp; struct mbuf *m0; struct sockaddr_in6 *dst; struct rtentry *rt0; { - register struct mbuf *m = m0; - register struct rtentry *rt = rt0; + struct mbuf *m = m0; + struct rtentry *rt = rt0; struct sockaddr_in6 *gw6 = NULL; struct llinfo_nd6 *ln = NULL; int error = 0; @@ -1783,22 +1833,8 @@ nd6_output(ifp, origifp, m0, dst, rt0) if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; - /* - * XXX: we currently do not make neighbor cache on any interface - * other than ARCnet, Ethernet, FDDI and GIF. - * - * draft-ietf-ngtrans-mech-06.txt says: - * - unidirectional tunnels needs no ND - */ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: - case IFT_GIF: /* XXX need more cases? */ - break; - default: + if (nd6_need_cache(ifp) == 0) goto sendpkt; - } /* * next hop determination. This routine is derived from ether_outpout. @@ -1824,7 +1860,7 @@ nd6_output(ifp, origifp, m0, dst, rt0) /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point - * of view, regardless the value of the value of + * of view, regardless the value of the * nd_ifinfo.flags. * The second condition is a bit tricky: we skip * if the gateway is our own address, which is @@ -1832,9 +1868,6 @@ nd6_output(ifp, origifp, m0, dst, rt0) */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { - if (rt->rt_flags & RTF_REJECT) - senderr(EHOSTDOWN); - /* * We allow this kind of tricky route only * when the outgoing interface is p2p. @@ -1855,8 +1888,6 @@ nd6_output(ifp, origifp, m0, dst, rt0) senderr(EHOSTUNREACH); } } - if (rt->rt_flags & RTF_REJECT) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } /* @@ -1894,8 +1925,10 @@ nd6_output(ifp, origifp, m0, dst, rt0) /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && - ln->ln_state < ND6_LLINFO_REACHABLE) + ln->ln_state < ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } /* * The first time we send a packet to a neighbor whose entry is @@ -1926,14 +1959,12 @@ nd6_output(ifp, origifp, m0, dst, rt0) * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ - if (ln->ln_state == ND6_LLINFO_WAITDELETE || - ln->ln_state == ND6_LLINFO_NOSTATE) + if (ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { - rt->rt_flags &= ~RTF_REJECT; if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; @@ -1946,12 +1977,10 @@ nd6_output(ifp, origifp, m0, dst, rt0) sendpkt: -#ifdef FAKE_LOOPBACK_IF - if (ifp->if_flags & IFF_LOOPBACK) { + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt)); } -#endif return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); bad: @@ -1962,6 +1991,32 @@ nd6_output(ifp, origifp, m0, dst, rt0) #undef senderr int +nd6_need_cache(ifp) + struct ifnet *ifp; +{ + /* + * XXX: we currently do not make neighbor cache on any interface + * other than ARCnet, Ethernet, FDDI and GIF. + * + * RFC2893 says: + * - unidirectional tunnels needs no ND + */ + switch (ifp->if_type) { + case IFT_ARCNET: + case IFT_ETHER: + case IFT_FDDI: + case IFT_IEEE1394: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif + case IFT_GIF: /* XXX need more cases? */ + return(1); + default: + return(0); + } +} + +int nd6_storelladdr(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; @@ -1969,16 +2024,23 @@ nd6_storelladdr(ifp, rt, m, dst, desten) struct sockaddr *dst; u_char *desten; { + int i; struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: - case IFT_FDDI: + case IFT_FDDI: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); - break; + case IFT_IEEE1394: + for (i = 0; i < ifp->if_addrlen; i++) + desten[i] = ~0; + return(1); case IFT_ARCNET: *desten = 0; return(1); @@ -1989,12 +2051,12 @@ nd6_storelladdr(ifp, rt, m, dst, desten) } if (rt == NULL) { - /* This could happen if we could not allocate memory */ + /* this could happen, if we could not allocate memory */ m_freem(m); return(0); } if (rt->rt_gateway->sa_family != AF_LINK) { - printf("nd6_storelladdr: something odd happened\n"); + printf("nd6_storelladdr: something odd happens\n"); m_freem(m); return(0); } @@ -2009,3 +2071,129 @@ nd6_storelladdr(ifp, rt, m, dst, desten) bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return(1); } + +static int nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS); +static int nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS); +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet6_icmp6); +#endif +SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_DRLIST, nd6_drlist, + CTLFLAG_RD, nd6_sysctl_drlist, ""); +SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_PRLIST, nd6_prlist, + CTLFLAG_RD, nd6_sysctl_prlist, ""); + +static int +nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS) +{ + int error; + char buf[1024]; + struct in6_defrouter *d, *de; + struct nd_defrouter *dr; + + if (req->newptr) + return EPERM; + error = 0; + + for (dr = TAILQ_FIRST(&nd_defrouter); + dr; + dr = TAILQ_NEXT(dr, dr_entry)) { + d = (struct in6_defrouter *)buf; + de = (struct in6_defrouter *)(buf + sizeof(buf)); + + if (d + 1 <= de) { + bzero(d, sizeof(*d)); + d->rtaddr.sin6_family = AF_INET6; + d->rtaddr.sin6_len = sizeof(d->rtaddr); + if (in6_recoverscope(&d->rtaddr, &dr->rtaddr, + dr->ifp) != 0) + log(LOG_ERR, + "scope error in " + "default router list (%s)\n", + ip6_sprintf(&dr->rtaddr)); + d->flags = dr->flags; + d->rtlifetime = dr->rtlifetime; + d->expire = dr->expire; + d->if_index = dr->ifp->if_index; + } else + panic("buffer too short"); + + error = SYSCTL_OUT(req, buf, sizeof(*d)); + if (error) + break; + } + return error; +} + +static int +nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS) +{ + int error; + char buf[1024]; + struct in6_prefix *p, *pe; + struct nd_prefix *pr; + + if (req->newptr) + return EPERM; + error = 0; + + for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + u_short advrtrs; + size_t advance; + struct sockaddr_in6 *sin6, *s6; + struct nd_pfxrouter *pfr; + + p = (struct in6_prefix *)buf; + pe = (struct in6_prefix *)(buf + sizeof(buf)); + + if (p + 1 <= pe) { + bzero(p, sizeof(*p)); + sin6 = (struct sockaddr_in6 *)(p + 1); + + p->prefix = pr->ndpr_prefix; + if (in6_recoverscope(&p->prefix, + &p->prefix.sin6_addr, pr->ndpr_ifp) != 0) + log(LOG_ERR, + "scope error in prefix list (%s)\n", + ip6_sprintf(&p->prefix.sin6_addr)); + p->raflags = pr->ndpr_raf; + p->prefixlen = pr->ndpr_plen; + p->vltime = pr->ndpr_vltime; + p->pltime = pr->ndpr_pltime; + p->if_index = pr->ndpr_ifp->if_index; + p->expire = pr->ndpr_expire; + p->refcnt = pr->ndpr_refcnt; + p->flags = pr->ndpr_stateflags; + p->origin = PR_ORIG_RA; + advrtrs = 0; + for (pfr = pr->ndpr_advrtrs.lh_first; + pfr; + pfr = pfr->pfr_next) { + if ((void *)&sin6[advrtrs + 1] > + (void *)pe) { + advrtrs++; + continue; + } + s6 = &sin6[advrtrs]; + bzero(s6, sizeof(*s6)); + s6->sin6_family = AF_INET6; + s6->sin6_len = sizeof(*sin6); + if (in6_recoverscope(s6, + &pfr->router->rtaddr, + pfr->router->ifp) != 0) + log(LOG_ERR, + "scope error in " + "prefix list (%s)\n", + ip6_sprintf(&pfr->router->rtaddr)); + advrtrs++; + } + p->advrtrs = advrtrs; + } else + panic("buffer too short"); + + advance = sizeof(*p) + sizeof(*sin6) * advrtrs; + error = SYSCTL_OUT(req, buf, advance); + if (error) + break; + } + return error; +} diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 26f58b5..73bbcd5 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: nd6.h,v 1.23 2000/06/04 12:54:57 itojun Exp $ */ +/* $KAME: nd6.h,v 1.55 2001/04/27 15:09:49 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -39,6 +39,7 @@ #endif #include <sys/queue.h> +#include <sys/callout.h> struct llinfo_nd6 { struct llinfo_nd6 *ln_next; @@ -53,7 +54,14 @@ struct llinfo_nd6 { }; #define ND6_LLINFO_NOSTATE -2 -#define ND6_LLINFO_WAITDELETE -1 +/* + * We don't need the WAITDELETE state any more, but we keep the definition + * in a comment line instead of removing it. This is necessary to avoid + * unintentionally reusing the value for another purpose, which might + * affect backward compatibility with old applications. + * (20000711 jinmei@kame.net) + */ +/* #define ND6_LLINFO_WAITDELETE -1 */ #define ND6_LLINFO_INCOMPLETE 0 #define ND6_LLINFO_REACHABLE 1 #define ND6_LLINFO_STALE 2 @@ -72,6 +80,10 @@ struct nd_ifinfo { int recalctm; /* BaseReacable re-calculation timer */ u_int8_t chlim; /* CurHopLimit */ u_int8_t receivedra; + /* the followings are for privacy extension for addrconf */ + u_int8_t randomseed0[8]; /* upper 64 bits of MD5 digest */ + u_int8_t randomseed1[8]; /* lower 64 bits (usually the EUI64 IFID) */ + u_int8_t randomid[8]; /* current random ID */ }; #define ND6_IFF_PERFORMNUD 0x1 @@ -98,6 +110,14 @@ struct in6_drlist { } defrouter[DRLSTSIZ]; }; +struct in6_defrouter { + struct sockaddr_in6 rtaddr; + u_char flags; + u_short rtlifetime; + u_long expire; + u_short if_index; +} __attribute__((__packed__)); + struct in6_prlist { char ifname[IFNAMSIZ]; struct { @@ -114,6 +134,38 @@ struct in6_prlist { } prefix[PRLSTSIZ]; }; +struct in6_prefix { + struct sockaddr_in6 prefix; + struct prf_ra raflags; + u_char prefixlen; + u_char origin; + u_long vltime; + u_long pltime; + u_long expire; + u_int32_t flags; + int refcnt; + u_short if_index; + u_short advrtrs; /* number of advertisement routers */ + /* struct sockaddr_in6 advrtr[] */ +} __attribute__((__packed__)); + +#ifdef _KERNEL +struct in6_ondireq { + char ifname[IFNAMSIZ]; + struct { + u_int32_t linkmtu; /* LinkMTU */ + u_int32_t maxmtu; /* Upper bound of LinkMTU */ + u_int32_t basereachable; /* BaseReachableTime */ + u_int32_t reachable; /* Reachable Time */ + u_int32_t retrans; /* Retrans Timer */ + u_int32_t flags; /* Flags */ + int recalctm; /* BaseReacable re-calculation timer */ + u_int8_t chlim; /* CurHopLimit */ + u_int8_t receivedra; + } ndi; +}; +#endif + struct in6_ndireq { char ifname[IFNAMSIZ]; struct nd_ifinfo ndi; @@ -124,6 +176,9 @@ struct in6_ndifreq { u_long ifindex; }; +/* Prefix status */ +#define NDPRF_ONLINK 0x1 +#define NDPRF_DETACHED 0x2 /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /*1sec*/ @@ -139,6 +194,10 @@ struct in6_ndifreq { #define RETRANS_TIMER 1000 /* msec */ #define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */ #define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */ +#define DEF_TEMP_VALID_LIFETIME 604800 /* 1 week */ +#define DEF_TEMP_PREFERRED_LIFETIME 86400 /* 1 day */ +#define TEMPADDR_REGEN_ADVANCE 5 /* sec */ +#define MAX_TEMP_DESYNC_FACTOR 600 /* 10 min */ #define ND_COMPUTE_RTIME(x) \ (((MIN_RANDOM_FACTOR * (x >> 10)) + (random() & \ ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000) @@ -167,13 +226,11 @@ struct nd_prefix { time_t ndpr_expire; /* expiration time of the prefix */ time_t ndpr_preferred; /* preferred time of the prefix */ struct prf_ra ndpr_flags; + u_int32_t ndpr_stateflags; /* actual state flags */ /* list of routers that advertise the prefix: */ LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs; u_char ndpr_plen; - struct ndpr_stateflags { - /* if this prefix can be regarded as on-link */ - u_char onlink : 1; - } ndpr_stateflags; + int ndpr_refcnt; /* reference couter from addresses */ }; #define ndpr_next ndpr_entry.le_next @@ -182,9 +239,6 @@ struct nd_prefix { #define ndpr_raf_onlink ndpr_flags.onlink #define ndpr_raf_auto ndpr_flags.autonomous -#define ndpr_statef_onlink ndpr_stateflags.onlink -#define ndpr_statef_addmark ndpr_stateflags.addmark - /* * We keep expired prefix for certain amount of time, for validation purposes. * 1800s = MaxRtrAdvInterval @@ -235,13 +289,23 @@ extern int nd6_umaxtries; extern int nd6_mmaxtries; extern int nd6_useloopback; extern int nd6_maxnudhint; +extern int nd6_gctimer; extern struct llinfo_nd6 llinfo_nd6; extern struct nd_ifinfo *nd_ifinfo; extern struct nd_drhead nd_defrouter; extern struct nd_prhead nd_prefix; +extern int nd6_debug; + +#define nd6log(x) do { if (nd6_debug) log x; } while (0) + +extern struct callout nd6_timer_ch; /* nd6_rtr.c */ extern int nd6_defifindex; +extern int ip6_desync_factor; /* seconds */ +extern u_int32_t ip6_temp_preferred_lifetime; /* seconds */ +extern u_int32_t ip6_temp_valid_lifetime; /* seconds */ +extern int ip6_temp_regen_advance; /* seconds */ union nd_opts { struct nd_opt_hdr *nd_opt_array[9]; /*max = home agent info*/ @@ -285,30 +349,30 @@ struct rtentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *)); void nd6_setmtu __P((struct ifnet *)); void nd6_timer __P((void *)); void nd6_purge __P((struct ifnet *)); -void nd6_free __P((struct rtentry *)); +struct llinfo_nd6 *nd6_free __P((struct rtentry *)); void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int)); int nd6_resolve __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *)); void nd6_rtrequest __P((int, struct rtentry *, struct sockaddr *)); -void nd6_p2p_rtrequest __P((int, struct rtentry *, struct sockaddr *)); int nd6_ioctl __P((u_long, caddr_t, struct ifnet *)); struct rtentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *, char *, int, int, int)); -/* for test */ int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *, struct rtentry *)); int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *)); +int nd6_need_cache __P((struct ifnet *)); /* nd6_nbr.c */ void nd6_na_input __P((struct mbuf *, int, int)); -void nd6_na_output __P((struct ifnet *, struct in6_addr *, - struct in6_addr *, u_long, int, struct sockaddr *)); +void nd6_na_output __P((struct ifnet *, const struct in6_addr *, + const struct in6_addr *, u_long, int, struct sockaddr *)); void nd6_ns_input __P((struct mbuf *, int, int)); -void nd6_ns_output __P((struct ifnet *, struct in6_addr *, - struct in6_addr *, struct llinfo_nd6 *, int)); +void nd6_ns_output __P((struct ifnet *, const struct in6_addr *, + const struct in6_addr *, struct llinfo_nd6 *, int)); caddr_t nd6_ifptomac __P((struct ifnet *)); void nd6_dad_start __P((struct ifaddr *, int *)); +void nd6_dad_stop __P((struct ifaddr *)); void nd6_dad_duplicated __P((struct ifaddr *)); /* nd6_rtr.c */ @@ -321,14 +385,19 @@ void defrouter_select __P((void)); void defrtrlist_del __P((struct nd_defrouter *)); void prelist_remove __P((struct nd_prefix *)); int prelist_update __P((struct nd_prefix *, struct nd_defrouter *, - struct mbuf *)); + struct mbuf *)); +int nd6_prelist_add __P((struct nd_prefix *, struct nd_defrouter *, + struct nd_prefix **)); +int nd6_prefix_onlink __P((struct nd_prefix *)); +int nd6_prefix_offlink __P((struct nd_prefix *)); void pfxlist_onlink_check __P((void)); struct nd_defrouter *defrouter_lookup __P((struct in6_addr *, struct ifnet *)); -int in6_ifdel __P((struct ifnet *, struct in6_addr *)); +struct nd_prefix *nd6_prefix_lookup __P((struct nd_prefix *)); int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr)); void rt6_flush __P((struct in6_addr *, struct ifnet *)); int nd6_setdefaultiface __P((int)); +int in6_tmpifadd __P((const struct in6_ifaddr *, int)); #endif /* _KERNEL */ diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index d3fa831..7527d43 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: nd6_nbr.c,v 1.37 2000/06/04 12:46:13 itojun Exp $ */ +/* $KAME: nd6_nbr.c,v 1.64 2001/05/17 03:48:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -45,6 +45,7 @@ #include <sys/errno.h> #include <sys/syslog.h> #include <sys/queue.h> +#include <sys/callout.h> #include <net/if.h> #include <net/if_types.h> @@ -72,6 +73,8 @@ struct dadq; static struct dadq *nd6_dad_find __P((struct ifaddr *)); +static void nd6_dad_starttimer __P((struct dadq *, int)); +static void nd6_dad_stoptimer __P((struct dadq *)); static void nd6_dad_timer __P((struct ifaddr *)); static void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *)); static void nd6_dad_ns_input __P((struct ifaddr *)); @@ -106,10 +109,25 @@ nd6_ns_input(m, off, icmp6len) union nd_opts ndopts; struct sockaddr_dl *proxydl = NULL; +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, icmp6len,); + nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); + if (nd_ns == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } +#endif + ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ + taddr6 = nd_ns->nd_ns_target; + if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_ns_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { @@ -121,26 +139,14 @@ nd6_ns_input(m, off, icmp6len) && daddr6.s6_addr8[12] == 0xff) { ; /*good*/ } else { - log(LOG_INFO, "nd6_ns_input: bad DAD packet " - "(wrong ip6 dst)\n"); + nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " + "(wrong ip6 dst)\n")); goto bad; } } -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, icmp6len,); - nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); -#else - IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); - if (nd_ns == NULL) { - icmp6stat.icp6s_tooshort++; - return; - } -#endif - taddr6 = nd_ns->nd_ns_target; - if (IN6_IS_ADDR_MULTICAST(&taddr6)) { - log(LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"); + nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n")); goto bad; } @@ -150,8 +156,10 @@ nd6_ns_input(m, off, icmp6len) icmp6len -= sizeof(*nd_ns); nd6_option_init(nd_ns + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_ns_input: invalid ND option, ignored\n"); - goto bad; + nd6log((LOG_INFO, + "nd6_ns_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ + goto freeit; } if (ndopts.nd_opts_src_lladdr) { @@ -160,8 +168,8 @@ nd6_ns_input(m, off, icmp6len) } if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { - log(LOG_INFO, "nd6_ns_input: bad DAD packet " - "(link-layer address option)\n"); + nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " + "(link-layer address option)\n")); goto bad; } @@ -223,7 +231,7 @@ nd6_ns_input(m, off, icmp6len) } if (!ifa) { /* - * We've got a NS packet, and we don't have that adddress + * We've got an NS packet, and we don't have that adddress * assigned for us. We MUST silently ignore it. * See RFC2461 7.2.3. */ @@ -236,10 +244,11 @@ nd6_ns_input(m, off, icmp6len) goto freeit; if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " "(if %d, NS packet %d)\n", - ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { @@ -306,9 +315,10 @@ nd6_ns_input(m, off, icmp6len) return; bad: - log(LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)); - log(LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)); - log(LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)); + nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6))); + nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6))); + nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6))); + icmp6stat.icp6s_badns++; m_freem(m); } @@ -324,7 +334,7 @@ nd6_ns_input(m, off, icmp6len) void nd6_ns_output(ifp, daddr6, taddr6, ln, dad) struct ifnet *ifp; - struct in6_addr *daddr6, *taddr6; + const struct in6_addr *daddr6, *taddr6; struct llinfo_nd6 *ln; /* for source address determination */ int dad; /* duplicated address detection */ { @@ -362,6 +372,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) } if (m == NULL) return; + m->m_pkthdr.rcvif = NULL; if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { m->m_flags |= M_MCAST; @@ -495,7 +506,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) #ifdef IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif); if (outif) { @@ -541,9 +552,11 @@ nd6_na_input(m, off, icmp6len) union nd_opts ndopts; if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } #ifndef PULLDOWN_TEST @@ -566,22 +579,24 @@ nd6_na_input(m, off, icmp6len) taddr6.s6_addr16[1] = htons(ifp->if_index); if (IN6_IS_ADDR_MULTICAST(&taddr6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "nd6_na_input: invalid target address %s\n", - ip6_sprintf(&taddr6)); - goto freeit; + ip6_sprintf(&taddr6))); + goto bad; } if (IN6_IS_ADDR_MULTICAST(&daddr6)) if (is_solicited) { - log(LOG_ERR, - "nd6_na_input: a solicited adv is multicasted\n"); - goto freeit; + nd6log((LOG_ERR, + "nd6_na_input: a solicited adv is multicasted\n")); + goto bad; } icmp6len -= sizeof(*nd_na); nd6_option_init(nd_na + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_na_input: invalid ND option, ignored\n"); + nd6log((LOG_INFO, + "nd6_na_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ goto freeit; } @@ -616,10 +631,11 @@ nd6_na_input(m, off, icmp6len) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s " "(if %d, NA packet %d)\n", - ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } /* @@ -649,10 +665,19 @@ nd6_na_input(m, off, icmp6len) ln->ln_byhint = 0; if (ln->ln_expire) ln->ln_expire = time_second + - nd_ifinfo[rt->rt_ifp->if_index].reachable; - } else + nd_ifinfo[rt->rt_ifp->if_index].reachable; + } else { ln->ln_state = ND6_LLINFO_STALE; - ln->ln_router = is_router; + ln->ln_expire = time_second + nd6_gctimer; + } + if ((ln->ln_router = is_router) != 0) { + /* + * This means a router's state has changed from + * non-reachable to probably reachable, and might + * affect the status of associated prefixes.. + */ + pfxlist_onlink_check(); + } } else { int llchange; @@ -695,8 +720,10 @@ nd6_na_input(m, off, icmp6len) * If state is REACHABLE, make it STALE. * no other updates should be done. */ - if (ln->ln_state == ND6_LLINFO_REACHABLE) + if (ln->ln_state == ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } goto freeit; } else if (is_override /* (2a) */ || (!is_override && (lladdr && !llchange)) /* (2b) */ @@ -719,11 +746,13 @@ nd6_na_input(m, off, icmp6len) ln->ln_byhint = 0; if (ln->ln_expire) { ln->ln_expire = time_second + - nd_ifinfo[ifp->if_index].reachable; + nd_ifinfo[ifp->if_index].reachable; } } else { - if (lladdr && llchange) + if (lladdr && llchange) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } } } @@ -759,21 +788,22 @@ nd6_na_input(m, off, icmp6len) rt->rt_flags &= ~RTF_REJECT; ln->ln_asked = 0; if (ln->ln_hold) { -#ifdef OLDIP6OUTPUT - (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); -#else /* * we assume ifp is not a p2p here, so just set the 2nd * argument as the 1st one. */ nd6_output(ifp, ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); -#endif ln->ln_hold = 0; } freeit: m_freem(m); + return; + + bad: + icmp6stat.icp6s_badna++; + m_freem(m); } /* @@ -788,7 +818,7 @@ nd6_na_input(m, off, icmp6len) void nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) struct ifnet *ifp; - struct in6_addr *daddr6, *taddr6; + const struct in6_addr *daddr6, *taddr6; u_long flags; int tlladdr; /* 1 if include target link-layer address */ struct sockaddr *sdl0; /* sockaddr_dl (= proxy NA) or NULL */ @@ -824,6 +854,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) } if (m == NULL) return; + m->m_pkthdr.rcvif = NULL; if (IN6_IS_ADDR_MULTICAST(daddr6)) { m->m_flags |= M_MCAST; @@ -917,7 +948,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) #ifdef IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif ip6_output(m, NULL, NULL, 0, &im6o, &outif); if (outif) { @@ -935,6 +966,10 @@ nd6_ifptomac(ifp) case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: + case IFT_IEEE1394: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif return ((caddr_t)(ifp + 1)); break; default: @@ -951,10 +986,11 @@ struct dadq { int dad_ns_ocount; /* NS sent so far */ int dad_ns_icount; int dad_na_icount; - struct callout_handle dad_timer; + struct callout dad_timer_ch; }; static struct dadq_head dadq; +static int dad_init = 0; static struct dadq * nd6_dad_find(ifa) @@ -969,6 +1005,24 @@ nd6_dad_find(ifa) return NULL; } +static void +nd6_dad_starttimer(dp, ticks) + struct dadq *dp; + int ticks; +{ + + callout_reset(&dp->dad_timer_ch, ticks, + (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa); +} + +static void +nd6_dad_stoptimer(dp) + struct dadq *dp; +{ + + callout_stop(&dp->dad_timer_ch); +} + /* * Start Duplicated Address Detection (DAD) for specified interface address. */ @@ -979,7 +1033,6 @@ nd6_dad_start(ifa, tick) { struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp; - static int dad_init = 0; if (!dad_init) { TAILQ_INIT(&dadq); @@ -1026,12 +1079,11 @@ nd6_dad_start(ifa, tick) return; } bzero(dp, sizeof(*dp)); + callout_init(&dp->dad_timer_ch, 0); TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); -#ifdef ND6_DEBUG - log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), - ip6_sprintf(&ia->ia_addr.sin6_addr)); -#endif + nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), + ip6_sprintf(&ia->ia_addr.sin6_addr))); /* * Send NS packet for DAD, ip6_dad_count times. @@ -1040,15 +1092,14 @@ nd6_dad_start(ifa, tick) * (re)initialization. */ dp->dad_ifa = ifa; - ifa->ifa_refcnt++; /*just for safety*/ + IFAREF(ifa); /*just for safety*/ dp->dad_count = ip6_dad_count; dp->dad_ns_icount = dp->dad_na_icount = 0; dp->dad_ns_ocount = dp->dad_ns_tcount = 0; if (!tick) { nd6_dad_ns_output(dp, ifa); - dp->dad_timer = - timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa, - nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000); + nd6_dad_starttimer(dp, + nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000); } else { int ntick; @@ -1057,12 +1108,35 @@ nd6_dad_start(ifa, tick) else ntick = *tick + random() % (hz / 2); *tick = ntick; - dp->dad_timer = - timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa, - ntick); + nd6_dad_starttimer(dp, ntick); } } +/* + * terminate DAD unconditionally. used for address removals. + */ +void +nd6_dad_stop(ifa) + struct ifaddr *ifa; +{ + struct dadq *dp; + + if (!dad_init) + return; + dp = nd6_dad_find(ifa); + if (!dp) { + /* DAD wasn't started yet */ + return; + } + + nd6_dad_stoptimer(dp); + + TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); + free(dp, M_IP6NDP); + dp = NULL; + IFAFREE(ifa); +} + static void nd6_dad_timer(ifa) struct ifaddr *ifa; @@ -1100,8 +1174,8 @@ nd6_dad_timer(ifa) /* timeouted with IFF_{RUNNING,UP} check */ if (dp->dad_ns_tcount > dad_maxtry) { - log(LOG_ERR, "%s: could not run DAD, driver problem?\n", - if_name(ifa->ifa_ifp)); + nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n", + if_name(ifa->ifa_ifp))); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); @@ -1116,9 +1190,8 @@ nd6_dad_timer(ifa) * We have more NS to go. Send NS packet for DAD. */ nd6_dad_ns_output(dp, ifa); - dp->dad_timer = - timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa, - nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000); + nd6_dad_starttimer(dp, + nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000); } else { /* * We have transmitted sufficient number of DAD packets. @@ -1177,12 +1250,10 @@ nd6_dad_timer(ifa) */ ia->ia6_flags &= ~IN6_IFF_TENTATIVE; -#ifdef ND6_DEBUG - log(LOG_INFO, + nd6log((LOG_DEBUG, "%s: DAD complete for %s - no duplicates found\n", if_name(ifa->ifa_ifp), - ip6_sprintf(&ia->ia_addr.sin6_addr)); -#endif + ip6_sprintf(&ia->ia_addr.sin6_addr))); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); @@ -1208,18 +1279,16 @@ nd6_dad_duplicated(ifa) return; } - log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: %d NS, " - "%d NA\n", if_name(ifa->ifa_ifp), - ip6_sprintf(&ia->ia_addr.sin6_addr), - dp->dad_ns_icount, dp->dad_na_icount); + log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " + "NS in/out=%d/%d, NA in=%d\n", + if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr), + dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount); ia->ia6_flags &= ~IN6_IFF_TENTATIVE; ia->ia6_flags |= IN6_IFF_DUPLICATED; /* We are done with DAD, with duplicated address found. (failure) */ - untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa - , dp->dad_timer - ); + nd6_dad_stoptimer(dp); log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr)); @@ -1264,7 +1333,7 @@ nd6_dad_ns_input(ifa) { struct in6_ifaddr *ia; struct ifnet *ifp; - struct in6_addr *taddr6; + const struct in6_addr *taddr6; struct dadq *dp; int duplicate; @@ -1277,17 +1346,12 @@ nd6_dad_ns_input(ifa) duplicate = 0; dp = nd6_dad_find(ifa); - /* - * If it is from myself, ignore this. - */ - if (ifp && (ifp->if_flags & IFF_LOOPBACK)) - return; - /* Quickhack - completely ignore DAD NS packets */ if (dad_ignore_ns) { - log(LOG_INFO, "nd6_dad_ns_input: ignoring DAD NS packet for " + nd6log((LOG_INFO, + "nd6_dad_ns_input: ignoring DAD NS packet for " "address %s(%s)\n", ip6_sprintf(taddr6), - if_name(ifa->ifa_ifp)); + if_name(ifa->ifa_ifp))); return; } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 258a59c..715ccf0 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: nd6_rtr.c,v 1.47 2000/08/08 08:58:42 jinmei Exp $ */ +/* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -40,8 +40,10 @@ #include <sys/socket.h> #include <sys/sockio.h> #include <sys/time.h> +#include <sys/kernel.h> #include <sys/errno.h> #include <sys/syslog.h> +#include <sys/queue.h> #include <net/if.h> #include <net/if_types.h> @@ -51,6 +53,7 @@ #include <netinet/in.h> #include <netinet6/in6_var.h> +#include <netinet6/in6_ifattach.h> #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> @@ -62,34 +65,39 @@ #define SDL(s) ((struct sockaddr_dl *)s) static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *)); -static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *)); -static struct nd_prefix *prefix_lookup __P((struct nd_prefix *)); -static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *, - struct in6_addr *, int)); +static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *, + struct in6_addr *)); static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, - struct nd_defrouter *)); + struct nd_defrouter *)); static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); static void pfxrtr_del __P((struct nd_pfxrouter *)); static struct nd_pfxrouter *find_pfxlist_reachable_router - __P((struct nd_prefix *)); -static void nd6_detach_prefix __P((struct nd_prefix *)); -static void nd6_attach_prefix __P((struct nd_prefix *)); + __P((struct nd_prefix *)); static void defrouter_addifreq __P((struct ifnet *)); -#ifdef ND6_USE_RTSOCK -static void defrouter_msg __P((int, struct rtentry *)); -#endif +static void nd6_rtmsg __P((int, struct rtentry *)); static void in6_init_address_ltimes __P((struct nd_prefix *ndpr, - struct in6_addrlifetime *lt6, - int update_vltime)); + struct in6_addrlifetime *lt6)); static int rt6_deleteroute __P((struct radix_node *, void *)); extern int nd6_recalc_reachtm_interval; -struct ifnet *nd6_defifp; +static struct ifnet *nd6_defifp; int nd6_defifindex; +int ip6_use_tempaddr = 0; + +int ip6_desync_factor; +u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; +u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; +/* + * shorter lifetimes for debugging purposes. +int ip6_temp_preferred_lifetime = 800; +static int ip6_temp_valid_lifetime = 1800; +*/ +int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; + /* * Receive Router Solicitation Message - just for routers. * Router solicitation/advertisement is mostly managed by userland program @@ -125,9 +133,11 @@ nd6_rs_input(m, off, icmp6len) /* Sanity checks */ if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } /* @@ -151,7 +161,9 @@ nd6_rs_input(m, off, icmp6len) icmp6len -= sizeof(*nd_rs); nd6_option_init(nd_rs + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n"); + nd6log((LOG_INFO, + "nd6_rs_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ goto freeit; } @@ -161,16 +173,22 @@ nd6_rs_input(m, off, icmp6len) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_rs_input: lladdrlen mismatch for %s " "(if %d, RS packet %d)\n", - ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); freeit: m_freem(m); + return; + + bad: + icmp6stat.icp6s_badrs++; + m_freem(m); } /* @@ -203,16 +221,18 @@ nd6_ra_input(m, off, icmp6len) goto freeit; if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "nd6_ra_input: src %s is not link-local\n", - ip6_sprintf(&saddr6)); - goto freeit; + ip6_sprintf(&saddr6))); + goto bad; } #ifndef PULLDOWN_TEST @@ -229,7 +249,9 @@ nd6_ra_input(m, off, icmp6len) icmp6len -= sizeof(*nd_ra); nd6_option_init(nd_ra + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n"); + nd6log((LOG_INFO, + "nd6_ra_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ goto freeit; } @@ -267,7 +289,7 @@ nd6_ra_input(m, off, icmp6len) */ if (ndopts.nd_opts_pi) { struct nd_opt_hdr *pt; - struct nd_opt_prefix_info *pi; + struct nd_opt_prefix_info *pi = NULL; struct nd_prefix pr; for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; @@ -279,34 +301,38 @@ nd6_ra_input(m, off, icmp6len) pi = (struct nd_opt_prefix_info *)pt; if (pi->nd_opt_pi_len != 4) { - log(LOG_INFO, "nd6_ra_input: invalid option " - "len %d for prefix information option, " - "ignored\n", pi->nd_opt_pi_len); + nd6log((LOG_INFO, + "nd6_ra_input: invalid option " + "len %d for prefix information option, " + "ignored\n", pi->nd_opt_pi_len)); continue; } if (128 < pi->nd_opt_pi_prefix_len) { - log(LOG_INFO, "nd6_ra_input: invalid prefix " - "len %d for prefix information option, " - "ignored\n", pi->nd_opt_pi_prefix_len); + nd6log((LOG_INFO, + "nd6_ra_input: invalid prefix " + "len %d for prefix information option, " + "ignored\n", pi->nd_opt_pi_prefix_len)); continue; } if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { - log(LOG_INFO, "nd6_ra_input: invalid prefix " - "%s, ignored\n", - ip6_sprintf(&pi->nd_opt_pi_prefix)); + nd6log((LOG_INFO, + "nd6_ra_input: invalid prefix " + "%s, ignored\n", + ip6_sprintf(&pi->nd_opt_pi_prefix))); continue; } /* aggregatable unicast address, rfc2374 */ if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20 && pi->nd_opt_pi_prefix_len != 64) { - log(LOG_INFO, "nd6_ra_input: invalid prefixlen " - "%d for rfc2374 prefix %s, ignored\n", - pi->nd_opt_pi_prefix_len, - ip6_sprintf(&pi->nd_opt_pi_prefix)); + nd6log((LOG_INFO, + "nd6_ra_input: invalid prefixlen " + "%d for rfc2374 prefix %s, ignored\n", + pi->nd_opt_pi_prefix_len, + ip6_sprintf(&pi->nd_opt_pi_prefix))); continue; } @@ -340,9 +366,9 @@ nd6_ra_input(m, off, icmp6len) /* lower bound */ if (mtu < IPV6_MMTU) { - log(LOG_INFO, "nd6_ra_input: bogus mtu option " + nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " "mtu=%d sent from %s, ignoring\n", - mtu, ip6_sprintf(&ip6->ip6_src)); + mtu, ip6_sprintf(&ip6->ip6_src))); goto skip; } @@ -355,17 +381,17 @@ nd6_ra_input(m, off, icmp6len) if (change) /* in6_maxmtu may change */ in6_setmaxmtu(); } else { - log(LOG_INFO, "nd6_ra_input: bogus mtu " + nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " "mtu=%d sent from %s; " "exceeds maxmtu %d, ignoring\n", mtu, ip6_sprintf(&ip6->ip6_src), - ndi->maxmtu); + ndi->maxmtu)); } } else { - log(LOG_INFO, "nd6_ra_input: mtu option " + nd6log((LOG_INFO, "nd6_ra_input: mtu option " "mtu=%d sent from %s; maxmtu unknown, " "ignoring\n", - mtu, ip6_sprintf(&ip6->ip6_src)); + mtu, ip6_sprintf(&ip6->ip6_src))); } } @@ -384,10 +410,11 @@ nd6_ra_input(m, off, icmp6len) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_ra_input: lladdrlen mismatch for %s " "(if %d, RA packet %d)\n", - ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); @@ -400,7 +427,12 @@ nd6_ra_input(m, off, icmp6len) pfxlist_onlink_check(); } -freeit: + freeit: + m_freem(m); + return; + + bad: + icmp6stat.icp6s_badra++; m_freem(m); } @@ -408,10 +440,9 @@ freeit: * default router list proccessing sub routines */ -#ifdef ND6_USE_RTSOCK /* tell the change to user processes watching the routing socket. */ static void -defrouter_msg(cmd, rt) +nd6_rtmsg(cmd, rt) int cmd; struct rtentry *rt; { @@ -421,10 +452,12 @@ defrouter_msg(cmd, rt) info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_IFP] = + (struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist); + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; rt_missmsg(cmd, &info, rt->rt_flags, 0); } -#endif void defrouter_addreq(new) @@ -448,9 +481,7 @@ defrouter_addreq(new) (struct sockaddr *)&gate, (struct sockaddr *)&mask, RTF_GATEWAY, &newrt); if (newrt) { -#ifdef ND6_USE_RTSOCK - defrouter_msg(RTM_ADD, newrt); /* tell user process */ -#endif + nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ newrt->rt_refcnt--; } splx(s); @@ -478,31 +509,27 @@ defrouter_addifreq(ifp) * XXX: An IPv6 address are required to be assigned on the interface. */ if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) { - log(LOG_ERR, /* better error? */ + nd6log((LOG_ERR, /* better error? */ "defrouter_addifreq: failed to find an ifaddr " "to install a route to interface %s\n", - if_name(ifp)); + if_name(ifp))); return; } flags = ifa->ifa_flags; - if ((ifp->if_flags & IFF_POINTOPOINT) != 0) - flags &= ~RTF_CLONING; - if ((error = rtrequest(RTM_ADD, (struct sockaddr *)&def, - ifa->ifa_addr, (struct sockaddr *)&mask, - flags, &newrt)) != 0) { - log(LOG_ERR, + error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr, + (struct sockaddr *)&mask, flags, &newrt); + if (error != 0) { + nd6log((LOG_ERR, "defrouter_addifreq: failed to install a route to " "interface %s (errno = %d)\n", - if_name(ifp), error); + if_name(ifp), error)); if (newrt) /* maybe unnecessary, but do it for safety */ newrt->rt_refcnt--; } else { if (newrt) { -#ifdef ND6_USE_RTSOCK - defrouter_msg(RTM_ADD, newrt); -#endif + nd6_rtmsg(RTM_ADD, newrt); newrt->rt_refcnt--; } } @@ -546,9 +573,7 @@ defrouter_delreq(dr, dofree) (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); if (oldrt) { -#ifdef ND6_USE_RTSOCK - defrouter_msg(RTM_DELETE, oldrt); -#endif + nd6_rtmsg(RTM_DELETE, oldrt); if (oldrt->rt_refcnt <= 0) { /* * XXX: borrowed from the RTM_DELETE case of @@ -669,15 +694,17 @@ defrouter_select() /* * Install a route to the default interface * as default route. + * XXX: we enable this for host only, because + * this may override a default route installed + * a user process (e.g. routing daemon) in a + * router case. */ defrouter_addifreq(nd6_defifp); - } -#ifdef ND6_DEBUG - else /* noisy log? */ - log(LOG_INFO, "defrouter_select: " + } else { + nd6log((LOG_INFO, "defrouter_select: " "there's no default router and no default" - " interface\n"); -#endif + " interface\n")); + } } } @@ -775,8 +802,8 @@ pfxrtr_del(pfr) free(pfr, M_IP6NDP); } -static struct nd_prefix * -prefix_lookup(pr) +struct nd_prefix * +nd6_prefix_lookup(pr) struct nd_prefix *pr; { struct nd_prefix *search; @@ -795,12 +822,12 @@ prefix_lookup(pr) return(search); } -static int -prelist_add(pr, dr) - struct nd_prefix *pr; +int +nd6_prelist_add(pr, dr, newp) + struct nd_prefix *pr, **newp; struct nd_defrouter *dr; { - struct nd_prefix *new; + struct nd_prefix *new = NULL; int i, s; new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); @@ -808,9 +835,10 @@ prelist_add(pr, dr) return ENOMEM; bzero(new, sizeof(*new)); *new = *pr; + if (newp != NULL) + *newp = new; /* initilization */ - new->ndpr_statef_onlink = pr->ndpr_statef_onlink; LIST_INIT(&new->ndpr_advrtrs); in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); /* make prefix in the canonical form */ @@ -818,13 +846,24 @@ prelist_add(pr, dr) new->ndpr_prefix.sin6_addr.s6_addr32[i] &= new->ndpr_mask.s6_addr32[i]; - /* xxx ND_OPT_PI_FLAG_ONLINK processing */ - s = splnet(); /* link ndpr_entry to nd_prefix list */ LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); splx(s); + /* ND_OPT_PI_FLAG_ONLINK processing */ + if (new->ndpr_raf_onlink) { + int e; + + if ((e = nd6_prefix_onlink(new)) != 0) { + nd6log((LOG_ERR, "nd6_prelist_add: failed to make " + "the prefix %s/%d on-link on %s (errno=%d)\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); + /* proceed anyway. XXX: is it correct? */ + } + } + if (dr) { pfxrtr_add(new, dr); } @@ -837,12 +876,35 @@ prelist_remove(pr) struct nd_prefix *pr; { struct nd_pfxrouter *pfr, *next; - int s; + int e, s; + + /* make sure to invalidate the prefix until it is really freed. */ + pr->ndpr_vltime = 0; + pr->ndpr_pltime = 0; +#if 0 + /* + * Though these flags are now meaningless, we'd rather keep the value + * not to confuse users when executing "ndp -p". + */ + pr->ndpr_raf_onlink = 0; + pr->ndpr_raf_auto = 0; +#endif + if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && + (e = nd6_prefix_offlink(pr)) != 0) { + nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " + "on %s, errno=%d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); + /* what should we do? */ + } + + if (pr->ndpr_refcnt > 0) + return; /* notice here? */ s = splnet(); + /* unlink ndpr_entry from nd_prefix list */ LIST_REMOVE(pr, ndpr_entry); - splx(s); /* free list of routers that adversed the prefix */ for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { @@ -850,30 +912,28 @@ prelist_remove(pr) free(pfr, M_IP6NDP); } + splx(s); + free(pr, M_IP6NDP); pfxlist_onlink_check(); } -/* - * NOTE: We set address lifetime to keep - * address lifetime <= prefix lifetime - * invariant. This is to simplify on-link determination code. - * If onlink determination is udated, this routine may have to be updated too. - */ int prelist_update(new, dr, m) struct nd_prefix *new; struct nd_defrouter *dr; /* may be NULL */ struct mbuf *m; { - struct in6_ifaddr *ia6 = NULL; + struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; + struct ifaddr *ifa; + struct ifnet *ifp = new->ndpr_ifp; struct nd_prefix *pr; int s = splnet(); int error = 0; + int newprefix = 0; int auth; - struct in6_addrlifetime *lt6; - u_char onlink; /* Mobile IPv6 */ + struct in6_addrlifetime lt6_tmp; auth = 0; if (m) { @@ -887,170 +947,259 @@ prelist_update(new, dr, m) #endif } - if ((pr = prefix_lookup(new)) != NULL) { - if (pr->ndpr_ifp != new->ndpr_ifp) { - error = EADDRNOTAVAIL; - goto end; - } - - /* update prefix information */ - pr->ndpr_flags = new->ndpr_flags; - pr->ndpr_vltime = new->ndpr_vltime; - pr->ndpr_pltime = new->ndpr_pltime; - pr->ndpr_preferred = new->ndpr_preferred; - pr->ndpr_expire = new->ndpr_expire; + if ((pr = nd6_prefix_lookup(new)) != NULL) { /* - * RFC 2462 5.5.3 (d) or (e) - * We got a prefix which we have seen in the past. + * nd6_prefix_lookup() ensures that pr and new have the same + * prefix on a same interface. */ - if (!new->ndpr_raf_auto) - goto noautoconf1; - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); + /* + * Update prefix information. Note that the on-link (L) bit + * and the autonomous (A) bit should NOT be changed from 1 + * to 0. + */ + if (new->ndpr_raf_onlink == 1) + pr->ndpr_raf_onlink = 1; + if (new->ndpr_raf_auto == 1) + pr->ndpr_raf_auto = 1; + if (new->ndpr_raf_onlink) { + pr->ndpr_vltime = new->ndpr_vltime; + pr->ndpr_pltime = new->ndpr_pltime; + pr->ndpr_preferred = new->ndpr_preferred; + pr->ndpr_expire = new->ndpr_expire; + } - if (ia6 == NULL) { - /* - * Special case: - * (1) We have seen the prefix advertised before, but - * we have never performed autoconfig for this prefix. - * This is because Autonomous bit was 0 previously, or - * autoconfig failed due to some other reasons. - * (2) We have seen the prefix advertised before and - * we have performed autoconfig in the past, but - * we seem to have no interface address right now. - * This is because the interface address have expired. - * - * This prefix is fresh, with respect to autoconfig - * process. - * - * Add an address based on RFC 2462 5.5.3 (d). - */ - ia6 = in6_ifadd(pr->ndpr_ifp, - &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr, - new->ndpr_plen); - if (!ia6) { - error = EADDRNOTAVAIL; - log(LOG_ERR, "prelist_update: failed to add a " - "new address\n"); - goto noautoconf1; + if (new->ndpr_raf_onlink && + (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { + int e; + + if ((e = nd6_prefix_onlink(pr)) != 0) { + nd6log((LOG_ERR, + "prelist_update: failed to make " + "the prefix %s/%d on-link on %s " + "(errno=%d)\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); + /* proceed anyway. XXX: is it correct? */ } + } - lt6 = &ia6->ia6_lifetime; + if (dr && pfxrtr_lookup(pr, dr) == NULL) + pfxrtr_add(pr, dr); + } else { + struct nd_prefix *newpr = NULL; - /* address lifetime <= prefix lifetime */ - lt6->ia6t_vltime = new->ndpr_vltime; - lt6->ia6t_pltime = new->ndpr_pltime; - in6_init_address_ltimes(new, lt6, 1); - } else { -#define TWOHOUR (120*60) - /* - * We have seen the prefix before, and we have added - * interface address in the past. We still have - * the interface address assigned. - * - * update address lifetime based on RFC 2462 - * 5.5.3 (e). - */ - int update = 0; - - lt6 = &ia6->ia6_lifetime; - -#if 0 /* RFC 2462 5.5.3 (e) */ - lt6->ia6t_pltime = new->ndpr_pltime; - if (TWOHOUR < new->ndpr_vltime - || lt6pr->nd < new->ndpr_vltime) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } else if (auth - && lt6->ia6t_vltime <= TWOHOUR0 - && new->ndpr_vltime <= lt6->ia6t_vltime) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } else { - lt6->ia6t_vltime = TWOHOUR; - update++; - } + newprefix = 1; - /* 2 hour rule is not imposed for pref lifetime */ - new->ndpr_apltime = new->ndpr_pltime; - lt6->ia6t_pltime = new->ndpr_pltime; -#else /* update from Jim Bound, (ipng 6712) */ - if (TWOHOUR < new->ndpr_vltime - || lt6->ia6t_vltime < new->ndpr_vltime) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } else if (auth) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } + if (new->ndpr_vltime == 0) + goto end; + if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) + goto end; - /* jim bound rule is not imposed for pref lifetime */ - lt6->ia6t_pltime = new->ndpr_pltime; -#endif - in6_init_address_ltimes(new, lt6, update); + bzero(&new->ndpr_addr, sizeof(struct in6_addr)); + + error = nd6_prelist_add(new, dr, &newpr); + if (error != 0 || newpr == NULL) { + nd6log((LOG_NOTICE, "prelist_update: " + "nd6_prelist_add failed for %s/%d on %s " + "errno=%d, returnpr=%p\n", + ip6_sprintf(&new->ndpr_prefix.sin6_addr), + new->ndpr_plen, if_name(new->ndpr_ifp), + error, newpr)); + goto end; /* we should just give up in this case. */ } - noautoconf1: + /* + * XXX: from the ND point of view, we can ignore a prefix + * with the on-link bit being zero. However, we need a + * prefix structure for references from autoconfigured + * addresses. Thus, we explicitly make suret that the prefix + * itself expires now. + */ + if (newpr->ndpr_raf_onlink == 0) { + newpr->ndpr_vltime = 0; + newpr->ndpr_pltime = 0; + in6_init_prefix_ltimes(newpr); + } -#if 0 - /* address lifetime expire processing, RFC 2462 5.5.4. */ - if (pr->ndpr_preferred && pr->ndpr_preferred < time_second) { - struct in6_ifaddr *ia6; + pr = newpr; + } - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6) - ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; - } -#endif + /* + * Address autoconfiguration based on Section 5.5.3 of RFC 2462. + * Note that pr must be non NULL at this point. + */ - onlink = pr->ndpr_statef_onlink; /* Mobile IPv6 */ + /* 5.5.3 (a). Ignore the prefix without the A bit set. */ + if (!new->ndpr_raf_auto) + goto afteraddrconf; - if (dr && pfxrtr_lookup(pr, dr) == NULL) - pfxrtr_add(pr, dr); + /* + * 5.5.3 (b). the link-local prefix should have been ignored in + * nd6_ra_input. + */ - } else { - int error_tmp; + /* + * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. + * This should have been done in nd6_ra_input. + */ - if (new->ndpr_vltime == 0) goto end; + /* + * 5.5.3 (d). If the prefix advertised does not match the prefix of an + * address already in the list, and the Valid Lifetime is not 0, + * form an address. Note that even a manually configured address + * should reject autoconfiguration of a new address. + */ + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) + { + struct in6_ifaddr *ifa6; + int ifa_plen; + u_int32_t storedlifetime; - bzero(&new->ndpr_addr, sizeof(struct in6_addr)); + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + ifa6 = (struct in6_ifaddr *)ifa; + + /* + * Spec is not clear here, but I believe we should concentrate + * on unicast (i.e. not anycast) addresses. + * XXX: other ia6_flags? detached or duplicated? + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) + continue; + + ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL); + if (ifa_plen != new->ndpr_plen || + !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr, + &new->ndpr_prefix.sin6_addr, + ifa_plen)) + continue; + + if (ia6_match == NULL) /* remember the first one */ + ia6_match = ifa6; + + if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; /* - * RFC 2462 5.5.3 (d) - * We got a fresh prefix. Perform some sanity checks - * and add an interface address by appending interface ID - * to the advertised prefix. + * An already autoconfigured address matched. Now that we + * are sure there is at least one matched address, we can + * proceed to 5.5.3. (e): update the lifetimes according to the + * "two hours" rule and the privacy extension. */ - if (!new->ndpr_raf_auto) - goto noautoconf2; - - ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr, - &new->ndpr_addr, new->ndpr_plen); - if (!ia6) { - error = EADDRNOTAVAIL; - log(LOG_ERR, "prelist_update: " - "failed to add a new address\n"); - goto noautoconf2; +#define TWOHOUR (120*60) + lt6_tmp = ifa6->ia6_lifetime; + + storedlifetime = IFA6_IS_INVALID(ifa6) ? 0 : + (lt6_tmp.ia6t_expire - time_second); + + if (TWOHOUR < new->ndpr_vltime || + storedlifetime < new->ndpr_vltime) { + lt6_tmp.ia6t_vltime = new->ndpr_vltime; + } else if (storedlifetime <= TWOHOUR +#if 0 + /* + * This condition is logically redundant, so we just + * omit it. + * See IPng 6712, 6717, and 6721. + */ + && new->ndpr_vltime <= storedlifetime +#endif + ) { + if (auth) { + lt6_tmp.ia6t_vltime = new->ndpr_vltime; + } + } else { + /* + * new->ndpr_vltime <= TWOHOUR && + * TWOHOUR < storedlifetime + */ + lt6_tmp.ia6t_vltime = TWOHOUR; } - /* set onlink bit if an interface route is configured */ - new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0; - lt6 = &ia6->ia6_lifetime; + /* The 2 hour rule is not imposed for preferred lifetime. */ + lt6_tmp.ia6t_pltime = new->ndpr_pltime; + + in6_init_address_ltimes(pr, <6_tmp); + + /* + * When adjusting the lifetimes of an existing temporary + * address, only lower the lifetimes. + * RFC 3041 3.3. (1). + * XXX: how should we modify ia6t_[pv]ltime? + */ + if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { + if (lt6_tmp.ia6t_expire == 0 || /* no expire */ + lt6_tmp.ia6t_expire > + ifa6->ia6_lifetime.ia6t_expire) { + lt6_tmp.ia6t_expire = + ifa6->ia6_lifetime.ia6t_expire; + } + if (lt6_tmp.ia6t_preferred == 0 || /* no expire */ + lt6_tmp.ia6t_preferred > + ifa6->ia6_lifetime.ia6t_preferred) { + lt6_tmp.ia6t_preferred = + ifa6->ia6_lifetime.ia6t_preferred; + } + } + + ifa6->ia6_lifetime = lt6_tmp; + } + if (ia6_match == NULL && new->ndpr_vltime) { + /* + * No address matched and the valid lifetime is non-zero. + * Create a new address. + */ + if ((ia6 = in6_ifadd(new, NULL)) != NULL) { + /* + * note that we should use pr (not new) for reference. + */ + pr->ndpr_refcnt++; + ia6->ia6_ndpr = pr; + +#if 0 + /* XXXYYY Don't do this, according to Jinmei. */ + pr->ndpr_addr = new->ndpr_addr; +#endif - /* address lifetime <= prefix lifetime */ - lt6->ia6t_vltime = new->ndpr_vltime; - lt6->ia6t_pltime = new->ndpr_pltime; - in6_init_address_ltimes(new, lt6, 1); + /* + * RFC 3041 3.3 (2). + * When a new public address is created as described + * in RFC2462, also create a new temporary address. + * + * RFC 3041 3.5. + * When an interface connects to a new link, a new + * randomized interface identifier should be generated + * immediately together with a new set of temporary + * addresses. Thus, we specifiy 1 as the 2nd arg of + * in6_tmpifadd(). + */ + if (ip6_use_tempaddr) { + int e; + if ((e = in6_tmpifadd(ia6, 1)) != 0) { + nd6log((LOG_NOTICE, "prelist_update: " + "failed to create a temporary " + "address, errno=%d\n", + e)); + } + } - noautoconf2: - error_tmp = prelist_add(new, dr); - error = error_tmp ? error_tmp : error; + /* + * A newly added address might affect the status + * of other addresses, so we check and update it. + * XXX: what if address duplication happens? + */ + pfxlist_onlink_check(); + } else { + /* just set an error. do not bark here. */ + error = EADDRNOTAVAIL; /* XXX: might be unused. */ + } } + afteraddrconf: + end: splx(s); return error; @@ -1061,7 +1210,7 @@ prelist_update(new, dr, m) * detect if a given prefix has a (probably) reachable advertising router. * XXX: lengthy function name... */ -struct nd_pfxrouter * +static struct nd_pfxrouter * find_pfxlist_reachable_router(pr) struct nd_prefix *pr; { @@ -1084,14 +1233,14 @@ find_pfxlist_reachable_router(pr) /* * Check if each prefix in the prefix list has at least one available router - * that advertised the prefix (A router is "available" if its neighbor cache - * entry has reachable or probably reachable). + * that advertised the prefix (a router is "available" if its neighbor cache + * entry is reachable or probably reachable). * If the check fails, the prefix may be off-link, because, for example, * we have moved from the network but the lifetime of the prefix has not - * been expired yet. So we should not use the prefix if there is another - * prefix that has an available router. - * But if there is no prefix that has an available router, we still regards - * all the prefixes as on-link. This is because we can't tell if all the + * expired yet. So we should not use the prefix if there is another prefix + * that has an available router. + * But, if there is no prefix that has an available router, we still regards + * all the prefixes as on-link. This is because we can't tell if all the * routers are simply dead or if we really moved from the network and there * is no router around us. */ @@ -1099,55 +1248,275 @@ void pfxlist_onlink_check() { struct nd_prefix *pr; + struct in6_ifaddr *ifa; /* * Check if there is a prefix that has a reachable advertising * router. */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (find_pfxlist_reachable_router(pr)) + if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) break; } if (pr) { /* * There is at least one prefix that has a reachable router. - * First, detach prefixes which has no reachable advertising - * router and then attach other prefixes. - * The order is important since an attached prefix and a - * detached prefix may have a same interface route. + * Detach prefixes which have no reachable advertising + * router, and attach other prefixes. */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (find_pfxlist_reachable_router(pr) == NULL && - pr->ndpr_statef_onlink) { - pr->ndpr_statef_onlink = 0; - nd6_detach_prefix(pr); - } + /* XXX: a link-local prefix should never be detached */ + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; + + /* + * we aren't interested in prefixes without the L bit + * set. + */ + if (pr->ndpr_raf_onlink == 0) + continue; + + if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && + find_pfxlist_reachable_router(pr) == NULL) + pr->ndpr_stateflags |= NDPRF_DETACHED; + if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && + find_pfxlist_reachable_router(pr) != 0) + pr->ndpr_stateflags &= ~NDPRF_DETACHED; } + } else { + /* there is no prefix that has a reachable router */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (find_pfxlist_reachable_router(pr) && - pr->ndpr_statef_onlink == 0) - nd6_attach_prefix(pr); + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; + + if (pr->ndpr_raf_onlink == 0) + continue; + + if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) + pr->ndpr_stateflags &= ~NDPRF_DETACHED; + } + } + + /* + * Remove each interface route associated with a (just) detached + * prefix, and reinstall the interface route for a (just) attached + * prefix. Note that all attempt of reinstallation does not + * necessarily success, when a same prefix is shared among multiple + * interfaces. Such cases will be handled in nd6_prefix_onlink, + * so we don't have to care about them. + */ + for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + int e; + + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; + + if (pr->ndpr_raf_onlink == 0) + continue; + + if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && + (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { + if ((e = nd6_prefix_offlink(pr)) != 0) { + nd6log((LOG_ERR, + "pfxlist_onlink_check: failed to " + "make %s/%d offlink, errno=%d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, e)); + } + } + if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && + (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && + pr->ndpr_raf_onlink) { + if ((e = nd6_prefix_onlink(pr)) != 0) { + nd6log((LOG_ERR, + "pfxlist_onlink_check: failed to " + "make %s/%d offlink, errno=%d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, e)); + } + } + } + + /* + * Changes on the prefix status might affect address status as well. + * Make sure that all addresses derived from an attached prefix are + * attached, and that all addresses derived from a detached prefix are + * detached. Note, however, that a manually configured address should + * always be attached. + * The precise detection logic is same as the one for prefixes. + */ + for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { + if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + if (ifa->ia6_ndpr == NULL) { + /* + * This can happen when we first configure the address + * (i.e. the address exists, but the prefix does not). + * XXX: complicated relationships... + */ + continue; + } + + if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) + break; + } + if (ifa) { + for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { + if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ + continue; + + if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) + ifa->ia6_flags &= ~IN6_IFF_DETACHED; + else + ifa->ia6_flags |= IN6_IFF_DETACHED; } } else { - /* there is no prefix that has a reachable router */ - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) - if (pr->ndpr_statef_onlink == 0) - nd6_attach_prefix(pr); + for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { + if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + ifa->ia6_flags &= ~IN6_IFF_DETACHED; + } } } -static void -nd6_detach_prefix(pr) +int +nd6_prefix_onlink(pr) struct nd_prefix *pr; { - struct in6_ifaddr *ia6; - struct sockaddr_in6 sa6, mask6; + struct ifaddr *ifa; + struct ifnet *ifp = pr->ndpr_ifp; + struct sockaddr_in6 mask6; + struct nd_prefix *opr; + u_long rtflags; + int error = 0; + struct rtentry *rt = NULL; + + /* sanity check */ + if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { + nd6log((LOG_ERR, + "nd6_prefix_onlink: %s/%d is already on-link\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen); + return(EEXIST)); + } /* - * Delete the interface route associated with the prefix. + * Add the interface route associated with the prefix. Before + * installing the route, check if there's the same prefix on another + * interface, and the prefix has already installed the interface route. + * Although such a configuration is expected to be rare, we explicitly + * allow it. */ + for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { + if (opr == pr) + continue; + + if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) + continue; + + if (opr->ndpr_plen == pr->ndpr_plen && + in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, + &opr->ndpr_prefix.sin6_addr, + pr->ndpr_plen)) + return(0); + } + + /* + * We prefer link-local addresses as the associated interface address. + */ + /* search for a link-local addr */ + ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, + IN6_IFF_NOTREADY| + IN6_IFF_ANYCAST); + if (ifa == NULL) { + /* XXX: freebsd does not have ifa_ifwithaf */ + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) + { + if (ifa->ifa_addr->sa_family == AF_INET6) + break; + } + /* should we care about ia6_flags? */ + } + if (ifa == NULL) { + /* + * This can still happen, when, for example, we receive an RA + * containing a prefix with the L bit set and the A bit clear, + * after removing all IPv6 addresses on the receiving + * interface. This should, of course, be rare though. + */ + nd6log((LOG_NOTICE, + "nd6_prefix_onlink: failed to find any ifaddr" + " to add route for a prefix(%s/%d) on %s\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(ifp))); + return(0); + } + + /* + * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. + * ifa->ifa_rtrequest = nd6_rtrequest; + */ + bzero(&mask6, sizeof(mask6)); + mask6.sin6_len = sizeof(mask6); + mask6.sin6_addr = pr->ndpr_mask; + rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; + if (nd6_need_cache(ifp)) { + /* explicitly set in case ifa_flags does not set the flag. */ + rtflags |= RTF_CLONING; + } else { + /* + * explicitly clear the cloning bit in case ifa_flags sets it. + */ + rtflags &= ~RTF_CLONING; + } + error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, + ifa->ifa_addr, (struct sockaddr *)&mask6, + rtflags, &rt); + if (error == 0) { + if (rt != NULL) /* this should be non NULL, though */ + nd6_rtmsg(RTM_ADD, rt); + pr->ndpr_stateflags |= NDPRF_ONLINK; + } + else { + nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" + " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " + "errno = %d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(ifp), + ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), + ip6_sprintf(&mask6.sin6_addr), rtflags, error)); + } + + if (rt != NULL) + rt->rt_refcnt--; + + return(error); +} + +int +nd6_prefix_offlink(pr) + struct nd_prefix *pr; +{ + int error = 0; + struct ifnet *ifp = pr->ndpr_ifp; + struct nd_prefix *opr; + struct sockaddr_in6 sa6, mask6; + struct rtentry *rt = NULL; + + /* sanity check */ + if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { + nd6log((LOG_ERR, + "nd6_prefix_offlink: %s/%d is already off-link\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); + return(EEXIST); + } + bzero(&sa6, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_len = sizeof(sa6); @@ -1157,103 +1526,113 @@ nd6_detach_prefix(pr) mask6.sin6_family = AF_INET6; mask6.sin6_len = sizeof(sa6); bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); - { - int e; + error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, + (struct sockaddr *)&mask6, 0, &rt); + if (error == 0) { + pr->ndpr_stateflags &= ~NDPRF_ONLINK; - e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, - (struct sockaddr *)&mask6, 0, NULL); - if (e) { - log(LOG_ERR, - "nd6_detach_prefix: failed to delete route: " - "%s/%d (errno = %d)\n", - ip6_sprintf(&sa6.sin6_addr), - pr->ndpr_plen, - e); - } - } + /* report the route deletion to the routing socket. */ + if (rt != NULL) + nd6_rtmsg(RTM_DELETE, rt); - /* - * Mark the address derived from the prefix detached so that - * it won't be used as a source address for a new connection. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6) - ia6->ia6_flags |= IN6_IFF_DETACHED; -} + /* + * There might be the same prefix on another interface, + * the prefix which could not be on-link just because we have + * the interface route (see comments in nd6_prefix_onlink). + * If there's one, try to make the prefix on-link on the + * interface. + */ + for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { + if (opr == pr) + continue; -static void -nd6_attach_prefix(pr) - struct nd_prefix *pr; -{ - struct ifaddr *ifa; - struct in6_ifaddr *ia6; + if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) + continue; - /* - * Add the interface route associated with the prefix(if necessary) - * Should we consider if the L bit is set in pr->ndpr_flags? - */ - ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix, - pr->ndpr_ifp); - if (ifa == NULL) { - log(LOG_ERR, - "nd6_attach_prefix: failed to find any ifaddr" - " to add route for a prefix(%s/%d)\n", - ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen); + /* + * KAME specific: detached prefixes should not be + * on-link. + */ + if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) + continue; + + if (opr->ndpr_plen == pr->ndpr_plen && + in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, + &opr->ndpr_prefix.sin6_addr, + pr->ndpr_plen)) { + int e; + + if ((e = nd6_prefix_onlink(opr)) != 0) { + nd6log((LOG_ERR, + "nd6_prefix_offlink: failed to " + "recover a prefix %s/%d from %s " + "to %s (errno = %d)\n", + ip6_sprintf(&opr->ndpr_prefix.sin6_addr), + opr->ndpr_plen, if_name(ifp), + if_name(opr->ndpr_ifp), e)); + } + } + } } else { - int e; - struct sockaddr_in6 mask6; - - bzero(&mask6, sizeof(mask6)); - mask6.sin6_family = AF_INET6; - mask6.sin6_len = sizeof(mask6); - mask6.sin6_addr = pr->ndpr_mask; - e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, - ifa->ifa_addr, (struct sockaddr *)&mask6, - ifa->ifa_flags, NULL); - if (e == 0) - pr->ndpr_statef_onlink = 1; - else { - log(LOG_ERR, - "nd6_attach_prefix: failed to add route for" - " a prefix(%s/%d), errno = %d\n", - ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e); - } + /* XXX: can we still set the NDPRF_ONLINK flag? */ + nd6log((LOG_ERR, + "nd6_prefix_offlink: failed to delete route: " + "%s/%d on %s (errno = %d)\n", + ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp), + error)); } - /* - * Now the address derived from the prefix can be used as a source - * for a new connection, so clear the detached flag. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6) { - ia6->ia6_flags &= ~IN6_IFF_DETACHED; - if (pr->ndpr_statef_onlink) - ia6->ia_flags |= IFA_ROUTE; + if (rt != NULL) { + if (rt->rt_refcnt <= 0) { + /* XXX: we should free the entry ourselves. */ + rt->rt_refcnt++; + rtfree(rt); + } } + + return(error); } static struct in6_ifaddr * -in6_ifadd(ifp, in6, addr, prefixlen) - struct ifnet *ifp; - struct in6_addr *in6; - struct in6_addr *addr; - int prefixlen; /* prefix len of the new prefix in "in6" */ +in6_ifadd(pr, ifid) + struct nd_prefix *pr; + struct in6_addr *ifid; /* Mobile IPv6 addition */ { + struct ifnet *ifp = pr->ndpr_ifp; struct ifaddr *ifa; - struct in6_ifaddr *ia, *ib, *oia; - int s, error; + struct in6_aliasreq ifra; + struct in6_ifaddr *ia, *ib; + int error, plen0; struct in6_addr mask; + int prefixlen = pr->ndpr_plen; in6_len2mask(&mask, prefixlen); - /* find link-local address (will be interface ID) */ + /* + * find a link-local address (will be interface ID). + * Is it really mandatory? Theoretically, a global or a site-local + * address can be configured without a link-local address, if we + * have a unique interface identifier... + * + * it is not mandatory to have a link-local address, we can generate + * interface identifier on the fly. we do this because: + * (1) it should be the easiest way to find interface identifier. + * (2) RFC2462 5.4 suggesting the use of the same interface identifier + * for multiple addresses on a single interface, and possible shortcut + * of DAD. we omitted DAD for this reason in the past. + * (3) a user can prevent autoconfiguration of global address + * by removing link-local address by hand (this is partly because we + * don't have other way to control the use of IPv6 on a interface. + * this has been our design choice - cf. NRL's "ifconfig auto"). + * (4) it is easier to manage when an interface has addresses + * with the same interface identifier, than to have multiple addresses + * with different interface identifiers. + * + * Mobile IPv6 addition: allow for caller to specify a wished interface + * ID. This is to not break connections when moving addresses between + * interfaces. + */ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */ if (ifa) ib = (struct in6_ifaddr *)ifa; @@ -1269,204 +1648,199 @@ in6_ifadd(ifp, in6, addr, prefixlen) #endif /* prefixlen + ifidlen must be equal to 128 */ - if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) { - log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s" - "(prefix=%d ifid=%d)\n", if_name(ifp), - prefixlen, - 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr)); + plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); + if (prefixlen != plen0) { + nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " + "(prefix=%d ifid=%d)\n", + if_name(ifp), prefixlen, 128 - plen0)); return NULL; } /* make ifaddr */ - ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT); - if (ia == NULL) { - printf("ENOBUFS in in6_ifadd %d\n", __LINE__); - return NULL; - } - bzero((caddr_t)ia, sizeof(*ia)); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - if (ifp->if_flags & IFF_POINTOPOINT) - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; - else - ia->ia_ifa.ifa_dstaddr = NULL; - ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; - ia->ia_ifp = ifp; - - /* link to in6_ifaddr */ - if ((oia = in6_ifaddr) != NULL) { - for( ; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else { - /* - * This should be impossible, since we have at least one - * link-local address (see the beginning of this function). - * XXX: should we rather panic here? - */ - printf("in6_ifadd: in6_ifaddr is NULL (impossible!)\n"); - in6_ifaddr = ia; - } - /* gain a refcnt for the link from in6_ifaddr */ - ia->ia_ifa.ifa_refcnt++; - - /* link to if_addrlist */ - TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); - /* gain another refcnt for the link from if_addrlist */ - ia->ia_ifa.ifa_refcnt++; - - /* new address */ - ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_addr.sin6_family = AF_INET6; + bzero(&ifra, sizeof(ifra)); + /* + * in6_update_ifa() does not use ifra_name, but we accurately set it + * for safety. + */ + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + ifra.ifra_addr.sin6_family = AF_INET6; + ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); /* prefix */ - bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr)); - ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; - ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; - ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; - ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; - /* interface ID */ - ia->ia_addr.sin6_addr.s6_addr32[0] - |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); - ia->ia_addr.sin6_addr.s6_addr32[1] - |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); - ia->ia_addr.sin6_addr.s6_addr32[2] - |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); - ia->ia_addr.sin6_addr.s6_addr32[3] - |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); - - /* new prefix */ - ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_prefixmask.sin6_family = AF_INET6; - bcopy(&mask, &ia->ia_prefixmask.sin6_addr, - sizeof(ia->ia_prefixmask.sin6_addr)); - - /* same routine */ - ia->ia_ifa.ifa_rtrequest = - (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - ia->ia_ifa.ifa_metric = ifp->if_metric; - - /* add interface route */ - if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) { - log(LOG_NOTICE, "in6_ifadd: failed to add an interface route " - "for %s/%d on %s, errno = %d\n", - ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen, - if_name(ifp), error); - } else - ia->ia_flags |= IFA_ROUTE; + bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr, + sizeof(ifra.ifra_addr.sin6_addr)); + ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; + ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; + ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; + ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; - *addr = ia->ia_addr.sin6_addr; + /* interface ID */ + if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid)) + ifid = &ib->ia_addr.sin6_addr; + ifra.ifra_addr.sin6_addr.s6_addr32[0] + |= (ifid->s6_addr32[0] & ~mask.s6_addr32[0]); + ifra.ifra_addr.sin6_addr.s6_addr32[1] + |= (ifid->s6_addr32[1] & ~mask.s6_addr32[1]); + ifra.ifra_addr.sin6_addr.s6_addr32[2] + |= (ifid->s6_addr32[2] & ~mask.s6_addr32[2]); + ifra.ifra_addr.sin6_addr.s6_addr32[3] + |= (ifid->s6_addr32[3] & ~mask.s6_addr32[3]); + + /* new prefix mask. */ + ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_prefixmask.sin6_family = AF_INET6; + bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, + sizeof(ifra.ifra_prefixmask.sin6_addr)); - if (ifp->if_flags & IFF_MULTICAST) { - int error; /* not used */ - struct in6_addr sol6; + /* + * lifetime. + * XXX: in6_init_address_ltimes would override these values later. + * We should reconsider this logic. + */ + ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; + ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; - /* join solicited node multicast address */ - bzero(&sol6, sizeof(sol6)); - sol6.s6_addr16[0] = htons(0xff02); - sol6.s6_addr16[1] = htons(ifp->if_index); - sol6.s6_addr32[1] = 0; - sol6.s6_addr32[2] = htonl(1); - sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; - sol6.s6_addr8[12] = 0xff; - (void)in6_addmulti(&sol6, ifp, &error); - } + /* XXX: scope zone ID? */ - ia->ia6_flags |= IN6_IFF_TENTATIVE; + ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ + /* + * temporarily set the nopfx flag to avoid conflict. + * XXX: we should reconsider the entire mechanism about prefix + * manipulation. + */ + ifra.ifra_flags |= IN6_IFF_NOPFX; /* - * To make the interface up. Only AF_INET6 in ia is used... + * keep the new address, regardless of the result of in6_update_ifa. + * XXX: this address is now meaningless. + * We should reconsider its role. */ - s = splimp(); - if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) { - splx(s); - return NULL; + pr->ndpr_addr = ifra.ifra_addr.sin6_addr; + + /* allocate ifaddr structure, link into chain, etc. */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + nd6log((LOG_ERR, + "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", + ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp), + error)); + return(NULL); /* ifaddr must not have been allocated. */ } - splx(s); - /* Perform DAD, if needed. */ - nd6_dad_start((struct ifaddr *)ia, NULL); + ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); - return ia; + return(ia); /* this must NOT be NULL. */ } int -in6_ifdel(ifp, in6) - struct ifnet *ifp; - struct in6_addr *in6; +in6_tmpifadd(ia0, forcegen) + const struct in6_ifaddr *ia0; /* corresponding public address */ { - struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL; - struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL; + struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; + struct in6_ifaddr *newia; + struct in6_aliasreq ifra; + int i, error; + int trylimit = 3; /* XXX: adhoc value */ + u_int32_t randid[2]; + time_t vltime0, pltime0; + + bzero(&ifra, sizeof(ifra)); + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + ifra.ifra_addr = ia0->ia_addr; + /* copy prefix mask */ + ifra.ifra_prefixmask = ia0->ia_prefixmask; + /* clear the old IFID */ + for (i = 0; i < 4; i++) { + ifra.ifra_addr.sin6_addr.s6_addr32[i] + &= ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; + } - if (!ifp) - return -1; + again: + in6_get_tmpifid(ifp, (u_int8_t *)randid, + (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], + forcegen); + ifra.ifra_addr.sin6_addr.s6_addr32[2] + |= (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); + ifra.ifra_addr.sin6_addr.s6_addr32[3] + |= (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); - ia = in6ifa_ifpwithaddr(ifp, in6); - if (!ia) - return -1; + /* + * If by chance the new temporary address is the same as an address + * already assigned to the interface, generate a new randomized + * interface identifier and repeat this step. + * RFC 3041 3.3 (4). + */ + if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { + if (trylimit-- == 0) { + nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find " + "a unique random IFID\n")); + return(EEXIST); + } + forcegen = 1; + goto again; + } - if (ifp->if_flags & IFF_MULTICAST) { - /* - * delete solicited multicast addr for deleting host id - */ - struct in6_multi *in6m; - struct in6_addr llsol; - bzero(&llsol, sizeof(struct in6_addr)); - llsol.s6_addr16[0] = htons(0xff02); - llsol.s6_addr16[1] = htons(ifp->if_index); - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr32[3] = - ia->ia_addr.sin6_addr.s6_addr32[3]; - llsol.s6_addr8[12] = 0xff; - - IN6_LOOKUP_MULTI(llsol, ifp, in6m); - if (in6m) - in6_delmulti(in6m); - } - - if (ia->ia_flags & IFA_ROUTE) { - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); - ia->ia_flags &= ~IFA_ROUTE; - } - - TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); - IFAFREE(&ia->ia_ifa); - - /* lladdr is never deleted */ - oia = ia; - if (oia == (ia = in6_ifaddr)) - in6_ifaddr = ia->ia_next; - else { - while (ia->ia_next && (ia->ia_next != oia)) - ia = ia->ia_next; - if (ia->ia_next) - ia->ia_next = oia->ia_next; - else - return -1; + /* + * The Valid Lifetime is the lower of the Valid Lifetime of the + * public address or TEMP_VALID_LIFETIME. + * The Preferred Lifetime is the lower of the Preferred Lifetime + * of the public address or TEMP_PREFERRED_LIFETIME - + * DESYNC_FACTOR. + */ + if (ia0->ia6_lifetime.ia6t_expire != 0) { + vltime0 = IFA6_IS_INVALID(ia0) ? 0 : + (ia0->ia6_lifetime.ia6t_expire - time_second); + if (vltime0 > ip6_temp_valid_lifetime) + vltime0 = ip6_temp_valid_lifetime; + } else + vltime0 = ip6_temp_valid_lifetime; + if (ia0->ia6_lifetime.ia6t_preferred != 0) { + pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : + (ia0->ia6_lifetime.ia6t_preferred - time_second); + if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ + pltime0 = ip6_temp_preferred_lifetime - + ip6_desync_factor; + } + } else + pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; + ifra.ifra_lifetime.ia6t_vltime = vltime0; + ifra.ifra_lifetime.ia6t_pltime = pltime0; + + /* + * A temporary address is created only if this calculated Preferred + * Lifetime is greater than REGEN_ADVANCE time units. + */ + if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) + return(0); + + /* XXX: scope zone ID? */ + + ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); + + /* allocate ifaddr structure, link into chain, etc. */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) + return(error); + + newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); + if (newia == NULL) { /* XXX: can it happen? */ + nd6log((LOG_ERR, + "in6_tmpifadd: ifa update succeeded, but we got " + "no ifaddr\n")); + return(EINVAL); /* XXX */ } + newia->ia6_ndpr = ia0->ia6_ndpr; + newia->ia6_ndpr->ndpr_refcnt++; - IFAFREE((&oia->ia_ifa)); -/* xxx - rtrequest(RTM_DELETE, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)0 - (struct sockaddr *)&ia->ia_prefixmask, - RTF_UP|RTF_CLONING, - (struct rtentry **)0); -*/ - return 0; -} + return(0); +} int in6_init_prefix_ltimes(struct nd_prefix *ndpr) { - - /* check if preferred lifetime > valid lifetime */ + /* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */ if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { - log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" + nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" "(%d) is greater than valid lifetime(%d)\n", - (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime); + (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime)); return (EINVAL); } if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) @@ -1482,24 +1856,15 @@ in6_init_prefix_ltimes(struct nd_prefix *ndpr) } static void -in6_init_address_ltimes(struct nd_prefix *new, - struct in6_addrlifetime *lt6, - int update_vltime) +in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) { - /* Valid lifetime must not be updated unless explicitly specified. */ - if (update_vltime) { - /* init ia6t_expire */ - if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) - lt6->ia6t_expire = 0; - else { - lt6->ia6t_expire = time_second; - lt6->ia6t_expire += lt6->ia6t_vltime; - } - /* Ensure addr lifetime <= prefix lifetime. */ - if (new->ndpr_expire && lt6->ia6t_expire && - new->ndpr_expire < lt6->ia6t_expire) - lt6->ia6t_expire = new->ndpr_expire; + /* init ia6t_expire */ + if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) + lt6->ia6t_expire = 0; + else { + lt6->ia6t_expire = time_second; + lt6->ia6t_expire += lt6->ia6t_vltime; } /* init ia6t_preferred */ @@ -1509,10 +1874,6 @@ in6_init_address_ltimes(struct nd_prefix *new, lt6->ia6t_preferred = time_second; lt6->ia6t_preferred += lt6->ia6t_pltime; } - /* Ensure addr lifetime <= prefix lifetime. */ - if (new->ndpr_preferred && lt6->ia6t_preferred - && new->ndpr_preferred < lt6->ia6t_preferred) - lt6->ia6t_preferred = new->ndpr_preferred; } /* @@ -1522,8 +1883,8 @@ in6_init_address_ltimes(struct nd_prefix *new, */ void rt6_flush(gateway, ifp) - struct in6_addr *gateway; - struct ifnet *ifp; + struct in6_addr *gateway; + struct ifnet *ifp; { struct radix_node_head *rnh = rt_tables[AF_INET6]; int s = splnet(); @@ -1556,6 +1917,14 @@ rt6_deleteroute(rn, arg) return(0); /* + * Do not delete a static route. + * XXX: this seems to be a bit ad-hoc. Should we consider the + * 'cloned' bit instead? + */ + if ((rt->rt_flags & RTF_STATIC) != 0) + return(0); + + /* * We delete only host route. This means, in particular, we don't * delete default route. */ diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 42f38fd..eda8bfa 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -65,6 +65,7 @@ */ #include "opt_ipsec.h" +#include "opt_inet6.h" #include <sys/param.h> #include <sys/malloc.h> @@ -94,6 +95,7 @@ #ifdef ENABLE_DEFAULT_SCOPE #include <netinet6/scope6_var.h> #endif +#include <netinet6/raw_ip6.h> #ifdef IPSEC #include <netinet6/ipsec.h> @@ -103,6 +105,9 @@ #include <machine/stdarg.h> #include "faith.h" +#if defined(NFAITH) && 0 < NFAITH +#include <net/if_faith.h> +#endif #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) @@ -116,6 +121,8 @@ extern struct inpcbinfo ripcbinfo; extern u_long rip_sendspace; extern u_long rip_recvspace; +struct rip6stat rip6stat; + /* * Setup generic address and protocol structures * for raw_input routine, then pass them along with @@ -130,18 +137,19 @@ rip6_input(mp, offp, proto) register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); register struct inpcb *in6p; struct inpcb *last = 0; - struct mbuf *opts = 0; + struct mbuf *opts = NULL; struct sockaddr_in6 rip6src; + rip6stat.rip6s_ipackets++; + #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif) { - if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { - /* XXX send icmp6 host/port unreach? */ - m_freem(m); - return IPPROTO_DONE; - } + if (faithprefix(&ip6->ip6_dst)) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; } #endif + init_sin6(&rip6src, m); /* general init */ LIST_FOREACH(in6p, &ripcb, inp_list) { @@ -156,14 +164,27 @@ rip6_input(mp, offp, proto) if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; - if (in6p->in6p_cksum != -1 - && in6_cksum(m, ip6->ip6_nxt, *offp, - m->m_pkthdr.len - *offp)) { - /* XXX bark something */ - continue; + if (in6p->in6p_cksum != -1) { + rip6stat.rip6s_isum++; + if (in6_cksum(m, ip6->ip6_nxt, *offp, + m->m_pkthdr.len - *offp)) { + rip6stat.rip6s_badsum++; + continue; + } } if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + +#ifdef IPSEC + /* + * Check AH/ESP integrity. + */ + if (n && ipsec6_in_reject_so(n, last->inp_socket)) { + m_freem(n); + ipsec6stat.in_polvio++; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ if (n) { if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) @@ -173,10 +194,10 @@ rip6_input(mp, offp, proto) if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&rip6src, n, opts) == 0) { - /* should notify about lost packet */ m_freem(n); if (opts) m_freem(opts); + rip6stat.rip6s_fullsock++; } else sorwakeup(last->in6p_socket); opts = NULL; @@ -184,6 +205,17 @@ rip6_input(mp, offp, proto) } last = in6p; } +#ifdef IPSEC + /* + * Check AH/ESP integrity. + */ + if (last && ipsec6_in_reject_so(m, last->inp_socket)) { + m_freem(m); + ipsec6stat.in_polvio++; + ip6stat.ip6s_delivered--; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ if (last) { if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) @@ -195,9 +227,13 @@ rip6_input(mp, offp, proto) m_freem(m); if (opts) m_freem(opts); + rip6stat.rip6s_fullsock++; } else sorwakeup(last->in6p_socket); } else { + rip6stat.rip6s_nosock++; + if (m->m_flags & M_MCAST) + rip6stat.rip6s_nosockmcast++; if (proto == IPPROTO_NONE) m_freem(m); else { @@ -217,10 +253,11 @@ rip6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off = 0; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; void (*notify) __P((struct inpcb *, int)) = in6_rtchange; if (sa->sa_family != AF_INET6 || @@ -238,37 +275,19 @@ rip6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - if (ip6) { - /* - * XXX: We assume that when IPV6 is non NULL, - * M and OFF are valid. - */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, - 0, &s, 0, cmd, notify); - } else - (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&ripcb, sa, 0, (struct sockaddr *)sa6_src, + 0, cmd, notify); } /* @@ -311,7 +330,7 @@ rip6_output(m, va_alist) priv = 1; dst = &dstsock->sin6_addr; if (control) { - if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) + if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) goto bad; optp = &opt; } else @@ -431,7 +450,10 @@ rip6_output(m, va_alist) } #ifdef IPSEC - ipsec_setsocket(m, so); + if (ipsec_setsocket(m, so) != 0) { + error = ENOBUFS; + goto bad; + } #endif /*IPSEC*/ error = ip6_output(m, optp, &in6p->in6p_route, 0, @@ -440,7 +462,8 @@ rip6_output(m, va_alist) if (oifp) icmp6_ifoutstat_inc(oifp, type, code); icmp6stat.icp6s_outhist[type]++; - } + } else + rip6stat.rip6s_opackets++; goto freectl; @@ -451,8 +474,11 @@ rip6_output(m, va_alist) freectl: if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) RTFREE(optp->ip6po_route.ro_rt); - if (control) + if (control) { + if (optp == &opt) + ip6_clearpktopts(optp, 0, -1); m_freem(control); + } return(error); } diff --git a/sys/netinet6/raw_ip6.h b/sys/netinet6/raw_ip6.h new file mode 100644 index 0000000..cfb390b --- /dev/null +++ b/sys/netinet6/raw_ip6.h @@ -0,0 +1,54 @@ +/* $FreeBSD$ */ +/* $KAME: raw_ip6.h,v 1.2 2001/05/27 13:28:35 itojun Exp $ */ + +/* + * Copyright (C) 2001 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. + */ + +#ifndef _NETINET6_RAW_IP6_H_ +#define _NETINET6_RAW_IP6_H_ + +/* + * ICMPv6 stat is counted separately. see netinet/icmp6.h + */ +struct rip6stat { + u_quad_t rip6s_ipackets; /* total input packets */ + u_quad_t rip6s_isum; /* input checksum computations */ + u_quad_t rip6s_badsum; /* of above, checksum error */ + u_quad_t rip6s_nosock; /* no matching socket */ + u_quad_t rip6s_nosockmcast; /* of above, arrived as multicast */ + u_quad_t rip6s_fullsock; /* not delivered, input socket full */ + + u_quad_t rip6s_opackets; /* total output packets */ +}; + +#ifdef _KERNEL +extern struct rip6stat rip6stat; +#endif + +#endif diff --git a/sys/netinet6/route6.c b/sys/netinet6/route6.c index 3cd95a1..807c6ad 100644 --- a/sys/netinet6/route6.c +++ b/sys/netinet6/route6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: route6.c,v 1.15 2000/06/23 16:18:20 itojun Exp $ */ +/* $KAME: route6.c,v 1.24 2001/03/14 03:07:05 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,6 +37,7 @@ #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/systm.h> +#include <sys/queue.h> #include <net/if.h> @@ -55,10 +56,22 @@ route6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto; /* proto is unused */ { - register struct ip6_hdr *ip6; - register struct mbuf *m = *mp; - register struct ip6_rthdr *rh; + struct ip6_hdr *ip6; + struct mbuf *m = *mp; + struct ip6_rthdr *rh; int off = *offp, rhlen; + struct mbuf *n; + + n = ip6_findaux(m); + if (n) { + struct ip6aux *ip6a = mtod(n, struct ip6aux *); + /* XXX reject home-address option before rthdr */ + if (ip6a->ip6a_flags & IP6A_SWAP) { + ip6stat.ip6s_badoptions++; + m_freem(m); + return IPPROTO_DONE; + } + } #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE); @@ -119,6 +132,9 @@ route6_input(mp, offp, proto) /* * Type0 routing header processing + * + * RFC2292 backward compatibility warning: no support for strict/loose bitmap, + * as it was dropped between RFC1883 and RFC2460. */ static int ip6_rthdr0(m, ip6, rh0) @@ -176,7 +192,7 @@ ip6_rthdr0(m, ip6, rh0) if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst) || - IN6_IS_ADDR_V4COMPAT(nextaddr)) { + IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { ip6stat.ip6s_badoptions++; m_freem(m); return(-1); diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c index 43a6fb7..09bba0c 100644 --- a/sys/netinet6/scope6.c +++ b/sys/netinet6/scope6.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: scope6.c,v 1.9 2000/05/18 15:03:26 jinmei Exp $ */ +/* $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */ /* * Copyright (C) 2000 WIDE Project. @@ -35,6 +35,7 @@ #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/systm.h> +#include <sys/queue.h> #include <net/route.h> #include <net/if.h> diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index ee05019..fd4d6f3 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: udp6_output.c,v 1.14 2000/06/13 10:31:23 itojun Exp $ */ +/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -69,6 +69,7 @@ #include "opt_inet.h" #include <sys/param.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> @@ -120,22 +121,22 @@ int udp6_output(in6p, m, addr6, control, p) - register struct in6pcb *in6p; - register struct mbuf *m; + struct in6pcb *in6p; + struct mbuf *m; struct mbuf *control; struct sockaddr *addr6; struct proc *p; { - register u_int32_t ulen = m->m_pkthdr.len; + u_int32_t ulen = m->m_pkthdr.len; u_int32_t plen = sizeof(struct udphdr) + ulen; struct ip6_hdr *ip6; struct udphdr *udp6; - struct in6_addr *laddr, *faddr; + struct in6_addr *laddr, *faddr; u_short fport; int error = 0; struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; int priv; - int af, hlen; + int af = AF_INET6, hlen = sizeof(struct ip6_hdr); int flags; struct sockaddr_in6 tmp; @@ -143,7 +144,7 @@ udp6_output(in6p, m, addr6, control, p) if (p && !suser(p)) priv = 1; if (control) { - if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) + if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) goto release; in6p->in6p_outputopts = &opt; } @@ -164,6 +165,7 @@ udp6_output(in6p, m, addr6, control, p) } if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + /* how about ::ffff:0.0.0.0 case? */ error = EISCONN; goto release; } @@ -175,6 +177,24 @@ udp6_output(in6p, m, addr6, control, p) faddr = &sin6->sin6_addr; fport = sin6->sin6_port; /* allow 0 port */ + if (IN6_IS_ADDR_V4MAPPED(faddr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) { + /* + * I believe we should explicitly discard the + * packet when mapped addresses are disabled, + * rather than send the packet as an IPv6 one. + * If we chose the latter approach, the packet + * might be sent out on the wire based on the + * default route, the situation which we'd + * probably want to avoid. + * (20010421 jinmei@kame.net) + */ + error = EINVAL; + goto release; + } else + af = AF_INET; + } + /* KAME hack: embed scopeid */ if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) { error = EINVAL; @@ -187,7 +207,7 @@ udp6_output(in6p, m, addr6, control, p) &in6p->in6p_route, &in6p->in6p_laddr, &error); } else - laddr = &in6p->in6p_laddr; /*XXX*/ + laddr = &in6p->in6p_laddr; /* XXX */ if (laddr == NULL) { if (error == 0) error = EADDRNOTAVAIL; @@ -201,18 +221,29 @@ udp6_output(in6p, m, addr6, control, p) error = ENOTCONN; goto release; } + if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) { + /* + * XXX: this case would happen when the + * application sets the V6ONLY flag after + * connecting the foreign address. + * Such applications should be fixed, + * so we bark here. + */ + log(LOG_INFO, "udp6_output: IPV6_V6ONLY " + "option was set for a connected socket\n"); + error = EINVAL; + goto release; + } else + af = AF_INET; + } laddr = &in6p->in6p_laddr; faddr = &in6p->in6p_faddr; fport = in6p->in6p_fport; } - if (!IN6_IS_ADDR_V4MAPPED(faddr)) { - af = AF_INET6; - hlen = sizeof(struct ip6_hdr); - } else { - af = AF_INET; + if (af == AF_INET) hlen = sizeof(struct ip); - } /* * Calculate data length and get a mbuf @@ -261,10 +292,13 @@ udp6_output(in6p, m, addr6, control, p) udp6stat.udp6s_opackets++; #ifdef IPSEC - ipsec_setsocket(m, in6p->in6p_socket); + if (ipsec_setsocket(m, in6p->in6p_socket) != 0) { + error = ENOBUFS; + goto release; + } #endif /*IPSEC*/ error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, - flags, in6p->in6p_moptions, NULL); + flags, in6p->in6p_moptions, NULL); break; case AF_INET: error = EAFNOSUPPORT; @@ -277,6 +311,7 @@ release: releaseopt: if (control) { + ip6_clearpktopts(in6p->in6p_outputopts, 0, -1); in6p->in6p_outputopts = stickyopt; m_freem(control); } diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index ca9ce2f..bb5a38a 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: udp6_usrreq.c,v 1.17 2000/10/13 17:46:21 itojun Exp $ */ +/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -107,6 +107,9 @@ #endif /*IPSEC*/ #include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include <net/if_faith.h> +#endif /* * UDP protocol inplementation. @@ -149,25 +152,25 @@ udp6_input(mp, offp, proto) register struct ip6_hdr *ip6; register struct udphdr *uh; register struct inpcb *in6p; - struct mbuf *opts = 0; + struct mbuf *opts = NULL; int off = *offp; int plen, ulen; struct sockaddr_in6 udp_in6; + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif) { - if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { - /* XXX send icmp6 host/port unreach? */ - m_freem(m); - return IPPROTO_DONE; - } + if (faithprefix(&ip6->ip6_dst)) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; } #endif - udpstat.udps_ipackets++; - IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + udpstat.udps_ipackets++; - ip6 = mtod(m, struct ip6_hdr *); plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); uh = (struct udphdr *)((caddr_t)ip6 + off); ulen = ntohs((u_short)uh->uh_ulen); @@ -274,6 +277,7 @@ udp6_input(mp, offp, proto) || last->in6p_socket->so_options & SO_TIMESTAMP) ip6_savecontrol(last, &opts, ip6, n); + m_adj(n, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, @@ -284,7 +288,7 @@ udp6_input(mp, offp, proto) udpstat.udps_fullsock++; } else sorwakeup(last->in6p_socket); - opts = 0; + opts = NULL; } } last = in6p; @@ -401,13 +405,17 @@ udp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct udphdr *uhp; struct udphdr uh; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off = 0; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; void (*notify) __P((struct inpcb *, int)) = udp_notify; + struct udp_portonly { + u_int16_t uh_sport; + u_int16_t uh_dport; + } *uhp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -424,51 +432,35 @@ udp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(uh)) + if (m->m_pkthdr.len < off + sizeof(*uhp)) return; - if (m->m_len < off + sizeof(uh)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - uhp = &uh; - } else - uhp = (struct udphdr *)(mtod(m, caddr_t) + off); - (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, - uhp->uh_dport, &s, - uhp->uh_sport, cmd, notify); + bzero(&uh, sizeof(uh)); + m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); + + (void) in6_pcbnotify(&udb, sa, uh.uh_dport, ip6cp->ip6c_src, + uh.uh_sport, cmd, notify); } else - (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&udb, sa, 0, (struct sockaddr *)&sa6_src, + 0, cmd, notify); } static int @@ -583,7 +575,7 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { struct sockaddr_in6 *sin6_p; sin6_p = (struct sockaddr_in6 *)nam; @@ -618,7 +610,8 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) inp = sotoinpcb(so); if (inp == 0) return EINVAL; - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { + + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { struct sockaddr_in6 *sin6_p; sin6_p = (struct sockaddr_in6 *)nam; @@ -644,15 +637,12 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) return EISCONN; s = splnet(); error = in6_pcbconnect(inp, nam, p); - if (ip6_auto_flowlabel) { - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; - inp->in6p_flowinfo |= - (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); - } splx(s); if (error == 0) { - inp->inp_vflag &= ~INP_IPV4; - inp->inp_vflag |= INP_IPV6; + if (ip6_mapped_addr_on) { /* should be non mapped addr */ + inp->inp_vflag &= ~INP_IPV4; + inp->inp_vflag |= INP_IPV6; + } soisconnected(so); } return error; diff --git a/sys/netkey/key.c b/sys/netkey/key.c index 497695a..31dc63b 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key.c,v 1.137 2000/06/24 00:47:07 itojun Exp $ */ +/* $KAME: key.c,v 1.187 2001/05/24 07:41:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -79,11 +79,7 @@ #include <netkey/keydb.h> #include <netkey/key.h> #include <netkey/keysock.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <netinet6/ipsec.h> #ifdef INET6 @@ -100,9 +96,15 @@ #endif #endif #include <netinet6/ipcomp.h> +#ifdef INET6 +#include <netinet6/ipcomp6.h> +#endif #include <machine/stdarg.h> +/* randomness */ +#include <sys/random.h> + #include <net/net_osdep.h> #ifndef satosin @@ -208,6 +210,10 @@ static const int maxsize[] = { sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ }; +static int ipsec_esp_keymin = 256; +static int ipsec_esp_auth = 0; +static int ipsec_ah_keymin = 128; + #ifdef SYSCTL_DECL SYSCTL_DECL(_net_key); #endif @@ -245,9 +251,13 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ &key_blockacq_lifetime, 0, ""); -static const int ipsec_esp_keymin = 256; -static const int ipsec_esp_auth = 0; -static const int ipsec_ah_keymin = 128; +/* minimum ESP key length */ +SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \ + &ipsec_esp_keymin, 0, ""); + +/* minimum AH key length */ +SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \ + &ipsec_ah_keymin, 0, ""); #ifndef LIST_FOREACH #define LIST_FOREACH(elm, head, field) \ @@ -371,6 +381,7 @@ static int key_spddump __P((struct socket *, struct mbuf *, static struct mbuf *key_setdumpsp __P((struct secpolicy *, u_int8_t, u_int32_t, u_int32_t)); static u_int key_getspreqmsglen __P((struct secpolicy *)); +static int key_spdexpire __P((struct secpolicy *)); static struct secashead *key_newsah __P((struct secasindex *)); static void key_delsah __P((struct secashead *)); static struct secasvar *key_newsav __P((struct mbuf *, @@ -404,6 +415,8 @@ static int key_cmpsaidx_exactly __P((struct secasindex *, struct secasindex *)); static int key_cmpsaidx_withmode __P((struct secasindex *, struct secasindex *)); +static int key_cmpsaidx_withoutmode2 + __P((struct secasindex *, struct secasindex *)); static int key_cmpsaidx_withoutmode __P((struct secasindex *, struct secasindex *)); static int key_cmpspidx_exactly @@ -413,7 +426,6 @@ static int key_cmpspidx_withmask static int key_sockaddrcmp __P((struct sockaddr *, struct sockaddr *, int)); static int key_bbcmp __P((caddr_t, caddr_t, u_int)); static void key_srandom __P((void)); -static u_long key_random __P((void)); static u_int16_t key_satype2proto __P((u_int8_t)); static u_int8_t key_proto2satype __P((u_int16_t)); @@ -437,10 +449,12 @@ static int key_delete __P((struct socket *, struct mbuf *, static int key_get __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); +static void key_getcomb_setlifetime __P((struct sadb_comb *)); #ifdef IPSEC_ESP static struct mbuf *key_getcomb_esp __P((void)); #endif static struct mbuf *key_getcomb_ah __P((void)); +static struct mbuf *key_getcomb_ipcomp __P((void)); static struct mbuf *key_getprop __P((const struct secasindex *)); static int key_acquire __P((struct secasindex *, struct secpolicy *)); @@ -485,6 +499,7 @@ key_allocsp(spidx, dir) u_int dir; { struct secpolicy *sp; + struct timeval tv; int s; /* sanity check */ @@ -525,6 +540,8 @@ found: KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp"); /* found a SPD entry */ + microtime(&tv); + sp->lastused = tv.tv_sec; sp->refcnt++; splx(s); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -535,8 +552,75 @@ found: } /* - * allocating a SA entry for a *OUTBOUND* packet. - * checking each request entries in SP, and acquire SA if need. + * return a policy that matches this particular inbound packet. + * XXX slow + */ +struct secpolicy * +key_gettunnel(osrc, odst, isrc, idst) + struct sockaddr *osrc, *odst, *isrc, *idst; +{ + struct secpolicy *sp; + const int dir = IPSEC_DIR_INBOUND; + struct timeval tv; + int s; + struct ipsecrequest *r1, *r2, *p; + struct sockaddr *os, *od, *is, *id; + struct secpolicyindex spidx; + + s = splnet(); /*called from softclock()*/ + LIST_FOREACH(sp, &sptree[dir], chain) { + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + + r1 = r2 = NULL; + for (p = sp->req; p; p = p->next) { + if (p->saidx.mode != IPSEC_MODE_TUNNEL) + continue; + + r1 = r2; + r2 = p; + + if (!r1) { + /* here we look at address matches only */ + spidx = sp->spidx; + if (isrc->sa_len > sizeof(spidx.src) || + idst->sa_len > sizeof(spidx.dst)) + continue; + bcopy(isrc, &spidx.src, isrc->sa_len); + bcopy(idst, &spidx.dst, idst->sa_len); + if (!key_cmpspidx_withmask(&sp->spidx, &spidx)) + continue; + } else { + is = (struct sockaddr *)&r1->saidx.src; + id = (struct sockaddr *)&r1->saidx.dst; + if (key_sockaddrcmp(is, isrc, 0) || + key_sockaddrcmp(id, idst, 0)) + continue; + } + + os = (struct sockaddr *)&r2->saidx.src; + od = (struct sockaddr *)&r2->saidx.dst; + if (key_sockaddrcmp(os, osrc, 0) || + key_sockaddrcmp(od, odst, 0)) + continue; + + goto found; + } + } + splx(s); + return NULL; + +found: + microtime(&tv); + sp->lastused = tv.tv_sec; + sp->refcnt++; + splx(s); + return sp; +} + +/* + * allocating an SA entry for an *OUTBOUND* packet. + * checking each request entries in SP, and acquire an SA if need. * OUT: 0: there are valid requests. * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. */ @@ -987,7 +1071,7 @@ key_freesav(sav) sav->refcnt--; KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n", + printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n", sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); if (sav->refcnt == 0) @@ -1212,9 +1296,7 @@ key_msg2sp(xpl0, len, error) switch (xisr->sadb_x_ipsecrequest_proto) { case IPPROTO_ESP: case IPPROTO_AH: -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: -#endif break; default: #ifdef IPSEC_DEBUG @@ -1534,11 +1616,11 @@ fail: /* * SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing * add a entry to SP database, when received - * <base, address(SD), policy> + * <base, address(SD), (lifetime(H),) policy> * from the user(?). * Adding to SP database, * and send - * <base, address(SD), policy> + * <base, address(SD), (lifetime(H),) policy> * to the socket which was send. * * SPDADD set a unique policy entry. @@ -1555,8 +1637,10 @@ key_spdadd(so, m, mhp) { struct sadb_address *src0, *dst0; struct sadb_x_policy *xpl0, *xpl; + struct sadb_lifetime *lft = NULL; struct secpolicyindex spidx; struct secpolicy *newsp; + struct timeval tv; int error; /* sanity check */ @@ -1579,6 +1663,16 @@ key_spdadd(so, m, mhp) #endif return key_senderror(so, m, EINVAL); } + if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) { + if (mhp->extlen[SADB_EXT_LIFETIME_HARD] + < sizeof(struct sadb_lifetime)) { +#ifdef IPSEC_DEBUG + printf("key_spdadd: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; + } src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; @@ -1702,6 +1796,12 @@ key_spdadd(so, m, mhp) } #endif + microtime(&tv); + newsp->created = tv.tv_sec; + newsp->lastused = tv.tv_sec; + newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; + newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; + newsp->refcnt = 1; /* do not reclaim until I say I do */ newsp->state = IPSEC_SPSTATE_ALIVE; LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain); @@ -1710,8 +1810,9 @@ key_spdadd(so, m, mhp) if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { struct secspacq *spacq; if ((spacq = key_getspacq(&spidx)) != NULL) { - /* reset counter in order to deletion by timehander. */ - spacq->tick = key_blockacq_lifetime; + /* reset counter in order to deletion by timehandler. */ + microtime(&tv); + spacq->created = tv.tv_sec; spacq->count = 0; } } @@ -1722,8 +1823,15 @@ key_spdadd(so, m, mhp) int off; /* create new sadb_msg to reply. */ - n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, - SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + if (lft) { + n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, + SADB_X_EXT_POLICY, SADB_EXT_LIFETIME_HARD, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + } else { + n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, + SADB_X_EXT_POLICY, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + } if (!n) return key_senderror(so, m, ENOBUFS); @@ -2308,6 +2416,123 @@ key_getspreqmsglen(sp) return tlen; } +/* + * SADB_SPDEXPIRE processing + * send + * <base, address(SD), lifetime(CH), policy> + * to KMD by PF_KEY. + * + * OUT: 0 : succeed + * others : error number + */ +static int +key_spdexpire(sp) + struct secpolicy *sp; +{ + int s; + struct mbuf *result = NULL, *m; + int len; + int error = -1; + struct sadb_lifetime *lt; + + /* XXX: Why do we lock ? */ + s = splnet(); /*called from softclock()*/ + + /* sanity check */ + if (sp == NULL) + panic("key_spdexpire: NULL pointer is passed.\n"); + + /* set msg header */ + m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0); + if (!m) { + error = ENOBUFS; + goto fail; + } + result = m; + + /* create lifetime extension (current and hard) */ + len = PFKEY_ALIGN8(sizeof(*lt)) * 2; + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + error = ENOBUFS; + goto fail; + } + bzero(mtod(m, caddr_t), len); + lt = mtod(m, struct sadb_lifetime *); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + lt->sadb_lifetime_allocations = 0; + lt->sadb_lifetime_bytes = 0; + lt->sadb_lifetime_addtime = sp->created; + lt->sadb_lifetime_usetime = sp->lastused; + lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + lt->sadb_lifetime_allocations = 0; + lt->sadb_lifetime_bytes = 0; + lt->sadb_lifetime_addtime = sp->lifetime; + lt->sadb_lifetime_usetime = sp->validtime; + m_cat(result, m); + + /* set sadb_address for source */ + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, sp->spidx.ul_proto); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + /* set sadb_address for destination */ + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, sp->spidx.ul_proto); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + /* set secpolicy */ + m = key_sp2msg(sp); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; + goto fail; + } + + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) { + error = ENOBUFS; + goto fail; + } + } + + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; + + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); + + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + + fail: + if (result) + m_freem(result); + splx(s); + return error; +} + /* %%% SAD management */ /* * allocating a memory for new SA head, and copy from the values of mhp. @@ -2484,8 +2709,12 @@ key_newsav(m, mhp, sah, errp) } } - /* reset tick */ - newsav->tick = 0; + /* reset created */ + { + struct timeval tv; + microtime(&tv); + newsav->created = tv.tv_sec; + } newsav->pid = mhp->msg->sadb_msg_pid; @@ -2517,28 +2746,41 @@ key_delsav(sav) if (__LIST_CHAINED(sav)) LIST_REMOVE(sav, chain); - if (sav->key_auth != NULL) + if (sav->key_auth != NULL) { + bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth)); KFREE(sav->key_auth); - if (sav->key_enc != NULL) + sav->key_auth = NULL; + } + if (sav->key_enc != NULL) { + bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc)); KFREE(sav->key_enc); - if (sav->replay != NULL) + sav->key_enc = NULL; + } + if (sav->sched) { + bzero(sav->sched, sav->schedlen); + KFREE(sav->sched); + sav->sched = NULL; + } + if (sav->replay != NULL) { keydb_delsecreplay(sav->replay); - if (sav->lft_c != NULL) + sav->replay = NULL; + } + if (sav->lft_c != NULL) { KFREE(sav->lft_c); - if (sav->lft_h != NULL) + sav->lft_c = NULL; + } + if (sav->lft_h != NULL) { KFREE(sav->lft_h); - if (sav->lft_s != NULL) + sav->lft_h = NULL; + } + if (sav->lft_s != NULL) { KFREE(sav->lft_s); - if (sav->iv != NULL) + sav->lft_s = NULL; + } + if (sav->iv != NULL) { KFREE(sav->iv); -#if notyet - if (sav->misc1 != NULL) - KFREE(sav->misc1); - if (sav->misc2 != NULL) - KFREE(sav->misc2); - if (sav->misc3 != NULL) - KFREE(sav->misc3); -#endif + sav->iv = NULL; + } KFREE(sav); @@ -2560,8 +2802,8 @@ key_getsah(saidx) LIST_FOREACH(sah, &sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; - if (key_cmpsaidx_exactly(&sah->saidx, saidx)) - return(sah); + if (key_cmpsaidx_withoutmode2(&sah->saidx, saidx)) + return sah; } return NULL; @@ -2671,15 +2913,12 @@ key_setsaval(sav, m, mhp) sav->replay = NULL; sav->key_auth = NULL; sav->key_enc = NULL; + sav->sched = NULL; + sav->schedlen = 0; sav->iv = NULL; sav->lft_c = NULL; sav->lft_h = NULL; sav->lft_s = NULL; -#if notyet - sav->misc1 = NULL; - sav->misc2 = NULL; - sav->misc3 = NULL; -#endif /* SA */ if (mhp->ext[SADB_EXT_SA] != NULL) { @@ -2725,7 +2964,7 @@ key_setsaval(sav, m, mhp) case SADB_SATYPE_AH: case SADB_SATYPE_ESP: if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && - sav->alg_auth != SADB_AALG_NULL) + sav->alg_auth != SADB_X_AALG_NULL) error = EINVAL; break; case SADB_X_SATYPE_IPCOMP: @@ -2766,11 +3005,26 @@ key_setsaval(sav, m, mhp) switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_ESP: if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && - sav->alg_enc != SADB_EALG_NULL) + sav->alg_enc != SADB_EALG_NULL) { error = EINVAL; + break; + } + sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); + if (sav->key_enc == NULL) { +#ifdef IPSEC_DEBUG + printf("key_setsaval: No more memory.\n"); +#endif + error = ENOBUFS; + goto fail; + } break; - case SADB_SATYPE_AH: case SADB_X_SATYPE_IPCOMP: + if (len != PFKEY_ALIGN8(sizeof(struct sadb_key))) + error = EINVAL; + sav->key_enc = NULL; /*just in case*/ + break; + case SADB_SATYPE_AH: + default: error = EINVAL; break; } @@ -2780,15 +3034,6 @@ key_setsaval(sav, m, mhp) #endif goto fail; } - - sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); - if (sav->key_enc == NULL) { -#ifdef IPSEC_DEBUG - printf("key_setsaval: No more memory.\n"); -#endif - error = ENOBUFS; - goto fail; - } } /* set iv */ @@ -2797,9 +3042,9 @@ key_setsaval(sav, m, mhp) switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_ESP: #ifdef IPSEC_ESP - algo = &esp_algorithms[sav->alg_enc]; + algo = esp_algorithm_lookup(sav->alg_enc); if (algo && algo->ivlen) - sav->ivlen = (*algo->ivlen)(sav); + sav->ivlen = (*algo->ivlen)(algo, sav); if (sav->ivlen == 0) break; KMALLOC(sav->iv, caddr_t, sav->ivlen); @@ -2812,20 +3057,11 @@ key_setsaval(sav, m, mhp) } /* initialize */ - { - int i; - u_int8_t *p = (u_int8_t *)sav->iv; - for (i = 0; i < sav->ivlen; i++) - p[i] = key_random() & 0xff; - } - break; -#else - break; + key_randomfill(sav->iv, sav->ivlen); #endif + break; case SADB_SATYPE_AH: -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: -#endif break; default: #ifdef IPSEC_DEBUG @@ -2835,8 +3071,9 @@ key_setsaval(sav, m, mhp) goto fail; } - /* reset tick */ - sav->tick = 0; + /* reset created */ + microtime(&tv); + sav->created = tv.tv_sec; /* make lifetime for CURRENT */ KMALLOC(sav->lft_c, struct sadb_lifetime *, @@ -2900,63 +3137,42 @@ key_setsaval(sav, m, mhp) } } -#if notyet - /* pre-processing for DES */ - switch (sav->alg_enc) { - case SADB_EALG_DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), - (des_key_schedule)sav->misc1) != 0) { -#ifdef IPSEC_DEBUG - printf("key_setsaval: error des_key_sched.\n"); -#endif - sav->misc1 = NULL; - /* THROUGH */ - } - break; - case SADB_EALG_3DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), - (des_key_schedule)sav->misc1) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), - (des_key_schedule)sav->misc2) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), - (des_key_schedule)sav->misc3) != 0) { -#ifdef IPSEC_DEBUG - printf("key_setsaval: error des_key_sched.\n"); -#endif - sav->misc1 = NULL; - sav->misc2 = NULL; - sav->misc3 = NULL; - /* THROUGH */ - } - } -#endif - return 0; fail: /* initialization */ - if (sav->replay != NULL) + if (sav->replay != NULL) { keydb_delsecreplay(sav->replay); - if (sav->key_auth != NULL) + sav->replay = NULL; + } + if (sav->key_auth != NULL) { KFREE(sav->key_auth); - if (sav->key_enc != NULL) + sav->key_auth = NULL; + } + if (sav->key_enc != NULL) { KFREE(sav->key_enc); - if (sav->iv != NULL) + sav->key_enc = NULL; + } + if (sav->sched) { + KFREE(sav->sched); + sav->sched = NULL; + } + if (sav->iv != NULL) { KFREE(sav->iv); - if (sav->lft_c != NULL) + sav->iv = NULL; + } + if (sav->lft_c != NULL) { KFREE(sav->lft_c); - if (sav->lft_h != NULL) + sav->lft_c = NULL; + } + if (sav->lft_h != NULL) { KFREE(sav->lft_h); - if (sav->lft_s != NULL) + sav->lft_h = NULL; + } + if (sav->lft_s != NULL) { KFREE(sav->lft_s); -#if notyet - if (sav->misc1 != NULL) - KFREE(sav->misc1); - if (sav->misc2 != NULL) - KFREE(sav->misc2); - if (sav->misc3 != NULL) - KFREE(sav->misc3); -#endif + sav->lft_s = NULL; + } return error; } @@ -2977,11 +3193,17 @@ key_mature(sav) mature = 0; /* check SPI value */ - if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { + switch (sav->sah->saidx.proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { #ifdef IPSEC_DEBUG - printf("key_mature: illegal range of SPI %d.\n", sav->spi); + printf("key_mature: illegal range of SPI %u.\n", + (u_int32_t)ntohl(sav->spi)); #endif - return EINVAL; + return EINVAL; + } + break; } /* check satype */ @@ -2996,7 +3218,10 @@ key_mature(sav) #endif return EINVAL; } - checkmask = 3; + if (sav->alg_auth == SADB_AALG_NONE) + checkmask = 1; + else + checkmask = 3; mustmask = 1; break; case IPPROTO_AH: @@ -3018,7 +3243,6 @@ key_mature(sav) checkmask = 2; mustmask = 2; break; -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: if (sav->alg_auth != SADB_AALG_NONE) { #ifdef IPSEC_DEBUG @@ -3037,7 +3261,6 @@ key_mature(sav) checkmask = 4; mustmask = 4; break; -#endif default: #ifdef IPSEC_DEBUG printf("key_mature: Invalid satype.\n"); @@ -3047,19 +3270,11 @@ key_mature(sav) /* check authentication algorithm */ if ((checkmask & 2) != 0) { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; int keylen; - /* XXX: should use algorithm map to check. */ - switch (sav->alg_auth) { - case SADB_AALG_NONE: - case SADB_AALG_MD5HMAC: - case SADB_AALG_SHA1HMAC: - case SADB_AALG_MD5: - case SADB_AALG_SHA: - case SADB_AALG_NULL: - break; - default: + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { #ifdef IPSEC_DEBUG printf("key_mature: " "unknown authentication algorithm.\n"); @@ -3068,8 +3283,6 @@ key_mature(sav) } /* algorithm-dependent check */ - algo = &ah_algorithms[sav->alg_auth]; - if (sav->key_auth) keylen = sav->key_auth->sadb_key_bits; else @@ -3102,19 +3315,11 @@ key_mature(sav) /* check encryption algorithm */ if ((checkmask & 1) != 0) { #ifdef IPSEC_ESP - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int keylen; - switch (sav->alg_enc) { - case SADB_EALG_NONE: - case SADB_EALG_DESCBC: - case SADB_EALG_3DESCBC: - case SADB_EALG_NULL: - case SADB_EALG_BLOWFISHCBC: - case SADB_EALG_CAST128CBC: - case SADB_EALG_RC5CBC: - break; - default: + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { #ifdef IPSEC_DEBUG printf("key_mature: unknown encryption algorithm.\n"); #endif @@ -3122,8 +3327,6 @@ key_mature(sav) } /* algorithm-dependent check */ - algo = &esp_algorithms[sav->alg_enc]; - if (sav->key_enc) keylen = sav->key_enc->sadb_key_bits; else @@ -3161,28 +3364,13 @@ key_mature(sav) /* check compression algorithm */ if ((checkmask & 4) != 0) { - struct ipcomp_algorithm *algo; - - switch (sav->alg_enc) { - case SADB_X_CALG_NONE: - case SADB_X_CALG_OUI: - case SADB_X_CALG_DEFLATE: - case SADB_X_CALG_LZS: - break; - default: -#ifdef IPSEC_DEBUG - printf("key_mature: unknown compression algorithm.\n"); -#endif - return EINVAL; - } + const struct ipcomp_algorithm *algo; /* algorithm-dependent check */ - algo = &ipcomp_algorithms[sav->alg_enc]; - - if (!(algo->compress && algo->decompress)) { + algo = ipcomp_algorithm_lookup(sav->alg_enc); + if (!algo) { #ifdef IPSEC_DEBUG - printf("key_mature: " - "unsupported compression algorithm.\n"); + printf("key_mature: unknown compression algorithm.\n"); #endif return EINVAL; } @@ -3752,7 +3940,50 @@ key_cmpsaidx_withmode(saidx0, saidx1) } /* - * compare two secasindex structure without mode. + * compare two secasindex structure without mode, but think reqid. + * don't compare port. + * IN: + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from user. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_withoutmode2(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; + + if (saidx0 == NULL || saidx1 == NULL) + return 0; + + if (saidx0->proto != saidx1->proto) + return 0; + + /* + * If reqid of SPD is non-zero, unique SA is required. + * The result must be of same reqid in this case. + */ + if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid) + return 0; + + if (key_sockaddrcmp((struct sockaddr *)&saidx0->src, + (struct sockaddr *)&saidx1->src, 0) != 0) { + return 0; + } + if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst, + (struct sockaddr *)&saidx1->dst, 0) != 0) { + return 0; + } + + return 1; +} + +/* + * compare two secasindex structure without both mode and reqid. * don't compare port. * IN: * saidx0: source, it is often in SAD. @@ -3870,7 +4101,13 @@ key_cmpspidx_withmask(spidx0, spidx1) && satosin6(&spidx0->src)->sin6_port != satosin6(&spidx1->src)->sin6_port) return 0; - if (satosin6(&spidx0->src)->sin6_scope_id != + /* + * scope_id check. if sin6_scope_id is 0, we regard it + * as a wildcard scope, which matches any scope zone ID. + */ + if (satosin6(&spidx0->src)->sin6_scope_id && + satosin6(&spidx1->src)->sin6_scope_id && + satosin6(&spidx0->src)->sin6_scope_id != satosin6(&spidx1->src)->sin6_scope_id) return 0; if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr, @@ -3899,7 +4136,13 @@ key_cmpspidx_withmask(spidx0, spidx1) && satosin6(&spidx0->dst)->sin6_port != satosin6(&spidx1->dst)->sin6_port) return 0; - if (satosin6(&spidx0->dst)->sin6_scope_id != + /* + * scope_id check. if sin6_scope_id is 0, we regard it + * as a wildcard scope, which matches any scope zone ID. + */ + if (satosin6(&spidx0->src)->sin6_scope_id && + satosin6(&spidx1->src)->sin6_scope_id && + satosin6(&spidx0->dst)->sin6_scope_id != satosin6(&spidx1->dst)->sin6_scope_id) return 0; if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr, @@ -4005,12 +4248,16 @@ key_bbcmp(p1, p2, bits) * time handler. * scanning SPD and SAD to check status for each entries, * and do to remove or to expire. + * XXX: year 2038 problem may remain. */ void key_timehandler(void) { u_int dir; int s; + struct timeval tv; + + microtime(&tv); s = splnet(); /*called from softclock()*/ @@ -4025,8 +4272,23 @@ key_timehandler(void) nextsp = LIST_NEXT(sp, chain); - if (sp->state == IPSEC_SPSTATE_DEAD) + if (sp->state == IPSEC_SPSTATE_DEAD) { key_freesp(sp); + continue; + } + + if (sp->lifetime == 0 && sp->validtime == 0) + continue; + + /* the deletion will occur next time */ + if ((sp->lifetime + && tv.tv_sec - sp->created > sp->lifetime) + || (sp->validtime + && tv.tv_sec - sp->lastused > sp->validtime)) { + sp->state = IPSEC_SPSTATE_DEAD; + key_spdexpire(sp); + continue; + } } } } @@ -4055,9 +4317,7 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - - if (key_larval_lifetime < sav->tick) { + if (tv.tv_sec - sav->created > key_larval_lifetime) { key_freesav(sav); } } @@ -4072,8 +4332,6 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - /* we don't need to check. */ if (sav->lft_s == NULL) continue; @@ -4087,9 +4345,9 @@ key_timehandler(void) continue; } - /* compare SOFT lifetime and tick */ + /* check SOFT lifetime */ if (sav->lft_s->sadb_lifetime_addtime != 0 - && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { /* * check SA to be used whether or not. * when SA hasn't been used, delete it. @@ -4134,8 +4392,6 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - /* we don't need to check. */ if (sav->lft_h == NULL) continue; @@ -4149,9 +4405,8 @@ key_timehandler(void) continue; } - /* compare HARD lifetime and tick */ if (sav->lft_h->sadb_lifetime_addtime != 0 - && sav->lft_h->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_h->sadb_lifetime_addtime) { key_sa_chgstate(sav, SADB_SASTATE_DEAD); key_freesav(sav); sav = NULL; @@ -4159,7 +4414,7 @@ key_timehandler(void) #if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ else if (sav->lft_s != NULL && sav->lft_s->sadb_lifetime_addtime != 0 - && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { /* * XXX: should be checked to be * installed the valid SA. @@ -4220,9 +4475,8 @@ key_timehandler(void) nextacq = LIST_NEXT(acq, chain); - acq->tick++; - - if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + if (tv.tv_sec - acq->created > key_blockacq_lifetime + && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); } @@ -4240,9 +4494,8 @@ key_timehandler(void) nextacq = LIST_NEXT(acq, chain); - acq->tick++; - - if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + if (tv.tv_sec - acq->created > key_blockacq_lifetime + && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); } @@ -4257,7 +4510,7 @@ key_timehandler(void) #ifndef IPSEC_DEBUG2 /* do exchange to tick time !! */ - (void)timeout((void *)key_timehandler, (void *)0, 100); + (void)timeout((void *)key_timehandler, (void *)0, hz); #endif /* IPSEC_DEBUG2 */ splx(s); @@ -4279,19 +4532,41 @@ key_srandom() return; } -/* - * to initialize a seed for random() - */ -static u_long +u_long key_random() { u_long value; - value = random(); - + key_randomfill(&value, sizeof(value)); return value; } +void +key_randomfill(p, l) + void *p; + size_t l; +{ + size_t n; + u_long v; + static int warn = 1; + + n = 0; + n = (size_t)read_random(p, (u_int)l); + /* last resort */ + while (n < l) { + v = random(); + bcopy(&v, (u_int8_t *)p + n, + l - n < sizeof(v) ? l - n : sizeof(v)); + n += sizeof(v); + + if (warn) { + printf("WARNING: pseudo-random number generator " + "used for IPsec processing\n"); + warn = 0; + } + } +} + /* * map SADB_SATYPE_* to IPPROTO_*. * if satype == SADB_SATYPE then satype is mapped to ~0. @@ -4309,11 +4584,9 @@ key_satype2proto(satype) return IPPROTO_AH; case SADB_SATYPE_ESP: return IPPROTO_ESP; -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: return IPPROTO_IPCOMP; break; -#endif default: return 0; } @@ -4334,11 +4607,9 @@ key_proto2satype(proto) return SADB_SATYPE_AH; case IPPROTO_ESP: return SADB_SATYPE_ESP; -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: return SADB_X_SATYPE_IPCOMP; break; -#endif default: return 0; } @@ -4481,8 +4752,10 @@ key_getspi(so, m, mhp) if (mhp->msg->sadb_msg_seq != 0) { struct secacq *acq; if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) { - /* reset counter in order to deletion by timehander. */ - acq->tick = key_blockacq_lifetime; + /* reset counter in order to deletion by timehandler. */ + struct timeval tv; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; } } @@ -5047,6 +5320,7 @@ key_setident(sah, m, mhp) KMALLOC(sah->identd, struct sadb_ident *, iddstlen); if (sah->identd == NULL) { KFREE(sah->idents); + sah->idents = NULL; #ifdef IPSEC_DEBUG printf("key_setident: No more memory.\n"); #endif @@ -5094,6 +5368,9 @@ key_getmsgbuf_x1(m, mhp) return n; } +static int key_delete_all __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *, u_int16_t)); + /* * SADB_DELETE processing * receive @@ -5130,16 +5407,15 @@ key_delete(so, m, mhp) return key_senderror(so, m, EINVAL); } - if (mhp->ext[SADB_EXT_SA] == NULL || - mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { #ifdef IPSEC_DEBUG printf("key_delete: invalid message is passed.\n"); #endif return key_senderror(so, m, EINVAL); } - if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || - mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { #ifdef IPSEC_DEBUG printf("key_delete: invalid message is passed.\n"); @@ -5147,6 +5423,23 @@ key_delete(so, m, mhp) return key_senderror(so, m, EINVAL); } + if (mhp->ext[SADB_EXT_SA] == NULL) { + /* + * Caller wants us to delete all non-LARVAL SAs + * that match the src/dst. This is used during + * IKE INITIAL-CONTACT. + */ +#ifdef IPSEC_DEBUG + printf("key_delete: doing delete all.\n"); +#endif + return key_delete_all(so, m, mhp, proto); + } else if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa)) { +#ifdef IPSEC_DEBUG + printf("key_delete: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); @@ -5202,6 +5495,84 @@ key_delete(so, m, mhp) } /* + * delete all SAs for src/dst. Called from key_delete(). + */ +static int +key_delete_all(so, m, mhp, proto) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; + u_int16_t proto; +{ + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav, *nextsav; + u_int stateidx, state; + + src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); + + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); + + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0) + continue; + + /* Delete all non-LARVAL SAs. */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { + state = saorder_state_alive[stateidx]; + if (state == SADB_SASTATE_LARVAL) + continue; + for (sav = LIST_FIRST(&sah->savtree[state]); + sav != NULL; sav = nextsav) { + nextsav = LIST_NEXT(sav, chain); + /* sanity check */ + if (sav->state != state) { +#ifdef IPSEC_DEBUG + printf("key_delete_all: " + "invalid sav->state " + "(queue: %d SA: %d)\n", + state, sav->state); +#endif + continue; + } + + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + } + } + } + { + struct mbuf *n; + struct sadb_msg *newmsg; + + /* create new sadb_msg to reply. */ + n = key_gather_mbuf(m, mhp, 1, 3, SADB_EXT_RESERVED, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + if (!n) + return key_senderror(so, m, ENOBUFS); + + if (n->m_len < sizeof(struct sadb_msg)) { + n = m_pullup(n, sizeof(struct sadb_msg)); + if (n == NULL) + return key_senderror(so, m, ENOBUFS); + } + newmsg = mtod(n, struct sadb_msg *); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); + + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + } +} + +/* * SADB_GET processing * receive * <base, SA(*), address(SD)> @@ -5304,17 +5675,32 @@ key_get(so, m, mhp) } } +/* XXX make it sysctl-configurable? */ +static void +key_getcomb_setlifetime(comb) + struct sadb_comb *comb; +{ + + comb->sadb_comb_soft_allocations = 1; + comb->sadb_comb_hard_allocations = 1; + comb->sadb_comb_soft_bytes = 0; + comb->sadb_comb_hard_bytes = 0; + comb->sadb_comb_hard_addtime = 86400; /* 1 day */ + comb->sadb_comb_soft_addtime = comb->sadb_comb_soft_addtime * 80 / 100; + comb->sadb_comb_soft_usetime = 28800; /* 8 hours */ + comb->sadb_comb_hard_usetime = comb->sadb_comb_hard_usetime * 80 / 100; +} + #ifdef IPSEC_ESP /* * XXX reorder combinations by preference * XXX no idea if the user wants ESP authentication or not - * XXX lifetime - should be in policy? */ static struct mbuf * key_getcomb_esp() { struct sadb_comb *comb; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; struct mbuf *result = NULL, *m, *n; int encmin; int i, off, o; @@ -5322,8 +5708,10 @@ key_getcomb_esp() const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); m = NULL; - for (i = 1; i < SADB_EALG_MAX; i++) { - algo = &esp_algorithms[i]; + for (i = 1; i <= SADB_EALG_MAX; i++) { + algo = esp_algorithm_lookup(i); + if (!algo) + continue; if (algo->keymax < ipsec_esp_keymin) continue; @@ -5365,6 +5753,8 @@ key_getcomb_esp() goto fail; } comb = (struct sadb_comb *)(mtod(n, caddr_t) + o); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); comb->sadb_comb_encrypt = i; comb->sadb_comb_encrypt_minbits = encmin; comb->sadb_comb_encrypt_maxbits = algo->keymax; @@ -5387,26 +5777,27 @@ key_getcomb_esp() /* * XXX reorder combinations by preference - * XXX lifetime - should be in policy? */ static struct mbuf * key_getcomb_ah() { struct sadb_comb *comb; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; struct mbuf *m; int min; int i; const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); m = NULL; - for (i = 1; i < SADB_AALG_MAX; i++) { + for (i = 1; i <= SADB_AALG_MAX; i++) { #if 1 /* we prefer HMAC algorithms, not old algorithms */ if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC) continue; #endif - algo = &ah_algorithms[i]; + algo = ah_algorithm_lookup(i); + if (!algo) + continue; if (algo->keymax < ipsec_ah_keymin) continue; @@ -5433,6 +5824,7 @@ key_getcomb_ah() comb = mtod(m, struct sadb_comb *); bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); comb->sadb_comb_auth = i; comb->sadb_comb_auth_minbits = min; comb->sadb_comb_auth_maxbits = algo->keymax; @@ -5442,6 +5834,51 @@ key_getcomb_ah() } /* + * not really an official behavior. discussed in pf_key@inner.net in Sep2000. + * XXX reorder combinations by preference + */ +static struct mbuf * +key_getcomb_ipcomp() +{ + struct sadb_comb *comb; + const struct ipcomp_algorithm *algo; + struct mbuf *m; + int i; + const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); + + m = NULL; + for (i = 1; i <= SADB_X_CALG_MAX; i++) { + algo = ipcomp_algorithm_lookup(i); + if (!algo) + continue; + + if (!m) { +#ifdef DIAGNOSTIC + if (l > MLEN) + panic("assumption failed in key_getcomb_ipcomp"); +#endif + MGET(m, M_DONTWAIT, MT_DATA); + if (m) { + M_ALIGN(m, l); + m->m_len = l; + m->m_next = NULL; + } + } else + M_PREPEND(m, l, M_DONTWAIT); + if (!m) + return NULL; + + comb = mtod(m, struct sadb_comb *); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); + comb->sadb_comb_encrypt = i; + /* what should we set into sadb_comb_*_{min,max}bits? */ + } + + return m; +} + +/* * XXX no way to pass mode (transport/tunnel) to userland * XXX replay checking? * XXX sysctl interface to ipsec_{ah,esp}_keymin @@ -5464,6 +5901,9 @@ key_getprop(saidx) case IPPROTO_AH: m = key_getcomb_ah(); break; + case IPPROTO_IPCOMP: + m = key_getcomb_ipcomp(); + break; default: return NULL; } @@ -5490,7 +5930,7 @@ key_getprop(saidx) /* * SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2(). * send - * <base, SA, address(SD), (address(P)), + * <base, SA, address(SD), (address(P)), x_policy, * (identity(SD),) (sensitivity,) proposal> * to KMD, and expect to receive * <base> with SADB_ACQUIRE if error occured, @@ -5498,7 +5938,10 @@ key_getprop(saidx) * <base, src address, dst address, (SPI range)> with SADB_GETSPI * from KMD by PF_KEY. * - * sensitivity is not supported. + * XXX x_policy is outside of RFC2367 (KAME extension). + * XXX sensitivity is not supported. + * XXX for ipcomp, RFC2367 does not define how to fill in proposal. + * see comment for key_getcomb_ipcomp(). * * OUT: * 0 : succeed @@ -5639,11 +6082,24 @@ key_acquire(saidx, sp) /* create proposal/combination extension */ m = key_getprop(saidx); +#if 0 + /* + * spec conformant: always attach proposal/combination extension, + * the problem is that we have no way to attach it for ipcomp, + * due to the way sadb_comb is declared in RFC2367. + */ if (!m) { error = ENOBUFS; goto fail; } m_cat(result, m); +#else + /* + * outside of spec; make proposal/combination extension optional. + */ + if (m) + m_cat(result, m); +#endif if ((result->m_flags & M_PKTHDR) == 0) { error = EINVAL; @@ -5679,6 +6135,7 @@ key_newacq(saidx) struct secasindex *saidx; { struct secacq *newacq; + struct timeval tv; /* get new entry */ KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); @@ -5693,7 +6150,8 @@ key_newacq(saidx) /* copy secindex */ bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); - newacq->tick = 0; + microtime(&tv); + newacq->created = tv.tv_sec; newacq->count = 0; return newacq; @@ -5733,6 +6191,7 @@ key_newspacq(spidx) struct secpolicyindex *spidx; { struct secspacq *acq; + struct timeval tv; /* get new entry */ KMALLOC(acq, struct secspacq *, sizeof(struct secspacq)); @@ -5746,7 +6205,8 @@ key_newspacq(spidx) /* copy secindex */ bcopy(spidx, &acq->spidx, sizeof(acq->spidx)); - acq->tick = 0; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; return acq; @@ -5778,7 +6238,7 @@ key_getspacq(spidx) * <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal> * to the socket. * - * m will always e freed. + * m will always be freed. */ static int key_acquire2(so, m, mhp) @@ -5805,6 +6265,7 @@ key_acquire2(so, m, mhp) if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { #ifndef IPSEC_NONBLOCK_ACQUIRE struct secacq *acq; + struct timeval tv; /* check sequence number */ if (mhp->msg->sadb_msg_seq == 0) { @@ -5816,16 +6277,17 @@ key_acquire2(so, m, mhp) } if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) { -#ifdef IPSEC_DEBUG - printf("key_acquire2: " - "invalid sequence number is passed.\n"); -#endif + /* + * the specified larval SA is already gone, or we got + * a bogus sequence number. we can silently ignore it. + */ m_freem(m); return 0; } /* reset acq counter in order to deletion by timehander. */ - acq->tick = key_blockacq_lifetime; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; #endif m_freem(m); @@ -5906,7 +6368,7 @@ key_acquire2(so, m, mhp) * to KMD by PF_KEY. * If socket is detached, must free from regnode. * - * m will always e freed. + * m will always be freed. */ static int key_register(so, m, mhp) @@ -5965,13 +6427,21 @@ key_register(so, m, mhp) struct sadb_alg *alg; /* create new sadb_msg to reply. */ - alen = sizeof(struct sadb_supported) - + ((SADB_AALG_MAX - 1) * sizeof(struct sadb_alg)); -#ifdef IPSEC_ESP - elen = sizeof(struct sadb_supported) - + ((SADB_EALG_MAX - 1) * sizeof(struct sadb_alg)); -#else + alen = 0; + for (i = 1; i <= SADB_AALG_MAX; i++) { + if (ah_algorithm_lookup(i)) + alen += sizeof(struct sadb_alg); + } + if (alen) + alen += sizeof(struct sadb_supported); elen = 0; +#ifdef IPSEC_ESP + for (i = 1; i <= SADB_EALG_MAX; i++) { + if (esp_algorithm_lookup(i)) + elen += sizeof(struct sadb_alg); + } + if (elen) + elen += sizeof(struct sadb_supported); #endif len = sizeof(struct sadb_msg) + alen + elen; @@ -6007,10 +6477,12 @@ key_register(so, m, mhp) sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; off += PFKEY_ALIGN8(sizeof(*sup)); - for (i = 1; i < SADB_AALG_MAX; i++) { - struct ah_algorithm *aalgo; + for (i = 1; i <= SADB_AALG_MAX; i++) { + const struct ah_algorithm *aalgo; - aalgo = &ah_algorithms[i]; + aalgo = ah_algorithm_lookup(i); + if (!aalgo) + continue; alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); alg->sadb_alg_id = i; alg->sadb_alg_ivlen = 0; @@ -6028,10 +6500,12 @@ key_register(so, m, mhp) sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; off += PFKEY_ALIGN8(sizeof(*sup)); - for (i = 1; i < SADB_EALG_MAX; i++) { - struct esp_algorithm *ealgo; + for (i = 1; i <= SADB_EALG_MAX; i++) { + const struct esp_algorithm *ealgo; - ealgo = &esp_algorithms[i]; + ealgo = esp_algorithm_lookup(i); + if (!ealgo) + continue; alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); alg->sadb_alg_id = i; if (ealgo && ealgo->ivlen) { @@ -6039,7 +6513,8 @@ key_register(so, m, mhp) * give NULL to get the value preferred by * algorithm XXX SADB_X_EXT_DERIV ? */ - alg->sadb_alg_ivlen = (*ealgo->ivlen)(NULL); + alg->sadb_alg_ivlen = + (*ealgo->ivlen)(ealgo, NULL); } else alg->sadb_alg_ivlen = 0; alg->sadb_alg_minbits = ealgo->keymin; @@ -6190,13 +6665,17 @@ key_expire(sav) } m_cat(result, m); - if ((result->m_flags & M_PKTHDR) == 0) + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; goto fail; + } if (result->m_len < sizeof(struct sadb_msg)) { result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) + if (result == NULL) { + error = ENOBUFS; goto fail; + } } result->m_pkthdr.len = 0; @@ -6608,9 +7087,7 @@ key_parse(m, so) break; case SADB_SATYPE_AH: case SADB_SATYPE_ESP: -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: -#endif switch (msg->sadb_msg_type) { case SADB_X_SPDADD: case SADB_X_SPDDELETE: @@ -6973,8 +7450,10 @@ key_init() LIST_INIT(&spacqtree); /* system default */ +#ifdef INET ip4_def_policy.policy = IPSEC_POLICY_NONE; ip4_def_policy.refcnt++; /*never reclaim this*/ +#endif #ifdef INET6 ip6_def_policy.policy = IPSEC_POLICY_NONE; ip6_def_policy.refcnt++; /*never reclaim this*/ @@ -7167,6 +7646,16 @@ key_sa_chgstate(sav, state) LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); } +void +key_sa_stir_iv(sav) + struct secasvar *sav; +{ + + if (!sav->iv) + panic("key_sa_stir_iv called with sav == NULL"); + key_randomfill(sav->iv, sav->ivlen); +} + /* XXX too much? */ static struct mbuf * key_alloc_mbuf(l) diff --git a/sys/netkey/key.h b/sys/netkey/key.h index 65a2755..20bcaa0 100644 --- a/sys/netkey/key.h +++ b/sys/netkey/key.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key.h,v 1.17 2000/06/12 07:01:13 itojun Exp $ */ +/* $KAME: key.h,v 1.20 2001/03/22 08:09:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -47,6 +47,8 @@ struct sadb_msg; struct sadb_x_policy; extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int)); +extern struct secpolicy *key_gettunnel __P((struct sockaddr *, + struct sockaddr *, struct sockaddr *, struct sockaddr *)); extern int key_checkrequest __P((struct ipsecrequest *isr, struct secasindex *)); extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t, @@ -61,6 +63,8 @@ extern struct mbuf *key_sp2msg __P((struct secpolicy *)); extern int key_ismyaddr __P((struct sockaddr *)); extern int key_spdacquire __P((struct secpolicy *)); extern void key_timehandler __P((void)); +extern u_long key_random __P((void)); +extern void key_randomfill __P((void *, size_t)); extern void key_freereg __P((struct socket *)); extern int key_parse __P((struct mbuf *, struct socket *)); extern void key_init __P((void)); @@ -68,6 +72,7 @@ extern int key_checktunnelsanity __P((struct secasvar *, u_int, caddr_t, caddr_t)); extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *)); extern void key_sa_routechange __P((struct sockaddr *)); +extern void key_sa_stir_iv __P((struct secasvar *)); #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_SECA); diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c index 3e8b12b..76a59f3 100644 --- a/sys/netkey/key_debug.c +++ b/sys/netkey/key_debug.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key_debug.c,v 1.23 2000/07/04 04:08:15 itojun Exp $ */ +/* $KAME: key_debug.c,v 1.25 2000/07/24 13:23:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -41,17 +41,14 @@ #ifdef _KERNEL #include <sys/systm.h> #include <sys/mbuf.h> +#include <sys/queue.h> #endif #include <sys/socket.h> #include <net/route.h> #include <netkey/key_var.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <netinet/in.h> #include <netinet6/ipsec.h> diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h index 383a0e8..f75a535 100644 --- a/sys/netkey/key_debug.h +++ b/sys/netkey/key_debug.h @@ -33,6 +33,8 @@ #ifndef _NETKEY_KEY_DEBUG_H_ #define _NETKEY_KEY_DEBUG_H_ +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + /* debug flags */ #define KEYDEBUG_STAMP 0x00000001 /* path */ #define KEYDEBUG_DATA 0x00000002 /* data */ @@ -84,5 +86,10 @@ extern void kdebug_sockaddr __P((struct sockaddr *)); extern void ipsec_hexdump __P((caddr_t, int)); extern void ipsec_bindump __P((caddr_t, int)); -#endif /* _NETKEY_KEY_DEBUG_H_ */ +#else + +#define KEYDEBUG(lev,arg) +#endif /*!defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))*/ + +#endif /* _NETKEY_KEY_DEBUG_H_ */ diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h index b7a62ba..4043a03 100644 --- a/sys/netkey/key_var.h +++ b/sys/netkey/key_var.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key_var.h,v 1.8 2000/05/24 17:28:23 itojun Exp $ */ +/* $KAME: key_var.h,v 1.9 2000/10/04 11:13:57 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -42,7 +42,10 @@ #define KEYCTL_LARVAL_LIFETIME 6 #define KEYCTL_BLOCKACQ_COUNT 7 #define KEYCTL_BLOCKACQ_LIFETIME 8 -#define KEYCTL_MAXID 9 +#define KEYCTL_ESP_KEYMIN 9 +#define KEYCTL_ESP_AUTH 10 +#define KEYCTL_AH_KEYMIN 11 +#define KEYCTL_MAXID 12 #define KEYCTL_NAMES { \ { 0, 0 }, \ @@ -54,8 +57,40 @@ { "larval_lifetime", CTLTYPE_INT }, \ { "blockacq_count", CTLTYPE_INT }, \ { "blockacq_lifetime", CTLTYPE_INT }, \ + { "esp_keymin", CTLTYPE_INT }, \ + { "ah_keymin", CTLTYPE_INT }, \ } +#ifdef IPSEC_DEBUG +#define KEYCTL_VARS { \ + 0, \ + &key_debug_level, \ + &key_spi_trycnt, \ + &key_spi_minval, \ + &key_spi_maxval, \ + &key_int_random, \ + &key_larval_lifetime, \ + &key_blockacq_count, \ + &key_blockacq_lifetime, \ + &ipsec_esp_keymin, \ + &ipsec_ah_keymin, \ +} +#else +#define KEYCTL_VARS { \ + 0, \ + 0, \ + &key_spi_trycnt, \ + &key_spi_minval, \ + &key_spi_maxval, \ + &key_int_random, \ + &key_larval_lifetime, \ + &key_blockacq_count, \ + &key_blockacq_lifetime, \ + &ipsec_esp_keymin, \ + &ipsec_ah_keymin, \ +} +#endif + #ifdef _KERNEL #define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0])) #define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3)) diff --git a/sys/netkey/keydb.h b/sys/netkey/keydb.h index fcb478c..1aff5be 100644 --- a/sys/netkey/keydb.h +++ b/sys/netkey/keydb.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: keydb.h,v 1.11 2000/06/15 12:20:50 sakane Exp $ */ +/* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -82,14 +82,11 @@ struct secasvar { struct sadb_key *key_enc; /* Key for Encryption */ caddr_t iv; /* Initilization Vector */ u_int ivlen; /* length of IV */ -#if 0 - caddr_t misc1; - caddr_t misc2; - caddr_t misc3; -#endif + void *sched; /* intermediate encryption key */ + size_t schedlen; struct secreplay *replay; /* replay prevention */ - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */ struct sadb_lifetime *lft_h; /* HARD lifetime */ @@ -126,7 +123,7 @@ struct secacq { struct secasindex saidx; u_int32_t seq; /* sequence number */ - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ int count; /* for lifetime */ }; #endif diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c index 68c70c8..5eab147 100644 --- a/sys/netkey/keysock.c +++ b/sys/netkey/keysock.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: keysock.c,v 1.22 2000/05/23 13:19:21 itojun Exp $ */ +/* $KAME: keysock.c,v 1.24 2000/12/03 00:41:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -56,11 +56,7 @@ #include <netkey/keydb.h> #include <netkey/key.h> #include <netkey/keysock.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <machine/stdarg.h> @@ -158,6 +154,8 @@ key_sendup0(rp, m, promisc) struct mbuf *m; int promisc; { + int error; + if (promisc) { struct sadb_msg *pmsg; @@ -184,17 +182,18 @@ key_sendup0(rp, m, promisc) pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; } - if (!sbappendaddr(&rp->rcb_socket->so_rcv, - (struct sockaddr *)&key_src, m, NULL)) { + if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src, + m, NULL)) { #ifdef IPSEC_DEBUG printf("key_sendup0: sbappendaddr failed\n"); #endif pfkeystat.in_nomem++; m_freem(m); - return ENOBUFS; - } + error = ENOBUFS; + } else + error = 0; sorwakeup(rp->rcb_socket); - return 0; + return error; } /* XXX this interface should be obsoleted. */ diff --git a/sys/netsmb/smb_crypt.c b/sys/netsmb/smb_crypt.c index e72a385..89b6d9e 100644 --- a/sys/netsmb/smb_crypt.c +++ b/sys/netsmb/smb_crypt.c @@ -74,8 +74,8 @@ smb_E(const u_char *key, u_char *data, u_char *dest) kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe); kk[7] = key[6] << 1; ksp = malloc(sizeof(des_key_schedule), M_SMBTEMP, M_WAITOK); - des_set_key((C_Block*)kk, *ksp); - des_ecb_encrypt((C_Block*)data, (C_Block*)dest, *ksp, 1); + des_set_key((des_cblock *)kk, *ksp); + des_ecb_encrypt((des_cblock *)data, (des_cblock *)dest, *ksp, 1); free(ksp, M_SMBTEMP); } #endif diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index de7a3c9..da23e27 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -228,6 +228,20 @@ struct mbstat { u_long m_minclsize; /* min length of data to allocate a cluster */ u_long m_mlen; /* length of data in an mbuf */ u_long m_mhlen; /* length of data in a header mbuf */ + + u_quad_t m_exthdrget; /* # of calls to IP6_EXTHDR_GET */ + u_quad_t m_exthdrget0; /* # of calls to IP6_EXTHDR_GET0 */ + u_quad_t m_pulldowns; /* # of calls to m_pulldown */ + u_quad_t m_pulldown_copy; /* # of mbuf copies in m_pulldown */ + u_quad_t m_pulldown_alloc; /* # of mbuf allocs in m_pulldown */ + u_quad_t m_pullups; /* # of calls to m_pullup */ + u_quad_t m_pullup_copy; /* # of possible m_pullup copies */ + u_quad_t m_pullup_alloc; /* # of possible m_pullup mallocs */ + u_quad_t m_pullup_fail; /* # of possible m_pullup failures */ + u_quad_t m_pullup2; /* # of calls to m_pullup2 */ + u_quad_t m_pullup2_copy; /* # of possible m_pullup2 copies */ + u_quad_t m_pullup2_alloc; /* # of possible m_pullup2 mallocs */ + u_quad_t m_pullup2_fail; /* # of possible m_pullup2 failures */ }; /* flags to m_get/MGET */ @@ -524,6 +538,10 @@ struct mcntfree_lst { * MFREE(struct mbuf *m, struct mbuf *n) * Free a single mbuf and associated external storage. * Place the successor, if any, in n. + * + * we do need to check non-first mbuf for m_aux, since some of existing + * code does not call M_PREPEND properly. + * (example: call to bpf_mtap from drivers) */ #define MFREE(m, n) do { \ struct mbuf *_mm = (m); \ @@ -533,6 +551,10 @@ struct mcntfree_lst { MEXTFREE(_mm); \ mtx_lock(&mbuf_mtx); \ mbtypes[_mm->m_type]--; \ + if ((_mm->m_flags & M_PKTHDR) != 0 && _mm->m_pkthdr.aux) { \ + m_freem(_mm->m_pkthdr.aux); \ + _mm->m_pkthdr.aux = NULL; \ + } \ _mm->m_type = MT_FREE; \ mbtypes[MT_FREE]++; \ (n) = _mm->m_next; \ @@ -649,6 +671,7 @@ struct mcntfree_lst { struct mauxtag { int af; int type; + void* p; }; extern u_long m_clalloc_wid; /* mbuf cluster wait count */ @@ -672,6 +695,8 @@ extern int nsfbufs; void m_adj(struct mbuf *, int); int m_alloc_ref(u_int, int); +struct mbuf *m_aux_add2 __P((struct mbuf *, int, int, void *)); +struct mbuf *m_aux_find2 __P((struct mbuf *, int, int, void *)); struct mbuf *m_aux_add(struct mbuf *, int, int); void m_aux_delete(struct mbuf *, struct mbuf *); struct mbuf *m_aux_find(struct mbuf *, int, int); diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h index 6742f7a..00d50ff 100644 --- a/sys/sys/protosw.h +++ b/sys/sys/protosw.h @@ -119,6 +119,7 @@ struct protosw { #define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */ #define PR_RIGHTS 0x10 /* passes capabilities */ #define PR_IMPLOPCL 0x20 /* implied open/close */ +#define PR_LASTHDR 0x40 /* enforce ipsec policy; last header */ /* * The arguments to usrreq are: @@ -319,6 +320,7 @@ char *prcorequests[] = { #ifdef _KERNEL void pfctlinput __P((int, struct sockaddr *)); +void pfctlinput2 __P((int, struct sockaddr *, void *)); struct protosw *pffindproto __P((int family, int protocol, int type)); struct protosw *pffindtype __P((int family, int type)); #endif diff --git a/sys/sys/socket.h b/sys/sys/socket.h index dfa90fa..3673ff6 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -49,6 +49,13 @@ /* * Data types. */ +#include <machine/types.h> + +/* + * needed for __CMSG_ALIGN + */ +#include <machine/param.h> + typedef u_char sa_family_t; #ifdef _BSD_SOCKLEN_T_ typedef _BSD_SOCKLEN_T_ socklen_t; @@ -373,22 +380,27 @@ struct cmsgcred { /* given pointer to struct cmsghdr, return pointer to data */ #define CMSG_DATA(cmsg) ((u_char *)(cmsg) + \ - _ALIGN(sizeof(struct cmsghdr))) + __CMSG_ALIGN(sizeof(struct cmsghdr))) + +#define __CMSG_ALIGN(n) ALIGN(n) +#ifdef _KERNEL +#define CMSG_ALIGN(n) __CMSG_ALIGN(n) +#endif /* given pointer to struct cmsghdr, return pointer to next cmsghdr */ #define CMSG_NXTHDR(mhdr, cmsg) \ - (((caddr_t)(cmsg) + _ALIGN((cmsg)->cmsg_len) + \ - _ALIGN(sizeof(struct cmsghdr)) > \ + (((caddr_t)(cmsg) + __CMSG_ALIGN((cmsg)->cmsg_len) + \ + __CMSG_ALIGN(sizeof(struct cmsghdr)) > \ (caddr_t)(mhdr)->msg_control + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ - (struct cmsghdr *)((caddr_t)(cmsg) + _ALIGN((cmsg)->cmsg_len))) + (struct cmsghdr *)((caddr_t)(cmsg) + __CMSG_ALIGN((cmsg)->cmsg_len))) #define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) /* RFC 2292 additions */ - -#define CMSG_SPACE(l) (_ALIGN(sizeof(struct cmsghdr)) + _ALIGN(l)) -#define CMSG_LEN(l) (_ALIGN(sizeof(struct cmsghdr)) + (l)) + +#define CMSG_SPACE(l) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(l)) +#define CMSG_LEN(l) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (l)) /* "Socket"-level control message types: */ #define SCM_RIGHTS 0x01 /* access rights (array of int) */ diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index c107562..74c2a95 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -91,6 +91,8 @@ #define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */ #define SIOCGIFPDSTADDR _IOWR('i', 72, struct ifreq) /* get gif pdst addr */ #define SIOCDIFPHYADDR _IOW('i', 73, struct ifreq) /* delete gif addrs */ +#define SIOCSLIFPHYADDR _IOW('i', 74, struct if_laddrreq) /* set gif addrs */ +#define SIOCGLIFPHYADDR _IOWR('i', 75, struct if_laddrreq) /* get gif addrs */ #define SIOCSIFGENERIC _IOW('i', 57, struct ifreq) /* generic IF set op */ #define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */ diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index 185506c..aee1aed 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -552,6 +552,7 @@ ip_stats(off, name) p(ips_ofragments, "\t%lu fragment%s created\n"); p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n"); p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n"); + p(ips_badaddr, "\t%lu datagram%s with bad address in header\n"); #undef p #undef p1a } diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 5b09706..c41ab90 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -47,6 +47,7 @@ static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; #include <sys/ioctl.h> #include <sys/mbuf.h> #include <sys/protosw.h> +#include <sys/sysctl.h> #include <net/route.h> #include <net/if.h> @@ -59,6 +60,7 @@ static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; #include <netinet6/in6_var.h> #include <netinet6/ip6_var.h> #include <netinet6/pim6_var.h> +#include <netinet6/raw_ip6.h> #include <arpa/inet.h> #include <netdb.h> @@ -868,6 +870,13 @@ icmp6_stats(off, name) p(icp6s_reflect, "\t%llu message response%s generated\n"); p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n"); + p(icp6s_nd_badopt, "\t%qu message%s with bad ND options\n"); + p(icp6s_badns, "\t%qu bad neighbor solicitation message%s\n"); + p(icp6s_badna, "\t%qu bad neighbor advertisement message%s\n"); + p(icp6s_badrs, "\t%qu bad router solicitation message%s\n"); + p(icp6s_badra, "\t%qu bad router advertisement message%s\n"); + p(icp6s_badredirect, "\t%qu bad redirect message%s\n"); + p(icp6s_pmtuchg, "\t%llu path MTU change%s\n"); #undef p #undef p_5 } @@ -966,6 +975,52 @@ pim6_stats(off, name) } /* + * Dump raw ip6 statistics structure. + */ +void +rip6_stats(off, name) + u_long off; + char *name; +{ + struct rip6stat rip6stat; + u_quad_t delivered; + int mib[4]; + size_t l; + + mib[0] = CTL_NET; + mib[1] = PF_INET6; + mib[2] = IPPROTO_IPV6; + mib[3] = IPV6CTL_RIP6STATS; + l = sizeof(rip6stat); + if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) { + perror("Warning: sysctl(net.inet6.ip6.rip6stats)"); + return; + } + + printf("%s:\n", name); + +#define p(f, m) if (rip6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f)) + p(rip6s_ipackets, "\t%llu message%s received\n"); + p(rip6s_isum, "\t%llu checksum calcuration%s on inbound\n"); + p(rip6s_badsum, "\t%llu message%s with bad checksum\n"); + p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n"); + p(rip6s_nosockmcast, + "\t%llu multicast message%s dropped due to no socket\n"); + p(rip6s_fullsock, + "\t%llu message%s dropped due to full socket buffers\n"); + delivered = rip6stat.rip6s_ipackets - + rip6stat.rip6s_badsum - + rip6stat.rip6s_nosock - + rip6stat.rip6s_nosockmcast - + rip6stat.rip6s_fullsock; + if (delivered || sflag <= 1) + printf("\t%llu delivered\n", (unsigned long long)delivered); + p(rip6s_opackets, "\t%llu datagram%s output\n"); +#undef p +} + +/* * Pretty print an Internet address (net address + port). * If the nflag was specified, use numbers instead of names. */ diff --git a/usr.bin/netstat/ipsec.c b/usr.bin/netstat/ipsec.c index ce96488..6037d13 100644 --- a/usr.bin/netstat/ipsec.c +++ b/usr.bin/netstat/ipsec.c @@ -1,5 +1,6 @@ /* $FreeBSD$ */ /* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */ +/* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -63,6 +64,7 @@ * SUCH DAMAGE. */ +#include <sys/cdefs.h> #ifndef lint /* static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; @@ -99,30 +101,52 @@ static const char rcsid[] = #define CAST unsigned long long #ifdef IPSEC -static const char *ipsec_ahnames[] = { - "none", - "hmac MD5", - "hmac SHA1", - "keyed MD5", - "keyed SHA1", - "null", +struct val2str { + int val; + const char *str; }; -static const char *ipsec_espnames[] = { - "none", - "DES CBC", - "3DES CBC", - "simple", - "blowfish CBC", - "CAST128 CBC", - "DES derived IV", +static struct val2str ipsec_ahnames[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif + { -1, NULL }, }; -static const char *ipsec_compnames[] = { - "none", - "OUI", - "deflate", - "LZS", +static struct val2str ipsec_espnames[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif + { -1, NULL }, +}; + +static struct val2str ipsec_compnames[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL }, }; static const char *pfkey_msgtypenames[] = { @@ -137,8 +161,8 @@ static struct ipsecstat ipsecstat; static void print_ipsecstats __P((void)); static const char *pfkey_msgtype_names __P((int)); -static void ipsec_hist __P((const u_quad_t *, size_t, const char **, size_t, - const char *)); +static void ipsec_hist __P((const u_quad_t *, size_t, const struct val2str *, + size_t, const char *)); /* * Dump IPSEC statistics structure. @@ -147,26 +171,31 @@ static void ipsec_hist(hist, histmax, name, namemax, title) const u_quad_t *hist; size_t histmax; - const char **name; + const struct val2str *name; size_t namemax; const char *title; { int first; size_t proto; + const struct val2str *p; - for (first = 1, proto = 0; proto < histmax; proto++) { + first = 1; + for (proto = 0; proto < histmax; proto++) { if (hist[proto] <= 0) continue; if (first) { printf("\t%s histogram:\n", title); first = 0; } - if (proto < namemax && name[proto]) { - printf("\t\t%s: " LLU "\n", name[proto], - (CAST)hist[proto]); + for (p = name; p && p->str; p++) { + if (p->val == proto) + break; + } + if (p && p->str) { + printf("\t\t%s: " LLU "\n", p->str, (CAST)hist[proto]); } else { printf("\t\t#%ld: " LLU "\n", (long)proto, - (CAST)hist[proto]); + (CAST)hist[proto]); } } } @@ -221,19 +250,6 @@ ipsec_stats(off, name) print_ipsecstats(); } -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 /* bsdi4 only */ -void -ipsec_stats0(name) - char *name; -{ - printf("%s:\n", name); - - skread(name, &ipsecstat_info); - - print_ipsecstats(); -} -#endif - static const char * pfkey_msgtype_names(x) int x; diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 7a11793..3aab72b 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -199,6 +199,8 @@ struct protox ip6protox[] = { pim6_stats, NULL, "pim6", 0 }, #endif { -1, -1, 1, 0, + rip6_stats, NULL, "rip6", 0 }, + { -1, -1, 1, 0, bdg_stats, NULL, "bdg", 1 /* bridging... */ }, { -1, -1, 0, 0, 0, NULL, 0, 0 } diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c index 7e38a05..3441445 100644 --- a/usr.bin/netstat/mroute6.c +++ b/usr.bin/netstat/mroute6.c @@ -76,6 +76,7 @@ #include <net/if.h> #include <net/if_var.h> +#include <net/route.h> #include <netinet/in.h> diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index ef297d5..012ca9b 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -79,6 +79,7 @@ void ip6_ifstats __P((char *)); void icmp6_stats __P((u_long, char *)); void icmp6_ifstats __P((char *)); void pim6_stats __P((u_long, char *)); +void rip6_stats __P((u_long, char *)); void mroute6pr __P((u_long, u_long)); void mrt6_stats __P((u_long)); diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index db7f190..72b48ec 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -608,8 +608,15 @@ p_rtentry(rt) p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW(addr.u_sa.sa_family)); p_flags(rt->rt_flags, "%-6.6s "); - if (addr.u_sa.sa_family == AF_INET || lflag) - printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use); + if (addr.u_sa.sa_family == AF_INET || lflag) { + printf("%6ld %8ld", rt->rt_refcnt, rt->rt_use); + if (lflag) { + if (rt->rt_rmx.rmx_mtu != 0) + printf("%6lu ", rt->rt_rmx.rmx_mtu); + else + printf("%6s ", ""); + } + } if (rt->rt_ifp) { if (rt->rt_ifp != lastif) { kget(rt->rt_ifp, ifnet); diff --git a/usr.sbin/faithd/Makefile b/usr.sbin/faithd/Makefile index c63b097..42da8df 100644 --- a/usr.sbin/faithd/Makefile +++ b/usr.sbin/faithd/Makefile @@ -14,7 +14,7 @@ # $FreeBSD$ PROG= faithd -SRCS= faithd.c tcp.c ftp.c rsh.c +SRCS= faithd.c tcp.c ftp.c rsh.c prefix.c MAN= faithd.8 #CFLAGS+= -DFAITH4 CFLAGS+= -Wall diff --git a/usr.sbin/faithd/README b/usr.sbin/faithd/README index 4808b4a..2ad0592 100644 --- a/usr.sbin/faithd/README +++ b/usr.sbin/faithd/README @@ -1,7 +1,7 @@ Configuring FAITH IPv6-to-IPv4 TCP relay Kazu Yamamoto and Jun-ichiro itojun Hagino -$KAME: README,v 1.4 2000/05/31 03:16:14 itojun Exp $ +$KAME: README,v 1.7 2001/04/25 11:25:19 itojun Exp $ $FreeBSD$ Introduction @@ -27,13 +27,13 @@ invoked per each TCP services (TCP port number). clients IPv6 node "src" | You will have to allocate an IPv6 address prefix to map IPv4 addresses into. -The following description uses 3ffe:0501:1234:ffff:: as example. +The following description uses 3ffe:0501:ffff:0000:: as example. Please use a prefix which belongs to your site. FAITH will make it possible to make a IPv6 TCP connection From IPv6 node "src", toward IPv4 node "dest", by specifying FAITH-mapped address -3ffe:0501:1234:ffff::123.4.5.6 -(which is, 3ffe:0501:1234:ffff:0000:0000:7b04:0506). -The address mapping can be performed by hand:-), by speical nameserver on +3ffe:0501:ffff:0000::123.4.5.6 +(which is, 3ffe:0501:ffff:0000:0000:0000:7b04:0506). +The address mapping can be performed by hand:-), by special nameserver on the network, or by special resolver on the source node. @@ -41,7 +41,7 @@ Setup ===== The following example assumes: -- You have assigned 3ffe:0501:1234:ffff:: as FAITH adderss prefix. +- You have assigned 3ffe:0501:ffff:0000:: as FAITH adderss prefix. - You are willing to provide IPv6-to IPv4 TCP relay for telnet. <<On the translating router on which faithd runs>> @@ -57,12 +57,12 @@ The following example assumes: (3) Route packets toward FAITH prefix into "faith0" interface. # ifconfig faith0 up - # route add -inet6 3ffe:0501:1234:ffff:: -prefixlen 64 \ - fe80::xxxx:yyyy:zzzz:wwww%faith0 + # route add -inet6 3ffe:0501:ffff:0000:: -prefixlen 64 ::1 + # route change -inet6 3ffe:0501:ffff:0000:: -prefixlen 64 -ifp faith0 (4) Execute "faithd" by root as follows: - # faithd telnet /usr/local/v6/libexec/telnetd telnetd + # faithd telnet /usr/libexec/telnetd telnetd 1st argument is a service name you are willing to provide TCP relay. (it can be specified either by number "23" or by string "telnet") @@ -73,11 +73,14 @@ The following example assumes: More examples: - # faithd login /usr/local/v6/libexec/rlogin rlogind - # faithd shell /usr/local/v6/libexec/rshd rshd - # faithd ftpd /usr/local/v6/libexec/ftpd ftpd -l + # faithd login /usr/libexec/rlogin rlogind + # faithd shell /usr/libexec/rshd rshd + # faithd ftpd /usr/libexec/ftpd ftpd -l # faithd sshd +If inetd(8) on your platform have special support for faithd, it is possible +to setup faithd services via inetd(8). Consult manpage for details. + <<Routing>> @@ -95,7 +98,7 @@ There are two ways to translate IPv4 address to IPv6 address: (5.b) Add an entry into /etc/hosts so that you can resolve hostname into faked IPv6 addrss. For example, add the following line for www.netbsd.org: - 3ffe:0501:1234:ffff::140.160.140.252 www.netbsd.org + 3ffe:0501:ffff:0000::140.160.140.252 www.netbsd.org <<On the translating router on which faithd runs.>> @@ -107,18 +110,31 @@ in "/var/log/daemon". daemon.* /var/log/daemon +Access control +============== + +Since faithd implements TCP relaying service, it is critical to implement +proper access control to cope with malicious use. Bad guy may try to +use your relay router to circumvent access controls, or may try to +abuse your network (like sending SPAMs from IPv4 address that belong to you). +Install IPv6 packet filter directives that would reject traffic from +unwanted source. If you are using inetd-based setup, you may be able to +use access control mechanisms in inetd. + + Advanced configuration ====================== If you would like to restrict IPv4 destination for translation, you may want to do the following: - # route add -inet6 3ffe:0501:1234:ffff::123.0.0.0 -prefixlen 104 \ - -interface faith0 + # route add -inet6 3ffe:0501:ffff:0000::123.0.0.0 -prefixlen 104 ::1 + # route change -inet6 3ffe:0501:ffff:0000::123.0.0.0 -prefixlen 104 \ + -ifp faith0 By this way, you can restrict IPv4 destination to 123.0.0.0/8. -You may also want to reject packets toward 3ffe:0501:1234:ffff::/64 which -is not in 3ffe:0501:1234:ffff::123.0.0.0/104. This will be left as excerside +You may also want to reject packets toward 3ffe:0501:ffff:0000::/64 which +is not in 3ffe:0501:ffff:0000::123.0.0.0/104. This will be left as excerside for the reader. By doing this, you will be able to provide your IPv4 web server to outside diff --git a/usr.sbin/faithd/faithd.8 b/usr.sbin/faithd/faithd.8 index 6d552eb..ff0fa65 100644 --- a/usr.sbin/faithd/faithd.8 +++ b/usr.sbin/faithd/faithd.8 @@ -1,4 +1,4 @@ -.\" $KAME: faithd.8,v 1.12 2000/07/04 13:15:01 itojun Exp $ +.\" $KAME: faithd.8,v 1.30 2001/05/24 20:47:56 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -38,7 +38,9 @@ .Sh SYNOPSIS .Nm .Op Fl dp -.Op Ar service Op Ar serverpath Op Ar serverargs +.Op Fl f Ar configfile +.Ar service +.Op Ar serverpath Op Ar serverargs .Sh DESCRIPTION .Nm provides IPv6-to-IPv4 TCP relay. @@ -96,6 +98,24 @@ address prefix, by using and .Xr sysctl 8 commands. +.Pp +.Nm +needs a special name-to-address translation logic, so that +hostnames gets resolved into special +.Tn IPv6 +address prefix. +For small-scale installation, use +.Xr hosts 5 . +For large-scale installation, it is useful to have +a DNS server with special address translation support. +An implementation called +.Nm totd +is available +at +.Pa http://www.vermicelli.pasta.cs.uit.no/ipv6/software.html . +Make sure you do not propagate translated DNS records to normal DNS cloud, +it is highly harmful. +.Pp .Ss Daemon mode When .Nm @@ -136,26 +156,14 @@ You can also specify .Ar serverargs for the arguments for the local daemon. .Pp -If -.Ar service -is not given, -.Li telnet -is assumed, and -.Nm -will relay TCP traffic on TCP port -.Li telnet . -With -.Ar service , -.Nm -will work as TCP relaying daemon for specified -.Ar service -as described above. -.Pp The following options are available: .Bl -tag -width indent .It Fl d Debugging information will be generated using .Xr syslog 3 . +.It Fl f Ar configfile +Specify a configuration file for access control. +See below. .It Fl p Use privileged TCP port number as source port, for IPv4 TCP connection toward final destination. @@ -200,7 +208,7 @@ is invoked via .Xr inetd 8 , .Nm will handle connection passed from standard input. -If it the connection endpoint is in the reserved IPv6 address prefix. +If the connection endpoint is in the reserved IPv6 address prefix, .Nm will relay the connection. Otherwise, @@ -223,6 +231,52 @@ The operation mode requires special support for .Nm in .Xr inetd 8 . +.Ss Access control +To prevent malicious accesses, +.Nm +implements a simple address-based access control. +With +.Pa /etc/faithd.conf +.Po +or +.Ar configfile +specified by +.Fl f +.Pc , +.Nm +will avoid relaying unwanted traffic. +The +.Pa faithd.conf +contains directives with the following format: +.Bl -bullet +.It +.Xo +.Ic Ar src/slen Li deny Ar dst/dlen +.Xc +.Pp +If the source address of a query matches +.Ar src/slen , +and the translated destination address matches +.Ar dst/dlen , +deny the connection. +.It +.Xo +.Ic Ar src/slen Li permit Ar dst/dlen +.Xc +.Pp +If the source address of a query matches +.Ar src/slen , +and the translated destination address matches +.Ar dst/dlen , +permit the connection. +.El +.Pp +The directives are evaluated in sequence, +and the first matching entry will be effective. +.Pp +With inetd mode, +traffic may be filtered by using access control functionality in +.Xr inetd 8 . .Sh EXAMPLES Before invoking .Nm , @@ -241,9 +295,8 @@ To translate .Li telnet service, and provide no local telnet service, invoke .Nm -as either of the following: +as follows: .Bd -literal -offset -# faithd # faithd telnet .Ed .Pp @@ -258,7 +311,7 @@ use the following command line: .Pp If you would like to pass extra arguments to the local daemon: .Bd -literal -offset -# faithd ftpd /usr/local/v6/libexec/ftpd ftpd -l +# faithd ftp /usr/local/v6/libexec/ftpd ftpd -l .Ed .Pp Here are some other examples. @@ -266,14 +319,15 @@ You may need .Fl p to translate rsh/rlogin services. .Bd -literal -offset -# faithd sshd +# faithd ssh # faithd login /usr/local/v6/libexec/rlogin rlogind # faithd shell /usr/local/v6/libexec/rshd rshd .Ed .Pp However, you should be careful when translating rlogin or rsh -connections. See -.Sx SECURITY NOTICE +connections. +See +.Sx SECURITY CONSIDERATIONS for more details. .Ss inetd mode samples Add the following lines into @@ -282,7 +336,7 @@ Syntax may vary depending upon your operating system. .Bd -literal -offset telnet stream tcp6/faith nowait root /usr/sbin/faithd telnetd ftp stream tcp6/faith nowait root /usr/sbin/faithd ftpd -l -ssh stream tcp6/faith nowait root /usr/sbin/faithd /usr/pkg/bin/sshd -i +ssh stream tcp6/faith nowait root /usr/sbin/faithd /usr/sbin/sshd -i .Ed .Pp .Xr inetd 8 @@ -298,6 +352,20 @@ Otherwise, .Nm will invoke service-specific daemon like .Xr telnetd 8 . +.Ss Access control samples +The following illustrates a simple +.Pa faithd.conf +setting. +.Bd -literal -offset +# permit anyone from 3ffe:501:ffff::/48 to use the translator, +# to connect to the following IPv4 destinations: +# - any location except 10.0.0.0/8 and 127.0.0.0/8. +# Permit no other connections. +# +3ffe:501:ffff::/48 deny 10.0.0.0/8 +3ffe:501:ffff::/48 deny 127.0.0.0/8 +3ffe:501:ffff::/48 permit 0.0.0.0/0 +.Ed .Sh RETURN VALUES .Nm exits with @@ -316,20 +384,34 @@ on error. .%A Kazu Yamamoto .%T "An IPv6-to-IPv4 transport relay translator" .%R internet draft -.%N draft-ietf-ngtrans-tcpudp-relay-01.txt +.%N draft-ietf-ngtrans-tcpudp-relay-04.txt .%O work in progress material .Re -.Sh SECURITY NOTICE +.\" +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" +.Pp +IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack +was initially integrated into +.Fx 4.0 +.Sh SECURITY CONSIDERATIONS It is very insecure to use .Xr rhosts 5 and other IP-address based authentication, for connections relayed by .Nm .Pq and any other TCP relaying services . .Pp +Administrators are advised to limit accesses to .Nm -itself does not implement access controls, as -it intends to implement transparent TCP relay services. -Administrators are advised to filter packets based on IPv6 address. +using +.Pa faithd.conf , +or by using IPv6 packet filters. +It is to protect +.Nm +service from malicious parties and avoid theft of service/bandwidth. IPv6 destination address can be limited by carefully configuring routing entries that points to .Xr faith 4 , @@ -339,12 +421,3 @@ IPv6 source address needs to be filtered by using packet filters. Documents listed in .Sx SEE ALSO have more discussions on this topic. -.\" -.Sh HISTORY -The -.Nm -command first appeared in WIDE Hydrangea IPv6 protocol stack kit. -.Pp -IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack -was initially integrated into -.Fx 4.0 diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c index fddf402..2f02da1 100644 --- a/usr.sbin/faithd/faithd.c +++ b/usr.sbin/faithd/faithd.c @@ -1,4 +1,4 @@ -/* $KAME: faithd.c,v 1.20 2000/07/01 11:40:45 itojun Exp $ */ +/* $KAME: faithd.c,v 1.39 2001/04/25 11:20:42 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -47,6 +47,9 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/ioctl.h> +#ifdef __FreeBSD__ +#include <libutil.h> +#endif #include <stdio.h> #include <stdlib.h> @@ -83,6 +86,7 @@ #endif #include "faithd.h" +#include "prefix.h" char *serverpath = NULL; char *serverarg[MAXARGV + 1]; @@ -101,6 +105,7 @@ static int sockfd = 0; int dflag = 0; static int pflag = 0; static int inetd = 0; +static char *configfile = NULL; int main __P((int, char **)); static int inetd_main __P((int, char **)); @@ -115,6 +120,8 @@ static int map4to6 __P((struct sockaddr_in *, struct sockaddr_in6 *)); static void sig_child __P((int)); static void sig_terminate __P((int)); static void start_daemon __P((void)); +static void exit_stderr __P((const char *, ...)) + __attribute__((__format__(__printf__, 1, 2))); #ifndef HAVE_GETIFADDRS static unsigned int if_maxindex __P((void)); #endif @@ -156,6 +163,11 @@ inetd_main(int argc, char **argv) const int on = 1; char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; + if (config_load(configfile) < 0 && configfile) { + exit_failure("could not load config file"); + /*NOTREACHED*/ + } + if (strrchr(argv[0], '/') == NULL) snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); else @@ -166,17 +178,21 @@ inetd_main(int argc, char **argv) sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); if (sockfd < 0) { - exit_error("socket(PF_ROUTE): %s", ERRSTR); + exit_failure("socket(PF_ROUTE): %s", ERRSTR); /*NOTREACHED*/ } #endif melen = sizeof(me); - if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) - exit_error("getsockname"); + if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) { + exit_failure("getsockname: %s", ERRSTR); + /*NOTREACHED*/ + } fromlen = sizeof(from); - if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) - exit_error("getpeername"); + if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { + exit_failure("getpeername: %s", ERRSTR); + /*NOTREACHED*/ + } if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) service = sbuf; @@ -190,8 +206,10 @@ inetd_main(int argc, char **argv) snprintf(procname, sizeof(procname), "accepting port %s", snum); openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - if (argc >= MAXARGV) + if (argc >= MAXARGV) { exit_failure("too many arguments"); + /*NOTREACHED*/ + } serverarg[0] = serverpath = path; for (i = 1; i < argc; i++) serverarg[i] = argv[i]; @@ -199,8 +217,10 @@ inetd_main(int argc, char **argv) error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error < 0) - exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); + /*NOTREACHED*/ + } play_child(STDIN_FILENO, (struct sockaddr *)&from); exit_failure("should not reach here"); @@ -218,11 +238,14 @@ daemon_main(int argc, char **argv) char *ns; #endif /* FAITH_NS */ - while ((c = getopt(argc, argv, "dp46")) != -1) { + while ((c = getopt(argc, argv, "df:p46")) != -1) { switch (c) { case 'd': dflag++; break; + case 'f': + configfile = optarg; + break; case 'p': pflag++; break; @@ -236,12 +259,17 @@ daemon_main(int argc, char **argv) #endif default: usage(); - break; + /*NOTREACHED*/ } } argc -= optind; argv += optind; + if (config_load(configfile) < 0 && configfile) { + exit_failure("could not load config file"); + /*NOTREACHED*/ + } + #ifdef FAITH_NS if ((ns = getenv(FAITH_NS)) != NULL) { struct sockaddr_storage ss; @@ -266,15 +294,12 @@ daemon_main(int argc, char **argv) switch (argc) { case 0: - serverpath = DEFAULT_PATH; - serverarg[0] = DEFAULT_NAME; - serverarg[1] = NULL; - service = DEFAULT_PORT_NAME; - break; + usage(); + /*NOTREACHED*/ default: serverargc = argc - NUMARG; if (serverargc >= MAXARGV) - exit_error("too many augments"); + exit_stderr("too many arguments"); serverpath = malloc(strlen(argv[NUMPRG]) + 1); strcpy(serverpath, argv[NUMPRG]); @@ -300,17 +325,17 @@ daemon_main(int argc, char **argv) hints.ai_protocol = 0; error = getaddrinfo(NULL, service, &hints, &res); if (error) - exit_error("getaddrinfo: %s", gai_strerror(error)); + exit_stderr("getaddrinfo: %s", gai_strerror(error)); s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s_wld == -1) - exit_error("socket: %s", ERRSTR); + exit_stderr("socket: %s", ERRSTR); #ifdef IPV6_FAITH if (res->ai_family == AF_INET6) { error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(IPV6_FAITH): %s", ERRSTR); + exit_stderr("setsockopt(IPV6_FAITH): %s", ERRSTR); } #endif #ifdef FAITH4 @@ -318,31 +343,31 @@ daemon_main(int argc, char **argv) if (res->ai_family == AF_INET) { error = setsockopt(s_wld, IPPROTO_IP, IP_FAITH, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(IP_FAITH): %s", ERRSTR); + exit_stderr("setsockopt(IP_FAITH): %s", ERRSTR); } #endif #endif /* FAITH4 */ error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(SO_REUSEADDR): %s", ERRSTR); + exit_stderr("setsockopt(SO_REUSEADDR): %s", ERRSTR); error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + exit_stderr("setsockopt(SO_OOBINLINE): %s", ERRSTR); error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); if (error == -1) - exit_error("bind: %s", ERRSTR); + exit_stderr("bind: %s", ERRSTR); error = listen(s_wld, 5); if (error == -1) - exit_error("listen: %s", ERRSTR); + exit_stderr("listen: %s", ERRSTR); #ifdef USE_ROUTE sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); if (sockfd < 0) { - exit_error("socket(PF_ROUTE): %s", ERRSTR); + exit_stderr("socket(PF_ROUTE): %s", ERRSTR); /*NOTREACHED*/ } #endif @@ -359,7 +384,7 @@ daemon_main(int argc, char **argv) syslog(LOG_INFO, "Staring faith daemon for %s port", service); play_service(s_wld); - /*NOTREACHED*/ + /* NOTREACHED */ exit(1); /*pacify gcc*/ } @@ -407,8 +432,10 @@ again: len = sizeof(srcaddr); s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); - if (s_src == -1) + if (s_src == -1) { exit_failure("socket: %s", ERRSTR); + /*NOTREACHED*/ + } child_pid = fork(); @@ -419,6 +446,7 @@ again: openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); play_child(s_src, (struct sockaddr *)&srcaddr); exit_failure("should never reach here"); + /*NOTREACHED*/ } else { /* parent process */ close(s_src); @@ -441,6 +469,7 @@ play_child(int s_src, struct sockaddr *srcaddr) int s_dst, error, hport, nresvport, on = 1; struct timeval tv; struct sockaddr *sa4; + const struct config *conf; tv.tv_sec = 1; tv.tv_usec = 0; @@ -450,8 +479,10 @@ play_child(int s_src, struct sockaddr *srcaddr) syslog(LOG_INFO, "accepted a client from %s", src); error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); - if (error == -1) + if (error == -1) { exit_failure("getsockname: %s", ERRSTR); + /*NOTREACHED*/ + } getnameinfo((struct sockaddr *)&dstaddr6, len, dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); @@ -487,7 +518,8 @@ play_child(int s_src, struct sockaddr *srcaddr) if (!map6to4((struct sockaddr_in6 *)&dstaddr6, (struct sockaddr_in *)&dstaddr4)) { close(s_src); - exit_error("map6to4 failed"); + exit_failure("map6to4 failed"); + /*NOTREACHED*/ } syslog(LOG_INFO, "translating from v6 to v4"); break; @@ -496,20 +528,35 @@ play_child(int s_src, struct sockaddr *srcaddr) if (!map4to6((struct sockaddr_in *)&dstaddr6, (struct sockaddr_in6 *)&dstaddr4)) { close(s_src); - exit_error("map4to6 failed"); + exit_failure("map4to6 failed"); + /*NOTREACHED*/ } syslog(LOG_INFO, "translating from v4 to v6"); break; #endif default: close(s_src); - exit_error("family not supported"); + exit_failure("family not supported"); /*NOTREACHED*/ } sa4 = (struct sockaddr *)&dstaddr4; getnameinfo(sa4, sa4->sa_len, dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); + + conf = config_match(srcaddr, sa4); + if (!conf || !conf->permit) { + close(s_src); + if (conf) { + exit_failure("translation to %s not permitted for %s", + dst4, prefix_string(&conf->match)); + /*NOTREACHED*/ + } else { + exit_failure("translation to %s not permitted", dst4); + /*NOTREACHED*/ + } + } + syslog(LOG_INFO, "the translator is connecting to %s", dst4); setproctitle("port %s, %s -> %s", service, src, dst4); @@ -531,31 +578,55 @@ play_child(int s_src, struct sockaddr *srcaddr) s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); break; } - if (s_dst == -1) + if (s_dst < 0) { exit_failure("socket: %s", ERRSTR); + /*NOTREACHED*/ + } + + if (conf->src.a.ss_family) { + if (bind(s_dst, (struct sockaddr *)&conf->src.a, + conf->src.a.ss_len) < 0) { + exit_failure("bind: %s", ERRSTR); + /*NOTREACHED*/ + } + } error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error == -1) - exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); + /*NOTREACHED*/ + } error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error == -1) - exit_error("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + /*NOTREACHED*/ + } error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error == -1) - exit_error("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + /*NOTREACHED*/ + } error = connect(s_dst, sa4, sa4->sa_len); - if (error == -1) + if (error < 0) { exit_failure("connect: %s", ERRSTR); + /*NOTREACHED*/ + } switch (hport) { case FTP_PORT: ftp_relay(s_src, s_dst); break; case RSH_PORT: + syslog(LOG_WARNING, + "WARINNG: it is insecure to relay rsh port"); rsh_relay(s_src, s_dst); break; + case RLOGIN_PORT: + syslog(LOG_WARNING, + "WARINNG: it is insecure to relay rlogin port"); + /*FALLTHROUGH*/ default: tcp_relay(s_src, s_dst, service); break; @@ -581,8 +652,10 @@ faith_prefix(struct sockaddr *dst) mib[2] = IPPROTO_IPV6; mib[3] = IPV6CTL_FAITH_PREFIX; size = sizeof(struct in6_addr); - if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) - exit_error("sysctl: %s", ERRSTR); + if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { + exit_failure("sysctl: %s", ERRSTR); + /*NOTREACHED*/ + } if (memcmp(dst, &faith_prefix, sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { @@ -649,7 +722,7 @@ map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) if (dst4->sin_addr.s_addr == INADDR_ANY || dst4->sin_addr.s_addr == INADDR_BROADCAST - || IN_MULTICAST(dst4->sin_addr.s_addr)) + || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) return 0; return 1; @@ -695,7 +768,7 @@ sig_child(int sig) pid_t pid; pid = wait3(&status, WNOHANG, (struct rusage *)0); - if (pid && status) + if (pid && WEXITSTATUS(status)) syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status); } @@ -709,18 +782,34 @@ sig_terminate(int sig) static void start_daemon(void) { - if (daemon(0, 0) == -1) - exit_error("daemon: %s", ERRSTR); +#ifdef SA_NOCLDWAIT + struct sigaction sa; +#endif - if (signal(SIGCHLD, sig_child) == SIG_ERR) + if (daemon(0, 0) == -1) + exit_stderr("daemon: %s", ERRSTR); + +#ifdef SA_NOCLDWAIT + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sig_child; + sa.sa_flags = SA_NOCLDWAIT; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, (struct sigaction *)0); +#else + if (signal(SIGCHLD, sig_child) == SIG_ERR) { exit_failure("signal CHLD: %s", ERRSTR); + /*NOTREACHED*/ + } +#endif - if (signal(SIGTERM, sig_terminate) == SIG_ERR) + if (signal(SIGTERM, sig_terminate) == SIG_ERR) { exit_failure("signal TERM: %s", ERRSTR); + /*NOTREACHED*/ + } } -void -exit_error(const char *fmt, ...) +static void +exit_stderr(const char *fmt, ...) { va_list ap; char buf[BUFSIZ]; @@ -977,7 +1066,7 @@ update_myaddrs() static void usage() { - fprintf(stderr, "usage: %s [-dp] [service [serverpath [serverargs]]]\n", + fprintf(stderr, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n", faithdname); exit(0); } diff --git a/usr.sbin/faithd/faithd.h b/usr.sbin/faithd/faithd.h index b882aad..8a5021b 100644 --- a/usr.sbin/faithd/faithd.h +++ b/usr.sbin/faithd/faithd.h @@ -1,4 +1,4 @@ -/* $KAME: faithd.h,v 1.2 2000/05/31 03:06:07 itojun Exp $ */ +/* $KAME: faithd.h,v 1.6 2000/10/05 22:20:37 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -40,12 +40,13 @@ extern int ftp_active __P((int, int, int *, int *)); extern int ftp_passive __P((int, int, int *, int *)); extern void rsh_relay __P((int, int)); extern void rsh_dual_relay __P((int, int)); -extern void exit_error __P((const char *fmt, ...)); -extern void exit_success __P((const char *fmt, ...)); -extern void exit_failure __P((const char *fmt, ...)); +extern void exit_success __P((const char *, ...)) + __attribute__((__format__(__printf__, 1, 2))); +extern void exit_failure __P((const char *, ...)) + __attribute__((__format__(__printf__, 1, 2))); #define DEFAULT_PORT_NAME "telnet" -#define DEFAULT_DIR "/usr/local/v6/libexec" +#define DEFAULT_DIR "/usr/libexec" #define DEFAULT_NAME "telnetd" #define DEFAULT_PATH (DEFAULT_DIR "/" DEFAULT_NAME) diff --git a/usr.sbin/faithd/ftp.c b/usr.sbin/faithd/ftp.c index e4838eb..b0daa5a 100644 --- a/usr.sbin/faithd/ftp.c +++ b/usr.sbin/faithd/ftp.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: ftp.c,v 1.10 2000/09/14 00:23:39 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -514,7 +514,7 @@ passivefail: error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(IPV6_FAITH): %s", ERRSTR); + exit_failure("setsockopt(IPV6_FAITH): %s", ERRSTR); } #endif error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len); @@ -924,6 +924,7 @@ eprtparamfail: } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(hostp, portp, &hints, &res); if (error) { n = snprintf(sbuf, sizeof(sbuf), diff --git a/usr.sbin/faithd/prefix.c b/usr.sbin/faithd/prefix.c new file mode 100644 index 0000000..739ae56 --- /dev/null +++ b/usr.sbin/faithd/prefix.c @@ -0,0 +1,360 @@ +/* $KAME: prefix.c,v 1.8 2000/11/24 06:16:56 itojun Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stddef.h> +#include <stdlib.h> +#include <limits.h> + +#ifndef offsetof +#define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member)) +#endif + +#include "faithd.h" +#include "prefix.h" + +static int prefix_set __P((const char *, struct prefix *, int)); +static struct config *config_load1 __P((const char *)); +#if 0 +static void config_show1 __P((const struct config *)); +static void config_show __P((void)); +#endif + +struct config *config_list = NULL; +#ifdef NI_WITHSCOPEID +const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else +const int niflags = NI_NUMERICHOST; +#endif + +static int +prefix_set(s, prefix, slash) + const char *s; + struct prefix *prefix; + int slash; +{ + char *p, *q, *r; + struct addrinfo hints, *res = NULL; + int max; + char *a; + + p = strdup(s); + q = strchr(p, '/'); + if (q) { + if (!slash) + goto fail; + *q++ = '\0'; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(p, "0", &hints, &res)) + goto fail; + if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) + goto fail; + memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); + + switch (prefix->a.ss_family) { + case AF_INET: + max = 32; + a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr; + break; + case AF_INET6: + max = 128; + a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr; + break; + default: + a = NULL; + max = -1; + break; + } + + if (q) { + r = NULL; + prefix->l = (int)strtoul(q, &r, 10); + if (!*q || *r) + goto fail; + if (prefix->l < 0 || prefix->l > max) + goto fail; + } else + prefix->l = max; + + if (p) + free(p); + if (res) + freeaddrinfo(res); + return 0; + +fail: + if (p) + free(p); + if (res) + freeaddrinfo(res); + return -1; +} + +const char * +prefix_string(prefix) + const struct prefix *prefix; +{ + static char buf[NI_MAXHOST + 20]; + char hbuf[NI_MAXHOST]; + + if (getnameinfo((struct sockaddr *)&prefix->a, prefix->a.ss_len, hbuf, + sizeof(hbuf), NULL, 0, niflags)) + return NULL; + snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); + return buf; +} + +int +prefix_match(prefix, sa) + const struct prefix *prefix; + const struct sockaddr *sa; +{ + struct sockaddr_storage a, b; + char *pa, *pb; + int off, l; + + if (prefix->a.ss_family != sa->sa_family || + prefix->a.ss_len != sa->sa_len) + return 0; + + if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) + return 0; + + switch (prefix->a.ss_family) { + case AF_INET: + off = offsetof(struct sockaddr_in, sin_addr); + break; + case AF_INET6: + off = offsetof(struct sockaddr_in6, sin6_addr); + break; + default: + if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) + return 0; + else + return 1; + } + + memcpy(&a, &prefix->a, prefix->a.ss_len); + memcpy(&b, sa, sa->sa_len); + l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); + + /* overrun check */ + if (off + l > a.ss_len) + return 0; + + pa = ((char *)&a) + off; + pb = ((char *)&b) + off; + if (prefix->l % 8) { + pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); + pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); + } + if (memcmp(pa, pb, l) != 0) + return 0; + else + return 1; +} + +/* + * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] + * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 + */ +static struct config * +config_load1(line) + const char *line; +{ + struct config *conf; + char buf[BUFSIZ]; + char *p; + char *token[4]; + int i; + + if (strlen(line) + 1 > sizeof(buf)) + return NULL; + strlcpy(buf, line, sizeof(buf)); + + p = strchr(buf, '\n'); + if (!p) + return NULL; + *p = '\0'; + p = strchr(buf, '#'); + if (p) + *p = '\0'; + if (strlen(buf) == 0) + return NULL; + + p = buf; + memset(token, 0, sizeof(token)); + for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { + token[i] = strtok(p, "\t "); + p = NULL; + if (token[i] == NULL) + break; + } + /* extra tokens? */ + if (strtok(p, "\t ") != NULL) + return NULL; + /* insufficient tokens */ + switch (i) { + case 3: + case 4: + break; + default: + return NULL; + } + + conf = (struct config *)malloc(sizeof(*conf)); + if (conf == NULL) + return NULL; + memset(conf, 0, sizeof(*conf)); + + if (strcasecmp(token[1], "permit") == 0) + conf->permit = 1; + else if (strcasecmp(token[1], "deny") == 0) + conf->permit = 0; + else { + /* invalid keyword is considered as "deny" */ + conf->permit = 0; + } + + if (prefix_set(token[0], &conf->match, 1) < 0) + goto fail; + if (prefix_set(token[2], &conf->dest, 1) < 0) + goto fail; + if (token[3]) { + if (prefix_set(token[3], &conf->src, 0) < 0) + goto fail; + } + + return conf; + +fail: + free(conf); + return NULL; +} + +int +config_load(configfile) + const char *configfile; +{ + FILE *fp; + char buf[BUFSIZ]; + struct config *conf, *p; + struct config sentinel; + + config_list = NULL; + + if (!configfile) + configfile = _PATH_PREFIX_CONF; + fp = fopen(configfile, "r"); + if (fp == NULL) + return -1; + + p = &sentinel; + while (fgets(buf, sizeof(buf), fp) != NULL) { + conf = config_load1(buf); + if (conf) { + p->next = conf; + p = p->next; + } + } + config_list = sentinel.next; + + fclose(fp); + return 0; +} + +#if 0 +static void +config_show1(conf) + const struct config *conf; +{ + const char *p; + + p = prefix_string(&conf->match); + printf("%s", p ? p : "?"); + + if (conf->permit) + printf(" permit"); + else + printf(" deny"); + + p = prefix_string(&conf->dest); + printf(" %s", p ? p : "?"); + + printf("\n"); +} + +static void +config_show() +{ + struct config *conf; + + for (conf = config_list; conf; conf = conf->next) + config_show1(conf); +} +#endif + +const struct config * +config_match(sa1, sa2) + struct sockaddr *sa1, *sa2; +{ + static struct config conf; + const struct config *p; + + if (sa1->sa_len > sizeof(conf.match.a) || + sa2->sa_len > sizeof(conf.dest.a)) + return NULL; + + memset(&conf, 0, sizeof(conf)); + if (!config_list) { + conf.permit = 1; + memcpy(&conf.match.a, sa1, sa1->sa_len); + memcpy(&conf.dest.a, sa2, sa2->sa_len); + return &conf; + } + + for (p = config_list; p; p = p->next) + if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) + return p; + + return NULL; +} diff --git a/usr.sbin/faithd/prefix.h b/usr.sbin/faithd/prefix.h new file mode 100644 index 0000000..3ef56e3 --- /dev/null +++ b/usr.sbin/faithd/prefix.h @@ -0,0 +1,52 @@ +/* $KAME: prefix.h,v 1.3 2000/11/19 11:45:38 itojun Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct prefix { + struct sockaddr_storage a; + int l; +}; + +struct config { + struct config *next; + + int permit; + struct prefix match; + struct prefix dest; + struct prefix src; /* src to use for outgoing connection */ +}; + +#define _PATH_PREFIX_CONF "/etc/faithd.conf" + +extern const char *prefix_string __P((const struct prefix *)); +extern int prefix_match __P((const struct prefix *, const struct sockaddr *)); +extern int config_load __P((const char *)); +extern const struct config *config_match __P((struct sockaddr *, struct sockaddr *)); diff --git a/usr.sbin/faithd/rsh.c b/usr.sbin/faithd/rsh.c index 6d81147..4e11d76 100644 --- a/usr.sbin/faithd/rsh.c +++ b/usr.sbin/faithd/rsh.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: rsh.c,v 1.5 2001/02/15 17:28:04 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. diff --git a/usr.sbin/faithd/tcp.c b/usr.sbin/faithd/tcp.c index 004686f..c754dfc 100644 --- a/usr.sbin/faithd/tcp.c +++ b/usr.sbin/faithd/tcp.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: tcp.c,v 1.5 2000/09/29 03:48:31 sakane Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -93,9 +93,9 @@ sig_child(int sig) pid_t pid; pid = wait3(&status, WNOHANG, (struct rusage *)0); - if (pid && status) + if (pid && WEXITSTATUS(status)) syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status); - exit_failure("terminate connection due to child termination"); + exit_success("terminate connection due to child termination"); } static void @@ -195,7 +195,8 @@ relay(int s_rcv, int s_snd, const char *service, int direction) FD_ZERO(&exceptfds); fcntl(s_snd, F_SETFD, O_NONBLOCK); oreadfds = readfds; owritefds = writefds; oexceptfds = exceptfds; - FD_SET(s_rcv, &readfds); FD_SET(s_rcv, &exceptfds); + FD_SET(s_rcv, &readfds); + FD_SET(s_rcv, &exceptfds); oob_exists = 0; maxfd = (s_rcv > s_snd) ? s_rcv : s_snd; diff --git a/usr.sbin/gifconfig/gifconfig.8 b/usr.sbin/gifconfig/gifconfig.8 index c851624..26b4dd6 100644 --- a/usr.sbin/gifconfig/gifconfig.8 +++ b/usr.sbin/gifconfig/gifconfig.8 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: gifconfig.8,v 1.5 2000/05/13 07:48:10 itojun Exp $ +.\" $KAME: gifconfig.8,v 1.6 2000/11/22 11:10:09 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -34,6 +34,7 @@ .Sh NAME .Nm gifconfig .Nd configure generic IP tunnel +.\" .Sh SYNOPSIS .Nm .Ar interface @@ -60,7 +61,7 @@ specifies the address family for .Ar physsrc and .Ar physdest . -.Ar Af +.Ar af can be .Li inet or @@ -81,7 +82,9 @@ If no outer addresses are specified, this usage has no effect. takes the following optional argument: .Bl -tag -width Ds .It Fl a -Display information associated all generic IP tunnel interfaces. +Display information associated with all +.Xr gif 4 +interfaces. .El .Pp Please note that it is very easy to create infinite routing loop, diff --git a/usr.sbin/gifconfig/gifconfig.c b/usr.sbin/gifconfig/gifconfig.c index d93d741..ac876dc 100644 --- a/usr.sbin/gifconfig/gifconfig.c +++ b/usr.sbin/gifconfig/gifconfig.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: gifconfig.c,v 1.12 2000/05/22 05:50:43 itojun Exp $ */ +/* $KAME: gifconfig.c,v 1.14 2001/01/01 04:04:56 jinmei Exp $ */ /* * Copyright (c) 1983, 1993 @@ -111,7 +111,7 @@ void delifaddrs __P((char *, int)); #define NEXTARG 0xffffff -struct cmd { +static struct cmd { char *c_name; int c_parameter; /* NEXTARG means next argv */ void (*c_func) __P((char *, int)); @@ -565,10 +565,11 @@ phys_status(force) char psrcaddr[256]; char pdstaddr[256]; char hostname[NI_MAXHOST]; - u_long srccmd, dstcmd; int flags = NI_NUMERICHOST; + char *af; +#ifndef SIOCGLIFPHYADDR + u_long srccmd, dstcmd; struct ifreq *ifrp; - char *ver = ""; #ifdef INET6 int s6; #endif @@ -596,20 +597,55 @@ phys_status(force) #endif /* INET6 */ if (0 <= ioctl(s, srccmd, (caddr_t)ifrp)) { - getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, - hostname, sizeof(hostname), 0, 0, flags); #ifdef INET6 if (ifrp->ifr_addr.sa_family == AF_INET6) - ver = "6"; + af = "inet6"; + else + af = "inet"; +#else + af = "inet"; #endif /* INET6 */ - sprintf(psrcaddr, "inet%s %s", ver, hostname); + if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0) + psrcaddr[0] = '\0'; } if (0 <= ioctl(s, dstcmd, (caddr_t)ifrp)) { - getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, - hostname, sizeof(hostname), 0, 0, flags); - sprintf(pdstaddr, "%s", hostname); + if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + pdstaddr, sizeof(pdstaddr), 0, 0, flags) != 0) + pdstaddr[0] = '\0'; + } + printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr); +#else + struct if_laddrreq iflr; + + force = 0; /*fool gcc*/ + + psrcaddr[0] = pdstaddr[0] = '\0'; + + memset(&iflr, 0, sizeof(iflr)); + memcpy(iflr.iflr_name, ifr.ifr_name, sizeof(iflr.iflr_name)); + + if (0 <= ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&iflr)) { + switch (iflr.addr.ss_family) { + case AF_INET: + af = "inet"; + break; +#ifdef INET6 + case AF_INET6: + af = "inet6"; + break; +#endif /* INET6 */ + } + if (getnameinfo((struct sockaddr *)&iflr.addr, iflr.addr.ss_len, + psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0) + psrcaddr[0] = '\0'; + if (getnameinfo((struct sockaddr *)&iflr.dstaddr, + iflr.dstaddr.ss_len, pdstaddr, sizeof(pdstaddr), 0, 0, + flags) != 0) + pdstaddr[0] = '\0'; } - printf("\tphysical address %s --> %s\n", psrcaddr, pdstaddr); + printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr); +#endif } void diff --git a/usr.sbin/ifmcstat/ifmcstat.8 b/usr.sbin/ifmcstat/ifmcstat.8 index 816da4b..bcb5bdd 100644 --- a/usr.sbin/ifmcstat/ifmcstat.8 +++ b/usr.sbin/ifmcstat/ifmcstat.8 @@ -1,16 +1,31 @@ -.\" Copyright (c) 1996 WIDE Project. All rights reserved. +.\" $KAME: ifmcstat.8,v 1.3 2000/10/15 11:43:57 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. +.\" 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$ .\" @@ -29,6 +44,3 @@ The command dumps multicast group information in the kernel. .Pp There are no command-line options. -.\" -.\" .Sh SEE ALSO -.\" RFC2080 -- IPng for IPv6. G. Malkin, R. Minnear. January 1997. diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c index e26db45..68cad62 100644 --- a/usr.sbin/ifmcstat/ifmcstat.c +++ b/usr.sbin/ifmcstat/ifmcstat.c @@ -39,6 +39,8 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/queue.h> + #include <net/if.h> #include <net/if_var.h> #include <net/if_types.h> @@ -234,6 +236,10 @@ if6_addrlist(ifap) KREAD(ifap0, &ifa, struct ifaddr); nam = strdup(ifname(ifa.ifa_ifp)); + if (!nam) { + fprintf(stderr, "ifmcstat: not enough core\n"); + exit(1); + } LIST_FOREACH(mkp, &in6_mk, mk_entry) { KREAD(mkp, &mk, struct multi6_kludge); diff --git a/usr.sbin/mld6query/mld6.c b/usr.sbin/mld6query/mld6.c index 473e0f4..9b0b30a 100644 --- a/usr.sbin/mld6query/mld6.c +++ b/usr.sbin/mld6query/mld6.c @@ -1,3 +1,6 @@ +/* $KAME: mld6.c,v 1.11 2001/05/13 15:45:07 suz Exp $ */ +/* $FreeBSD$ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. @@ -75,7 +78,7 @@ main(int argc, char *argv[]) int ch; type = MLD6_LISTENER_QUERY; - while ((ch = getopt(argc, argv, "d")) != EOF) { + while ((ch = getopt(argc, argv, "dr")) != -1) { switch (ch) { case 'd': type = MLD6_LISTENER_DONE; @@ -98,7 +101,7 @@ main(int argc, char *argv[]) ifindex = (u_short)if_nametoindex(argv[0]); if (ifindex == 0) usage(); - if (argc == 3 && inet_pton(AF_INET6, argv[1], &maddr) != 1) + if (argc == 2 && inet_pton(AF_INET6, argv[1], &maddr) != 1) usage(); if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) @@ -188,7 +191,7 @@ make_msg(int index, struct in6_addr *addr, u_int type) m.msg_control = (caddr_t)cmsgbuf; m.msg_controllen = cmsglen; /* specify the outgoing interface */ - cmsgp->cmsg_len = CMSG_SPACE(sizeof(struct in6_pktinfo)); + cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_PKTINFO; pi = (struct in6_pktinfo *)CMSG_DATA(cmsgp); diff --git a/usr.sbin/mld6query/mld6query.8 b/usr.sbin/mld6query/mld6query.8 index 470e18a..4b7bf9c 100644 --- a/usr.sbin/mld6query/mld6query.8 +++ b/usr.sbin/mld6query/mld6query.8 @@ -1,3 +1,5 @@ +.\" $KAME: mld6query.8,v 1.5 2000/12/04 06:28:23 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" @@ -25,7 +27,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: mld6query.8,v 1.3 1999/08/20 10:00:06 itojun Exp $ +.\" $FreeBSD$ .\" .Dd May 17, 1998 .Dt MLD6QUERY 8 diff --git a/usr.sbin/ndp/ndp.8 b/usr.sbin/ndp/ndp.8 index e2eae63..9ea9660 100644 --- a/usr.sbin/ndp/ndp.8 +++ b/usr.sbin/ndp/ndp.8 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: ndp.8,v 1.12 2000/06/20 21:50:17 itojun Exp $ +.\" $KAME: ndp.8,v 1.15 2001/02/08 07:17:03 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -30,7 +30,7 @@ .\" .Dd May 17, 1998 .Dt NDP 8 -.Os KAME +.Os .\" .Sh NAME .Nm ndp @@ -39,10 +39,10 @@ .Sh SYNOPSIS .Nm .Fl a -.Op Fl ntl +.Op Fl nt .Nm .Fl A Ar wait -.Op Fl ntl +.Op Fl nt .Nm .Fl c .Op Fl nt @@ -106,7 +106,8 @@ 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 Op Cm delete | Ar interface Shows or specifies the default interface used as the default route when -there is no default router. If no argument is given to the option, +there is no default router. +If no argument is given to the option, the current default interface will be shown. If an .Ar interface @@ -121,7 +122,8 @@ If additional arguments are given, .Nm sets or clears the specified flags for the interface. -Possible flags are as follows. All of the flags can begin with the +Possible flags are as follows. +All of the flags can begin with the special character .Ql - , which means the flag should be cleared. @@ -131,10 +133,9 @@ which means the flag should be cleared. .Ic nud .Xc turn on or off NUD (Neighbor Unreachability Detection) on the -interface. NUD is usually turned on by default. +interface. +NUD is usually turned on by default. .El -.It Fl l -Do not truncate numeric IPv6 address. .It Fl n Do not try to resolve numeric address to hostname. .It Fl p @@ -146,7 +147,7 @@ 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. +Register an NDP entry for a node. The entry will be permanent unless the word .Li temp is given in the command. diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index a01886a..d1e74a2 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ndp.c,v 1.46 2000/10/09 09:17:10 sumikawa Exp $ */ +/* $KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -84,6 +84,7 @@ #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/time.h> +#include <sys/queue.h> #include <net/if.h> #include <net/if_var.h> @@ -128,7 +129,6 @@ 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() */ @@ -162,6 +162,13 @@ static char *sec2str __P((time_t t)); static char *ether_str __P((struct sockaddr_dl *sdl)); static void ts_print __P((const struct timeval *)); +static char *rtpref_str[] = { + "medium", /* 00 */ + "high", /* 01 */ + "rsv", /* 10 */ + "low" /* 11 */ +}; + int main(argc, argv) int argc; @@ -173,7 +180,7 @@ main(argc, argv) pid = getpid(); thiszone = gmt2local(0); - while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != EOF) + while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1) switch ((char)ch) { case 'a': aflag = 1; @@ -213,7 +220,7 @@ main(argc, argv) file(argv[2]); exit(0); case 'l' : - lflag = 1; + /* obsolete, ignored */ break; case 'r' : rflag = 1; @@ -504,11 +511,7 @@ delete(host) 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; - } + goto delete; } /* * IPv4 arp command retries with sin_other = SIN_PROXY here. @@ -541,6 +544,10 @@ delete: return 0; } +#define W_ADDR 31 +#define W_LL 17 +#define W_IF 6 + /* * Dump the entire neighbor cache */ @@ -558,13 +565,16 @@ dump(addr) struct in6_nbrinfo *nbi; struct timeval time; int addrwidth; + int llwidth; + int ifwidth; char flgbuf[8]; + char *ifname; /* Print header */ if (!tflag && !cflag) - printf("%-31.31s %-17.17s %6.6s %-9.9s %2s %4s %4s\n", - "Neighbor", "Linklayer Address", "Netif", "Expire", - "St", "Flgs", "Prbs"); + printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n", + W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", + W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs"); again:; mib[0] = CTL_NET; @@ -590,6 +600,23 @@ again:; rtm = (struct rt_msghdr *)next; sin = (struct sockaddr_in6 *)(rtm + 1); sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); + + /* + * Some OSes can produce a route that has the LINK flag but + * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD + * and BSD/OS, where xx is not the interface identifier on + * lo0). Such routes entry would annoy getnbrinfo() below, + * so we skip them. + * XXX: such routes should have the GATEWAY flag, not the + * LINK flag. However, there are rotten routing software + * that advertises all routes that have the GATEWAY flag. + * Thus, KAME kernel intentionally does not set the LINK flag. + * What is to be fixed is not ndp, but such routing software + * (and the kernel workaround)... + */ + if (sdl->sdl_family != AF_LINK) + continue; + if (addr) { if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) continue; @@ -617,16 +644,21 @@ again:; if (tflag) ts_print(&time); - if (lflag) { - addrwidth = strlen(host_buf); - if (addrwidth < 31) - addrwidth = 31; - } else - addrwidth = 31; - - printf("%-*.*s %-17.17s %6.6s", addrwidth, addrwidth, host_buf, - ether_str(sdl), - if_indextoname(sdl->sdl_index, ifix_buf)); + addrwidth = strlen(host_buf); + if (addrwidth < W_ADDR) + addrwidth = W_ADDR; + llwidth = strlen(ether_str(sdl)); + if (W_ADDR + W_LL - addrwidth > llwidth) + llwidth = W_ADDR + W_LL - addrwidth; + ifname = if_indextoname(sdl->sdl_index, ifix_buf); + if (!ifname) + ifname = "?"; + ifwidth = strlen(ifname); + if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) + ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; + + printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf, + llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); /* Print neighbor discovery specific informations */ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); @@ -634,8 +666,7 @@ again:; if (nbi->expire > time.tv_sec) { printf(" %-9.9s", sec2str(nbi->expire - time.tv_sec)); - } - else if (nbi->expire == 0) + } else if (nbi->expire == 0) printf(" %-9.9s", "permanent"); else printf(" %-9.9s", "expired"); @@ -644,9 +675,11 @@ again:; case ND6_LLINFO_NOSTATE: printf(" N"); break; +#ifdef ND6_LLINFO_WAITDELETE case ND6_LLINFO_WAITDELETE: printf(" W"); break; +#endif case ND6_LLINFO_INCOMPLETE: printf(" I"); break; @@ -669,8 +702,7 @@ again:; isrouter = nbi->isrouter; prbs = nbi->asked; - } - else { + } else { warnx("failed to get neighbor information"); printf(" "); } @@ -701,6 +733,8 @@ again:; printf("\n"); } + if (buf != NULL) + free(buf); if (repeat) { printf("\n"); @@ -746,8 +780,7 @@ ether_str(sdl) 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 { + } else { sprintf(ebuf, "(incomplete)"); } @@ -776,8 +809,8 @@ void usage() { printf("usage: ndp hostname\n"); - printf(" ndp -a[ntl]\n"); - printf(" ndp [-ntl] -A wait\n"); + printf(" ndp -a[nt]\n"); + printf(" ndp [-nt] -A wait\n"); printf(" ndp -c[nt]\n"); printf(" ndp -d[nt] hostname\n"); printf(" ndp -f[nt] filename\n"); @@ -866,6 +899,9 @@ ifinfo(argc, argv) int i, s; char *ifname = argv[0]; u_int32_t newflags; +#ifdef IPV6CTL_USETEMPADDR + u_int8_t nullbuf[8]; +#endif if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("ndp: socket"); @@ -913,6 +949,32 @@ ifinfo(argc, argv) ND.basereachable / 1000, ND.basereachable % 1000); printf(", reachable=%ds", ND.reachable); printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); +#ifdef IPV6CTL_USETEMPADDR + memset(nullbuf, 0, sizeof(nullbuf)); + if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { + int j; + u_int8_t *rbuf; + + for (i = 0; i < 3; i++) { + switch(i) { + case 0: + printf("\nRandom seed(0): "); + rbuf = ND.randomseed0; + break; + case 1: + printf("\nRandom seed(1): "); + rbuf = ND.randomseed1; + break; + case 2: + printf("\nRandom ID: "); + rbuf = ND.randomid; + break; + } + for (j = 0; j < 8; j++) + printf("%02x", rbuf[j]); + } + } +#endif if (ND.flags) { printf("\nFlags: "); if ((ND.flags & ND6_IFF_PERFORMNUD) != 0) @@ -924,9 +986,60 @@ ifinfo(argc, argv) close(s); } +#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ +#endif + void rtrlist() { +#ifdef ICMPV6CTL_ND6_DRLIST + int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; + char *buf; + struct in6_defrouter *p, *ep; + size_t l; + struct timeval time; + + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); + /*NOTREACHED*/ + } + buf = malloc(l); + if (!buf) { + errx(1, "not enough core"); + /*NOTREACHED*/ + } + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); + /*NOTREACHED*/ + } + + ep = (struct in6_defrouter *)(buf + l); + for (p = (struct in6_defrouter *)buf; p < ep; p++) { + int rtpref; + + if (getnameinfo((struct sockaddr *)&p->rtaddr, + p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0) + strlcpy(host_buf, "?", sizeof(host_buf)); + + printf("%s if=%s", host_buf, + if_indextoname(p->if_index, ifix_buf)); + printf(", flags=%s%s", + p->flags & ND_RA_FLAG_MANAGED ? "M" : "", + p->flags & ND_RA_FLAG_OTHER ? "O" : ""); + rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; + printf(", pref=%s", rtpref_str[rtpref]); + + gettimeofday(&time, 0); + if (p->expire == 0) + printf(", expire=Never\n"); + else + printf(", expire=%s\n", + sec2str(p->expire - time.tv_sec)); + } + free(buf); +#else struct in6_drlist dr; int s, i; struct timeval time; @@ -942,7 +1055,7 @@ rtrlist() exit(1); } #define DR dr.defrouter[i] - for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { + for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { struct sockaddr_in6 sin6; bzero(&sin6, sizeof(sin6)); @@ -967,11 +1080,128 @@ rtrlist() } #undef DR close(s); +#endif } void plist() { +#ifdef ICMPV6CTL_ND6_PRLIST + int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; + char *buf; + struct in6_prefix *p, *ep, *n; + struct sockaddr_in6 *advrtr; + size_t l; + struct timeval time; +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; + int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; + int ninflags = nflag ? NI_NUMERICHOST : 0; +#endif + char namebuf[NI_MAXHOST]; + + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); + /*NOTREACHED*/ + } + buf = malloc(l); + if (!buf) { + errx(1, "not enough core"); + /*NOTREACHED*/ + } + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); + /*NOTREACHED*/ + } + + ep = (struct in6_prefix *)(buf + l); + for (p = (struct in6_prefix *)buf; p < ep; p = n) { + advrtr = (struct sockaddr_in6 *)(p + 1); + n = (struct in6_prefix *)&advrtr[p->advrtrs]; + + if (getnameinfo((struct sockaddr *)&p->prefix, + p->prefix.sin6_len, namebuf, sizeof(namebuf), + NULL, 0, niflags) != 0) + strlcpy(namebuf, "?", sizeof(namebuf)); + printf("%s/%d if=%s\n", namebuf, p->prefixlen, + if_indextoname(p->if_index, ifix_buf)); + + gettimeofday(&time, 0); + /* + * meaning of fields, especially flags, is very different + * by origin. notify the difference to the users. + */ + printf("flags=%s%s%s%s%s", + p->raflags.onlink ? "L" : "", + p->raflags.autonomous ? "A" : "", + (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", + (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", +#ifdef NDPRF_HOME + (p->flags & NDPRF_HOME) != 0 ? "H" : "" +#else + "" +#endif + ); + if (p->vltime == ND6_INFINITE_LIFETIME) + printf(" vltime=infinity"); + else + printf(" vltime=%ld", (long)p->vltime); + if (p->pltime == ND6_INFINITE_LIFETIME) + printf(", pltime=infinity"); + else + printf(", pltime=%ld", (long)p->pltime); + if (p->expire == 0) + printf(", expire=Never"); + else if (p->expire >= time.tv_sec) + printf(", expire=%s", + sec2str(p->expire - time.tv_sec)); + else + printf(", expired"); + printf(", ref=%d", p->refcnt); + printf("\n"); + /* + * "advertising router" list is meaningful only if the prefix + * information is from RA. + */ + if (p->advrtrs) { + int j; + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)(p + 1); + printf(" advertised by\n"); + for (j = 0; j < p->advrtrs; j++) { + struct in6_nbrinfo *nbi; + + if (getnameinfo((struct sockaddr *)sin6, + sin6->sin6_len, namebuf, sizeof(namebuf), + NULL, 0, ninflags) != 0) + strlcpy(namebuf, "?", sizeof(namebuf)); + printf(" %s", namebuf); + + nbi = getnbrinfo(&sin6->sin6_addr, p->if_index, + 0); + if (nbi) { + switch(nbi->state) { + case ND6_LLINFO_REACHABLE: + case ND6_LLINFO_STALE: + case ND6_LLINFO_DELAY: + case ND6_LLINFO_PROBE: + printf(" (reachable)\n"); + break; + default: + printf(" (unreachable)\n"); + } + } else + printf(" (no neighbor state)\n"); + sin6++; + } + } else + printf(" No advertising router\n"); + } + free(buf); +#else struct in6_prlist pr; int s, i; struct timeval time; @@ -990,19 +1220,73 @@ plist() } #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, + struct sockaddr_in6 p6; + char namebuf[NI_MAXHOST]; + int niflags; + +#ifdef NDPRF_ONLINK + p6 = PR.prefix; +#else + memset(&p6, 0, sizeof(p6)); + p6.sin6_family = AF_INET6; + p6.sin6_len = sizeof(p6); + p6.sin6_addr = PR.prefix; +#endif + + /* + * copy link index to sin6_scope_id field. + * XXX: KAME specific. + */ + if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) { + u_int16_t linkid; + + memcpy(&linkid, &p6.sin6_addr.s6_addr[2], + sizeof(linkid)); + linkid = ntohs(linkid); + p6.sin6_scope_id = linkid; + p6.sin6_addr.s6_addr[2] = 0; + p6.sin6_addr.s6_addr[3] = 0; + } + + niflags = NI_NUMERICHOST; +#ifdef __KAME__ + niflags |= NI_WITHSCOPEID; +#endif + if (getnameinfo((struct sockaddr *)&p6, + sizeof(p6), namebuf, sizeof(namebuf), + NULL, 0, niflags)) { + warnx("getnameinfo failed"); + continue; + } + printf("%s/%d if=%s\n", namebuf, PR.prefixlen, if_indextoname(PR.if_index, ifix_buf)); + gettimeofday(&time, 0); /* * meaning of fields, especially flags, is very different * by origin. notify the difference to the users. */ - printf(" %s", PR.origin == PR_ORIG_RA ? "" : "advertise: "); +#if 0 + printf(" %s", + PR.origin == PR_ORIG_RA ? "" : "advertise: "); +#endif +#ifdef NDPRF_ONLINK + printf("flags=%s%s%s%s%s", + PR.raflags.onlink ? "L" : "", + PR.raflags.autonomous ? "A" : "", + (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", + (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", +#ifdef NDPRF_HOME + (PR.flags & NDPRF_HOME) != 0 ? "H" : "" +#else + "" +#endif + ); +#else printf("flags=%s%s", PR.raflags.onlink ? "L" : "", PR.raflags.autonomous ? "A" : ""); +#endif if (PR.vltime == ND6_INFINITE_LIFETIME) printf(" vltime=infinity"); else @@ -1018,6 +1302,10 @@ plist() sec2str(PR.expire - time.tv_sec)); else printf(", expired"); +#ifdef NDPRF_ONLINK + printf(", ref=%d", PR.refcnt); +#endif +#if 0 switch (PR.origin) { case PR_ORIG_RA: printf(", origin=RA"); @@ -1035,12 +1323,14 @@ plist() printf(", origin=?"); break; } +#endif printf("\n"); /* * "advertising router" list is meaningful only if the prefix * information is from RA. */ - if (PR.origin != PR_ORIG_RA) + if (0 && /* prefix origin is almost obsolted */ + PR.origin != PR_ORIG_RA) ; else if (PR.advrtrs) { int j; @@ -1073,8 +1363,7 @@ plist() default: printf(" (unreachable)\n"); } - } - else + } else printf(" (no neighbor state)\n"); } if (PR.advrtrs > DRLSTSIZ) @@ -1085,6 +1374,7 @@ plist() } #undef PR close(s); +#endif } void diff --git a/usr.sbin/prefix/Makefile b/usr.sbin/prefix/Makefile index 4681577..69bd0e3 100644 --- a/usr.sbin/prefix/Makefile +++ b/usr.sbin/prefix/Makefile @@ -2,9 +2,10 @@ # $Id: Makefile,v 1.1.1.1 1999/08/08 23:31:13 itojun Exp $ # $FreeBSD$ -PROG= prefix MAN= prefix.8 -CFLAGS+=-DINET6 +realinstall: + ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/prefix.sh ${DESTDIR}${BINDIR}/prefix .include <bsd.prog.mk> diff --git a/usr.sbin/prefix/prefix.c b/usr.sbin/prefix/prefix.c deleted file mode 100644 index 84fbf26..0000000 --- a/usr.sbin/prefix/prefix.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/sysctl.h> -#include <sys/time.h> - -#include <net/if.h> -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include <net/if_var.h> -#endif /* __FreeBSD__ >= 3 */ -#include <net/if_dl.h> -#include <net/if_types.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define DEF_ADVVALIDLIFETIME 2592000 -#define DEF_ADVPREFERREDLIFETIME 604800 -struct in6_prefixreq prereq = {{NULL}, /* interface name */ - PR_ORIG_STATIC, - 64, /* default plen */ - 2592000, /* vltime=30days */ - 604800, /* pltime=7days */ - /* ra onlink=1 autonomous=1 */ - {{1,1,0}}, - {NULL}}; /* prefix */ -struct in6_rrenumreq rrreq = {{NULL}, /* interface name */ - PR_ORIG_STATIC, /* default origin */ - 64, /* default match len */ - 0, /* default min match len */ - 128, /* default max match len */ - 0, /* default uselen */ - 0, /* default keeplen */ - {1,1,0}, /* default raflag mask */ - 2592000, /* vltime=30days */ - 604800, /* pltime=7days */ - /* ra onlink=1 autonomous=1 */ - {{1,1,0}}, - {NULL}, /* match prefix */ - {NULL} /* use prefix */ - }; - -#define C(x) ((caddr_t) &x) - -struct prefix_cmds { - const char *errmsg; - int cmd; - caddr_t req; -} prcmds[] = { - {"SIOCSIFPREFIX_IN6 failed", SIOCSIFPREFIX_IN6, C(prereq)}, - {"SIOCDIFPREFIX_IN6 failed", SIOCDIFPREFIX_IN6, C(prereq)}, - {"SIOCAIFPREFIX_IN6 failed", SIOCAIFPREFIX_IN6, C(rrreq)}, - {"SIOCCIFPREFIX_IN6 failed", SIOCCIFPREFIX_IN6, C(rrreq)}, - {"SIOCSGIFPREFIX_IN6 failed", SIOCSGIFPREFIX_IN6, C(rrreq)} -}; - -#define PREF_CMD_SET 0 -#define PREF_CMD_DELETE 1 -#define PREF_CMD_ADD 2 -#define PREF_CMD_CHANGE 3 -#define PREF_CMD_SETGLOBAL 4 -#define PREF_CMD_MAX 5 - -u_int prcmd = PREF_CMD_SET; /* default command */ - -char name[32]; -int flags; - -int newprefix_setdel, newprefix_match, newprefix_use, newprefix_uselen, - newprefix_keeplen; - -void Perror __P((const char *cmd)); -int prefix __P((int argc, char *const *argv)); -void usage __P((void)); -void setlifetime __P((const char *atime, u_int32_t *btime)); -int all, explicit_prefix = 0; - -typedef void c_func __P((const char *cmd, int arg)); -c_func set_vltime, set_pltime, set_raf_onlink, - set_raf_auto, set_rrf_decrvalid, set_rrf_decrprefd, - get_setdelprefix, get_matchprefix, get_useprefix, set_matchlen, - set_match_minlen, set_match_maxlen, - set_use_uselen, set_use_keeplen, set_prefix_cmd; - -void getprefixlen __P((const char *, int)); -void getprefix __P((const char *, int)); - -#define NEXTARG 0xffffff - -const -struct cmd { - const char *c_name; - int c_parameter; /* NEXTARG means next argv */ - void (*c_func) __P((const char *, int)); -} cmds[] = { - { "set", PREF_CMD_SET, set_prefix_cmd }, - { "delete", PREF_CMD_DELETE, set_prefix_cmd }, - { "prefixlen", NEXTARG, getprefixlen }, - { "add", PREF_CMD_ADD, set_prefix_cmd }, - { "change", PREF_CMD_CHANGE, set_prefix_cmd }, - { "setglobal", PREF_CMD_SETGLOBAL, set_prefix_cmd }, - { "matchpr", NEXTARG, get_matchprefix }, - { "usepr", NEXTARG, get_useprefix }, - { "mp_len", NEXTARG, set_matchlen }, - { "mp_minlen", NEXTARG, set_match_minlen }, - { "mp_maxlen", NEXTARG, set_match_maxlen }, - { "up_uselen", NEXTARG, set_use_uselen }, - { "up_keeplen", NEXTARG, set_use_keeplen }, - { "vltime", NEXTARG, set_vltime }, - { "pltime", NEXTARG, set_pltime }, - { "raf_onlink", 1, set_raf_onlink }, - { "-raf_onlink", 0, set_raf_onlink }, - { "raf_auto", 1, set_raf_auto }, - { "-raf_auto", 0, set_raf_auto }, - { "rrf_decrvalid", 1, set_rrf_decrvalid }, - { "-rrf_decrvalid", 0, set_rrf_decrvalid }, - { "rrf_decrprefd", 1, set_rrf_decrprefd }, - { "-rrf_decrprefd", 0, set_rrf_decrprefd }, - { 0, 0, get_setdelprefix }, - { 0, 0, 0 }, -}; - - -void -usage() -{ - fprintf(stderr, "%s", - "usage: prefix interface prefix_value [parameters] [set|delete]\n" - " prefix interface\n" - " matchpr matchpr_value mp_len mp_len_value\n" - " usepr usepr_value up_uselen up_uselen_value\n" - " [parameters] [add|change|setglobal]\n" - " prefix -a [-d] [-u]\n" - " matchpr matchpr_value mp_len mp_len_value\n" - " usepr usepr_value up_uselen up_uselen_value\n" - " [parameters] [add|change|setglobal]\n"); - exit(1); -} - -int -main(argc, argv) - int argc; - char *const *argv; -{ - int c; - int downonly, uponly; - int foundit = 0; - int addrcount; - struct if_msghdr *ifm, *nextifm; - struct ifa_msghdr *ifam; - struct sockaddr_dl *sdl; - char *buf, *lim, *next; - - - size_t needed; - int mib[6]; - - /* Parse leading line options */ - all = downonly = uponly = 0; - while ((c = getopt(argc, argv, "adu")) != -1) { - switch (c) { - case 'a': /* scan all interfaces */ - all++; - break; - case 'd': /* restrict scan to "down" interfaces */ - downonly++; - break; - case 'u': /* restrict scan to "up" interfaces */ - uponly++; - break; - default: - usage(); - break; - } - } - argc -= optind; - argv += optind; - - /* nonsense.. */ - if (uponly && downonly) - usage(); - - if (!all) { - /* not listing, need an argument */ - if (argc < 1) - usage(); - - strncpy(name, *argv, sizeof(name)); - argc--, argv++; - } - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET6; /* address family */ - mib[4] = NET_RT_IFLIST; - mib[5] = 0; - - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - errx(1, "iflist-sysctl-estimate"); - if ((buf = malloc(needed)) == NULL) - errx(1, "malloc"); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) - errx(1, "actual retrieval of interface table"); - lim = buf + needed; - - next = buf; - while (next < lim) { - - ifm = (struct if_msghdr *)next; - - if (ifm->ifm_type == RTM_IFINFO) { - sdl = (struct sockaddr_dl *)(ifm + 1); - flags = ifm->ifm_flags; - } else { - fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n"); - fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, - ifm->ifm_type); - fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen); - fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, - lim); - exit (1); - } - - next += ifm->ifm_msglen; - ifam = NULL; - addrcount = 0; - while (next < lim) { - - nextifm = (struct if_msghdr *)next; - - if (nextifm->ifm_type != RTM_NEWADDR) - break; - - if (ifam == NULL) - ifam = (struct ifa_msghdr *)nextifm; - - addrcount++; - next += nextifm->ifm_msglen; - } - - if (all) { - if (uponly) - if ((flags & IFF_UP) == 0) - continue; /* not up */ - if (downonly) - if (flags & IFF_UP) - continue; /* not down */ - strncpy(name, sdl->sdl_data, sdl->sdl_nlen); - name[sdl->sdl_nlen] = '\0'; - } else { - if (strlen(name) != sdl->sdl_nlen) - continue; /* not same len */ - if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0) - continue; /* not same name */ - } - - if (argc > 0) - prefix(argc, argv); -#if 0 - else { - /* TODO: print prefix status by sysctl */ - } -#endif - - if (all == 0) { - foundit++; /* flag it as 'done' */ - break; - } - } - free(buf); - - if (all == 0 && foundit == 0) - errx(1, "interface %s does not exist", name); - - - exit (0); -} - - -int -prefix(int argc, char *const *argv) -{ - int s; - - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - - while (argc > 0) { - register const struct cmd *p; - - for (p = cmds; p->c_name; p++) - if (strcmp(*argv, p->c_name) == 0) - break; - if (p->c_func) { - if (p->c_parameter == NEXTARG) { - if (argv[1] == NULL) - errx(1, "'%s' requires argument", - p->c_name); - (*p->c_func)(argv[1], 0); - argc--, argv++; - } else - (*p->c_func)(*argv, p->c_parameter); - } - argc--, argv++; - } - if (prcmd > PREF_CMD_MAX) { - Perror("ioctl: unknown prefix cmd"); - goto end; - } - if (prcmd == PREF_CMD_SET || prcmd == PREF_CMD_DELETE) { - if (!newprefix_setdel) - usage(); - } else { /* ADD|CHANGE|SETGLOBAL */ - if (!newprefix_match) - usage(); - } - if (!newprefix_use) - rrreq.irr_u_uselen = 0; /* make clear that no use_prefix */ - else if (newprefix_keeplen == NULL && rrreq.irr_u_uselen < 64) - /* init keeplen to make uselen + keeplen equal 64 */ - rrreq.irr_u_keeplen = 64 - rrreq.irr_u_uselen; - if (explicit_prefix == 0) { - /* Aggregatable address architecture defines all prefixes - are 64. So, it is convenient to set prefixlen to 64 if - it is not specified. */ - getprefixlen("64", 0); - } - strncpy(prcmds[prcmd].req, name, IFNAMSIZ); - if (ioctl(s, prcmds[prcmd].cmd, prcmds[prcmd].req) < 0) { - if (all && errno == EADDRNOTAVAIL) - goto end; - Perror(prcmds[prcmd].errmsg); - } - end: - close(s); - return(0); -} -#define PREFIX 0 -#define MPREFIX 1 -#define UPREFIX 2 - -void -Perror(cmd) - const char *cmd; -{ - switch (errno) { - - case ENXIO: - errx(1, "%s: no such interface", cmd); - break; - - case EPERM: - errx(1, "%s: permission denied", cmd); - break; - - default: - err(1, "%s", cmd); - } -} - -#define SIN6(x) ((struct sockaddr_in6 *) &(x)) -struct sockaddr_in6 *sin6tab[] = { -SIN6(prereq.ipr_prefix), SIN6(rrreq.irr_matchprefix), -SIN6(rrreq.irr_useprefix)}; - -void -getprefixlen(const char *plen, int unused) -{ - int len = atoi(plen); - - if ((len < 0) || (len > 128)) - errx(1, "%s: bad value", plen); - - /* set plen for prereq */ - prereq.ipr_plen = len; - explicit_prefix = 1; -} - -void -getprefix(const char *prefix, int which) -{ - register struct sockaddr_in6 *sin = sin6tab[which]; - - /* - * Delay the ioctl to set the interface prefix until flags are all set. - * The prefix interpretation may depend on the flags, - * and the flags may change when the prefix is set. - */ - - sin->sin6_len = sizeof(*sin); - sin->sin6_family = AF_INET6; - - if (inet_pton(AF_INET6, prefix, &sin->sin6_addr) != 1) - errx(1, "%s: bad value", prefix); -} - -void -get_setdelprefix(const char *prefix, int unused) -{ - newprefix_setdel++; - getprefix(prefix, PREFIX); -} - -void -get_matchprefix(const char *prefix, int unused) -{ - newprefix_match++; - prcmd = (prcmd == PREF_CMD_SET) ? PREF_CMD_ADD : prcmd; - getprefix(prefix, MPREFIX); -} - -void -get_useprefix(const char *prefix, int unused) -{ - newprefix_use++; - if (newprefix_uselen == 0) - rrreq.irr_u_uselen = 64; - getprefix(prefix, UPREFIX); -} - -static int -get_plen(const char *plen) -{ - int len; - - len = atoi(plen); - if ((len < 0) || (len > 128)) - errx(1, "%s: bad value", plen); - return len; -} - -void -set_matchlen(const char *plen, int unused) -{ - rrreq.irr_m_len = get_plen(plen); -} - -void -set_match_minlen(const char *plen, int unused) -{ - rrreq.irr_m_minlen = get_plen(plen); -} - -void -set_match_maxlen(const char *plen, int unused) -{ - rrreq.irr_m_maxlen = get_plen(plen); -} - -void -set_use_uselen(const char *plen, int unused) -{ - newprefix_uselen++; - rrreq.irr_u_uselen = get_plen(plen); -} - -void -set_use_keeplen(const char *plen, int unused) -{ - newprefix_keeplen++; - rrreq.irr_u_keeplen = get_plen(plen); -} - -void -set_vltime(const char *ltime, int unused) -{ - setlifetime(ltime, &prereq.ipr_vltime); - rrreq.irr_vltime = prereq.ipr_vltime; -} - -void -set_pltime(const char *ltime, int unused) -{ - setlifetime(ltime, &prereq.ipr_pltime); - rrreq.irr_pltime = prereq.ipr_pltime; -} - -void -set_raf_onlink(const char *unused, int value) -{ - /* raflagmask is only meaningful when newprefix_rrenum */ - rrreq.irr_raflagmask.onlink = 1; - prereq.ipr_flags.prf_ra.onlink = - rrreq.irr_flags.prf_ra.onlink = value ? 1 : 0; -} - -void -set_raf_auto(const char *unused, int value) -{ - /* only meaningful when newprefix_rrenum */ - rrreq.irr_raflagmask.autonomous = 1; - prereq.ipr_flags.prf_ra.autonomous = - rrreq.irr_flags.prf_ra.autonomous = value ? 1 : 0; -} - -void -set_rrf_decrvalid(const char *unused, int value) -{ - prereq.ipr_flags.prf_rr.decrvalid = - rrreq.irr_flags.prf_rr.decrvalid = value ? 1 : 0; -} - -void -set_rrf_decrprefd(const char *unused, int value) -{ - prereq.ipr_flags.prf_rr.decrprefd = - rrreq.irr_flags.prf_rr.decrprefd = value ? 1 : 0; -} - -void -set_prefix_cmd(const char *unused, int cmd) -{ - prcmd = cmd; -} - -void -setlifetime(const char *atime, u_int32_t *btime) -{ - int days = 0, hours = 0, minutes = 0, seconds = 0; - u_int32_t ttime; - char *check; - - if (strcmp(atime, "infinity") == 0) { - *btime = 0xffffffff; - return; - } - ttime = strtoul(atime, &check ,10) & 0xffffffff; - if (*check == '\0') { - *btime = ttime; - return; - } - if (sscanf(atime, "d%2dh%2dm%2ds%2d", &days, &hours, &minutes, - &seconds) < 0) { - Perror("wrong time format: valid is d00h00m00s00, \n" - "where 00 can be any octal number, \n" - "\'d\' is for days, \'h\' is for hours, \n" - "\'m\' is for minutes, and \'s\' is for seconds \n"); - return; - } - *btime = 0; - *btime += seconds; - *btime += minutes * 60; - *btime += hours * 3600; - *btime += days * 86400; - return; -} diff --git a/usr.sbin/prefix/prefix.sh b/usr.sbin/prefix/prefix.sh new file mode 100644 index 0000000..ee727b3 --- /dev/null +++ b/usr.sbin/prefix/prefix.sh @@ -0,0 +1,74 @@ +#!/bin/sh + +# $KAME: prefix.sh,v 1.12 2001/05/26 23:38:10 itojun Exp $ +# $FreeBSD$ + +# Copyright (c) 2001 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. + +iface=$1 +prefix=$2 + +usage() { + echo "usage: prefix interface prefix [set|delete]" +} + +# We're now invalidating the prefix ioctls and the corresponding command. +echo "** The prefix command is almost invalidated. Please use ifconfig(8). **" + +if [ X"$iface" = X -o X"$prefix" = X ]; then + usage + exit 1 +fi + +if [ -z $3 ]; then + command=set +else + command=$3 +fi + +case $command in + set) + laddr=`ifconfig $iface inet6 | grep 'inet6 fe80:' | head -1 | awk '{print $2}'` + if [ X"$laddr" = X ]; then + echo "prefix: no interface ID found" + exit 1 + fi + hostid=`echo $laddr | sed -e 's/^fe80:[0-9a-fA-F]*:/fe80::/' -e 's/^fe80:://' -e 's/%.*//'` + address=$2$hostid + exec ifconfig $iface inet6 $address prefixlen 64 alias + ;; + delete) + addrs=`ifconfig $iface inet6 | grep "inet6 $prefix" | awk '{print $2}'` + for a in $addrs; do + ifconfig $iface inet6 $a -alias + done + ;; + *) + usage + exit 1 + ;; +esac diff --git a/usr.sbin/rip6query/rip6query.8 b/usr.sbin/rip6query/rip6query.8 index dab1bbb..e16df23 100644 --- a/usr.sbin/rip6query/rip6query.8 +++ b/usr.sbin/rip6query/rip6query.8 @@ -1,3 +1,4 @@ +.\" $KAME: rip6query.8,v 1.4 2001/03/15 12:35:24 itojun Exp $ .\" .\" Copyright (C) 1998 and 1999 WIDE Project. .\" All rights reserved. @@ -44,7 +45,7 @@ .Sh DESCRIPTION .Nm requests remote RIPng daemon on -.Ar destionation +.Ar destination to dump RIPng routing information. .Fl I lets you specify outgoing diff --git a/usr.sbin/rip6query/rip6query.c b/usr.sbin/rip6query/rip6query.c index ed0f6f9..bc8efe7 100644 --- a/usr.sbin/rip6query/rip6query.c +++ b/usr.sbin/rip6query/rip6query.c @@ -1,3 +1,5 @@ +/* $KAME: rip6query.c,v 1.11 2001/05/08 04:36:37 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -41,6 +43,8 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/queue.h> + #include <net/if.h> #if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include <net/if_var.h> @@ -82,7 +86,7 @@ main(argc, argv) char pbuf[10]; struct addrinfo hints, *res; - while ((c = getopt(argc, argv, "I:")) != EOF) { + while ((c = getopt(argc, argv, "I:")) != -1) { switch (c) { case 'I': ifidx = if_nametoindex(optarg); @@ -102,7 +106,7 @@ main(argc, argv) if (argc != 1) { usage(); - exit(-1); + exit(1); } if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { diff --git a/usr.sbin/route6d/route6d.8 b/usr.sbin/route6d/route6d.8 index 851e867..7da9b53 100644 --- a/usr.sbin/route6d/route6d.8 +++ b/usr.sbin/route6d/route6d.8 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: route6d.8,v 1.8 2000/05/31 17:00:09 itojun Exp $ +.\" $KAME: route6d.8,v 1.10 2000/11/24 11:57:18 itojun Exp $ .\" .\" Copyright (c) 1996 WIDE Project. All rights reserved. .\" @@ -16,13 +16,13 @@ .\" A PARTICULAR PURPOSE. .Dd January 31, 1997 .Dt ROUTE6D 8 -.Os KAME +.Os .Sh NAME .Nm route6d .Nd RIP6 Routing Daemon .Sh SYNOPSIS .Nm -.Op Fl adDhlqsS +.Op Fl adDhlnqsS .Bk -words .Op Fl R Ar routelog .Ek @@ -146,6 +146,9 @@ For example, with .Nm will accept default route and routes in 6bone test address, but no others. .\" +.It Fl n +Do not update the kernel routing table. +.\" .It Fl N Ar if1[,if2...] Do not listen to, or advertise, route from/to interfaces specified by .Ar if1,[if2...] . diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c index 264206e..d41efd0 100644 --- a/usr.sbin/route6d/route6d.c +++ b/usr.sbin/route6d/route6d.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: route6d.c,v 1.37 2000/10/10 13:02:30 itojun Exp $ */ +/* $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -31,7 +31,7 @@ */ #ifndef lint -static char _rcsid[] = "$KAME: route6d.c,v 1.37 2000/10/10 13:02:30 itojun Exp $"; +static char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $"; #endif #include <stdio.h> @@ -72,9 +72,7 @@ static char _rcsid[] = "$KAME: route6d.c,v 1.37 2000/10/10 13:02:30 itojun Exp $ #include <netinet/ip6.h> #include <netinet/udp.h> #include <netdb.h> -#ifdef HAVE_GETIFADDRS #include <ifaddrs.h> -#endif #include <arpa/inet.h> @@ -111,7 +109,8 @@ struct ifc { /* Configuration of an interface */ int ifc_index; /* if index */ int ifc_mtu; /* if mtu */ int ifc_metric; /* if metric */ - short ifc_flags; /* flags */ + u_int ifc_flags; /* flags */ + short ifc_cflags; /* IFC_XXX */ struct in6_addr ifc_mylladdr; /* my link-local address */ struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ struct iff *ifc_filter; /* filter structure */ @@ -147,13 +146,13 @@ int ripsock; /* socket to send/receive RIP datagram */ struct rip6 *ripbuf; /* packet buffer for sending */ /* - * Maintain the routes in a linked list. When the number of the routes + * Maintain the routes in a linked list. When the number of the routes * grows, somebody would like to introduce a hash based or a radix tree - * based strucutre. I believe the number of routes handled by RIP is + * based structure. I believe the number of routes handled by RIP is * limited and I don't have to manage a complex data structure, however. * * One of the major drawbacks of the linear linked list is the difficulty - * of representing the relationship between a couple of routes. This may + * of representing the relationship between a couple of routes. This may * be a significant problem when we have to support route aggregation with * supressing the specifices covered by the aggregate. */ @@ -201,6 +200,11 @@ int logopened = 0; static u_long seq = 0; +volatile int signo; +volatile sig_atomic_t seenalrm; +volatile sig_atomic_t seenquit; +volatile sig_atomic_t seenusr1; + #define RRTF_AGGREGATE 0x08000000 #define RRTF_NOADVERTISE 0x10000000 #define RRTF_NH_NOT_LLADDR 0x20000000 @@ -208,9 +212,11 @@ static u_long seq = 0; #define RRTF_CHANGED 0x80000000 int main __P((int, char **)); -void ripalarm __P((int)); +void sighandler __P((int)); +void ripalarm __P((void)); void riprecv __P((void)); void ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); +int out_filter __P((struct riprt *, struct ifc *)); void init __P((void)); void sockopt __P((struct ifc *)); void ifconfig __P((void)); @@ -222,10 +228,10 @@ int rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, const struct sockaddr_in6 *)); void filterconfig __P((void)); int getifmtu __P((int)); -const char *rttypes __P((struct rt_msghdr *rtm)); -const char *rtflags __P((struct rt_msghdr *rtm)); -const char *ifflags __P((int flags)); -void ifrt __P((struct ifc *, int)); +const char *rttypes __P((struct rt_msghdr *)); +const char *rtflags __P((struct rt_msghdr *)); +const char *ifflags __P((int)); +int ifrt __P((struct ifc *, int)); void ifrt_p2p __P((struct ifc *, int)); void applymask __P((struct in6_addr *, struct in6_addr *)); void applyplen __P((struct in6_addr *, int)); @@ -234,10 +240,12 @@ void ifdump __P((int)); void ifdump0 __P((FILE *, const struct ifc *)); void rtdump __P((int)); void rt_entry __P((struct rt_msghdr *, int)); -void rtdexit __P((int)); -void riprequest __P((struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *)); +void rtdexit __P((void)); +void riprequest __P((struct ifc *, struct netinfo6 *, int, + struct sockaddr_in6 *)); void ripflush __P((struct ifc *, struct sockaddr_in6 *)); void sendrequest __P((struct ifc *)); +int sin6mask2len __P((const struct sockaddr_in6 *)); int mask2len __P((const struct in6_addr *, int)); int sendpacket __P((struct sockaddr_in6 *, int)); int addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); @@ -250,7 +258,7 @@ char *hms __P((void)); const char *inet6_n2p __P((const struct in6_addr *)); struct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); struct in6_addr *plen2mask __P((int)); -struct riprt *rtsearch __P((struct netinfo6 *)); +struct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); int ripinterval __P((int)); time_t ripsuptrig __P((void)); void fatal __P((const char *, ...)) @@ -286,7 +294,7 @@ main(argc, argv) progname = *argv; pid = getpid(); - while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != EOF) { + while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { switch (ch) { case 'A': case 'N': @@ -332,8 +340,10 @@ main(argc, argv) } argc -= optind; argv += optind; - if (argc > 0) + if (argc > 0) { fatal("bogus extra arguments"); + /*NOTREACHED*/ + } if (geteuid()) { nflag = 1; @@ -341,6 +351,15 @@ main(argc, argv) } openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); logopened++; + + if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) + fatal("malloc"); + memset(ripbuf, 0, RIP6_MAXMTU); + ripbuf->rip6_cmd = RIP6_RESPONSE; + ripbuf->rip6_vers = RIP6_VERSION; + ripbuf->rip6_res1[0] = 0; + ripbuf->rip6_res1[1] = 0; + init(); ifconfig(); for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { @@ -353,8 +372,10 @@ main(argc, argv) } if (error) exit(1); - if (loopifcp == NULL) + if (loopifcp == NULL) { fatal("No loopback found"); + /*NOTREACHED*/ + } loopifindex = loopifcp->ifc_index; for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) ifrt(ifcp, 0); @@ -365,13 +386,17 @@ main(argc, argv) if (dflag == 0) { #if 1 - if (daemon(0, 0) < 0) + if (daemon(0, 0) < 0) { fatal("daemon"); + /*NOTREACHED*/ + } #else if (fork()) exit(0); - if (setsid() < 0) + if (setsid() < 0) { fatal("setid"); + /*NOTREACHED*/ + } #endif } pid = getpid(); @@ -380,26 +405,25 @@ main(argc, argv) fclose(pidfile); } - if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) + if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { fatal("malloc"); + /*NOTREACHED*/ + } memset(ripbuf, 0, RIP6_MAXMTU); ripbuf->rip6_cmd = RIP6_RESPONSE; ripbuf->rip6_vers = RIP6_VERSION; ripbuf->rip6_res1[0] = 0; ripbuf->rip6_res1[1] = 0; - if (signal(SIGALRM, ripalarm) == SIG_ERR) - fatal("signal: SIGALRM"); - if (signal(SIGQUIT, rtdexit) == SIG_ERR) - fatal("signal: SIGQUIT"); - if (signal(SIGTERM, rtdexit) == SIG_ERR) - fatal("signal: SIGTERM"); - if (signal(SIGUSR1, ifrtdump) == SIG_ERR) - fatal("signal: SIGUSR1"); - if (signal(SIGHUP, ifrtdump) == SIG_ERR) - fatal("signal: SIGHUP"); - if (signal(SIGINT, ifrtdump) == SIG_ERR) - fatal("signal: SIGINT"); + if (signal(SIGALRM, sighandler) == SIG_ERR || + signal(SIGQUIT, sighandler) == SIG_ERR || + signal(SIGTERM, sighandler) == SIG_ERR || + signal(SIGUSR1, sighandler) == SIG_ERR || + signal(SIGHUP, sighandler) == SIG_ERR || + signal(SIGINT, sighandler) == SIG_ERR) { + fatal("signal"); + /*NOTREACHED*/ + } /* * To avoid rip packet congestion (not on a cable but in this * process), wait for a moment to send the first RIP6_RESPONSE @@ -418,12 +442,31 @@ main(argc, argv) while (1) { fd_set recvec; + if (seenalrm) { + ripalarm(); + seenalrm = 0; + continue; + } + if (seenquit) { + rtdexit(); + seenquit = 0; + continue; + } + if (seenusr1) { + ifrtdump(SIGUSR1); + seenusr1 = 0; + continue; + } + FD_COPY(&sockvec, &recvec); + signo = 0; switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { case -1: - if (errno == EINTR) - continue; - fatal("select"); + if (errno != EINTR) { + fatal("select"); + /*NOTREACHED*/ + } + continue; case 0: continue; default: @@ -441,13 +484,34 @@ main(argc, argv) } } +void +sighandler(sig) + int sig; +{ + + signo = sig; + switch (signo) { + case SIGALRM: + seenalrm++; + break; + case SIGQUIT: + case SIGTERM: + seenquit++; + break; + case SIGUSR1: + case SIGHUP: + case SIGINT: + seenusr1++; + break; + } +} + /* * gracefully exits after resetting sockopts. */ /* ARGSUSED */ void -rtdexit(sig) - int sig; +rtdexit() { struct riprt *rrt; @@ -468,14 +532,13 @@ rtdexit(sig) * Called periodically: * 1. age out the learned route. remove it if necessary. * 2. submit RIP6_RESPONSE packets. - * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have + * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have * to invoke this function in every 1 or 5 or 10 seconds only to age the * routes more precisely. */ /* ARGSUSED */ void -ripalarm(sig) - int sig; +ripalarm() { struct ifc *ifcp; struct riprt *rrt, *rrt_prev, *rrt_next; @@ -532,43 +595,63 @@ init() hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, port, &hints, &res); - if (error) + if (error) { fatal("%s", gai_strerror(error)); - if (res->ai_next) + /*NOTREACHED*/ + } + if (res->ai_next) { fatal(":: resolved to multiple address"); + /*NOTREACHED*/ + } int0 = 0; int255 = 255; ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (ripsock < 0) + if (ripsock < 0) { fatal("rip socket"); - if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) + /*NOTREACHED*/ + } + if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { fatal("rip bind"); + /*NOTREACHED*/ + } if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &int255, sizeof(int255)) < 0) + &int255, sizeof(int255)) < 0) { fatal("rip IPV6_MULTICAST_HOPS"); + /*NOTREACHED*/ + } if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &int0, sizeof(int0)) < 0) + &int0, sizeof(int0)) < 0) { fatal("rip IPV6_MULTICAST_LOOP"); + /*NOTREACHED*/ + } i = 1; #ifdef IPV6_RECVPKTINFO if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i, - sizeof(i)) < 0) + sizeof(i)) < 0) { fatal("rip IPV6_RECVPKTINFO"); + /*NOTREACHED*/ + } #else /* old adv. API */ if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i, - sizeof(i)) < 0) + sizeof(i)) < 0) { fatal("rip IPV6_PKTINFO"); + /*NOTREACHED*/ + } #endif memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET6; hints.ai_socktype = SOCK_DGRAM; error = getaddrinfo(RIP6_DEST, port, &hints, &res); - if (error) + if (error) { fatal("%s", gai_strerror(error)); - if (res->ai_next) + /*NOTREACHED*/ + } + if (res->ai_next) { fatal("%s resolved to multiple address", RIP6_DEST); + /*NOTREACHED*/ + } memcpy(&ripsin, res->ai_addr, res->ai_addrlen); #ifdef FD_ZERO @@ -579,8 +662,10 @@ init() FD_SET(ripsock, &sockvec); if (nflag == 0) { - if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) + if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { fatal("route socket"); + /*NOTREACHED*/ + } FD_SET(rtsock, &sockvec); } else rtsock = -1; /*just for safety */ @@ -654,9 +739,7 @@ ripsend(ifcp, sin, flag) { struct riprt *rrt; struct in6_addr *nh; /* next hop */ - struct in6_addr ia; - struct iff *iffp; - int maxrte, ok; + int maxrte; if (ifcp == NULL) { /* @@ -687,14 +770,19 @@ ripsend(ifcp, sin, flag) if ((flag & RRTF_SENDANYWAY) == 0 && (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) return; + + /* -N: no use */ if (iff_find(ifcp, 'N') != NULL) return; + + /* -T: generate default route only */ if (iff_find(ifcp, 'T') != NULL) { struct netinfo6 rrt_info; memset(&rrt_info, 0, sizeof(struct netinfo6)); rrt_info.rip6_dest = in6addr_any; rrt_info.rip6_plen = 0; rrt_info.rip6_metric = 1; + rrt_info.rip6_metric += ifcp->ifc_metric; rrt_info.rip6_tag = htons(routetag & 0xffff); np = ripbuf->rip6_nets; *np = rrt_info; @@ -702,52 +790,30 @@ ripsend(ifcp, sin, flag) ripflush(ifcp, sin); return; } + maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - sizeof(struct udphdr) - sizeof(struct rip6) + sizeof(struct netinfo6)) / sizeof(struct netinfo6); + nrt = 0; np = ripbuf->rip6_nets; nh = NULL; for (rrt = riprt; rrt; rrt = rrt->rrt_next) { if (rrt->rrt_rflags & RRTF_NOADVERTISE) continue; - /* Need to check filer here */ - ok = 1; - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { - if (iffp->iff_type != 'A') - continue; - if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) - continue; - ia = rrt->rrt_info.rip6_dest; - applyplen(&ia, iffp->iff_plen); - if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { - ok = 0; - break; - } - } - if (!ok) - continue; - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { - if (iffp->iff_type != 'O') - continue; - ok = 0; - if (rrt->rrt_info.rip6_plen < iffp->iff_plen) - continue; - ia = rrt->rrt_info.rip6_dest; - applyplen(&ia, iffp->iff_plen); - if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { - ok = 1; - break; - } - } - if (!ok) + + /* Need to check filter here */ + if (out_filter(rrt, ifcp) == 0) continue; + /* Check split horizon and other conditions */ if (tobeadv(rrt, ifcp) == 0) continue; + /* Only considers the routes with flag if specified */ if ((flag & RRTF_CHANGED) && (rrt->rrt_rflags & RRTF_CHANGED) == 0) continue; + /* Check nexthop */ if (rrt->rrt_index == ifcp->ifc_index && !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && @@ -775,6 +841,7 @@ ripsend(ifcp, sin, flag) nh = NULL; np++; nrt++; } + /* Put the route to the buffer */ *np = rrt->rrt_info; np++; nrt++; @@ -788,6 +855,78 @@ ripsend(ifcp, sin, flag) } /* + * outbound filter logic, per-route/interface. + */ +int +out_filter(rrt, ifcp) + struct riprt *rrt; + struct ifc *ifcp; +{ + struct iff *iffp; + struct in6_addr ia; + int ok; + + /* + * -A: filter out less specific routes, if we have aggregated + * route configured. + */ + for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + if (iffp->iff_type != 'A') + continue; + if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) + continue; + ia = rrt->rrt_info.rip6_dest; + applyplen(&ia, iffp->iff_plen); + if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) + return 0; + } + + /* + * if it is an aggregated route, advertise it only to the + * interfaces specified on -A. + */ + if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { + ok = 0; + for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + if (iffp->iff_type != 'A') + continue; + if (rrt->rrt_info.rip6_plen == iffp->iff_plen && + IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, + &iffp->iff_addr)) { + ok = 1; + break; + } + } + if (!ok) + return 0; + } + + /* + * -O: advertise only if prefix matches the configured prefix. + */ + if (iff_find(ifcp, 'O')) { + ok = 0; + for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + if (iffp->iff_type != 'O') + continue; + if (rrt->rrt_info.rip6_plen < iffp->iff_plen) + continue; + ia = rrt->rrt_info.rip6_dest; + applyplen(&ia, iffp->iff_plen); + if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { + ok = 1; + break; + } + } + if (!ok) + return 0; + } + + /* the prefix should be advertised */ + return 1; +} + +/* * Determine if the route is to be advertised on the specified interface. * It checks options specified in the arguments and the split horizon rule. */ @@ -825,7 +964,7 @@ sendpacket(sin, len) { /* * MSG_DONTROUTE should not be specified when it responds with a - * RIP6_REQUEST message. SO_DONTROUTE has been specified to + * RIP6_REQUEST message. SO_DONTROUTE has been specified to * other sockets. */ struct msghdr m; @@ -833,7 +972,7 @@ sendpacket(sin, len) struct iovec iov[2]; u_char cmsgbuf[256]; struct in6_pktinfo *pi; - int index; + int idx; struct sockaddr_in6 sincopy; /* do not overwrite the given sin */ @@ -842,10 +981,10 @@ sendpacket(sin, len) if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) { - index = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr); + idx = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr); SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0); } else - index = 0; + idx = 0; m.msg_name = (caddr_t)sin; m.msg_namelen = sizeof(*sin); @@ -853,7 +992,7 @@ sendpacket(sin, len) iov[0].iov_len = len; m.msg_iov = iov; m.msg_iovlen = 1; - if (!index) { + if (!idx) { m.msg_control = NULL; m.msg_controllen = 0; } else { @@ -867,7 +1006,7 @@ sendpacket(sin, len) cm->cmsg_type = IPV6_PKTINFO; pi = (struct in6_pktinfo *)CMSG_DATA(cm); memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ - pi->ipi6_ifindex = index; + pi->ipi6_ifindex = idx; } if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { @@ -879,7 +1018,7 @@ sendpacket(sin, len) } /* - * Receive and process RIP packets. Update the routes/kernel forwarding + * Receive and process RIP packets. Update the routes/kernel forwarding * table if necessary. */ void @@ -891,7 +1030,7 @@ riprecv() struct rip6 *rp; struct netinfo6 *np, *nq; struct riprt *rrt; - int len, nn, need_trigger, index; + int len, nn, need_trigger, idx; char buf[4 * RIP6_MAXMTU]; time_t t; struct msghdr m; @@ -902,6 +1041,7 @@ riprecv() struct iff *iffp; struct in6_addr ia; int ok; + time_t t_half_lifetime; need_trigger = 0; @@ -914,21 +1054,23 @@ riprecv() cm = (struct cmsghdr *)cmsgbuf; m.msg_control = (caddr_t)cm; m.msg_controllen = sizeof(cmsgbuf); - if ((len = recvmsg(ripsock, &m, 0)) < 0) + if ((len = recvmsg(ripsock, &m, 0)) < 0) { fatal("recvmsg"); - index = 0; + /*NOTREACHED*/ + } + idx = 0; for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { - if (cm->cmsg_level == IPPROTO_IPV6 - && cm->cmsg_type == IPV6_PKTINFO) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO) { pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); - index = pi->ipi6_ifindex; + idx = pi->ipi6_ifindex; break; } } - if (index && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) - SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, index); + if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) + SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); nh = fsock.sin6_addr; nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / @@ -941,8 +1083,8 @@ riprecv() return; } if (rp->rip6_cmd == RIP6_REQUEST) { - if (index && index < nindex2ifc) { - ifcp = index2ifc[index]; + if (idx && idx < nindex2ifc) { + ifcp = index2ifc[idx]; riprequest(ifcp, np, nn, &fsock); } else { riprequest(NULL, np, nn, &fsock); @@ -952,13 +1094,13 @@ riprecv() if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { trace(1, "Packets from non-ll addr: %s\n", - inet6_n2p(&fsock.sin6_addr)); + inet6_n2p(&fsock.sin6_addr)); return; /* Ignore packets from non-link-local addr */ } - index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); - ifcp = (index < nindex2ifc) ? index2ifc[index] : NULL; + idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); + ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; if (!ifcp) { - trace(1, "Packets to unknown interface index %d\n", index); + trace(1, "Packets to unknown interface index %d\n", idx); return; /* Ignore it */ } if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) @@ -967,18 +1109,22 @@ riprecv() trace(1, "Invalid command %d\n", rp->rip6_cmd); return; } + + /* -N: no use */ if (iff_find(ifcp, 'N') != NULL) return; + tracet(1, "Recv(%s): from %s.%d info(%d)\n", - ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); + ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); t = time(NULL); + t_half_lifetime = t - (RIP_LIFETIME/2); for (; nn; nn--, np++) { if (np->rip6_metric == NEXTHOP_METRIC) { /* modify neighbor address */ if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { nh = np->rip6_dest; - SET_IN6_LINKLOCAL_IFINDEX(nh, index); + SET_IN6_LINKLOCAL_IFINDEX(nh, idx); trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { nh = fsock.sin6_addr; @@ -986,7 +1132,7 @@ riprecv() } else { nh = fsock.sin6_addr; trace(1, "\tInvalid Nexthop: %s\n", - inet6_n2p(&np->rip6_dest)); + inet6_n2p(&np->rip6_dest)); } continue; } @@ -1027,7 +1173,9 @@ riprecv() trace(2, " [junk outside prefix]"); } - /* Listen-only filter */ + /* + * -L: listen only if the prefix matches the configuration + */ ok = 1; /* if there's no L filter, it is ok */ for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { if (iffp->iff_type != 'L') @@ -1057,7 +1205,7 @@ riprecv() np->rip6_metric = HOPCNT_INFINITY6; applyplen(&np->rip6_dest, np->rip6_plen); - if ((rrt = rtsearch(np)) != NULL) { + if ((rrt = rtsearch(np, NULL)) != NULL) { if (rrt->rrt_t == 0) continue; /* Intf route has priority */ nq = &rrt->rrt_info; @@ -1087,20 +1235,33 @@ riprecv() rrt->rrt_rflags |= RRTF_CHANGED; need_trigger = 1; } else if (nq->rip6_metric == np->rip6_metric && - rrt->rrt_index == ifcp->ifc_index && - IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw) && np->rip6_metric < HOPCNT_INFINITY6) { - /* same metric, same route from same gw */ - rrt->rrt_t = t; + if (rrt->rrt_index == ifcp->ifc_index && + IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { + /* same metric, same route from same gw */ + rrt->rrt_t = t; + } else if (rrt->rrt_t < t_half_lifetime) { + /* Better route found */ + rrt->rrt_index = ifcp->ifc_index; + /* Update routing table */ + delroute(nq, &rrt->rrt_gw); + rrt->rrt_gw = nh; + *nq = *np; + addroute(rrt, &nh, ifcp); + rrt->rrt_rflags |= RRTF_CHANGED; + rrt->rrt_t = t; + } } /* * if nq->rip6_metric == HOPCNT_INFINITY6 then - * do not update age value. Do nothing. + * do not update age value. Do nothing. */ } else if (np->rip6_metric < HOPCNT_INFINITY6) { /* Got a new valid route */ - if ((rrt = MALLOC(struct riprt)) == NULL) + if ((rrt = MALLOC(struct riprt)) == NULL) { fatal("malloc: struct riprt"); + /*NOTREACHED*/ + } memset(rrt, 0, sizeof(*rrt)); nq = &rrt->rrt_info; @@ -1187,7 +1348,7 @@ riprequest(ifcp, np, nn, sin) /* Specific response, don't split-horizon */ trace(1, "\tRIP Request\n"); for (i = 0; i < nn; i++, np++) { - rrt = rtsearch(np); + rrt = rtsearch(np, NULL); if (rrt) np->rip6_metric = rrt->rrt_info.rip6_metric; else @@ -1207,17 +1368,20 @@ riprequest(ifcp, np, nn, sin) void ifconfig() { -#ifdef HAVE_GETIFADDRS struct ifaddrs *ifap, *ifa; struct ifc *ifcp; struct ipv6_mreq mreq; int s; - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { fatal("socket"); + /*NOTREACHED*/ + } - if (getifaddrs(&ifap) != 0) + if (getifaddrs(&ifap) != 0) { fatal("getifaddrs"); + /*NOTREACHED*/ + } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1228,8 +1392,10 @@ ifconfig() continue; if (!ifcp) { /* new interface */ - if ((ifcp = MALLOC(struct ifc)) == NULL) + if ((ifcp = MALLOC(struct ifc)) == NULL) { fatal("malloc: struct ifc"); + /*NOTREACHED*/ + } memset(ifcp, 0, sizeof(*ifcp)); ifcp->ifc_index = -1; ifcp->ifc_next = ifc; @@ -1249,6 +1415,7 @@ ifconfig() trace(1, "%s: <%s> -> ", ifcp->ifc_name, ifflags(ifcp->ifc_flags)); trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); + ifcp->ifc_cflags |= IFC_CHANGED; } ifcp->ifc_flags = ifa->ifa_flags; } @@ -1257,117 +1424,17 @@ ifconfig() && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; mreq.ipv6mr_interface = ifcp->ifc_index; - if (setsockopt(ripsock, IPPROTO_IPV6, - IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) + if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) < 0) { fatal("IPV6_JOIN_GROUP"); - trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); - ifcp->ifc_joined++; - } - } - close(s); - freeifaddrs(ifap); -#else - int s, i; - char *buf; - struct ifconf ifconf; - struct ifreq *ifrp, ifr; - struct ifc *ifcp; - struct ipv6_mreq mreq; - int bufsiz; - - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - fatal("socket"); - - /* wild guess - v4, media, link, v6 * 3 */ - bufsiz = if_maxindex() * sizeof(struct ifreq) * 6; - if ((buf = (char *)malloc(bufsiz)) == NULL) - fatal("malloc"); - - /* - * ioctl(SIOCGIFCONF) does not return error on buffer size. - * we'll try to guess the buffer size by trying it twice, with - * different buffer size. - */ - ifconf.ifc_buf = buf; - ifconf.ifc_len = bufsiz / 2; - if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0) - fatal("ioctl: SIOCGIFCONF"); - i = ifconf.ifc_len; - while (1) { - char *newbuf; - - ifconf.ifc_buf = buf; - ifconf.ifc_len = bufsiz; - if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0) - fatal("ioctl: SIOCGIFCONF"); - if (i == ifconf.ifc_len) - break; - i = ifconf.ifc_len; - bufsiz *= 2; - if ((newbuf = (char *)realloc(buf, bufsiz)) == NULL) { - free(buf); - fatal("realloc"); - } - buf = newbuf; - } - for (i = 0; i < ifconf.ifc_len; ) { - ifrp = (struct ifreq *)(buf + i); - if (ifrp->ifr_addr.sa_family != AF_INET6) - goto skip; - ifcp = ifc_find(ifrp->ifr_name); - strcpy(ifr.ifr_name, ifrp->ifr_name); - if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0) - fatal("ioctl: SIOCGIFFLAGS"); - /* we are interested in multicast-capable interfaces */ - if ((ifr.ifr_flags & IFF_MULTICAST) == 0) - goto skip; - if (!ifcp) { - /* new interface */ - if ((ifcp = MALLOC(struct ifc)) == NULL) - fatal("malloc: struct ifc"); - memset(ifcp, 0, sizeof(*ifcp)); - ifcp->ifc_index = -1; - ifcp->ifc_next = ifc; - ifc = ifcp; - nifc++; - ifcp->ifc_name = allocopy(ifrp->ifr_name); - ifcp->ifc_addr = 0; - ifcp->ifc_filter = 0; - ifcp->ifc_flags = ifr.ifr_flags; - trace(1, "newif %s <%s>\n", ifcp->ifc_name, - ifflags(ifcp->ifc_flags)); - if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) - loopifcp = ifcp; - } else { - /* update flag, this may be up again */ - if (ifcp->ifc_flags != ifr.ifr_flags) { - trace(1, "%s: <%s> -> ", ifcp->ifc_name, - ifflags(ifcp->ifc_flags)); - trace(1, "<%s>\n", ifflags(ifr.ifr_flags)); + /*NOTREACHED*/ } - ifcp->ifc_flags = ifr.ifr_flags; - } - ifconfig1(ifrp->ifr_name, &ifrp->ifr_addr, ifcp, s); - if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP - && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { - mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; - mreq.ipv6mr_interface = ifcp->ifc_index; - if (setsockopt(ripsock, IPPROTO_IPV6, - IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) - fatal("IPV6_JOIN_GROUP"); trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); ifcp->ifc_joined++; } -skip: - i += IFNAMSIZ; - if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) - i += ifrp->ifr_addr.sa_len; - else - i += sizeof(struct sockaddr); } close(s); - free(buf); -#endif + freeifaddrs(ifap); } void @@ -1378,17 +1445,19 @@ ifconfig1(name, sa, ifcp, s) int s; { struct in6_ifreq ifr; - struct sockaddr_in6 *sin; + const struct sockaddr_in6 *sin; struct ifac *ifa; int plen; char buf[BUFSIZ]; - sin = (struct sockaddr_in6 *)sa; + sin = (const struct sockaddr_in6 *)sa; ifr.ifr_addr = *sin; strcpy(ifr.ifr_name, name); - if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) + if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { fatal("ioctl: SIOCGIFNETMASK_IN6"); - plen = mask2len(&ifr.ifr_addr.sin6_addr, 16); + /*NOTREACHED*/ + } + plen = sin6mask2len(&ifr.ifr_addr); if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) { /* same interface found */ /* need check if something changed */ @@ -1398,8 +1467,10 @@ ifconfig1(name, sa, ifcp, s) /* * New address is found */ - if ((ifa = MALLOC(struct ifac)) == NULL) + if ((ifa = MALLOC(struct ifac)) == NULL) { fatal("malloc: struct ifac"); + /*NOTREACHED*/ + } memset(ifa, 0, sizeof(*ifa)); ifa->ifa_conf = ifcp; ifa->ifa_next = ifcp->ifc_addr; @@ -1408,8 +1479,10 @@ ifconfig1(name, sa, ifcp, s) ifa->ifa_plen = plen; if (ifcp->ifc_flags & IFF_POINTOPOINT) { ifr.ifr_addr = *sin; - if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) + if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { fatal("ioctl: SIOCGIFDSTADDR_IN6"); + /*NOTREACHED*/ + } ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); trace(1, "found address %s/%d -- %s\n", @@ -1428,12 +1501,15 @@ ifconfig1(name, sa, ifcp, s) ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); if (ifcp->ifc_mtu > RIP6_MAXMTU) ifcp->ifc_mtu = RIP6_MAXMTU; - if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) + if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { fatal("ioctl: SIOCGIFMETRIC"); + /*NOTREACHED*/ + } ifcp->ifc_metric = ifr.ifr_metric; trace(1, "\tindex: %d, mtu: %d, metric: %d\n", ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); - } + } else + ifcp->ifc_cflags |= IFC_CHANGED; } /* @@ -1449,14 +1525,16 @@ rtrecv() struct ifa_msghdr *ifam; struct if_msghdr *ifm; int len; - struct ifc *ifcp; + struct ifc *ifcp, *ic; int iface = 0, rtable = 0; struct sockaddr_in6 *rta[RTAX_MAX]; + struct sockaddr_in6 mask; int i, addrs; + struct riprt *rrt; if ((len = read(rtsock, buf, sizeof(buf))) < 0) { perror("read from rtsock"); - exit(-1); + exit(1); } if (len < sizeof(*rtm)) { trace(1, "short read from rtsock: %d (should be > %lu)\n", @@ -1515,7 +1593,6 @@ rtrecv() trace(1, "rtsock: %s (addrs=%x)\n", rttypes((struct rt_msghdr *)p), addrs); if (dflag >= 2) { - int i; for (i = 0; i < ((struct rt_msghdr *)p)->rtm_msglen; i++) { @@ -1584,13 +1661,25 @@ rtrecv() case RTM_LOCK: /* should already be handled */ fatal("rtrecv: never reach here"); + /*NOTREACHED*/ case RTM_DELETE: - if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY] - || !rta[RTAX_NETMASK]) { - trace(1, "\tsome of dst/gw/netamsk are unavailable, ignored\n"); + if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { + trace(1, "\tsome of dst/gw/netamsk are " + "unavailable, ignored\n"); + break; + } + if ((rtm->rtm_flags & RTF_HOST) != 0) { + mask.sin6_len = sizeof(mask); + memset(&mask.sin6_addr, 0xff, + sizeof(mask.sin6_addr)); + rta[RTAX_NETMASK] = &mask; + } else if (!rta[RTAX_NETMASK]) { + trace(1, "\tsome of dst/gw/netamsk are " + "unavailable, ignored\n"); break; } - if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], rta[RTAX_NETMASK]) == 0) { + if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], + rta[RTAX_NETMASK]) == 0) { rtable++; /*just to be sure*/ } break; @@ -1612,8 +1701,8 @@ rtrecv() ifam->ifam_index); break; } - rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]); - iface++; + if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) + iface++; break; case RTM_OLDADD: case RTM_OLDDEL: @@ -1627,7 +1716,21 @@ rtrecv() trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); ifconfig(); for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) - ifrt(ifcp, 1); + if (ifcp->ifc_cflags & IFC_CHANGED) { + if (ifrt(ifcp, 1)) { + for (ic = ifc; ic; ic = ic->ifc_next) { + if (ifcp->ifc_index == ic->ifc_index) + continue; + if (ic->ifc_flags & IFF_UP) + ripsend(ic, &ic->ifc_ripsin, + RRTF_CHANGED); + } + /* Reset the flag */ + for (rrt = riprt; rrt; rrt = rrt->rrt_next) + rrt->rrt_rflags &= ~RRTF_CHANGED; + } + ifcp->ifc_cflags &= ~IFC_CHANGED; + } } if (rtable) { trace(1, "rtsock: read routing table again\n"); @@ -1663,11 +1766,10 @@ rt_del(sdst, sgw, smask) return -1; } dst = &sdst->sin6_addr; - if (sgw->sin6_family == AF_INET6 - && smask->sin6_family == AF_INET6) { + if (sgw->sin6_family == AF_INET6) { /* easy case */ gw = &sgw->sin6_addr; - prefix = mask2len(&smask->sin6_addr, 16); + prefix = sin6mask2len(smask); } else if (sgw->sin6_family == AF_LINK) { /* * Interface route... a hard case. We need to get the prefix @@ -1698,8 +1800,7 @@ rt_del(sdst, sgw, smask) gw = &in6addr_loopback; prefix = rrt->rrt_info.rip6_plen; } else { - trace(1, "\tunsupported af: (gw=%d, mask=%d)\n", - sgw->sin6_family, smask->sin6_family); + trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); return -1; } @@ -1713,13 +1814,16 @@ rt_del(sdst, sgw, smask) applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen); - if (!rrt && (rrt = rtsearch(&ni6)) == NULL) { + if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { trace(1, "\tno route found\n"); return -1; } +#if 0 if ((rrt->rrt_flags & RTF_STATIC) == 0) { trace(1, "\tyou can delete static routes only\n"); - } else if (memcmp(&rrt->rrt_gw, gw, sizeof(rrt->rrt_gw)) != 0) { + } else +#endif + if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { trace(1, "\tgw mismatch: %s <-> ", inet6_n2p(&rrt->rrt_gw)); trace(1, "%s\n", inet6_n2p(gw)); @@ -1750,12 +1854,12 @@ rt_deladdr(ifcp, sifa, smask) time_t t_lifetime; int updated = 0; - if (sifa->sin6_family != AF_INET6 || smask->sin6_family != AF_INET6) { + if (sifa->sin6_family != AF_INET6) { trace(1, "\tother AF, ignored\n"); return -1; } addr = &sifa->sin6_addr; - prefix = mask2len(&smask->sin6_addr, 16); + prefix = sin6mask2len(smask); trace(1, "\tdeleting %s/%d from %s\n", inet6_n2p(addr), prefix, ifcp->ifc_name); @@ -1793,11 +1897,12 @@ rt_deladdr(ifcp, sifa, smask) applyplen(&ni6.rip6_dest, ni6.rip6_plen); trace(1, "\tfind interface route %s/%d on %d\n", inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); - if ((rrt = rtsearch(&ni6)) != NULL) { + if ((rrt = rtsearch(&ni6, NULL)) != NULL) { struct in6_addr none; memset(&none, 0, sizeof(none)); - if (rrt->rrt_index == ifcp->ifc_index - && memcmp(&rrt->rrt_gw, &none, sizeof(rrt->rrt_gw)) == 0) { + if (rrt->rrt_index == ifcp->ifc_index && + (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || + IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { trace(1, "\troute found, age it\n"); if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { rrt->rrt_t = t_lifetime; @@ -1821,15 +1926,14 @@ rt_deladdr(ifcp, sifa, smask) trace(1, "\tfind p2p route %s/%d on %d\n", inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); - if ((rrt = rtsearch(&ni6)) != NULL) { - if (rrt->rrt_index == ifcp->ifc_index - && memcmp(&rrt->rrt_gw, &ifa->ifa_addr, - sizeof(rrt->rrt_gw)) == 0) { + if ((rrt = rtsearch(&ni6, NULL)) != NULL) { + if (rrt->rrt_index == ifcp->ifc_index && + IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { trace(1, "\troute found, age it\n"); if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { rrt->rrt_t = t_lifetime; rrt->rrt_info.rip6_metric = - HOPCNT_INFINITY6; + HOPCNT_INFINITY6; updated++; } } else { @@ -1848,20 +1952,22 @@ rt_deladdr(ifcp, sifa, smask) * Get each interface address and put those interface routes to the route * list. */ -void +int ifrt(ifcp, again) struct ifc *ifcp; int again; { struct ifac *ifa; - struct riprt *rrt; + struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt; struct netinfo6 *np; + time_t t_lifetime; + int need_trigger = 0; if (ifcp->ifc_flags & IFF_LOOPBACK) - return; /* ignore loopback */ + return 0; /* ignore loopback */ if (ifcp->ifc_flags & IFF_POINTOPOINT) { ifrt_p2p(ifcp, again); - return; + return 0; } for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { @@ -1880,37 +1986,73 @@ ifrt(ifcp, again) #endif continue; } - if ((rrt = MALLOC(struct riprt)) == NULL) - fatal("malloc: struct riprt"); - memset(rrt, 0, sizeof(*rrt)); - rrt->rrt_same = NULL; - rrt->rrt_index = ifcp->ifc_index; - rrt->rrt_t = 0; /* don't age */ - rrt->rrt_info.rip6_dest = ifa->ifa_addr; - rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); - rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; - rrt->rrt_info.rip6_plen = ifa->ifa_plen; - applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); - memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); - np = &rrt->rrt_info; - if (rtsearch(np) == NULL) { + if (ifcp->ifc_flags & IFF_UP) { + if ((rrt = MALLOC(struct riprt)) == NULL) + fatal("malloc: struct riprt"); + memset(rrt, 0, sizeof(*rrt)); + rrt->rrt_same = NULL; + rrt->rrt_index = ifcp->ifc_index; + rrt->rrt_t = 0; /* don't age */ + rrt->rrt_info.rip6_dest = ifa->ifa_addr; + rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); + rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; + rrt->rrt_info.rip6_plen = ifa->ifa_plen; + rrt->rrt_flags = RTF_CLONING; + rrt->rrt_rflags |= RRTF_CHANGED; + applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); + memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); +#if 0 + /* XXX why gateway address == network adddress? */ + rrt->rrt_gw = ifa->ifa_addr; +#endif + np = &rrt->rrt_info; + search_rrt = rtsearch(np, &prev_rrt); + if (search_rrt != NULL) { + if (search_rrt->rrt_info.rip6_metric > + rrt->rrt_info.rip6_metric) { + if (prev_rrt) + prev_rrt->rrt_next = rrt->rrt_next; + else + riprt = rrt->rrt_next; + delroute(&rrt->rrt_info, &rrt->rrt_gw); + free(rrt); + } else { + /* Already have better route */ + if (!again) { + trace(1, "route: %s/%d: " + "already registered (%s)\n", + inet6_n2p(&np->rip6_dest), np->rip6_plen, + ifcp->ifc_name); + } + free(rrt); + continue; + } + } /* Attach the route to the list */ trace(1, "route: %s/%d: register route (%s)\n", inet6_n2p(&np->rip6_dest), np->rip6_plen, ifcp->ifc_name); rrt->rrt_next = riprt; riprt = rrt; + addroute(rrt, &rrt->rrt_gw, ifcp); + sendrequest(ifcp); + ripsend(ifcp, &ifcp->ifc_ripsin, 0); + need_trigger = 1; } else { - /* Already found */ - if (!again) { - trace(1, "route: %s/%d: " - "already registered (%s)\n", - inet6_n2p(&np->rip6_dest), np->rip6_plen, - ifcp->ifc_name); + for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { + if (loop_rrt->rrt_index == ifcp->ifc_index) { + t_lifetime = time(NULL) - RIP_LIFETIME; + if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { + loop_rrt->rrt_t = t_lifetime; + loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; + loop_rrt->rrt_rflags |= RRTF_CHANGED; + need_trigger = 1; + } + } } - free(rrt); - } + } } + return need_trigger; } /* @@ -1924,7 +2066,7 @@ ifrt_p2p(ifcp, again) int again; { struct ifac *ifa; - struct riprt *rrt; + struct riprt *rrt, *orrt, *prevrrt; struct netinfo6 *np; struct in6_addr addr, dest; int advert, ignore, i; @@ -1933,7 +2075,7 @@ ifrt_p2p(ifcp, again) #define P2PADVERT_DEST 4 #define P2PADVERT_MAX 4 const enum { CISCO, GATED, ROUTE6D } behavior = GATED; - const char *category; + const char *category = ""; const char *noadv; for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { @@ -1961,6 +2103,10 @@ ifrt_p2p(ifcp, again) * do not install network route to route6d routing * table (if we do, it would prevent route installation * for other p2p interface that shares addr/plen). + * + * XXX what should we do if dest is ::? it will not + * get announced anyways (see following filter), + * but we need to think. */ advert |= P2PADVERT_ADDR; advert |= P2PADVERT_DEST; @@ -1968,23 +2114,39 @@ ifrt_p2p(ifcp, again) break; case ROUTE6D: /* - * just for testing... + * just for testing. actually the code is redundant + * given the current p2p interface address assignment + * rule for kame kernel. + * + * intent: + * A/n -> announce A/n + * A B/n, A and B share prefix -> A/n (= B/n) + * A B/n, do not share prefix -> A/128 and B/128 + * actually, A/64 and A B/128 are the only cases + * permitted by the kernel: + * A/64 -> A/64 + * A B/128 -> A/128 and B/128 */ - if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) + if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { + if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) + advert |= P2PADVERT_NETWORK; + else { + advert |= P2PADVERT_ADDR; + advert |= P2PADVERT_DEST; + ignore |= P2PADVERT_NETWORK; + } + } else advert |= P2PADVERT_NETWORK; - else { - advert |= P2PADVERT_ADDR; - advert |= P2PADVERT_DEST; - ignore |= P2PADVERT_NETWORK; - } break; } for (i = 1; i <= P2PADVERT_MAX; i *= 2) { if ((ignore & i) != 0) continue; - if ((rrt = MALLOC(struct riprt)) == NULL) + if ((rrt = MALLOC(struct riprt)) == NULL) { fatal("malloc: struct riprt"); + /*NOTREACHED*/ + } memset(rrt, 0, sizeof(*rrt)); rrt->rrt_same = NULL; rrt->rrt_index = ifcp->ifc_index; @@ -2000,11 +2162,13 @@ ifrt_p2p(ifcp, again) case P2PADVERT_ADDR: rrt->rrt_info.rip6_dest = ifa->ifa_addr; rrt->rrt_info.rip6_plen = 128; + rrt->rrt_gw = in6addr_loopback; category = "addr"; break; case P2PADVERT_DEST: rrt->rrt_info.rip6_dest = ifa->ifa_raddr; rrt->rrt_info.rip6_plen = 128; + rrt->rrt_gw = ifa->ifa_addr; category = "dest"; break; } @@ -2024,9 +2188,9 @@ ifrt_p2p(ifcp, again) noadv = ""; rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; - memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); np = &rrt->rrt_info; - if (rtsearch(np) == NULL) { + orrt = rtsearch(np, &prevrrt); + if (!orrt) { /* Attach the route to the list */ trace(1, "route: %s/%d: register route " "(%s on %s%s)\n", @@ -2034,6 +2198,19 @@ ifrt_p2p(ifcp, again) category, ifcp->ifc_name, noadv); rrt->rrt_next = riprt; riprt = rrt; + } else if (rrt->rrt_index != orrt->rrt_index || + rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { + /* swap route */ + rrt->rrt_next = orrt->rrt_next; + if (prevrrt) + prevrrt->rrt_next = rrt; + else + riprt = rrt; + free(orrt); + + trace(1, "route: %s/%d: update (%s on %s%s)\n", + inet6_n2p(&np->rip6_dest), np->rip6_plen, + category, ifcp->ifc_name, noadv); } else { /* Already found */ if (!again) { @@ -2069,18 +2246,26 @@ getifmtu(ifindex) mib[3] = AF_INET6; mib[4] = NET_RT_IFLIST; mib[5] = ifindex; - if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) + if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { fatal("sysctl estimate NET_RT_IFLIST"); - if ((buf = malloc(msize)) == NULL) + /*NOTREACHED*/ + } + if ((buf = malloc(msize)) == NULL) { fatal("malloc"); - if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) + /*NOTREACHED*/ + } + if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { fatal("sysctl NET_RT_IFLIST"); + /*NOTREACHED*/ + } ifm = (struct if_msghdr *)buf; mtu = ifm->ifm_data.ifi_mtu; -#ifdef __FREEBSD__ - if (ifindex != ifm->ifm_index) +#ifdef __FreeBSD__ + if (ifindex != ifm->ifm_index) { fatal("ifindex does not match with ifm_index"); -#endif /* __FREEBSD__ */ + /*NOTREACHED*/ + } +#endif free(buf); return mtu; } @@ -2108,6 +2293,24 @@ do { \ RTTYPE("NEWADDR", RTM_NEWADDR); RTTYPE("DELADDR", RTM_DELADDR); RTTYPE("IFINFO", RTM_IFINFO); +#ifdef RTM_OLDADD + RTTYPE("OLDADD", RTM_OLDADD); +#endif +#ifdef RTM_OLDDEL + RTTYPE("OLDDEL", RTM_OLDDEL); +#endif +#ifdef RTM_OIFINFO + RTTYPE("OIFINFO", RTM_OIFINFO); +#endif +#ifdef RTM_IFANNOUNCE + RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); +#endif +#ifdef RTM_NEWMADDR + RTTYPE("NEWMADDR", RTM_NEWMADDR); +#endif +#ifdef RTM_DELMADDR + RTTYPE("DELMADDR", RTM_DELMADDR); +#endif #undef RTTYPE return NULL; } @@ -2118,11 +2321,14 @@ rtflags(rtm) { static char buf[BUFSIZ]; - strcpy(buf, ""); + /* + * letter conflict should be okay. painful when *BSD diverges... + */ + strlcpy(buf, "", sizeof(buf)); #define RTFLAG(s, f) \ do { \ if (rtm->rtm_flags & (f)) \ - strcat(buf, (s)); \ + strlcat(buf, (s), sizeof(buf)); \ } while (0) RTFLAG("U", RTF_UP); RTFLAG("G", RTF_GATEWAY); @@ -2135,12 +2341,42 @@ do { \ RTFLAG("m", RTF_MASK); #endif RTFLAG("C", RTF_CLONING); +#ifdef RTF_CLONED + RTFLAG("c", RTF_CLONED); +#endif +#ifdef RTF_PRCLONING + RTFLAG("c", RTF_PRCLONING); +#endif +#ifdef RTF_WASCLONED + RTFLAG("W", RTF_WASCLONED); +#endif RTFLAG("X", RTF_XRESOLVE); RTFLAG("L", RTF_LLINFO); RTFLAG("S", RTF_STATIC); RTFLAG("B", RTF_BLACKHOLE); +#ifdef RTF_PROTO3 + RTFLAG("3", RTF_PROTO3); +#endif RTFLAG("2", RTF_PROTO2); RTFLAG("1", RTF_PROTO1); +#ifdef RTF_BROADCAST + RTFLAG("b", RTF_BROADCAST); +#endif +#ifdef RTF_DEFAULT + RTFLAG("d", RTF_DEFAULT); +#endif +#ifdef RTF_ISAROUTER + RTFLAG("r", RTF_ISAROUTER); +#endif +#ifdef RTF_TUNNEL + RTFLAG("T", RTF_TUNNEL); +#endif +#ifdef RTF_AUTH + RTFLAG("A", RTF_AUTH); +#endif +#ifdef RTF_CRYPT + RTFLAG("E", RTF_CRYPT); +#endif #undef RTFLAG return buf; } @@ -2151,13 +2387,13 @@ ifflags(flags) { static char buf[BUFSIZ]; - strcpy(buf, ""); + strlcpy(buf, "", sizeof(buf)); #define IFFLAG(s, f) \ do { \ if (flags & f) { \ if (buf[0]) \ - strcat(buf, ","); \ - strcat(buf, s); \ + strlcat(buf, ",", sizeof(buf)); \ + strlcat(buf, s, sizeof(buf)); \ } \ } while (0) IFFLAG("UP", IFF_UP); @@ -2168,6 +2404,9 @@ do { \ #ifdef IFF_NOTRAILERS IFFLAG("NOTRAILERS", IFF_NOTRAILERS); #endif +#ifdef IFF_SMART + IFFLAG("SMART", IFF_SMART); +#endif IFFLAG("RUNNING", IFF_RUNNING); IFFLAG("NOARP", IFF_NOARP); IFFLAG("PROMISC", IFF_PROMISC); @@ -2219,10 +2458,11 @@ krtread(again) continue; } } while (retry < 5 && errmsg != NULL); - if (errmsg) + if (errmsg) { fatal("%s (with %d retries, msize=%lu)", errmsg, retry, (u_long)msize); - else if (1 < retry) + /*NOTREACHED*/ + } else if (1 < retry) syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); lim = buf + msize; @@ -2241,7 +2481,7 @@ rt_entry(rtm, again) struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; struct sockaddr_in6 *sin6_genmask, *sin6_ifp; char *rtmp, *ifname = NULL; - struct riprt *rrt; + struct riprt *rrt, *orrt; struct netinfo6 *np; int s; @@ -2298,8 +2538,10 @@ rt_entry(rtm, again) if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) return; - if ((rrt = MALLOC(struct riprt)) == NULL) + if ((rrt = MALLOC(struct riprt)) == NULL) { fatal("malloc: struct riprt"); + /*NOTREACHED*/ + } memset(rrt, 0, sizeof(*rrt)); np = &rrt->rrt_info; rrt->rrt_same = NULL; @@ -2320,13 +2562,13 @@ rt_entry(rtm, again) /* Mask or plen */ if (rtm->rtm_flags & RTF_HOST) np->rip6_plen = 128; /* Host route */ - else if (sin6_mask) { - np->rip6_plen = mask2len(&sin6_mask->sin6_addr, - sin6_mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); - } else + else if (sin6_mask) + np->rip6_plen = sin6mask2len(sin6_mask); + else np->rip6_plen = 0; - if (rtsearch(np)) { + orrt = rtsearch(np, NULL); + if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { /* Already found */ if (!again) { trace(1, "route: %s/%d flags %s: already registered\n", @@ -2381,8 +2623,18 @@ rt_entry(rtm, again) } /* Put it to the route list */ - rrt->rrt_next = riprt; - riprt = rrt; + if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { + /* replace route list */ + rrt->rrt_next = orrt->rrt_next; + *orrt = *rrt; + trace(1, "route: %s/%d flags %s: replace new route\n", + inet6_n2p(&np->rip6_dest), np->rip6_plen, + rtflags(rtm)); + free(rrt); + } else { + rrt->rrt_next = riprt; + riprt = rrt; + } } int @@ -2398,7 +2650,7 @@ addroute(rrt, gw, ifcp) int len; np = &rrt->rrt_info; - inet_ntop(AF_INET6, (void *)gw, (char *)buf1, sizeof(buf1)); + inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, @@ -2484,6 +2736,8 @@ delroute(np, gw) rtm->rtm_seq = ++seq; rtm->rtm_pid = pid; rtm->rtm_flags = RTF_UP | RTF_GATEWAY; + if (np->rip6_plen == sizeof(struct in6_addr) * 8) + rtm->rtm_flags |= RTF_HOST; rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; /* Destination */ @@ -2551,12 +2805,12 @@ getroute(np, gw) if (errno == ESRCH) /* No such route found */ return NULL; perror("write to rtsock"); - exit(-1); + exit(1); } do { if ((len = read(rtsock, buf, sizeof(buf))) < 0) { perror("read from rtsock"); - exit(-1); + exit(1); } rtm = (struct rt_msghdr *)buf; } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); @@ -2578,7 +2832,7 @@ inet6_n2p(p) { static char buf[BUFSIZ]; - return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf)); + return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); } void @@ -2662,7 +2916,7 @@ ifdump0(dump, ifcp) case 'A': ft = "Aggregate"; addr++; break; case 'N': - ft = "No-advertise"; break; + ft = "No-use"; break; case 'O': ft = "Advertise-only"; addr++; break; case 'T': @@ -2731,7 +2985,7 @@ rtdump(sig) /* * Parse the -A (and -O) options and put corresponding filter object to the - * specified interface structures. Each of the -A/O option has the following + * specified interface structures. Each of the -A/O option has the following * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) * -O 5f09:c400::/32,ef0,ef1 (only when match) */ @@ -2740,11 +2994,11 @@ filterconfig() { int i; char *p, *ap, *iflp, *ifname; - struct iff ftmp, *iff_obj; - struct ifc *ifcp; - struct riprt *rrt; + struct iff ftmp, *iff_obj; + struct ifc *ifcp; + struct riprt *rrt; #if 0 - struct in6_addr gw; + struct in6_addr gw; #endif for (i = 0; i < nfilter; i++) { @@ -2759,41 +3013,57 @@ filterconfig() *p++ = '\0'; iflp = p; } - if ((p = index(ap, '/')) == NULL) + if ((p = index(ap, '/')) == NULL) { fatal("no prefixlen specified for '%s'", ap); + /*NOTREACHED*/ + } *p++ = '\0'; - if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) + if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { fatal("invalid prefix specified for '%s'", ap); + /*NOTREACHED*/ + } ftmp.iff_plen = atoi(p); ftmp.iff_next = NULL; applyplen(&ftmp.iff_addr, ftmp.iff_plen); ifonly: ftmp.iff_type = filtertype[i]; - if (iflp == NULL || *iflp == '\0') + if (iflp == NULL || *iflp == '\0') { fatal("no interface specified for '%s'", ap); + /*NOTREACHED*/ + } /* parse the interface listing portion */ while (iflp) { ifname = iflp; if ((iflp = index(iflp, ',')) != NULL) *iflp++ = '\0'; ifcp = ifc_find(ifname); - if (ifcp == NULL) + if (ifcp == NULL) { fatal("no interface %s exists", ifname); + /*NOTREACHED*/ + } iff_obj = (struct iff *)malloc(sizeof(struct iff)); - if (iff_obj == NULL) + if (iff_obj == NULL) { fatal("malloc of iff_obj"); + /*NOTREACHED*/ + } memcpy((void *)iff_obj, (void *)&ftmp, - sizeof(struct iff)); + sizeof(struct iff)); /* link it to the interface filter */ iff_obj->iff_next = ifcp->ifc_filter; ifcp->ifc_filter = iff_obj; } + + /* + * -A: aggregate configuration. + */ if (filtertype[i] != 'A') continue; /* put the aggregate to the kernel routing table */ rrt = (struct riprt *)malloc(sizeof(struct riprt)); - if (rrt == NULL) + if (rrt == NULL) { fatal("malloc: rrt"); + /*NOTREACHED*/ + } memset(rrt, 0, sizeof(struct riprt)); rrt->rrt_info.rip6_dest = ftmp.iff_addr; rrt->rrt_info.rip6_plen = ftmp.iff_plen; @@ -2813,12 +3083,13 @@ ifonly: */ delroute(&rrt->rrt_info, &gw); #else - /* it is more safe behavior */ + /* it is safer behavior */ errno = EINVAL; fatal("%s/%u already in routing table, " "cannot aggregate", inet6_n2p(&rrt->rrt_info.rip6_dest), rrt->rrt_info.rip6_plen); + /*NOTREACHED*/ #endif } #endif @@ -2860,31 +3131,46 @@ ifa_match(ifcp, ia, plen) /* * Return a pointer to riprt structure whose address and prefix length * matches with the address and prefix length found in the argument. - * Note: This is not a rtalloc(). Therefore exact match is necessary. + * Note: This is not a rtalloc(). Therefore exact match is necessary. */ - struct riprt * -rtsearch(np) +rtsearch(np, prev_rrt) struct netinfo6 *np; + struct riprt **prev_rrt; { struct riprt *rrt; + if (prev_rrt) + *prev_rrt = NULL; for (rrt = riprt; rrt; rrt = rrt->rrt_next) { if (rrt->rrt_info.rip6_plen == np->rip6_plen && IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, &np->rip6_dest)) return rrt; + if (prev_rrt) + *prev_rrt = rrt; } + if (prev_rrt) + *prev_rrt = NULL; return 0; } int +sin6mask2len(sin6) + const struct sockaddr_in6 *sin6; +{ + + return mask2len(&sin6->sin6_addr, + sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); +} + +int mask2len(addr, lenlim) const struct in6_addr *addr; int lenlim; { int i = 0, j; - u_char *p = (u_char *)addr; + const u_char *p = (const u_char *)addr; for (j = 0; j < lenlim; j++, p++) { if (*p != 0xff) @@ -2984,9 +3270,12 @@ hms() struct tm *tm; t = time(NULL); - if ((tm = localtime(&t)) == 0) + if ((tm = localtime(&t)) == 0) { fatal("localtime"); - snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + /*NOTREACHED*/ + } + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, + tm->tm_sec); return buf; } @@ -3010,7 +3299,7 @@ ripsuptrig() double r = rand(); t = (int)(RIP_TRIG_INT6_MIN + - (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX )); + (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); sup_trig_update = time(NULL) + t; return t; } @@ -3035,7 +3324,7 @@ fatal(fmt, va_alist) vsnprintf(buf, sizeof(buf), fmt, ap); perror(buf); syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); - rtdexit(0); + rtdexit(); va_end(ap); } @@ -3140,8 +3429,8 @@ iff_find(ifcp, type) } void -setindex2ifc(index, ifcp) - int index; +setindex2ifc(idx, ifcp) + int idx; struct ifc *ifcp; { int n; @@ -3151,19 +3440,24 @@ setindex2ifc(index, ifcp) nindex2ifc = 5; /*initial guess*/ index2ifc = (struct ifc **) malloc(sizeof(*index2ifc) * nindex2ifc); - if (index2ifc == NULL) + if (index2ifc == NULL) { fatal("malloc"); + /*NOTREACHED*/ + } memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); } n = nindex2ifc; - while (nindex2ifc <= index) + while (nindex2ifc <= idx) nindex2ifc *= 2; if (n != nindex2ifc) { p = (struct ifc **)realloc(index2ifc, sizeof(*index2ifc) * nindex2ifc); - if (p == NULL) + if (p == NULL) { fatal("realloc"); + /*NOTREACHED*/ + } + memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); index2ifc = p; } - index2ifc[index] = ifcp; + index2ifc[idx] = ifcp; } diff --git a/usr.sbin/route6d/route6d.h b/usr.sbin/route6d/route6d.h index b3a353f..5c59d6a 100644 --- a/usr.sbin/route6d/route6d.h +++ b/usr.sbin/route6d/route6d.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: route6d.h,v 1.3 2000/02/25 06:15:06 itojun Exp $ */ +/* $KAME: route6d.h,v 1.4 2001/01/15 03:50:54 inoue Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -42,6 +42,8 @@ #define RIP6_REQUEST 1 #define RIP6_RESPONSE 2 +#define IFC_CHANGED 1 + struct netinfo6 { struct in6_addr rip6_dest; u_short rip6_tag; diff --git a/usr.sbin/rrenumd/lexer.l b/usr.sbin/rrenumd/lexer.l index d906b0c..6ad9953 100644 --- a/usr.sbin/rrenumd/lexer.l +++ b/usr.sbin/rrenumd/lexer.l @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: lexer.l,v 1.7 2000/11/08 02:40:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,9 +32,12 @@ */ %{ +#define YY_NO_UNPUT + #include <sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> +#include <sys/queue.h> #include <string.h> @@ -55,6 +58,10 @@ int lineno = 1; #define LINEBUF_SIZE 1000 char linebuf[LINEBUF_SIZE]; + +int parse __P((FILE **)); +void yyerror __P((const char *)); +int yylex __P((void)); %} /* common section */ @@ -248,9 +255,11 @@ off { int parse(FILE **fp) { + extern int yyparse __P((void)); + yyin = *fp; - if(yyparse()) + if (yyparse()) return(-1); return(0); diff --git a/usr.sbin/rrenumd/parser.y b/usr.sbin/rrenumd/parser.y index 15ca06d..0cfe3b5 100644 --- a/usr.sbin/rrenumd/parser.y +++ b/usr.sbin/rrenumd/parser.y @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: parser.y,v 1.8 2000/11/08 03:03:34 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -36,6 +36,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/uio.h> +#include <sys/queue.h> #include <net/if.h> #if defined(__FreeBSD__) && __FreeBSD__ >= 3 @@ -48,6 +49,7 @@ #include <netdb.h> #include <string.h> +#include <stdio.h> #include "rrenumd.h" @@ -62,6 +64,7 @@ char errbuf[LINE_MAX]; extern int lineno; extern void yyerror __P((const char *s)); +extern int yylex __P((void)); static struct payload_list * pllist_lookup __P((int seqnum)); static void pllist_enqueue __P((struct payload_list *pl_entry)); @@ -192,8 +195,9 @@ dest_addr : 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)); + snprintf(errbuf, sizeof(errbuf), + "name resolution failed for %s:%s", + $1.cp, gai_strerror(error)); yyerror(errbuf); } ss = (struct sockaddr_storage *)malloc(sizeof(*ss)); @@ -274,8 +278,9 @@ rrenum_statement_with_seqnum: SEQNUM_CMD seqnum { if (pllist_lookup($2)) { - sprintf(errbuf, "duplicate seqnum %d specified" - " at %d", $2, lineno); + snprintf(errbuf, sizeof(errbuf), + "duplicate seqnum %ld specified at %d", + $2, lineno); yyerror(errbuf); } } @@ -294,9 +299,10 @@ seqnum: | decstring { if ($1 > MAX_SEQNUM) { - sprintf(errbuf, "seqnum %d is illegal for this" - " program. should be between 0 and %d", - $1, MAX_SEQNUM); + snprintf(errbuf, sizeof(errbuf), + "seqnum %ld is illegal for this program. " + "should be between 0 and %d", + $1, MAX_SEQNUM); yyerror(errbuf); } $$ = $1; @@ -307,8 +313,9 @@ rrenum_statement_without_seqnum: rrenum_statement EOS { if (pllist_lookup(0)) { - sprintf(errbuf, "duplicate seqnum %d specified" - " at %d", 0, lineno); + snprintf(errbuf, sizeof(errbuf), + "duplicate seqnum %d specified at %d", + 0, lineno); yyerror(errbuf); } $1->pl_irr.rr_seqnum = 0; @@ -435,8 +442,8 @@ use_prefix_values: rpu = (struct rr_pco_use *)(rpm + 1); memset(rpu, 0, sizeof(*rpu)); - rpu->rpu_vltime = DEF_VLTIME; - rpu->rpu_pltime = DEF_PLTIME; + rpu->rpu_vltime = htonl(DEF_VLTIME); + rpu->rpu_pltime = htonl(DEF_PLTIME); rpu->rpu_ramask = 0; rpu->rpu_flags = 0; } @@ -510,7 +517,7 @@ keeplen: vltime: /* empty */ { - $$ = DEF_VLTIME; + $$ = htonl(DEF_VLTIME); } | VLTIME_CMD lifetime { @@ -521,7 +528,7 @@ vltime: pltime: /* empty */ { - $$ = DEF_PLTIME; + $$ = htonl(DEF_PLTIME); } | PLTIME_CMD lifetime { @@ -573,8 +580,8 @@ raf_decrprefd: ; flag: - ON - | OFF + ON { $$ = ON; } + | OFF { $$ = OFF; } ; lifetime: @@ -653,15 +660,16 @@ static void pllist_enqueue(struct payload_list *pl_entry) { struct payload_list *pl, *pl_last; - if (pl_head == NULL) { - pl_head = pl_entry; - return; - } + + pl_last = NULL; 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; + if (pl_last) + pl_last->pl_next = pl_entry; + else + pl_head = pl_entry; return; } diff --git a/usr.sbin/rrenumd/rrenumd.8 b/usr.sbin/rrenumd/rrenumd.8 index 42ea29d..09e3089 100644 --- a/usr.sbin/rrenumd/rrenumd.8 +++ b/usr.sbin/rrenumd/rrenumd.8 @@ -1,4 +1,4 @@ -.\" $KAME$ +.\" $KAME: rrenumd.8,v 1.6 2001/01/22 02:06:24 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -37,13 +37,19 @@ .Nd router renumbering daemon .Sh SYNOPSIS .Nm +.Op Fl df .Oo .Fl c Ar conf_file | Fl s .Oc -.Op Fl df .Sh DESCRIPTION -.Nm Rrenumd -assigns prefixes to subnets inside the site, or renumbers them. +.Nm +transmits router renumbering request packets, +to renumber the routers in the site network. +.Pp +On KAME-based systems, +router renumbering requests are received and processed by +.Xr rtadvd 8 . +For other systems, refer to relevant documents. .Pp The program will daemonize itself on invocation. It reads configuration information from standard input if @@ -78,8 +84,16 @@ Specify a configuration file where configuration information is kept. .Sh RETURN VALUES The program exits with 0 on success, and non-zero on failures. .Sh SEE ALSO -.Xr daemon 3 , -.Xr rrenumd.conf 5 +.Xr rrenumd.conf 5 , +.Xr rtadvd 8 +.Sh STANDARDS +.Rs +.%A Matt Crawford +.%R RFC +.%N 2894 +.%D August 2000 +.%T "Router Renumbering for IPv6" +.Re .Sh HISTORY The .Nm diff --git a/usr.sbin/rrenumd/rrenumd.c b/usr.sbin/rrenumd/rrenumd.c index fa3257d..686a869 100644 --- a/usr.sbin/rrenumd/rrenumd.c +++ b/usr.sbin/rrenumd/rrenumd.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: rrenumd.c,v 1.20 2000/11/08 02:40:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,6 +64,8 @@ #define LL_ALLROUTERS "ff02::2" #define SL_ALLROUTERS "ff05::2" +#define RR_MCHLIM_DEFAULT 64 + #ifndef IN6_IS_SCOPE_LINKLOCAL #define IN6_IS_SCOPE_LINKLOCAL(a) \ ((IN6_IS_ADDR_LINKLOCAL(a)) || \ @@ -93,7 +95,30 @@ int with_v4dest, with_v6dest; struct in6_addr prefix; /* ADHOC */ int prefixlen = 64; /* ADHOC */ -extern int parse(FILE **fp); +extern int parse __P((FILE **)); + +static void show_usage __P((void)); +static void init_sin6 __P((struct sockaddr_in6 *, const char *)); +#if 0 +static void join_multi __P((const char *)); +#endif +static void init_globals __P((void)); +static void config __P((FILE **)); +#ifdef IPSEC_POLICY_IPSEC +static void sock6_open __P((struct flags *, char *)); +static void sock4_open __P((struct flags *, char *)); +#else +static void sock6_open __P((struct flags *)); +static void sock4_open __P((struct flags *)); +#endif +static void rrenum_output __P((struct payload_list *, struct dst_list *)); +static void rrenum_snd_eachdst __P((struct payload_list *)); +#if 0 +static void rrenum_snd_fullsequence __P((void)); +#endif +static void rrenum_input __P((int)); +int main __P((int, char *[])); + /* Print usage. Don't call this after daemonized. */ static void @@ -111,7 +136,7 @@ show_usage() exit(1); } -void +static void init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) { memset(sin6, 0, sizeof(*sin6)); @@ -122,7 +147,7 @@ init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) } #if 0 /* XXX: not necessary ?? */ -void +static void join_multi(const char *addrname) { struct ipv6_mreq mreq; @@ -151,7 +176,7 @@ join_multi(const char *addrname) } #endif -void +static void init_globals() { static struct iovec rcviov; @@ -193,7 +218,7 @@ init_globals() sndmhdr.msg_controllen = sndcmsglen; } -void +static void config(FILE **fpp) { struct payload_list *pl; @@ -236,7 +261,7 @@ config(FILE **fpp) } } -void +static void sock6_open(struct flags *flags #ifdef IPSEC_POLICY_IPSEC , char *policy @@ -297,7 +322,7 @@ sock6_open(struct flags *flags /* XXX should handle in/out bound policy. */ if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) - err(1, NULL); + err(1, "setsockopt(IPV6_IPSEC_POLICY)"); free(buf); } #else /* IPSEC_POLICY_IPSEC */ @@ -325,7 +350,7 @@ sock6_open(struct flags *flags return; } -void +static void sock4_open(struct flags *flags #ifdef IPSEC_POLICY_IPSEC , char *policy @@ -363,7 +388,7 @@ sock4_open(struct flags *flags /* XXX should handle in/out bound policy. */ if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) - err(1, NULL); + err(1, "setsockopt(IP_IPSEC_POLICY)"); free(buf); } #else /* IPSEC_POLICY_IPSEC */ @@ -391,7 +416,7 @@ sock4_open(struct flags *flags return; } -void +static void rrenum_output(struct payload_list *pl, struct dst_list *dl) { int i, msglen = 0; @@ -404,8 +429,8 @@ rrenum_output(struct payload_list *pl, struct dst_list *dl) sin6 = (struct sockaddr_in6 *)dl->dl_dst; if (sin6 != NULL && - IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { - int hoplimit = 255; + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + int hoplimit = RR_MCHLIM_DEFAULT; cm = CMSG_FIRSTHDR(&sndmhdr); /* specify the outgoing interface */ @@ -438,7 +463,7 @@ rrenum_output(struct payload_list *pl, struct dst_list *dl) strerror(errno)); } -void +static void rrenum_snd_eachdst(struct payload_list *pl) { struct dst_list *dl; @@ -448,7 +473,8 @@ rrenum_snd_eachdst(struct payload_list *pl) } } -void +#if 0 +static void rrenum_snd_fullsequence() { struct payload_list *pl; @@ -457,8 +483,9 @@ rrenum_snd_fullsequence() rrenum_snd_eachdst(pl); } } +#endif -void +static void rrenum_input(int s) { int i; @@ -603,9 +630,8 @@ main(int argc, char *argv[]) /* ADHOC: timeout each 30seconds */ memset(&timeout, 0, sizeof(timeout)); - timeout.tv_sec = 30; - /* init temporal payload_list and send_counter*/ + /* init temporary payload_list and send_counter*/ pl = pl_head; send_counter = retry + 1; while (1) { @@ -622,7 +648,9 @@ main(int argc, char *argv[]) exit(0); rrenum_snd_eachdst(pl); send_counter--; + timeout.tv_sec = 30; if (send_counter == 0) { + timeout.tv_sec = 0; pl = pl->pl_next; send_counter = retry + 1; } diff --git a/usr.sbin/rrenumd/rrenumd.conf.5 b/usr.sbin/rrenumd/rrenumd.conf.5 index 1fba85b..833bc6b 100644 --- a/usr.sbin/rrenumd/rrenumd.conf.5 +++ b/usr.sbin/rrenumd/rrenumd.conf.5 @@ -1,4 +1,4 @@ -.\" $KAME$ +.\" $KAME: rrenumd.conf.5,v 1.8 2001/02/06 02:17:23 jinmei Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -62,8 +62,8 @@ 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. +Curly braces (`{' and +`}') are used to group keywords and parameters when necessary. .\" .Sh Interface specification There are some statements that may or have to specify interface. @@ -84,7 +84,8 @@ then debugging is enabled, If .Ic off is specified, -then debugging is disabled. It is disabled by default. +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 @@ -102,12 +103,25 @@ specifies how many router renumbering messages are sent repeatedly. .El .It Op Ic add|change|setglobal .Cm match-prefix Ar match-prefix-val +.Bk -words .Op /match-prefix-len +.Ek +.Bk -words .Op Cm maxlen Ar maxlen-val +.Ek +.Bk -words .Op Cm minlen Ar minlen-val +.Ek +.Bk -words .Op Cm use-prefix Ar use-prefix-val +.Ek +.Bk -words .Op /use-prefix-len +.Ek +.Bk -words .Op Cm keeplen Ar keeplen-val +.Ek +.Bk -words .Op Ar use-prefix-values ; .Pp Specifies contents of sending router renumbering message with seqnum 0. @@ -121,11 +135,21 @@ has following syntax. .Pp { .Op Cm vltime Ar vltime-val +.Bk -words .Op Cm pltime Ar pltime-val +.Ek +.Bk -words .Op Cm raf_onlink Cm on|off +.Ek +.Bk -words .Op Cm raf_auto Cm on|off +.Ek +.Bk -words .Op Cm rrf_decrprefd Cm on|off +.Ek +.Bk -words .Op Cm rrf_decrvalid Cm on|off +.Ek } .Pp Each value has following meaning. @@ -163,7 +187,7 @@ 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 +Specify the medium part of .Ar use-prefix-val just next to the starting part specified by .Ar use-prefix-len @@ -180,7 +204,8 @@ 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 +"m" means minutes, "s" means seconds. +And alternatively, special keyword "infinity" can be also be specified. .It Cm pltime Ar pltime-val Assign an @@ -192,38 +217,49 @@ 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 +for the assigned interface. +If .Cm on -is specified, the prefix have on-link nature. (e.g. the prefix -belong to the link) If +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) +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 +for the prefix to be added. +If .Cm on is specified, autonomous address auto configuration is -enabled. If +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 +Enable or disable the decrementation of the pltime. +If .Cm on -is specified, decrementation of the pltime is enabled. If +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 +Enable or disable the decrementation of the vltime. +If .Cm on -is specified, decrementation of the vltime is enabled. If +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 +specific seqnum. +Multiple of this statement can be specified if they have different .Ar seqnum-val each other. @@ -234,19 +270,20 @@ has just same syntax with above add|change|setglobal statement. .Sh EXAMPLES 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) +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 +If you want to assign prefixes beginning with 3ffe:501:ffff::/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. +newly assigned 3ffe:501:ffff::/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; +add match-prefix fec0:0:0:: /48 use-prefix 3ffe:501:ffff:: /48 keeplen 16; .Ed .Pp .\" @@ -258,20 +295,21 @@ 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; +add match-prefix fec0:0:0:: /48 use-prefix 3ffe:501:ffff:: /48 keeplen 16; .Ed .Pp .\" If you are going to do renumbering, then following procedure will be natural. .Bl -enum -offset indent .It -Assigne new prefix. +Assign a new prefix. .It Set old prefix lifetimes to some appropriate transition -period. In the followng example we use 1 week for valid +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) +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. @@ -287,23 +325,24 @@ The following configuration file will do 1 and 2. dest ff05::2; seqnum 0 { - add match-prefix fec0:0:0:: /48 use-prefix fec0:2:2:: /48 keeplen 16; + add match-prefix fec0:0:0:: /48 use-prefix 3ffe:501:fffe:: /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; + change match-prefix 3ffe:501:ffff:: /48 use-prefix 3ffe:501:ffff:: /48 keeplen 16 vltime d7 pltime 0 rrf_decrvalid on rrf_decrprefd on; }; .Ed .Pp .\" -And the following configuration file will do 3. (should be +And the following configuration file will do 3 +(should be used for the router renumbering message to be sent 1 week -afterward) +afterward). .\" .Bd -literal -offset indent dest ff05::2; -change match-prefix fec0:1:1:: /48; +change match-prefix 3ffe:501:ffff:: /48; .Ed .Pp .\" @@ -319,7 +358,7 @@ 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 rrenumd 8 , .Xr prefix 8 .Sh HISTORY The diff --git a/usr.sbin/rrenumd/rrenumd.h b/usr.sbin/rrenumd/rrenumd.h index 4854cb4..df0280b 100644 --- a/usr.sbin/rrenumd/rrenumd.h +++ b/usr.sbin/rrenumd/rrenumd.h @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: rrenumd.h,v 1.2 2000/07/03 02:54:09 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c index 55a43ce..5cba1f5 100644 --- a/usr.sbin/rtadvd/advcap.c +++ b/usr.sbin/rtadvd/advcap.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: advcap.c,v 1.3 2000/05/16 13:34:13 itojun Exp $ */ +/* $KAME: advcap.c,v 1.5 2001/02/01 09:12:08 jinmei Exp $ */ /* * Copyright (c) 1983 The Regents of the University of California. @@ -96,7 +96,7 @@ int getent __P((char *, char *, char *)); int tnchktc __P((void)); int tnamatch __P((char *)); static char *tskip __P((char *)); -int tgetnum __P((char *)); +long long tgetnum __P((char *)); int tgetflag __P((char *)); char *tgetstr __P((char *, char **)); static char *tdecode __P((char *, char **)); @@ -307,11 +307,11 @@ breakbreak: * a # character. If the option is not found we return -1. * Note that we handle octal numbers beginning with 0. */ -int +long long tgetnum(id) char *id; { - register long int i; + register long long i; register int base; register char *bp = tbuf; diff --git a/usr.sbin/rtadvd/advcap.h b/usr.sbin/rtadvd/advcap.h index dc3f428..7b3715a 100644 --- a/usr.sbin/rtadvd/advcap.h +++ b/usr.sbin/rtadvd/advcap.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME$ */ +/* $KAME: advcap.h,v 1.3 2001/02/01 09:12:08 jinmei Exp $ */ /* * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia. @@ -38,7 +38,7 @@ __BEGIN_DECLS extern int agetent __P((char *, const char *)); extern int agetflag __P((const char *)); -extern int agetnum __P((const char *)); +extern long long agetnum __P((const char *)); extern char *agetstr __P((const char *, char **)); __END_DECLS diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index ec294f1..01cfb4c 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: config.c,v 1.11 2000/05/16 13:34:13 itojun Exp $ */ +/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -34,6 +34,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/sysctl.h> #include <net/if.h> #if defined(__FreeBSD__) && __FreeBSD__ >= 3 @@ -62,6 +63,7 @@ #include <search.h> #endif #include <unistd.h> +#include <ifaddrs.h> #include "rtadvd.h" #include "advcap.h" @@ -71,6 +73,7 @@ static void makeentry __P((char *, int, char *, int)); static void get_prefix __P((struct rainfo *)); +static int getinet6sysctl __P((int)); extern struct rainfo *ralist; @@ -82,9 +85,11 @@ getconfig(intface) char tbuf[BUFSIZ]; struct rainfo *tmp; long val; + long long val64; char buf[BUFSIZ]; char *bp = buf; char *addr; + static int forwarding = -1; #define MUSTHAVE(var, cap) \ do { \ @@ -114,6 +119,13 @@ getconfig(intface) tmp = (struct rainfo *)malloc(sizeof(*ralist)); memset(tmp, 0, sizeof(*tmp)); tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; + tmp->route.next = tmp->route.prev = &tmp->route; + + /* check if we are allowed to forward packets (if not determined) */ + if (forwarding < 0) { + if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) + exit(1); + } /* get interface information */ if (agetflag("nolladdr")) @@ -164,12 +176,22 @@ getconfig(intface) tmp->hoplimit = val & 0xff; MAYHAVE(val, "raflags", 0); - tmp->managedflg= val & ND_RA_FLAG_MANAGED; + tmp->managedflg = val & ND_RA_FLAG_MANAGED; tmp->otherflg = val & ND_RA_FLAG_OTHER; #ifdef MIP6 if (mobileip6) tmp->haflg = val & ND_RA_FLAG_HA; #endif +#ifndef ND_RA_FLAG_RTPREF_MASK +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ +#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ +#endif + tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { + syslog(LOG_ERR, "<%s> invalid router preference on %s", + __FUNCTION__, intface); + exit(1); + } MAYHAVE(val, "rltime", tmp->maxinterval * 3); if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { @@ -180,6 +202,21 @@ getconfig(intface) tmp->maxinterval, MAXROUTERLIFETIME); exit(1); } + /* + * Basically, hosts MUST NOT send Router Advertisement messages at any + * time (RFC 2461, Section 6.2.3). However, it would sometimes be + * useful to allow hosts to advertise some parameters such as prefix + * information and link MTU. Thus, we allow hosts to invoke rtadvd + * only when router lifetime (on every advertising interface) is + * explicitly set zero. (see also the above section) + */ + if (val && forwarding == 0) { + syslog(LOG_WARNING, + "<%s> non zero router lifetime is specified for %s, " + "which must not be allowed for hosts.", + __FUNCTION__, intface); + exit(1); + } tmp->lifetime = val & 0xffff; MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); @@ -191,20 +228,23 @@ getconfig(intface) } tmp->reachabletime = (u_int32_t)val; - MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER); - if (val < 0 || val > 0xffffffff) { + MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); + if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> retrans time out of range", __FUNCTION__); exit(1); } - tmp->retranstimer = (u_int32_t)val; + tmp->retranstimer = (u_int32_t)val64; -#ifdef MIP6 - if (!mobileip6) +#ifndef MIP6 + if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { + syslog(LOG_ERR, + "<%s> mobile-ip6 configuration not supported", + __FUNCTION__); + exit(1); + } #else - if (1) -#endif - { + if (!mobileip6) { if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { syslog(LOG_ERR, "<%s> mobile-ip6 configuration without " @@ -212,9 +252,7 @@ getconfig(intface) __FUNCTION__); exit(1); } - } -#ifdef MIP6 - else { + } else { tmp->hapref = 0; if ((val = agetnum("hapref")) >= 0) tmp->hapref = (int16_t)val; @@ -233,6 +271,15 @@ getconfig(intface) #endif /* prefix information */ + + /* + * This is an implementation specific parameter to consinder + * link propagation delays and poorly synchronized clocks when + * checking consistency of advertised lifetimes. + */ + MAYHAVE(val, "clockskew", 0); + tmp->clockskew = val; + if ((pfxs = agetnum("addrs")) < 0) { /* auto configure prefix information */ if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { @@ -281,7 +328,7 @@ getconfig(intface) { MAYHAVE(val, entbuf, (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| - ND_OPT_PI_FLAG_RTADDR)); + ND_OPT_PI_FLAG_ROUTER)); } else #endif { @@ -291,29 +338,44 @@ getconfig(intface) pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; #ifdef MIP6 - if (mobileip6) - pfx->routeraddr = val & ND_OPT_PI_FLAG_RTADDR; + pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER; #endif makeentry(entbuf, i, "vltime", added); - MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME); - if (val < 0 || val > 0xffffffff) { + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> vltime out of range", __FUNCTION__); exit(1); } - pfx->validlifetime = (u_int32_t)val; + pfx->validlifetime = (u_int32_t)val64; + + makeentry(entbuf, i, "vltimedecr", added); + if (agetflag(entbuf)) { + struct timeval now; + gettimeofday(&now, 0); + pfx->vltimeexpire = + now.tv_sec + pfx->validlifetime; + } makeentry(entbuf, i, "pltime", added); - MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME); - if (val < 0 || val > 0xffffffff) { + MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> pltime out of range", __FUNCTION__); exit(1); } - pfx->preflifetime = (u_int32_t)val; + pfx->preflifetime = (u_int32_t)val64; + + makeentry(entbuf, i, "pltimedecr", added); + if (agetflag(entbuf)) { + struct timeval now; + gettimeofday(&now, 0); + pfx->pltimeexpire = + now.tv_sec + pfx->preflifetime; + } makeentry(entbuf, i, "addr", added); addr = (char *)agetstr(entbuf, &bp); @@ -368,6 +430,106 @@ getconfig(intface) exit(1); } + /* route information */ + + MAYHAVE(val, "routes", 0); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> number of route information improper", __FUNCTION__); + exit(1); + } + tmp->routes = val; + for (i = 0; i < tmp->routes; i++) { + struct rtinfo *rti; + char entbuf[256]; + int added = (tmp->routes > 1) ? 1 : 0; + + /* allocate memory to store prefix information */ + if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate enough memory", + __FUNCTION__); + exit(1); + } + memset(rti, 0, sizeof(*rti)); + + /* link into chain */ + insque(rti, &tmp->route); + + makeentry(entbuf, i, "rtrplen", added); + MAYHAVE(val, entbuf, 64); + if (val < 0 || val > 128) { + syslog(LOG_ERR, + "<%s> prefixlen out of range", + __FUNCTION__); + exit(1); + } + rti->prefixlen = (int)val; + + makeentry(entbuf, i, "rtrflags", added); + MAYHAVE(val, entbuf, 0); + rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { + syslog(LOG_ERR, "<%s> invalid router preference", + __FUNCTION__); + exit(1); + } + + makeentry(entbuf, i, "rtrltime", added); + /* + * XXX: since default value of route lifetime is not defined in + * draft-draves-route-selection-01.txt, I took the default + * value of valid lifetime of prefix as its default. + * It need be much considered. + */ + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { + syslog(LOG_ERR, + "<%s> rtrltime out of range", + __FUNCTION__); + exit(1); + } + rti->ltime = (u_int32_t)val64; + + makeentry(entbuf, i, "rtrprefix", added); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) { + syslog(LOG_ERR, + "<%s> need %s as an route for " + "interface %s", + __FUNCTION__, entbuf, intface); + exit(1); + } + if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { + syslog(LOG_ERR, + "<%s> inet_pton failed for %s", + __FUNCTION__, addr); + exit(1); + } +#if 0 + /* + * XXX: currently there's no restriction in route information + * prefix according to draft-draves-route-selection-01.txt, + * however I think the similar restriction be necessary. + */ + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { + syslog(LOG_ERR, + "<%s> multicast route (%s) must " + "not be advertised (IF=%s)", + __FUNCTION__, addr, intface); + exit(1); + } + if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { + syslog(LOG_NOTICE, + "<%s> link-local route (%s) must " + "not be advertised on %s", + __FUNCTION__, addr, intface); + exit(1); + } +#endif + } + /* okey */ tmp->next = ralist; ralist = tmp; @@ -385,33 +547,26 @@ getconfig(intface) static void get_prefix(struct rainfo *rai) { - size_t len; - u_char *buf, *lim, *next; + struct ifaddrs *ifap, *ifa; + struct prefix *pp; + struct in6_addr *a; + u_char *p, *ep, *m, *lim; u_char ntopbuf[INET6_ADDRSTRLEN]; - if ((len = rtbuf_len()) < 0) { + if (getifaddrs(&ifap) < 0) { syslog(LOG_ERR, - "<%s> can't get buffer length for routing info", + "<%s> can't get interface addresses", __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; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, rai->ifname) != 0) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(a)) + continue; /* allocate memory to store prefix info. */ if ((pp = malloc(sizeof(*pp))) == NULL) { @@ -422,21 +577,35 @@ get_prefix(struct rainfo *rai) } 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) { + /* set prefix length */ + m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; + lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; + pp->prefixlen = prefixlen(m, lim); + if (pp->prefixlen < 0 || pp->prefixlen > 128) { syslog(LOG_ERR, "<%s> failed to get prefixlen " - "or prefixl is invalid", + "or prefix is invalid", __FUNCTION__); exit(1); } + + /* set prefix, sweep bits outside of prefixlen */ + memcpy(&pp->prefix, a, sizeof(*a)); + p = (u_char *)&pp->prefix; + ep = (u_char *)(&pp->prefix + 1); + while (m < lim) + *p++ &= *m++; + while (p < ep) + *p++ = 0x00; + + if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, + sizeof(ntopbuf))) { + syslog(LOG_ERR, "<%s> inet_ntop failed", __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); + __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname); /* set other fields with protocol defaults */ pp->validlifetime = DEF_ADVVALIDLIFETIME; @@ -450,14 +619,9 @@ get_prefix(struct rainfo *rai) /* 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); + freeifaddrs(ifap); } static void @@ -493,6 +657,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) __FUNCTION__); return; /* XXX: error or exit? */ } + memset(prefix, 0, sizeof(*prefix)); prefix->prefix = ipr->ipr_prefix.sin6_addr; prefix->prefixlen = ipr->ipr_plen; prefix->validlifetime = ipr->ipr_vltime; @@ -510,7 +675,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) /* free the previous packet */ free(rai->ra_data); - rai->ra_data = 0; + rai->ra_data = NULL; /* reconstruct the packet */ rai->pfxs++; @@ -617,10 +782,12 @@ make_packet(struct rainfo *rainfo) struct nd_opt_prefix_info *ndopt_pi; struct nd_opt_mtu *ndopt_mtu; #ifdef MIP6 - struct nd_opt_advint *ndopt_advint; - struct nd_opt_hai *ndopt_hai; + struct nd_opt_advinterval *ndopt_advint; + struct nd_opt_homeagent_info *ndopt_hai; #endif + struct nd_opt_route_info *ndopt_rti; struct prefix *pfx; + struct rtinfo *rti; /* calculate total length */ packlen = sizeof(struct nd_router_advert); @@ -641,9 +808,14 @@ make_packet(struct rainfo *rainfo) packlen += sizeof(struct nd_opt_mtu); #ifdef MIP6 if (mobileip6 && rainfo->maxinterval) - packlen += sizeof(struct nd_opt_advint); + packlen += sizeof(struct nd_opt_advinterval); if (mobileip6 && rainfo->hatime) - packlen += sizeof(struct nd_opt_hai); + packlen += sizeof(struct nd_opt_homeagent_info); +#endif +#ifdef ND_OPT_ROUTE_INFO + for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) + packlen += sizeof(struct nd_opt_route_info) + + ((rti->prefixlen + 0x3f) >> 6) * 8; #endif /* allocate memory for the packet */ @@ -653,6 +825,11 @@ make_packet(struct rainfo *rainfo) __FUNCTION__); exit(1); } + if (rainfo->ra_data) { + /* free the previous packet */ + free(rainfo->ra_data); + rainfo->ra_data = NULL; + } rainfo->ra_data = buf; /* XXX: what if packlen > 576? */ rainfo->ra_datalen = packlen; @@ -665,7 +842,12 @@ make_packet(struct rainfo *rainfo) 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 = 0; /* just in case */ + /* + * XXX: the router preference field, which is a 2-bit field, should be + * initialized before other fields. + */ + ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; ra->nd_ra_flags_reserved |= rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; ra->nd_ra_flags_reserved |= @@ -689,36 +871,39 @@ make_packet(struct rainfo *rainfo) 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); + ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); buf += sizeof(struct nd_opt_mtu); } #ifdef MIP6 if (mobileip6 && rainfo->maxinterval) { - ndopt_advint = (struct nd_opt_advint *)buf; - ndopt_advint->nd_opt_int_type = ND_OPT_ADV_INTERVAL; - ndopt_advint->nd_opt_int_len = 1; - ndopt_advint->nd_opt_int_reserved = 0; - ndopt_advint->nd_opt_int_interval = ntohl(rainfo->maxinterval * + ndopt_advint = (struct nd_opt_advinterval *)buf; + ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL; + ndopt_advint->nd_opt_adv_len = 1; + ndopt_advint->nd_opt_adv_reserved = 0; + ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval * 1000); - buf += sizeof(struct nd_opt_advint); + buf += sizeof(struct nd_opt_advinterval); } #endif #ifdef MIP6 if (rainfo->hatime) { - ndopt_hai = (struct nd_opt_hai *)buf; - ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; + ndopt_hai = (struct nd_opt_homeagent_info *)buf; + ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO; ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; - ndopt_hai->nd_opt_hai_pref = ntohs(rainfo->hapref); - ndopt_hai->nd_opt_hai_lifetime = ntohs(rainfo->hatime); - buf += sizeof(struct nd_opt_hai); + ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref); + ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime); + buf += sizeof(struct nd_opt_homeagent_info); } #endif for (pfx = rainfo->prefix.next; pfx != &rainfo->prefix; pfx = pfx->next) { + u_int32_t vltime, pltime; + struct timeval now; + 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; @@ -733,16 +918,69 @@ make_packet(struct rainfo *rainfo) #ifdef MIP6 if (pfx->routeraddr) ndopt_pi->nd_opt_pi_flags_reserved |= - ND_OPT_PI_FLAG_RTADDR; + ND_OPT_PI_FLAG_ROUTER; #endif - ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime); - ndopt_pi->nd_opt_pi_preferred_time = - ntohl(pfx->preflifetime); + if (pfx->vltimeexpire || pfx->pltimeexpire) + gettimeofday(&now, NULL); + if (pfx->vltimeexpire == 0) + vltime = pfx->validlifetime; + else + vltime = (pfx->vltimeexpire > now.tv_sec) ? + pfx->vltimeexpire - now.tv_sec : 0; + if (pfx->pltimeexpire == 0) + pltime = pfx->preflifetime; + else + pltime = (pfx->pltimeexpire > now.tv_sec) ? + pfx->pltimeexpire - now.tv_sec : 0; + if (vltime < pltime) { + /* + * this can happen if vltime is decrement but pltime + * is not. + */ + pltime = vltime; + } + ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); + ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); ndopt_pi->nd_opt_pi_reserved2 = 0; ndopt_pi->nd_opt_pi_prefix = pfx->prefix; buf += sizeof(struct nd_opt_prefix_info); } +#ifdef ND_OPT_ROUTE_INFO + for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { + u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; + + ndopt_rti = (struct nd_opt_route_info *)buf; + ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; + ndopt_rti->nd_opt_rti_len = 1 + psize; + ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; + ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; + ndopt_rti->nd_opt_rti_lifetime = rti->ltime; + memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); + buf += sizeof(struct nd_opt_route_info) + psize * 8; + } +#endif + return; } + +static int +getinet6sysctl(int code) +{ + int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; + int value; + size_t size; + + mib[3] = code; + size = sizeof(value); + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) + < 0) { + syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", + __FUNCTION__, code, + strerror(errno)); + return(-1); + } + else + return(value); +} diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h index f08a702..9000461 100644 --- a/usr.sbin/rtadvd/config.h +++ b/usr.sbin/rtadvd/config.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME$ */ +/* $KAME: config.h,v 1.3 2000/05/16 13:34:13 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c index 4b2801d..4e4be1a 100644 --- a/usr.sbin/rtadvd/dump.c +++ b/usr.sbin/rtadvd/dump.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: dump.c,v 1.10 2000/05/23 11:31:25 itojun Exp $ */ +/* $KAME: dump.c,v 1.16 2001/03/21 17:41:13 jinmei Exp $ */ /* * Copyright (C) 2000 WIDE Project. @@ -31,6 +31,7 @@ */ #include <sys/types.h> #include <sys/socket.h> +#include <sys/queue.h> #include <net/if.h> #if defined(__FreeBSD__) && __FreeBSD__ >= 3 @@ -71,6 +72,13 @@ static void if_dump __P((void)); #define LONGLONG "%llu" #endif +static char *rtpref_str[] = { + "medium", /* 00 */ + "high", /* 01 */ + "rsv", /* 10 */ + "low" /* 11 */ +}; + static char * ether_str(sdl) struct sockaddr_dl *sdl; @@ -97,7 +105,9 @@ if_dump() struct prefix *pfx; char prefixbuf[INET6_ADDRSTRLEN]; int first; + struct timeval now; + gettimeofday(&now, NULL); /* XXX: unused in most cases */ for (rai = ralist; rai; rai = rai->next) { fprintf(fp, "%s:\n", rai->ifname); @@ -141,12 +151,15 @@ if_dump() " DefaultLifetime: %d, MaxAdvInterval: %d, " "MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval, rai->mininterval); - fprintf(fp, " Flags: %s%s%s MTU: %d\n", + fprintf(fp, " Flags: %s%s%s, ", rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", #ifdef MIP6 rai->haflg ? "H" : #endif - "", rai->linkmtu); + ""); + fprintf(fp, "Preference: %s, ", + rtpref_str[(rai->rtpref >> 3) & 0xff]); + fprintf(fp, "MTU: %d\n", rai->linkmtu); fprintf(fp, " ReachableTime: %d, RetransTimer: %d, " "CurHopLimit: %d\n", rai->reachabletime, rai->retranstimer, rai->hoplimit); @@ -155,6 +168,9 @@ if_dump() rai->hapref, rai->hatime); #endif + if (rai->clockskew) + fprintf(fp, " Clock skew: %ldsec\n", + rai->clockskew); for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix; pfx = pfx->next) { if (first) { @@ -177,15 +193,27 @@ if_dump() break; } if (pfx->validlifetime == ND6_INFINITE_LIFETIME) - fprintf(fp, "vltime: infinity, "); + fprintf(fp, "vltime: infinity"); else - fprintf(fp, "vltime: %ld, ", + fprintf(fp, "vltime: %ld", (long)pfx->validlifetime); + if (pfx->vltimeexpire != 0) + fprintf(fp, "(decr,expire %ld), ", (long) + pfx->vltimeexpire > now.tv_sec ? + pfx->vltimeexpire - now.tv_sec : 0); + else + fprintf(fp, ", "); if (pfx->preflifetime == ND6_INFINITE_LIFETIME) - fprintf(fp, "pltime: infinity, "); + fprintf(fp, "pltime: infinity"); else - fprintf(fp, "pltime: %ld, ", + fprintf(fp, "pltime: %ld", (long)pfx->preflifetime); + if (pfx->pltimeexpire != 0) + fprintf(fp, "(decr,expire %ld), ", (long) + pfx->pltimeexpire > now.tv_sec ? + pfx->pltimeexpire - now.tv_sec : 0); + else + fprintf(fp, ", "); fprintf(fp, "flags: %s%s%s", pfx->onlinkflg ? "L" : "", pfx->autoconfflg ? "A" : "", diff --git a/usr.sbin/rtadvd/dump.h b/usr.sbin/rtadvd/dump.h index 03dff70..cc3b472 100644 --- a/usr.sbin/rtadvd/dump.h +++ b/usr.sbin/rtadvd/dump.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME$ */ +/* $KAME: dump.h,v 1.1 2000/05/23 11:31:26 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c index b77f472..c6aa2e6 100644 --- a/usr.sbin/rtadvd/if.c +++ b/usr.sbin/rtadvd/if.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if.c,v 1.14 2000/10/25 04:28:34 jinmei Exp $ */ +/* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -259,17 +259,6 @@ rtbuf_len() 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)) @@ -357,7 +346,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) return (char *)rtm; } -#undef FILTER_MATCH(type, filter) +#undef FILTER_MATCH struct in6_addr * get_addr(char *buf) diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h index f91e8d4..23f9a98 100644 --- a/usr.sbin/rtadvd/if.h +++ b/usr.sbin/rtadvd/if.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */ +/* $KAME: if.h,v 1.6 2001/01/21 15:37:14 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -37,23 +37,22 @@ extern size_t ifblock_size; extern char *ifblock; struct nd_opt_hdr; -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)); +struct sockaddr_dl *if_nametosdl __P((char *)); +int if_getmtu __P((char *)); +int if_getflags __P((int, int)); +int lladdropt_length __P((struct sockaddr_dl *)); +void lladdropt_fill __P((struct sockaddr_dl *, struct nd_opt_hdr *)); 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)); +char *get_next_msg __P((char *, char *, int, size_t *, int)); +struct in6_addr *get_addr __P((char *)); +int get_rtm_ifindex __P((char *)); +int get_ifm_ifindex __P((char *)); +int get_ifam_ifindex __P((char *)); +int get_ifm_flags __P((char *)); +int get_prefixlen __P((char *)); +int prefixlen __P((u_char *, u_char *)); +int rtmsg_type __P((char *)); +int ifmsg_type __P((char *)); +int rtmsg_len __P((char *)); +int ifmsg_len __P((char *)); void init_iflist __P((void)); diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h index 9c68cc4..3afee55 100644 --- a/usr.sbin/rtadvd/pathnames.h +++ b/usr.sbin/rtadvd/pathnames.h @@ -1,4 +1,4 @@ +/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */ /* $FreeBSD$ */ -/* $KAME$ */ #define _PATH_RTADVDCONF "/etc/rtadvd.conf" diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c index a0edf9f..a5fbe20 100644 --- a/usr.sbin/rtadvd/rrenum.c +++ b/usr.sbin/rtadvd/rrenum.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: rrenum.c,v 1.3 2000/05/16 13:34:14 itojun Exp $ */ +/* $KAME: rrenum.c,v 1.10 2001/01/21 15:32:16 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - +#include <sys/types.h> #include <sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -50,6 +50,7 @@ #include <string.h> #include <stdlib.h> #include <syslog.h> +#include "rtadvd.h" #include "rrenum.h" #include "if.h" @@ -138,13 +139,17 @@ rr_pco_check(int len, struct rr_pco_match *rpm) } static void -do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) { +do_use_prefix(int len, struct rr_pco_match *rpm, + struct in6_rrenumreq *irr, int ifindex) +{ struct rr_pco_use *rpu, *rpulim; + struct rainfo *rai; + struct prefix *pp; rpu = (struct rr_pco_use *)(rpm + 1); rpulim = (struct rr_pco_use *)((char *)rpm + len); - if (rpu == rpulim) { + if (rpu == rpulim) { /* no use prefix */ if (rpm->rpm_code == RPM_PCO_ADD) return; @@ -176,16 +181,16 @@ do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) { (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_vltime = ntohl(rpu->rpu_vltime); + irr->irr_pltime = ntohl(rpu->rpu_pltime); irr->irr_raf_onlink = - (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1; irr->irr_raf_auto = - (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1; irr->irr_rrf_decrvalid = - (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME); + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1; irr->irr_rrf_decrprefd = - (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME); + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1; irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); irr->irr_useprefix.sin6_family = AF_INET6; irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; @@ -194,6 +199,40 @@ do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) { errno != EADDRNOTAVAIL) syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, strerror(errno)); + + /* very adhoc: should be rewritten */ + if (rpm->rpm_code == RPM_PCO_CHANGE && + IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) && + rpm->rpm_matchlen == rpu->rpu_uselen && + rpu->rpu_uselen == rpu->rpu_keeplen) { + if ((rai = if_indextorainfo(ifindex)) == NULL) + continue; /* non-advertising IF */ + + for (pp = rai->prefix.next; pp != &rai->prefix; + pp = pp->next) { + struct timeval now; + + if (prefix_match(&pp->prefix, pp->prefixlen, + &rpm->rpm_prefix, + rpm->rpm_matchlen)) { + /* change parameters */ + pp->validlifetime = ntohl(rpu->rpu_vltime); + pp->preflifetime = ntohl(rpu->rpu_pltime); + if (irr->irr_rrf_decrvalid) { + gettimeofday(&now, 0); + pp->vltimeexpire = + now.tv_sec + pp->validlifetime; + } else + pp->vltimeexpire = 0; + if (irr->irr_rrf_decrprefd) { + gettimeofday(&now, 0); + pp->pltimeexpire = + now.tv_sec + pp->preflifetime; + } else + pp->pltimeexpire = 0; + } + } + } } } @@ -234,7 +273,7 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) (iflist[ifindex]->ifm_flags & IFF_UP) == 0) continue; /* TODO: interface scope check */ - do_use_prefix(len, rpm, &irr); + do_use_prefix(len, rpm, &irr, ifindex); } if (errno == ENXIO) return 0; @@ -392,9 +431,40 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); - rr_rcvifindex = pi->ipi6_ifindex; + /* packet validation based on Section 4.1 of RFC2894 */ + if (len < sizeof(struct icmp6_router_renum)) { + syslog(LOG_NOTICE, + "<%s>: RR short message (size %d) from %s to %s on %s", + __FUNCTION__, len, + 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)); + return; + } - /* TODO: some consistency check. */ + /* + * If the IPv6 destination address is neither an All Routers multicast + * address [AARCH] nor one of the receiving router's unicast addresses, + * the message MUST be discarded and SHOULD be logged to network + * management. + * We rely on the kernel input routine for unicast addresses, and thus + * check multicast destinations only. + */ + if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && + !IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) { + syslog(LOG_NOTICE, + "<%s>: RR message with invalid destination (%s) " + "from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf[1], INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + rr_rcvifindex = pi->ipi6_ifindex; switch (rr->rr_code) { case ICMP6_ROUTER_RENUMBERING_COMMAND: diff --git a/usr.sbin/rtadvd/rrenum.h b/usr.sbin/rtadvd/rrenum.h index 3ab1e7d..ce94015 100644 --- a/usr.sbin/rtadvd/rrenum.h +++ b/usr.sbin/rtadvd/rrenum.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME$ */ +/* $KAME: rrenum.h,v 1.3 2001/01/21 15:37:14 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -30,6 +30,5 @@ * SUCH DAMAGE. */ -void rr_input __P((int len, struct icmp6_router_renum *rr, - struct in6_pktinfo *pi, struct sockaddr_in6 *from, - struct in6_addr *dst)); +void rr_input __P((int, struct icmp6_router_renum *, struct in6_pktinfo *, + struct sockaddr_in6 *, struct in6_addr *)); diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8 index 3ddc77d..dcdcdab 100644 --- a/usr.sbin/rtadvd/rtadvd.8 +++ b/usr.sbin/rtadvd/rtadvd.8 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: rtadvd.8,v 1.9 2000/05/27 13:37:01 jinmei Exp $ +.\" $KAME: rtadvd.8,v 1.17 2001/02/04 05:34:38 jinmei Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -36,8 +36,8 @@ .Nd router advertisement daemon .Sh SYNOPSIS .Nm +.Op Fl dDfMRs .Op Fl c Ar configfile -.Op Fl dDfRs .Ar interface ... .Sh DESCRIPTION .Nm @@ -77,6 +77,15 @@ Moreover, if the status of an advertising interface changes, will start or stop sending router advertisements according to the latest status. .Pp +Basically, hosts MUST NOT send Router Advertisement messages at any +time (RFC 2461, Section 6.2.3). +However, it would sometimes be useful to allow hosts to advertise some +parameters such as prefix information and link MTU. +Thus, +.Nm +can be invoked if router lifetime is explicitly set zero on every +advertising interface. +.Pp The command line options are: .Bl -tag -width indent .\" @@ -93,6 +102,15 @@ Print debugging information. Even more debugging information is printed. .It Fl f Foreground mode (useful when debugging). +.It Fl M +Specify an interface to join the all-routers site-local multicast group. +By default, +.Nm +tries to join the first advertising interface appeared in the command +line. +This option has meaning only with the +.Fl R +option, which enables routing renumbering protocol support. .\".It Fl m .\"Enables mobile IPv6 support. .\"This changes the content of router advertisement option, as well as @@ -100,6 +118,12 @@ Foreground mode (useful when debugging). .It Fl R Accept router renumbering requests. If you enable it, certain IPsec setup is suggested for security reasons. +On KAME-based systems, +.Xr rrenumd 8 +generates router renumbering request packets. +This option is currently disabled, and is ignored by +.Nm +with a warning message. .It Fl s Do not add or delete prefixes dynamically. Only statically configured prefixes, if any, will be advertised. @@ -138,17 +162,20 @@ in which dumps its internal state. .El .Sh SEE ALSO -.Xr daemon 3 , .Xr rtadvd.conf 5 , -.Xr rtsol 8 +.Xr rtsol 8 , +.Xr rrenumd 8 .Sh HISTORY The .Nm command first appeared in WIDE Hydrangea IPv6 protocol stack kit. .Sh CAVEAT -Router advertisements should only be performed downstream. -Erroneous upstream advertisements will cause +There used to be some text that recommended users not to let +.Nm +advertise Router Advertisement messages on an upstream link to avoid +undesirable .Xr icmp6 4 -redirect packet storms in the subnet, as (per the specification) the -advertising router is assumed to become the default router for -end hosts in the subnet. +redirect messages. +However, based on the later discussion in the IETF ipng working group, +all routers should rather advertise the messages regardless of +the network topology, in order to ensure reachability. diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index 000e612..e9931df 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: rtadvd.c,v 1.30 2000/06/22 20:16:12 itojun Exp $ */ +/* $KAME: rtadvd.c,v 1.50 2001/02/04 06:15:15 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -34,6 +34,7 @@ #include <sys/socket.h> #include <sys/uio.h> #include <sys/time.h> +#include <sys/queue.h> #include <net/if.h> #include <net/route.h> @@ -68,14 +69,18 @@ static size_t rcvcmsgbuflen; static u_char *sndcmsgbuf = NULL; static size_t sndcmsgbuflen; static int do_dump; +static int do_die; 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}; +struct in6_addr in6a_site_allrouters; static char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX: should be configurable */ static char *pidfilename = "/var/run/rtadvd.pid"; /* should be configurable */ -int sock, rtsock; +static char *mcastif; +int sock; +int rtsock = -1; #ifdef MIP6 int mobileip6 = 0; #endif @@ -120,7 +125,8 @@ u_int32_t ndopt_flags[] = { }; int main __P((int, char *[])); -static void die __P((int)); +static void set_die __P((int)); +static void die __P((void)); static void sock_open __P((void)); static void rtsock_open __P((void)); static void rtadvd_input __P((void)); @@ -133,7 +139,6 @@ static int prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, 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)); static void rtadvd_set_dump_file __P((void)); @@ -157,9 +162,9 @@ main(argc, argv) /* get command line options and arguments */ #ifdef MIP6 -#define OPTIONS "c:dDfmRs" +#define OPTIONS "c:dDfM:mRs" #else -#define OPTIONS "c:dDfRs" +#define OPTIONS "c:dDfM:Rs" #endif while ((ch = getopt(argc, argv, OPTIONS)) != -1) { #undef OPTIONS @@ -176,13 +181,19 @@ main(argc, argv) case 'f': fflag = 1; break; + case 'M': + mcastif = optarg; + break; #ifdef MIP6 case 'm': mobileip6 = 1; break; #endif case 'R': - accept_rr = 1; + fprintf(stderr, "rtadvd: " + "the -R option is currently ignored.\n"); + /* accept_rr = 1; */ + /* run anyway... */ break; case 's': sflag = 1; @@ -194,9 +205,9 @@ main(argc, argv) if (argc == 0) { fprintf(stderr, #ifdef MIP6 - "usage: rtadvd [-dDfmRs] [-c conffile] " + "usage: rtadvd [-dDfMmRs] [-c conffile] " #else - "usage: rtadvd [-dDfRs] [-c conffile] " + "usage: rtadvd [-dDfMRs] [-c conffile] " #endif "interfaces...\n"); exit(1); @@ -243,12 +254,15 @@ main(argc, argv) FD_ZERO(&fdset); FD_SET(sock, &fdset); maxfd = sock; - rtsock_open(); - FD_SET(rtsock, &fdset); - if (rtsock > sock) + if (sflag == 0) { + rtsock_open(); + FD_SET(rtsock, &fdset); + if (rtsock > sock) maxfd = rtsock; + } else + rtsock = -1; - signal(SIGTERM, (void *)die); + signal(SIGTERM, (void *)set_die); signal(SIGUSR1, (void *)rtadvd_set_dump_file); while (1) { @@ -259,6 +273,11 @@ main(argc, argv) rtadvd_dump_file(dumpfilename); } + if (do_die) { + die(); + /*NOTREACHED*/ + } + /* timer expiration check and reset the timer */ timeout = rtadvd_check_timer(); @@ -285,7 +304,7 @@ main(argc, argv) } if (i == 0) /* timeout */ continue; - if (sflag == 0 && FD_ISSET(rtsock, &select_fd)) + if (rtsock != -1 && FD_ISSET(rtsock, &select_fd)) rtmsg_input(); if (FD_ISSET(sock, &select_fd)) rtadvd_input(); @@ -300,9 +319,15 @@ rtadvd_set_dump_file() } static void -die(sig) +set_die(sig) int sig; { + do_die = 1; +} + +static void +die() +{ struct rainfo *ra; int i; const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; @@ -331,13 +356,13 @@ rtmsg_input() int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; - u_char ifname[16]; + u_char ifname[IF_NAMESIZE]; struct prefix *prefix; struct rainfo *rai; struct in6_addr *addr; char addrbuf[INET6_ADDRSTRLEN]; - n = read(rtsock, msg, 2048); + n = read(rtsock, msg, sizeof(msg)); if (dflag > 1) { syslog(LOG_DEBUG, "<%s> received a routing message " @@ -876,8 +901,8 @@ ra_input(int len, struct nd_router_advert *ra, 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)) { + &ndopts, NDOPT_FLAG_SRCLINKADDR | + NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { syslog(LOG_ERR, "<%s> ND option check failed for an RA from %s on %s", __FUNCTION__, @@ -905,7 +930,7 @@ ra_input(int len, struct nd_router_advert *ra, /* Cur Hop Limit value */ if (ra->nd_ra_curhoplimit && rai->hoplimit && ra->nd_ra_curhoplimit != rai->hoplimit) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "<%s> CurHopLimit inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, @@ -919,7 +944,7 @@ ra_input(int len, struct nd_router_advert *ra, /* M flag */ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != rai->managedflg) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "<%s> M flag inconsistent on %s:" " %s from %s, %s from us", __FUNCTION__, @@ -933,7 +958,7 @@ ra_input(int len, struct nd_router_advert *ra, /* O flag */ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != rai->otherflg) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "<%s> O flag inconsistent on %s:" " %s from %s, %s from us", __FUNCTION__, @@ -948,7 +973,7 @@ ra_input(int len, struct nd_router_advert *ra, reachabletime = ntohl(ra->nd_ra_reachable); if (reachabletime && rai->reachabletime && reachabletime != rai->reachabletime) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "<%s> ReachableTime inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, @@ -963,7 +988,7 @@ ra_input(int len, struct nd_router_advert *ra, retranstimer = ntohl(ra->nd_ra_retransmit); if (retranstimer && rai->retranstimer && retranstimer != rai->retranstimer) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "<%s> RetranceTimer inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, @@ -978,7 +1003,7 @@ ra_input(int len, struct nd_router_advert *ra, 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, + syslog(LOG_INFO, "<%s> MTU option value inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, @@ -992,7 +1017,7 @@ ra_input(int len, struct nd_router_advert *ra, /* Preferred and Valid Lifetimes for prefixes */ { struct nd_optlist *optp = ndopts.nd_opts_list; - + if (ndopts.nd_opts_pi) { if (prefix_check(ndopts.nd_opts_pi, rai, from)) inconsistent++; @@ -1005,10 +1030,8 @@ ra_input(int len, struct nd_router_advert *ra, } } - if (inconsistent) { - printf("RA input %d inconsistents\n", inconsistent); + if (inconsistent) rai->rainconsistent++; - } done: free_ndopts(&ndopts); @@ -1024,6 +1047,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, struct prefix *pp; int inconsistent = 0; u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; + struct timeval now; #if 0 /* impossible */ if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) @@ -1061,8 +1085,36 @@ prefix_check(struct nd_opt_prefix_info *pinfo, } preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); - if (preferred_time != pp->preflifetime) { - syslog(LOG_WARNING, + if (pp->pltimeexpire) { + /* + * The lifetime is decremented in real time, so we should + * compare the expiration time. + * (RFC 2461 Section 6.2.7.) + * XXX: can we really expect that all routers on the link + * have synchronized clocks? + */ + gettimeofday(&now, NULL); + preferred_time += now.tv_sec; + + if (rai->clockskew && + abs(preferred_time - pp->pltimeexpire) > rai->clockskew) { + syslog(LOG_INFO, + "<%s> prefeerred lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld 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->pltimeexpire); + inconsistent++; + } + } + else if (preferred_time != pp->preflifetime) { + syslog(LOG_INFO, "<%s> prefeerred lifetime for %s/%d" " inconsistent on %s:" " %d from %s, %d from us", @@ -1074,12 +1126,32 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), pp->preflifetime); - inconsistent++; } valid_time = ntohl(pinfo->nd_opt_pi_valid_time); - if (valid_time != pp->validlifetime) { - syslog(LOG_WARNING, + if (pp->vltimeexpire) { + gettimeofday(&now, NULL); + valid_time += now.tv_sec; + + if (rai->clockskew && + abs(valid_time - pp->vltimeexpire) > rai->clockskew) { + syslog(LOG_INFO, + "<%s> valid lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld 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->vltimeexpire); + inconsistent++; + } + } + else if (valid_time != pp->validlifetime) { + syslog(LOG_INFO, "<%s> valid lifetime for %s/%d" " inconsistent on %s:" " %d from %s, %d from us", @@ -1118,6 +1190,26 @@ find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) return(NULL); } +/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */ +int +prefix_match(struct in6_addr *p0, int plen0, + struct in6_addr *p1, int plen1) +{ + int bytelen, bitlen; + + if (plen0 < plen1) + return(0); + bytelen = plen1 / 8; + bitlen = plen1 % 8; + if (memcmp((void *)p0, (void *)p1, bytelen)) + return(0); + if (p0->s6_addr[bytelen] >> (8 - bitlen) == + p1->s6_addr[bytelen] >> (8 - bitlen)) + return(1); + + return(0); +} + static int nd6_options(struct nd_opt_hdr *hdr, int limit, union nd_opts *ndopts, u_int32_t optflags) @@ -1276,7 +1368,7 @@ sock_open() __FUNCTION__, strerror(errno)); exit(1); } -#endif +#endif ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); @@ -1293,7 +1385,8 @@ sock_open() /* * join all routers multicast address on each advertising interface. */ - if (inet_pton(AF_INET6, ALLROUTERS, &mreq.ipv6mr_multiaddr.s6_addr) + if (inet_pton(AF_INET6, ALLROUTERS_LINK, + &mreq.ipv6mr_multiaddr.s6_addr) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", __FUNCTION__); @@ -1301,15 +1394,47 @@ sock_open() } while(ra) { mreq.ipv6mr_interface = ra->ifindex; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq, + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", + syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s", __FUNCTION__, ra->ifname, strerror(errno)); exit(1); } ra = ra->next; } + + /* + * When attending router renumbering, join all-routers site-local + * multicast group. + */ + if (accept_rr) { + if (inet_pton(AF_INET6, ALLROUTERS_SITE, + &in6a_site_allrouters) != 1) { + syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", + __FUNCTION__); + exit(1); + } + mreq.ipv6mr_multiaddr = in6a_site_allrouters; + if (mcastif) { + if ((mreq.ipv6mr_interface = if_nametoindex(mcastif)) + == 0) { + syslog(LOG_ERR, + "<%s> invalid interface: %s", + __FUNCTION__, mcastif); + exit(1); + } + } else + mreq.ipv6mr_interface = ralist->ifindex; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) < 0) { + syslog(LOG_ERR, + "<%s> IPV6_JOIN_GROUP(site) on %s: %s", + __FUNCTION__, + mcastif ? mcastif : ralist->ifname, + strerror(errno)); + exit(1); + } + } /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)answer; @@ -1342,7 +1467,7 @@ rtsock_open() } } -static struct rainfo * +struct rainfo * if_indextorainfo(int index) { struct rainfo *rai = ralist; @@ -1370,6 +1495,8 @@ struct rainfo *rainfo; return; } + make_packet(rainfo); /* XXX: inefficient */ + 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; @@ -1474,7 +1601,7 @@ ra_timer_update(void *data, struct timeval *tm) * 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). + * MaxRtrAdvInterval (RFC2461 6.2.4). */ interval = rai->mininterval; interval += random() % (rai->maxinterval - rai->mininterval); diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5 index b6d4f5c..9b9faaa 100644 --- a/usr.sbin/rtadvd/rtadvd.conf.5 +++ b/usr.sbin/rtadvd/rtadvd.conf.5 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: rtadvd.conf.5,v 1.32 2001/01/19 05:32:05 jinmei Exp $ +.\" $KAME: rtadvd.conf.5,v 1.35 2001/05/25 07:40:22 jinmei Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -117,6 +117,16 @@ and Bit 6 .Li 0x40 .Pc means Other stateful configuration flag bit. +Bit 4 +.Po +.Li 0x10 +.Pc +and Bit 3 +.Po +.Li 0x08 +.Pc +are used to encode router preference. +0x01 means high, 0x00 means medium, and 0x11 means low. The default value is 0. .It Cm \&rltime (num) Router lifetime field @@ -145,6 +155,17 @@ These items can be omitted, then will automatically get appropriate prefixes from the kernel's routing table, and advertise the prefixes with the default parameters. .Bl -tag -width indent +.It Cm \&clockskew +(num) Time skew to adjust link propagation delays and clock skews +betwen routers on the link +.Pq unit: seconds . +This value is used in consistency check for locally-configured and +advertised prefix lifetimes, and has its meaning when the local router +configures a prefix on the link with a lifetime that decrements in +real time. +If the value is 0, it means the consistency check will be skipped +for such prefixes. +The default value is 0. .It Cm \&addrs (num) Number of prefixes. Its default is 0, so it must explicitly be set to positve values @@ -193,10 +214,16 @@ is more than 0. (num) Valid lifetime field .Pq unit: seconds . The default value is 2592000 (30 days). +.It Cm \&vltimedecr +(bool) This item means the advertised valid lifetime will decrements +in real time, which is disabled by default. .It Cm \&pltime (num) Preferred lifetime field .Pq unit: seconds . The default value is 604800 (7 days). +.It Cm \&pltimedecr +(bool) This item means the advertised preferred lifetime will decrements +in real time, which is disabled by default. .El .Pp The following item is for ICMPv6 MTU option, @@ -237,6 +264,75 @@ will not attach source link-layer address option to router advertisement packets. .El .Pp +The following item controls ICMPV6 home agent information option, +which was defined with mobile IPv6 support. +It will be attached to router advertisement header just like other options do. +.Bl -tag -width indent +.It Cm \&hapref +(num) Specifies home agent preference. +If set to non-zero, +.Cm \&hatime +must be present as well. +.It Cm \&hatime +(num) Specifies home agent lifetime. +.El +.Pp +When mobile IPv6 support is turned on for +.Xr rtadvd 8 , +advertisement interval option will be attached to router advertisement +packet, by configuring +.Cm \&maxinterval +explicitly. +.Pp +The following items are for ICMPv6 route information option, +which will be attached to router advertisement header. +These items are optional. +.Bl -tag -width indent +.It Cm \&routes +(num) Number of routes. +Its default is 0, so it must explicitly be set to positve values +if you want to specify any route information option. +If its value is 0, no route information is sent. +If its value is more than 1, you must specify the index of the routes +for each item below. +Indices vary from 0 to N-1, where N is the +value of +.Cm routes. +Each index shall follow the name of each item, e.g., +.Dq rtrplen2 . +.It Cm \&rtrplen +(num) Prefix length field in route information option. +The default value is 64. +.It Cm \&rtrflags +(num) Flags field in route information option. +Bit 4 +.Po +.Li 0x10 +.Pc +and +and Bit 3 +.Po +.Li 0x08 +.Pc +are used to encode router preference for the route. +The default value is 0x00, i.e. medium router preference. +.It Cm \&rtrprefix +(str) The prefix filled into the Prefix field of route information option. +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 +.Cm addrs +is more than 0. +.It Cm \&rtrltime +(num) route lifetime field in route information option. +.Pq unit: seconds . +The default value is 2592000 (30 days). (not specified in draft-draves-router-selection-01.txt now) +.El You can also refer one line from another by using .Cm tc capability. @@ -293,6 +389,12 @@ Thomas Narten, Erik Nordmark and W. A. Simpson, Neighbor Discovery for IP version 6 (IPv6) .Dc , RFC 2461 +.Pp +Richard Draves, +.Do +Default Router Preferences and More-Specific Routes +.Dc , +draft-ietf-ipngwg-router-selection-01.txt .Sh HISTORY The .Xr rtadvd 8 diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h index 3ffc7e6..c05dcf4 100644 --- a/usr.sbin/rtadvd/rtadvd.h +++ b/usr.sbin/rtadvd/rtadvd.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: rtadvd.h,v 1.8 2000/05/16 13:34:14 itojun Exp $ */ +/* $KAME: rtadvd.h,v 1.16 2001/04/10 15:08:31 suz Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -31,7 +31,8 @@ */ #define ALLNODES "ff02::1" -#define ALLROUTERS "ff02::2" +#define ALLROUTERS_LINK "ff02::2" +#define ALLROUTERS_SITE "ff05::2" #define ANY "::" #define RTSOLLEN 8 @@ -74,7 +75,9 @@ struct prefix { struct prefix *prev; /* previous link */ u_int32_t validlifetime; /* AdvValidLifetime */ + long vltimeexpire; /* expiration of vltime; decrement case only */ u_int32_t preflifetime; /* AdvPreferredLifetime */ + long pltimeexpire; /* expiration of pltime; decrement case only */ u_int onlinkflg; /* bool: AdvOnLinkFlag */ u_int autoconfflg; /* bool: AdvAutonomousFlag */ #ifdef MIP6 @@ -85,6 +88,16 @@ struct prefix { struct in6_addr prefix; }; +struct rtinfo { + struct rtinfo *prev; /* previous link */ + struct rtinfo *next; /* forward link */ + + u_int32_t ltime; /* route lifetime */ + u_int rtpref; /* router preference */ + int prefixlen; + struct in6_addr prefix; +}; + struct soliciter { struct soliciter *next; struct sockaddr_in6 addr; @@ -116,17 +129,21 @@ struct rainfo { #ifdef MIP6 int haflg; /* HAFlag */ #endif + int rtpref; /* router preference */ 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 */ + long clockskew; /* used for consisitency check of lifetimes */ #ifdef MIP6 u_short hapref; /* Home Agent Preference */ u_short hatime; /* Home Agent Lifetime */ #endif + struct rtinfo route; /* route information option (link head) */ + int routes; /* number of route information options */ /* actual RA packet data and its length */ size_t ra_datalen; @@ -145,6 +162,10 @@ struct rainfo { void ra_timeout __P((void *)); void ra_timer_update __P((void *, struct timeval *)); +int prefix_match __P((struct in6_addr *, int, struct in6_addr *, int)); +struct rainfo *if_indextorainfo __P((int)); + +extern struct in6_addr in6a_site_allrouters; #ifdef MIP6 extern int mobileip6; #endif diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c index 7ccfb7e..439cbb2 100644 --- a/usr.sbin/rtadvd/timer.c +++ b/usr.sbin/rtadvd/timer.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: timer.c,v 1.3 2000/05/22 22:23:07 itojun Exp $ */ +/* $KAME: timer.c,v 1.4 2000/05/27 11:30:43 jinmei Exp $ */ /* * Copyright (C) 1998 WIDE Project. diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h index c5f8b85..3baf0d0 100644 --- a/usr.sbin/rtadvd/timer.h +++ b/usr.sbin/rtadvd/timer.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: timer.h,v 1.2 2000/05/16 13:34:14 itojun Exp $ */ +/* $KAME: timer.h,v 1.3 2000/05/27 11:30:43 jinmei Exp $ */ /* * Copyright (C) 1998 WIDE Project. diff --git a/usr.sbin/rtsold/Makefile b/usr.sbin/rtsold/Makefile index 9181ed5..a677ba5 100644 --- a/usr.sbin/rtsold/Makefile +++ b/usr.sbin/rtsold/Makefile @@ -14,10 +14,8 @@ # $FreeBSD$ PROG= rtsold -SRCS= rtsold.c rtsol.c if.c probe.c dump.c +SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c CFLAGS+=-DINET6 -DHAVE_GETIFADDRS -LDADD= -lkvm -DPADD= ${LIBKVM} MAN= rtsold.8 MLINKS= rtsold.8 rtsol.8 diff --git a/usr.sbin/rtsold/dump.c b/usr.sbin/rtsold/dump.c index ce55ddd..0f75971 100644 --- a/usr.sbin/rtsold/dump.c +++ b/usr.sbin/rtsold/dump.c @@ -1,4 +1,4 @@ -/* $KAME: dump.c,v 1.7 2000/08/13 06:14:59 itojun Exp $ */ +/* $KAME: dump.c,v 1.8 2000/10/05 22:20:39 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. diff --git a/usr.sbin/rtsold/if.c b/usr.sbin/rtsold/if.c index 35f16d2..4566b73 100644 --- a/usr.sbin/rtsold/if.c +++ b/usr.sbin/rtsold/if.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: if.c,v 1.15 2001/05/22 06:04:17 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -218,6 +218,9 @@ lladdropt_length(struct sockaddr_dl *sdl) { switch(sdl->sdl_type) { case IFT_ETHER: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif return(ROUNDUP8(ETHER_ADDR_LEN + 2)); default: return(0); @@ -233,6 +236,9 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) switch(sdl->sdl_type) { case IFT_ETHER: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; addr = (char *)(ndopt + 1); memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); @@ -295,6 +301,7 @@ if_nametosdl(char *name) return(NULL); memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); + free(buf); return(ret_sdl); } diff --git a/usr.sbin/rtsold/probe.c b/usr.sbin/rtsold/probe.c index 3b29cb4..34bb66e 100644 --- a/usr.sbin/rtsold/probe.c +++ b/usr.sbin/rtsold/probe.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. diff --git a/usr.sbin/rtsold/rtsock.c b/usr.sbin/rtsold/rtsock.c new file mode 100644 index 0000000..f1c4be8 --- /dev/null +++ b/usr.sbin/rtsold/rtsock.c @@ -0,0 +1,179 @@ +/* $KAME: rtsock.c,v 1.3 2000/10/10 08:46:45 itojun Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/time.h> +#include <sys/queue.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_dl.h> + +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <netinet/icmp6.h> + +#include <time.h> +#include <unistd.h> +#include <stdio.h> +#include <stddef.h> +#include <err.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> +#include "rtsold.h" + +#define ROUNDUP(a, size) \ + (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) + +#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ + ((caddr_t)(ap) + \ + ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) \ + : sizeof(u_long))) + +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ +static int rtsock_input_ifannounce __P((int, struct rt_msghdr *, char *)); +#endif + +static struct { + u_char type; + size_t minlen; + int (*func) __P((int, struct rt_msghdr *, char *)); +} rtsock_dispatch[] = { +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ + { RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr), + rtsock_input_ifannounce }, +#endif + { 0, NULL }, +}; + +int +rtsock_open() +{ + + return socket(PF_ROUTE, SOCK_RAW, 0); +} + +int +rtsock_input(s) + int s; +{ + ssize_t n; + char msg[2048]; + char *lim, *next; + struct rt_msghdr *rtm; + int idx; + size_t len; + int ret = 0; + const size_t lenlim = + offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen); + + n = read(s, msg, sizeof(msg)); + + lim = msg + n; + for (next = msg; next < lim; next += len) { + rtm = (struct rt_msghdr *)next; + if (lim - next < lenlim) + break; + len = rtm->rtm_msglen; + if (len < lenlim) + break; + + if (dflag > 1) { + warnmsg(LOG_INFO, __FUNCTION__, + "rtmsg type %d, len=%lu", rtm->rtm_type, + (u_long)len); + } + + for (idx = 0; rtsock_dispatch[idx].func; idx++) { + if (rtm->rtm_type != rtsock_dispatch[idx].type) + continue; + if (rtm->rtm_msglen < rtsock_dispatch[idx].minlen) { + warnmsg(LOG_INFO, __FUNCTION__, + "rtmsg type %d too short!", rtm->rtm_type); + continue; + } + + ret = (*rtsock_dispatch[idx].func)(s, rtm, lim); + break; + } + } + + return ret; +} + +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ +static int +rtsock_input_ifannounce(s, rtm, lim) + int s; + struct rt_msghdr *rtm; + char *lim; +{ + struct if_announcemsghdr *ifan; + struct ifinfo *ifinfo; + + ifan = (struct if_announcemsghdr *)rtm; + if ((char *)(ifan + 1) > lim) + return -1; + + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + /* + * XXX for NetBSD 1.5, interface index will monotonically be + * increased as new pcmcia card gets inserted. + * we may be able to do a name-based interface match, + * and call ifreconfig() to enable the interface again. + */ + warnmsg(LOG_INFO, __FUNCTION__, + "interface %s inserted", ifan->ifan_name); + break; + case IFAN_DEPARTURE: + warnmsg(LOG_WARNING, __FUNCTION__, + "interface %s removed", ifan->ifan_name); + ifinfo = find_ifinfo(ifan->ifan_index); + if (ifinfo) { + if (dflag > 1) { + warnmsg(LOG_INFO, __FUNCTION__, + "bring interface %s to DOWN state", + ifan->ifan_name); + } + ifinfo->state = IFS_DOWN; + } + break; + } + + return 0; +} +#endif diff --git a/usr.sbin/rtsold/rtsol.c b/usr.sbin/rtsold/rtsol.c index 7f27aef..62a73d0 100644 --- a/usr.sbin/rtsold/rtsol.c +++ b/usr.sbin/rtsold/rtsol.c @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $KAME: rtsol.c,v 1.11 2000/08/13 06:14:59 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. diff --git a/usr.sbin/rtsold/rtsold.8 b/usr.sbin/rtsold/rtsold.8 index 2eaae80..1cf369e 100644 --- a/usr.sbin/rtsold/rtsold.8 +++ b/usr.sbin/rtsold/rtsold.8 @@ -1,4 +1,4 @@ -.\" $KAME: rtsold.8,v 1.14 2000/08/13 18:06:39 itojun Exp $ +.\" $KAME: rtsold.8,v 1.16 2000/10/15 13:19:05 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -31,7 +31,7 @@ .\" .Dd May 17, 1998 .Dt RTSOLD 8 -.Os KAME +.Os .\" .Sh NAME .Nm rtsold @@ -62,8 +62,8 @@ all-routers multicast address to discover new routers and to get non link-local addresses. .Pp .Nm -should be used on IPv6 host -.Pq non-router node +should be used on IPv6 hosts +.Pq non-router nodes only. .Pp If you invoke the program as @@ -106,9 +106,9 @@ Every 60 seconds if the option is specified and the .Nm daemon cannot get the interface status. -This feature does not conform to IPv6 neighbor discovery +This feature does not conform to the IPv6 neighbor discovery specification, but is provided for mobile stations. -Default interval for router advertisements, which is on the order of 10 +The default interval for router advertisements, which is on the order of 10 minutes, is slightly long for mobile stations. This feature is provided for such stations so that they can find new routers as soon as possible @@ -117,14 +117,14 @@ when they attach to another link. .Lp Once .Nm -sends a Router Solicitation, and receives a valid Router Advertisement, +has sent a Router Solicitation, and has received a valid Router Advertisement, it refrains from sending additional solicitations on that interface, until the next time one of the above events occurs. .Lp When sending a Router Solicitation on an interface, .Nm includes a Source Link-layer address option if the interface -has its link-layer address. +has a link-layer address. .Pp Upon receipt of signal .Dv SIGUSR1 , @@ -137,7 +137,7 @@ will dump the current internal state into .It Fl a Autoprobe outgoing interface. .Nm -will try to find a non-loopback, non-p2p and IPv6-capable, interface. +will try to find a non-loopback, non-point-to-point, IPv6-capable interface. If .Nm finds multiple interfaces, @@ -147,13 +147,13 @@ will exit with error. .It Fl d Enable debugging. .It Fl D -Enable more debugging including to print internal timer information. +Enable more debugging including the printing of internal timer information. .It Fl f .Fl f prevents .Nm from becoming a daemon (foreground mode). -Warning messages are generated to standard error output, +Warning messages are generated to standard error instead of .Xr syslog 3 . .It Fl m @@ -170,11 +170,15 @@ periodically sends Router Solicitation on an interface that does not support ioctl. .It Fl 1 Perform only one probe. -Transmit Router Solicitation packet until valid Router Advertisement packet -arrives all the interfaces more than once, then exit. +Transmit Router Solicitation packets until at least one valid Router +Advertisement packet has arrived on each +.Ar interface , +then exit. .El .Sh RETURN VALUES -The program exits with 0 on success, non-zero on failures. +The +.Nm +program exits 0 on success, and >0 on failures. .\" .Sh FILES .Bl -tag -width /var/run/rtsold.dump -compact @@ -204,7 +208,7 @@ In some operating systems, when a PCMCIA network card is removed and reinserted, the corresponding interface index is changed. However, .Nm -does not assume such changes, and always uses the index that +assumes such changes will not occur, and always uses the index that it got at invocation. As a result, .Nm may not work if you reinsert a network card. @@ -212,11 +216,11 @@ In such a case, .Nm should be killed and restarted. .Pp -IPv6 autoconfiguration specification assumes single interface host. -You may see kernel error message if you try to autoconfigure a host with +The IPv6 autoconfiguration specification assumes a single-interface host. +You may see kernel error messages if you try to autoconfigure a host with multiple interfaces. Also, it seems contradictory for .Nm to accept multiple -.Ar interfaces -in argument. +.Ar interface +arguments. diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c index a2e39df..a4bb0e4 100644 --- a/usr.sbin/rtsold/rtsold.c +++ b/usr.sbin/rtsold/rtsold.c @@ -1,4 +1,4 @@ -/* $KAME: rtsold.c,v 1.26 2000/08/13 18:17:15 itojun Exp $ */ +/* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -110,7 +110,7 @@ main(argc, argv) int argc; char *argv[]; { - int s, ch; + int s, rtsock, maxfd, ch; int once = 0; struct timeval *timeout; struct fd_set fdset; @@ -223,6 +223,13 @@ main(argc, argv) errx(1, "failed to open a socket"); /*NOTREACHED*/ } + maxfd = s; + if ((rtsock = rtsock_open()) < 0) { + errx(1, "failed to open a socket"); + /*NOTREACHED*/ + } + if (rtsock > maxfd) + maxfd = rtsock; /* configuration per interface */ if (ifinit()) { @@ -263,6 +270,7 @@ main(argc, argv) FD_ZERO(&fdset); FD_SET(s, &fdset); + FD_SET(rtsock, &fdset); while (1) { /* main loop */ int e; struct fd_set select_fd = fdset; @@ -289,8 +297,8 @@ main(argc, argv) if (ifi == NULL) break; } - - if ((e = select(s + 1, &select_fd, NULL, NULL, timeout)) < 1) { + e = select(maxfd + 1, &select_fd, NULL, NULL, timeout); + if (e < 1) { if (e < 0 && errno != EINTR) { warnmsg(LOG_ERR, __FUNCTION__, "select: %s", strerror(errno)); @@ -299,7 +307,9 @@ main(argc, argv) } /* packet reception */ - if (FD_ISSET(s, &fdset)) + if (FD_ISSET(rtsock, &select_fd)) + rtsock_input(rtsock); + if (FD_ISSET(s, &select_fd)) rtsol_input(s); } /* NOTREACHED */ @@ -597,7 +607,18 @@ rtsol_timer_update(struct ifinfo *ifinfo) ifinfo->timer.tv_usec = interval % MILLION; break; case IFS_PROBE: - ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; + if (ifinfo->probes < MAX_RTR_SOLICITATIONS) + ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; + else { + /* + * After sending MAX_RTR_SOLICITATIONS solicitations, + * we're just waiting for possible replies; there + * will be no more solicatation. Thus, we change + * the timer value to MAX_RTR_SOLICITATION_DELAY based + * on RFC 2461, Section 6.3.7. + */ + ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; + } break; default: warnmsg(LOG_ERR, __FUNCTION__, diff --git a/usr.sbin/rtsold/rtsold.h b/usr.sbin/rtsold/rtsold.h index b6eec21..52175fa 100644 --- a/usr.sbin/rtsold/rtsold.h +++ b/usr.sbin/rtsold/rtsold.h @@ -1,4 +1,4 @@ -/* $KAME: rtsold.h,v 1.9 2000/08/13 06:15:00 itojun Exp $ */ +/* $KAME: rtsold.h,v 1.11 2000/10/10 06:18:04 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -89,3 +89,7 @@ extern void defrouter_probe __P((int ifindex)); /* dump.c */ extern void rtsold_dump_file __P((char *)); + +/* rtsock.c */ +extern int rtsock_open __P((void)); +extern int rtsock_input __P((int)); diff --git a/usr.sbin/setkey/parse.y b/usr.sbin/setkey/parse.y index 0eea4c1..1d43dc4 100644 --- a/usr.sbin/setkey/parse.y +++ b/usr.sbin/setkey/parse.y @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: parse.y,v 1.29 2000/06/10 14:17:44 sakane Exp $ */ +/* $KAME: kame/kame/kame/setkey/parse.y,v 1.36 2001/06/07 15:53:12 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -57,6 +57,7 @@ u_int p_type; u_int32_t p_spi; +int p_no_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; @@ -79,7 +80,6 @@ extern int m_len; extern char cmdarg[8192]; extern int f_debug; -int setkeymsg __P((void)); static struct addrinfo *parse_addr __P((char *, char *, int)); static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int)); void parse_init __P((void)); @@ -107,7 +107,7 @@ extern void yyerror __P((const char *)); %token F_EXT EXTENSION NOCYCLICSEQ %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 +%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY /* SPD management */ %token SPDADD SPDDELETE SPDDUMP SPDFLUSH %token F_POLICY PL_REQUESTS @@ -118,7 +118,7 @@ extern void yyerror __P((const char *)); %type <num> DECSTRING %type <val> ADDRESS PL_REQUESTS %type <val> key_string policy_requests -%type <val> QUOTEDSTRING HEXSTRING +%type <val> QUOTEDSTRING HEXSTRING STRING %% commands @@ -140,6 +140,7 @@ command : add_command | get_command | delete_command + | deleteall_command | flush_command | dump_command | spdadd_command @@ -166,6 +167,16 @@ delete_command EOT ; + /* deleteall command */ +deleteall_command + : DELETEALL { p_type = SADB_DELETE; } + ipaddress { p_src = pp_addr; } + ipaddress { p_dst = pp_addr; } + protocol_spec + { p_no_spi = 1; } + EOT + ; + /* get command */ get_command : GET { p_type = SADB_GET; } @@ -327,7 +338,7 @@ auth_alg auth_key : /*NOTHING*/ { - if (p_alg_auth != SADB_AALG_NULL) { + if (p_alg_auth != SADB_X_AALG_NULL) { yyerror("no key found."); return -1; } @@ -541,10 +552,27 @@ port upper_spec : DECSTRING { p_upper = $1; } | UP_PROTO { p_upper = $1; } - | PR_ESP { p_upper = IPPROTO_ESP; }; - | PR_AH { p_upper = IPPROTO_AH; }; - | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; }; | ANY { p_upper = IPSEC_ULPROTO_ANY; } + | STRING + { + struct protoent *ent; + + ent = getprotobyname($1.buf); + if (ent) + p_upper = ent->p_proto; + else { + if (strcmp("icmp6", $1.buf) == 0) { + p_upper = IPPROTO_ICMPV6; + } else if(strcmp("ip4", $1.buf) == 0) { + p_upper = IPPROTO_IPV4; + } else { + yyerror("invalid upper layer protocol"); + free($1.buf); + return -1; + } + } + free($1.buf); + } ; policy_spec @@ -665,27 +693,29 @@ setkeymsg() 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; + if (p_no_spi == 0) { + 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; - len = sizeof(struct sadb_x_sa2); - m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); - m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - m_sa2.sadb_x_sa2_mode = p_mode; - m_sa2.sadb_x_sa2_reqid = p_reqid; + len = sizeof(struct sadb_x_sa2); + m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); + m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + m_sa2.sadb_x_sa2_mode = p_mode; + m_sa2.sadb_x_sa2_reqid = p_reqid; - memcpy(m_buf + m_len, &m_sa2, len); - m_len += len; + memcpy(m_buf + m_len, &m_sa2, len); + m_len += len; + } /* set src */ m_addr.sadb_address_len = @@ -864,6 +894,7 @@ parse_init() { p_type = 0; p_spi = 0; + p_no_spi = 0; p_src = 0, p_dst = 0; pp_prefix = p_prefs = p_prefd = ~0; diff --git a/usr.sbin/setkey/scriptdump.pl b/usr.sbin/setkey/scriptdump.pl index aa36544..33907dc 100644 --- a/usr.sbin/setkey/scriptdump.pl +++ b/usr.sbin/setkey/scriptdump.pl @@ -33,11 +33,11 @@ foreach $_ (<IN>) { $akey =~ s/\s//g; $akey =~ s/^/0x/g; } elsif (/^\treplay=(\d+) flags=(0x\d+) state=/) { - print "$mode $src $dst $proto $spi -m $ipsecmode"; + print "$mode $src $dst $proto $spi"; $replay = $1; print " -u $reqid" if $reqid; if ($mode eq 'add') { - print " -r $replay" if $replay; + print " -m $ipsecmode -r $replay" if $replay; if ($proto eq 'esp') { print " -E $ealgo $ekey" if $ealgo; print " -A $aalgo $akey" if $aalgo; diff --git a/usr.sbin/setkey/setkey.8 b/usr.sbin/setkey/setkey.8 index 7921800..368fc5d 100644 --- a/usr.sbin/setkey/setkey.8 +++ b/usr.sbin/setkey/setkey.8 @@ -1,5 +1,5 @@ -.\" $FreeBSD$ -.\" $KAME: setkey.8,v 1.28 2000/06/16 12:03:46 sakane Exp $ +.\" $KAME: setkey.8,v 1.49 2001/05/18 05:49:51 sakane Exp $ +.\" $FreeBSD$ .\" .\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. .\" All rights reserved. @@ -28,9 +28,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 17, 1998 +.Dd November 20, 2000 .Dt SETKEY 8 -.Os KAME +.Os .\" .Sh NAME .Nm setkey @@ -55,7 +55,7 @@ .\" .Sh DESCRIPTION .Nm -addes, updates, dumpes, or flushes +adds, updates, dumps, or flushes Security Association Database (SAD) entries as well as Security Policy Database (SPD) entries in the kernel. .Pp @@ -94,11 +94,14 @@ it has been expired but remains because it is referenced by SPD entries. .It Fl d Enable to print debugging messages for command parser, -without talking to kernel. It is not used usually. +without talking to kernel. +It is not used usually. .It Fl x Loop forever and dump all the messages transmitted to .Dv PF_KEY socket. +.Fl xx +makes each timestamps unformatted. .It Fl h Add hexadecimal dump on .Fl x @@ -108,14 +111,13 @@ Loop forever with short output on .Fl D . .It Fl v Be verbose. +The program will dump messages exchanged on .Dv PF_KEY -socket -.Po -including messages sent from other processes -.Pc . +socket, including messages sent from other processes to the kernel. .El .Pp -Operations have the following grammar. Note that lines starting with +Operations have the following grammar. +Note that lines starting with hashmarks ('#') are treated as comment lines. .Bl -tag -width Ds .It Xo @@ -142,6 +144,13 @@ Show an SAD entry. Remove an SAD entry. .\" .It Xo +.Li deleteall +.Ar src Ar dst Ar protocol +.Li ; +.Xc +Remove all SAD entries that match the specification. +.\" +.It Xo .Li flush .Op Ar protocol .Li ; @@ -227,7 +236,7 @@ attached .\" .Pp .It Ar extensions -take some of the following: +takes some of the following: .Bl -tag -width Fl -compact .\" .It Fl m Ar mode @@ -243,39 +252,49 @@ The default value is .It Fl r Ar size Specify window size of bytes for replay prevention. .Ar size -must be decimal number in 32-bit word. If +must be decimal number in 32-bit word. +If .Ar size is zero or not specified, replay check don't take place. .\" .It Fl u Ar id -Specify the identifier of policy. See also -.Xr ipsec_set_policy 3 . +Specify the identifier of the policy entry in SPD. +See +.Ar policy . .\" .It Fl f Ar pad_option +defines the content of the ESP padding. .Ar pad_option is one of following: -.Li zero-pad , random-pad -or -.Li seq-pad +.Bl -tag -width random-pad -compact +.It Li zero-pad +All of the padding are zero. +.It Li random-pad +A series of randomized values are set. +.It Li seq-pad +A series of sequential increasing numbers started from 1 are set. +.El .\" .It Fl f Li nocyclic-seq Don't allow cyclic sequence number. .\" .It Fl lh Ar time .It Fl ls Ar time -Specify hard/soft lifetime. +Specify hard/soft life time duration of the SA. .El .\" .Pp .It Ar algorithm .Bl -tag -width Fl -compact .It Fl E Ar ealgo Ar key -Specify encryption algorithm. +Specify a encryption algorithm. .It Fl A Ar aalgo Ar key -Specify authentication algorithm. +Specify a authentication algorithm. If .Fl A -is used for esp, it will be treated as ESP payload authentication algorithm. +is used with +.Ar protocol Li esp , +it will be treated as ESP payload authentication algorithm. .It Fl C Ar calgo Op Fl R Specify compression algorithm. If @@ -302,23 +321,23 @@ field needs to be smaller than in this case. .El .Pp -.Li esp -SAs accept +.Ar protocol Li esp +accepts .Fl E and .Fl A . -.Li esp-old -SAs accept +.Ar protocol Li esp-old +accepts .Fl E only. -.Li ah +.Ar protocol Li ah and .Li ah-old -SAs accept +accept .Fl A only. -.Li ipcomp -SAs accept +.Ar protocol Li ipcomp +accepts .Fl C only. .Pp @@ -365,45 +384,57 @@ They must be in numeric form. .Pp .It Ar upperspec Upper-layer protocol to be used. -Currently -.Li icmp , +You can use one of words in +.Pa /etc/protocols +as +.Ar upperspec . +Or .Li icmp6 , .Li ip4 , -.Li tcp , -.Li udp and .Li any can be specified. .Li any stands for .Dq any protocol . +Also you can use the protocol number. .Pp NOTE: .Ar upperspec does not work against forwarding case at this moment, as it requires extra reassembly at forwarding node .Pq not implemented at this moment . +We have many protocols in +.Pa /etc/protocols , +but protocols except of TCP, UDP and ICMP may not be suitable to use with IPSec. +You have to consider and be careful to use them. +.Li icmp +.Li tcp +.Li udp +all protocols .\" .Pp .It Ar policy .Ar policy is the one of following: -.Pp -.Bl -item -compact -.It +.Bd -literal -offset +.Xo .Fl P .Ar direction .Li discard -.It +.Xc +.Xo .Fl P .Ar direction .Li none -.It +.Xc +.Xo .Fl P .Ar direction .Li ipsec .Ar protocol/mode/src-dst/level -.El +.Xc +.Ed .Pp You must specify the direction of its policy as .Ar direction . @@ -430,18 +461,33 @@ is either .Li transport or .Li tunnel . -You must specify the end-points addresses of the SA as +If +.Ar mode +is +.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. +If +.Ar mode +is +.Li transport , +both +.Ar src +and +.Ar dst +can be omited. .Ar level is to be one of the following: -.Li default , use +.Li default , use , require or -.Li require . +.Li unique . +If the SA is not available in every level, the kernel will request +getting SA to the key exchange daemon. .Li default means the kernel consults to the system wide default against protocol you specified, e.g. @@ -451,7 +497,23 @@ sysctl variable, when the kernel processes the packet. means that the kernel use a SA if it's available, otherwise the kernel keeps normal operation. .Li require -means SA is required whenever the kernel deals with the packet. +means SA is required whenever the kernel sends a packet matched +with the policy. +.Li unique +is the same to require. +In addition, it allows the policy to bind with the unique out-bound SA. +If you use the SA by manual keying, +you can put the decimal number as the policy identifier after +.Li unique +separated by colon +.Sq \: +like the following; +.Li unique:number . +.Li number +must be between 1 and 32767. +It corresponds to +.Ar extensions Fl u . +.Pp Note that .Dq Li discard and @@ -491,6 +553,12 @@ keyed-md5 128 ah: 96bit ICV (no document) keyed-sha1 160 ah: 96bit ICV (no document) 160 ah-old: 128bit ICV (no document) null 0 to 2048 for debugging +hmac-sha2-256 256 ah: 96bit ICV (no document) + 256 ah-old: 128bit ICV (no document) +hmac-sha2-384 384 ah: 96bit ICV (no document) + 384 ah-old: 128bit ICV (no document) +hmac-sha2-512 512 ah: 96bit ICV (no document) + 512 ah-old: 128bit ICV (no document) .Ed .Pp Followings are the list of encryption algorithms that can be used as @@ -508,9 +576,9 @@ des-cbc 64 esp-old: rfc1829, esp: rfc2405 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 +rijndael-cbc 128/192/256 draft-ietf-ipsec-ciph-aes-cbc-00 .Ed .Pp Followings are the list of compression algorithms that can be used as @@ -555,7 +623,8 @@ The command exits with 0 on success, and non-zero on errors. .\" .Sh SEE ALSO .Xr ipsec_set_policy 3 , -.Xr sysctl 8 +.Xr sysctl 8 , +.Xr racoon 8 .\" .Sh HISTORY The diff --git a/usr.sbin/setkey/setkey.c b/usr.sbin/setkey/setkey.c index b1e1c1e..e729e7d 100644 --- a/usr.sbin/setkey/setkey.c +++ b/usr.sbin/setkey/setkey.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: setkey.c,v 1.14 2000/06/10 06:47:09 sakane Exp $ */ +/* $KAME: setkey.c,v 1.18 2001/05/08 04:36:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -63,6 +63,8 @@ int postproc __P((struct sadb_msg *, int)); const char *numstr __P((int)); void shortdump_hdr __P((void)); void shortdump __P((struct sadb_msg *)); +static void printdate __P((void)); +static int32_t gmt2local __P((time_t)); #define MODE_SCRIPT 1 #define MODE_CMDDUMP 2 @@ -79,11 +81,14 @@ int f_mode = 0; int f_cmddump = 0; int f_policy = 0; int f_hexdump = 0; +int f_tflag = 0; char *pname; u_char m_buf[BUFSIZ]; u_int m_len; +static time_t thiszone; + extern int lineno; extern int parse __P((FILE **)); @@ -112,7 +117,9 @@ main(ac, av) if (ac == 1) Usage(); - while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) { + thiszone = gmt2local(0); + + while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { switch (c) { case 'c': f_mode = MODE_SCRIPT; @@ -142,6 +149,7 @@ main(ac, av) break; case 'x': f_mode = MODE_PROMISC; + f_tflag++; break; case 'P': f_policy = 1; @@ -199,7 +207,7 @@ get_supported() if (f_debug) return 0; - if (pfkey_send_register(so, PF_UNSPEC) < 0) + if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) return -1; if (pfkey_recv_register(so) < 0) @@ -275,6 +283,7 @@ promisc() err(1, "recv"); /*NOTREACHED*/ } + printdate(); if (f_hexdump) { int i; for (i = 0; i < len; i++) { @@ -541,7 +550,7 @@ shortdump(msg) snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); printf("%s", buf); } else - printf(" ???/???"); + printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ printf(" "); @@ -576,3 +585,64 @@ shortdump(msg) printf("\n"); } + +/* From: tcpdump(1):gmt2local.c and util.c */ +/* + * Print the timestamp + */ +static void +printdate() +{ + struct timeval tp; + int s; + + if (gettimeofday(&tp, NULL) == -1) { + perror("gettimeofday"); + return; + } + + if (f_tflag == 1) { + /* Default */ + s = (tp.tv_sec + thiszone ) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); + } else if (f_tflag > 1) { + /* Unix timeval style */ + (void)printf("%u.%06u ", + (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); + } + + printf("\n"); +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + */ +int32_t +gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} diff --git a/usr.sbin/setkey/token.l b/usr.sbin/setkey/token.l index c2eaad5..208196e 100644 --- a/usr.sbin/setkey/token.l +++ b/usr.sbin/setkey/token.l @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: token.l,v 1.13 2000/06/07 00:29:14 itojun Exp $ */ +/* $KAME: token.l,v 1.21 2001/05/18 05:35:01 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -47,7 +47,11 @@ #include <unistd.h> #include <errno.h> #include "vchar.h" +#ifdef __NetBSD__ +#include "parse.h" +#else #include "y.tab.h" +#endif #define DECHO \ if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); } @@ -121,6 +125,7 @@ hostname {name}(({dot}{name})+{dot}?)? add { PREPROC; return(ADD); } delete { PREPROC; return(DELETE); } +deleteall { PREPROC; return(DELETEALL); } get { PREPROC; return(GET); } flush { PREPROC; return(FLUSH); } dump { PREPROC; return(DUMP); } @@ -160,20 +165,23 @@ ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); } {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); } +keyed-md5 { PREPROC; yylval.num = SADB_X_AALG_MD5; return(ALG_AUTH); } +keyed-sha1 { PREPROC; yylval.num = SADB_X_AALG_SHA; return(ALG_AUTH); } +hmac-sha2-256 { PREPROC; yylval.num = SADB_X_AALG_SHA2_256; return(ALG_AUTH); } +hmac-sha2-384 { PREPROC; yylval.num = SADB_X_AALG_SHA2_384; return(ALG_AUTH); } +hmac-sha2-512 { PREPROC; yylval.num = SADB_X_AALG_SHA2_512; return(ALG_AUTH); } +null { PREPROC; yylval.num = SADB_X_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); } +blowfish-cbc { PREPROC; yylval.num = SADB_X_EALG_BLOWFISHCBC; return(ALG_ENC); } +cast128-cbc { PREPROC; yylval.num = SADB_X_EALG_CAST128CBC; 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); } +rijndael-cbc { PREPROC; yylval.num = SADB_X_EALG_RIJNDAELCBC; return(ALG_ENC); } /* compression algorithms */ {hyphen}C { PREPROC; return(F_COMP); } @@ -196,14 +204,6 @@ nocyclic-seq { PREPROC; return(NOCYCLICSEQ); } {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); } -ip4 { PREPROC; yylval.num = IPPROTO_IPV4; 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; } @@ -277,6 +277,12 @@ any { PREPROC; return(ANY); } return(QUOTEDSTRING); } +[a-z0-9.\-]* { + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + return(STRING); + } + . { yyfatal("Syntax error"); /*NOTREACHED*/ diff --git a/usr.sbin/traceroute6/traceroute6.8 b/usr.sbin/traceroute6/traceroute6.8 index 532f198..20f9d38 100644 --- a/usr.sbin/traceroute6/traceroute6.8 +++ b/usr.sbin/traceroute6/traceroute6.8 @@ -1,3 +1,5 @@ +.\" $KAME: traceroute6.8,v 1.8 2000/06/12 16:29:18 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" diff --git a/usr.sbin/traceroute6/traceroute6.c b/usr.sbin/traceroute6/traceroute6.c index d715cc3..f5f3fbe 100644 --- a/usr.sbin/traceroute6/traceroute6.c +++ b/usr.sbin/traceroute6/traceroute6.c @@ -1,4 +1,4 @@ -/* $KAME: traceroute6.c,v 1.32 2000/07/07 12:21:34 itojun Exp $ */ +/* $KAME: traceroute6.c,v 1.42 2001/05/08 04:36:41 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -385,6 +385,7 @@ main(argc, argv) int ch, i, on, probe, seq, hops, rcvcmsglen; static u_char *rcvcmsgbuf; char hbuf[NI_MAXHOST], src0[NI_MAXHOST]; + char *ep; /* * Receive ICMP @@ -394,6 +395,10 @@ main(argc, argv) exit(5); } + /* revoke privs */ + seteuid(getuid()); + setuid(getuid()); + /* set a minimum set of socket options */ on = 1; /* specify to tell receiving interface */ @@ -418,19 +423,21 @@ main(argc, argv) err(1, "setsockopt(IPV6_HOPLIMIT)"); #endif - /* revoke privs */ - seteuid(getuid()); - setuid(getuid()); - seq = 0; - while ((ch = getopt(argc, argv, "df:g:lm:np:q:rs:w:v")) != EOF) + while ((ch = getopt(argc, argv, "df:g:lm:np:q:rs:w:v")) != -1) switch(ch) { case 'd': options |= SO_DEBUG; break; case 'f': - first_hop = atoi(optarg); + ep = NULL; + first_hop = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid min hoplimit.\n"); + exit(1); + } if (first_hop > max_hops) { Fprintf(stderr, "traceroute6: min hoplimit must be <= %d.\n", max_hops); @@ -477,7 +484,13 @@ main(argc, argv) lflag++; break; case 'm': - max_hops = atoi(optarg); + ep = NULL; + max_hops = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid max hoplimit.\n"); + exit(1); + } if (max_hops < first_hop) { Fprintf(stderr, "traceroute6: max hoplimit must be >= %d.\n", first_hop); @@ -488,7 +501,13 @@ main(argc, argv) nflag++; break; case 'p': - port = atoi(optarg); + ep = NULL; + port = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: port.\n"); + exit(1); + } if (port < 1) { Fprintf(stderr, "traceroute6: port must be >0.\n"); @@ -496,7 +515,13 @@ main(argc, argv) } break; case 'q': - nprobes = atoi(optarg); + ep = NULL; + nprobes = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid nprobes.\n"); + exit(1); + } if (nprobes < 1) { Fprintf(stderr, "traceroute6: nprobes must be >0.\n"); @@ -517,7 +542,13 @@ main(argc, argv) verbose++; break; case 'w': - waittime = atoi(optarg); + ep = NULL; + waittime = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid wait time.\n"); + exit(1); + } if (waittime <= 1) { Fprintf(stderr, "traceroute6: wait must be >1 sec.\n"); @@ -530,7 +561,7 @@ main(argc, argv) argc -= optind; argv += optind; - if (argc < 1) + if (argc < 1 || argc > 2) usage(); #if 1 @@ -557,9 +588,20 @@ main(argc, argv) } memcpy(&Dst, res->ai_addr, res->ai_addrlen); hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; + if (!hostname) { + (void)fprintf(stderr, "traceroute6: not enough core\n"); + exit(1); + } - if (*++argv) - datalen = atoi(*argv); + if (*++argv) { + ep = NULL; + datalen = strtoul(*argv, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid packet length.\n"); + exit(1); + } + } if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { Fprintf(stderr, "traceroute6: packet size must be 0 <= s < %ld.\n", @@ -787,7 +829,7 @@ main(argc, argv) */ if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag)) - strcpy(hbuf, "(invalid)"); + strlcpy(hbuf, "(invalid)", sizeof(hbuf)); Fprintf(stderr, "traceroute6"); Fprintf(stderr, " to %s (%s)", hostname, hbuf); if (source) @@ -889,7 +931,7 @@ wait_for_reply(sock, mhdr) struct timeval wait; int cc = 0, fdsn; - fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask); + fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) err(1, "malloc"); memset(fdsp, 0, fdsn); @@ -1074,7 +1116,7 @@ packet_ok(mhdr, cc, seq) if (getnameinfo((struct sockaddr *)from, from->sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) - strcpy(hbuf, "invalid"); + strlcpy(hbuf, "invalid", sizeof(hbuf)); Printf("packet too short (%d bytes) from %s\n", cc, hbuf); } @@ -1088,7 +1130,7 @@ packet_ok(mhdr, cc, seq) if (getnameinfo((struct sockaddr *)from, from->sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) - strcpy(hbuf, "invalid"); + strlcpy(hbuf, "invalid", sizeof(hbuf)); Printf("data too short (%d bytes) from %s\n", cc, hbuf); } return(0); @@ -1146,7 +1188,7 @@ packet_ok(mhdr, cc, seq) if (getnameinfo((struct sockaddr *)from, from->sin6_len, sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) - strcpy(sbuf, "invalid"); + strlcpy(sbuf, "invalid", sizeof(hbuf)); Printf("\n%d bytes from %s to %s", cc, sbuf, rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, dbuf, sizeof(dbuf)) @@ -1225,7 +1267,7 @@ print(mhdr, cc) if (getnameinfo((struct sockaddr *)from, from->sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) - strcpy(hbuf, "invalid"); + strlcpy(hbuf, "invalid", sizeof(hbuf)); if (nflag) Printf(" %s", hbuf); else if (lflag) @@ -1282,7 +1324,7 @@ inetname(sa) first = 0; if (gethostname(domain, MAXHOSTNAMELEN) == 0 && (cp = index(domain, '.'))) - (void) strcpy(domain, cp + 1); + (void) strlcpy(domain, cp + 1, sizeof(domain)); else domain[0] = 0; } @@ -1301,7 +1343,7 @@ inetname(sa) if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, NI_NUMERICHOST | niflag) != 0) - strcpy(line, "invalid"); + strlcpy(line, "invalid", sizeof(line)); return line; } @@ -1309,7 +1351,7 @@ void usage() { (void)fprintf(stderr, -"usage: traceroute6 [-dlnrv] [-f first_hop] [-m max_hops] [-p port#] \n" -" [-q nqueries] [-s src_addr] [-g gateway] [-w wait] host [data size]\n"); +"usage: traceroute6 [-dlnrv] [-f firsthop] [-g gateway] [-m hoplimit] [-p port]\n" +" [-q probes] [-s src] [-w waittime] target [datalen]\n"); exit(1); } |