Module Name:    src
Committed By:   martin
Date:           Mon Apr  9 17:01:20 UTC 2018

Modified Files:
        src/sys/net [netbsd-8]: if_ipsec.c
        src/sys/netipsec [netbsd-8]: ipsecif.c ipsecif.h

Log Message:
Pull up following revision(s) (requested by knakahara in ticket #714):

        sys/net/if_ipsec.c: revision 1.8 - 1.11
        sys/netipsec/ipsecif.h: revision 1.2
        sys/netipsec/ipsecif.c: revision 1.6,1.7

fix ipsec(4) encap_lock leak.

fix ipsecif(4) unmatch curlwp_bind.

fix ipsecif(4) stack overflow.

Add IPv4 ID when the ipsecif(4) packet can be fragmented. Implemented by 
hsuenaga@IIJ and ohishi@IIJ, thanks.
This modification reduces packet loss of fragmented packets on a
network where reordering occurs.

Alghough this modification has been applied, IPv4 ID is not set for
the packet smaller then IP_MINFRAGSIZE. According to RFC 6864, that
must not cause problems.

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.3.2.4 -r1.3.2.5 src/sys/net/if_ipsec.c
cvs rdiff -u -r1.1.2.5 -r1.1.2.6 src/sys/netipsec/ipsecif.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 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.3.2.4 src/sys/net/if_ipsec.c:1.3.2.5
--- src/sys/net/if_ipsec.c:1.3.2.4	Tue Mar 13 15:34:33 2018
+++ src/sys/net/if_ipsec.c	Mon Apr  9 17:01:20 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ipsec.c,v 1.3.2.4 2018/03/13 15:34:33 martin Exp $  */
+/*	$NetBSD: if_ipsec.c,v 1.3.2.5 2018/04/09 17:01:20 martin 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.3.2.4 2018/03/13 15:34:33 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.3.2.5 2018/04/09 17:01:20 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -76,6 +76,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v
 #include <net/pfkeyv2.h>
 
 #include <netipsec/key.h>
+#include <netipsec/keydb.h> /* for union sockaddr_union */
 #include <netipsec/ipsec.h>
 #include <netipsec/ipsecif.h>
 
@@ -279,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;
@@ -303,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;
@@ -637,6 +659,7 @@ if_ipsec_ioctl(struct ifnet *ifp, u_long
 		error = if_ipsec_set_tunnel(&sc->ipsec_if, src, dst);
 		if (error)
 			goto bad;
+		curlwp_bindx(bound);
 		break;
 
 	case SIOCDIFPHYADDR:
@@ -769,6 +792,7 @@ if_ipsec_ioctl(struct ifnet *ifp, u_long
 			error = if_ipsec_ensure_flags(&sc->ipsec_if, oflags);
 			if (error)
 				goto bad;
+			curlwp_bindx(bound);
 		}
 		break;
 	}
@@ -1166,6 +1190,7 @@ if_ipsec_ensure_flags(struct ifnet *ifp,
 	if (if_ipsec_variant_is_unconfigured(ovar)) {
 		/* nothing to do */
 		mutex_exit(&sc->ipsec_lock);
+		encap_lock_exit();
 		return 0;
 	}
 
@@ -1337,10 +1362,11 @@ if_ipsec_add_mbuf_addr_port(struct mbuf 
 	if (port == 0) {
 		if_ipsec_add_mbuf_optalign(m0, addr, addr->sa_len, align);
 	} else {
-		struct sockaddr addrport;
+		union sockaddr_union addrport_u;
+		struct sockaddr *addrport = &addrport_u.sa;
 
-		if_ipsec_set_addr_port(&addrport, addr, port);
-		if_ipsec_add_mbuf_optalign(m0, &addrport, addrport.sa_len, align);
+		if_ipsec_set_addr_port(addrport, addr, port);
+		if_ipsec_add_mbuf_optalign(m0, addrport, addrport->sa_len, align);
 	}
 }
 

Index: src/sys/netipsec/ipsecif.c
diff -u src/sys/netipsec/ipsecif.c:1.1.2.5 src/sys/netipsec/ipsecif.c:1.1.2.6
--- src/sys/netipsec/ipsecif.c:1.1.2.5	Tue Mar 13 15:34:33 2018
+++ src/sys/netipsec/ipsecif.c	Mon Apr  9 17:01:20 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsecif.c,v 1.1.2.5 2018/03/13 15:34:33 martin Exp $  */
+/*	$NetBSD: ipsecif.c,v 1.1.2.6 2018/04/09 17:01:20 martin Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.1.2.5 2018/03/13 15:34:33 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.1.2.6 2018/04/09 17:01:20 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -135,7 +135,10 @@ ipsecif4_prepend_hdr(struct ipsec_varian
 	ip = mtod(m, struct ip *);
 	ip->ip_v = IPVERSION;
 	ip->ip_off = htons(0);
-	ip->ip_id = 0;
+	if (m->m_pkthdr.len < IP_MINFRAGSIZE)
+		ip->ip_id = 0;
+	else
+		ip->ip_id = ip_newid(NULL);
 	ip->ip_hl = sizeof(*ip) >> 2;
 	if (ip_ipsec_copy_tos)
 		ip->ip_tos = tos;
@@ -410,6 +413,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)
 {
@@ -844,9 +898,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.2.2 src/sys/netipsec/ipsecif.h:1.1.2.3
--- src/sys/netipsec/ipsecif.h:1.1.2.2	Sun Feb 11 21:17:34 2018
+++ src/sys/netipsec/ipsecif.h	Mon Apr  9 17:01:20 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsecif.h,v 1.1.2.2 2018/02/11 21:17:34 snj Exp $  */
+/*	$NetBSD: ipsecif.h,v 1.1.2.3 2018/04/09 17:01:20 martin 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