Module Name:    src
Committed By:   martin
Date:           Thu Jul 25 08:58:21 UTC 2019

Modified Files:
        src/crypto/dist/ipsec-tools/src/setkey [netbsd-8]: parse.y token.l
        src/sys/netipsec [netbsd-8]: key.c
        src/tests/net/ipsec [netbsd-8]: t_ipsec_misc.sh

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #1306):

        crypto/dist/ipsec-tools/src/setkey/parse.y: revision 1.23
        sys/netipsec/key.c: revision 1.265
        crypto/dist/ipsec-tools/src/setkey/token.l: revision 1.23
        tests/net/ipsec/t_ipsec_misc.sh: revision 1.23

ipsec: fix a regression of the update API

The update API updates an SA by creating a new SA and removing an existing SA.
The previous change removed a newly added SA wrongly if an existing SA had been
created by the getspi API.

setkey: enable to use the getspi API

If a specified SPI is not zero, tell the kernel to use the SPI by using
SADB_EXT_SPIRANGE.  Otherwise, the kernel picks a random SPI.

It enables to mimic racoon.

tests: add tests for getspi and udpate


To generate a diff of this commit:
cvs rdiff -u -r1.18.4.1 -r1.18.4.2 \
    src/crypto/dist/ipsec-tools/src/setkey/parse.y
cvs rdiff -u -r1.19.8.1 -r1.19.8.2 \
    src/crypto/dist/ipsec-tools/src/setkey/token.l
cvs rdiff -u -r1.163.2.11 -r1.163.2.12 src/sys/netipsec/key.c
cvs rdiff -u -r1.6.2.3 -r1.6.2.4 src/tests/net/ipsec/t_ipsec_misc.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/crypto/dist/ipsec-tools/src/setkey/parse.y
diff -u src/crypto/dist/ipsec-tools/src/setkey/parse.y:1.18.4.1 src/crypto/dist/ipsec-tools/src/setkey/parse.y:1.18.4.2
--- src/crypto/dist/ipsec-tools/src/setkey/parse.y:1.18.4.1	Sat Oct 21 19:43:53 2017
+++ src/crypto/dist/ipsec-tools/src/setkey/parse.y	Thu Jul 25 08:58:21 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: parse.y,v 1.18.4.1 2017/10/21 19:43:53 snj Exp $	*/
+/*	$NetBSD: parse.y,v 1.18.4.2 2019/07/25 08:58:21 martin Exp $	*/
 
 /*	$KAME: parse.y,v 1.81 2003/07/01 04:01:48 itojun Exp $	*/
 
@@ -115,7 +115,7 @@ static int setkeymsg_add __P((unsigned i
 }
 
 %token EOT SLASH BLCL ELCL
-%token ADD UPDATE GET DELETE DELETEALL FLUSH DUMP EXIT
+%token ADD UPDATE GET GETSPI DELETE DELETEALL FLUSH DUMP EXIT
 %token PR_ESP PR_AH PR_IPCOMP PR_ESPUDP PR_TCP
 %token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI
 %token F_MODE MODE F_REQID
@@ -162,6 +162,7 @@ command
 	:	add_command
 	|	update_command
 	|	get_command
+	|	getspi_command
 	|	delete_command
 	|	deleteall_command
 	|	flush_command
@@ -261,6 +262,17 @@ get_command
 		}
 	;
 
+	/* getspi command */
+getspi_command
+	:	GETSPI ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT
+		{
+			int status;
+
+			status = setkeymsg_add(SADB_GETSPI, $5, $3, $4);
+			if (status < 0)
+				return -1;
+		}
+
 	/* flush */
 flush_command
 	:	FLUSH protocol_spec EOT
@@ -1409,6 +1421,21 @@ setkeymsg_add(type, satype, srcs, dsts)
 	}
 #endif
 
+	/* SPI == 0 allows the kernel to pick a random SPI */
+	if (type == SADB_GETSPI && p_spi != 0) {
+		struct sadb_spirange spirange;
+		u_int slen = sizeof(struct sadb_spirange);
+
+		memset(&spirange, 0, sizeof(spirange));
+		spirange.sadb_spirange_len = PFKEY_UNIT64(slen);
+		spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+		spirange.sadb_spirange_min = p_spi;
+		spirange.sadb_spirange_max = p_spi;
+
+		memcpy(buf + l, &spirange, slen);
+		l += slen;
+	}
+
 	len = sizeof(struct sadb_sa);
 	m_sa.sadb_sa_len = PFKEY_UNIT64(len);
 	m_sa.sadb_sa_exttype = SADB_EXT_SA;

