From patchwork Mon Mar 9 02:17:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Rozman X-Patchwork-Id: 1022 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net with LMTP id iBOUEU1CZl4SagAAIUCqbw for ; Mon, 09 Mar 2020 09:19:09 -0400 Received: from proxy19.mail.ord1d.rsapps.net ([172.30.191.6]) by director8.mail.ord1d.rsapps.net with LMTP id sKRYEU1CZl7dagAAfY0hYg ; Mon, 09 Mar 2020 09:19:09 -0400 Received: from smtp33.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy19.mail.ord1d.rsapps.net with LMTP id CDsGEU1CZl4JRAAAyH2SIw ; Mon, 09 Mar 2020 09:19:09 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp33.gate.ord1d.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=rozman.si; dmarc=fail (p=none; dis=none) header.from=rozman.si X-Suspicious-Flag: YES X-Classification-ID: 8e8741e8-6208-11ea-aefc-525400041ef2-1-1 Received: from [216.105.38.7] ([216.105.38.7:46048] helo=lists.sourceforge.net) by smtp33.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id BE/CB-22814-C42466E5; Mon, 09 Mar 2020 09:19:08 -0400 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.90_1) (envelope-from ) id 1jBIIS-0005tk-O8; Mon, 09 Mar 2020 13:18:16 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jBIIP-0005ss-0m for openvpn-devel@lists.sourceforge.net; Mon, 09 Mar 2020 13:18:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=sUByytGJzo4iZtTa6NCteCaGpg+TQgWLJ2QZ+2fxSP4=; b=i6ipSaitYd4uPr4hCLlmBCx0My QlLOtzimRk3DgrmOyXiEKUjoFBYU7LCz9ljPLO1fbSgcjhIGfsGCEYjDLZPNs8/rW2KOvP8uF0EVx k6N0p3O2D5BY6fO0IragXZT+4i8BUJSLqWRUk+FSOk5hAxQVhsJ3xCjPfJiTUKQgTFAk=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=sUByytGJzo4iZtTa6NCteCaGpg+TQgWLJ2QZ+2fxSP4=; b=O9EL49mJHaPUXTXlCMEe2JbLQS 6wr8rTO/6xR7Uc3CtgAScRZyUEx17sYi8ENFOJ0veLhWmMLpTyze9NZSqv4i8TDIrYo1OGIfOqf5x 8YYy4lhJ2s+mB+E6G9SE+JMxBgyeb+z3hSU3G5WIlZKZmrd0lj5iZoD6gu2S1rOBCR1k=; Received: from pub5.amebis.si ([213.250.55.21]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1jBIIL-0033P4-05 for openvpn-devel@lists.sourceforge.net; Mon, 09 Mar 2020 13:18:12 +0000 Received: by pub5.amebis.si (Postfix, from userid 1000) id 3F5AD1002F94; Mon, 9 Mar 2020 14:17:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rozman.si; s=default; t=1583759875; bh=sUByytGJzo4iZtTa6NCteCaGpg+TQgWLJ2QZ+2fxSP4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aT1zJFNnyuwD4j/UNT4DuTaYp3Yj1nPpnaVi54yhXs+2YszsZVrquj3XyS69lVzeV Zl7W5/ftyELWqMQtlkbYKua+cRDerUacyv3O0iYxlYuUD405f/Zo8DSI9T0ezFgIM/ FNG14EC6Z+W8odvlQYTMrRAaSZUL0rsJ0lZ4ncGg= X-Spam-Checker-Version: SpamAssassin 3.4.3 (2019-12-06) on brana.amebis.doma X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00 autolearn=ham autolearn_force=no version=3.4.3 Received: from SR6.amebis.doma (unknown [IPv6:2a00:ee2:209:164:a5ae:e83c:b7b:725]) by pub5.amebis.si (Postfix) with ESMTP id 08A1D1002FB6; Mon, 9 Mar 2020 14:17:49 +0100 (CET) From: Simon Rozman To: openvpn-devel@lists.sourceforge.net Date: Mon, 9 Mar 2020 14:17:20 +0100 Message-Id: <20200309131728.380-4-simon@rozman.si> X-Mailer: git-send-email 2.24.1.windows.2 In-Reply-To: <20200309131728.380-1-simon@rozman.si> References: <20200309131728.380-1-simon@rozman.si> MIME-Version: 1.0 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1jBIIL-0033P4-05 Subject: [Openvpn-devel] [PATCH 04/12] tapctl: Add functions for enabling/disabling adapters 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: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Signed-off-by: Simon Rozman Acked-by: Lev Stipakov --- src/tapctl/tap.c | 287 ++++++++++++++++++++++++++++++++++++++++------- src/tapctl/tap.h | 28 +++++ 2 files changed, 275 insertions(+), 40 deletions(-) diff --git a/src/tapctl/tap.c b/src/tapctl/tap.c index b8249919..576f6740 100644 --- a/src/tapctl/tap.c +++ b/src/tapctl/tap.c @@ -47,6 +47,28 @@ const static TCHAR szInterfaceRegKeyPathTemplate[] = TEXT("SYSTEM\\CurrentContro #define INTERFACE_REGKEY_PATH_MAX (_countof(TEXT("SYSTEM\\CurrentControlSet\\Control\\Network\\")) - 1 + 38 + _countof(TEXT("\\")) - 1 + 38 + _countof(TEXT("\\Connection"))) +/** + * Function that performs a specific task on a device + * + * @param hDeviceInfoSet A handle to a device information set that contains a device + * information element that represents the device. + * + * @param pDeviceInfoData A pointer to an SP_DEVINFO_DATA structure that specifies the + * device information element in hDeviceInfoSet. + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +typedef DWORD (*devop_func_t)( + _In_ HDEVINFO hDeviceInfoSet, + _In_ PSP_DEVINFO_DATA pDeviceInfoData, + _Inout_ LPBOOL pbRebootRequired); + + /** * Checks device install parameters if a system reboot is required. * @@ -94,6 +116,186 @@ check_reboot( } +/** + * Deletes the device. + * + * @param hDeviceInfoSet A handle to a device information set that contains a device + * information element that represents the device. + * + * @param pDeviceInfoData A pointer to an SP_DEVINFO_DATA structure that specifies the + * device information element in hDeviceInfoSet. + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +static DWORD +delete_device( + _In_ HDEVINFO hDeviceInfoSet, + _In_ PSP_DEVINFO_DATA pDeviceInfoData, + _Inout_ LPBOOL pbRebootRequired) +{ + SP_REMOVEDEVICE_PARAMS params = + { + .ClassInstallHeader = + { + .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_REMOVE, + }, + .Scope = DI_REMOVEDEVICE_GLOBAL, + .HwProfile = 0, + }; + + /* Set class installer parameters for DIF_REMOVE. */ + if (!SetupDiSetClassInstallParams( + hDeviceInfoSet, + pDeviceInfoData, + ¶ms.ClassInstallHeader, + sizeof(SP_REMOVEDEVICE_PARAMS))) + { + DWORD dwResult = GetLastError(); + msg(M_NONFATAL | M_ERRNO, "%s: SetupDiSetClassInstallParams failed", __FUNCTION__); + return dwResult; + } + + /* Call appropriate class installer. */ + if (!SetupDiCallClassInstaller( + DIF_REMOVE, + hDeviceInfoSet, + pDeviceInfoData)) + { + DWORD dwResult = GetLastError(); + msg(M_NONFATAL | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_REMOVE) failed", __FUNCTION__); + return dwResult; + } + + /* Check if a system reboot is required. */ + check_reboot(hDeviceInfoSet, pDeviceInfoData, pbRebootRequired); + return ERROR_SUCCESS; +} + + +/** + * Changes the device state. + * + * @param hDeviceInfoSet A handle to a device information set that contains a device + * information element that represents the device. + * + * @param pDeviceInfoData A pointer to an SP_DEVINFO_DATA structure that specifies the + * device information element in hDeviceInfoSet. + * + * @param bEnable TRUE to enable the device; FALSE to disable. + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +static DWORD +change_device_state( + _In_ HDEVINFO hDeviceInfoSet, + _In_ PSP_DEVINFO_DATA pDeviceInfoData, + _In_ BOOL bEnable, + _Inout_ LPBOOL pbRebootRequired) +{ + SP_PROPCHANGE_PARAMS params = + { + .ClassInstallHeader = + { + .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE, + }, + .StateChange = bEnable ? DICS_ENABLE : DICS_DISABLE, + .Scope = DICS_FLAG_GLOBAL, + .HwProfile = 0, + }; + + /* Set class installer parameters for DIF_PROPERTYCHANGE. */ + if (!SetupDiSetClassInstallParams( + hDeviceInfoSet, + pDeviceInfoData, + ¶ms.ClassInstallHeader, + sizeof(SP_PROPCHANGE_PARAMS))) + { + DWORD dwResult = GetLastError(); + msg(M_NONFATAL | M_ERRNO, "%s: SetupDiSetClassInstallParams failed", __FUNCTION__); + return dwResult; + } + + /* Call appropriate class installer. */ + if (!SetupDiCallClassInstaller( + DIF_PROPERTYCHANGE, + hDeviceInfoSet, + pDeviceInfoData)) + { + DWORD dwResult = GetLastError(); + msg(M_NONFATAL | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_PROPERTYCHANGE) failed", __FUNCTION__); + return dwResult; + } + + /* Check if a system reboot is required. */ + check_reboot(hDeviceInfoSet, pDeviceInfoData, pbRebootRequired); + return ERROR_SUCCESS; +} + + +/** + * Enables the device. + * + * @param hDeviceInfoSet A handle to a device information set that contains a device + * information element that represents the device. + * + * @param pDeviceInfoData A pointer to an SP_DEVINFO_DATA structure that specifies the + * device information element in hDeviceInfoSet. + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +static DWORD +enable_device( + _In_ HDEVINFO hDeviceInfoSet, + _In_ PSP_DEVINFO_DATA pDeviceInfoData, + _Inout_ LPBOOL pbRebootRequired) +{ + return change_device_state(hDeviceInfoSet, pDeviceInfoData, TRUE, pbRebootRequired); +} + + +/** + * Disables the device. + * + * @param hDeviceInfoSet A handle to a device information set that contains a device + * information element that represents the device. + * + * @param pDeviceInfoData A pointer to an SP_DEVINFO_DATA structure that specifies the + * device information element in hDeviceInfoSet. + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +static DWORD +disable_device( + _In_ HDEVINFO hDeviceInfoSet, + _In_ PSP_DEVINFO_DATA pDeviceInfoData, + _Inout_ LPBOOL pbRebootRequired) +{ + return change_device_state(hDeviceInfoSet, pDeviceInfoData, FALSE, pbRebootRequired); +} + + /** * Reads string value from registry key. * @@ -754,10 +956,31 @@ cleanup_hDevInfoList: } -DWORD -tap_delete_interface( +/** + * Performs a given task on an interface. + * + * @param hwndParent A handle to the top-level window to use for any user interface that is + * related to non-device-specific actions (such as a select-device dialog + * box that uses the global class driver list). This handle is optional + * and can be NULL. If a specific top-level window is not required, set + * hwndParent to NULL. + * + * @param pguidInterface A pointer to GUID that contains network interface ID. + * + * @param funcOperation A pointer for the function to perform specific task on the interface. + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +static DWORD +execute_on_first_interface( _In_opt_ HWND hwndParent, _In_ LPCGUID pguidInterface, + _In_ devop_func_t funcOperation, _Inout_ LPBOOL pbRebootRequired) { DWORD dwResult; @@ -831,44 +1054,7 @@ tap_delete_interface( /* Compare GUIDs. */ if (memcmp(pguidInterface, &guidInterface, sizeof(GUID)) == 0) { - /* Remove the device. */ - SP_REMOVEDEVICE_PARAMS removedevice_params = - { - .ClassInstallHeader = - { - .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE, - }, - .Scope = DI_REMOVEDEVICE_GLOBAL, - .HwProfile = 0, - }; - - /* Set class installer parameters for DIF_REMOVE. */ - if (!SetupDiSetClassInstallParams( - hDevInfoList, - &devinfo_data, - &removedevice_params.ClassInstallHeader, - sizeof(SP_REMOVEDEVICE_PARAMS))) - { - dwResult = GetLastError(); - msg(M_NONFATAL, "%s: SetupDiSetClassInstallParams failed", __FUNCTION__); - goto cleanup_hDevInfoList; - } - - /* Call appropriate class installer. */ - if (!SetupDiCallClassInstaller( - DIF_REMOVE, - hDevInfoList, - &devinfo_data)) - { - dwResult = GetLastError(); - msg(M_NONFATAL, "%s: SetupDiCallClassInstaller(DIF_REMOVE) failed", __FUNCTION__); - goto cleanup_hDevInfoList; - } - - /* Check if a system reboot is required. */ - check_reboot(hDevInfoList, &devinfo_data, pbRebootRequired); - dwResult = ERROR_SUCCESS; + dwResult = funcOperation(hDevInfoList, &devinfo_data, pbRebootRequired); break; } } @@ -879,6 +1065,27 @@ cleanup_hDevInfoList: } +DWORD +tap_delete_interface( + _In_opt_ HWND hwndParent, + _In_ LPCGUID pguidInterface, + _Inout_ LPBOOL pbRebootRequired) +{ + return execute_on_first_interface(hwndParent, pguidInterface, delete_device, pbRebootRequired); +} + + +DWORD +tap_enable_interface( + _In_opt_ HWND hwndParent, + _In_ LPCGUID pguidInterface, + _In_ BOOL bEnable, + _Inout_ LPBOOL pbRebootRequired) +{ + return execute_on_first_interface(hwndParent, pguidInterface, bEnable ? enable_device : disable_device, pbRebootRequired); +} + + DWORD tap_set_interface_name( _In_ LPCGUID pguidInterface, diff --git a/src/tapctl/tap.h b/src/tapctl/tap.h index ca66e5da..4c2d73ba 100644 --- a/src/tapctl/tap.h +++ b/src/tapctl/tap.h @@ -84,6 +84,34 @@ tap_delete_interface( _Inout_ LPBOOL pbRebootRequired); +/** + * Enables or disables an interface. + * + * @param hwndParent A handle to the top-level window to use for any user interface that is + * related to non-device-specific actions (such as a select-device dialog + * box that uses the global class driver list). This handle is optional + * and can be NULL. If a specific top-level window is not required, set + * hwndParent to NULL. + * + * @param pguidInterface A pointer to GUID that contains network interface ID. + * + * @param bEnable TRUE to enable; FALSE to disable + * + * @param pbRebootRequired A pointer to a BOOL flag. If the device requires a system restart, + * this flag is set to TRUE. Otherwise, the flag is left unmodified. This + * allows the flag to be globally initialized to FALSE and reused for multiple + * interface manipulations. + * + * @return ERROR_SUCCESS on success; Win32 error code otherwise + **/ +DWORD +tap_enable_interface( + _In_opt_ HWND hwndParent, + _In_ LPCGUID pguidInterface, + _In_ BOOL bEnable, + _Inout_ LPBOOL pbRebootRequired); + + /** * Sets interface name. *