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