xfrm: allow to enable udp encapsulation without userspace socket

It is currently not possible to enable UDP encapsulation in xfrm without
a userspace process that listen on the specified UDP listener port in
the SA.

People have work around this by creating dummy userspace daemons such as
the one in the smallish perl program (see the script at the bottom of
this link):

http://techblog.newsnow.co.uk/2011/11/simple-udp-esp-encapsulation-nat-t-for.html

This patch enabled two new encapsulation modes:

- espinudp-tx, for the sender side, this requires the source and
  destination ports to be specified, to be placed in the UDP header.
- espinudp-rx, for the receiver side, this requires only the source port
  which is used for the listener in-kernel UDP socket.

The following example shows how to enable the standalone UDP
encapsulation:

ip xfrm state add src 192.168.10.10 dst 192.168.10.11 proto esp spi 1 \
        encap espinudp-tx 9999 9999 0.0.0.0 \
        if_id 0x1 reqid 1 replay-window 1  mode tunnel aead 'rfc4106(gcm(aes))' \
        0x1111111111111111111111111111111111111111 96 \
        sel src 10.141.10.0/24 dst 10.141.11.0/24

ip xfrm state add src 192.168.10.11 dst 192.168.10.10 proto esp spi 2 \
        encap espinudp-rx 9999 0 0.0.0.0 \
        if_id 0x1 reqid 2 replay-window 10 mode tunnel aead 'rfc4106(gcm(aes))' \
        0x2222222222222222222222222222222222222222 96
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 52474e4..2916f8b 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -2181,6 +2181,8 @@ static inline bool xfrm6_local_dontfrag(const struct sock *sk)
 }
 #endif
 
+int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
+
 #if (IS_BUILTIN(CONFIG_XFRM_INTERFACE) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) || \
     (IS_MODULE(CONFIG_XFRM_INTERFACE) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES))
 
diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
index 4828794..4031b99 100644
--- a/include/uapi/linux/udp.h
+++ b/include/uapi/linux/udp.h
@@ -43,5 +43,7 @@ struct udphdr {
 #define UDP_ENCAP_GTP1U		5 /* 3GPP TS 29.060 */
 #define UDP_ENCAP_RXRPC		6
 #define TCP_ENCAP_ESPINTCP	7 /* Yikes, this is really xfrm encap types. */
+#define UDP_ENCAP_ESPINUDP_RX	8
+#define UDP_ENCAP_ESPINUDP_TX	9
 
 #endif /* _UAPI_LINUX_UDP_H */
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index c787e44..58e6e9b 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -433,6 +433,7 @@ static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
 	default:
 	case UDP_ENCAP_ESPINUDP:
 	case UDP_ENCAP_ESPINUDP_NON_IKE:
+	case UDP_ENCAP_ESPINUDP_TX:
 		esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);
 		break;
 	case TCP_ENCAP_ESPINTCP:
@@ -990,6 +991,7 @@ static int esp_input_done_direct(struct sk_buff *skb, struct xfrm_state *x)
 			break;
 		case UDP_ENCAP_ESPINUDP:
 		case UDP_ENCAP_ESPINUDP_NON_IKE:
+		case UDP_ENCAP_ESPINUDP_RX:
 			source = uh->source;
 			break;
 		default:
@@ -1546,6 +1548,8 @@ static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
 			err = -EINVAL;
 			goto error;
 		case UDP_ENCAP_ESPINUDP:
+		case UDP_ENCAP_ESPINUDP_RX:
+		case UDP_ENCAP_ESPINUDP_TX:
 			x->props.header_len += sizeof(struct udphdr);
 			break;
 		case UDP_ENCAP_ESPINUDP_NON_IKE:
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index ad2afee..eac206a 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -164,6 +164,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
 	kfree_skb(skb);
 	return 0;
 }
