svn commit: r364018 - in head/sys: netinet netinet6 sys

Bjoern A. Zeeb bz at FreeBSD.org
Fri Aug 7 15:13:54 UTC 2020


Author: bz
Date: Fri Aug  7 15:13:53 2020
New Revision: 364018
URL: https://svnweb.freebsd.org/changeset/base/364018

Log:
  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)
  Reviewed by:	melifaro
  MFC after:	2 weeks
  Differential Revision:	https://reviews.freebsd.org/D24135

Modified:
  head/sys/netinet/udp_usrreq.c
  head/sys/netinet6/udp6_usrreq.c
  head/sys/sys/protosw.h

Modified: head/sys/netinet/udp_usrreq.c
==============================================================================
--- head/sys/netinet/udp_usrreq.c	Fri Aug  7 15:11:27 2020	(r364017)
+++ head/sys/netinet/udp_usrreq.c	Fri Aug  7 15:13:53 2020	(r364018)
@@ -163,7 +163,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
@@ -1083,9 +1083,65 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
 }
 
 #ifdef INET
+#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
+
+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;
@@ -1149,6 +1205,11 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct s
 				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;
 
@@ -1696,7 +1757,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: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c	Fri Aug  7 15:11:27 2020	(r364017)
+++ head/sys/netinet6/udp6_usrreq.c	Fri Aug  7 15:13:53 2020	(r364018)
@@ -784,7 +784,7 @@ udp6_output(struct socket *so, int flags_arg, struct m
 				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: head/sys/sys/protosw.h
==============================================================================
--- head/sys/sys/protosw.h	Fri Aug  7 15:11:27 2020	(r364017)
+++ head/sys/sys/protosw.h	Fri Aug  7 15:13:53 2020	(r364018)
@@ -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);


More information about the svn-src-all mailing list