|
|
#include "memdbg.h" | #include "memdbg.h" |
| |
const int proto_overhead[] = { /* indexed by PROTO_x */ | const int proto_overhead[] = { /* indexed by PROTO_x */ |
IPv4_UDP_HEADER_SIZE, |
0, |
|
IPv4_UDP_HEADER_SIZE, /* IPv4 */ |
IPv4_TCP_HEADER_SIZE, | IPv4_TCP_HEADER_SIZE, |
IPv4_TCP_HEADER_SIZE, | IPv4_TCP_HEADER_SIZE, |
IPv4_TCP_HEADER_SIZE |
#ifdef USE_PF_INET6 |
|
IPv6_UDP_HEADER_SIZE, /* IPv6 */ |
|
IPv6_TCP_HEADER_SIZE, |
|
IPv6_TCP_HEADER_SIZE, |
|
IPv6_TCP_HEADER_SIZE, |
|
#endif |
}; | }; |
| |
/* | /* |
|
Lines 260-279
update_remote (const char* host,
|
Link Here
|
|---|
|
struct openvpn_sockaddr *addr, | struct openvpn_sockaddr *addr, |
bool *changed) | bool *changed) |
{ | { |
if (host && addr) |
switch(addr->addr.sa.sa_family) { |
{ |
case AF_INET: |
const in_addr_t new_addr = getaddr ( |
if (host && addr) |
GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, |
{ |
host, |
const in_addr_t new_addr = getaddr ( |
1, |
GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, |
NULL, |
host, |
NULL); |
1, |
if (new_addr && addr->sa.sin_addr.s_addr != new_addr) |
NULL, |
|
NULL); |
|
if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr) |
{ | { |
addr->sa.sin_addr.s_addr = new_addr; |
addr->addr.in4.sin_addr.s_addr = new_addr; |
*changed = true; | *changed = true; |
} | } |
} |
} |
|
break; |
|
#ifdef USE_PF_INET6 |
|
case AF_INET6: /* jjoFIXME: should adapt getaddr() for AF_INET6 */ |
|
if (host && addr) |
|
{ |
|
struct addrinfo hints , *ai; |
|
int err; |
|
memset(&hints, 0, sizeof hints); |
|
hints.ai_flags=AI_PASSIVE; |
|
hints.ai_family=AF_INET6; |
|
if ((err=getaddrinfo(host, NULL, &hints, &ai))==0) |
|
{ |
|
struct sockaddr_in6 *sin6=(struct sockaddr_in6*)ai->ai_addr; |
|
if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &addr->addr.in6.sin6_addr)) |
|
{ |
|
int port=addr->addr.in6.sin6_port; /* backup current port for easier copy, restore later */ |
|
addr->addr.in6=*sin6; /* ipv6 requires also eg. sin6_scope_id => easy to full copy*/ |
|
addr->addr.in6.sin6_port=port; |
|
} |
|
freeaddrinfo(ai); |
|
} |
|
} |
|
break; |
|
#endif |
|
default: |
|
ASSERT(0); |
|
} |
} | } |
| |
static int | static int |
|
|
return sd; | return sd; |
} | } |
| |
|
#ifdef USE_PF_INET6 |
|
static socket_descriptor_t |
|
create_socket_udp6 (const unsigned int flags) |
|
{ |
|
socket_descriptor_t sd; |
|
|
|
if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
|
msg (M_SOCKERR, "UDP: Cannot create UDP6 socket"); |
|
#if ENABLE_IP_PKTINFO |
|
else if (flags & SF_USE_IP_PKTINFO) |
|
{ |
|
int pad = 1; |
|
setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, (void*)&pad, sizeof(pad)); |
|
} |
|
#endif |
|
return sd; |
|
} |
|
|
|
static socket_descriptor_t |
|
create_socket_tcp6 (void) |
|
{ |
|
socket_descriptor_t sd; |
|
|
|
if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) |
|
msg (M_SOCKERR, "Cannot create TCP6 socket"); |
|
|
|
/* set SO_REUSEADDR on socket */ |
|
{ |
|
int on = 1; |
|
if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, |
|
(void *) &on, sizeof (on)) < 0) |
|
msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket"); |
|
} |
|
|
|
return sd; |
|
} |
|
|
|
#endif |
static void | static void |
create_socket (struct link_socket *sock) | create_socket (struct link_socket *sock) |
{ | { |
|
|
{ | { |
sock->sd = create_socket_tcp (); | sock->sd = create_socket_tcp (); |
} | } |
|
#ifdef USE_PF_INET6 |
|
else if (sock->info.proto == PROTO_TCPv6_SERVER |
|
|| sock->info.proto == PROTO_TCPv6_CLIENT) |
|
{ |
|
sock->sd = create_socket_tcp6 (); |
|
} |
|
else if (sock->info.proto == PROTO_UDPv6) |
|
{ |
|
sock->sd = create_socket_udp6 (sock->sockflags); |
|
} |
|
#endif |
else | else |
{ | { |
ASSERT (0); | ASSERT (0); |
|
Lines 586-592
socket_do_accept (socket_descriptor_t sd
|
Link Here
|
|---|
|
struct link_socket_actual *act, | struct link_socket_actual *act, |
const bool nowait) | const bool nowait) |
{ | { |
socklen_t remote_len = sizeof (act->dest.sa); |
/* af_addr_size WILL return 0 in this case if AFs other than AF_INET |
|
* are compiled because act is empty here. |
|
* could use getsockname() to support later remote_len check |
|
*/ |
|
socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family); |
|
socklen_t remote_len = sizeof(act->dest.addr); |
socket_descriptor_t new_sd = SOCKET_UNDEFINED; | socket_descriptor_t new_sd = SOCKET_UNDEFINED; |
| |
CLEAR (*act); | CLEAR (*act); |
|
Lines 594-600
socket_do_accept (socket_descriptor_t sd
|
Link Here
|
|---|
|
#ifdef HAVE_GETPEERNAME | #ifdef HAVE_GETPEERNAME |
if (nowait) | if (nowait) |
{ | { |
new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len); |
new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len); |
| |
if (!socket_defined (new_sd)) | if (!socket_defined (new_sd)) |
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed"); | msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed"); |
|
|
#endif | #endif |
else | else |
{ | { |
new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len); |
new_sd = accept (sd, &act->dest.addr.sa, &remote_len); |
} | } |
| |
#if 0 /* For debugging only, test the effect of accept() failures */ | #if 0 /* For debugging only, test the effect of accept() failures */ |
|
|
{ | { |
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd); | msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd); |
} | } |
else if (remote_len != sizeof (act->dest.sa)) |
/* only valid if we have remote_len_af!=0 */ |
|
else if (remote_len_af && remote_len != remote_len_af) |
{ | { |
msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); | msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); |
openvpn_close_socket (new_sd); | openvpn_close_socket (new_sd); |
|
Lines 724-730
socket_bind (socket_descriptor_t sd,
|
Link Here
|
|---|
|
{ | { |
struct gc_arena gc = gc_new (); | struct gc_arena gc = gc_new (); |
| |
if (bind (sd, (struct sockaddr *) &local->sa, sizeof (local->sa))) |
if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family))) |
{ | { |
const int errnum = openvpn_errno_socket (); | const int errnum = openvpn_errno_socket (); |
msg (M_FATAL, "%s: Socket bind failed on local address %s: %s", | msg (M_FATAL, "%s: Socket bind failed on local address %s: %s", |
|
Lines 745-751
openvpn_connect (socket_descriptor_t sd,
|
Link Here
|
|---|
|
| |
#ifdef CONNECT_NONBLOCK | #ifdef CONNECT_NONBLOCK |
set_nonblock (sd); | set_nonblock (sd); |
status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa)); |
status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family)); |
if (status) | if (status) |
status = openvpn_errno_socket (); | status = openvpn_errno_socket (); |
if (status == EINPROGRESS) | if (status == EINPROGRESS) |
|
Lines 829-901
socket_connect (socket_descriptor_t *sd,
|
Link Here
|
|---|
|
| |
#ifdef CONNECT_NONBLOCK | #ifdef CONNECT_NONBLOCK |
msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", | msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", |
print_sockaddr (remote, &gc)); |
print_sockaddr (remote, &gc)); |
#else | #else |
msg (M_INFO, "Attempting to establish TCP connection with %s", | msg (M_INFO, "Attempting to establish TCP connection with %s", |
print_sockaddr (remote, &gc)); |
print_sockaddr (remote, &gc)); |
#endif | #endif |
| |
while (true) | while (true) |
{ |
{ |
int status; |
int status; |
| |
#ifdef ENABLE_MANAGEMENT | #ifdef ENABLE_MANAGEMENT |
if (management) |
if (management) |
management_set_state (management, |
management_set_state (management, |
OPENVPN_STATE_TCP_CONNECT, |
OPENVPN_STATE_TCP_CONNECT, |
NULL, |
NULL, |
(in_addr_t)0, |
(in_addr_t)0, |
(in_addr_t)0); |
(in_addr_t)0); |
#endif | #endif |
| |
status = openvpn_connect (*sd, remote, connect_timeout, signal_received); |
status = openvpn_connect (*sd, remote, connect_timeout, signal_received); |
| |
get_signal (signal_received); |
get_signal (signal_received); |
if (*signal_received) |
if (*signal_received) |
goto done; |
goto done; |
| |
if (!status) |
if (!status) |
break; |
break; |
| |
msg (D_LINK_ERRORS, |
msg (D_LINK_ERRORS, |
"TCP: connect to %s failed, will try again in %d seconds: %s", |
"TCP: connect to %s failed, will try again in %d seconds: %s", |
print_sockaddr (remote, &gc), |
print_sockaddr (remote, &gc), |
connect_retry_seconds, |
connect_retry_seconds, |
strerror_ts (status, &gc)); |
strerror_ts (status, &gc)); |
| |
openvpn_close_socket (*sd); |
openvpn_close_socket (*sd); |
*sd = SOCKET_UNDEFINED; |
*sd = SOCKET_UNDEFINED; |
| |
if (connect_retry_max > 0 && ++retry >= connect_retry_max) |
if (connect_retry_max > 0 && ++retry >= connect_retry_max) |
{ |
{ |
*signal_received = SIGUSR1; |
*signal_received = SIGUSR1; |
goto done; |
goto done; |
} |
} |
| |
openvpn_sleep (connect_retry_seconds); |
openvpn_sleep (connect_retry_seconds); |
| |
get_signal (signal_received); |
get_signal (signal_received); |
if (*signal_received) |
if (*signal_received) |
goto done; |
goto done; |
| |
if (remote_list) |
switch(remote->addr.sa.sa_family) { |
|
case AF_INET: |
|
if (remote_list) |
{ | { |
remote_list_next (remote_list); | remote_list_next (remote_list); |
remote_dynamic = remote_list_host (remote_list); | remote_dynamic = remote_list_host (remote_list); |
remote->sa.sin_port = htons (remote_list_port (remote_list)); |
remote->addr.in4.sin_port = htons (remote_list_port (remote_list)); |
*remote_changed = true; | *remote_changed = true; |
} | } |
| |
*sd = create_socket_tcp (); |
*sd = create_socket_tcp (); |
if (bind_local) |
if (bind_local) |
socket_bind (*sd, local, "TCP Client"); |
socket_bind (*sd, local, "TCP Client"); |
update_remote (remote_dynamic, remote, remote_changed); |
update_remote (remote_dynamic, remote, remote_changed); |
|
break; |
|
#ifdef USE_PF_INET6 |
|
case AF_INET6: |
|
if (remote_list) |
|
{ |
|
remote_list_next (remote_list); |
|
remote_dynamic = remote_list_host (remote_list); |
|
remote->addr.in6.sin6_port = htons (remote_list_port (remote_list)); |
|
*remote_changed = true; |
|
} |
|
*sd = create_socket_tcp6 (); |
|
if (bind_local) |
|
socket_bind (*sd, local, "TCP6 Client"); |
|
update_remote (remote_dynamic, remote, remote_changed); |
|
break; |
|
#endif |
|
default: |
|
msg(M_FATAL, "Only TCP is supported for connection oriented, sa_family=%d", |
|
remote->addr.sa.sa_family); |
} | } |
|
} |
| |
msg (M_INFO, "TCP connection established with %s", | msg (M_INFO, "TCP connection established with %s", |
print_sockaddr (remote, &gc)); |
print_sockaddr (remote, &gc)); |
| |
done: |
done: |
gc_free (&gc); | gc_free (&gc); |
} | } |
| |
|
Lines 950-966
resolve_bind_local (struct link_socket *
|
Link Here
|
|---|
|
| |
/* resolve local address if undefined */ | /* resolve local address if undefined */ |
if (!addr_defined (&sock->info.lsa->local)) | if (!addr_defined (&sock->info.lsa->local)) |
{ |
{ |
sock->info.lsa->local.sa.sin_family = AF_INET; |
/* may return AF_{INET|INET6} guessed from local_host */ |
sock->info.lsa->local.sa.sin_addr.s_addr = |
switch(addr_guess_family(sock->info.proto, sock->local_host)) { |
(sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, |
case AF_INET: |
sock->local_host, |
sock->info.lsa->local.addr.in4.sin_family = AF_INET; |
0, |
sock->info.lsa->local.addr.in4.sin_addr.s_addr = |
NULL, |
(sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, |
NULL) |
sock->local_host, |
: htonl (INADDR_ANY)); |
0, |
sock->info.lsa->local.sa.sin_port = htons (sock->local_port); |
NULL, |
|
NULL) |
|
: htonl (INADDR_ANY)); |
|
sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port); |
|
break; |
|
#ifdef USE_PF_INET6 |
|
case AF_INET6: |
|
{ |
|
struct addrinfo hints , *ai; |
|
int err; |
|
memset(&hints, 0, sizeof hints); |
|
hints.ai_flags=AI_PASSIVE; |
|
hints.ai_family=AF_INET6; |
|
/* if no local_host provided, ask for IN6ADDR_ANY ... */ |
|
if ((err=getaddrinfo(sock->local_host? sock->local_host : "::", |
|
NULL, &hints, &ai))==0) { |
|
sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); |
|
freeaddrinfo(ai); |
|
} else { |
|
msg (M_FATAL, "getaddrinfo() failed for local \"%s\": %s", |
|
sock->local_host, |
|
gai_strerror(err)); |
|
} |
|
sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); |
|
} |
|
break; |
|
#endif |
} | } |
|
} |
| |
/* bind to local address/port */ | /* bind to local address/port */ |
if (sock->bind_local) | if (sock->bind_local) |
|
Lines 984-1086
resolve_remote (struct link_socket *sock
|
Link Here
|
|---|
|
struct gc_arena gc = gc_new (); | struct gc_arena gc = gc_new (); |
| |
if (!sock->did_resolve_remote) | if (!sock->did_resolve_remote) |
|
{ |
|
/* resolve remote address if undefined */ |
|
if (!addr_defined (&sock->info.lsa->remote)) |
{ | { |
/* resolve remote address if undefined */ |
switch(addr_guess_family(sock->info.proto, sock->remote_host)) |
if (!addr_defined (&sock->info.lsa->remote)) |
{ |
{ |
case AF_INET: |
sock->info.lsa->remote.sa.sin_family = AF_INET; |
sock->info.lsa->remote.addr.in4.sin_family = AF_INET; |
sock->info.lsa->remote.sa.sin_addr.s_addr = 0; |
sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; |
| |
if (sock->remote_host) | if (sock->remote_host) |
{ |
{ |
unsigned int flags = GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE; |
unsigned int flags = GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE; |
int retry = 0; |
int retry = 0; |
bool status = false; |
bool status = false; |
| |
if (remote_list_len (sock->remote_list) > 1 && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) |
if (remote_list_len (sock->remote_list) > 1 && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) |
{ |
{ |
if (phase == 2) |
if (phase == 2) |
flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); |
flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); |
retry = 0; |
retry = 0; |
} |
} |
else if (phase == 1) |
else if (phase == 1) |
{ |
{ |
if (sock->resolve_retry_seconds) |
if (sock->resolve_retry_seconds) |
{ |
{ |
retry = 0; |
retry = 0; |
} |
} |
else |
|
{ |
|
flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); |
|
retry = 0; |
|
} |
|
} |
|
else if (phase == 2) |
|
{ |
|
if (sock->resolve_retry_seconds) |
|
{ |
|
flags |= GETADDR_FATAL; |
|
retry = sock->resolve_retry_seconds; |
|
} |
|
else |
|
{ |
|
ASSERT (0); |
|
} |
|
} |
|
else | else |
{ |
{ |
ASSERT (0); |
flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); |
} |
retry = 0; |
|
} |
sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr ( |
} |
flags, |
else if (phase == 2) |
sock->remote_host, |
{ |
retry, |
if (sock->resolve_retry_seconds) |
&status, |
{ |
signal_received); |
flags |= GETADDR_FATAL; |
|
retry = sock->resolve_retry_seconds; |
dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", |
} |
flags, |
else |
phase, |
{ |
retry, |
ASSERT (0); |
signal_received ? *signal_received : -1, |
} |
status); |
} |
|
else |
|
{ |
|
ASSERT (0); |
|
} |
| |
|
sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr ( |
|
flags, |
|
sock->remote_host, |
|
retry, |
|
&status, |
|
signal_received); |
|
|
|
dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", |
|
flags, |
|
phase, |
|
retry, |
|
signal_received ? *signal_received : -1, |
|
status); |
|
|
|
if (signal_received) |
|
{ |
|
if (*signal_received) |
|
goto done; |
|
} |
|
if (!status) |
|
{ |
if (signal_received) | if (signal_received) |
{ |
*signal_received = SIGUSR1; |
if (*signal_received) |
goto done; |
goto done; |
|
} |
|
if (!status) |
|
{ |
|
if (signal_received) |
|
*signal_received = SIGUSR1; |
|
goto done; |
|
} |
|
} | } |
|
} |
| |
sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port); |
sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); |
} |
break; |
|
|
/* should we re-use previous active remote address? */ |
|
if (link_socket_actual_defined (&sock->info.lsa->actual)) |
|
{ |
|
msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", |
|
print_link_socket_actual (&sock->info.lsa->actual, &gc)); |
|
if (remote_dynamic) |
|
*remote_dynamic = NULL; |
|
} |
|
else |
|
{ |
|
CLEAR (sock->info.lsa->actual); |
|
sock->info.lsa->actual.dest = sock->info.lsa->remote; |
|
} |
|
| |
/* remember that we finished */ |
#ifdef USE_PF_INET6 |
sock->did_resolve_remote = true; |
case AF_INET6: /* jjoFIXME: ipv6 signal logic */ |
|
{ |
|
struct addrinfo hints , *ai; |
|
int err; |
|
memset(&hints, 0, sizeof hints); |
|
hints.ai_flags=0; |
|
hints.ai_family=AF_INET6; |
|
if ((err=getaddrinfo(sock->remote_host? sock->remote_host : "::" , NULL, &hints, &ai))==0) { |
|
sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); |
|
freeaddrinfo(ai); |
|
} else { |
|
msg (M_FATAL, "getaddrinfo() failed for remote \"%s\": %s", |
|
sock->remote_host, |
|
gai_strerror(err)); |
|
} |
|
sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); |
|
} |
|
break; |
|
#endif |
|
} |
|
} |
|
/* should we re-use previous active remote address? */ |
|
if (link_socket_actual_defined (&sock->info.lsa->actual)) |
|
{ |
|
msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", |
|
print_link_socket_actual (&sock->info.lsa->actual, &gc)); |
|
if (remote_dynamic) |
|
*remote_dynamic = NULL; |
|
} |
|
else |
|
{ |
|
CLEAR (sock->info.lsa->actual); |
|
sock->info.lsa->actual.dest = sock->info.lsa->remote; |
} | } |
| |
done: |
/* remember that we finished */ |
|
sock->did_resolve_remote = true; |
|
} |
|
|
|
done: |
gc_free (&gc); | gc_free (&gc); |
} | } |
| |
|
Lines 1310-1316
link_socket_init_phase2 (struct link_soc
|
Link Here
|
|---|
|
goto done; | goto done; |
| |
/* TCP client/server */ | /* TCP client/server */ |
if (sock->info.proto == PROTO_TCPv4_SERVER) |
if (sock->info.proto == PROTO_TCPv4_SERVER |
|
#ifdef USE_PF_INET6 |
|
||sock->info.proto == PROTO_TCPv6_SERVER |
|
#endif |
|
) |
{ | { |
switch (sock->mode) | switch (sock->mode) |
{ | { |
|
Lines 1345-1351
link_socket_init_phase2 (struct link_soc
|
Link Here
|
|---|
|
ASSERT (0); | ASSERT (0); |
} | } |
} | } |
else if (sock->info.proto == PROTO_TCPv4_CLIENT) |
else if (sock->info.proto == PROTO_TCPv4_CLIENT |
|
#ifdef USE_PF_INET6 |
|
||sock->info.proto == PROTO_TCPv6_CLIENT |
|
#endif |
|
) |
{ | { |
| |
#ifdef GENERAL_PROXY_SUPPORT | #ifdef GENERAL_PROXY_SUPPORT |
|
Lines 1430-1437
#ifdef ENABLE_SOCKS
|
Link Here
|
|---|
|
sock->remote_port = sock->proxy_dest_port; | sock->remote_port = sock->proxy_dest_port; |
sock->did_resolve_remote = false; | sock->did_resolve_remote = false; |
| |
sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0; |
addr_zero_host(&sock->info.lsa->actual.dest); |
sock->info.lsa->remote.sa.sin_addr.s_addr = 0; |
addr_zero_host(&sock->info.lsa->remote); |
| |
resolve_remote (sock, 1, NULL, signal_received); | resolve_remote (sock, 1, NULL, signal_received); |
| |
|
|
if (remote_changed) | if (remote_changed) |
{ | { |
msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); | msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); |
sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr; |
addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest); |
} | } |
} | } |
| |
|
Lines 1618-1630
link_socket_bad_incoming_addr (struct bu
|
Link Here
|
|---|
|
{ | { |
struct gc_arena gc = gc_new (); | struct gc_arena gc = gc_new (); |
| |
msg (D_LINK_ERRORS, |
switch(from_addr->dest.addr.sa.sa_family) |
"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_link_socket_actual (from_addr, &gc), |
case AF_INET: |
(int)from_addr->dest.sa.sin_family, |
#ifdef USE_PF_INET6 |
print_sockaddr (&info->lsa->remote, &gc)); |
case AF_INET6: |
|
#endif |
|
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_link_socket_actual (from_addr, &gc), |
|
(int)from_addr->dest.addr.sa.sa_family, |
|
print_sockaddr (&info->lsa->remote, &gc)); |
|
break; |
|
} |
buf->len = 0; | buf->len = 0; |
|
|
gc_free (&gc); | gc_free (&gc); |
} | } |
| |
|
Lines 1639-1648
link_socket_current_remote (const struct
|
Link Here
|
|---|
|
{ | { |
const struct link_socket_addr *lsa = info->lsa; | const struct link_socket_addr *lsa = info->lsa; |
| |
|
/* |
|
* This logic supports "redirect-gateway" semantic, which |
|
* makes sense only for PF_INET routes over PF_INET endpoints |
|
* |
|
* Maybe in the future consider PF_INET6 endpoints also ... |
|
* by now just ignore it |
|
* |
|
*/ |
|
#if defined ( USE_PF_INET6 ) |
|
if(lsa->actual.dest.addr.sa.sa_family != AF_INET) |
|
return 0; |
|
#else |
|
ASSERT(lsa->actual.dest.addr.sa.sa_family == AF_INET); |
|
#endif |
|
|
if (link_socket_actual_defined (&lsa->actual)) | if (link_socket_actual_defined (&lsa->actual)) |
return ntohl (lsa->actual.dest.sa.sin_addr.s_addr); |
return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr); |
else if (addr_defined (&lsa->remote)) | else if (addr_defined (&lsa->remote)) |
return ntohl (lsa->remote.sa.sin_addr.s_addr); |
return ntohl (lsa->remote.addr.in4.sin_addr.s_addr); |
else | else |
return 0; | return 0; |
} | } |
|
Lines 1869-1895
print_sockaddr_ex (const struct openvpn_
|
Link Here
|
|---|
|
const unsigned int flags, | const unsigned int flags, |
struct gc_arena *gc) | struct gc_arena *gc) |
{ | { |
if (addr) |
struct buffer out; |
{ |
bool addr_is_defined; |
struct buffer out = alloc_buf_gc (64, gc); |
if (!addr) { |
const int port = ntohs (addr->sa.sin_port); |
return "[NULL]"; |
|
} |
mutex_lock_static (L_INET_NTOA); |
addr_is_defined = addr_defined (addr); |
buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]")); |
switch(addr->addr.sa.sa_family) { |
mutex_unlock_static (L_INET_NTOA); |
case AF_INET: |
|
{ |
if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) |
const int port= ntohs (addr->addr.in4.sin_port); |
&& port) |
out = alloc_buf_gc (128, gc); |
|
buf_puts (&out, "[AF_INET]"); |
|
mutex_lock_static (L_INET_NTOA); |
|
buf_puts (&out, (addr_is_defined ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]")); |
|
mutex_unlock_static (L_INET_NTOA); |
|
|
|
if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) |
|
&& port) |
{ | { |
if (separator) | if (separator) |
buf_printf (&out, "%s", separator); | buf_printf (&out, "%s", separator); |
| |
buf_printf (&out, "%d", port); | buf_printf (&out, "%d", port); |
} | } |
return BSTR (&out); |
} |
} |
break; |
else |
#ifdef USE_PF_INET6 |
return "[NULL]"; |
case AF_INET6: |
|
{ |
|
const int port= ntohs (addr->addr.in6.sin6_port); |
|
char buf[INET6_ADDRSTRLEN] = "[undef]"; |
|
out = alloc_buf_gc (128, gc); |
|
buf_puts (&out, "[AF_INET6]"); |
|
if (addr_is_defined) |
|
{ |
|
getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), |
|
buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); |
|
buf_puts (&out, buf); |
|
} |
|
if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) |
|
&& port) |
|
{ |
|
if (separator) |
|
buf_puts (&out, separator); |
|
|
|
buf_printf (&out, "%d", port); |
|
} |
|
} |
|
break; |
|
#endif |
|
} |
|
return BSTR (&out); |
} | } |
| |
const char * | const char * |
|
Lines 1909-1920
print_link_socket_actual_ex (const struc
|
Link Here
|
|---|
|
struct buffer out = alloc_buf_gc (128, gc); | struct buffer out = alloc_buf_gc (128, gc); |
buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc)); | buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc)); |
#if ENABLE_IP_PKTINFO | #if ENABLE_IP_PKTINFO |
if ((flags & PS_SHOW_PKTINFO) && act->pi.ipi_spec_dst.s_addr) |
if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act)) |
{ | { |
|
switch(act->dest.addr.sa.sa_family) |
|
{ |
|
case AF_INET: |
|
{ |
struct openvpn_sockaddr sa; | struct openvpn_sockaddr sa; |
CLEAR (sa); | CLEAR (sa); |
sa.sa.sin_addr = act->pi.ipi_spec_dst; |
sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; |
buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); | buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); |
|
} |
|
break; |
|
#ifdef USE_PF_INET6 |
|
case AF_INET6: |
|
{ |
|
struct sockaddr_in6 sin6; |
|
char buf[INET6_ADDRSTRLEN] = "[undef]"; |
|
memset(&sin6, 0, sizeof sin6); |
|
sin6.sin6_family = AF_INET6; |
|
sin6.sin6_addr = act->pi.in6.ipi6_addr; |
|
{ |
|
if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), |
|
buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0) |
|
buf_printf (&out, " (via %s)", buf); |
|
else |
|
buf_printf (&out, " (via [getnameinfo() err])"); |
|
} |
|
} |
|
break; |
|
#endif |
|
} |
|
|
} | } |
#endif | #endif |
return BSTR (&out); | return BSTR (&out); |
|
|
setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *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]; | char name_buf[256]; |
|
char buf[128]; |
| |
if (flags & SA_IP_PORT) |
switch(addr->addr.sa.sa_family) { |
openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); |
case AF_INET: |
else |
if (flags & SA_IP_PORT) |
openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix); |
openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); |
|
else |
|
openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix); |
| |
mutex_lock_static (L_INET_NTOA); |
mutex_lock_static (L_INET_NTOA); |
setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr)); |
setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr)); |
mutex_unlock_static (L_INET_NTOA); |
mutex_unlock_static (L_INET_NTOA); |
|
|
|
if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port) |
|
{ |
|
openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); |
|
setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port)); |
|
} |
|
break; |
|
#ifdef USE_PF_INET6 |
|
case AF_INET6: |
|
openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); |
|
getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), |
|
buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); |
|
setenv_str (es, name_buf, buf); |
| |
if ((flags & SA_IP_PORT) && addr->sa.sin_port) |
|
{ |
|
openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); | openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); |
setenv_int (es, name_buf, ntohs (addr->sa.sin_port)); |
setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port)); |
} |
break; |
|
#endif |
|
} |
} | } |
| |
void | void |
|
Lines 1974-1980
setenv_in_addr_t (struct env_set *es, co
|
Link Here
|
|---|
|
{ | { |
struct openvpn_sockaddr si; | struct openvpn_sockaddr si; |
CLEAR (si); | CLEAR (si); |
si.sa.sin_addr.s_addr = htonl (addr); |
si.addr.in4.sin_family = AF_INET; |
|
si.addr.in4.sin_addr.s_addr = htonl (addr); |
setenv_sockaddr (es, name_prefix, &si, flags); | setenv_sockaddr (es, name_prefix, &si, flags); |
} | } |
} | } |
|
Lines 1995-2010
setenv_link_socket_actual (struct env_se
|
Link Here
|
|---|
|
struct proto_names { | struct proto_names { |
const char *short_form; | const char *short_form; |
const char *display_form; | const char *display_form; |
|
bool is_dgram; |
|
bool is_net; |
|
sa_family_t proto_af; |
}; | }; |
| |
/* Indexed by PROTO_x */ | /* Indexed by PROTO_x */ |
static const struct proto_names proto_names[] = { |
static const struct proto_names proto_names[PROTO_N] = { |
{"udp", "UDPv4"}, |
{"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC}, |
{"tcp-server", "TCPv4_SERVER"}, |
{"udp", "UDPv4",1,1, AF_INET}, |
{"tcp-client", "TCPv4_CLIENT"}, |
{"tcp-server", "TCPv4_SERVER",0,1, AF_INET}, |
{"tcp", "TCPv4"} |
{"tcp-client", "TCPv4_CLIENT",0,1, AF_INET}, |
|
{"tcp", "TCPv4",0,1, AF_INET}, |
|
#ifdef USE_PF_INET6 |
|
{"udp6" ,"UDPv6",1,1, AF_INET6}, |
|
{"tcp6-server","TCPv6_SERVER",0,1, AF_INET6}, |
|
{"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6}, |
|
{"tcp6" ,"TCPv6",0,1, AF_INET6}, |
|
#endif |
}; | }; |
| |
|
bool |
|
proto_is_net(int proto) |
|
{ |
|
if (proto < 0 || proto >= PROTO_N) |
|
ASSERT(0); |
|
return proto_names[proto].is_net; |
|
} |
|
bool |
|
proto_is_dgram(int proto) |
|
{ |
|
if (proto < 0 || proto >= PROTO_N) |
|
ASSERT(0); |
|
return proto_names[proto].is_dgram; |
|
} |
|
bool |
|
proto_is_udp(int proto) |
|
{ |
|
if (proto < 0 || proto >= PROTO_N) |
|
ASSERT(0); |
|
return proto_names[proto].is_dgram&&proto_names[proto].is_net; |
|
} |
|
bool |
|
proto_is_tcp(int proto) |
|
{ |
|
if (proto < 0 || proto >= PROTO_N) |
|
ASSERT(0); |
|
return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; |
|
} |
|
|
|
sa_family_t |
|
proto_sa_family(int proto) |
|
{ |
|
if (proto < 0 || proto >= PROTO_N) |
|
ASSERT(0); |
|
return proto_names[proto].proto_af; |
|
} |
|
|
int | int |
ascii2proto (const char* proto_name) | ascii2proto (const char* proto_name) |
{ | { |
|
Lines 2044-2049
proto2ascii_all (struct gc_arena *gc)
|
Link Here
|
|---|
|
return BSTR (&out); | return BSTR (&out); |
} | } |
| |
|
int |
|
addr_guess_family(int proto, const char *name) |
|
{ |
|
sa_family_t ret; |
|
if (proto) { |
|
return proto_sa_family(proto); /* already stamped */ |
|
} |
|
#ifdef USE_PF_UNIX |
|
else if (name && name[0] == '/') { |
|
return AF_UNIX; |
|
} |
|
#endif |
|
#ifdef USE_PF_INET6 |
|
else { |
|
struct addrinfo hints , *ai; |
|
int err; |
|
memset(&hints, 0, sizeof hints); |
|
hints.ai_flags=AI_NUMERICHOST; |
|
if ((err=getaddrinfo(name, NULL, &hints, &ai))==0) { |
|
ret=ai->ai_family; |
|
freeaddrinfo(ai); |
|
return ret; |
|
} |
|
} |
|
#endif |
|
return AF_INET; /* default */ |
|
} |
|
const char * |
|
addr_family_name (int af) |
|
{ |
|
switch (af) { |
|
case AF_INET: return "AF_INET"; |
|
case AF_INET6: return "AF_INET6"; |
|
#ifdef USE_PF_UNIX |
|
case AF_UNIX: return "AF_UNIX"; |
|
#endif |
|
} |
|
return "AF_UNSPEC"; |
|
} |
|
|
/* | /* |
* Given a local proto, return local proto | * Given a local proto, return local proto |
* if !remote, or compatible remote proto | * if !remote, or compatible remote proto |
|
Lines 2058-2067
proto_remote (int proto, bool remote)
|
Link Here
|
|---|
|
ASSERT (proto >= 0 && proto < PROTO_N); | ASSERT (proto >= 0 && proto < PROTO_N); |
if (remote) | if (remote) |
{ | { |
if (proto == PROTO_TCPv4_SERVER) |
switch (proto) |
return PROTO_TCPv4_CLIENT; |
{ |
if (proto == PROTO_TCPv4_CLIENT) |
case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT; |
return PROTO_TCPv4_SERVER; |
case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER; |
|
#ifdef USE_PF_INET6 |
|
case PROTO_TCPv6_SERVER: return PROTO_TCPv6_CLIENT; |
|
case PROTO_TCPv6_CLIENT: return PROTO_TCPv6_SERVER; |
|
#endif |
|
} |
} | } |
return proto; | return proto; |
} | } |
|
|
| |
#if ENABLE_IP_PKTINFO | #if ENABLE_IP_PKTINFO |
| |
struct openvpn_pktinfo |
struct openvpn_in4_pktinfo |
{ | { |
struct cmsghdr cmsghdr; | struct cmsghdr cmsghdr; |
struct in_pktinfo in_pktinfo; |
struct in_pktinfo pi; |
}; | }; |
|
#ifdef USE_PF_INET6 |
|
struct openvpn_in6_pktinfo |
|
{ |
|
struct cmsghdr cmsghdr; |
|
struct in6_pktinfo pi6; |
|
}; |
|
#endif |
|
|
|
union openvpn_pktinfo { |
|
struct openvpn_in4_pktinfo cmsgpi; |
|
#ifdef USE_PF_INET6 |
|
struct openvpn_in6_pktinfo cmsgpi6; |
|
#endif |
|
}; |
|
|
| |
static socklen_t | static socklen_t |
link_socket_read_udp_posix_recvmsg (struct link_socket *sock, | link_socket_read_udp_posix_recvmsg (struct link_socket *sock, |
|
Lines 2132-2146
link_socket_read_udp_posix_recvmsg (stru
|
Link Here
|
|---|
|
struct link_socket_actual *from) | struct link_socket_actual *from) |
{ | { |
struct iovec iov; | struct iovec iov; |
struct openvpn_pktinfo opi; |
union openvpn_pktinfo opi; |
struct msghdr mesg; | struct msghdr mesg; |
socklen_t fromlen = sizeof (from->dest.sa); |
socklen_t fromlen = sizeof (from->dest.addr); |
| |
iov.iov_base = BPTR (buf); | iov.iov_base = BPTR (buf); |
iov.iov_len = maxsize; | iov.iov_len = maxsize; |
mesg.msg_iov = &iov; | mesg.msg_iov = &iov; |
mesg.msg_iovlen = 1; | mesg.msg_iovlen = 1; |
mesg.msg_name = &from->dest.sa; |
mesg.msg_name = &from->dest.addr; |
mesg.msg_namelen = fromlen; | mesg.msg_namelen = fromlen; |
mesg.msg_control = &opi; | mesg.msg_control = &opi; |
mesg.msg_controllen = sizeof (opi); | mesg.msg_controllen = sizeof (opi); |
|
Lines 2157-2165
link_socket_read_udp_posix_recvmsg (stru
|
Link Here
|
|---|
|
&& cmsg->cmsg_len >= sizeof (opi)) | && cmsg->cmsg_len >= sizeof (opi)) |
{ | { |
struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); | struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); |
from->pi.ipi_ifindex = pkti->ipi_ifindex; |
from->pi.in4.ipi_ifindex = pkti->ipi_ifindex; |
from->pi.ipi_spec_dst = pkti->ipi_spec_dst; |
from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst; |
|
} |
|
#ifdef USE_PF_INET6 |
|
else if (cmsg != NULL |
|
&& CMSG_NXTHDR (&mesg, cmsg) == NULL |
|
&& cmsg->cmsg_level == IPPROTO_IPV6 |
|
&& cmsg->cmsg_type == IPV6_PKTINFO |
|
&& cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo)) |
|
{ |
|
struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); |
|
from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; |
|
from->pi.in6.ipi6_addr = pkti6->ipi6_addr; |
} | } |
|
#endif |
} | } |
return fromlen; | return fromlen; |
} | } |
|
Lines 2171-2188
link_socket_read_udp_posix (struct link_
|
Link Here
|
|---|
|
int maxsize, | int maxsize, |
struct link_socket_actual *from) | struct link_socket_actual *from) |
{ | { |
socklen_t fromlen = sizeof (from->dest.sa); |
socklen_t fromlen = sizeof (from->dest.addr); |
from->dest.sa.sin_addr.s_addr = 0; |
socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto)); |
|
addr_zero_host(&from->dest); |
ASSERT (buf_safe (buf, maxsize)); | ASSERT (buf_safe (buf, maxsize)); |
#if ENABLE_IP_PKTINFO | #if ENABLE_IP_PKTINFO |
if (sock->sockflags & SF_USE_IP_PKTINFO) |
/* Both PROTO_UDPv4 and PROTO_UDPv6 */ |
|
if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO) |
fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); | fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); |
else | else |
#endif | #endif |
buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, | buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, |
(struct sockaddr *) &from->dest.sa, &fromlen); |
&from->dest.addr.sa, &fromlen); |
if (fromlen != sizeof (from->dest.sa)) |
if (buf->len >= 0 && expectedlen && fromlen != expectedlen) |
bad_address_length (fromlen, sizeof (from->dest.sa)); |
bad_address_length (fromlen, expectedlen); |
return buf->len; | return buf->len; |
} | } |
| |
|
Lines 2219-2244
link_socket_write_udp_posix_sendmsg (str
|
Link Here
|
|---|
|
struct iovec iov; | struct iovec iov; |
struct msghdr mesg; | struct msghdr mesg; |
struct cmsghdr *cmsg; | struct cmsghdr *cmsg; |
struct in_pktinfo *pkti; |
|
struct openvpn_pktinfo opi; |
|
| |
iov.iov_base = BPTR (buf); | iov.iov_base = BPTR (buf); |
iov.iov_len = BLEN (buf); | iov.iov_len = BLEN (buf); |
mesg.msg_iov = &iov; | mesg.msg_iov = &iov; |
mesg.msg_iovlen = 1; | mesg.msg_iovlen = 1; |
mesg.msg_name = &to->dest.sa; |
switch (sock->info.lsa->remote.addr.sa.sa_family) |
mesg.msg_namelen = sizeof (to->dest.sa); |
{ |
mesg.msg_control = &opi; |
case AF_INET: { |
mesg.msg_controllen = sizeof (opi); |
struct openvpn_in4_pktinfo opi; |
mesg.msg_flags = 0; |
struct in_pktinfo *pkti; |
cmsg = CMSG_FIRSTHDR (&mesg); |
mesg.msg_name = &to->dest.addr.sa; |
cmsg->cmsg_len = sizeof (opi); |
mesg.msg_namelen = sizeof (struct sockaddr_in); |
cmsg->cmsg_level = SOL_IP; |
mesg.msg_control = &opi; |
cmsg->cmsg_type = IP_PKTINFO; |
mesg.msg_controllen = sizeof (opi); |
pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); |
mesg.msg_flags = 0; |
pkti->ipi_ifindex = to->pi.ipi_ifindex; |
cmsg = CMSG_FIRSTHDR (&mesg); |
pkti->ipi_spec_dst = to->pi.ipi_spec_dst; |
cmsg->cmsg_len = sizeof (opi); |
pkti->ipi_addr.s_addr = 0; |
cmsg->cmsg_level = SOL_IP; |
|
cmsg->cmsg_type = IP_PKTINFO; |
|
pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); |
|
pkti->ipi_ifindex = to->pi.in4.ipi_ifindex; |
|
pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst; |
|
pkti->ipi_addr.s_addr = 0; |
|
break; |
|
} |
|
#ifdef USE_PF_INET6 |
|
case AF_INET6: { |
|
struct openvpn_in6_pktinfo opi6; |
|
struct in6_pktinfo *pkti6; |
|
mesg.msg_name = &to->dest.addr.sa; |
|
mesg.msg_namelen = sizeof (struct sockaddr_in6); |
|
mesg.msg_control = &opi6; |
|
mesg.msg_controllen = sizeof (opi6); |
|
mesg.msg_flags = 0; |
|
cmsg = CMSG_FIRSTHDR (&mesg); |
|
cmsg->cmsg_len = sizeof (opi6); |
|
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; |
|
break; |
|
} |
|
#endif |
|
default: ASSERT(0); |
|
} |
return sendmsg (sock->sd, &mesg, 0); | return sendmsg (sock->sd, &mesg, 0); |
} | } |
| |
|
Lines 2382-2388
socket_send_queue (struct link_socket *s
|
Link Here
|
|---|
|
{ | { |
/* set destination address for UDP writes */ | /* set destination address for UDP writes */ |
sock->writes.addr_defined = true; | sock->writes.addr_defined = true; |
sock->writes.addr = to->dest.sa; |
sock->writes.addr = to->dest.addr.in4; |
sock->writes.addrlen = sizeof (sock->writes.addr); | sock->writes.addrlen = sizeof (sock->writes.addr); |
| |
status = WSASendTo( | status = WSASendTo( |
|
Lines 2538-2547
socket_finalize (SOCKET s,
|
Link Here
|
|---|
|
{ | { |
if (io->addrlen != sizeof (io->addr)) | if (io->addrlen != sizeof (io->addr)) |
bad_address_length (io->addrlen, sizeof (io->addr)); | bad_address_length (io->addrlen, sizeof (io->addr)); |
from->dest.sa = io->addr; |
from->dest.addr.sa = io->addr; |
} | } |
else | else |
CLEAR (from->dest.sa); |
CLEAR (from->dest.addr.sa); |
} | } |
| |
if (buf) | if (buf) |