@@ -233,11 +233,6 @@ dco_check_startup_option_conflict(int msglevel, const struct options *o)
return false;
}
- if (o->persist_tun)
- {
- msg(msglevel, "--persist-tun is not supported with ovpn-dco.");
- return false;
- }
#elif defined(TARGET_LINUX)
/* if the device name is fixed, we need to check if an interface with this
* name already exists. IF it does, it must be a DCO interface, otherwise
@@ -42,7 +42,7 @@
const IN_ADDR in4addr_any = { 0 };
#endif
-static struct tuntap
+struct tuntap
create_dco_handle(const char *devname, struct gc_arena *gc)
{
struct tuntap tt = { .windows_driver = WINDOWS_DRIVER_DCO };
@@ -104,7 +104,7 @@ dco_start_tun(struct tuntap *tt)
dco_wait_ready(tt->adapter_index);
}
-static int
+static void
dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, volatile int *signal_received)
{
/* GetOverlappedResultEx is available starting from Windows 8 */
@@ -129,7 +129,7 @@ dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, volatile int *signa
if (get_overlapped_result_ex(handle, ov, &transferred, poll_interval_ms, FALSE) != 0)
{
/* TCP connection established by dco */
- return 0;
+ return;
}
DWORD err = GetLastError();
@@ -138,13 +138,13 @@ dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, volatile int *signa
/* dco reported connection error */
msg(M_NONFATAL | M_ERRNO, "dco connect error");
*signal_received = SIGUSR1;
- return -1;
+ return;
}
get_signal(signal_received);
if (*signal_received)
{
- return -1;
+ return;
}
management_sleep(0);
@@ -153,14 +153,11 @@ dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, volatile int *signa
/* we end up here when timeout occurs in userspace */
msg(M_NONFATAL, "dco connect timeout");
*signal_received = SIGUSR1;
-
- return -1;
}
-struct tuntap
-dco_create_socket(struct addrinfo *remoteaddr, bool bind_local,
- struct addrinfo *bind, const char *devname,
- struct gc_arena *gc, int timeout,
+void
+dco_create_socket(HANDLE handle, struct addrinfo *remoteaddr, bool bind_local,
+ struct addrinfo *bind, int timeout,
volatile int *signal_received)
{
msg(D_DCO_DEBUG, "%s", __func__);
@@ -232,10 +229,8 @@ dco_create_socket(struct addrinfo *remoteaddr, bool bind_local,
ASSERT(0);
}
- struct tuntap tt = create_dco_handle(devname, gc);
-
OVERLAPPED ov = { 0 };
- if (!DeviceIoControl(tt.hand, OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, NULL, &ov))
+ if (!DeviceIoControl(handle, OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, NULL, &ov))
{
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING)
@@ -244,13 +239,9 @@ dco_create_socket(struct addrinfo *remoteaddr, bool bind_local,
}
else
{
- if (dco_connect_wait(tt.hand, &ov, timeout, signal_received) < 0)
- {
- close_tun_handle(&tt);
- }
+ dco_connect_wait(handle, &ov, timeout, signal_received);
}
}
- return tt;
}
int
@@ -265,7 +256,15 @@ dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd,
int
dco_del_peer(dco_context_t *dco, unsigned int peerid)
{
- msg(D_DCO_DEBUG, "%s: peer-id %d - not implemented", __func__, peerid);
+ msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
+
+ DWORD bytes_returned = 0;
+ if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_DEL_PEER, NULL,
+ 0, NULL, 0, &bytes_returned, NULL))
+ {
+ msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_DEL_PEER) failed");
+ return -1;
+ }
return 0;
}
@@ -37,9 +37,11 @@ struct dco_context {
typedef struct dco_context dco_context_t;
struct tuntap
-dco_create_socket(struct addrinfo *remoteaddr, bool bind_local,
- struct addrinfo *bind, const char *devname,
- struct gc_arena *gc, int timeout,
+create_dco_handle(const char *devname, struct gc_arena *gc);
+
+void
+dco_create_socket(HANDLE handle, struct addrinfo *remoteaddr, bool bind_local,
+ struct addrinfo *bind, int timeout,
volatile int *signal_received);
void
@@ -2183,10 +2183,23 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found)
{
/* if so, close tun, delete routes, then reinitialize tun and add routes */
msg(M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.");
+
+ bool tt_dco_win = tuntap_is_dco_win(c->c1.tuntap);
do_close_tun(c, true);
- management_sleep(1);
- c->c2.did_open_tun = do_open_tun(c);
- update_time();
+
+ if (tt_dco_win)
+ {
+ msg(M_NONFATAL, "dco-win doesn't yet support reopening TUN device");
+ /* prevent link_socket_close() from closing handle with WinSock API */
+ c->c2.link_socket->sd = SOCKET_UNDEFINED;
+ return false;
+ }
+ else
+ {
+ management_sleep(1);
+ c->c2.did_open_tun = do_open_tun(c);
+ update_time();
+ }
}
}
@@ -106,3 +106,4 @@ typedef struct _OVPN_SET_PEER {
#define OVPN_IOCTL_SWAP_KEYS CTL_CODE(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_SET_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_START_VPN CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define OVPN_IOCTL_DEL_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
@@ -2128,23 +2128,25 @@ static void
create_socket_dco_win(struct context *c, struct link_socket *sock,
volatile int *signal_received)
{
- struct tuntap *tt;
- /* In this case persist-tun is enabled, which we don't support yet */
- ASSERT(!c->c1.tuntap);
-
- ALLOC_OBJ(tt, struct tuntap);
-
- *tt = dco_create_socket(sock->info.lsa->current_remote,
- sock->bind_local,
- sock->info.lsa->bind_local,
- c->options.dev_node,
- &c->gc,
- get_server_poll_remaining_time(sock->server_poll_timeout),
- signal_received);
-
- /* This state is used by signal handler which does teardown,
- * so it has to be set before return */
- c->c1.tuntap = tt;
+ if (!c->c1.tuntap)
+ {
+ struct tuntap *tt;
+ ALLOC_OBJ(tt, struct tuntap);
+
+ *tt = create_dco_handle(c->options.dev_node, &c->gc);
+
+ /* Ensure we can "safely" cast the handle to a socket */
+ static_assert(sizeof(sock->sd) == sizeof(tt->hand), "HANDLE and SOCKET size differs");
+
+ c->c1.tuntap = tt;
+ }
+
+ dco_create_socket(c->c1.tuntap->hand,
+ sock->info.lsa->current_remote,
+ sock->bind_local, sock->info.lsa->bind_local,
+ get_server_poll_remaining_time(sock->server_poll_timeout),
+ signal_received);
+
sock->info.dco_installed = true;
if (*signal_received)
@@ -2152,10 +2154,7 @@ create_socket_dco_win(struct context *c, struct link_socket *sock,
return;
}
- /* Ensure we can "safely" cast the handle to a socket */
- static_assert(sizeof(sock->sd) == sizeof(tt->hand), "HANDLE and SOCKET size differs");
- sock->sd = (SOCKET)tt->hand;
-
+ sock->sd = (SOCKET)c->c1.tuntap->hand;
linksock_print_addr(sock);
}
#endif /* if defined(_WIN32) */