aboutsummaryrefslogtreecommitdiff
path: root/socket.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--socket.c337
1 files changed, 246 insertions, 91 deletions
diff --git a/socket.c b/socket.c
index c7172ac..35d38a1 100644
--- a/socket.c
+++ b/socket.c
@@ -236,7 +236,7 @@ openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr)
static void
update_remote (const char* host,
- struct sockaddr_in *addr,
+ struct openvpn_sockaddr *addr,
bool *changed)
{
if (host && addr)
@@ -247,9 +247,9 @@ update_remote (const char* host,
1,
NULL,
NULL);
- if (new_addr && addr->sin_addr.s_addr != new_addr)
+ if (new_addr && addr->sa.sin_addr.s_addr != new_addr)
{
- addr->sin_addr.s_addr = new_addr;
+ addr->sa.sin_addr.s_addr = new_addr;
*changed = true;
}
}
@@ -492,12 +492,19 @@ create_socket_tcp (void)
}
static socket_descriptor_t
-create_socket_udp (void)
+create_socket_udp (const unsigned int flags)
{
socket_descriptor_t sd;
if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
msg (M_SOCKERR, "UDP: Cannot create UDP socket");
+#if ENABLE_IP_PKTINFO
+ else if (flags & SF_USE_IP_PKTINFO)
+ {
+ int pad = 1;
+ setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad));
+ }
+#endif
return sd;
}
@@ -507,7 +514,7 @@ create_socket (struct link_socket *sock)
/* create socket */
if (sock->info.proto == PROTO_UDPv4)
{
- sock->sd = create_socket_udp ();
+ sock->sd = create_socket_udp (sock->sockflags);
#ifdef ENABLE_SOCKS
if (sock->socks_proxy)
@@ -531,7 +538,7 @@ create_socket (struct link_socket *sock)
static void
socket_do_listen (socket_descriptor_t sd,
- const struct sockaddr_in *local,
+ const struct openvpn_sockaddr *local,
bool do_listen,
bool do_set_nonblock)
{
@@ -553,16 +560,18 @@ socket_do_listen (socket_descriptor_t sd,
socket_descriptor_t
socket_do_accept (socket_descriptor_t sd,
- struct sockaddr_in *remote,
+ struct link_socket_actual *act,
const bool nowait)
{
- socklen_t remote_len = sizeof (*remote);
+ socklen_t remote_len = sizeof (act->dest.sa);
socket_descriptor_t new_sd = SOCKET_UNDEFINED;
+ CLEAR (*act);
+
#ifdef HAVE_GETPEERNAME
if (nowait)
{
- new_sd = getpeername (sd, (struct sockaddr *) remote, &remote_len);
+ new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
if (!socket_defined (new_sd))
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed");
@@ -575,14 +584,14 @@ socket_do_accept (socket_descriptor_t sd,
#endif
else
{
- new_sd = accept (sd, (struct sockaddr *) remote, &remote_len);
+ new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
}
if (!socket_defined (new_sd))
{
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd);
}
- else if (remote_len != sizeof (*remote))
+ else if (remote_len != sizeof (act->dest.sa))
{
msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
openvpn_close_socket (new_sd);
@@ -592,28 +601,30 @@ socket_do_accept (socket_descriptor_t sd,
}
static void
-tcp_connection_established (const struct sockaddr_in *remote)
+tcp_connection_established (const struct link_socket_actual *act)
{
struct gc_arena gc = gc_new ();
msg (M_INFO, "TCP connection established with %s",
- print_sockaddr (remote, &gc));
+ print_link_socket_actual (act, &gc));
gc_free (&gc);
}
static int
socket_listen_accept (socket_descriptor_t sd,
- struct sockaddr_in *remote,
+ struct link_socket_actual *act,
const char *remote_dynamic,
bool *remote_changed,
- const struct sockaddr_in *local,
+ const struct openvpn_sockaddr *local,
bool do_listen,
bool nowait,
volatile int *signal_received)
{
struct gc_arena gc = gc_new ();
- struct sockaddr_in remote_verify = *remote;
+ //struct openvpn_sockaddr *remote = &act->dest;
+ struct openvpn_sockaddr remote_verify = act->dest;
int new_sd = SOCKET_UNDEFINED;
+ CLEAR (*act);
socket_do_listen (sd, local, do_listen, true);
while (true)
@@ -645,17 +656,17 @@ socket_listen_accept (socket_descriptor_t sd,
continue;
}
- new_sd = socket_do_accept (sd, remote, nowait);
+ new_sd = socket_do_accept (sd, act, nowait);
if (socket_defined (new_sd))
{
update_remote (remote_dynamic, &remote_verify, remote_changed);
if (addr_defined (&remote_verify)
- && !addr_match (&remote_verify, remote))
+ && !addr_match (&remote_verify, &act->dest))
{
msg (M_WARN,
"TCP NOTE: Rejected connection attempt from %s due to --remote setting",
- print_sockaddr (remote, &gc));
+ print_link_socket_actual (act, &gc));
if (openvpn_close_socket (new_sd))
msg (M_SOCKERR, "TCP: close socket failed (new_sd)");
}
@@ -668,7 +679,7 @@ socket_listen_accept (socket_descriptor_t sd,
if (!nowait && openvpn_close_socket (sd))
msg (M_SOCKERR, "TCP: close socket failed (sd)");
- tcp_connection_established (remote);
+ tcp_connection_established (act);
gc_free (&gc);
return new_sd;
@@ -676,7 +687,7 @@ socket_listen_accept (socket_descriptor_t sd,
static void
socket_connect (socket_descriptor_t *sd,
- struct sockaddr_in *remote,
+ struct openvpn_sockaddr *remote,
struct remote_list *remote_list,
const char *remote_dynamic,
bool *remote_changed,
@@ -689,8 +700,8 @@ socket_connect (socket_descriptor_t *sd,
print_sockaddr (remote, &gc));
while (true)
{
- const int status = connect (*sd, (struct sockaddr *) remote,
- sizeof (*remote));
+ const int status = connect (*sd, (struct sockaddr *) &remote->sa,
+ sizeof (remote->sa));
get_signal (signal_received);
if (*signal_received)
@@ -711,7 +722,7 @@ socket_connect (socket_descriptor_t *sd,
{
remote_list_next (remote_list);
remote_dynamic = remote_list_host (remote_list);
- remote->sin_port = htons (remote_list_port (remote_list));
+ remote->sa.sin_port = htons (remote_list_port (remote_list));
*remote_changed = true;
}
@@ -771,22 +782,22 @@ resolve_bind_local (struct link_socket *sock)
/* resolve local address if undefined */
if (!addr_defined (&sock->info.lsa->local))
{
- sock->info.lsa->local.sin_family = AF_INET;
- sock->info.lsa->local.sin_addr.s_addr =
+ sock->info.lsa->local.sa.sin_family = AF_INET;
+ sock->info.lsa->local.sa.sin_addr.s_addr =
(sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
sock->local_host,
0,
NULL,
NULL)
: htonl (INADDR_ANY));
- sock->info.lsa->local.sin_port = htons (sock->local_port);
+ sock->info.lsa->local.sa.sin_port = htons (sock->local_port);
}
/* bind to local address/port */
if (sock->bind_local)
{
- if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local,
- sizeof (sock->info.lsa->local)))
+ if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local.sa,
+ sizeof (sock->info.lsa->local.sa)))
{
const int errnum = openvpn_errno_socket ();
msg (M_FATAL, "TCP/UDP: Socket bind failed on local address %s: %s",
@@ -810,8 +821,8 @@ resolve_remote (struct link_socket *sock,
/* resolve remote address if undefined */
if (!addr_defined (&sock->info.lsa->remote))
{
- sock->info.lsa->remote.sin_family = AF_INET;
- sock->info.lsa->remote.sin_addr.s_addr = 0;
+ sock->info.lsa->remote.sa.sin_family = AF_INET;
+ sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
if (sock->remote_host)
{
@@ -856,7 +867,7 @@ resolve_remote (struct link_socket *sock,
ASSERT (0);
}
- sock->info.lsa->remote.sin_addr.s_addr = getaddr (
+ sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr (
flags,
sock->remote_host,
retry,
@@ -883,19 +894,22 @@ resolve_remote (struct link_socket *sock,
}
}
- sock->info.lsa->remote.sin_port = htons (sock->remote_port);
+ sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port);
}
/* should we re-use previous active remote address? */
- if (addr_defined (&sock->info.lsa->actual))
+ if (link_socket_actual_defined (&sock->info.lsa->actual))
{
msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
- print_sockaddr (&sock->info.lsa->actual, &gc));
+ print_link_socket_actual (&sock->info.lsa->actual, &gc));
if (remote_dynamic)
*remote_dynamic = NULL;
}
else
- sock->info.lsa->actual = sock->info.lsa->remote;
+ {
+ CLEAR (sock->info.lsa->actual);
+ sock->info.lsa->actual.dest = sock->info.lsa->remote;
+ }
/* remember that we finished */
sock->did_resolve_remote = true;
@@ -1162,7 +1176,7 @@ link_socket_init_phase2 (struct link_socket *sock,
else if (sock->info.proto == PROTO_TCPv4_CLIENT)
{
socket_connect (&sock->sd,
- &sock->info.lsa->actual,
+ &sock->info.lsa->actual.dest,
sock->remote_list,
remote_dynamic,
&remote_changed,
@@ -1200,7 +1214,7 @@ link_socket_init_phase2 (struct link_socket *sock,
else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy)
{
socket_connect (&sock->ctrl_sd,
- &sock->info.lsa->actual,
+ &sock->info.lsa->actual.dest,
NULL,
remote_dynamic,
&remote_changed,
@@ -1212,7 +1226,8 @@ link_socket_init_phase2 (struct link_socket *sock,
establish_socks_proxy_udpassoc (sock->socks_proxy,
sock->ctrl_sd,
- sock->sd, &sock->socks_relay,
+ sock->sd,
+ &sock->socks_relay.dest,
signal_received);
if (*signal_received)
@@ -1221,8 +1236,9 @@ link_socket_init_phase2 (struct link_socket *sock,
sock->remote_host = sock->proxy_dest_host;
sock->remote_port = sock->proxy_dest_port;
sock->did_resolve_remote = false;
- sock->info.lsa->actual.sin_addr.s_addr = 0;
- sock->info.lsa->remote.sin_addr.s_addr = 0;
+
+ sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0;
+ sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
resolve_remote (sock, 1, NULL, signal_received);
@@ -1237,7 +1253,7 @@ link_socket_init_phase2 (struct link_socket *sock,
if (remote_changed)
{
msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
- sock->info.lsa->remote.sin_addr.s_addr = sock->info.lsa->actual.sin_addr.s_addr;
+ sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr;
}
}
@@ -1274,12 +1290,15 @@ link_socket_init_phase2 (struct link_socket *sock,
msg (M_INFO, "%s link local%s: %s",
proto2ascii (sock->info.proto, true),
(sock->bind_local ? " (bound)" : ""),
- print_sockaddr_ex (&sock->info.lsa->local, sock->bind_local, ":", &gc));
+ print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc));
/* print active remote address */
msg (M_INFO, "%s link remote: %s",
proto2ascii (sock->info.proto, true),
- print_sockaddr_ex (&sock->info.lsa->actual, addr_defined (&sock->info.lsa->actual), ":", &gc));
+ print_link_socket_actual_ex (&sock->info.lsa->actual,
+ ":",
+ PS_SHOW_PORT_IF_DEFINED,
+ &gc));
done:
gc_free (&gc);
@@ -1344,19 +1363,19 @@ socket_adjust_frame_parameters (struct frame *frame, int proto)
void
setenv_trusted (struct env_set *es, const struct link_socket_info *info)
{
- setenv_sockaddr (es, "trusted", &info->lsa->actual, SA_IP_PORT);
+ setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT);
}
void
link_socket_connection_initiated (const struct buffer *buf,
struct link_socket_info *info,
- const struct sockaddr_in *addr,
+ const struct link_socket_actual *act,
const char *common_name,
struct env_set *es)
{
struct gc_arena gc = gc_new ();
- info->lsa->actual = *addr; /* Note: skip this line for --force-dest */
+ info->lsa->actual = *act; /* Note: skip this line for --force-dest */
setenv_trusted (es, info);
info->connection_established = true;
@@ -1365,7 +1384,7 @@ link_socket_connection_initiated (const struct buffer *buf,
struct buffer out = alloc_buf_gc (256, &gc);
if (common_name)
buf_printf (&out, "[%s] ", common_name);
- buf_printf (&out, "Peer Connection Initiated with %s", print_sockaddr (&info->lsa->actual, &gc));
+ buf_printf (&out, "Peer Connection Initiated with %s", print_link_socket_actual (&info->lsa->actual, &gc));
msg (M_INFO, "%s", BSTR (&out));
}
@@ -1375,7 +1394,7 @@ link_socket_connection_initiated (const struct buffer *buf,
/* Process --ipchange plugin */
if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
{
- const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual, true, " ", &gc);
+ const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc);
if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es))
msg (M_WARN, "WARNING: ipchange plugin call failed");
}
@@ -1387,7 +1406,7 @@ link_socket_connection_initiated (const struct buffer *buf,
setenv_str (es, "script_type", "ipchange");
buf_printf (&out, "%s %s",
info->ipchange_command,
- print_sockaddr_ex (&info->lsa->actual, true, " ", &gc));
+ print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc));
system_check (BSTR (&out), es, S_SCRIPT, "ip-change command failed");
}
@@ -1397,14 +1416,14 @@ link_socket_connection_initiated (const struct buffer *buf,
void
link_socket_bad_incoming_addr (struct buffer *buf,
const struct link_socket_info *info,
- const struct sockaddr_in *from_addr)
+ const struct link_socket_actual *from_addr)
{
struct gc_arena gc = gc_new ();
msg (D_LINK_ERRORS,
"TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
- print_sockaddr (from_addr, &gc),
- (int)from_addr->sin_family,
+ print_link_socket_actual (from_addr, &gc),
+ (int)from_addr->dest.sa.sin_family,
print_sockaddr (&info->lsa->remote, &gc));
buf->len = 0;
@@ -1422,10 +1441,10 @@ link_socket_current_remote (const struct link_socket_info *info)
{
const struct link_socket_addr *lsa = info->lsa;
- if (addr_defined (&lsa->actual))
- return ntohl (lsa->actual.sin_addr.s_addr);
+ if (link_socket_actual_defined (&lsa->actual))
+ return ntohl (lsa->actual.dest.sa.sin_addr.s_addr);
else if (addr_defined (&lsa->remote))
- return ntohl (lsa->remote.sin_addr.s_addr);
+ return ntohl (lsa->remote.sa.sin_addr.s_addr);
else
return 0;
}
@@ -1618,29 +1637,69 @@ socket_listen_event_handle (struct link_socket *s)
*/
const char *
-print_sockaddr (const struct sockaddr_in *addr, struct gc_arena *gc)
+print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc)
{
- return print_sockaddr_ex(addr, true, ":", gc);
+ return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc);
}
const char *
-print_sockaddr_ex (const struct sockaddr_in *addr, bool do_port, const char* separator, struct gc_arena *gc)
+print_sockaddr_ex (const struct openvpn_sockaddr *addr,
+ const char* separator,
+ const unsigned int flags,
+ struct gc_arena *gc)
{
- struct buffer out = alloc_buf_gc (64, gc);
- const int port = ntohs (addr->sin_port);
+ if (addr)
+ {
+ struct buffer out = alloc_buf_gc (64, gc);
+ const int port = ntohs (addr->sa.sin_port);
- mutex_lock_static (L_INET_NTOA);
- buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sin_addr) : "[undef]"));
- mutex_unlock_static (L_INET_NTOA);
+ mutex_lock_static (L_INET_NTOA);
+ buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
+ mutex_unlock_static (L_INET_NTOA);
- if (do_port && port)
- {
- if (separator)
- buf_printf (&out, "%s", separator);
+ if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
+ && port)
+ {
+ if (separator)
+ buf_printf (&out, "%s", separator);
- buf_printf (&out, "%d", port);
+ buf_printf (&out, "%d", port);
+ }
+ return BSTR (&out);
}
- return BSTR (&out);
+ else
+ return "[NULL]";
+}
+
+const char *
+print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena *gc)
+{
+ return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
+}
+
+const char *
+print_link_socket_actual_ex (const struct link_socket_actual *act,
+ const char *separator,
+ const unsigned int flags,
+ struct gc_arena *gc)
+{
+ if (act)
+ {
+ struct buffer out = alloc_buf_gc (128, gc);
+ buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc));
+#if ENABLE_IP_PKTINFO
+ if ((flags & PS_SHOW_PKTINFO) && act->pi.ipi_spec_dst.s_addr)
+ {
+ struct openvpn_sockaddr sa;
+ CLEAR (sa);
+ sa.sa.sin_addr = act->pi.ipi_spec_dst;
+ buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc));
+ }
+#endif
+ return BSTR (&out);
+ }
+ else
+ return "[NULL]";
}
/*
@@ -1667,7 +1726,7 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
/* set environmental variables for ip/port in *addr */
void
-setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct sockaddr_in *addr, const bool flags)
+setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags)
{
char name_buf[256];
@@ -1677,13 +1736,13 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct socka
openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
mutex_lock_static (L_INET_NTOA);
- setenv_str (es, name_buf, inet_ntoa (addr->sin_addr));
+ setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr));
mutex_unlock_static (L_INET_NTOA);
- if ((flags & SA_IP_PORT) && addr->sin_port)
+ if ((flags & SA_IP_PORT) && addr->sa.sin_port)
{
openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
- setenv_int (es, name_buf, ntohs (addr->sin_port));
+ setenv_int (es, name_buf, ntohs (addr->sa.sin_port));
}
}
@@ -1692,13 +1751,22 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c
{
if (addr || !(flags & SA_SET_IF_NONZERO))
{
- struct sockaddr_in si;
+ struct openvpn_sockaddr si;
CLEAR (si);
- si.sin_addr.s_addr = htonl (addr);
+ si.sa.sin_addr.s_addr = htonl (addr);
setenv_sockaddr (es, name_prefix, &si, flags);
}
}
+void
+setenv_link_socket_actual (struct env_set *es,
+ const char *name_prefix,
+ const struct link_socket_actual *act,
+ const bool flags)
+{
+ setenv_sockaddr (es, name_prefix, &act->dest, flags);
+}
+
/*
* Convert protocol names between index and ascii form.
*/
@@ -1828,19 +1896,72 @@ link_socket_read_tcp (struct link_socket *sock,
#ifndef WIN32
+#if ENABLE_IP_PKTINFO
+
+struct openvpn_pktinfo
+{
+ struct cmsghdr cmsghdr;
+ struct in_pktinfo in_pktinfo;
+};
+
+static socklen_t
+link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
+ struct buffer *buf,
+ int maxsize,
+ struct link_socket_actual *from)
+{
+ struct iovec iov;
+ struct openvpn_pktinfo opi;
+ struct msghdr mesg;
+ socklen_t fromlen = sizeof (from->dest.sa);
+
+ iov.iov_base = BPTR (buf);
+ iov.iov_len = maxsize;
+ mesg.msg_iov = &iov;
+ mesg.msg_iovlen = 1;
+ mesg.msg_name = &from->dest.sa;
+ mesg.msg_namelen = fromlen;
+ mesg.msg_control = &opi;
+ mesg.msg_controllen = sizeof (opi);
+ buf->len = recvmsg (sock->sd, &mesg, 0);
+ if (buf->len >= 0)
+ {
+ struct cmsghdr *cmsg;
+ fromlen = mesg.msg_namelen;
+ cmsg = CMSG_FIRSTHDR (&mesg);
+ if (cmsg != NULL
+ && CMSG_NXTHDR (&mesg, cmsg) == NULL
+ && cmsg->cmsg_level == SOL_IP
+ && cmsg->cmsg_type == IP_PKTINFO
+ && cmsg->cmsg_len >= sizeof (opi))
+ {
+ struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+ from->pi.ipi_ifindex = pkti->ipi_ifindex;
+ from->pi.ipi_spec_dst = pkti->ipi_spec_dst;
+ }
+ }
+ return fromlen;
+}
+#endif
+
int
link_socket_read_udp_posix (struct link_socket *sock,
struct buffer *buf,
int maxsize,
- struct sockaddr_in *from)
+ struct link_socket_actual *from)
{
- socklen_t fromlen = sizeof (*from);
- CLEAR (*from);
+ socklen_t fromlen = sizeof (from->dest.sa);
+ from->dest.sa.sin_addr.s_addr = 0;
ASSERT (buf_safe (buf, maxsize));
- buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
- (struct sockaddr *) from, &fromlen);
- if (fromlen != sizeof (*from))
- bad_address_length (fromlen, sizeof (*from));
+#if ENABLE_IP_PKTINFO
+ if (sock->sockflags & SF_USE_IP_PKTINFO)
+ fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
+ else
+#endif
+ buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
+ (struct sockaddr *) &from->dest.sa, &fromlen);
+ if (fromlen != sizeof (from->dest.sa))
+ bad_address_length (fromlen, sizeof (from->dest.sa));
return buf->len;
}
@@ -1853,7 +1974,7 @@ link_socket_read_udp_posix (struct link_socket *sock,
int
link_socket_write_tcp (struct link_socket *sock,
struct buffer *buf,
- struct sockaddr_in *to)
+ struct link_socket_actual *to)
{
packet_size_type len = BLEN (buf);
dmsg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset);
@@ -1867,6 +1988,41 @@ link_socket_write_tcp (struct link_socket *sock,
#endif
}
+#if ENABLE_IP_PKTINFO
+
+int
+link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
+ struct buffer *buf,
+ struct link_socket_actual *to)
+{
+ struct iovec iov;
+ struct msghdr mesg;
+ struct cmsghdr *cmsg;
+ struct in_pktinfo *pkti;
+ struct openvpn_pktinfo opi;
+
+ iov.iov_base = BPTR (buf);
+ iov.iov_len = BLEN (buf);
+ mesg.msg_iov = &iov;
+ mesg.msg_iovlen = 1;
+ mesg.msg_name = &to->dest.sa;
+ mesg.msg_namelen = sizeof (to->dest.sa);
+ mesg.msg_control = &opi;
+ mesg.msg_controllen = sizeof (opi);
+ mesg.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR (&mesg);
+ cmsg->cmsg_len = sizeof (opi);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+ pkti->ipi_ifindex = to->pi.ipi_ifindex;
+ pkti->ipi_spec_dst = to->pi.ipi_spec_dst;
+ pkti->ipi_addr.s_addr = 0;
+ return sendmsg (sock->sd, &mesg, 0);
+}
+
+#endif
+
/*
* Win32 overlapped socket I/O functions.
*/
@@ -1981,7 +2137,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
}
int
-socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct sockaddr_in *to)
+socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to)
{
if (sock->writes.iostate == IOSTATE_INITIAL)
{
@@ -2005,7 +2161,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct so
{
/* set destination address for UDP writes */
sock->writes.addr_defined = true;
- sock->writes.addr = *to;
+ sock->writes.addr = to->dest.sa;
sock->writes.addrlen = sizeof (sock->writes.addr);
status = WSASendTo(
@@ -2081,11 +2237,10 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct so
}
int
-socket_finalize (
- SOCKET s,
+socket_finalize (SOCKET s,
struct overlapped_io *io,
struct buffer *buf,
- struct sockaddr_in *from)
+ struct link_socket_actual *from)
{
int ret = -1;
BOOL status;
@@ -2162,10 +2317,10 @@ socket_finalize (
{
if (io->addrlen != sizeof (io->addr))
bad_address_length (io->addrlen, sizeof (io->addr));
- *from = io->addr;
+ from->dest.sa = io->addr;
}
else
- CLEAR (*from);
+ CLEAR (from->dest.sa);
}
if (buf)