From patchwork Thu Nov 21 18:07:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "plaisthos (Code Review)" X-Patchwork-Id: 3956 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:1b0d:b0:5db:37e7:e801 with SMTP id cv13csp501441mab; Thu, 21 Nov 2024 10:08:24 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCUTowRxvaR8262oLhZt89kJJ/+NeJbQoQfllpmFDPLM4DPoM5IGpTPOP4ZFZOSzUMbeVs8tirYMfFI=@openvpn.net X-Google-Smtp-Source: AGHT+IFRY1JvEUDBLKvY56dsnC2Q+1SejY3d5zNfsrI7OEXmulqX1vbz4I/oLDQw0cWcAUKujwTO X-Received: by 2002:a05:6870:b4a3:b0:287:32f7:ef42 with SMTP id 586e51a60fabf-296d9ae3365mr8311462fac.16.1732212504303; Thu, 21 Nov 2024 10:08:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1732212504; cv=none; d=google.com; s=arc-20240605; b=lFmucoF5RzbhQCBzWP6G0ZqM0hc5y0dEBppGVHIRWM2s0HSCD15gvmpGjguF6KH600 CmCvWHU3xs9ODCUhA0jZPo9rk5qW7+R/zakVqR/i+7/+b0OqQhhXkzf04kOwMztvTFyD oEkGj5BfFfE3BPoXhuUdjDCA5kY0Vt9EU4vqbgYmRs+LT5U42gE7jCVh/2/tMZC4NiK0 ln94gFAQ/7UbmV5n97zHS49ViCxf1XuFSZuxnMBQJk06anhtlGRPGtuOsBDKxZhVxBOs 6kTRN90VwKwaPzwF199m9WUCuokbIAmg1a95kZkTDN0Fr4wyEQRTsozV6aK9ETNQhBrs dn2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:cc:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:user-agent :mime-version:message-id:references:auto-submitted:to:date:from :dkim-signature:dkim-signature:dkim-signature; bh=G02y+VfTzqiIPPOfBrzr1soM3HsotaMTjiWz2V9dJ3c=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=WIsDgJLEpdcn8erER2KbrYVaU7cQgRw5jw8SOP38Qm4+xzkUldh37T18Z+t2o8UJEb EpkWZ4WYu8lLvJlIWXyEBpD/di96uHTwKSNGGx83ZRPvVIKPF0X/GRBEDD43qdG6JAoC 7MxVkT8CbbjDKi1xk+YchJuzRRczaYYeR2hUk9ZTGLlMBOFLpeTCGLeXiHV3voij9UaJ O3NN5hJtPu6y9WgsuaYHAlkWN6BG0y0Sxw4IUH7gDCVSUHDkdEn3o8UILyEm4TIBOdvf GxfXLwLB59iAKdgMKEFm1BkgJFvs/MyuKzfXsku5p7H05hZPcn6JqxrRMgFo/roEX7mS P8ng==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=mwDTvy0K; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Co8L75C5; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=DG83zyPT; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net; dara=fail header.i=@openvpn.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 586e51a60fabf-2971d88cbe0si83264fac.229.2024.11.21.10.08.24 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Nov 2024 10:08:24 -0800 (PST) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=mwDTvy0K; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Co8L75C5; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=DG83zyPT; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net; dara=fail header.i=@openvpn.net Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1tEBbA-0006xU-1y; Thu, 21 Nov 2024 18:08:12 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1tEBb8-0006xG-ES for openvpn-devel@lists.sourceforge.net; Thu, 21 Nov 2024 18:08:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Content-Transfer-Encoding:MIME-Version :Message-ID:Reply-To:References:Subject:List-Unsubscribe:List-Id:Cc:To:Date: From:Sender:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help: List-Subscribe:List-Post:List-Owner:List-Archive; bh=JVT6klZ9Yz3jO4NR8vwjDrKGbWwQAUCCk9AfDGGRHac=; b=mwDTvy0KF5tetwI0Wob6oeIuOg +/ezXtbbqygls/FBM6bIlDCd7LbRMx3Sr/jKXoz7KnQyfvcjANuq+55kYbYG9zVkRLRhYwwq5gS4q +7LplSHtSAvcT9cdIUHybcjZ+aQLlUKehGAeic+ZR5oFZ6C/laKw13Nlaco+tLU2bh/M=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Content-Transfer-Encoding:MIME-Version:Message-ID:Reply-To: References:Subject:List-Unsubscribe:List-Id:Cc:To:Date:From:Sender:Content-ID :Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To: Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help:List-Subscribe:List-Post: List-Owner:List-Archive; bh=JVT6klZ9Yz3jO4NR8vwjDrKGbWwQAUCCk9AfDGGRHac=; b=C o8L75C55Rm3ZieXOX5uIhYaQIQOidw3BiR70f7F8bLFfxaZBXa6Y3wRVpuZd4QCGay16nHsfvQ8s/ ASAhD51p/tTPQFdF4X+Ur2es8MBWSPXrbb1eqgun5s0nqdrnYfOEdYZRxrg2RcBLt9vDMgItp1JVQ mkcDtjNfztXwdPgU=; Received: from mail-wm1-f45.google.com ([209.85.128.45]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1tEBb5-0004Sy-T9 for openvpn-devel@lists.sourceforge.net; Thu, 21 Nov 2024 18:08:11 +0000 Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4315eeb2601so14081295e9.2 for ; Thu, 21 Nov 2024 10:08:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1732212480; x=1732817280; darn=lists.sourceforge.net; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from:from:to:cc :subject:date:message-id:reply-to; bh=JVT6klZ9Yz3jO4NR8vwjDrKGbWwQAUCCk9AfDGGRHac=; b=DG83zyPTxpuwF3Md2Fp7Uzn/Kp+l1Ya7t38bho1ckigcw6Hb8lWQhlFt5iHeVPM5ky JSmwI0xwjkpznFY4DZaR0+XhBRIpN1V7RveKGH1+dUco3sjR5h51PzMVtWz3nUILP+Cn Ge5Id1k74jBtH963bGAyA3HF2J8SlDwJ1jBevO9wuqocJJJtW3P54O5OOelxad2REmrK Punjg384umtvVGHh+rX+RPeOze/oEy2gVBZXyYc4JaoEYCEF2WX2s+vnizMJml85VUkx oEt3IZmyCBg7sfTLcFwAYWm+xVh7wGmYiGwVhfiuLNyiYdd0+CPH+djBO9pDcadsUL5Z 2ttw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732212480; x=1732817280; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JVT6klZ9Yz3jO4NR8vwjDrKGbWwQAUCCk9AfDGGRHac=; b=ovh/ZHmU9saY8YPf8ON4P/da3zOShXcnBtdBI3iyn730PNSsH8FJSg1fvEqHMjex/q iJzMlw+G66d2sTDpptD8uGThd2zrttmBNQTWt3RRi4fgakQ+A4a781kIA8YE4WqTEfjf mTMZEHe+WfhJ1aEVTFEyTEPm32VGK3amd3kXCPJtywiSdBcdtga2vChvm3V7EJmGMVZt /MTrsUWAeR2pFM5z9Ei309sVq9eXyi4Cm/dbfLjrmwOKjUiJc4qsezyzrRlnTZe+eocG slkDIpjgqweeiAdPZvc601UWkz7IAjf3E4bT3aP/wc8tPdVuWnFprnPs3s7uZHn71Ie+ 6bxQ== X-Gm-Message-State: AOJu0YzTJ8M7di81AA4z6m0VIA0E9SgwkvVoVrqFlQeOMjTnvvWMaoWt eEPL3qJe75Bv5mayKX6tykiXu6tpPuWLP8BqihPz+ut72udCeaWwSspPD+LWFYQ= X-Gm-Gg: ASbGncsHGwvYEVscl7yGQpIFoQFxkGgRw2sDsHCARooZzyT9fUWEEm75j1CjUAZKmXb tbvXlqfJJmGOqA0AW2piKEx0SjA/2IkYGPknXiUZL9tr1IuO3A/ixNfiBprBpkbXfnZxzE9BcXl Fv2oQy+wbf9SdYQEmjZ8/mi9zVFBaH9L9pNX+sChrInJjflFWsxk56VY1BWv22fobONNAf9j4e+ ELSxUwFQHMEuBqlvT9DkKy8wnzRw4QN31T73sFh+wl0QMAlbFOdM9jM8yumLes1BCdXaMEejhzh 6MKeXtgY0XnswNH70sd2ARilPvSyAxh+J2HiqV8IeQ== X-Received: by 2002:a05:600c:19ca:b0:426:59fe:ac27 with SMTP id 5b1f17b1804b1-4334f015603mr73593545e9.26.1732212477808; Thu, 21 Nov 2024 10:07:57 -0800 (PST) Received: from gerrit.openvpn.in (ec2-18-159-0-78.eu-central-1.compute.amazonaws.com. [18.159.0.78]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-433b464310csm63651525e9.42.2024.11.21.10.07.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Nov 2024 10:07:57 -0800 (PST) From: "stipa (Code Review)" X-Google-Original-From: "stipa (Code Review)" X-Gerrit-PatchSet: 1 Date: Thu, 21 Nov 2024 18:07:56 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: Ia267276d61fa1425ba205f54ba6eb89021f32dba X-Gerrit-Change-Number: 815 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: d6c680f030929677ba0c11f5b26c1e456662a81b References: Message-ID: MIME-Version: 1.0 User-Agent: Gerrit/3.8.2 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.128.45 listed in list.dnswl.org] 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [209.85.128.45 listed in sa-accredit.habeas.com] 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [209.85.128.45 listed in bl.score.senderscore.com] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.128.45 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 WEIRD_PORT URI: Uses non-standard port number for HTTP 0.0 HTML_MESSAGE BODY: HTML included in message -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.0 T_KAM_HTML_FONT_INVALID Test for Invalidly Named or Formatted Colors in HTML X-Headers-End: 1tEBb5-0004Sy-T9 Subject: [Openvpn-devel] [L] Change in openvpn[master]: dco-win: multipeer support X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: lstipakov@gmail.com, arne-openvpn@rfc2549.org, openvpn-devel@lists.sourceforge.net, frank@lichtenheld.com Cc: openvpn-devel Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1816356458953168695?= X-GMAIL-MSGID: =?utf-8?q?1816356458953168695?= X-getmail-filter-classifier: gerrit message type newchange Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit http://gerrit.openvpn.net/c/openvpn/+/815?usp=email to review the following change. Change subject: dco-win: multipeer support ...................................................................... dco-win: multipeer support This is the main commit for dco-win multipeer implementation. This adds concept of "mode" to DCO implementation, which is peer-to-peer or multipeer. Depends on mode, some functions use MP-specific IOCTL commands, which include peer-id as a part of input. The driver initialization accomodates server mode, in which tun device is created before transport. Since on Windows the socket is visible to the kernel only, control channel packets have to be prepended with remote sockaddr of the peer - this allows userspace to distinguish among peers. Sadly there is no reliable way to get peer local address, such as on Linux/FreeBSD, so we have to do a bit of guesswork figure out IP address based on remote IP and local routing table, which may backfire if there are multiple IPs assigned to the same network adapter. However, as for now peer-specific local IP is not used by the driver. We use instead the result of bind() to the listening address. Existing sockethandle_finalize() function has been refactored to accomodate packets with possibly prepended sockaddr. Change-Id: Ia267276d61fa1425ba205f54ba6eb89021f32dba Signed-off-by: Lev Stipakov --- M src/openvpn/dco.h M src/openvpn/dco_freebsd.c M src/openvpn/dco_linux.c M src/openvpn/dco_win.c M src/openvpn/dco_win.h M src/openvpn/forward.c M src/openvpn/init.c M src/openvpn/ovpn_dco_win.h M src/openvpn/socket.c M src/openvpn/socket.h 10 files changed, 518 insertions(+), 103 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/15/815/1 diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h index 035474f..7f2021d 100644 --- a/src/openvpn/dco.h +++ b/src/openvpn/dco.h @@ -106,9 +106,10 @@ * * @param mode the instance operating mode (P2P or multi-peer) * @param dco the context to initialize + * @param dev_node device node, used on Windows to specify certain DCO adapter * @return true on success, false otherwise */ -bool ovpn_dco_init(int mode, dco_context_t *dco); +bool ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node); /** * Open/create a DCO interface @@ -284,7 +285,7 @@ } static inline bool -ovpn_dco_init(int mode, dco_context_t *dco) +ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node) { return true; } diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c index f4c3b02..0e536de 100644 --- a/src/openvpn/dco_freebsd.c +++ b/src/openvpn/dco_freebsd.c @@ -165,7 +165,7 @@ } bool -ovpn_dco_init(int mode, dco_context_t *dco) +ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node) { if (open_fd(dco) < 0) { diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c index b038382..0a38a0e 100644 --- a/src/openvpn/dco_linux.c +++ b/src/openvpn/dco_linux.c @@ -391,7 +391,7 @@ } bool -ovpn_dco_init(int mode, dco_context_t *dco) +ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node) { switch (mode) { diff --git a/src/openvpn/dco_win.c b/src/openvpn/dco_win.c index 3bc123b..7be6fdb 100644 --- a/src/openvpn/dco_win.c +++ b/src/openvpn/dco_win.c @@ -28,6 +28,7 @@ #include "syshead.h" #include "dco.h" +#include "forward.h" #include "tun.h" #include "crypto.h" #include "ssl_common.h" @@ -42,16 +43,37 @@ #endif struct tuntap -create_dco_handle(const char *devname, struct gc_arena *gc) +create_dco_handle(const char *devname, struct gc_arena *gc, int mode) { struct tuntap tt = { .backend_driver = DRIVER_DCO }; const char *device_guid; tun_open_device(&tt, devname, &device_guid, gc); + /* for mp we set mode in ovpn_dco_init(), however for p2p it is too late */ + tt.dco.mode = (mode == MODE_SERVER) ? dco_mode_mp : dco_mode_p2p; + return tt; } +/* Sometimes IP Helper API, which we use for setting IP address etc, + * complains that interface is not found. Give it some time to settle + */ +static void +dco_wait_ready(DWORD idx) +{ + for (int i = 0; i < 20; ++i) + { + MIB_IPINTERFACE_ROW row = { .InterfaceIndex = idx, .Family = AF_INET }; + if (GetIpInterfaceEntry(&row) != ERROR_NOT_FOUND) + { + break; + } + msg(D_DCO_DEBUG, "interface %ld not yet ready, retrying", idx); + Sleep(50); + } +} + /** * Gets version of dco-win driver * @@ -104,8 +126,32 @@ } bool -ovpn_dco_init(int mode, dco_context_t *dco) +ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node) { + /* for p2p dco->mode is already set */ + dco->mode = (mode == MODE_POINT_TO_POINT) ? dco_mode_p2p : dco_mode_mp; + + if (dco->mode == dco_mode_p2p) + { + return true; + } + + /* open DCO device */ + struct gc_arena gc = gc_new(); + const char *device_guid; + tun_open_device(dco->tt, dev_node, &device_guid, &gc); + gc_free(&gc); + + /* set mp mode */ + OVPN_MODE m = OVPN_MODE_MP; + DWORD bytes_returned = 0; + if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_SET_MODE, &m, sizeof(m), NULL, 0, &bytes_returned, NULL)) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SET_MODE) failed"); + } + + dco_wait_ready(dco->tt->adapter_index); + return true; } @@ -116,19 +162,19 @@ return 0; } -static void -dco_wait_ready(DWORD idx) +void +dco_p2p_start_vpn(struct tuntap *tt) { - for (int i = 0; i < 20; ++i) + DWORD bytes_returned = 0; + if (!DeviceIoControl(tt->hand, OVPN_IOCTL_START_VPN, NULL, 0, NULL, 0, &bytes_returned, NULL)) { - MIB_IPINTERFACE_ROW row = {.InterfaceIndex = idx, .Family = AF_INET}; - if (GetIpInterfaceEntry(&row) != ERROR_NOT_FOUND) - { - break; - } - msg(D_DCO_DEBUG, "interface %ld not yet ready, retrying", idx); - Sleep(50); + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_START_VPN) failed"); } + + /* Sometimes IP Helper API, which we use for setting IP address etc, + * complains that interface is not found. Give it some time to settle + */ + dco_wait_ready(tt->adapter_index); } void @@ -141,17 +187,10 @@ */ tt->dco.tt = tt; - DWORD bytes_returned = 0; - if (!DeviceIoControl(tt->hand, OVPN_IOCTL_START_VPN, NULL, 0, NULL, 0, - &bytes_returned, NULL)) + if (tt->dco.mode == dco_mode_p2p) { - msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_START_VPN) failed"); + dco_p2p_start_vpn(tt); } - - /* Sometimes IP Helper API, which we use for setting IP address etc, - * complains that interface is not found. Give it some time to settle - */ - dco_wait_ready(tt->adapter_index); } static void @@ -207,14 +246,67 @@ } void -dco_create_socket(HANDLE handle, struct addrinfo *remoteaddr, bool bind_local, - struct addrinfo *bind, int timeout, - struct signal_info *sig_info) +dco_mp_start_vpn(HANDLE handle, struct link_socket *sock) +{ + msg(D_DCO_DEBUG, "%s", __func__); + + int ai_family = sock->info.lsa->bind_local->ai_family; + struct addrinfo *local = sock->info.lsa->bind_local; + struct addrinfo *cur = NULL; + + for (cur = local; cur; cur = cur->ai_next) + { + if (cur->ai_family == ai_family) + { + break; + } + } + if (!cur) + { + msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", + __func__, addr_family_name(ai_family)); + } + + OVPN_MP_START_VPN in, out; + in.IPv6Only = sock->info.bind_ipv6_only ? 1 : 0; + if (ai_family == AF_INET) + { + memcpy(&in.ListenAddress.Addr4, cur->ai_addr, sizeof(struct sockaddr_in)); + } + else + { + memcpy(&in.ListenAddress.Addr6, cur->ai_addr, sizeof(struct sockaddr_in6)); + } + + /* in multipeer mode control channel packets are prepended with remote peer's sockaddr */ + sock->sockflags |= SF_PREPEND_SA; + + DWORD bytes_returned = 0; + if (!DeviceIoControl(handle, OVPN_IOCTL_MP_START_VPN, &in, sizeof(in), &out, sizeof(out), + &bytes_returned, NULL)) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_MP_START_VPN) failed"); + } + + if (out.ListenAddress.Addr4.sin_family == AF_INET) + { + memcpy(&sock->info.lsa->actual.dest.addr.in4, &out.ListenAddress.Addr4, sizeof(struct sockaddr_in)); + } + else + { + memcpy(&sock->info.lsa->actual.dest.addr.in6, &out.ListenAddress.Addr6, sizeof(struct sockaddr_in6)); + } +} + +void +dco_p2p_new_peer(HANDLE handle, struct link_socket *sock, struct signal_info *sig_info) { msg(D_DCO_DEBUG, "%s", __func__); OVPN_NEW_PEER peer = { 0 }; + struct addrinfo *remoteaddr = sock->info.lsa->current_remote; + struct sockaddr *local = NULL; struct sockaddr *remote = remoteaddr->ai_addr; @@ -228,9 +320,10 @@ peer.Proto = OVPN_PROTO_UDP; } - if (bind_local) + if (sock->bind_local) { /* Use first local address with correct address family */ + struct addrinfo *bind = sock->info.lsa->bind_local; while (bind && !local) { if (bind->ai_family == remote->sa_family) @@ -241,7 +334,7 @@ } } - if (bind_local && !local) + if (sock->bind_local && !local) { msg(M_FATAL, "DCO: Socket bind failed: Address to bind lacks %s record", addr_family_name(remote->sa_family)); @@ -290,17 +383,131 @@ } else { - dco_connect_wait(handle, &ov, timeout, sig_info); + dco_connect_wait(handle, &ov, get_server_poll_remaining_time(sock->server_poll_timeout), sig_info); } } } +static struct sockaddr * +dco_get_source_ip_for_dst(const struct sockaddr *dst) +{ + SOCKADDR_INET dst_in = { 0 }; + + /* Cast the destination address to SOCKADDR_INET */ + if (dst->sa_family == AF_INET) + { + dst_in.Ipv4 = *((struct sockaddr_in *)dst); + dst_in.si_family = AF_INET; + } + else if (dst->sa_family == AF_INET6) + { + dst_in.Ipv6 = *((struct sockaddr_in6 *)dst); + dst_in.si_family = AF_INET6; + } + else + { + msg(M_FATAL, "%s: unknown dst address family %d", __func__, dst->sa_family); + } + + /* Get the best source address */ + MIB_IPFORWARD_ROW2 row; + SOCKADDR_INET best_src = { 0 }; + DWORD ret = GetBestRoute2(NULL, 0, NULL, &dst_in, 0, &row, &best_src); + if (ret != NO_ERROR) + { + msg(M_WARN, "%s: GetBestRoute2() failed with error: %ld\n", __func__, ret); + return NULL; + } + + /* Allocate and copy the best source address to return as sockaddr */ + struct sockaddr *src = NULL; + if (best_src.si_family == AF_INET6) + { + struct sockaddr_in6 *src_in6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); + if (src_in6 == NULL) + { + msg(M_FATAL, "%s: malloc failed", __func__); + } + *src_in6 = best_src.Ipv6; + src = (struct sockaddr *)src_in6; + } + else if (best_src.si_family == AF_INET) + { + struct sockaddr_in *src_in = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); + if (src_in == NULL) + { + msg(M_FATAL, "%s: malloc failed", __func__); + } + *src_in = best_src.Ipv4; + src = (struct sockaddr *)src_in; + } + else + { + msg(M_FATAL, "%s: unknown src family %d", __func__, best_src.si_family); + } + + return src; +} + int dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, struct sockaddr *localaddr, struct sockaddr *remoteaddr, struct in_addr *vpn_ipv4, struct in6_addr *vpn_ipv6) { msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd); + + if (dco->mode == dco_mode_p2p) + { + /* no-op for p2p */ + return 0; + } + + OVPN_MP_NEW_PEER newPeer = {0}; + + if (remoteaddr) + { + struct sockaddr *local = dco_get_source_ip_for_dst(remoteaddr); + if (local) + { + if (local->sa_family == AF_INET) + { + memcpy(&newPeer.Local.Addr4, local, sizeof(struct sockaddr_in)); + } + else + { + memcpy(&newPeer.Local.Addr6, local, sizeof(struct sockaddr_in6)); + } + free(local); + } + + if (remoteaddr->sa_family == AF_INET) + { + memcpy(&newPeer.Remote.Addr4, remoteaddr, sizeof(struct sockaddr_in)); + } + else + { + memcpy(&newPeer.Remote.Addr6, remoteaddr, sizeof(struct sockaddr_in6)); + } + } + + if (vpn_ipv4) + { + newPeer.VpnAddr4 = *vpn_ipv4; + } + + if (vpn_ipv6) + { + newPeer.VpnAddr6 = *vpn_ipv6; + } + + newPeer.PeerId = peerid; + + DWORD bytesReturned; + if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_NEW_PEER, &newPeer, sizeof(newPeer), NULL, 0, &bytesReturned, NULL)) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_MP_NEW_PEER) failed"); + } + return 0; } @@ -309,9 +516,20 @@ { msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid); + OVPN_MP_DEL_PEER del_peer = { peerid }; + VOID *buf = NULL; + DWORD len = 0; + DWORD ioctl = OVPN_IOCTL_DEL_PEER; + + if (dco->mode == dco_mode_mp) + { + ioctl = OVPN_IOCTL_MP_DEL_PEER; + buf = &del_peer; + len = sizeof(del_peer); + } + DWORD bytes_returned = 0; - if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_DEL_PEER, NULL, - 0, NULL, 0, &bytes_returned, NULL)) + if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL)) { msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_DEL_PEER) failed"); return -1; @@ -326,19 +544,30 @@ msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__, peerid, keepalive_interval, keepalive_timeout, mss); - OVPN_SET_PEER peer; + OVPN_MP_SET_PEER mp_peer = { peerid, keepalive_interval, keepalive_timeout, mss }; + OVPN_SET_PEER peer = { keepalive_interval, keepalive_timeout, mss }; + VOID *buf = NULL; + DWORD len = 0; + DWORD ioctl = (dco->mode == dco_mode_mp) ? OVPN_IOCTL_MP_SET_PEER : OVPN_IOCTL_SET_PEER; - peer.KeepaliveInterval = keepalive_interval; - peer.KeepaliveTimeout = keepalive_timeout; - peer.MSS = mss; + if (dco->mode == dco_mode_mp) + { + buf = &mp_peer; + len = sizeof(OVPN_MP_SET_PEER); + } + else + { + buf = &peer; + len = sizeof(OVPN_SET_PEER); + } DWORD bytes_returned = 0; - if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_SET_PEER, &peer, - sizeof(peer), NULL, 0, &bytes_returned, NULL)) + if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL)) { - msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_SET_PEER) failed"); + msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_SET_PEER) failed"); return -1; } + return 0; } @@ -397,9 +626,20 @@ { msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id); + OVPN_MP_SWAP_KEYS swap = {peer_id}; + DWORD ioctl = OVPN_IOCTL_SWAP_KEYS; + VOID *buf = NULL; + DWORD len = 0; + + if (dco->mode == dco_mode_mp) + { + ioctl = OVPN_IOCTL_MP_SWAP_KEYS; + buf = &swap; + len = sizeof(swap); + } + DWORD bytes_returned = 0; - if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_SWAP_KEYS, NULL, 0, NULL, 0, - &bytes_returned, NULL)) + if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL)) { msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SWAP_KEYS) failed"); return -1; diff --git a/src/openvpn/dco_win.h b/src/openvpn/dco_win.h index a28436c..3e1c2f3 100644 --- a/src/openvpn/dco_win.h +++ b/src/openvpn/dco_win.h @@ -31,19 +31,28 @@ typedef OVPN_KEY_SLOT dco_key_slot_t; typedef OVPN_CIPHER_ALG dco_cipher_t; +typedef enum { + dco_mode_uninit, + dco_mode_p2p, + dco_mode_mp +} dco_mode_type; + struct dco_context { struct tuntap *tt; + dco_mode_type mode; + }; typedef struct dco_context dco_context_t; struct tuntap -create_dco_handle(const char *devname, struct gc_arena *gc); +create_dco_handle(const char *devname, struct gc_arena *gc, int mode); void -dco_create_socket(HANDLE handle, struct addrinfo *remoteaddr, bool bind_local, - struct addrinfo *bind, int timeout, - struct signal_info *sig_info); +dco_mp_start_vpn(HANDLE handle, struct link_socket *sock); + +void +dco_p2p_new_peer(HANDLE handle, struct link_socket *sock, struct signal_info *sig_info); void dco_start_tun(struct tuntap *tt); diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index d50b24c..0a3936a 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1315,7 +1315,8 @@ } else { - sockethandle_t sh = { .is_handle = true, .h = c->c1.tuntap->hand }; + bool prepend_sa = c->options.mode == MODE_SERVER && dco_enabled(&c->options); + sockethandle_t sh = { .is_handle = true, .h = c->c1.tuntap->hand, .prepend_sa = prepend_sa }; sockethandle_finalize(sh, &c->c1.tuntap->reads, &c->c2.buf, NULL); } #else /* ifdef _WIN32 */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 656fedf..b02e4f1 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1987,7 +1987,7 @@ #endif if (dco_enabled(&c->options)) { - ovpn_dco_init(c->mode, &c->c1.tuntap->dco); + ovpn_dco_init(c->mode, &c->c1.tuntap->dco, c->options.dev_node); } /* open the tun device */ diff --git a/src/openvpn/ovpn_dco_win.h b/src/openvpn/ovpn_dco_win.h index ea2a733..8003ace 100644 --- a/src/openvpn/ovpn_dco_win.h +++ b/src/openvpn/ovpn_dco_win.h @@ -47,6 +47,23 @@ OVPN_PROTO Proto; } OVPN_NEW_PEER, * POVPN_NEW_PEER; +typedef struct _OVPN_MP_NEW_PEER { + union { + SOCKADDR_IN Addr4; + SOCKADDR_IN6 Addr6; + } Local; + + union { + SOCKADDR_IN Addr4; + SOCKADDR_IN6 Addr6; + } Remote; + + IN_ADDR VpnAddr4; + IN6_ADDR VpnAddr6; + + int PeerId; +} OVPN_MP_NEW_PEER, * POVPN_MP_NEW_PEER; + typedef struct _OVPN_STATS { LONG LostInControlPackets; LONG LostOutControlPackets; @@ -94,10 +111,25 @@ int PeerId; } OVPN_CRYPTO_DATA, * POVPN_CRYPTO_DATA; +#define CRYPTO_OPTIONS_AEAD_TAG_END (1<<1) +#define CRYPTO_OPTIONS_64BIT_PKTID (1<<2) + +typedef struct _OVPN_CRYPTO_DATA_V2 { + OVPN_CRYPTO_DATA V1; + UINT32 CryptoOptions; +} OVPN_CRYPTO_DATA_V2, * POVPN_CRYPTO_DATA_V2; + +typedef struct _OVPN_MP_SET_PEER { + int PeerId; + LONG KeepaliveInterval; + LONG KeepaliveTimeout; + LONG MSS; +} OVPN_MP_SET_PEER, * POVPN_MP_SET_PEER; + typedef struct _OVPN_SET_PEER { - LONG KeepaliveInterval; - LONG KeepaliveTimeout; - LONG MSS; + LONG KeepaliveInterval; + LONG KeepaliveTimeout; + LONG MSS; } OVPN_SET_PEER, * POVPN_SET_PEER; typedef struct _OVPN_VERSION { @@ -106,6 +138,50 @@ LONG Patch; } OVPN_VERSION, * POVPN_VERSION; +typedef enum { + OVPN_MODE_P2P, + OVPN_MODE_MP +} OVPN_MODE; + +typedef struct _OVPN_SET_MODE { + OVPN_MODE Mode; +} OVPN_SET_MODE, * POVPN_SET_MODE; + +typedef struct _OVPN_MP_START_VPN { + union { + SOCKADDR_IN Addr4; + SOCKADDR_IN6 Addr6; + } ListenAddress; + int IPv6Only; +} OVPN_MP_START_VPN, * POVPN_MP_START_VPN; + +typedef enum { + OVPN_CMD_DEL_PEER, + OVPN_CMD_SWAP_KEYS +} OVPN_NOTIFY_CMD; + +typedef enum { + OVPN_DEL_PEER_REASON_TEARDOWN, + OVPN_DEL_PEER_REASON_USERSPACE, + OVPN_DEL_PEER_REASON_EXPIRED, + OVPN_DEL_PEER_REASON_TRANSPORT_ERROR, + OVPN_DEL_PEER_REASON_TRANSPORT_DISCONNECT +} OVPN_DEL_PEER_REASON; + +typedef struct _OVPN_NOTIFY_EVENT { + OVPN_NOTIFY_CMD Cmd; + int PeerId; + OVPN_DEL_PEER_REASON DelPeerReason; +} OVPN_NOTIFY_EVENT, * POVPN_NOTIFY_EVENT; + +typedef struct _OVPN_MP_DEL_PEER { + int PeerId; +} OVPN_MP_DEL_PEER, * POVPN_MP_DEL_PEER; + +typedef struct _OVPN_MP_SWAP_KEYS { + int PeerId; +} OVPN_MP_SWAP_KEYS, * POVPN_MP_SWAP_KEYS; + #define OVPN_IOCTL_NEW_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) #define OVPN_IOCTL_GET_STATS CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) #define OVPN_IOCTL_NEW_KEY CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS) @@ -114,3 +190,14 @@ #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) #define OVPN_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define OVPN_IOCTL_NEW_KEY_V2 CTL_CODE(FILE_DEVICE_UNKNOWN, 9, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define OVPN_IOCTL_SET_MODE CTL_CODE(FILE_DEVICE_UNKNOWN, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define OVPN_IOCTL_MP_START_VPN CTL_CODE(FILE_DEVICE_UNKNOWN, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define OVPN_IOCTL_MP_NEW_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define OVPN_IOCTL_MP_SET_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 13, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define OVPN_IOCTL_NOTIFY_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, 14, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define OVPN_IOCTL_MP_DEL_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define OVPN_IOCTL_MP_SWAP_KEYS CTL_CODE(FILE_DEVICE_UNKNOWN, 16, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index efd742c..6909e7a 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2144,7 +2144,7 @@ struct tuntap *tt; ALLOC_OBJ(tt, struct tuntap); - *tt = create_dco_handle(c->options.dev_node, &c->gc); + *tt = create_dco_handle(c->options.dev_node, &c->gc, c->options.mode); /* Ensure we can "safely" cast the handle to a socket */ static_assert(sizeof(sock->sd) == sizeof(tt->hand), "HANDLE and SOCKET size differs"); @@ -2152,12 +2152,14 @@ 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), - sig_info); - + if (c->options.mode == MODE_SERVER) + { + dco_mp_start_vpn(c->c1.tuntap->hand, sock); + } + else + { + dco_p2p_new_peer(c->c1.tuntap->hand, sock, sig_info); + } sock->sockflags |= SF_DCO_WIN; if (sig_info->signal_received) @@ -2207,16 +2209,16 @@ resolve_remote(sock, 2, &remote_dynamic, sig_info); /* If a valid remote has been found, create the socket with its addrinfo */ - if (sock->info.lsa->current_remote) - { #if defined(_WIN32) - if (dco_enabled(&c->options)) - { - create_socket_dco_win(c, sock, sig_info); - goto done; - } - else + if (dco_enabled(&c->options)) + { + create_socket_dco_win(c, sock, sig_info); + goto done; + } + else #endif + { + if (sock->info.lsa->current_remote) { create_socket(sock, sock->info.lsa->current_remote); } @@ -3753,6 +3755,91 @@ return sock->writes.iostate; } +void +read_sockaddr_from_overlapped(struct overlapped_io *io, struct sockaddr *dst, int overlapped_ret) +{ + if (overlapped_ret >= 0 && io->addr_defined) + { + /* TODO(jjo): streamline this mess */ + /* in this func we don't have relevant info about the PF_ of this + * endpoint, as link_socket_actual will be zero for the 1st received packet + * + * Test for inets PF_ possible sizes + */ + switch (io->addrlen) + { + case sizeof(struct sockaddr_in): + case sizeof(struct sockaddr_in6): + /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 + * under _WIN32*/ + case sizeof(struct sockaddr_in6) - 4: + break; + + default: + bad_address_length(io->addrlen, af_addr_size(io->addr.sin_family)); + } + + switch (io->addr.sin_family) + { + case AF_INET: + memcpy(dst, &io->addr, sizeof(struct sockaddr_in)); + break; + + case AF_INET6: + memcpy(dst, &io->addr, sizeof(struct sockaddr_in)); + break; + } + } + else + { + CLEAR(*dst); + } +} + +/** + * @brief Extracts a sockaddr from a packet payload. + * + * Reads a sockaddr structure from the start of the packet buffer and writes it to `dst`. + * + * @param[in] buf Packet buffer containing the payload. + * @param[out] dst Destination buffer for the extracted sockaddr. + * @return Length of the extracted sockaddr + */ +static int +read_sockaddr_from_packet(struct buffer *buf, struct sockaddr *dst) +{ + int sa_len = 0; + + const struct sockaddr *sa = (const struct sockaddr *)BPTR(buf); + switch (sa->sa_family) + { + case AF_INET: + if (buf_len(buf) < sizeof(struct sockaddr_in)) + { + msg(M_FATAL, "ERROR: received incoming packet with too short length of %d -- must be at least %zu.", buf_len(buf), sizeof(struct sockaddr_in)); + } + memcpy(dst, sa, sizeof(struct sockaddr_in)); + buf_advance(buf, sizeof(struct sockaddr_in)); + sa_len = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + if (buf_len(buf) < sizeof(struct sockaddr_in6)) + { + msg(M_FATAL, "ERROR: received incoming packet with too short length of %d -- must be at least %zu.", buf_len(buf), sizeof(struct sockaddr_in6)); + } + memcpy(dst, sa, sizeof(struct sockaddr_in6)); + buf_advance(buf, sizeof(struct sockaddr_in6)); + sa_len = sizeof(struct sockaddr_in6); + break; + + default: + msg(M_FATAL, "ERROR: received incoming packet with invalid address family %d.", sa->sa_family); + } + + return sa_len; +} + /* Returns the number of bytes successfully read */ int sockethandle_finalize(sockethandle_t sh, @@ -3826,45 +3913,14 @@ ASSERT(0); } - /* return from address if requested */ + if (from && ret > 0 && sh.is_handle && sh.prepend_sa) + { + ret -= read_sockaddr_from_packet(buf, &from->dest.addr.sa); + } + if (!sh.is_handle && from) { - if (ret >= 0 && io->addr_defined) - { - /* TODO(jjo): streamline this mess */ - /* in this func we don't have relevant info about the PF_ of this - * endpoint, as link_socket_actual will be zero for the 1st received packet - * - * Test for inets PF_ possible sizes - */ - switch (io->addrlen) - { - case sizeof(struct sockaddr_in): - case sizeof(struct sockaddr_in6): - /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 - * under _WIN32*/ - case sizeof(struct sockaddr_in6)-4: - break; - - default: - bad_address_length(io->addrlen, af_addr_size(io->addr.sin_family)); - } - - switch (io->addr.sin_family) - { - case AF_INET: - from->dest.addr.in4 = io->addr; - break; - - case AF_INET6: - from->dest.addr.in6 = io->addr6; - break; - } - } - else - { - CLEAR(from->dest.addr); - } + read_sockaddr_from_overlapped(io, &from->dest.addr.sa, ret); } if (buf) diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 465d92b..36c683c 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -224,6 +224,7 @@ #define SF_HOST_RANDOMIZE (1<<3) #define SF_GETADDRINFO_DGRAM (1<<4) #define SF_DCO_WIN (1<<5) +#define SF_PREPEND_SA (1<<6) unsigned int sockflags; int mark; const char *bind_dev; @@ -287,6 +288,7 @@ HANDLE h; }; bool is_handle; + bool prepend_sa; /* are incoming packets prepended with sockaddr? */ } sockethandle_t; int sockethandle_finalize(sockethandle_t sh, @@ -1042,6 +1044,7 @@ { *from = sock->info.lsa->actual; sh.is_handle = true; + sh.prepend_sa = sock->sockflags & SF_PREPEND_SA; } return sockethandle_finalize(sh, &sock->reads, buf, from); } @@ -1112,6 +1115,24 @@ err = SocketHandleGetLastError(sh); } } + + /* dco-win mp requires control packets to be prepended with sockaddr */ + if (sock->sockflags & SF_PREPEND_SA) + { + if (to->dest.addr.sa.sa_family == AF_INET) + { + struct sockaddr_in sa; + memcpy(&sa, &to->dest.addr.in4, sizeof(sa)); + buf_write_prepend(buf, &sa, sizeof(sa)); + } + else + { + struct sockaddr_in6 sa; + memcpy(&sa, &to->dest.addr.in6, sizeof(sa)); + buf_write_prepend(buf, &sa, sizeof(sa)); + } + } + socket_send_queue(sock, buf, to); if (status < 0) {