Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Sep 2020 19:54:44 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r365059 - in stable/12/sys: netinet netinet6 sys
Message-ID:  <202009011954.081Jsi2w067493@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Tue Sep  1 19:54:43 2020
New Revision: 365059
URL: https://svnweb.freebsd.org/changeset/base/365059

Log:
  MFC r364018:
  
    IPV6_PKTINFO support for v4-mapped IPv6 sockets
  
    When using v4-mapped IPv6 sockets with IPV6_PKTINFO we do not
    respect the given v4-mapped src address on the IPv4 socket.
    Implement the needed functionality. This allows single-socket
    UDP applications (such as OpenVPN) to work better on FreeBSD.
  
    Requested by:	Gert Doering (gert greenie.net), pfsense
    Tested by:	Gert Doering (gert greenie.net)

Modified:
  stable/12/sys/netinet/udp_usrreq.c
  stable/12/sys/netinet6/udp6_usrreq.c
  stable/12/sys/sys/protosw.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/netinet/udp_usrreq.c
==============================================================================
--- stable/12/sys/netinet/udp_usrreq.c	Tue Sep  1 19:06:08 2020	(r365058)
+++ stable/12/sys/netinet/udp_usrreq.c	Tue Sep  1 19:54:43 2020	(r365059)
@@ -162,7 +162,7 @@ VNET_PCPUSTAT_SYSUNINIT(udpstat);
 #ifdef INET
 static void	udp_detach(struct socket *so);
 static int	udp_output(struct inpcb *, struct mbuf *, struct sockaddr *,
-		    struct mbuf *, struct thread *);
+		    struct mbuf *, struct thread *, int);
 #endif
 
 static void
@@ -1114,13 +1114,69 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
 	return (error);
 }
 
+#ifdef INET6
+/* The logic here is derived from ip6_setpktopt(). See comments there. */
+static int
+udp_v4mapped_pktinfo(struct cmsghdr *cm, struct sockaddr_in * src,
+    struct inpcb *inp, int flags)
+{
+	struct ifnet *ifp;
+	struct in6_pktinfo *pktinfo;
+	struct in_addr ia;
+
+	if ((flags & PRUS_IPV6) == 0)
+		return (0);
+
+	if (cm->cmsg_level != IPPROTO_IPV6)
+		return (0);
+
+	if  (cm->cmsg_type != IPV6_2292PKTINFO &&
+	    cm->cmsg_type != IPV6_PKTINFO)
+		return (0);
+
+	if (cm->cmsg_len !=
+	    CMSG_LEN(sizeof(struct in6_pktinfo)))
+		return (EINVAL);
+
+	pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm);
+	if (!IN6_IS_ADDR_V4MAPPED(&pktinfo->ipi6_addr) &&
+	    !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr))
+		return (EINVAL);
+
+	/* Validate the interface index if specified. */
+	if (pktinfo->ipi6_ifindex > V_if_index)
+		return (ENXIO);
+
+	ifp = NULL;
+	if (pktinfo->ipi6_ifindex) {
+		ifp = ifnet_byindex(pktinfo->ipi6_ifindex);
+		if (ifp == NULL)
+			return (ENXIO);
+	}
+	if (ifp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
+
+		ia.s_addr = pktinfo->ipi6_addr.s6_addr32[3];
+		if (in_ifhasaddr(ifp, ia) == 0)
+			return (EADDRNOTAVAIL);
+	}
+
+	bzero(src, sizeof(*src));
+	src->sin_family = AF_INET;
+	src->sin_len = sizeof(*src);
+	src->sin_port = inp->inp_lport;
+	src->sin_addr.s_addr = pktinfo->ipi6_addr.s6_addr32[3];
+
+	return (0);
+}
+#endif
+
 #ifdef INET
 #define	UH_WLOCKED	2
 #define	UH_RLOCKED	1
 #define	UH_UNLOCKED	0
 static int
 udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
-    struct mbuf *control, struct thread *td)
+    struct mbuf *control, struct thread *td, int flags)
 {
 	struct udpiphdr *ui;
 	int len = m->m_pkthdr.len;
@@ -1201,6 +1257,11 @@ retry:
 				error = EINVAL;
 				break;
 			}
+#ifdef INET6
+			error = udp_v4mapped_pktinfo(cm, &src, inp, flags);
+			if (error != 0)
+				break;
+#endif
 			if (cm->cmsg_level != IPPROTO_IP)
 				continue;
 
@@ -1816,7 +1877,7 @@ udp_send(struct socket *so, int flags, struct mbuf *m,
 
 	inp = sotoinpcb(so);
 	KASSERT(inp != NULL, ("udp_send: inp == NULL"));
-	return (udp_output(inp, m, addr, control, td));
+	return (udp_output(inp, m, addr, control, td, flags));
 }
 #endif /* INET */
 

Modified: stable/12/sys/netinet6/udp6_usrreq.c
==============================================================================
--- stable/12/sys/netinet6/udp6_usrreq.c	Tue Sep  1 19:06:08 2020	(r365058)
+++ stable/12/sys/netinet6/udp6_usrreq.c	Tue Sep  1 19:54:43 2020	(r365059)
@@ -804,7 +804,7 @@ retry:
 				in6_sin6_2_sin_in_sock((struct sockaddr *)sin6);
 			pru = inetsw[ip_protox[nxt]].pr_usrreqs;
 			/* addr will just be freed in sendit(). */
-			return ((*pru->pru_send)(so, flags_arg, m,
+			return ((*pru->pru_send)(so, flags_arg | PRUS_IPV6, m,
 			    (struct sockaddr *)sin6, control, td));
 		}
 	} else

Modified: stable/12/sys/sys/protosw.h
==============================================================================
--- stable/12/sys/sys/protosw.h	Tue Sep  1 19:06:08 2020	(r365058)
+++ stable/12/sys/sys/protosw.h	Tue Sep  1 19:54:43 2020	(r365059)
@@ -210,6 +210,7 @@ struct pr_usrreqs {
 #define	PRUS_EOF	0x2
 #define	PRUS_MORETOCOME	0x4
 #define	PRUS_NOTREADY	0x8
+#define	PRUS_IPV6	0x10
 	int	(*pru_ready)(struct socket *so, struct mbuf *m, int count);
 	int	(*pru_sense)(struct socket *so, struct stat *sb);
 	int	(*pru_shutdown)(struct socket *so);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202009011954.081Jsi2w067493>