From 742e7210d00b359d81b9c778ab520003704e9b6c Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Mon, 11 Apr 2022 15:58:28 +0200 Subject: [PATCH] udp: allow udp_tun_func_t() to indicate it did not eat the packet Allow udp tunnel functions to indicate they have not taken ownership of the packet, and that normal UDP processing should continue. This is especially useful for scenarios where the kernel has taken ownership of a socket that was originally created by userspace. It allows the tunnel function to pass through certain packets for userspace processing. The primary user of this is if_ovpn, when it receives messages from unknown peers (which might be a new client). Reviewed by: tuexen Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D34883 --- sys/net/if_vxlan.c | 6 ++++-- sys/netinet/ip_gre.c | 6 ++++-- sys/netinet/sctputil.c | 6 ++++-- sys/netinet/tcp_subr.c | 6 ++++-- sys/netinet/udp_usrreq.c | 6 ++++-- sys/netinet/udp_var.h | 5 ++++- sys/netinet6/ip6_gre.c | 8 +++++--- 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 291c7b591766..99efbe255695 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -363,7 +363,7 @@ static int vxlan_encap6(struct vxlan_softc *, const union vxlan_sockaddr *, struct mbuf *); static int vxlan_transmit(struct ifnet *, struct mbuf *); static void vxlan_qflush(struct ifnet *); -static void vxlan_rcv_udp_packet(struct mbuf *, int, struct inpcb *, +static bool vxlan_rcv_udp_packet(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); static int vxlan_input(struct vxlan_socket *, uint32_t, struct mbuf **, const struct sockaddr *); @@ -2758,7 +2758,7 @@ vxlan_qflush(struct ifnet *ifp __unused) { } -static void +static bool vxlan_rcv_udp_packet(struct mbuf *m, int offset, struct inpcb *inpcb, const struct sockaddr *srcsa, void *xvso) { @@ -2802,6 +2802,8 @@ vxlan_rcv_udp_packet(struct mbuf *m, int offset, struct inpcb *inpcb, out: if (m != NULL) m_freem(m); + + return (true); } static int diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c index a70452026642..93261a094a36 100644 --- a/sys/netinet/ip_gre.c +++ b/sys/netinet/ip_gre.c @@ -219,7 +219,7 @@ in_gre_srcaddr(void *arg __unused, const struct sockaddr *sa, } } -static void +static bool in_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa, void *ctx) { @@ -237,9 +237,11 @@ in_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, } if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){ gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc); - return; + return (true); } m_freem(m); + + return (true); } static int diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index e0ac9e23fc68..7b82a2ce6d86 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -7094,7 +7094,7 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_ } #endif -static void +static bool sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) { @@ -7172,9 +7172,11 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, goto out; break; } - return; + return (true); out: m_freem(m); + + return (true); } #ifdef INET diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 95c34c581e59..348a8bb7151e 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -590,7 +590,7 @@ tcp_switch_back_to_default(struct tcpcb *tp) } } -static void +static bool tcp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa, void *ctx) { @@ -659,9 +659,11 @@ tcp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, goto out; break; } - return; + return (true); out: m_freem(m); + + return (true); } static int diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index f216e993b4f3..f35ba81f3936 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -278,6 +278,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, struct sockaddr_in6 udp_in6; #endif struct udpcb *up; + bool filtered; INP_LOCK_ASSERT(inp); @@ -288,10 +289,11 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, if (up->u_tun_func != NULL) { in_pcbref(inp); INP_RUNLOCK(inp); - (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0], + filtered = (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0], up->u_tun_ctx); INP_RLOCK(inp); - return (in_pcbrele_rlocked(inp)); + if (filtered) + return (in_pcbrele_rlocked(inp)); } off += sizeof(struct udphdr); diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index cd9c4fd47e4f..9db5494ab82b 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -36,6 +36,7 @@ #ifndef _NETINET_UDP_VAR_H_ #define _NETINET_UDP_VAR_H_ +#include #include #include @@ -60,7 +61,8 @@ struct udpiphdr { struct inpcb; struct mbuf; -typedef void(*udp_tun_func_t)(struct mbuf *, int, struct inpcb *, +#ifdef _KERNEL +typedef bool(*udp_tun_func_t)(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); typedef void(*udp_tun_icmp_t)(int, struct sockaddr *, void *, void *); @@ -78,6 +80,7 @@ struct udpcb { #define intoudpcb(ip) ((struct udpcb *)(ip)->inp_ppcb) #define sotoudpcb(so) (intoudpcb(sotoinpcb(so))) +#endif /* IPsec: ESP in UDP tunneling: */ #define UF_ESPINUDP_NON_IKE 0x00000001 /* w/ non-IKE marker .. */ diff --git a/sys/netinet6/ip6_gre.c b/sys/netinet6/ip6_gre.c index eb3f92d55adc..9057a95e109b 100644 --- a/sys/netinet6/ip6_gre.c +++ b/sys/netinet6/ip6_gre.c @@ -212,7 +212,7 @@ in6_gre_srcaddr(void *arg __unused, const struct sockaddr *sa, } } -static void +static bool in6_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa, void *ctx) { @@ -226,7 +226,7 @@ in6_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, dst = *(const struct sockaddr_in6 *)sa; if (sa6_embedscope(&dst, 0)) { m_freem(m); - return; + return (true); } CK_LIST_FOREACH(sc, &gs->list, chain) { if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, &dst.sin6_addr)) @@ -234,9 +234,11 @@ in6_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, } if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){ gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc); - return; + return (true); } m_freem(m); + + return (true); } static int