37#include <versionhelpers.h>
43#define IO_TIMEOUT 2000
45#define ERROR_OPENVPN_STARTUP 0x20000000
46#define ERROR_STARTUP_DATA 0x20000001
47#define ERROR_MESSAGE_DATA 0x20000002
48#define ERROR_MESSAGE_TYPE 0x20000003
51static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
55#define RDNS_TIMEOUT 600
57#define TUN_IOCTL_REGISTER_RINGS \
58 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
137 if (new_item == NULL)
139 return ERROR_OUTOFMEMORY;
142 new_item->
next = *pfirst;
157 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
160 if (!match(item->
data, ctx))
178 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
180 CloseHandle(*handle);
181 *handle = INVALID_HANDLE_VALUE;
183 return INVALID_HANDLE_VALUE;
189 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
190 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
191 return overlapped->hEvent;
197 HANDLE io_event = overlapped->hEvent;
198 if (!ResetEvent(io_event))
202 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
203 overlapped->hEvent = io_event;
221 DWORD
res, bytes = 0;
222 OVERLAPPED overlapped;
223 LPHANDLE handles = NULL;
231 handles = malloc((count + 1) *
sizeof(HANDLE));
239 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
243 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
245 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
250 handles[0] = io_event;
251 for (
i = 0;
i < count;
i++)
253 handles[
i + 1] = events[
i];
256 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
257 if (
res != WAIT_OBJECT_0)
265 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
269 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
299 const WCHAR
msg[] = L
"Process ID";
300 WCHAR buf[22 + _countof(
msg)];
306 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
308 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
312ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
315 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
316 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
320 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
321 | FORMAT_MESSAGE_IGNORE_INSERTS,
322 0, error, 0, (LPWSTR)&args[2], 0, NULL);
325 result_len = FormatMessageW(
326 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
327 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
329 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
334 LocalFree((LPVOID)args[2]);
362 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
363 L
" that requires admin approval. This error may be avoided"
364 L
" by adding your account to the \"%ls\" group";
366 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
367 L
" only with admin approval. This error may be avoided"
368 L
" by adding your account to the \"%ls\" group";
374 swprintf(errmsg, capacity,
375 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
392 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
401 for (
i = 0;
i < argc; ++
i)
410 if (wcscmp(L
"--config",
argv[
i]) == 0 && argc -
i > 1)
448 size = bytes /
sizeof(*data);
456 data = malloc(bytes);
472 if (
data[size - 1] != 0)
490 len = wcslen(sud->
options) + 1;
519 SOCKADDR_INET sa_inet;
520 ZeroMemory(&sa_inet,
sizeof(sa_inet));
521 sa_inet.si_family = family;
522 if (family == AF_INET)
524 sa_inet.Ipv4.sin_addr = addr->
ipv4;
526 else if (family == AF_INET6)
528 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
537 LPWSTR wide_name =
utf8to16(iface_name);
541 status = ConvertInterfaceAliasToLuid(wide_name, luid);
546 status = ERROR_OUTOFMEMORY;
554 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
560 return DeleteUnicastIpAddressEntry(addr_row);
567 PMIB_UNICASTIPADDRESS_ROW addr_row;
570 addr_row = malloc(
sizeof(*addr_row));
571 if (addr_row == NULL)
573 return ERROR_OUTOFMEMORY;
576 InitializeUnicastIpAddressEntry(addr_row);
578 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
580 if (
msg->iface.index != -1)
582 addr_row->InterfaceIndex =
msg->iface.index;
592 addr_row->InterfaceLuid = luid;
597 err = CreateUnicastIpAddressEntry(addr_row);
632 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
638 return DeleteIpForwardEntry2(fwd_row);
645 PMIB_IPFORWARD_ROW2 fwd_row;
648 fwd_row = malloc(
sizeof(*fwd_row));
651 return ERROR_OUTOFMEMORY;
654 ZeroMemory(fwd_row,
sizeof(*fwd_row));
655 fwd_row->ValidLifetime = 0xffffffff;
656 fwd_row->PreferredLifetime = 0xffffffff;
657 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
658 fwd_row->Metric =
msg->metric;
660 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
663 if (
msg->iface.index != -1)
665 fwd_row->InterfaceIndex =
msg->iface.index;
667 else if (strlen(
msg->iface.name))
675 fwd_row->InterfaceLuid = luid;
680 err = CreateIpForwardEntry2(fwd_row);
716 if (
msg->family == AF_INET)
718 return FlushIpNetTable(
msg->iface.index);
721 return FlushIpNetTable2(
msg->family,
msg->iface.index);
735 err_str = L
"Unknown Win32 Error";
737 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
738 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
739 NULL, err, 0, buf,
sizeof(buf), NULL))
786 HANDLE engine = NULL;
799 err = ERROR_OUTOFMEMORY;
802 block_data->
engine = engine;
803 block_data->
index =
msg->iface.index;
867ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
871 PROCESS_INFORMATION pi;
872 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
873 WCHAR *cmdline_dup = NULL;
875 ZeroMemory(&si,
sizeof(si));
876 ZeroMemory(&pi,
sizeof(pi));
881 cmdline_dup = _wcsdup(cmdline);
883 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
885 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
886 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
889 exit_code = GetLastError();
891 else if (exit_code == STILL_ACTIVE)
893 exit_code = WAIT_TIMEOUT;
896 TerminateProcess(pi.hProcess, exit_code);
897 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
909 CloseHandle(pi.hProcess);
910 CloseHandle(pi.hThread);
914 exit_code = GetLastError();
933 WCHAR ipcfg[MAX_PATH];
941 { ipcfg, L
"ipconfig /flushdns", timeout },
942 { ipcfg, L
"ipconfig /registerdns", timeout },
947 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
949 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
952 for (
i = 0;
i < _countof(cmds); ++
i)
966 err = ERROR_SEM_TIMEOUT;
975 HANDLE thread = NULL;
978 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
991 err = GetLastError();
1010 int timeout = 30000;
1011 wchar_t argv0[MAX_PATH];
1012 wchar_t *cmdline = NULL;
1013 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1017 if (wcscmp(action, L
"delete") == 0)
1028 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1033 const wchar_t *fmt = L
"netsh interface ip %ls wins \"%ls\" %ls %ls";
1036 size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(action) + wcslen(addr)
1037 + wcslen(addr_static) + 32 + 1;
1038 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1041 err = ERROR_OUTOFMEMORY;
1045 swprintf(cmdline, ncmdline, fmt, action, if_name, addr_static, addr);
1057 return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1069 typedef NTSTATUS(__stdcall * publish_fn_t)(DWORD StateNameLo, DWORD StateNameHi, DWORD TypeId,
1070 DWORD Buffer, DWORD Length, DWORD ExplicitScope);
1071 publish_fn_t RtlPublishWnfStateData;
1072 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1073 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1075 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1081 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1082 if (RtlPublishWnfStateData == NULL)
1087 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0)
1105 typedef NTSTATUS (*publish_fn_t)(INT64 StateName, INT64 TypeId, INT64 Buffer,
1106 unsigned int Length, INT64 ExplicitScope);
1107 publish_fn_t RtlPublishWnfStateData;
1108 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1110 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1116 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1117 if (RtlPublishWnfStateData == NULL)
1122 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1140 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1155 SC_HANDLE scm = NULL;
1156 SC_HANDLE dnssvc = NULL;
1163 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1166 MsgToEventLog(
M_ERR, L
"%S: OpenSCManager call failed (%lu)", __func__, GetLastError());
1170 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1173 MsgToEventLog(
M_ERR, L
"%S: OpenService call failed (%lu)", __func__, GetLastError());
1178 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1180 MsgToEventLog(
M_ERR, L
"%S: ControlService call failed (%lu)", __func__, GetLastError());
1189 CloseServiceHandle(dnssvc);
1193 CloseServiceHandle(scm);
1213 PWSTR iid_str = NULL;
1221 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1228 if (StringFromIID(&guid, &iid_str) != S_OK)
1231 err = ERROR_OUTOFMEMORY;
1234 if (wcslen(iid_str) + 1 > len)
1236 err = ERROR_INVALID_PARAMETER;
1240 wcsncpy(str, iid_str, len);
1245 CoTaskMemFree(iid_str);
1267 DWORD size =
sizeof(
data);
1268 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1269 if (!err || err == ERROR_MORE_DATA)
1272 for (
int i = 0;
i < strlen(
data); ++
i)
1308 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1309 0, KEY_ALL_ACCESS,
key);
1322 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1323 0, KEY_ALL_ACCESS,
key);
1342 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1343 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1344 0, KEY_ALL_ACCESS, &itfs);
1347 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1357 *
key = INVALID_HANDLE_VALUE;
1373 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1376 if (err == ERROR_FILE_NOT_FOUND)
1386#if defined(__GNUC__) || defined(__clang__)
1387#pragma GCC diagnostic push
1388#pragma GCC diagnostic ignored "-Wconversion"
1404 if (!list || wcslen(list) == 0)
1416 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1417 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1420 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1440 WCHAR list[2048] = { 0 };
1441 DWORD size =
sizeof(list);
1445 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1458 size_t listlen = (size /
sizeof(list[0])) - 1;
1459 size_t domlen = wcslen(domains);
1460 if (listlen + domlen + 2 > _countof(list))
1468 PWSTR
pos = list + listlen;
1470 wcsncpy(
pos + 1, domains, domlen + 1);
1474 wcsncpy(list, domains, wcslen(domains) + 1);
1477 size = (wcslen(list) + 1) *
sizeof(list[0]);
1478 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1505 DWORD size =
sizeof(list);
1507 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1510 if (err != ERROR_FILE_NOT_FOUND)
1518 size = (wcslen(list) + 1) *
sizeof(list[0]);
1519 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1526 RegDeleteValueA(
key,
"InitialSearchList");
1544 DWORD size =
sizeof(list);
1546 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1553 PWSTR dst = wcsstr(list, domains);
1561 size_t domlen = wcslen(domains);
1562 PCWSTR src = dst + domlen;
1564 dst = dst > list ? dst - 1 : dst;
1565 wmemmove(dst, src, domlen);
1567 size_t list_len = wcslen(list);
1571 WCHAR initial[2048];
1572 size =
sizeof(initial);
1573 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1582 if (wcsncmp(list, initial, wcslen(list)) == 0)
1589 size = (list_len + 1) *
sizeof(list[0]);
1590 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1606 HKEY dns_searchlist_key;
1608 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1611 RegCloseKey(dns_searchlist_key);
1643 DWORD err = ERROR_OUTOFMEMORY;
1647 if (list_key == INVALID_HANDLE_VALUE)
1650 return ERROR_FILE_NOT_FOUND;
1664 if (domains && *domains)
1666 wchar_t *wide_domains =
utf8to16(domains);
1672 undo_data = malloc(
sizeof(*undo_data));
1676 wide_domains = NULL;
1680 undo_data->
domains = wide_domains;
1696 RegCloseKey(list_key);
1710 PCSTR itfs_key = family == AF_INET6
1711 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1712 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1714 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1717 *
key = INVALID_HANDLE_VALUE;
1719 __func__, family, err);
1722 return err ? FALSE : TRUE;
1742 return ERROR_FILE_NOT_FOUND;
1745 HKEY itf = INVALID_HANDLE_VALUE;
1746 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1750 __func__, itf_id, family, err);
1754 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1758 __func__, value, itf_id, family, err);
1762 if (itf != INVALID_HANDLE_VALUE)
1766 if (itfs != INVALID_HANDLE_VALUE)
1807 int addr_len =
msg->addr_len;
1810 const size_t max_addrs = _countof(
msg->addr);
1811 if (addr_len > max_addrs)
1813 addr_len = max_addrs;
1816 if (!
msg->iface.name[0])
1825 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1826 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1852 if (
msg->domains[0])
1861 if (
msg->addr_len > 0)
1866 CHAR addrs[_countof(
msg->addr) * 64];
1868 for (
int i = 0;
i < addr_len; ++
i)
1872 addrs[offset++] =
',';
1874 if (
msg->family == AF_INET6)
1876 RtlIpv6AddressToStringA(&
msg->addr[
i].ipv6, addrs + offset);
1880 RtlIpv4AddressToStringA(&
msg->addr[
i].ipv4, addrs + offset);
1882 offset += strlen(addrs);
1891 wchar_t *tmp_iid = _wcsdup(iid);
1892 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1896 return ERROR_OUTOFMEMORY;
1901 if (
msg->domains[0])
1922 DWORD size =
sizeof(
dhcp);
1925 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1926 if (err != NO_ERROR)
1932 return dhcp ? TRUE : FALSE;
1946 const short families[] = { AF_INET, AF_INET6 };
1947 for (
int i = 0;
i < _countof(families);
i++)
1949 short family = families[
i];
1956 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1957 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1964 addr_list[offset++] =
',';
1966 strcpy(addr_list + offset, addresses[j]);
1967 offset += strlen(addresses[j]);
1999 addrs[*size - 1] =
'\0';
2003 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2004 if (err && err != ERROR_FILE_NOT_FOUND)
2014 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2022 if (strchr(addrs,
'.'))
2029 return ERROR_FILE_NOT_FOUND;
2044 addrs[*size - 1] =
'\0';
2048 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2049 if (err && err != ERROR_FILE_NOT_FOUND)
2058 IN6_ADDR in_addrs[8];
2059 DWORD in_addrs_size =
sizeof(in_addrs);
2060 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2061 (PBYTE)in_addrs, &in_addrs_size);
2070 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2071 for (
size_t i = 0;
i < in_addrs_read; ++
i)
2080 if (inet_ntop(AF_INET6, &in_addrs[
i],
pos, s) != NULL)
2083 return ERROR_MORE_DATA;
2086 size_t addr_len = strlen(
pos);
2090 s = strlen(addrs) + 1;
2093 if (strchr(addrs,
':'))
2100 return ERROR_FILE_NOT_FOUND;
2115 PCWSTR match = list;
2118 match = wcsstr(match, domain);
2124 if ((match == list || *(match - 1) ==
',')
2125 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2159 if (domains == NULL || size == 0)
2161 return ERROR_INVALID_PARAMETER;
2164 LSTATUS err = ERROR_FILE_NOT_FOUND;
2165 const DWORD buf_size = *size;
2166 const size_t one_glyph =
sizeof(*domains);
2167 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2169 for (
int i = 0; values[
i];
i++)
2172 err = RegGetValueW(itf, NULL, values[
i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2173 if (!err && *size > one_glyph && wcschr(domains,
'.'))
2180 PWCHAR
pos = domains;
2181 const DWORD
buf_len = buf_size / one_glyph;
2185 PWCHAR comma = wcschr(
pos,
',');
2192 size_t domain_len = wcslen(
pos);
2205 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2211 size_t converted_size =
pos - domains;
2212 size_t domain_size = domain_len * one_glyph;
2213 size_t extra_size = 2 * one_glyph;
2214 if (converted_size + domain_size + extra_size > buf_size)
2218 *size = converted_size == 0 ? 0 : *size + 1;
2219 return ERROR_MORE_DATA;
2223 memmove(
pos + 1,
pos, buf_size - converted_size - one_glyph);
2231 *(
pos + domain_len) =
'\0';
2258 MIB_IF_ROW2 itf_row;
2261 if (IIDFromString(iid_str, &iid) != S_OK)
2269 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2275 if (GetIfEntry2(&itf_row) != NO_ERROR)
2281 if (itf_row.MediaConnectState == MediaConnectStateConnected
2282 && itf_row.OperStatus == IfOperStatusUp)
2303 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2304 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2312 DWORD enum_index = 0;
2313 while (
i < data_size)
2315 WCHAR itf_guid[MAX_PATH];
2316 DWORD itf_guid_len = _countof(itf_guid);
2318 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2321 if (err != ERROR_NO_MORE_ITEMS)
2335 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2343 data[
i].domains_size =
sizeof(
data[0].domains);
2344 memset(
data[
i].domains, 0,
data[
i].domains_size);
2348 if (err != ERROR_FILE_NOT_FOUND)
2357 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2359 if (err && err != ERROR_FILE_NOT_FOUND)
2362 __func__, itf_guid, err);
2367 PSTR v6_addrs =
data[
i].addresses + v4_addrs_size;
2368 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2372 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2375 __func__, itf_guid);
2379 RegCloseKey(v6_itf);
2380 if (err && err != ERROR_FILE_NOT_FOUND)
2383 __func__, itf_guid, err);
2388 if (v4_addrs_size || v6_addrs_size)
2391 for (
int j = 0; j <
sizeof(
data[0].addresses) &&
data[
i].addresses[j]; j++)
2393 if (
data[
i].addresses[j] ==
',' ||
data[
i].addresses[j] ==
' ')
2395 data[
i].addresses[j] =
';';
2402 RegCloseKey(v4_itf);
2406 RegCloseKey(v6_itfs);
2407 RegCloseKey(v4_itfs);
2427 DWORD err = NO_ERROR;
2429 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2436 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2443 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2455 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2463 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2471 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2480 reg_val = dnssec ? 0x0000000A : 0x00000008;
2481 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2490 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2499 RegDeleteKeyW(nrpt_key, subkey);
2501 RegCloseKey(rule_key);
2522 for (
int i = 0;
i < _countof(
data); ++
i)
2532 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2555 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2557 DWORD err = NO_ERROR;
2558 PWSTR wide_domains = L
".\0";
2564 size_t domains_len = strlen(domains);
2565 dom_size = domains_len + 2;
2568 dom_size *=
sizeof(*wide_domains);
2571 return ERROR_OUTOFMEMORY;
2574 for (
size_t i = 0;
i < domains_len; ++
i)
2576 if (wide_domains[
i] ==
',')
2578 wide_domains[
i] = 0;
2584 PWSTR wide_search_domains;
2585 wide_search_domains =
utf8to16(search_domains);
2586 if (!wide_search_domains)
2588 return ERROR_OUTOFMEMORY;
2591 free(wide_search_domains);
2596 PSTR
pos = addr_list;
2603 strcpy(
pos, addresses[
i]);
2607 WCHAR subkey[MAX_PATH];
2608 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2609 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2622#if defined(__GNUC__) || defined(__clang__)
2623#pragma GCC diagnostic pop
2643 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2644 static PCSTR sys_key =
2645 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2649 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2650 if (err == ERROR_FILE_NOT_FOUND)
2653 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2657 nrpt = INVALID_HANDLE_VALUE;
2691 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2692 pidlen = wcslen(pid_str);
2696 DWORD enum_index = 0;
2699 WCHAR name[MAX_PATH];
2700 DWORD namelen = _countof(name);
2701 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2704 if (err != ERROR_NO_MORE_ITEMS)
2712 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2713 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2718 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2726 return deleted ? TRUE : FALSE;
2764 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2769 msgptr->
addresses[
i][_countof(
msg->addresses[0]) - 1] =
'\0';
2774 if (
msg->iface.name[0] == 0)
2783 if (
msg->addresses[0][0] == 0)
2788 const char *rdom =
msg->resolve_domains;
2789 size_t rdom_size =
sizeof(
msg->resolve_domains);
2790 size_t rdom_len = strlen(rdom);
2791 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2797 BOOL gpol_nrpt = FALSE;
2798 BOOL gpol_list = FALSE;
2811 if (*undo_pid != ovpn_pid)
2814 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2815 "This is likely an error. Cleaning up anyway.",
2816 __func__, *undo_pid, ovpn_pid);
2840 PDWORD pid = malloc(
sizeof(ovpn_pid));
2843 err = ERROR_OUTOFMEMORY;
2849 err = ERROR_OUTOFMEMORY;
2871 if (
msg->search_domains[0])
2887 int addr_len =
msg->addr_len;
2890 if (addr_len > _countof(
msg->addr))
2892 addr_len = _countof(
msg->addr);
2895 if (!
msg->iface.name[0])
2904 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2910 return ERROR_OUTOFMEMORY;
2931 for (
int i = 0;
i < addr_len; ++
i)
2933 RtlIpv4AddressToStringW(&
msg->addr[
i].ipv4, addr);
2948 wchar_t *tmp_name = _wcsdup(wide_name);
2953 err = ERROR_OUTOFMEMORY;
2967 DWORD timeout = 5000;
2968 wchar_t argv0[MAX_PATH];
2971 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2976 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2981 size_t ncmdline = wcslen(fmt) + 10 + 1;
2982 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
2985 err = ERROR_OUTOFMEMORY;
2989 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3005 MIB_IPINTERFACE_ROW ipiface;
3006 InitializeIpInterfaceEntry(&ipiface);
3007 ipiface.Family = mtu->
family;
3009 err = GetIpInterfaceEntry(&ipiface);
3010 if (err != NO_ERROR)
3014 if (mtu->
family == AF_INET)
3016 ipiface.SitePrefixLength = 0;
3018 ipiface.NlMtu = mtu->
mtu;
3020 err = SetIpInterfaceEntry(&ipiface);
3036 switch (
msg->adapter_type)
3043 hwid = L
"root\\tap0901";
3047 return ERROR_INVALID_PARAMETER;
3050 WCHAR cmd[MAX_PATH];
3051 WCHAR args[MAX_PATH];
3053 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3055 return ERROR_BUFFER_OVERFLOW;
3058 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3060 return ERROR_BUFFER_OVERFLOW;
3067HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3084 switch (
msg.header.type)
3088 if (
msg.header.size ==
sizeof(
msg.address))
3096 if (
msg.header.size ==
sizeof(
msg.route))
3103 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3111 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3129 DWORD ovpn_pid = proc_info->dwProcessId;
3140 if (
msg.header.size ==
sizeof(
msg.dhcp))
3147 if (
msg.header.size ==
sizeof(
msg.mtu))
3154 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3233 *pnext = item->
next;
3244 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3245 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3246 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3247 HANDLE stdin_read = NULL, stdin_write = NULL;
3248 HANDLE stdout_write = NULL;
3249 DWORD pipe_mode, len, exit_code = 0;
3251 STARTUPINFOW startup_info;
3252 PROCESS_INFORMATION proc_info;
3253 LPVOID user_env = NULL;
3254 WCHAR ovpn_pipe_name[256];
3257 WCHAR *cmdline = NULL;
3258 size_t cmdline_size;
3260 WCHAR errmsg[512] = L
"";
3262 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3263 .lpSecurityDescriptor = NULL,
3264 .bInheritHandle = TRUE };
3267 EXPLICIT_ACCESS ea[2];
3268 SECURITY_DESCRIPTOR ovpn_sd;
3269 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3270 .lpSecurityDescriptor = &ovpn_sd,
3271 .bInheritHandle = FALSE };
3273 ZeroMemory(&ea,
sizeof(ea));
3274 ZeroMemory(&startup_info,
sizeof(startup_info));
3275 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3276 ZeroMemory(&proc_info,
sizeof(proc_info));
3283 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3290 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3296 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3298 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3304 svc_user = malloc(len);
3305 if (svc_user == NULL)
3311 if (!IsValidSid(svc_user->User.Sid))
3317 if (!ImpersonateNamedPipeClient(pipe))
3322 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3328 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3330 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3336 ovpn_user = malloc(len);
3337 if (ovpn_user == NULL)
3343 if (!IsValidSid(ovpn_user->User.Sid))
3365 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3366 ea[0].grfAccessMode = SET_ACCESS;
3367 ea[0].grfInheritance = NO_INHERITANCE;
3368 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3369 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3370 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3371 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3372 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3373 ea[1].grfAccessMode = SET_ACCESS;
3374 ea[1].grfInheritance = NO_INHERITANCE;
3375 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3376 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3377 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3380 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3385 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3390 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3397 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3404 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3405 OPEN_EXISTING, 0, NULL);
3406 if (stdout_write == INVALID_HANDLE_VALUE)
3412 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3413 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3419 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3421 GetCurrentThreadId());
3422 ovpn_pipe = CreateNamedPipe(
3423 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3424 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
3425 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3431 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3432 OPEN_EXISTING, 0, NULL);
3433 if (svc_pipe == INVALID_HANDLE_VALUE)
3439 pipe_mode = PIPE_READMODE_MESSAGE;
3440 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3446 cmdline_size = wcslen(sud.
options) + 128;
3447 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3448 if (cmdline == NULL)
3456 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3457 (uintptr_t)svc_pipe);
3459 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3465 startup_info.cb =
sizeof(startup_info);
3466 startup_info.dwFlags = STARTF_USESTDHANDLES;
3467 startup_info.hStdInput = stdin_read;
3468 startup_info.hStdOutput = stdout_write;
3469 startup_info.hStdError = stdout_write;
3474 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3476 user_env, sud.
directory, &startup_info, &proc_info))
3482 if (!RevertToSelf())
3484 TerminateProcess(proc_info.hProcess, 1);
3495 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3497 if (input_size && (input = malloc(input_size)))
3500 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3501 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3518 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3526 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3527 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3528 if (exit_code == STILL_ACTIVE)
3530 TerminateProcess(proc_info.hProcess, 1);
3532 else if (exit_code != 0)
3535 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3541 FlushFileBuffers(pipe);
3542 DisconnectNamedPipe(pipe);
3547 DestroyEnvironmentBlock(user_env);
3568 SERVICE_STATUS *
status = ctx;
3571 case SERVICE_CONTROL_STOP:
3572 status->dwCurrentState = SERVICE_STOP_PENDING;
3580 case SERVICE_CONTROL_INTERROGATE:
3584 return ERROR_CALL_NOT_IMPLEMENTED;
3598 const WCHAR *sddlString =
3599 L
"D:(A;OICI;GA;;;S-1-5-18)(D;OICI;0x4;;;S-1-1-0)(A;OICI;GRGW;;;S-1-5-11)(D;;GA;;;S-1-5-7)";
3601 PSECURITY_DESCRIPTOR sd = NULL;
3602 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3606 return INVALID_HANDLE_VALUE;
3610 SECURITY_ATTRIBUTES sa = { 0 };
3611 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3612 sa.lpSecurityDescriptor = sd;
3613 sa.bInheritHandle = FALSE;
3615 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3617 static BOOL first = TRUE;
3620 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3624 WCHAR pipe_name[256];
3626 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(
PACKAGE) L
"%ls\\service",
3628 HANDLE pipe = CreateNamedPipe(
3629 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3630 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3634 if (pipe == INVALID_HANDLE_VALUE)
3637 return INVALID_HANDLE_VALUE;
3648 static DWORD size = 10;
3649 static LPHANDLE handles = NULL;
3652 if (handles == NULL)
3654 handles = malloc(size *
sizeof(HANDLE));
3655 *handles_ptr = handles;
3656 if (handles == NULL)
3658 return ERROR_OUTOFMEMORY;
3662 handles[
pos++] = io_event;
3675 tmp = realloc(handles, size *
sizeof(HANDLE));
3680 return ERROR_OUTOFMEMORY;
3683 *handles_ptr = handles;
3685 handles[
pos++] = threads->
data;
3686 threads = threads->
next;
3710 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3722 BOOL changed = FALSE;
3732 if (
key != INVALID_HANDLE_VALUE)
3750 HANDLE pipe, io_event = NULL;
3751 OVERLAPPED overlapped;
3752 DWORD error = NO_ERROR;
3754 PHANDLE handles = NULL;
3764 status.dwCurrentState = SERVICE_START_PENDING;
3765 status.dwServiceSpecificExitCode = NO_ERROR;
3766 status.dwWin32ExitCode = NO_ERROR;
3767 status.dwWaitHint = 3000;
3775 if (error != ERROR_SUCCESS)
3781 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3796 if (error != NO_ERROR)
3802 if (pipe == INVALID_HANDLE_VALUE)
3807 status.dwCurrentState = SERVICE_RUNNING;
3813 if (ConnectNamedPipe(pipe, &overlapped) == FALSE && GetLastError() != ERROR_PIPE_CONNECTED
3814 && GetLastError() != ERROR_IO_PENDING)
3820 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3821 if (error == WAIT_OBJECT_0)
3825 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3836 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3841 TerminateThread(thread, 1);
3847 ResumeThread(thread);
3861 if (error == WAIT_FAILED)
3891 status.dwCurrentState = SERVICE_STOPPED;
3892 status.dwWin32ExitCode = error;
static int buf_len(const struct buffer *buf)
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static LSTATUS GetItfDnsServersV4(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv4 addresses of an interface.
static LSTATUS SetNameServerAddresses(PWSTR itf_id, const nrpt_address_t *addresses)
Set name servers from a NRPT address list.
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static BOOL GetInterfacesKey(short family, PHKEY key)
Return the interfaces registry key for the specified address family.
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static void UndoNrptRules(DWORD ovpn_pid)
Delete a process' NRPT rules and apply the reduced set of rules.
static BOOL ApplyGpolSettings(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings.
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static BOOL GetDnsSearchListKey(PCSTR itf_name, PBOOL gpol, PHKEY key)
Find the registry key for storing the DNS domains for the VPN interface.
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static LSTATUS GetItfDnsDomains(HKEY itf, PCWSTR search_domains, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD SetNameServers(PCWSTR itf_id, short family, PCSTR addrs)
Set the DNS name servers in a registry interface configuration.
static void SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid, PCWSTR search_domains)
Set NRPT exclude rules to accompany a catch all rule.
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL CmpWString(LPVOID item, LPVOID str)
static HANDLE CreateClientPipeInstance(VOID)
static void GetNrptExcludeData(PCWSTR search_domains, nrpt_exclude_data_t *data, size_t data_size)
Collect interface DNS settings to be used in excluding NRPT rules.
static DWORD SetNameServersValue(PCWSTR itf_id, short family, PCSTR value)
Set the DNS name servers in a registry interface configuration.
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
static DWORD DeleteWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL DeleteNrptRules(DWORD pid, PBOOL gpol)
Delete OpenVPN NRPT rules from the registry.
static VOID Undo(undo_lists_t *lists)
static BOOL ApplyDnsSettings(BOOL apply_gpol)
Signal the DNS resolver to reload its settings.
#define ERROR_STARTUP_DATA
static DWORD WINAPI RunOpenvpn(LPVOID p)
static settings_t settings
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
static SERVICE_STATUS status
static DWORD HandleDNSConfigNrptMessage(const nrpt_dns_cfg_message_t *msg, DWORD ovpn_pid, undo_lists_t *lists)
Add Name Resolution Policy Table (NRPT) rules as documented in https://msdn.microsoft....
static DWORD SetDnsSearchDomains(PCSTR itf_name, PCSTR domains, PBOOL gpol, undo_lists_t *lists)
Add or remove DNS search domains.
static void CleanupRegistry(void)
Clean up remains of previous sessions in registry.
#define ERROR_MESSAGE_TYPE
static SOCKADDR_INET sockaddr_inet(short family, inet_address_t *addr)
static LPVOID RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
static BOOL CmpHandle(LPVOID item, LPVOID hnd)
static BOOL ApplyGpolSettings64(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 64 bit ...
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
static VOID ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
static DWORD AddListItem(list_item_t **pfirst, LPVOID data)
static void BlockDNSErrHandler(DWORD err, const char *msg)
static DWORD ResetNameServers(PCWSTR itf_id, short family)
Delete all DNS name servers from a registry interface configuration.
static LSTATUS OpenNrptBaseKey(PHKEY key, PBOOL gpol)
Return the registry key where NRPT rules are stored.
static BOOL HasValidSearchList(HKEY key)
Check for a valid search list in a certain key of the registry.
static DWORD HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
static DWORD WINAPI RegisterDNS(LPVOID unused)
static HANDLE InitOverlapped(LPOVERLAPPED overlapped)
BOOL(* match_fn_t)(LPVOID item, LPVOID ctx)
static HANDLE CloseHandleEx(LPHANDLE handle)
static DWORD WINAPI ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
static BOOL StoreInitialDnsSearchList(HKEY key, PCWSTR list)
Prepare DNS domain "SearchList" registry value, so additional VPN domains can be added and its origin...
struct _list_item list_item_t
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
static BOOL IsInterfaceConnected(PWSTR iid_str)
Check if an interface is connected and up.
#define ERROR_OPENVPN_STARTUP
static DWORD SetNrptRules(HKEY nrpt_key, const nrpt_address_t *addresses, const char *domains, const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
Set NRPT rules for a openvpn process.
static LSTATUS GetItfDnsServersV6(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv6 addresses of an interface.
static DWORD SetNrptRule(HKEY nrpt_key, PCWSTR subkey, PCSTR address, PCWSTR domains, DWORD dom_size, BOOL dnssec)
Set a NRPT rule (subkey) and its values in the registry.
static BOOL AddDnsSearchDomains(HKEY key, BOOL have_list, PCWSTR domains)
Append domain suffixes to an existing search list.
static VOID FreeWaitHandles(LPHANDLE h)
openvpn_service_t interactive_service
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static BOOL ListContainsDomain(PCWSTR list, PCWSTR domain, size_t len)
Check if a domain is contained in a comma separated list of domains.
static BOOL IsDhcpEnabled(HKEY key)
Checks if DHCP is enabled for an interface.
static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
static BOOL ApplyGpolSettings32(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 32 bit ...
static DWORD HandleMTUMessage(const set_mtu_message_t *mtu)
list_item_t * undo_lists_t[_undo_type_max]
static VOID HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
static DWORD HandleRegisterDNSMessage(void)
static void RemoveDnsSearchDomains(HKEY key, PCWSTR domains)
Remove domain suffixes from an existing search list.
static BOOL InitialSearchListExists(HKEY key)
Check if a initial list had already been created.
#define ERROR_MESSAGE_DATA
static VOID FreeStartupData(STARTUP_DATA *sud)
static DWORD HandleWfpBlockMessage(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE rdns_semaphore
static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid)
static BOOL ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
static DWORD UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, HANDLE io_event, HANDLE exit_event, list_item_t *threads)
static BOOL CmpRoute(LPVOID item, LPVOID route)
static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAny(LPVOID item, LPVOID any)
static DWORD netsh_wins_cmd(const wchar_t *action, const wchar_t *if_name, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_name [static] $addr.
static DWORD HandleCreateAdapterMessage(const create_adapter_message_t *msg)
Creates a VPN adapter of the specified type by invoking tapctl.exe.
static DWORD InterfaceIdString(PCSTR itf_name, PWSTR str, size_t len)
Get the string interface UUID (with braces) for an interface alias name.
static SERVICE_STATUS_HANDLE service
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
static void UndoDnsSearchDomains(dns_domains_undo_data_t *undo_data)
Removes DNS domains from a search list they were previously added to.
char nrpt_address_t[NRPT_ADDR_SIZE]
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
#define SERVICE_DEPENDENCIES
static wchar_t * utf8to16(const char *utf8)
Convert a zero terminated UTF-8 string to UTF-16.
Wrapper structure for dynamically allocated memory.
Container for unidirectional cipher and HMAC key material.
char resolve_domains[512]
nrpt_address_t addresses[NRPT_ADDR_NUM]
CHAR addresses[NRPT_ADDR_NUM *NRPT_ADDR_SIZE]
WCHAR ovpn_admin_group[MAX_NAME]
WCHAR ovpn_service_user[MAX_NAME]
address_message_t address
flush_neighbors_message_t flush_neighbors
wfp_block_message_t wfp_block
enable_dhcp_message_t dhcp
nrpt_dns_cfg_message_t nrpt_dns
create_adapter_message_t create_adapter
BOOL IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group, const WCHAR *ovpn_service_user)
BOOL CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
static BOOL IsOption(const WCHAR *o)
int get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, int *is_auto)
Return interface metric value for the specified interface index.
DWORD set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, const ULONG metric)
Sets interface metric value for specified interface index.
DWORD delete_wfp_block_filters(HANDLE engine_handle)
DWORD add_wfp_block_filters(HANDLE *engine_handle, int index, const WCHAR *exe_path, wfp_block_msg_handler_t msg_handler, BOOL dns_only)
#define WFP_BLOCK_IFACE_METRIC
char * get_win_sys_path(void)