Index: src/crypto/dist/ipsec-tools/src/setkey/token.l
diff -u src/crypto/dist/ipsec-tools/src/setkey/token.l:1.19.8.1 src/crypto/dist/ipsec-tools/src/setkey/token.l:1.19.8.2
--- src/crypto/dist/ipsec-tools/src/setkey/token.l:1.19.8.1	Sat Oct 21 19:43:53 2017
+++ src/crypto/dist/ipsec-tools/src/setkey/token.l	Thu Jul 25 08:58:21 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: token.l,v 1.19.8.1 2017/10/21 19:43:53 snj Exp $	*/
+/*	$NetBSD: token.l,v 1.19.8.2 2019/07/25 08:58:21 martin Exp $	*/
 
 /*	$KAME: token.l,v 1.44 2003/10/21 07:20:58 itojun Exp $	*/
 
@@ -120,6 +120,7 @@ update		{ return(UPDATE); }
 delete		{ return(DELETE); }
 deleteall	{ return(DELETEALL); }
 get		{ return(GET); }
+getspi		{ return(GETSPI); }
 flush		{ return(FLUSH); }
 dump		{ return(DUMP); }
 exit		{ return(EXIT); }

Index: src/sys/netipsec/key.c
diff -u src/sys/netipsec/key.c:1.163.2.11 src/sys/netipsec/key.c:1.163.2.12
--- src/sys/netipsec/key.c:1.163.2.11	Mon Jul 22 18:07:07 2019
+++ src/sys/netipsec/key.c	Thu Jul 25 08:58:21 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: key.c,v 1.163.2.11 2019/07/22 18:07:07 martin Exp $	*/
+/*	$NetBSD: key.c,v 1.163.2.12 2019/07/25 08:58:21 martin Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $	*/
 /*	$KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $	*/
 
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.163.2.11 2019/07/22 18:07:07 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.163.2.12 2019/07/25 08:58:21 martin Exp $");
 
 /*
  * This code is referred to RFC 2367
@@ -3517,7 +3517,8 @@ out:
  *	others	: found, pointer to a SA.
  */
 static struct secasvar *
