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;
222 DWORD res, bytes = 0;
223 OVERLAPPED overlapped;
224 LPHANDLE handles = NULL;
232 handles = malloc((count + 1) *
sizeof(HANDLE));
240 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
244 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
246 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
251 handles[0] = io_event;
252 for (i = 0; i < count; i++)
254 handles[i + 1] = events[i];
257 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
258 if (res != WAIT_OBJECT_0)
266 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
270 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
306 const WCHAR
msg[] = L
"Process ID";
307 WCHAR buf[22 + _countof(
msg)];
313 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
315 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
319ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
322 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
323 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
327 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
328 | FORMAT_MESSAGE_IGNORE_INSERTS,
329 0, error, 0, (LPWSTR)&args[2], 0, NULL);
332 result_len = FormatMessageW(
333 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
334 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
336 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
341 LocalFree((LPVOID)args[2]);
369 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
370 L
" that requires admin approval. This error may be avoided"
371 L
" by adding your account to the \"%ls\" group";
373 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
374 L
" only with admin approval. This error may be avoided"
375 L
" by adding your account to the \"%ls\" group";
381 swprintf(errmsg, capacity,
382 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
399 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
408 for (i = 0; i < argc; ++i)
417 if (wcscmp(L
"--config",
argv[i]) == 0 && argc - i > 1)
455 size = bytes /
sizeof(*data);
456 if ((size == 0) || (size > 4096))
463 data = malloc(bytes);
479 if (
data[size - 1] != 0)
497 len = wcslen(sud->
options) + 1;
526 SOCKADDR_INET sa_inet;
527 ZeroMemory(&sa_inet,
sizeof(sa_inet));
528 sa_inet.si_family = family;
529 if (family == AF_INET)
531 sa_inet.Ipv4.sin_addr = addr->
ipv4;
533 else if (family == AF_INET6)
535 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
544 LPWSTR wide_name =
utf8to16(iface_name);
548 status = ConvertInterfaceAliasToLuid(wide_name, luid);
553 status = ERROR_OUTOFMEMORY;
561 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
567 return DeleteUnicastIpAddressEntry(addr_row);
574 PMIB_UNICASTIPADDRESS_ROW addr_row;
577 addr_row = malloc(
sizeof(*addr_row));
578 if (addr_row == NULL)
580 return ERROR_OUTOFMEMORY;
583 InitializeUnicastIpAddressEntry(addr_row);
585 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
587 if (
msg->iface.index != -1)
589 addr_row->InterfaceIndex =
msg->iface.index;
599 addr_row->InterfaceLuid = luid;
604 err = CreateUnicastIpAddressEntry(addr_row);
639 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
645 return DeleteIpForwardEntry2(fwd_row);
652 PMIB_IPFORWARD_ROW2 fwd_row;
655 fwd_row = malloc(
sizeof(*fwd_row));
658 return ERROR_OUTOFMEMORY;
661 ZeroMemory(fwd_row,
sizeof(*fwd_row));
662 fwd_row->ValidLifetime = 0xffffffff;
663 fwd_row->PreferredLifetime = 0xffffffff;
664 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
665 fwd_row->Metric =
msg->metric;
667 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
670 if (
msg->iface.index != -1)
672 fwd_row->InterfaceIndex =
msg->iface.index;
674 else if (strlen(
msg->iface.name))
682 fwd_row->InterfaceLuid = luid;
687 err = CreateIpForwardEntry2(fwd_row);
723 if (
msg->family == AF_INET)
725 return FlushIpNetTable(
msg->iface.index);
728 return FlushIpNetTable2(
msg->family,
msg->iface.index);
742 err_str = L
"Unknown Win32 Error";
744 if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
745 NULL, err, 0, buf, _countof(buf), NULL))
792 HANDLE engine = NULL;
805 err = ERROR_OUTOFMEMORY;
808 block_data->
engine = engine;
809 block_data->
index =
msg->iface.index;
873ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
877 PROCESS_INFORMATION pi;
878 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
879 WCHAR *cmdline_dup = NULL;
881 ZeroMemory(&si,
sizeof(si));
882 ZeroMemory(&pi,
sizeof(pi));
887 cmdline_dup = _wcsdup(cmdline);
889 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
891 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
892 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
895 exit_code = GetLastError();
897 else if (exit_code == STILL_ACTIVE)
899 exit_code = WAIT_TIMEOUT;
902 TerminateProcess(pi.hProcess, exit_code);
903 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
915 CloseHandle(pi.hProcess);
916 CloseHandle(pi.hThread);
920 exit_code = GetLastError();
939 WCHAR ipcfg[MAX_PATH];
947 { ipcfg, L
"ipconfig /flushdns", timeout },
948 { ipcfg, L
"ipconfig /registerdns", timeout },
953 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
955 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
958 for (i = 0; i < _countof(cmds); ++i)
960 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
972 err = ERROR_SEM_TIMEOUT;
981 HANDLE thread = NULL;
984 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
997 err = GetLastError();
1016 int timeout = 30000;
1017 wchar_t argv0[MAX_PATH];
1018 wchar_t *cmdline = NULL;
1019 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1023 if (wcscmp(action, L
"delete") == 0)
1034 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1039 const wchar_t *fmt = L
"netsh interface ip %ls wins %d %ls %ls";
1042 size_t ncmdline = wcslen(fmt) + 11 + wcslen(action) + wcslen(addr)
1043 + wcslen(addr_static) + 32 + 1;
1044 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1047 err = ERROR_OUTOFMEMORY;
1051 swprintf(cmdline, ncmdline, fmt, action, if_index, addr_static, addr);
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)
1274 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
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 == 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 glyph_size =
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 > glyph_size && domains[(*size / glyph_size) - 1] ==
'\0' && wcschr(domains,
'.'))
2180 PWCHAR
pos = domains;
2181 const DWORD
buf_len = buf_size / glyph_size;
2185 PWCHAR comma = wcschr(
pos,
',');
2191 size_t domain_len = wcslen(
pos);
2192 size_t domain_size = domain_len * glyph_size;
2193 size_t converted_size = (
pos - domains) * glyph_size;
2201 memmove(
pos, comma + 1, buf_size - converted_size);
2202 *size -= domain_size + glyph_size;
2209 *size -= domain_size;
2210 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2216 domain_size += glyph_size;
2219 size_t extra_size = 2 * glyph_size;
2222 if (converted_size + domain_size + extra_size > buf_size)
2226 *size = converted_size == 0 ? 0 : converted_size + glyph_size;
2227 return ERROR_MORE_DATA;
2231 memmove(
pos + 1,
pos, buf_size - converted_size - glyph_size);
2234 *size += glyph_size;
2239 *(
pos + domain_len) =
'\0';
2240 *size += glyph_size;
2267 MIB_IF_ROW2 itf_row;
2270 if (IIDFromString(iid_str, &iid) != S_OK)
2278 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2284 if (GetIfEntry2(&itf_row) != NO_ERROR)
2290 if (itf_row.MediaConnectState == MediaConnectStateConnected
2291 && itf_row.OperStatus == IfOperStatusUp)
2312 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2313 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2321 DWORD enum_index = 0;
2322 while (i < data_size)
2324 WCHAR itf_guid[MAX_PATH];
2325 DWORD itf_guid_len = _countof(itf_guid);
2327 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2330 if (err != ERROR_NO_MORE_ITEMS)
2344 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2352 data[i].domains_size =
sizeof(
data[0].domains);
2353 memset(
data[i].domains, 0,
data[i].domains_size);
2357 if (err != ERROR_FILE_NOT_FOUND)
2366 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2368 if (err && err != ERROR_FILE_NOT_FOUND)
2371 __func__, itf_guid, err);
2376 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2377 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2381 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2384 __func__, itf_guid);
2388 RegCloseKey(v6_itf);
2389 if (err && err != ERROR_FILE_NOT_FOUND)
2392 __func__, itf_guid, err);
2397 if (v4_addrs_size || v6_addrs_size)
2400 for (
int j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2402 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2404 data[i].addresses[j] =
';';
2411 RegCloseKey(v4_itf);
2415 RegCloseKey(v6_itfs);
2416 RegCloseKey(v4_itfs);
2436 DWORD err = NO_ERROR;
2438 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2445 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2452 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2464 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2472 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2480 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2489 reg_val = dnssec ? 0x0000000A : 0x00000008;
2490 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2499 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2508 RegDeleteKeyW(nrpt_key, subkey);
2510 RegCloseKey(rule_key);
2531 for (
int i = 0; i < _countof(
data); ++i)
2541 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2564 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2566 DWORD err = NO_ERROR;
2567 PWSTR wide_domains = L
".\0";
2573 size_t domains_len = strlen(domains);
2574 dom_size = domains_len + 2;
2577 dom_size *=
sizeof(*wide_domains);
2580 return ERROR_OUTOFMEMORY;
2583 for (
size_t i = 0; i < domains_len; ++i)
2585 if (wide_domains[i] ==
',')
2587 wide_domains[i] = 0;
2593 PWSTR wide_search_domains;
2594 wide_search_domains =
utf8to16(search_domains);
2595 if (!wide_search_domains)
2597 return ERROR_OUTOFMEMORY;
2600 free(wide_search_domains);
2605 PSTR
pos = addr_list;
2612 strcpy(
pos, addresses[i]);
2616 WCHAR subkey[MAX_PATH];
2617 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2618 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2631#if defined(__GNUC__) || defined(__clang__)
2632#pragma GCC diagnostic pop
2652 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2653 static PCSTR sys_key =
2654 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2658 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2659 if (err == ERROR_FILE_NOT_FOUND)
2662 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2666 nrpt = INVALID_HANDLE_VALUE;
2700 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2701 pidlen = wcslen(pid_str);
2705 DWORD enum_index = 0;
2708 WCHAR name[MAX_PATH];
2709 DWORD namelen = _countof(name);
2710 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2713 if (err != ERROR_NO_MORE_ITEMS)
2721 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2722 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2727 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2735 return deleted ? TRUE : FALSE;
2773 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2778 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2783 if (
msg->iface.name[0] == 0)
2792 if (
msg->addresses[0][0] == 0)
2797 const char *rdom =
msg->resolve_domains;
2798 size_t rdom_size =
sizeof(
msg->resolve_domains);
2799 size_t rdom_len = strlen(rdom);
2800 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2806 BOOL gpol_nrpt = FALSE;
2807 BOOL gpol_list = FALSE;
2820 if (*undo_pid != ovpn_pid)
2823 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2824 "This is likely an error. Cleaning up anyway.",
2825 __func__, *undo_pid, ovpn_pid);
2849 PDWORD pid = malloc(
sizeof(ovpn_pid));
2852 err = ERROR_OUTOFMEMORY;
2858 err = ERROR_OUTOFMEMORY;
2880 if (
msg->search_domains[0])
2894 DWORD err = NO_ERROR;
2896 int addr_len =
msg->addr_len;
2899 if (addr_len > _countof(
msg->addr))
2901 addr_len = _countof(
msg->addr);
2904 if (!
msg->iface.index)
2927 for (
int i = 0; i < addr_len; ++i)
2929 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2940 int *if_index = malloc(
sizeof(
msg->iface.index));
2943 *if_index =
msg->iface.index;
2950 err = ERROR_OUTOFMEMORY;
2964 DWORD timeout = 5000;
2965 wchar_t argv0[MAX_PATH];
2968 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2973 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2978 size_t ncmdline = wcslen(fmt) + 10 + 1;
2979 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
2982 err = ERROR_OUTOFMEMORY;
2986 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3002 MIB_IPINTERFACE_ROW ipiface;
3003 InitializeIpInterfaceEntry(&ipiface);
3004 ipiface.Family = mtu->
family;
3006 err = GetIpInterfaceEntry(&ipiface);
3007 if (err != NO_ERROR)
3011 if (mtu->
family == AF_INET)
3013 ipiface.SitePrefixLength = 0;
3015 ipiface.NlMtu = mtu->
mtu;
3017 err = SetIpInterfaceEntry(&ipiface);
3033 switch (
msg->adapter_type)
3040 hwid = L
"root\\tap0901";
3044 return ERROR_INVALID_PARAMETER;
3047 WCHAR cmd[MAX_PATH];
3048 WCHAR args[MAX_PATH];
3050 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3052 return ERROR_BUFFER_OVERFLOW;
3055 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3057 return ERROR_BUFFER_OVERFLOW;
3064HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3081 switch (
msg.header.type)
3085 if (
msg.header.size ==
sizeof(
msg.address))
3093 if (
msg.header.size ==
sizeof(
msg.route))
3100 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3108 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3126 DWORD ovpn_pid = proc_info->dwProcessId;
3137 if (
msg.header.size ==
sizeof(
msg.dhcp))
3144 if (
msg.header.size ==
sizeof(
msg.mtu))
3151 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3230 *pnext = item->
next;
3241 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3242 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3243 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3244 HANDLE stdin_read = NULL, stdin_write = NULL;
3245 HANDLE stdout_write = NULL;
3246 DWORD pipe_mode, len, exit_code = 0;
3248 STARTUPINFOW startup_info;
3249 PROCESS_INFORMATION proc_info;
3250 LPVOID user_env = NULL;
3251 WCHAR ovpn_pipe_name[256];
3254 WCHAR *cmdline = NULL;
3255 size_t cmdline_size;
3257 WCHAR errmsg[512] = L
"";
3258 BOOL flush_pipe = TRUE;
3260 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3261 .lpSecurityDescriptor = NULL,
3262 .bInheritHandle = TRUE };
3265 EXPLICIT_ACCESS ea[2];
3266 SECURITY_DESCRIPTOR ovpn_sd;
3267 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3268 .lpSecurityDescriptor = &ovpn_sd,
3269 .bInheritHandle = FALSE };
3271 ZeroMemory(&ea,
sizeof(ea));
3272 ZeroMemory(&startup_info,
sizeof(startup_info));
3273 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3274 ZeroMemory(&proc_info,
sizeof(proc_info));
3282 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3289 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3295 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3297 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3303 svc_user = malloc(len);
3304 if (svc_user == NULL)
3310 if (!IsValidSid(svc_user->User.Sid))
3316 if (!ImpersonateNamedPipeClient(pipe))
3321 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3327 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3329 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3335 ovpn_user = malloc(len);
3336 if (ovpn_user == NULL)
3342 if (!IsValidSid(ovpn_user->User.Sid))
3364 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3365 ea[0].grfAccessMode = SET_ACCESS;
3366 ea[0].grfInheritance = NO_INHERITANCE;
3367 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3368 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3369 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3370 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3371 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3372 ea[1].grfAccessMode = SET_ACCESS;
3373 ea[1].grfInheritance = NO_INHERITANCE;
3374 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3375 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3376 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3379 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3384 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3389 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3396 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3403 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3404 OPEN_EXISTING, 0, NULL);
3405 if (stdout_write == INVALID_HANDLE_VALUE)
3411 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3412 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3419 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3420 if (rpc_stat != RPC_S_OK)
3426 RPC_WSTR pipe_uuid_str = NULL;
3427 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3428 if (rpc_stat != RPC_S_OK)
3433 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3435 GetCurrentThreadId(), pipe_uuid_str);
3436 RpcStringFree(&pipe_uuid_str);
3442 SECURITY_ATTRIBUTES sa;
3443 PSECURITY_DESCRIPTOR pSD = NULL;
3444 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3445 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3446 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3451 sa.nLength =
sizeof(sa);
3452 sa.lpSecurityDescriptor = pSD;
3453 sa.bInheritHandle = FALSE;
3455 ovpn_pipe = CreateNamedPipe(
3456 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3457 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3458 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3464 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3465 OPEN_EXISTING, 0, NULL);
3466 if (svc_pipe == INVALID_HANDLE_VALUE)
3472 pipe_mode = PIPE_READMODE_MESSAGE;
3473 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3479 cmdline_size = wcslen(sud.
options) + 128;
3480 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3481 if (cmdline == NULL)
3489 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3490 (uintptr_t)svc_pipe);
3492 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3498 startup_info.cb =
sizeof(startup_info);
3499 startup_info.dwFlags = STARTF_USESTDHANDLES;
3500 startup_info.hStdInput = stdin_read;
3501 startup_info.hStdOutput = stdout_write;
3502 startup_info.hStdError = stdout_write;
3507 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3509 user_env, sud.
directory, &startup_info, &proc_info))
3515 if (!RevertToSelf())
3517 TerminateProcess(proc_info.hProcess, 1);
3528 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3530 if (input_size && (input = malloc(input_size)))
3533 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3534 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3551 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3559 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3560 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3561 if (exit_code == STILL_ACTIVE)
3563 TerminateProcess(proc_info.hProcess, 1);
3565 else if (exit_code != 0)
3568 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3576 FlushFileBuffers(pipe);
3578 DisconnectNamedPipe(pipe);
3583 DestroyEnvironmentBlock(user_env);
3604 SERVICE_STATUS *
status = ctx;
3607 case SERVICE_CONTROL_STOP:
3608 status->dwCurrentState = SERVICE_STOP_PENDING;
3616 case SERVICE_CONTROL_INTERROGATE:
3620 return ERROR_CALL_NOT_IMPLEMENTED;
3634 const WCHAR *sddlString =
3635 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)";
3637 PSECURITY_DESCRIPTOR sd = NULL;
3638 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3642 return INVALID_HANDLE_VALUE;
3646 SECURITY_ATTRIBUTES sa = { 0 };
3647 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3648 sa.lpSecurityDescriptor = sd;
3649 sa.bInheritHandle = FALSE;
3651 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3653 static BOOL first = TRUE;
3656 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3660 WCHAR pipe_name[256];
3662 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(PACKAGE) L
"%ls\\service",
3664 HANDLE pipe = CreateNamedPipe(
3665 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3666 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3670 if (pipe == INVALID_HANDLE_VALUE)
3673 return INVALID_HANDLE_VALUE;
3684 static DWORD size = 10;
3685 static LPHANDLE handles = NULL;
3688 if (handles == NULL)
3690 handles = malloc(size *
sizeof(HANDLE));
3691 *handles_ptr = handles;
3692 if (handles == NULL)
3694 return ERROR_OUTOFMEMORY;
3698 handles[
pos++] = io_event;
3711 tmp = realloc(handles, size *
sizeof(HANDLE));
3716 return ERROR_OUTOFMEMORY;
3719 *handles_ptr = handles;
3721 handles[
pos++] = threads->
data;
3722 threads = threads->
next;
3746 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3758 BOOL changed = FALSE;
3768 if (
key != INVALID_HANDLE_VALUE)
3786 HANDLE pipe, io_event = NULL;
3787 OVERLAPPED overlapped;
3788 DWORD error = NO_ERROR;
3790 PHANDLE handles = NULL;
3800 status.dwCurrentState = SERVICE_START_PENDING;
3801 status.dwServiceSpecificExitCode = NO_ERROR;
3802 status.dwWin32ExitCode = NO_ERROR;
3803 status.dwWaitHint = 3000;
3811 if (error != ERROR_SUCCESS)
3817 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3832 if (error != NO_ERROR)
3838 if (pipe == INVALID_HANDLE_VALUE)
3843 status.dwCurrentState = SERVICE_RUNNING;
3849 if (!ConnectNamedPipe(pipe, &overlapped))
3851 DWORD connect_error = GetLastError();
3852 if (connect_error == ERROR_NO_DATA)
3859 DisconnectNamedPipe(pipe);
3863 else if (connect_error == ERROR_PIPE_CONNECTED)
3866 SetEvent(overlapped.hEvent);
3868 else if (connect_error != ERROR_IO_PENDING)
3875 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3876 if (error == WAIT_OBJECT_0)
3882 if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS)
3891 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3902 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3907 TerminateThread(thread, 1);
3913 ResumeThread(thread);
3927 if (error == WAIT_FAILED)
3957 status.dwCurrentState = SERVICE_STOPPED;
3958 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 PeekNamedPipeAsyncTimed(HANDLE pipe, DWORD count, LPHANDLE events)
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 DWORD DeleteWfpBlock(undo_lists_t *lists)
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 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)