android: Pin direct-flow sockets to the active network (2.13.10)
Android / pre-check (push) Failing after 6s
Android / android (push) Skipped
CIFuzz / pre-check (push) Failing after 4s
CIFuzz / fuzzing (address) (push) Skipped
CIFuzz / fuzzing (undefined) (push) Skipped
CodeQL / pre-check (push) Failing after 3s
CodeQL / analyze (python) (push) Skipped
CodeQL / analyze (ruby) (push) Skipped
CodeQL / analyze-cpp (push) Skipped
FreeBSD / pre-check (push) Failing after 3s
FreeBSD / freebsd (14.4) (push) Skipped
FreeBSD / freebsd (15.0) (push) Skipped
Linux / pre-check (push) Failing after 3s
Linux / latest (apidoc) (push) Skipped
Linux / latest (clang, no, all) (push) Skipped
Linux / latest (clang, no, default) (push) Skipped
Linux / latest (clang, no, printf-builtin) (push) Skipped
Linux / latest (clang, no-dbg) (push) Skipped
Linux / latest (clang, no-testable-ke) (push) Skipped
Linux / latest (clang, yes, all) (push) Skipped
Linux / latest (clang, yes, default) (push) Skipped
Linux / latest (clang, yes, fuzzing) (push) Skipped
Linux / latest (coverage) (push) Skipped
Linux / latest (dist) (push) Skipped
Linux / latest (gcc, no, all) (push) Skipped
Linux / latest (gcc, no, default) (push) Skipped
Linux / latest (gcc, no, printf-builtin) (push) Skipped
Linux / latest (gcc, yes, all) (push) Skipped
Linux / latest (gcc, yes, default) (push) Skipped
Linux / latest (nm) (push) Skipped
Linux / latest (no-dbg) (push) Skipped
Linux / latest (no-testable-ke) (push) Skipped
Linux / latest (yes, ld) (push) Skipped
Linux / crypto (ubuntu-22.04, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, botan) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-3) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-4) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-awslc) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, wolfssl) (push) Skipped
Linux / older (clang, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, nm) (push) Skipped
Linux / alpine (push) Skipped
macOS / pre-check (push) Failing after 5s
macOS / macos (macos-14) (push) Skipped
macOS / macos (macos-latest) (push) Skipped
SonarCloud / pre-check (push) Canceled after 3s
SonarCloud / sonarcloud (push) Canceled after 0s
TKM / pre-check (push) Canceled after 0s
TKM / tkm (push) Canceled after 0s
Windows / pre-check (push) Canceled after 1s
Windows / cross-compile (win32) (push) Canceled after 0s
Windows / cross-compile (win64) (push) Canceled after 0s
Windows / native (i686, mingw32, win32) (push) Canceled after 0s
Windows / native (x86_64, mingw64, win64) (push) Canceled after 0s
Android / pre-check (push) Failing after 6s
Android / android (push) Skipped
CIFuzz / pre-check (push) Failing after 4s
CIFuzz / fuzzing (address) (push) Skipped
CIFuzz / fuzzing (undefined) (push) Skipped
CodeQL / pre-check (push) Failing after 3s
CodeQL / analyze (python) (push) Skipped
CodeQL / analyze (ruby) (push) Skipped
CodeQL / analyze-cpp (push) Skipped
FreeBSD / pre-check (push) Failing after 3s
FreeBSD / freebsd (14.4) (push) Skipped
FreeBSD / freebsd (15.0) (push) Skipped
Linux / pre-check (push) Failing after 3s
Linux / latest (apidoc) (push) Skipped
Linux / latest (clang, no, all) (push) Skipped
Linux / latest (clang, no, default) (push) Skipped
Linux / latest (clang, no, printf-builtin) (push) Skipped
Linux / latest (clang, no-dbg) (push) Skipped
Linux / latest (clang, no-testable-ke) (push) Skipped
Linux / latest (clang, yes, all) (push) Skipped
Linux / latest (clang, yes, default) (push) Skipped
Linux / latest (clang, yes, fuzzing) (push) Skipped
Linux / latest (coverage) (push) Skipped
Linux / latest (dist) (push) Skipped
Linux / latest (gcc, no, all) (push) Skipped
Linux / latest (gcc, no, default) (push) Skipped
Linux / latest (gcc, no, printf-builtin) (push) Skipped
Linux / latest (gcc, yes, all) (push) Skipped
Linux / latest (gcc, yes, default) (push) Skipped
Linux / latest (nm) (push) Skipped
Linux / latest (no-dbg) (push) Skipped
Linux / latest (no-testable-ke) (push) Skipped
Linux / latest (yes, ld) (push) Skipped
Linux / crypto (ubuntu-22.04, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, botan) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-3) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-4) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-awslc) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, wolfssl) (push) Skipped
Linux / older (clang, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, nm) (push) Skipped
Linux / alpine (push) Skipped
macOS / pre-check (push) Failing after 5s
macOS / macos (macos-14) (push) Skipped
macOS / macos (macos-latest) (push) Skipped
SonarCloud / pre-check (push) Canceled after 3s
SonarCloud / sonarcloud (push) Canceled after 0s
TKM / pre-check (push) Canceled after 0s
TKM / tkm (push) Canceled after 0s
Windows / pre-check (push) Canceled after 1s
Windows / cross-compile (win32) (push) Canceled after 0s
Windows / cross-compile (win64) (push) Canceled after 0s
Windows / native (i686, mingw32, win32) (push) Canceled after 0s
Windows / native (x86_64, mingw64, win64) (push) Canceled after 0s
Diag/charon logs from 2026-09-30 16:45 showed that after a Wi-Fi->cellular roam every direct-TCP connect failed asynchronously with EHOSTUNREACH for minutes, while the IKE socket worked and a Java socket explicitly bound to the underlying network connected fine: a bare VpnService.protect() left fresh sockets routed over the vanished network. - CharonVpnService.protectDirect(fd): protect + Network.bindSocket to the active non-VPN network (API 23+, best-effort, adoptFd/detachFd) - charonservice_protect_direct_socket() JNI wrapper; relay and UDP flow sockets use it at creation - direct_tcp: one retry on a fresh socket when an async connect fails; reprotect aborts still-connecting relays (RST) instead of letting the kernel take ~90s to report the dead route; failures log dst=ip:port - direct_udp: reprotect closes all flows; they re-open per packet with a fresh, network-pinned socket - TUN reader: EBADF after a reauth re-establish is no longer logged Published as 2.13.10 (versionCode 147).
This commit is contained in:
1 parent
d12fb96dc2
commit
e9bdf60f82
7 files changed
+202
-35
No files matched your search
@@ -37,8 +37,8 @@ android {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 36
|
||||
|
||||
versionCode 146
|
||||
versionName "2.13.9"
|
||||
versionCode 147
|
||||
versionName "2.13.10"
|
||||
|
||||
/* Base URL of the update storage, trailing slash included */
|
||||
buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\""
|
||||
|
||||
+60
@@ -1284,6 +1284,66 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
|
||||
return KeyChain.getPrivateKey(getApplicationContext(), mCurrentUserCertificateAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via JNI for the sockets of direct (RU-split) flows: besides the
|
||||
* regular VPN bypass this pins the socket to the currently active physical
|
||||
* network. A bare protect() leaves the network choice to the system's
|
||||
* default-network bookkeeping, which was observed to keep routing fresh
|
||||
* sockets over a network that vanished during a Wi-Fi/cellular roam
|
||||
* (async EHOSTUNREACH), while sockets explicitly bound to the underlying
|
||||
* network connected fine on the same network.
|
||||
*
|
||||
* Must be called before connect(). Best effort: on any failure the socket
|
||||
* keeps the plain protect() routing.
|
||||
*
|
||||
* @param fd socket file descriptor
|
||||
* @return TRUE if protect() itself succeeded
|
||||
*/
|
||||
public boolean protectDirect(int fd)
|
||||
{
|
||||
if (!protect(fd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
{
|
||||
android.net.Network network = null;
|
||||
try
|
||||
{
|
||||
ConnectivityManager manager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
network = manager != null ? manager.getActiveNetwork() : null;
|
||||
if (network != null)
|
||||
{
|
||||
android.net.NetworkCapabilities caps = manager.getNetworkCapabilities(network);
|
||||
if (caps == null || caps.hasTransport(android.net.NetworkCapabilities.TRANSPORT_VPN))
|
||||
{ /* while the tunnel is up our own default is the physical
|
||||
* network; fall back to the tracked set otherwise */
|
||||
android.net.Network[] tracked = mUnderlyingTracker.getNetworks();
|
||||
network = tracked != null && tracked.length > 0 ? tracked[0] : null;
|
||||
}
|
||||
}
|
||||
if (network != null)
|
||||
{
|
||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(fd);
|
||||
try
|
||||
{
|
||||
network.bindSocket(pfd.getFileDescriptor());
|
||||
}
|
||||
finally
|
||||
{
|
||||
/* release ownership without closing the fd, native code owns it */
|
||||
pfd.detachFd();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DiagLog.i(TAG, "direct socket network bind skipped: " + e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization of charon, provided by libandroidbridge.so
|
||||
*
|
||||
|
||||
@@ -188,7 +188,13 @@ static job_requeue_t handle_plain(private_android_service_t *this)
|
||||
len = read(tunfd, raw.ptr, raw.len);
|
||||
if (len < 0)
|
||||
{
|
||||
DBG1(DBG_DMN, "reading from TUN device failed: %s", strerror(errno));
|
||||
if (errno != EBADF)
|
||||
{
|
||||
DBG1(DBG_DMN, "reading from TUN device failed: %s", strerror(errno));
|
||||
}
|
||||
/* EBADF: the TUN got closed between the check above and the read
|
||||
* (e.g. a reauth re-established it) - retry, the next round sees
|
||||
* tunfd < 0 and quits */
|
||||
chunk_free(&raw);
|
||||
return JOB_REQUEUE_FAIR;
|
||||
}
|
||||
|
||||
@@ -235,9 +235,10 @@ failed:
|
||||
}
|
||||
|
||||
/**
|
||||
* Bypass a single socket
|
||||
* Bypass a single socket, optionally pinning it to the active network
|
||||
*/
|
||||
static bool bypass_single_socket(private_charonservice_t *this, int fd)
|
||||
static bool bypass_single_socket(private_charonservice_t *this, int fd,
|
||||
bool direct)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jmethodID method_id;
|
||||
@@ -245,7 +246,8 @@ static bool bypass_single_socket(private_charonservice_t *this, int fd)
|
||||
androidjni_attach_thread(&env);
|
||||
|
||||
method_id = (*env)->GetMethodID(env, android_charonvpnservice_class,
|
||||
"protect", "(I)Z");
|
||||
direct ? "protectDirect" : "protect",
|
||||
"(I)Z");
|
||||
if (!method_id)
|
||||
{
|
||||
goto failed;
|
||||
@@ -270,7 +272,7 @@ CALLBACK(bypass_single_socket_cb, void,
|
||||
private_charonservice_t *this;
|
||||
|
||||
VA_ARGS_VGET(args, this);
|
||||
bypass_single_socket(this, fd);
|
||||
bypass_single_socket(this, fd, FALSE);
|
||||
}
|
||||
|
||||
METHOD(charonservice_t, bypass_socket, bool,
|
||||
@@ -282,7 +284,7 @@ METHOD(charonservice_t, bypass_socket, bool,
|
||||
{
|
||||
this->sockets->insert_last(this->sockets, (void*)(intptr_t)fd);
|
||||
}
|
||||
return bypass_single_socket(this, fd);
|
||||
return bypass_single_socket(this, fd, FALSE);
|
||||
}
|
||||
this->sockets->invoke_function(this->sockets, bypass_single_socket_cb, this);
|
||||
return TRUE;
|
||||
@@ -303,7 +305,25 @@ bool charonservice_protect_socket(int fd)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return bypass_single_socket(this, fd);
|
||||
return bypass_single_socket(this, fd, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as charonservice_protect_socket(), but additionally pins the socket to
|
||||
* the currently active physical network (Java protectDirect()). Used when a
|
||||
* direct-flow socket is created: after a Wi-Fi/cellular roam a bare protect()
|
||||
* was observed to keep routing fresh sockets over the vanished network
|
||||
* (async EHOSTUNREACH), while explicitly bound sockets connected fine.
|
||||
*/
|
||||
bool charonservice_protect_direct_socket(int fd)
|
||||
{
|
||||
private_charonservice_t *this = (private_charonservice_t*)charonservice;
|
||||
|
||||
if (!this || fd < 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return bypass_single_socket(this, fd, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -173,4 +173,11 @@ extern charonservice_t *charonservice;
|
||||
*/
|
||||
bool charonservice_protect_socket(int fd);
|
||||
|
||||
/**
|
||||
* Like charonservice_protect_socket(), but additionally pins the socket to
|
||||
* the currently active physical network (Java protectDirect()); call before
|
||||
* connect(). For freshly created direct-flow sockets.
|
||||
*/
|
||||
bool charonservice_protect_direct_socket(int fd);
|
||||
|
||||
#endif /** CHARONSERVICE_H_ @}*/
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
@@ -74,6 +75,9 @@ typedef struct {
|
||||
bool connected;
|
||||
bool dead;
|
||||
bool remote_eof;
|
||||
bool retried;
|
||||
struct sockaddr_storage dest;
|
||||
socklen_t dest_len;
|
||||
uint8_t *to_sock;
|
||||
size_t to_sock_len, to_sock_cap;
|
||||
uint8_t *to_pcb;
|
||||
@@ -265,6 +269,53 @@ static void relay_flush_to_sock(tcp_relay_t *relay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "ip:port" of a relay destination for log lines
|
||||
*/
|
||||
static void format_dest(const struct sockaddr_storage *ss, char *buf, size_t len)
|
||||
{
|
||||
char host[INET6_ADDRSTRLEN];
|
||||
in_port_t port = 0;
|
||||
|
||||
if (ss->ss_family == AF_INET6)
|
||||
{
|
||||
inet_ntop(AF_INET6, &((struct sockaddr_in6*)ss)->sin6_addr, host, sizeof(host));
|
||||
port = ((struct sockaddr_in6*)ss)->sin6_port;
|
||||
}
|
||||
else
|
||||
{
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in*)ss)->sin_addr, host, sizeof(host));
|
||||
port = ((struct sockaddr_in*)ss)->sin_port;
|
||||
}
|
||||
snprintf(buf, len, "%s:%u", host, ntohs(port));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a protected, network-pinned non-blocking socket and start connecting
|
||||
* it to the given destination. Returns -1 on failure.
|
||||
*/
|
||||
static int relay_connect_socket(const struct sockaddr_storage *ss, socklen_t len)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = socket(ss->ss_family, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
|
||||
if (fd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!charonservice_protect_direct_socket(fd))
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (connect(fd, (struct sockaddr*)ss, len) < 0 && errno != EINPROGRESS)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* lwIP accept callback: a connection arrived for some destination
|
||||
*/
|
||||
@@ -275,6 +326,8 @@ static lwip_err_t on_accept(void *arg, struct tcp_pcb *newpcb, lwip_err_t err)
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in*)&ss;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&ss;
|
||||
socklen_t ss_len;
|
||||
char dest[INET6_ADDRSTRLEN + 8];
|
||||
int fd;
|
||||
|
||||
DIRECT_STATS_ADD(this->stats->tcp_accepts, 1);
|
||||
@@ -285,35 +338,23 @@ static lwip_err_t on_accept(void *arg, struct tcp_pcb *newpcb, lwip_err_t err)
|
||||
sin6->sin6_family = AF_INET6;
|
||||
memcpy(&sin6->sin6_addr, &ip_2_ip6(&newpcb->local_ip)->addr, 16);
|
||||
sin6->sin6_port = htons(newpcb->local_port);
|
||||
ss_len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else
|
||||
{
|
||||
sin->sin_family = AF_INET;
|
||||
memcpy(&sin->sin_addr, &ip_2_ip4(&newpcb->local_ip)->addr, 4);
|
||||
sin->sin_port = htons(newpcb->local_port);
|
||||
ss_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
format_dest(&ss, dest, sizeof(dest));
|
||||
|
||||
fd = socket(ss.ss_family, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
|
||||
fd = relay_connect_socket(&ss, ss_len);
|
||||
if (fd < 0)
|
||||
{
|
||||
DIRECT_STATS_ADD(this->stats->relay_errors, 1);
|
||||
DBG1(DBG_NET, "direct tcp: accept socket failed: %s", strerror(errno));
|
||||
tcp_abort(newpcb);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
if (!charonservice_protect_socket(fd))
|
||||
{
|
||||
DIRECT_STATS_ADD(this->stats->relay_errors, 1);
|
||||
DBG1(DBG_NET, "direct tcp: accept protect failed fd=%d", fd);
|
||||
close(fd);
|
||||
tcp_abort(newpcb);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
if (connect(fd, (struct sockaddr*)&ss, sizeof(ss)) < 0 && errno != EINPROGRESS)
|
||||
{
|
||||
DIRECT_STATS_ADD(this->stats->relay_errors, 1);
|
||||
DBG1(DBG_NET, "direct tcp: accept connect failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
DBG1(DBG_NET, "direct tcp: accept socket setup failed dst=%s: %s",
|
||||
dest, strerror(errno));
|
||||
tcp_abort(newpcb);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
@@ -322,7 +363,9 @@ static lwip_err_t on_accept(void *arg, struct tcp_pcb *newpcb, lwip_err_t err)
|
||||
.m = this,
|
||||
.pcb = newpcb,
|
||||
.fd = fd,
|
||||
.dest_len = ss_len,
|
||||
);
|
||||
memcpy(&relay->dest, &ss, ss_len);
|
||||
/* keep our own segments within the TUN MTU regardless of TCP_MSS */
|
||||
if (newpcb->mss > this->mtu - 72)
|
||||
{
|
||||
@@ -581,6 +624,15 @@ METHOD(direct_tcp_t, reprotect, void,
|
||||
enumerator = this->relays->create_enumerator(this->relays);
|
||||
while (enumerator->enumerate(enumerator, &relay))
|
||||
{
|
||||
if (!relay->connected)
|
||||
{ /* SYN still in flight on the old network - it can no longer
|
||||
* complete (the source/network it started on is gone, and the
|
||||
* kernel may take over a minute to report EHOSTUNREACH). Abort
|
||||
* now so the client re-SYNs at once and gets a fresh socket,
|
||||
* pinned to the new active network. */
|
||||
relay->dead = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (relay->fd >= 0 && !charonservice_protect_socket(relay->fd))
|
||||
{
|
||||
DBG1(DBG_NET, "direct tcp: re-protect failed fd=%d", relay->fd);
|
||||
@@ -641,6 +693,7 @@ METHOD(direct_tcp_t, process_poll, void,
|
||||
{
|
||||
int err = 0;
|
||||
socklen_t len = sizeof(err);
|
||||
char dest[INET6_ADDRSTRLEN + 8];
|
||||
|
||||
getsockopt(relay->fd, SOL_SOCKET, SO_ERROR, &err, &len);
|
||||
if (err == 0)
|
||||
@@ -649,8 +702,29 @@ METHOD(direct_tcp_t, process_poll, void,
|
||||
}
|
||||
else
|
||||
{
|
||||
format_dest(&relay->dest, dest, sizeof(dest));
|
||||
if (!relay->retried)
|
||||
{ /* one retry on a fresh socket: the first attempt may have
|
||||
* been pinned to a network that vanished mid-roam (its
|
||||
* EHOSTUNREACH can take over a minute to surface, leaving
|
||||
* the connection hanging) */
|
||||
int nfd;
|
||||
|
||||
DBG1(DBG_NET, "direct tcp: connect failed dst=%s: %s, retrying on a fresh socket",
|
||||
dest, strerror(err));
|
||||
relay->retried = TRUE;
|
||||
close(relay->fd);
|
||||
nfd = relay_connect_socket(&relay->dest, relay->dest_len);
|
||||
if (nfd >= 0)
|
||||
{
|
||||
relay->fd = nfd;
|
||||
continue;
|
||||
}
|
||||
err = errno;
|
||||
}
|
||||
DIRECT_STATS_ADD(this->stats->relay_errors, 1);
|
||||
DBG1(DBG_NET, "direct tcp: connect failed async: %s", strerror(err));
|
||||
DBG1(DBG_NET, "direct tcp: connect failed dst=%s: %s",
|
||||
dest, strerror(err));
|
||||
this->relays->remove_at(this->relays, enumerator);
|
||||
relay_destroy(this, relay, TRUE);
|
||||
continue;
|
||||
|
||||
@@ -90,7 +90,7 @@ static void flow_close(private_direct_udp_t *this, int slot)
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a protected datagram socket connected to the remote end
|
||||
* Open a protected, network-pinned datagram socket connected to the remote
|
||||
*/
|
||||
static int open_flow_socket(host_t *remote)
|
||||
{
|
||||
@@ -102,7 +102,7 @@ static int open_flow_socket(host_t *remote)
|
||||
DBG1(DBG_NET, "direct udp: socket failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (!charonservice_protect_socket(fd))
|
||||
if (!charonservice_protect_direct_socket(fd))
|
||||
{
|
||||
DBG1(DBG_NET, "direct udp: protecting socket failed");
|
||||
close(fd);
|
||||
@@ -291,13 +291,13 @@ METHOD(direct_udp_t, reprotect, void,
|
||||
{
|
||||
int slot;
|
||||
|
||||
/* A connected datagram socket cannot be moved to another network; on a
|
||||
* roam these flows are dead anyway. Close them all - the next packet of
|
||||
* each flow re-opens it with a fresh socket, pinned to the new active
|
||||
* network (see open_flow_socket). */
|
||||
for (slot = 0; slot < FLOW_SLOTS; slot++)
|
||||
{
|
||||
if (this->flows[slot].fd >= 0 &&
|
||||
!charonservice_protect_socket(this->flows[slot].fd))
|
||||
{
|
||||
DBG1(DBG_NET, "direct udp: re-protect failed on slot %d", slot);
|
||||
}
|
||||
flow_close(this, slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user