-key_lookup_and_remove_sav(struct secashead *sah, u_int32_t spi)
+key_lookup_and_remove_sav(struct secashead *sah, u_int32_t spi,
+    const struct secasvar *hint)
 {
 	struct secasvar *sav = NULL;
 	u_int state;
@@ -3529,6 +3530,8 @@ key_lookup_and_remove_sav(struct secashe
 			KASSERT(sav->state == state);
 
 			if (sav->spi == spi) {
+				if (hint != NULL && hint != sav)
+					continue;
 				sav->state = SADB_SASTATE_DEAD;
 				SAVLIST_WRITER_REMOVE(sav);
 				SAVLUT_WRITER_REMOVE(sav);
@@ -5777,7 +5780,8 @@ key_api_update(struct socket *so, struct
 	 * We need to lookup and remove the sav atomically, so get it again
 	 * here by a special API while we have a reference to it.
 	 */
-	oldsav = key_lookup_and_remove_sav(sah, sa0->sadb_sa_spi);
+	oldsav = key_lookup_and_remove_sav(sah, sa0->sadb_sa_spi, sav);
+	KASSERT(oldsav == NULL || oldsav == sav);
 	/* We can release the reference because of oldsav */
 	KEY_SA_UNREF(&sav);
 	if (oldsav == NULL) {
@@ -6191,7 +6195,7 @@ key_api_delete(struct socket *so, struct
 	sah = key_getsah_ref(&saidx, CMP_HEAD);
 	if (sah != NULL) {
 		/* get a SA with SPI. */
-		sav = key_lookup_and_remove_sav(sah, sa0->sadb_sa_spi);
+		sav = key_lookup_and_remove_sav(sah, sa0->sadb_sa_spi, NULL);
 		key_sah_unref(sah);
 	}
 

Index: src/tests/net/ipsec/t_ipsec_misc.sh
diff -u src/tests/net/ipsec/t_ipsec_misc.sh:1.6.2.3 src/tests/net/ipsec/t_ipsec_misc.sh:1.6.2.4
--- src/tests/net/ipsec/t_ipsec_misc.sh:1.6.2.3	Tue Nov 21 11:11:20 2017
+++ src/tests/net/ipsec/t_ipsec_misc.sh	Thu Jul 25 08:58:21 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: t_ipsec_misc.sh,v 1.6.2.3 2017/11/21 11:11:20 martin Exp $
+#	$NetBSD: t_ipsec_misc.sh,v 1.6.2.4 2019/07/25 08:58:21 martin Exp $
 #
 # Copyright (c) 2017 Internet Initiative Japan Inc.
 # All rights reserved.
@@ -40,9 +40,16 @@ setup_sasp()
 	local lifetime=$5
 	local update=$6
 	local tmpfile=./tmp
+	local saadd=add
+	local saadd_algo_args="$algo_args"
 	local extra=
 
-	if [ "$update" = sa ]; then
+	if [ "$update" = getspi ]; then
+		saadd=getspi
+		saadd_algo_args=
+	fi
+
+	if [ "$update" = sa -o "$update" = getspi ]; then
 		extra="update $ip_local $ip_peer $proto 10000 $algo_args;
 		       update $ip_peer $ip_local $proto 10001 $algo_args;"
 	elif [ "$update" = sp ]; then
@@ -51,8 +58,8 @@ setup_sasp()
 
 	export RUMP_SERVER=$SOCK_LOCAL
 	cat > $tmpfile <<-EOF
-	add $ip_local $ip_peer $proto 10000 -lh $lifetime -ls $lifetime $algo_args;
-	add $ip_peer $ip_local $proto 10001 -lh $lifetime -ls $lifetime $algo_args;
+	$saadd $ip_local $ip_peer $proto 10000 -lh $lifetime -ls $lifetime $saadd_algo_args;
+	$saadd $ip_peer $ip_local $proto 10001 -lh $lifetime -ls $lifetime $saadd_algo_args;
 	spdadd $ip_local $ip_peer any -P out ipsec $proto/transport//require;
 	$extra
 	EOF
@@ -67,8 +74,8 @@ setup_sasp()
 
 	export RUMP_SERVER=$SOCK_PEER
 	cat > $tmpfile <<-EOF
-	add $ip_local $ip_peer $proto 10000 -lh $lifetime -ls $lifetime $algo_args;
-	add $ip_peer $ip_local $proto 10001 -lh $lifetime -ls $lifetime $algo_args;
+	$saadd $ip_local $ip_peer $proto 10000 -lh $lifetime -ls $lifetime $saadd_algo_args;
+	$saadd $ip_peer $ip_local $proto 10001 -lh $lifetime -ls $lifetime $saadd_algo_args;
 	spdadd $ip_peer $ip_local any -P out ipsec $proto/transport//require;
 	$extra
 	EOF
@@ -370,6 +377,71 @@ add_test_update()
 	atf_add_test_case ${name}
 }
 
+test_getspi_update()
+{
+	local proto=$1
+	local algo=$2
+	local ip_local=10.0.0.1
+	local ip_peer=10.0.0.2
+	local algo_args="$(generate_algo_args $proto $algo)"
+	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
+	local outfile=./out
+
+	rump_server_crypto_start $SOCK_LOCAL netipsec
+	rump_server_crypto_start $SOCK_PEER netipsec
+	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
+	rump_server_add_iface $SOCK_PEER shmif0 $BUS
+
+	export RUMP_SERVER=$SOCK_LOCAL
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24
+
+	export RUMP_SERVER=$SOCK_PEER
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
+
+	setup_sasp $proto "$algo_args" $ip_local $ip_peer 100 getspi
+
+	extract_new_packets $BUS > $outfile
+
+	export RUMP_SERVER=$SOCK_LOCAL
+	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
+
+	extract_new_packets $BUS > $outfile
+	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: $proto_cap" \
+	    cat $outfile
+	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: $proto_cap" \
+	    cat $outfile
+}
+
+add_test_getspi_update()
+{
+	local proto=$1
+	local algo=$2
+	local _algo=$(echo $algo | sed 's/-//g')
+	local name= desc=
+
+	desc="Tests trying to getspi and udpate SA of $proto ($algo)"
+	name="ipsec_getspi_update_sa_${proto}_${_algo}"
+
+	atf_test_case ${name} cleanup
+	eval "
+	    ${name}_head() {
+	        atf_set descr \"$desc\"
+	        atf_set require.progs rump_server setkey
+	    }
+	    ${name}_body() {
+	        test_getspi_update $proto $algo
+	        rump_server_destroy_ifaces
+	    }
+	    ${name}_cleanup() {
+	        \$DEBUG && dump
+	        cleanup
+	    }
+	"
+	atf_add_test_case ${name}
+}
+
 add_sa()
 {
 	local proto=$1
@@ -717,6 +789,7 @@ atf_init_test_cases()
 		add_test_lifetime ipv6 esp $algo
 		add_test_update esp $algo sa
 		add_test_update esp $algo sp
+		add_test_getspi_update esp $algo
 		add_test_spi esp $algo new delete
 		add_test_spi esp $algo old delete
 		add_test_spi esp $algo new timeout
@@ -728,6 +801,7 @@ atf_init_test_cases()
 		add_test_lifetime ipv6 ah $algo
 		add_test_update ah $algo sa
 		add_test_update ah $algo sp
+		add_test_getspi_update ah $algo
 		add_test_spi ah $algo new delete
 		add_test_spi ah $algo old delete
 		add_test_spi ah $algo new timeout

Reply via email to