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)
61 _L(PACKAGE_NAME) L
" Interactive Service",
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);
449 if ((size == 0) || (size > 4096))
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)
954 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
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 %d %ls %ls";
1036 size_t ncmdline = wcslen(fmt) + 11 + 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_index, addr_static, addr);
1063 typedef NTSTATUS(__stdcall * publish_fn_t)(DWORD StateNameLo, DWORD StateNameHi, DWORD TypeId,
1064 DWORD Buffer, DWORD Length, DWORD ExplicitScope);
1065 publish_fn_t RtlPublishWnfStateData;
1066 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1067 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1069 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1075 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1076 if (RtlPublishWnfStateData == NULL)
1081 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0)
1099 typedef NTSTATUS (*publish_fn_t)(INT64 StateName, INT64 TypeId, INT64 Buffer,
1100 unsigned int Length, INT64 ExplicitScope);
1101 publish_fn_t RtlPublishWnfStateData;
1102 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1104 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1110 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1111 if (RtlPublishWnfStateData == NULL)
1116 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1134 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1149 SC_HANDLE scm = NULL;
1150 SC_HANDLE dnssvc = NULL;
1157 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1160 MsgToEventLog(
M_ERR, L
"%S: OpenSCManager call failed (%lu)", __func__, GetLastError());
1164 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1167 MsgToEventLog(
M_ERR, L
"%S: OpenService call failed (%lu)", __func__, GetLastError());
1172 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1174 MsgToEventLog(
M_ERR, L
"%S: ControlService call failed (%lu)", __func__, GetLastError());
1183 CloseServiceHandle(dnssvc);
1187 CloseServiceHandle(scm);
1207 PWSTR iid_str = NULL;
1215 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1222 if (StringFromIID(&guid, &iid_str) != S_OK)
1225 err = ERROR_OUTOFMEMORY;
1228 if (wcslen(iid_str) + 1 > len)
1230 err = ERROR_INVALID_PARAMETER;
1234 wcsncpy(str, iid_str, len);
1239 CoTaskMemFree(iid_str);
1261 DWORD size =
sizeof(
data);
1262 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1263 if (!err || err == ERROR_MORE_DATA)
1266 for (
int i = 0; i < strlen(
data); ++i)
1268 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1302 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1303 0, KEY_ALL_ACCESS,
key);
1316 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1317 0, KEY_ALL_ACCESS,
key);
1336 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1337 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1338 0, KEY_ALL_ACCESS, &itfs);
1341 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1351 *
key = INVALID_HANDLE_VALUE;
1367 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1370 if (err == ERROR_FILE_NOT_FOUND)
1380#if defined(__GNUC__) || defined(__clang__)
1381#pragma GCC diagnostic push
1382#pragma GCC diagnostic ignored "-Wconversion"
1398 if (!list || wcslen(list) == 0)
1410 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1411 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1414 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1434 WCHAR list[2048] = { 0 };
1435 DWORD size =
sizeof(list);
1439 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1452 size_t listlen = (size /
sizeof(list[0])) - 1;
1453 size_t domlen = wcslen(domains);
1454 if (listlen + domlen + 2 > _countof(list))
1462 PWSTR
pos = list + listlen;
1464 wcsncpy(
pos + 1, domains, domlen + 1);
1468 wcsncpy(list, domains, wcslen(domains) + 1);
1471 size = (wcslen(list) + 1) *
sizeof(list[0]);
1472 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1499 DWORD size =
sizeof(list);
1501 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1504 if (err != ERROR_FILE_NOT_FOUND)
1512 size = (wcslen(list) + 1) *
sizeof(list[0]);
1513 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1520 RegDeleteValueA(
key,
"InitialSearchList");
1538 DWORD size =
sizeof(list);
1540 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1547 PWSTR dst = wcsstr(list, domains);
1555 size_t domlen = wcslen(domains);
1556 PCWSTR src = dst + domlen;
1558 dst = dst > list ? dst - 1 : dst;
1559 wmemmove(dst, src, domlen);
1561 size_t list_len = wcslen(list);
1565 WCHAR initial[2048];
1566 size =
sizeof(initial);
1567 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1576 if (wcsncmp(list, initial, wcslen(list)) == 0)
1583 size = (list_len + 1) *
sizeof(list[0]);
1584 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1600 HKEY dns_searchlist_key;
1602 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1605 RegCloseKey(dns_searchlist_key);
1637 DWORD err = ERROR_OUTOFMEMORY;
1641 if (list_key == INVALID_HANDLE_VALUE)
1644 return ERROR_FILE_NOT_FOUND;
1658 if (domains && *domains)
1660 wchar_t *wide_domains =
utf8to16(domains);
1666 undo_data = malloc(
sizeof(*undo_data));
1670 wide_domains = NULL;
1674 undo_data->
domains = wide_domains;
1690 RegCloseKey(list_key);
1704 PCSTR itfs_key = family == AF_INET6
1705 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1706 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1708 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1711 *
key = INVALID_HANDLE_VALUE;
1713 __func__, family, err);
1716 return err ? FALSE : TRUE;
1736 return ERROR_FILE_NOT_FOUND;
1739 HKEY itf = INVALID_HANDLE_VALUE;
1740 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1744 __func__, itf_id, family, err);
1748 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1752 __func__, value, itf_id, family, err);
1756 if (itf != INVALID_HANDLE_VALUE)
1760 if (itfs != INVALID_HANDLE_VALUE)
1801 int addr_len =
msg->addr_len;
1804 const size_t max_addrs = _countof(
msg->addr);
1805 if (addr_len > max_addrs)
1807 addr_len = max_addrs;
1810 if (!
msg->iface.name[0])
1819 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1820 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1846 if (
msg->domains[0])
1855 if (
msg->addr_len > 0)
1860 CHAR addrs[_countof(
msg->addr) * 64];
1862 for (
int i = 0; i < addr_len; ++i)
1866 addrs[offset++] =
',';
1868 if (
msg->family == AF_INET6)
1870 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1874 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1876 offset = strlen(addrs);
1885 wchar_t *tmp_iid = _wcsdup(iid);
1886 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1890 return ERROR_OUTOFMEMORY;
1895 if (
msg->domains[0])
1916 DWORD size =
sizeof(
dhcp);
1919 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1920 if (err != NO_ERROR)
1926 return dhcp ? TRUE : FALSE;
1940 const short families[] = { AF_INET, AF_INET6 };
1941 for (
int i = 0; i < _countof(families); i++)
1943 short family = families[i];
1950 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1951 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1958 addr_list[offset++] =
',';
1960 strcpy(addr_list + offset, addresses[j]);
1961 offset += strlen(addresses[j]);
1993 addrs[*size - 1] =
'\0';
1997 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
1998 if (err && err != ERROR_FILE_NOT_FOUND)
2008 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2016 if (strchr(addrs,
'.'))
2023 return ERROR_FILE_NOT_FOUND;
2038 addrs[*size - 1] =
'\0';
2042 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2043 if (err && err != ERROR_FILE_NOT_FOUND)
2052 IN6_ADDR in_addrs[8];
2053 DWORD in_addrs_size =
sizeof(in_addrs);
2054 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2055 (PBYTE)in_addrs, &in_addrs_size);
2064 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2065 for (
size_t i = 0; i < in_addrs_read; ++i)
2074 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2077 return ERROR_MORE_DATA;
2080 size_t addr_len = strlen(
pos);
2084 s = strlen(addrs) + 1;
2087 if (strchr(addrs,
':'))
2094 return ERROR_FILE_NOT_FOUND;
2109 PCWSTR match = list;
2112 match = wcsstr(match, domain);
2118 if ((match == list || *(match - 1) ==
',')
2119 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2153 if (domains == NULL || size == 0)
2155 return ERROR_INVALID_PARAMETER;
2158 LSTATUS err = ERROR_FILE_NOT_FOUND;
2159 const DWORD buf_size = *size;
2160 const size_t one_glyph =
sizeof(*domains);
2161 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2163 for (
int i = 0; values[i]; i++)
2166 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2167 if (!err && *size > one_glyph && wcschr(domains,
'.'))
2174 PWCHAR
pos = domains;
2175 const DWORD
buf_len = buf_size / one_glyph;
2179 PWCHAR comma = wcschr(
pos,
',');
2186 size_t domain_len = wcslen(
pos);
2199 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2205 size_t converted_size =
pos - domains;
2206 size_t domain_size = domain_len * one_glyph;
2207 size_t extra_size = 2 * one_glyph;
2208 if (converted_size + domain_size + extra_size > buf_size)
2212 *size = converted_size == 0 ? 0 : *size + 1;
2213 return ERROR_MORE_DATA;
2217 memmove(
pos + 1,
pos, buf_size - converted_size - one_glyph);
2225 *(
pos + domain_len) =
'\0';
2252 MIB_IF_ROW2 itf_row;
2255 if (IIDFromString(iid_str, &iid) != S_OK)
2263 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2269 if (GetIfEntry2(&itf_row) != NO_ERROR)
2275 if (itf_row.MediaConnectState == MediaConnectStateConnected
2276 && itf_row.OperStatus == IfOperStatusUp)
2297 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2298 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2306 DWORD enum_index = 0;
2307 while (i < data_size)
2309 WCHAR itf_guid[MAX_PATH];
2310 DWORD itf_guid_len = _countof(itf_guid);
2312 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2315 if (err != ERROR_NO_MORE_ITEMS)
2329 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2337 data[i].domains_size =
sizeof(
data[0].domains);
2338 memset(
data[i].domains, 0,
data[i].domains_size);
2342 if (err != ERROR_FILE_NOT_FOUND)
2351 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2353 if (err && err != ERROR_FILE_NOT_FOUND)
2356 __func__, itf_guid, err);
2361 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2362 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2366 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2369 __func__, itf_guid);
2373 RegCloseKey(v6_itf);
2374 if (err && err != ERROR_FILE_NOT_FOUND)
2377 __func__, itf_guid, err);
2382 if (v4_addrs_size || v6_addrs_size)
2385 for (
int j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2387 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2389 data[i].addresses[j] =
';';
2396 RegCloseKey(v4_itf);
2400 RegCloseKey(v6_itfs);
2401 RegCloseKey(v4_itfs);
2421 DWORD err = NO_ERROR;
2423 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2430 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2437 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2449 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2457 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2465 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2474 reg_val = dnssec ? 0x0000000A : 0x00000008;
2475 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2484 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2493 RegDeleteKeyW(nrpt_key, subkey);
2495 RegCloseKey(rule_key);
2516 for (
int i = 0; i < _countof(
data); ++i)
2526 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2549 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2551 DWORD err = NO_ERROR;
2552 PWSTR wide_domains = L
".\0";
2558 size_t domains_len = strlen(domains);
2559 dom_size = domains_len + 2;
2562 dom_size *=
sizeof(*wide_domains);
2565 return ERROR_OUTOFMEMORY;
2568 for (
size_t i = 0; i < domains_len; ++i)
2570 if (wide_domains[i] ==
',')
2572 wide_domains[i] = 0;
2578 PWSTR wide_search_domains;
2579 wide_search_domains =
utf8to16(search_domains);
2580 if (!wide_search_domains)
2582 return ERROR_OUTOFMEMORY;
2585 free(wide_search_domains);
2590 PSTR
pos = addr_list;
2597 strcpy(
pos, addresses[i]);
2601 WCHAR subkey[MAX_PATH];
2602 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2603 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2616#if defined(__GNUC__) || defined(__clang__)
2617#pragma GCC diagnostic pop
2637 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2638 static PCSTR sys_key =
2639 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2643 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2644 if (err == ERROR_FILE_NOT_FOUND)
2647 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2651 nrpt = INVALID_HANDLE_VALUE;
2685 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2686 pidlen = wcslen(pid_str);
2690 DWORD enum_index = 0;
2693 WCHAR name[MAX_PATH];
2694 DWORD namelen = _countof(name);
2695 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2698 if (err != ERROR_NO_MORE_ITEMS)
2706 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2707 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2712 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2720 return deleted ? TRUE : FALSE;
2758 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2763 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2768 if (
msg->iface.name[0] == 0)
2777 if (
msg->addresses[0][0] == 0)
2782 const char *rdom =
msg->resolve_domains;
2783 size_t rdom_size =
sizeof(
msg->resolve_domains);
2784 size_t rdom_len = strlen(rdom);
2785 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2791 BOOL gpol_nrpt = FALSE;
2792 BOOL gpol_list = FALSE;
2805 if (*undo_pid != ovpn_pid)
2808 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2809 "This is likely an error. Cleaning up anyway.",
2810 __func__, *undo_pid, ovpn_pid);
2834 PDWORD pid = malloc(
sizeof(ovpn_pid));
2837 err = ERROR_OUTOFMEMORY;
2843 err = ERROR_OUTOFMEMORY;
2865 if (
msg->search_domains[0])
2879 DWORD err = NO_ERROR;
2881 int addr_len =
msg->addr_len;
2884 if (addr_len > _countof(
msg->addr))
2886 addr_len = _countof(
msg->addr);
2889 if (!
msg->iface.index)
2912 for (
int i = 0; i < addr_len; ++i)
2914 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2925 int *if_index = malloc(
sizeof(
msg->iface.index));
2928 *if_index =
msg->iface.index;
2935 err = ERROR_OUTOFMEMORY;
2949 DWORD timeout = 5000;
2950 wchar_t argv0[MAX_PATH];
2953 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2958 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2963 size_t ncmdline = wcslen(fmt) + 10 + 1;
2964 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
2967 err = ERROR_OUTOFMEMORY;
2971 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
2987 MIB_IPINTERFACE_ROW ipiface;
2988 InitializeIpInterfaceEntry(&ipiface);
2989 ipiface.Family = mtu->
family;
2991 err = GetIpInterfaceEntry(&ipiface);
2992 if (err != NO_ERROR)
2996 if (mtu->
family == AF_INET)
2998 ipiface.SitePrefixLength = 0;
3000 ipiface.NlMtu = mtu->
mtu;
3002 err = SetIpInterfaceEntry(&ipiface);
3018 switch (
msg->adapter_type)
3025 hwid = L
"root\\tap0901";
3029 return ERROR_INVALID_PARAMETER;
3032 WCHAR cmd[MAX_PATH];
3033 WCHAR args[MAX_PATH];
3035 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3037 return ERROR_BUFFER_OVERFLOW;
3040 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3042 return ERROR_BUFFER_OVERFLOW;
3049HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3066 switch (
msg.header.type)
3070 if (
msg.header.size ==
sizeof(
msg.address))
3078 if (
msg.header.size ==
sizeof(
msg.route))
3085 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3093 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3111 DWORD ovpn_pid = proc_info->dwProcessId;
3122 if (
msg.header.size ==
sizeof(
msg.dhcp))
3129 if (
msg.header.size ==
sizeof(
msg.mtu))
3136 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3215 *pnext = item->
next;
3226 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3227 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3228 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3229 HANDLE stdin_read = NULL, stdin_write = NULL;
3230 HANDLE stdout_write = NULL;
3231 DWORD pipe_mode, len, exit_code = 0;
3233 STARTUPINFOW startup_info;
3234 PROCESS_INFORMATION proc_info;
3235 LPVOID user_env = NULL;
3236 WCHAR ovpn_pipe_name[256];
3239 WCHAR *cmdline = NULL;
3240 size_t cmdline_size;
3242 WCHAR errmsg[512] = L
"";
3244 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3245 .lpSecurityDescriptor = NULL,
3246 .bInheritHandle = TRUE };
3249 EXPLICIT_ACCESS ea[2];
3250 SECURITY_DESCRIPTOR ovpn_sd;
3251 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3252 .lpSecurityDescriptor = &ovpn_sd,
3253 .bInheritHandle = FALSE };
3255 ZeroMemory(&ea,
sizeof(ea));
3256 ZeroMemory(&startup_info,
sizeof(startup_info));
3257 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3258 ZeroMemory(&proc_info,
sizeof(proc_info));
3265 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3272 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3278 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3280 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3286 svc_user = malloc(len);
3287 if (svc_user == NULL)
3293 if (!IsValidSid(svc_user->User.Sid))
3299 if (!ImpersonateNamedPipeClient(pipe))
3304 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3310 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3312 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3318 ovpn_user = malloc(len);
3319 if (ovpn_user == NULL)
3325 if (!IsValidSid(ovpn_user->User.Sid))
3347 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3348 ea[0].grfAccessMode = SET_ACCESS;
3349 ea[0].grfInheritance = NO_INHERITANCE;
3350 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3351 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3352 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3353 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3354 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3355 ea[1].grfAccessMode = SET_ACCESS;
3356 ea[1].grfInheritance = NO_INHERITANCE;
3357 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3358 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3359 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3362 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3367 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3372 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3379 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3386 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3387 OPEN_EXISTING, 0, NULL);
3388 if (stdout_write == INVALID_HANDLE_VALUE)
3394 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3395 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3401 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3403 GetCurrentThreadId());
3404 ovpn_pipe = CreateNamedPipe(
3405 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3406 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
3407 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3413 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3414 OPEN_EXISTING, 0, NULL);
3415 if (svc_pipe == INVALID_HANDLE_VALUE)
3421 pipe_mode = PIPE_READMODE_MESSAGE;
3422 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3428 cmdline_size = wcslen(sud.
options) + 128;
3429 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3430 if (cmdline == NULL)
3438 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3439 (uintptr_t)svc_pipe);
3441 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3447 startup_info.cb =
sizeof(startup_info);
3448 startup_info.dwFlags = STARTF_USESTDHANDLES;
3449 startup_info.hStdInput = stdin_read;
3450 startup_info.hStdOutput = stdout_write;
3451 startup_info.hStdError = stdout_write;
3456 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3458 user_env, sud.
directory, &startup_info, &proc_info))
3464 if (!RevertToSelf())
3466 TerminateProcess(proc_info.hProcess, 1);
3477 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3479 if (input_size && (input = malloc(input_size)))
3482 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3483 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3500 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3508 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3509 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3510 if (exit_code == STILL_ACTIVE)
3512 TerminateProcess(proc_info.hProcess, 1);
3514 else if (exit_code != 0)
3517 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3523 FlushFileBuffers(pipe);
3524 DisconnectNamedPipe(pipe);
3529 DestroyEnvironmentBlock(user_env);
3550 SERVICE_STATUS *
status = ctx;
3553 case SERVICE_CONTROL_STOP:
3554 status->dwCurrentState = SERVICE_STOP_PENDING;
3562 case SERVICE_CONTROL_INTERROGATE:
3566 return ERROR_CALL_NOT_IMPLEMENTED;
3580 const WCHAR *sddlString =
3581 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)";
3583 PSECURITY_DESCRIPTOR sd = NULL;
3584 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3588 return INVALID_HANDLE_VALUE;
3592 SECURITY_ATTRIBUTES sa = { 0 };
3593 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3594 sa.lpSecurityDescriptor = sd;
3595 sa.bInheritHandle = FALSE;
3597 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3599 static BOOL first = TRUE;
3602 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3606 WCHAR pipe_name[256];
3608 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(PACKAGE) L
"%ls\\service",
3610 HANDLE pipe = CreateNamedPipe(
3611 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3612 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3616 if (pipe == INVALID_HANDLE_VALUE)
3619 return INVALID_HANDLE_VALUE;
3630 static DWORD size = 10;
3631 static LPHANDLE handles = NULL;
3634 if (handles == NULL)
3636 handles = malloc(size *
sizeof(HANDLE));
3637 *handles_ptr = handles;
3638 if (handles == NULL)
3640 return ERROR_OUTOFMEMORY;
3644 handles[
pos++] = io_event;
3657 tmp = realloc(handles, size *
sizeof(HANDLE));
3662 return ERROR_OUTOFMEMORY;
3665 *handles_ptr = handles;
3667 handles[
pos++] = threads->
data;
3668 threads = threads->
next;
3692 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3704 BOOL changed = FALSE;
3714 if (
key != INVALID_HANDLE_VALUE)
3732 HANDLE pipe, io_event = NULL;
3733 OVERLAPPED overlapped;
3734 DWORD error = NO_ERROR;
3736 PHANDLE handles = NULL;
3746 status.dwCurrentState = SERVICE_START_PENDING;
3747 status.dwServiceSpecificExitCode = NO_ERROR;
3748 status.dwWin32ExitCode = NO_ERROR;
3749 status.dwWaitHint = 3000;
3757 if (error != ERROR_SUCCESS)
3763 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3778 if (error != NO_ERROR)
3784 if (pipe == INVALID_HANDLE_VALUE)
3789 status.dwCurrentState = SERVICE_RUNNING;
3795 if (ConnectNamedPipe(pipe, &overlapped) == FALSE && GetLastError() != ERROR_PIPE_CONNECTED
3796 && GetLastError() != ERROR_IO_PENDING)
3802 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3803 if (error == WAIT_OBJECT_0)
3807 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3818 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3823 TerminateThread(thread, 1);
3829 ResumeThread(thread);
3843 if (error == WAIT_FAILED)
3873 status.dwCurrentState = SERVICE_STOPPED;
3874 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 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 netsh_wins_cmd(const wchar_t *action, int if_index, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_index [static] $addr.
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 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)