+EXPORT_SYMBOL(xfrm4_udp_encap_rcv);
 
 int xfrm4_rcv(struct sk_buff *skb)
 {
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index f124258..52e1a29 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -468,6 +468,8 @@ static int esp6_output_encap(struct xfrm_state *x, struct sk_buff *skb,
 	switch (encap_type) {
 	default:
 	case UDP_ENCAP_ESPINUDP:
+	case UDP_ENCAP_ESPINUDP_RX:
+	case UDP_ENCAP_ESPINUDP_TX:
 	case UDP_ENCAP_ESPINUDP_NON_IKE:
 		esph = esp6_output_udp_encap(skb, encap_type, esp, sport, dport);
 		break;
@@ -1606,6 +1608,8 @@ static int esp6_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
 			err = -EINVAL;
 			goto error;
 		case UDP_ENCAP_ESPINUDP:
+		case UDP_ENCAP_ESPINUDP_RX:
+		case UDP_ENCAP_ESPINUDP_TX:
 			x->props.header_len += sizeof(struct udphdr);
 			break;
 		case UDP_ENCAP_ESPINUDP_NON_IKE:
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 00afe831..2e1a18e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -521,6 +521,15 @@ EXPORT_SYMBOL(xfrm_state_free);
 
 static void ___xfrm_state_destroy(struct xfrm_state *x)
 {
+	if (x->encap && x->encap->encap_type == UDP_ENCAP_ESPINUDP_RX) {
+		struct sock *sk = x->encap_sk;
+
+		lock_sock(sk);
+		sock_put(sk);
+		release_sock(sk);
+		x->encap_sk = NULL;
+	}
+
 	hrtimer_cancel(&x->mtimer);
 	del_timer_sync(&x->rtimer);
 	kfree(x->aead);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index cf5172d..9ace8ec 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -29,6 +29,7 @@
 #include <net/xfrm.h>
 #include <net/netlink.h>
 #include <net/ah.h>
+#include <net/udp_tunnel.h>
 #include <linux/uaccess.h>
 #if IS_ENABLED(CONFIG_IPV6)
 #include <linux/in6.h>
@@ -779,6 +780,48 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
 	return NULL;
 }
 
+static int xfrm_setup_socket(struct net *net, struct xfrm_state *x)
+{
+	struct udp_tunnel_sock_cfg tuncfg = {};
+	struct udp_port_cfg udp_conf = {
+		.family = x->props.family,
+	};
+	struct socket *sock;
+	int err;
+
+	if (!x->encap)
+		return -EOPNOTSUPP;
+
+	switch (x->props.family) {
+	case AF_INET:
+		udp_conf.local_ip.s_addr = x->encap->encap_oa.a4;
+		tuncfg.encap_rcv = xfrm4_udp_encap_rcv;
+		break;
+#if IS_ENABLED(CONFIG_IPV6)
+	case AF_INET6:
+		udp_conf.local_ip6  = x->encap->encap_oa.in6;
+		tuncfg.encap_rcv = ipv6_stub->xfrm6_udp_encap_rcv;
+		break;
+#endif
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	udp_conf.local_udp_port = x->encap->encap_sport;
+
+	err = udp_sock_create(net, &udp_conf, &sock);
+	if (err)
+		return err;
+
+	tuncfg.encap_type = UDP_ENCAP_ESPINUDP_RX;
+
+	setup_udp_tunnel_sock(net, sock, &tuncfg);
+
+	x->encap_sk = sock->sk;
+
+	return 0;
+}
+
 static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 		       struct nlattr **attrs, struct netlink_ext_ack *extack)
 {
@@ -796,6 +839,12 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 	if (!x)
 		return err;
 
+	if (x->encap && x->encap->encap_type == UDP_ENCAP_ESPINUDP_RX) {
+		err = xfrm_setup_socket(net, x);
+		if (err < 0)
+			return err;
+	}
+
 	xfrm_state_hold(x);
 	if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
 		err = xfrm_state_add(x);