aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGert Doering2016-10-09 12:09:29 +0200
committerGert Doering2016-10-09 13:40:14 +0200
commitf7aba873ca593eb2ab8a4a358cd6c06ef46a09e1 (patch)
treed5c955ca1284e4396ae2fd5dd75fa9632b56e89d /src
parent7891c8ce93b33749ee75ab579aa391bc5eab6e2f (diff)
downloadopenvpn-f7aba873ca593eb2ab8a4a358cd6c06ef46a09e1.zip
openvpn-f7aba873ca593eb2ab8a4a358cd6c06ef46a09e1.tar.gz
Fix --multihome for IPv6 on 64bit BSD systems.
The old code only worked if "struct openvpn*pktinfo" happened to use the same structure packing as the CMSG_SPACE() / CMSG_LEN() macros (which are part of the official API, see RFC 2292). Get rid of "struct openvpn_*_pktinfo" definitions, replace them by an opaque buffer sized large enough to fit IPv4 and IPv6 packet info messages, as defined by CMSG_SPACE(sizeof(struct ...)). On 32 bit platforms, the net result is the same. On 64 bit platforms, the new buffer is bigger than openvpn_pktinfo was, fixing an overflow with ipi6_ifindex corruption on reception, and EINVAL on sendmsg(). The IPv4 related changes are only side effects of using the new buffer. Fixes: FreeBSD 10.3/amd64, FreeBSD 9.3/sparc64, OpenBSD 6.0/amd64, NetBSD 7.0.1/i386. Note: --multihome for IPv4 on NetBSD is still broken and non-fixable(!) as NetBSD lacks the necessary kernel code for the sendmsg() side. Verified that "--multihome works as well as before" on FreeBSD 7.4/amd64, NetBSD 5.1/amd64, OpenBSD 4.9/i386, Linux/x86_64, Linux/i386, OpenSolaris 10 (--multihome needs -D_XPG4_2, see trac #750) See also: ip(4), ip6(4), recv(2) Trac #634, #327, #28 Signed-off-by: Gert Doering <gert@greenie.muc.de> Acked-by: Arne Schwabe <arne@rfc2549.org> Message-Id: <20161009100929.46472-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12626.html Signed-off-by: Gert Doering <gert@greenie.muc.de> (cherry picked from commit 3fb246e38fc670c7dfff8ce4521c75c95c766c9e)
Diffstat (limited to 'src')
-rw-r--r--src/openvpn/socket.c59
1 files changed, 26 insertions, 33 deletions
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index c76fd36..3474f18 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -2672,27 +2672,16 @@ link_socket_read_tcp (struct link_socket *sock,
#if ENABLE_IP_PKTINFO
-#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
-struct openvpn_in4_pktinfo
-{
- struct cmsghdr cmsghdr;
-#ifdef HAVE_IN_PKTINFO
- struct in_pktinfo pi4;
-#elif defined(IP_RECVDSTADDR)
- struct in_addr pi4;
+/* make the buffer large enough to handle ancilliary socket data for
+ * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292)
+ */
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \
+ CMSG_SPACE(sizeof (struct in_pktinfo)) )
+#else
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \
+ CMSG_SPACE(sizeof (struct in_addr)) )
#endif
-};
-struct openvpn_in6_pktinfo
-{
- struct cmsghdr cmsghdr;
- struct in6_pktinfo pi6;
-};
-
-union openvpn_pktinfo {
- struct openvpn_in4_pktinfo msgpi4;
- struct openvpn_in6_pktinfo msgpi6;
-};
-#pragma pack()
static socklen_t
link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
@@ -2700,7 +2689,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
struct link_socket_actual *from)
{
struct iovec iov;
- union openvpn_pktinfo opi;
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
struct msghdr mesg;
socklen_t fromlen = sizeof (from->dest.addr);
@@ -2710,8 +2699,8 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
mesg.msg_iovlen = 1;
mesg.msg_name = &from->dest.addr;
mesg.msg_namelen = fromlen;
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof opi;
+ mesg.msg_control = pktinfo_buf;
+ mesg.msg_controllen = sizeof pktinfo_buf;
buf->len = recvmsg (sock->sd, &mesg, 0);
if (buf->len >= 0)
{
@@ -2723,13 +2712,14 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
#ifdef IP_PKTINFO
&& cmsg->cmsg_level == SOL_IP
&& cmsg->cmsg_type == IP_PKTINFO
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) )
#elif defined(IP_RECVDSTADDR)
&& cmsg->cmsg_level == IPPROTO_IP
&& cmsg->cmsg_type == IP_RECVDSTADDR
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) )
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
{
#ifdef IP_PKTINFO
struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
@@ -2745,7 +2735,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
&& CMSG_NXTHDR (&mesg, cmsg) == NULL
&& cmsg->cmsg_level == IPPROTO_IPV6
&& cmsg->cmsg_type == IPV6_PKTINFO
- && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo))
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) )
{
struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
@@ -2810,7 +2800,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct iovec iov;
struct msghdr mesg;
struct cmsghdr *cmsg;
- union openvpn_pktinfo opi;
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
iov.iov_base = BPTR (buf);
iov.iov_len = BLEN (buf);
@@ -2822,12 +2812,12 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
{
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in);
- mesg.msg_control = &opi;
+ mesg.msg_control = pktinfo_buf;
mesg.msg_flags = 0;
#ifdef HAVE_IN_PKTINFO
- mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo));
cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
+ cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo));
cmsg->cmsg_level = SOL_IP;
cmsg->cmsg_type = IP_PKTINFO;
{
@@ -2838,7 +2828,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
pkti->ipi_addr.s_addr = 0;
}
#elif defined(IP_RECVDSTADDR)
- ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) );
+ ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) );
mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
@@ -2855,13 +2845,16 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct in6_pktinfo *pkti6;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in6);
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
+
+ ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) );
+ mesg.msg_control = pktinfo_buf;
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo));
mesg.msg_flags = 0;
cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
+
pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
pkti6->ipi6_addr = to->pi.in6.ipi6_addr;