mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-02-11 00:00:08 +08:00
183 lines
5.7 KiB
C++
183 lines
5.7 KiB
C++
// OpenVPN -- An application to securely tunnel IP networks
|
|
// over a single port, with support for SSL/TLS-based
|
|
// session authentication and key exchange,
|
|
// packet encryption, packet authentication, and
|
|
// packet compression.
|
|
//
|
|
// Copyright (C) 2012-2017 OpenVPN Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
|
// as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program in the COPYING file.
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
// proxy settings for Windows
|
|
|
|
#pragma once
|
|
|
|
#include <WinInet.h>
|
|
|
|
#include <openvpn\win\impersonate.hpp>
|
|
#include <openvpn\tun\proxy.hpp>
|
|
#include <openvpn\win\reg.hpp>
|
|
|
|
using namespace openvpn::Win;
|
|
|
|
namespace openvpn {
|
|
namespace TunWin {
|
|
class WinProxySettings : public ProxySettings {
|
|
public:
|
|
typedef RCPtr<WinProxySettings> Ptr;
|
|
|
|
WinProxySettings(const TunBuilderCapture::ProxyAutoConfigURL& config_arg)
|
|
: ProxySettings(config_arg) { }
|
|
|
|
void set_proxy(bool del) override
|
|
{
|
|
Impersonate imp{false};
|
|
|
|
LONG status;
|
|
RegKey hkcu;
|
|
RegKey key;
|
|
|
|
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
|
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
|
|
|
status = ::RegCreateKeyExA(hkcu(), key_name, 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, key.ref(), NULL);
|
|
check_reg_error<proxy_error>(status, key_name);
|
|
|
|
if (!del)
|
|
{
|
|
save_key(key, "AutoConfigURL", config.url, true);
|
|
save_key(key, "ProxyEnable", "0", false);
|
|
}
|
|
else
|
|
{
|
|
restore_key(key, "AutoConfigURL", true);
|
|
restore_key(key, "ProxyEnable", false);
|
|
}
|
|
|
|
// WinInet API cannot be called from service, even via impersonation
|
|
if (!imp.is_local_system())
|
|
{
|
|
OPENVPN_LOG("Refresh proxy settings");
|
|
|
|
InternetSetOptionA(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
|
|
InternetSetOptionA(NULL, INTERNET_OPTION_REFRESH, NULL, 0);
|
|
}
|
|
}
|
|
|
|
private:
|
|
void restore_key(Win::RegKey& regkey, const std::string& key, bool str)
|
|
{
|
|
LONG status;
|
|
char prev_val_str[1024] = { 0 }; // should be enough to fit proxy URL
|
|
DWORD prev_val_dword;
|
|
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
|
|
bool del = false;
|
|
Win::RegKey hkcu;
|
|
|
|
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
|
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
|
|
|
// get previous value
|
|
std::string prev_key_name = sname + key;
|
|
status = ::RegGetValueA(hkcu(),
|
|
key_name,
|
|
prev_key_name.c_str(),
|
|
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
|
|
NULL,
|
|
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
|
|
&prev_buf_size);
|
|
check_reg_error<proxy_error>(status, prev_key_name);
|
|
|
|
RegDeleteValueA(regkey(), prev_key_name.c_str());
|
|
|
|
// check if previous value needs to be deleted
|
|
if (str)
|
|
del = strcmp(delete_value_str, prev_val_str) == 0;
|
|
else
|
|
del = prev_val_dword == delete_value_dword;
|
|
|
|
if (del)
|
|
::RegDeleteValueA(regkey(), key.c_str());
|
|
else
|
|
::RegSetValueExA(regkey(),
|
|
key.c_str(),
|
|
0,
|
|
str ? REG_SZ : REG_DWORD,
|
|
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
|
|
str ? strlen(prev_val_str) + 1 : sizeof(prev_val_dword));
|
|
}
|
|
|
|
void save_key(Win::RegKey& regkey, const std::string& key, const std::string& value, bool str)
|
|
{
|
|
LONG status;
|
|
char prev_val_str[1024] = { 0 }; // should be enought to fit proxy URL
|
|
DWORD prev_val_dword;
|
|
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
|
|
Win::RegKey hkcu;
|
|
|
|
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
|
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
|
|
|
// get original value
|
|
status = ::RegGetValueA(hkcu(),
|
|
key_name,
|
|
key.c_str(),
|
|
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
|
|
NULL,
|
|
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
|
|
&prev_buf_size);
|
|
switch (status)
|
|
{
|
|
case ERROR_FILE_NOT_FOUND:
|
|
// mark that original value doesn't exist
|
|
strcpy(prev_val_str, delete_value_str);
|
|
prev_val_dword = delete_value_dword;
|
|
case ERROR_SUCCESS:
|
|
break;
|
|
default:
|
|
check_reg_error<proxy_error>(status, key);
|
|
break;
|
|
}
|
|
|
|
// save original value
|
|
std::string prev_key_name = sname + key;
|
|
status = ::RegSetValueExA(regkey(),
|
|
prev_key_name.c_str(),
|
|
0,
|
|
str ? REG_SZ : REG_DWORD,
|
|
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
|
|
str ? strlen(prev_val_str) + 1 : sizeof(DWORD));
|
|
check_reg_error<proxy_error>(status, prev_key_name);
|
|
|
|
// save new value
|
|
DWORD val_dword = 0;
|
|
if (!str)
|
|
val_dword = std::atol(value.c_str());
|
|
status = ::RegSetValueExA(regkey(),
|
|
key.c_str(),
|
|
0,
|
|
str ? REG_SZ : REG_DWORD,
|
|
str ? (const BYTE *)value.c_str() : (CONST BYTE *)&val_dword,
|
|
str ? value.length() + 1 : sizeof(val_dword));
|
|
check_reg_error<proxy_error>(status, key);
|
|
}
|
|
|
|
const char* key_name = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
|
|
const char* delete_value_str = "DeleteValue";
|
|
const DWORD delete_value_dword = 0xCAFEBABE;
|
|
};
|
|
}
|
|
}
|