Module Name:    src
Committed By:   knakahara
Date:           Fri Apr  6 10:38:53 UTC 2018

Modified Files:
        src/sys/net: if_ipsec.c
        src/sys/netipsec: ipsecif.c ipsecif.h

Log Message:
Fix unexpected failure when ipsecif(4) over IPv6 is changed port number only.

Here is an example of the operation which causes this problem.
    # ifconfig ipsec0 create link0
    # ifconfig ipsec0 tunnel fc00:1001::2,4500 fc00:1001::1,4501
    # ifconfig ipsec0 tunnel fc00:1001::2,4500 fc00:1001::1,4502


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/net/if_ipsec.c
cvs rdiff -u -r1.6 -r1.7 src/sys/netipsec/ipsecif.c
cvs rdiff -u -r1.1 -r1.2 src/sys/netipsec/ipsecif.h

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

Modified files:

Index: src/sys/net/if_ipsec.c
diff -u src/sys/net/if_ipsec.c:1.10 src/sys/net/if_ipsec.c:1.11
--- src/sys/net/if_ipsec.c:1.10	Fri Apr  6 09:30:09 2018
+++ src/sys/net/if_ipsec.c	Fri Apr  6 10:38:53 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ipsec.c,v 1.10 2018/04/06 09:30:09 knakahara Exp $  */
+/*	$NetBSD: if_ipsec.c,v 1.11 2018/04/06 10:38:53 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.10 2018/04/06 09:30:09 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.11 2018/04/06 10:38:53 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -280,7 +280,7 @@ if_ipsec_fwd_ipv6(struct ipsec_softc *sc
 int
 if_ipsec_encap_func(struct mbuf *m, int off, int proto, void *arg)
 {
-	struct ip ip;
+	uint8_t v;
 	struct ipsec_softc *sc;
 	struct ipsec_variant *var = NULL;
 	struct psref psref;
@@ -304,18 +304,39 @@ if_ipsec_encap_func(struct mbuf *m, int 
 		goto out;
 	}
 
-	if (m->m_pkthdr.len < sizeof(ip))
-		goto out;
+	m_copydata(m, 0, sizeof(v), &v);
+	v = (v >> 4) & 0xff;  /* Get the IP version number. */
 
-	m_copydata(m, 0, sizeof(ip), &ip);
-	switch (ip.ip_v) {
+	switch (v) {
 #ifdef INET
-	case IPVERSION:
+	case IPVERSION: {
+		struct ip ip;
+
+		if (m->m_pkthdr.len < sizeof(ip))
+			goto out;
+
+		m_copydata(m, 0, sizeof(ip), &ip);
 		if (var->iv_psrc->sa_family != AF_INET ||
 		    var->iv_pdst->sa_family != AF_INET)
 			goto out;
 		ret = ipsecif4_encap_func(m, &ip, var);
 		break;
+	}
+#endif
+#ifdef INET6
+	case (IPV6_VERSION >> 4): {
+		struct ip6_hdr ip6;
+
+		if (m->m_pkthdr.len < sizeof(ip6))
+			goto out;
+
+		m_copydata(m, 0, sizeof(ip6), &ip6);
+		if (var->iv_psrc->sa_family != AF_INET6 ||
+		    var->iv_pdst->sa_family != AF_INET6)
+			goto out;
+		ret = ipsecif6_encap_func(m, &ip6, var);
+		break;
+	}
 #endif
 	default:
 		goto out;

Index: src/sys/netipsec/ipsecif.c
diff -u src/sys/netipsec/ipsecif.c:1.6 src/sys/netipsec/ipsecif.c:1.7
--- src/sys/netipsec/ipsecif.c:1.6	Fri Apr  6 10:31:35 2018
+++ src/sys/netipsec/ipsecif.c	Fri Apr  6 10:38:53 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsecif.c,v 1.6 2018/04/06 10:31:35 knakahara Exp $  */
+/*	$NetBSD: ipsecif.c,v 1.7 2018/04/06 10:38:53 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.6 2018/04/06 10:31:35 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.7 2018/04/06 10:38:53 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -412,6 +412,57 @@ done:
 }
 
 #ifdef INET6
+int
+ipsecif6_encap_func(struct mbuf *m, struct ip6_hdr *ip6, struct ipsec_variant *var)
+{
+	struct m_tag *mtag;
+	struct sockaddr_in6 *src, *dst;
+	u_int16_t src_port = 0;
+	u_int16_t dst_port = 0;
+
+	KASSERT(var != NULL);
+
+	src = satosin6(var->iv_psrc);
+	dst = satosin6(var->iv_pdst);
+	mtag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL);
+	if (mtag) {
+		u_int16_t *ports;
+
+		ports = (u_int16_t *)(mtag + 1);
+		src_port = ports[0];
+		dst_port = ports[1];
+	}
+
+	/* address match */
+	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
+	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
+		return 0;
+
+	/* UDP encap? */
+	if (mtag == NULL && var->iv_sport == 0 && var->iv_dport == 0)
+		goto match;
+
+	/* port match */
+	if (src_port != var->iv_dport ||
+	    dst_port != var->iv_sport) {
+#ifdef DEBUG
+		printf("%s: port mismatch: pkt(%u, %u), if(%u, %u)\n",
+		    __func__, ntohs(src_port), ntohs(dst_port),
+		    ntohs(var->iv_sport), ntohs(var->iv_dport));
+#endif
+		return 0;
+	}
+
+match:
+	/*
+	 * hide NAT-T information from encapsulated traffics.
+	 * they don't know about IPsec.
+	 */
+	if (mtag)
+		m_tag_delete(m, mtag);
+	return sizeof(src->sin6_addr) + sizeof(dst->sin6_addr);
+}
+
 static int
 ipsecif6_output(struct ipsec_variant *var, int family, struct mbuf *m)
 {
@@ -841,9 +892,7 @@ ipsecif6_attach(struct ipsec_variant *va
 	mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
 	mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
 
-	var->iv_encap_cookie6 = encap_attach(AF_INET6, -1,
-	    var->iv_psrc, (struct sockaddr *)&mask6,
-	    var->iv_pdst, (struct sockaddr *)&mask6,
+	var->iv_encap_cookie6 = encap_attach_func(AF_INET6, -1, if_ipsec_encap_func,
 	    &ipsecif6_encapsw, sc);
 	if (var->iv_encap_cookie6 == NULL)
 		return EEXIST;

Index: src/sys/netipsec/ipsecif.h
diff -u src/sys/netipsec/ipsecif.h:1.1 src/sys/netipsec/ipsecif.h:1.2
--- src/sys/netipsec/ipsecif.h:1.1	Wed Jan 10 10:56:30 2018
+++ src/sys/netipsec/ipsecif.h	Fri Apr  6 10:38:53 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsecif.h,v 1.1 2018/01/10 10:56:30 knakahara Exp $  */
+/*	$NetBSD: ipsecif.h,v 1.2 2018/04/06 10:38:53 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -39,6 +39,7 @@ int ipsecif4_encap_func(struct mbuf *, s
 int ipsecif4_attach(struct ipsec_variant *);
 int ipsecif4_detach(struct ipsec_variant *);
 
+int ipsecif6_encap_func(struct mbuf *, struct ip6_hdr *, struct ipsec_variant *);
 int ipsecif6_attach(struct ipsec_variant *);
 int ipsecif6_detach(struct ipsec_variant *);
 void *ipsecif6_ctlinput(int, const struct sockaddr *, void *, void *);

Reply via email to