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>
| ... | ... |
@@ -2863,27 +2863,16 @@ link_socket_read_tcp (struct link_socket *sock, |
| 2863 | 2863 |
|
| 2864 | 2864 |
#if ENABLE_IP_PKTINFO |
| 2865 | 2865 |
|
| 2866 |
-#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */ |
|
| 2867 |
-struct openvpn_in4_pktinfo |
|
| 2868 |
-{
|
|
| 2869 |
- struct cmsghdr cmsghdr; |
|
| 2866 |
+/* make the buffer large enough to handle ancilliary socket data for |
|
| 2867 |
+ * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292) |
|
| 2868 |
+ */ |
|
| 2870 | 2869 |
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| 2871 |
- struct in_pktinfo pi4; |
|
| 2872 |
-#elif defined(IP_RECVDSTADDR) |
|
| 2873 |
- struct in_addr pi4; |
|
| 2870 |
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ |
|
| 2871 |
+ CMSG_SPACE(sizeof (struct in_pktinfo)) ) |
|
| 2872 |
+#else |
|
| 2873 |
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ |
|
| 2874 |
+ CMSG_SPACE(sizeof (struct in_addr)) ) |
|
| 2874 | 2875 |
#endif |
| 2875 |
-}; |
|
| 2876 |
-struct openvpn_in6_pktinfo |
|
| 2877 |
-{
|
|
| 2878 |
- struct cmsghdr cmsghdr; |
|
| 2879 |
- struct in6_pktinfo pi6; |
|
| 2880 |
-}; |
|
| 2881 |
- |
|
| 2882 |
-union openvpn_pktinfo {
|
|
| 2883 |
- struct openvpn_in4_pktinfo msgpi4; |
|
| 2884 |
- struct openvpn_in6_pktinfo msgpi6; |
|
| 2885 |
-}; |
|
| 2886 |
-#pragma pack() |
|
| 2887 | 2876 |
|
| 2888 | 2877 |
static socklen_t |
| 2889 | 2878 |
link_socket_read_udp_posix_recvmsg (struct link_socket *sock, |
| ... | ... |
@@ -2891,7 +2880,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, |
| 2891 | 2891 |
struct link_socket_actual *from) |
| 2892 | 2892 |
{
|
| 2893 | 2893 |
struct iovec iov; |
| 2894 |
- union openvpn_pktinfo opi; |
|
| 2894 |
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; |
|
| 2895 | 2895 |
struct msghdr mesg; |
| 2896 | 2896 |
socklen_t fromlen = sizeof (from->dest.addr); |
| 2897 | 2897 |
|
| ... | ... |
@@ -2901,8 +2890,8 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, |
| 2901 | 2901 |
mesg.msg_iovlen = 1; |
| 2902 | 2902 |
mesg.msg_name = &from->dest.addr; |
| 2903 | 2903 |
mesg.msg_namelen = fromlen; |
| 2904 |
- mesg.msg_control = &opi; |
|
| 2905 |
- mesg.msg_controllen = sizeof opi; |
|
| 2904 |
+ mesg.msg_control = pktinfo_buf; |
|
| 2905 |
+ mesg.msg_controllen = sizeof pktinfo_buf; |
|
| 2906 | 2906 |
buf->len = recvmsg (sock->sd, &mesg, 0); |
| 2907 | 2907 |
if (buf->len >= 0) |
| 2908 | 2908 |
{
|
| ... | ... |
@@ -2914,13 +2903,14 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, |
| 2914 | 2914 |
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| 2915 | 2915 |
&& cmsg->cmsg_level == SOL_IP |
| 2916 | 2916 |
&& cmsg->cmsg_type == IP_PKTINFO |
| 2917 |
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) ) |
|
| 2917 | 2918 |
#elif defined(IP_RECVDSTADDR) |
| 2918 | 2919 |
&& cmsg->cmsg_level == IPPROTO_IP |
| 2919 | 2920 |
&& cmsg->cmsg_type == IP_RECVDSTADDR |
| 2921 |
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) ) |
|
| 2920 | 2922 |
#else |
| 2921 | 2923 |
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) |
| 2922 | 2924 |
#endif |
| 2923 |
- && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo)) |
|
| 2924 | 2925 |
{
|
| 2925 | 2926 |
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| 2926 | 2927 |
struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); |
| ... | ... |
@@ -2936,7 +2926,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, |
| 2936 | 2936 |
&& CMSG_NXTHDR (&mesg, cmsg) == NULL |
| 2937 | 2937 |
&& cmsg->cmsg_level == IPPROTO_IPV6 |
| 2938 | 2938 |
&& cmsg->cmsg_type == IPV6_PKTINFO |
| 2939 |
- && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo)) |
|
| 2939 |
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) ) |
|
| 2940 | 2940 |
{
|
| 2941 | 2941 |
struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); |
| 2942 | 2942 |
from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; |
| ... | ... |
@@ -3007,7 +2997,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, |
| 3007 | 3007 |
struct iovec iov; |
| 3008 | 3008 |
struct msghdr mesg; |
| 3009 | 3009 |
struct cmsghdr *cmsg; |
| 3010 |
- union openvpn_pktinfo opi; |
|
| 3010 |
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; |
|
| 3011 | 3011 |
|
| 3012 | 3012 |
iov.iov_base = BPTR (buf); |
| 3013 | 3013 |
iov.iov_len = BLEN (buf); |
| ... | ... |
@@ -3019,12 +3009,12 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, |
| 3019 | 3019 |
{
|
| 3020 | 3020 |
mesg.msg_name = &to->dest.addr.sa; |
| 3021 | 3021 |
mesg.msg_namelen = sizeof (struct sockaddr_in); |
| 3022 |
- mesg.msg_control = &opi; |
|
| 3022 |
+ mesg.msg_control = pktinfo_buf; |
|
| 3023 | 3023 |
mesg.msg_flags = 0; |
| 3024 | 3024 |
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| 3025 |
- mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo); |
|
| 3025 |
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo)); |
|
| 3026 | 3026 |
cmsg = CMSG_FIRSTHDR (&mesg); |
| 3027 |
- cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo); |
|
| 3027 |
+ cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo)); |
|
| 3028 | 3028 |
cmsg->cmsg_level = SOL_IP; |
| 3029 | 3029 |
cmsg->cmsg_type = IP_PKTINFO; |
| 3030 | 3030 |
{
|
| ... | ... |
@@ -3035,7 +3025,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, |
| 3035 | 3035 |
pkti->ipi_addr.s_addr = 0; |
| 3036 | 3036 |
} |
| 3037 | 3037 |
#elif defined(IP_RECVDSTADDR) |
| 3038 |
- ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) ); |
|
| 3038 |
+ ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) ); |
|
| 3039 | 3039 |
mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr)); |
| 3040 | 3040 |
cmsg = CMSG_FIRSTHDR (&mesg); |
| 3041 | 3041 |
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); |
| ... | ... |
@@ -3052,13 +3042,16 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, |
| 3052 | 3052 |
struct in6_pktinfo *pkti6; |
| 3053 | 3053 |
mesg.msg_name = &to->dest.addr.sa; |
| 3054 | 3054 |
mesg.msg_namelen = sizeof (struct sockaddr_in6); |
| 3055 |
- mesg.msg_control = &opi; |
|
| 3056 |
- mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo); |
|
| 3055 |
+ |
|
| 3056 |
+ ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) ); |
|
| 3057 |
+ mesg.msg_control = pktinfo_buf; |
|
| 3058 |
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo)); |
|
| 3057 | 3059 |
mesg.msg_flags = 0; |
| 3058 | 3060 |
cmsg = CMSG_FIRSTHDR (&mesg); |
| 3059 |
- cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo); |
|
| 3061 |
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); |
|
| 3060 | 3062 |
cmsg->cmsg_level = IPPROTO_IPV6; |
| 3061 | 3063 |
cmsg->cmsg_type = IPV6_PKTINFO; |
| 3064 |
+ |
|
| 3062 | 3065 |
pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); |
| 3063 | 3066 |
pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; |
| 3064 | 3067 |
pkti6->ipi6_addr = to->pi.in6.ipi6_addr; |