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);
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)
1399 if (!list || wcslen(list) == 0)
1411 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1412 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1415 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1435 WCHAR list[2048] = { 0 };
1436 DWORD size =
sizeof(list);
1440 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1453 size_t listlen = (size /
sizeof(list[0])) - 1;
1454 size_t domlen = wcslen(domains);
1455 if (listlen + domlen + 2 > _countof(list))
1463 PWSTR
pos = list + listlen;
1465 wcsncpy(
pos + 1, domains, domlen + 1);
1469 wcsncpy(list, domains, wcslen(domains) + 1);
1472 size = (wcslen(list) + 1) *
sizeof(list[0]);
1473 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1500 DWORD size =
sizeof(list);
1502 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1505 if (err != ERROR_FILE_NOT_FOUND)
1513 size = (wcslen(list) + 1) *
sizeof(list[0]);
1514 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1521 RegDeleteValueA(
key,
"InitialSearchList");
1539 DWORD size =
sizeof(list);
1541 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1548 PWSTR dst = wcsstr(list, domains);
1556 size_t domlen = wcslen(domains);
1557 PCWSTR src = dst + domlen;
1559 dst = dst > list ? dst - 1 : dst;
1560 wmemmove(dst, src, domlen);
1562 size_t list_len = wcslen(list);
1566 WCHAR initial[2048];
1567 size =
sizeof(initial);
1568 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1577 if (wcsncmp(list, initial, wcslen(list)) == 0)
1584 size = (list_len + 1) *
sizeof(list[0]);
1585 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1601 HKEY dns_searchlist_key;
1603 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1606 RegCloseKey(dns_searchlist_key);
1638 DWORD err = ERROR_OUTOFMEMORY;
1642 if (list_key == INVALID_HANDLE_VALUE)
1645 return ERROR_FILE_NOT_FOUND;
1659 if (domains && *domains)
1661 wchar_t *wide_domains =
utf8to16(domains);
1667 undo_data = malloc(
sizeof(*undo_data));
1671 wide_domains = NULL;
1675 undo_data->
domains = wide_domains;
1691 RegCloseKey(list_key);
1705 PCSTR itfs_key = family == AF_INET6
1706 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1707 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1709 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1712 *
key = INVALID_HANDLE_VALUE;
1714 __func__, family, err);
1717 return err ? FALSE : TRUE;
1737 return ERROR_FILE_NOT_FOUND;
1740 HKEY itf = INVALID_HANDLE_VALUE;
1741 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1745 __func__, itf_id, family, err);
1749 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1753 __func__, value, itf_id, family, err);
1757 if (itf != INVALID_HANDLE_VALUE)
1761 if (itfs != INVALID_HANDLE_VALUE)
1802 int addr_len =
msg->addr_len;
1805 const size_t max_addrs = _countof(
msg->addr);
1806 if (addr_len > max_addrs)
1808 addr_len = max_addrs;
1811 if (!
msg->iface.name[0])
1820 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1821 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1847 if (
msg->domains[0])
1856 if (
msg->addr_len > 0)
1861 CHAR addrs[_countof(
msg->addr) * 64];
1863 for (
int i = 0;
i < addr_len; ++
i)
1867 addrs[offset++] =
',';
1869 if (
msg->family == AF_INET6)
1871 RtlIpv6AddressToStringA(&
msg->addr[
i].ipv6, addrs + offset);
1875 RtlIpv4AddressToStringA(&
msg->addr[
i].ipv4, addrs + offset);
1877 offset += strlen(addrs);
1886 wchar_t *tmp_iid = _wcsdup(iid);
1887 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1891 return ERROR_OUTOFMEMORY;
1896 if (
msg->domains[0])
1917 DWORD size =
sizeof(
dhcp);
1920 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1921 if (err != NO_ERROR)
1927 return dhcp ? TRUE : FALSE;
1941 const short families[] = { AF_INET, AF_INET6 };
1942 for (
int i = 0;
i < _countof(families);
i++)
1944 short family = families[
i];
1951 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1952 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1959 addr_list[offset++] =
',';
1961 strcpy(addr_list + offset, addresses[j]);
1962 offset += strlen(addresses[j]);
1994 addrs[*size - 1] =
'\0';
1998 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
1999 if (err && err != ERROR_FILE_NOT_FOUND)
2009 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2017 if (strchr(addrs,
'.'))
2024 return ERROR_FILE_NOT_FOUND;
2039 addrs[*size - 1] =
'\0';
2043 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2044 if (err && err != ERROR_FILE_NOT_FOUND)
2053 IN6_ADDR in_addrs[8];
2054 DWORD in_addrs_size =
sizeof(in_addrs);
2055 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2056 (PBYTE)in_addrs, &in_addrs_size);
2065 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2066 for (
size_t i = 0;
i < in_addrs_read; ++
i)
2075 if (inet_ntop(AF_INET6, &in_addrs[
i],
pos, s) != NULL)
2078 return ERROR_MORE_DATA;
2081 size_t addr_len = strlen(
pos);
2085 s = strlen(addrs) + 1;
2088 if (strchr(addrs,
':'))
2095 return ERROR_FILE_NOT_FOUND;
2110 PCWSTR match = list;
2113 match = wcsstr(match, domain);
2119 if ((match == list || *(match - 1) ==
',')
2120 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2154 if (domains == NULL || size == 0)
2156 return ERROR_INVALID_PARAMETER;
2159 LSTATUS err = ERROR_FILE_NOT_FOUND;
2160 const DWORD buf_size = *size;
2161 const size_t one_glyph =
sizeof(*domains);
2162 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2164 for (
int i = 0; values[
i];
i++)
2167 err = RegGetValueW(itf, NULL, values[
i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2168 if (!err && *size > one_glyph && wcschr(domains,
'.'))
2175 PWCHAR
pos = domains;
2176 const DWORD
buf_len = buf_size / one_glyph;
2180 PWCHAR comma = wcschr(
pos,
',');
2187 size_t domain_len = wcslen(
pos);
2200 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2206 size_t converted_size =
pos - domains;
2207 size_t domain_size = domain_len * one_glyph;
2208 size_t extra_size = 2 * one_glyph;
2209 if (converted_size + domain_size + extra_size > buf_size)
2213 *size = converted_size == 0 ? 0 : *size + 1;
2214 return ERROR_MORE_DATA;
2218 memmove(
pos + 1,
pos, buf_size - converted_size - one_glyph);
2226 *(
pos + domain_len) =
'\0';
2253 MIB_IF_ROW2 itf_row;
2256 if (IIDFromString(iid_str, &iid) != S_OK)
2264 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2270 if (GetIfEntry2(&itf_row) != NO_ERROR)
2276 if (itf_row.MediaConnectState == MediaConnectStateConnected
2277 && itf_row.OperStatus == IfOperStatusUp)
2298 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2299 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2307 DWORD enum_index = 0;
2308 while (
i < data_size)
2310 WCHAR itf_guid[MAX_PATH];
2311 DWORD itf_guid_len = _countof(itf_guid);
2313 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2316 if (err != ERROR_NO_MORE_ITEMS)
2330 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2338 data[
i].domains_size =
sizeof(
data[0].domains);
2339 memset(
data[
i].domains, 0,
data[
i].domains_size);
2343 if (err != ERROR_FILE_NOT_FOUND)
2352 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2354 if (err && err != ERROR_FILE_NOT_FOUND)
2357 __func__, itf_guid, err);
2362 PSTR v6_addrs =
data[
i].addresses + v4_addrs_size;
2363 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2367 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2370 __func__, itf_guid);
2374 RegCloseKey(v6_itf);
2375 if (err && err != ERROR_FILE_NOT_FOUND)
2378 __func__, itf_guid, err);
2383 if (v4_addrs_size || v6_addrs_size)
2386 for (
int j = 0; j <
sizeof(
data[0].addresses) &&
data[
i].addresses[j]; j++)
2388 if (
data[
i].addresses[j] ==
',' ||
data[
i].addresses[j] ==
' ')
2390 data[
i].addresses[j] =
';';
2397 RegCloseKey(v4_itf);
2401 RegCloseKey(v6_itfs);
2402 RegCloseKey(v4_itfs);
2422 DWORD err = NO_ERROR;
2424 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2431 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2438 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2450 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2458 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2466 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2475 reg_val = dnssec ? 0x0000000A : 0x00000008;
2476 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2485 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2494 RegDeleteKeyW(nrpt_key, subkey);
2496 RegCloseKey(rule_key);
2517 for (
int i = 0;
i < _countof(
data); ++
i)
2527 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2550 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2552 DWORD err = NO_ERROR;
2553 PWSTR wide_domains = L
".\0";
2559 size_t domains_len = strlen(domains);
2560 dom_size = domains_len + 2;
2563 dom_size *=
sizeof(*wide_domains);
2566 return ERROR_OUTOFMEMORY;
2569 for (
size_t i = 0;
i < domains_len; ++
i)
2571 if (wide_domains[
i] ==
',')
2573 wide_domains[
i] = 0;
2579 PWSTR wide_search_domains;
2580 wide_search_domains =
utf8to16(search_domains);
2581 if (!wide_search_domains)
2583 return ERROR_OUTOFMEMORY;
2586 free(wide_search_domains);
2591 PSTR
pos = addr_list;
2598 strcpy(
pos, addresses[
i]);
2602 WCHAR subkey[MAX_PATH];
2603 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2604 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2634 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2635 static PCSTR sys_key =
2636 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2640 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2641 if (err == ERROR_FILE_NOT_FOUND)
2644 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2648 nrpt = INVALID_HANDLE_VALUE;
2682 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2683 pidlen = wcslen(pid_str);
2687 DWORD enum_index = 0;
2690 WCHAR name[MAX_PATH];
2691 DWORD namelen = _countof(name);
2692 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2695 if (err != ERROR_NO_MORE_ITEMS)
2703 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2704 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2709 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2717 return deleted ? TRUE : FALSE;
2755 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2760 msgptr->
addresses[
i][_countof(
msg->addresses[0]) - 1] =
'\0';
2765 if (
msg->iface.name[0] == 0)
2774 if (
msg->addresses[0][0] == 0)
2779 const char *rdom =
msg->resolve_domains;
2780 size_t rdom_size =
sizeof(
msg->resolve_domains);
2781 size_t rdom_len = strlen(rdom);
2782 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2788 BOOL gpol_nrpt = FALSE;
2789 BOOL gpol_list = FALSE;
2802 if (*undo_pid != ovpn_pid)
2805 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2806 "This is likely an error. Cleaning up anyway.",
2807 __func__, *undo_pid, ovpn_pid);
2831 PDWORD pid = malloc(
sizeof(ovpn_pid));
2834 err = ERROR_OUTOFMEMORY;
2840 err = ERROR_OUTOFMEMORY;
2862 if (
msg->search_domains[0])
2878 int addr_len =
msg->addr_len;
2881 if (addr_len > _countof(
msg->addr))
2883 addr_len = _countof(
msg->addr);
2886 if (!
msg->iface.name[0])
2895 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2901 return ERROR_OUTOFMEMORY;
2922 for (
int i = 0;
i < addr_len; ++
i)
2924 RtlIpv4AddressToStringW(&
msg->addr[
i].ipv4, addr);
2939 wchar_t *tmp_name = _wcsdup(wide_name);
2944 err = ERROR_OUTOFMEMORY;
2958 DWORD timeout = 5000;
2959 wchar_t argv0[MAX_PATH];
2962 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2967 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2972 size_t ncmdline = wcslen(fmt) + 10 + 1;
2973 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
2976 err = ERROR_OUTOFMEMORY;
2980 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
2996 MIB_IPINTERFACE_ROW ipiface;
2997 InitializeIpInterfaceEntry(&ipiface);
2998 ipiface.Family = mtu->
family;
3000 err = GetIpInterfaceEntry(&ipiface);
3001 if (err != NO_ERROR)
3005 if (mtu->
family == AF_INET)
3007 ipiface.SitePrefixLength = 0;
3009 ipiface.NlMtu = mtu->
mtu;
3011 err = SetIpInterfaceEntry(&ipiface);
3027 switch (
msg->adapter_type)
3034 hwid = L
"root\\tap0901";
3038 return ERROR_INVALID_PARAMETER;
3041 WCHAR cmd[MAX_PATH];
3042 WCHAR args[MAX_PATH];
3044 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3046 return ERROR_BUFFER_OVERFLOW;
3049 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3051 return ERROR_BUFFER_OVERFLOW;
3058HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3075 switch (
msg.header.type)
3079 if (
msg.header.size ==
sizeof(
msg.address))
3087 if (
msg.header.size ==
sizeof(
msg.route))
3094 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3102 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3120 DWORD ovpn_pid = proc_info->dwProcessId;
3131 if (
msg.header.size ==
sizeof(
msg.dhcp))
3138 if (
msg.header.size ==
sizeof(
msg.mtu))
3145 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3224 *pnext = item->
next;
3235 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3236 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3237 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3238 HANDLE stdin_read = NULL, stdin_write = NULL;
3239 HANDLE stdout_write = NULL;
3240 DWORD pipe_mode, len, exit_code = 0;
3242 STARTUPINFOW startup_info;
3243 PROCESS_INFORMATION proc_info;
3244 LPVOID user_env = NULL;
3245 WCHAR ovpn_pipe_name[256];
3248 WCHAR *cmdline = NULL;
3249 size_t cmdline_size;
3251 WCHAR errmsg[512] = L
"";
3253 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3254 .lpSecurityDescriptor = NULL,
3255 .bInheritHandle = TRUE };
3258 EXPLICIT_ACCESS ea[2];
3259 SECURITY_DESCRIPTOR ovpn_sd;
3260 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3261 .lpSecurityDescriptor = &ovpn_sd,
3262 .bInheritHandle = FALSE };
3264 ZeroMemory(&ea,
sizeof(ea));
3265 ZeroMemory(&startup_info,
sizeof(startup_info));
3266 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3267 ZeroMemory(&proc_info,
sizeof(proc_info));
3274 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3281 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3287 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3289 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3295 svc_user = malloc(len);
3296 if (svc_user == NULL)
3302 if (!IsValidSid(svc_user->User.Sid))
3308 if (!ImpersonateNamedPipeClient(pipe))
3313 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3319 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3321 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3327 ovpn_user = malloc(len);
3328 if (ovpn_user == NULL)
3334 if (!IsValidSid(ovpn_user->User.Sid))
3356 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3357 ea[0].grfAccessMode = SET_ACCESS;
3358 ea[0].grfInheritance = NO_INHERITANCE;
3359 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3360 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3361 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3362 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3363 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3364 ea[1].grfAccessMode = SET_ACCESS;
3365 ea[1].grfInheritance = NO_INHERITANCE;
3366 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3367 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3368 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3371 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3376 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3381 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3388 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3395 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3396 OPEN_EXISTING, 0, NULL);
3397 if (stdout_write == INVALID_HANDLE_VALUE)
3403 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3404 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3410 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3412 GetCurrentThreadId());
3413 ovpn_pipe = CreateNamedPipe(
3414 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3415 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
3416 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3422 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3423 OPEN_EXISTING, 0, NULL);
3424 if (svc_pipe == INVALID_HANDLE_VALUE)
3430 pipe_mode = PIPE_READMODE_MESSAGE;
3431 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3437 cmdline_size = wcslen(sud.
options) + 128;
3438 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3439 if (cmdline == NULL)
3447 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3448 (uintptr_t)svc_pipe);
3450 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3456 startup_info.cb =
sizeof(startup_info);
3457 startup_info.dwFlags = STARTF_USESTDHANDLES;
3458 startup_info.hStdInput = stdin_read;
3459 startup_info.hStdOutput = stdout_write;
3460 startup_info.hStdError = stdout_write;
3465 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3467 user_env, sud.
directory, &startup_info, &proc_info))
3473 if (!RevertToSelf())
3475 TerminateProcess(proc_info.hProcess, 1);
3486 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3488 if (input_size && (input = malloc(input_size)))
3491 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3492 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3509 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3517 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3518 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3519 if (exit_code == STILL_ACTIVE)
3521 TerminateProcess(proc_info.hProcess, 1);
3523 else if (exit_code != 0)
3526 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3532 FlushFileBuffers(pipe);
3533 DisconnectNamedPipe(pipe);
3538 DestroyEnvironmentBlock(user_env);
3559 SERVICE_STATUS *
status = ctx;
3562 case SERVICE_CONTROL_STOP:
3563 status->dwCurrentState = SERVICE_STOP_PENDING;
3571 case SERVICE_CONTROL_INTERROGATE:
3575 return ERROR_CALL_NOT_IMPLEMENTED;
3589 const WCHAR *sddlString =
3590 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)";
3592 PSECURITY_DESCRIPTOR sd = NULL;
3593 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3597 return INVALID_HANDLE_VALUE;
3601 SECURITY_ATTRIBUTES sa = { 0 };
3602 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3603 sa.lpSecurityDescriptor = sd;
3604 sa.bInheritHandle = FALSE;
3606 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3608 static BOOL first = TRUE;
3611 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3615 WCHAR pipe_name[256];
3617 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(PACKAGE) L
"%ls\\service",
3619 HANDLE pipe = CreateNamedPipe(
3620 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3621 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3625 if (pipe == INVALID_HANDLE_VALUE)
3628 return INVALID_HANDLE_VALUE;
3639 static DWORD size = 10;
3640 static LPHANDLE handles = NULL;
3643 if (handles == NULL)
3645 handles = malloc(size *
sizeof(HANDLE));
3646 *handles_ptr = handles;
3647 if (handles == NULL)
3649 return ERROR_OUTOFMEMORY;
3653 handles[
pos++] = io_event;
3666 tmp = realloc(handles, size *
sizeof(HANDLE));
3671 return ERROR_OUTOFMEMORY;
3674 *handles_ptr = handles;
3676 handles[
pos++] = threads->
data;
3677 threads = threads->
next;
3701 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3713 BOOL changed = FALSE;
3723 if (
key != INVALID_HANDLE_VALUE)
3741 HANDLE pipe, io_event = NULL;
3742 OVERLAPPED overlapped;
3743 DWORD error = NO_ERROR;
3745 PHANDLE handles = NULL;
3755 status.dwCurrentState = SERVICE_START_PENDING;
3756 status.dwServiceSpecificExitCode = NO_ERROR;
3757 status.dwWin32ExitCode = NO_ERROR;
3758 status.dwWaitHint = 3000;
3766 if (error != ERROR_SUCCESS)
3772 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3787 if (error != NO_ERROR)
3793 if (pipe == INVALID_HANDLE_VALUE)
3798 status.dwCurrentState = SERVICE_RUNNING;
3804 if (ConnectNamedPipe(pipe, &overlapped) == FALSE && GetLastError() != ERROR_PIPE_CONNECTED
3805 && GetLastError() != ERROR_IO_PENDING)
3811 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3812 if (error == WAIT_OBJECT_0)
3816 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3827 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3832 TerminateThread(thread, 1);
3838 ResumeThread(thread);
3852 if (error == WAIT_FAILED)
3882 status.dwCurrentState = SERVICE_STOPPED;
3883 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)