37#include <versionhelpers.h>
43#define IO_TIMEOUT 2000
45#define ERROR_OPENVPN_STARTUP 0x20000000
46#define ERROR_STARTUP_DATA 0x20000001
47#define ERROR_MESSAGE_DATA 0x20000002
48#define ERROR_MESSAGE_TYPE 0x20000003
51static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
55#define RDNS_TIMEOUT 600
57#define TUN_IOCTL_REGISTER_RINGS \
58 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
137 if (new_item == NULL)
139 return ERROR_OUTOFMEMORY;
142 new_item->
next = *pfirst;
157 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
160 if (!match(item->
data, ctx))
178 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
180 CloseHandle(*handle);
181 *handle = INVALID_HANDLE_VALUE;
183 return INVALID_HANDLE_VALUE;
189 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
190 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
191 return overlapped->hEvent;
197 HANDLE io_event = overlapped->hEvent;
198 if (!ResetEvent(io_event))
202 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
203 overlapped->hEvent = io_event;
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);
1250#if defined(__GNUC__) || defined(__clang__)
1251#pragma GCC diagnostic push
1252#pragma GCC diagnostic ignored "-Wsign-compare"
1272 DWORD size =
sizeof(
data);
1273 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1274 if (!err || err == ERROR_MORE_DATA)
1277 for (
size_t i = 0; i < strlen(
data); ++i)
1279 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1313 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1314 0, KEY_ALL_ACCESS,
key);
1327 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1328 0, KEY_ALL_ACCESS,
key);
1347 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1348 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1349 0, KEY_ALL_ACCESS, &itfs);
1352 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1362 *
key = INVALID_HANDLE_VALUE;
1378 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1381 if (err == ERROR_FILE_NOT_FOUND)
1398 size_t length = (wcslen(
string) + 1) *
sizeof(
wchar_t);
1399 if (length > UINT_MAX)
1403 return (DWORD)length;
1419 if (!list || wcslen(list) == 0)
1432 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1435 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1455 WCHAR list[2048] = { 0 };
1456 DWORD size =
sizeof(list);
1460 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1473 size_t listlen = (size /
sizeof(list[0])) - 1;
1474 size_t domlen = wcslen(domains);
1475 if (listlen + domlen + 2 > _countof(list))
1483 PWSTR
pos = list + listlen;
1485 wcsncpy(
pos + 1, domains, domlen + 1);
1489 wcsncpy(list, domains, wcslen(domains) + 1);
1493 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1520 DWORD size =
sizeof(list);
1522 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1525 if (err != ERROR_FILE_NOT_FOUND)
1534 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1541 RegDeleteValueA(
key,
"InitialSearchList");
1559 DWORD size =
sizeof(list);
1561 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1568 PWSTR dst = wcsstr(list, domains);
1576 size_t domlen = wcslen(domains);
1577 PCWSTR src = dst + domlen;
1579 dst = dst > list ? dst - 1 : dst;
1580 wmemmove(dst, src, domlen);
1582 size_t list_len = wcslen(list);
1586 WCHAR initial[2048];
1587 size =
sizeof(initial);
1588 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1597 if (wcsncmp(list, initial, list_len) == 0)
1605 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1621 HKEY dns_searchlist_key;
1623 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1626 RegCloseKey(dns_searchlist_key);
1658 DWORD err = ERROR_OUTOFMEMORY;
1662 if (list_key == INVALID_HANDLE_VALUE)
1665 return ERROR_FILE_NOT_FOUND;
1679 if (domains && *domains)
1681 wchar_t *wide_domains =
utf8to16(domains);
1687 undo_data = malloc(
sizeof(*undo_data));
1691 wide_domains = NULL;
1695 undo_data->
domains = wide_domains;
1711 RegCloseKey(list_key);
1725 PCSTR itfs_key = family == AF_INET6
1726 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1727 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1729 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1732 *
key = INVALID_HANDLE_VALUE;
1734 __func__, family, err);
1737 return err ? FALSE : TRUE;
1757 return ERROR_FILE_NOT_FOUND;
1760 HKEY itf = INVALID_HANDLE_VALUE;
1761 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1765 __func__, itf_id, family, err);
1769 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, (DWORD)strlen(value) + 1);
1773 __func__, value, itf_id, family, err);
1777 if (itf != INVALID_HANDLE_VALUE)
1781 if (itfs != INVALID_HANDLE_VALUE)
1822 int addr_len =
msg->addr_len;
1825 const int max_addrs = _countof(
msg->addr);
1826 if (addr_len > max_addrs)
1828 addr_len = max_addrs;
1831 if (!
msg->iface.name[0])
1840 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1841 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1867 if (
msg->domains[0])
1876 if (
msg->addr_len > 0)
1881 CHAR addrs[_countof(
msg->addr) * 64];
1883 for (
int i = 0; i < addr_len; ++i)
1887 addrs[offset++] =
',';
1889 if (
msg->family == AF_INET6)
1891 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1895 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1897 offset = strlen(addrs);
1906 wchar_t *tmp_iid = _wcsdup(iid);
1907 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1911 return ERROR_OUTOFMEMORY;
1916 if (
msg->domains[0])
1937 DWORD size =
sizeof(
dhcp);
1940 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1941 if (err != NO_ERROR)
1947 return dhcp ? TRUE : FALSE;
1961 const short families[] = { AF_INET, AF_INET6 };
1962 for (
size_t i = 0; i < _countof(families); i++)
1964 short family = families[i];
1971 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1972 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1979 addr_list[offset++] =
',';
1981 strcpy(addr_list + offset, addresses[j]);
1982 offset += strlen(addresses[j]);
2014 addrs[*size - 1] =
'\0';
2018 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2019 if (err && err != ERROR_FILE_NOT_FOUND)
2029 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2037 if (strchr(addrs,
'.'))
2044 return ERROR_FILE_NOT_FOUND;
2059 addrs[*size - 1] =
'\0';
2063 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2064 if (err && err != ERROR_FILE_NOT_FOUND)
2073 IN6_ADDR in_addrs[8];
2074 DWORD in_addrs_size =
sizeof(in_addrs);
2075 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2076 (PBYTE)in_addrs, &in_addrs_size);
2085 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2086 for (
size_t i = 0; i < in_addrs_read; ++i)
2095 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2098 return ERROR_MORE_DATA;
2101 size_t addr_len = strlen(
pos);
2103 s -= (DWORD)addr_len;
2105 s = (DWORD)strlen(addrs) + 1;
2108 if (strchr(addrs,
':'))
2115 return ERROR_FILE_NOT_FOUND;
2130 PCWSTR match = list;
2133 match = wcsstr(match, domain);
2139 if ((match == list || *(match - 1) ==
',')
2140 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2174 const DWORD glyph_size =
sizeof(*domains);
2175 const DWORD
buf_len = buf_size / glyph_size;
2182 PWCHAR
pos = domains;
2186 PWCHAR comma = wcschr(
pos,
',');
2192 DWORD domain_len = (DWORD)wcslen(
pos);
2193 DWORD domain_size = domain_len * glyph_size;
2194 DWORD converted_size = (DWORD)(
pos - domains) * glyph_size;
2202 memmove(
pos, comma + 1, buf_size - converted_size);
2203 *size -= domain_size + glyph_size;
2210 *size -= domain_size;
2211 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2217 domain_size += glyph_size;
2220 const DWORD extra_size = 2 * glyph_size;
2223 if (converted_size + domain_size + extra_size > buf_size)
2227 *size = converted_size == 0 ? 0 : converted_size + glyph_size;
2228 return ERROR_MORE_DATA;
2232 memmove(
pos + 1,
pos, buf_size - converted_size - glyph_size);
2235 *size += glyph_size;
2240 *(
pos + domain_len) =
'\0';
2241 *size += glyph_size;
2274 if (domains == NULL || size == NULL || *size == 0)
2276 return ERROR_INVALID_PARAMETER;
2279 LSTATUS err = ERROR_FILE_NOT_FOUND;
2280 const DWORD buf_size = *size;
2281 const DWORD glyph_size =
sizeof(*domains);
2282 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2284 for (
int i = 0; values[i]; i++)
2287 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2288 if (!err && *size > glyph_size && domains[(*size / glyph_size) - 1] ==
'\0' && wcschr(domains,
'.'))
2311 MIB_IF_ROW2 itf_row;
2314 if (IIDFromString(iid_str, &iid) != S_OK)
2322 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2328 if (GetIfEntry2(&itf_row) != NO_ERROR)
2334 if (itf_row.MediaConnectState == MediaConnectStateConnected
2335 && itf_row.OperStatus == IfOperStatusUp)
2356 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2357 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2365 DWORD enum_index = 0;
2366 while (i < data_size)
2368 WCHAR itf_guid[MAX_PATH];
2369 DWORD itf_guid_len = _countof(itf_guid);
2371 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2374 if (err != ERROR_NO_MORE_ITEMS)
2388 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2396 data[i].domains_size =
sizeof(
data[0].domains);
2397 memset(
data[i].domains, 0,
data[i].domains_size);
2401 if (err != ERROR_FILE_NOT_FOUND)
2410 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2412 if (err && err != ERROR_FILE_NOT_FOUND)
2415 __func__, itf_guid, err);
2420 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2421 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2425 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2428 __func__, itf_guid);
2432 RegCloseKey(v6_itf);
2433 if (err && err != ERROR_FILE_NOT_FOUND)
2436 __func__, itf_guid, err);
2441 if (v4_addrs_size || v6_addrs_size)
2444 for (
size_t j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2446 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2448 data[i].addresses[j] =
';';
2455 RegCloseKey(v4_itf);
2459 RegCloseKey(v6_itfs);
2460 RegCloseKey(v4_itfs);
2480 DWORD err = NO_ERROR;
2482 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2489 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2496 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2508 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2516 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2524 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2533 reg_val = dnssec ? 0x0000000A : 0x00000008;
2534 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2543 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2552 RegDeleteKeyW(nrpt_key, subkey);
2554 RegCloseKey(rule_key);
2575 for (
size_t i = 0; i < _countof(
data); ++i)
2585 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2608 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2610 DWORD err = NO_ERROR;
2611 PWSTR wide_domains = L
".\0";
2617 size_t domains_len = strlen(domains);
2618 dom_size = (DWORD)domains_len + 2;
2621 dom_size *=
sizeof(*wide_domains);
2624 return ERROR_OUTOFMEMORY;
2627 for (
size_t i = 0; i < domains_len; ++i)
2629 if (wide_domains[i] ==
',')
2631 wide_domains[i] = 0;
2637 PWSTR wide_search_domains;
2638 wide_search_domains =
utf8to16(search_domains);
2639 if (!wide_search_domains)
2641 return ERROR_OUTOFMEMORY;
2644 free(wide_search_domains);
2649 PSTR
pos = addr_list;
2656 strcpy(
pos, addresses[i]);
2660 WCHAR subkey[MAX_PATH];
2661 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2662 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2692 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2693 static PCSTR sys_key =
2694 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2698 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2699 if (err == ERROR_FILE_NOT_FOUND)
2702 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2706 nrpt = INVALID_HANDLE_VALUE;
2740 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2741 pidlen = wcslen(pid_str);
2745 DWORD enum_index = 0;
2748 WCHAR name[MAX_PATH];
2749 DWORD namelen = _countof(name);
2750 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2753 if (err != ERROR_NO_MORE_ITEMS)
2761 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2762 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2767 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2775 return deleted ? TRUE : FALSE;
2813 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2818 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2823 if (
msg->iface.name[0] == 0)
2832 if (
msg->addresses[0][0] == 0)
2837 const char *rdom =
msg->resolve_domains;
2838 size_t rdom_size =
sizeof(
msg->resolve_domains);
2839 size_t rdom_len = strlen(rdom);
2840 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2846 BOOL gpol_nrpt = FALSE;
2847 BOOL gpol_list = FALSE;
2860 if (*undo_pid != ovpn_pid)
2863 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2864 "This is likely an error. Cleaning up anyway.",
2865 __func__, *undo_pid, ovpn_pid);
2889 PDWORD pid = malloc(
sizeof(ovpn_pid));
2892 err = ERROR_OUTOFMEMORY;
2898 err = ERROR_OUTOFMEMORY;
2918 if (
msg->search_domains[0] || !
msg->resolve_domains[0])
2928 if (
msg->search_domains[0])
2942 DWORD err = NO_ERROR;
2944 int addr_len =
msg->addr_len;
2947 if (addr_len > _countof(
msg->addr))
2949 addr_len = _countof(
msg->addr);
2952 if (!
msg->iface.index)
2975 for (
int i = 0; i < addr_len; ++i)
2977 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2988 int *if_index = malloc(
sizeof(
msg->iface.index));
2991 *if_index =
msg->iface.index;
2998 err = ERROR_OUTOFMEMORY;
3008#if defined(__GNUC__) || defined(__clang__)
3009#pragma GCC diagnostic pop
3016 DWORD timeout = 5000;
3017 wchar_t argv0[MAX_PATH];
3020 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
3025 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
3030 size_t ncmdline = wcslen(fmt) + 10 + 1;
3031 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
3034 err = ERROR_OUTOFMEMORY;
3038 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3054 MIB_IPINTERFACE_ROW ipiface;
3055 InitializeIpInterfaceEntry(&ipiface);
3056 ipiface.Family = mtu->
family;
3058 err = GetIpInterfaceEntry(&ipiface);
3059 if (err != NO_ERROR)
3063 if (mtu->
family == AF_INET)
3065 ipiface.SitePrefixLength = 0;
3067 ipiface.NlMtu = mtu->
mtu;
3069 err = SetIpInterfaceEntry(&ipiface);
3085 switch (
msg->adapter_type)
3092 hwid = L
"root\\tap0901";
3096 return ERROR_INVALID_PARAMETER;
3099 WCHAR cmd[MAX_PATH];
3100 WCHAR args[MAX_PATH];
3102 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3104 return ERROR_BUFFER_OVERFLOW;
3107 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3109 return ERROR_BUFFER_OVERFLOW;
3116HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3133 switch (
msg.header.type)
3137 if (
msg.header.size ==
sizeof(
msg.address))
3145 if (
msg.header.size ==
sizeof(
msg.route))
3152 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3160 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3178 DWORD ovpn_pid = proc_info->dwProcessId;
3189 if (
msg.header.size ==
sizeof(
msg.dhcp))
3196 if (
msg.header.size ==
sizeof(
msg.mtu))
3203 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3282 *pnext = item->
next;
3293 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3294 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3295 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3296 HANDLE stdin_read = NULL, stdin_write = NULL;
3297 HANDLE stdout_write = NULL;
3298 DWORD pipe_mode, len, exit_code = 0;
3300 STARTUPINFOW startup_info;
3301 PROCESS_INFORMATION proc_info;
3302 LPVOID user_env = NULL;
3303 WCHAR ovpn_pipe_name[256];
3306 WCHAR *cmdline = NULL;
3307 size_t cmdline_size;
3309 WCHAR errmsg[512] = L
"";
3310 BOOL flush_pipe = TRUE;
3312 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3313 .lpSecurityDescriptor = NULL,
3314 .bInheritHandle = TRUE };
3317 EXPLICIT_ACCESS ea[2];
3318 SECURITY_DESCRIPTOR ovpn_sd;
3319 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3320 .lpSecurityDescriptor = &ovpn_sd,
3321 .bInheritHandle = FALSE };
3323 ZeroMemory(&ea,
sizeof(ea));
3324 ZeroMemory(&startup_info,
sizeof(startup_info));
3325 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3326 ZeroMemory(&proc_info,
sizeof(proc_info));
3334 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3341 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3347 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3349 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3355 svc_user = malloc(len);
3356 if (svc_user == NULL)
3362 if (!IsValidSid(svc_user->User.Sid))
3368 if (!ImpersonateNamedPipeClient(pipe))
3373 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3379 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3381 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3387 ovpn_user = malloc(len);
3388 if (ovpn_user == NULL)
3394 if (!IsValidSid(ovpn_user->User.Sid))
3416 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3417 ea[0].grfAccessMode = SET_ACCESS;
3418 ea[0].grfInheritance = NO_INHERITANCE;
3419 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3420 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3421 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3422 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3423 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3424 ea[1].grfAccessMode = SET_ACCESS;
3425 ea[1].grfInheritance = NO_INHERITANCE;
3426 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3427 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3428 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3431 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3436 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3441 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3448 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3455 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3456 OPEN_EXISTING, 0, NULL);
3457 if (stdout_write == INVALID_HANDLE_VALUE)
3463 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3464 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3471 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3472 if (rpc_stat != RPC_S_OK)
3478 RPC_WSTR pipe_uuid_str = NULL;
3479 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3480 if (rpc_stat != RPC_S_OK)
3485 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3487 GetCurrentThreadId(), pipe_uuid_str);
3488 RpcStringFree(&pipe_uuid_str);
3494 SECURITY_ATTRIBUTES sa;
3495 PSECURITY_DESCRIPTOR pSD = NULL;
3496 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3497 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3498 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3503 sa.nLength =
sizeof(sa);
3504 sa.lpSecurityDescriptor = pSD;
3505 sa.bInheritHandle = FALSE;
3507 ovpn_pipe = CreateNamedPipe(
3508 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3509 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3510 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3516 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3517 OPEN_EXISTING, 0, NULL);
3518 if (svc_pipe == INVALID_HANDLE_VALUE)
3524 pipe_mode = PIPE_READMODE_MESSAGE;
3525 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3531 cmdline_size = wcslen(sud.
options) + 128;
3532 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3533 if (cmdline == NULL)
3541 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3542 (uintptr_t)svc_pipe);
3544 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3550 startup_info.cb =
sizeof(startup_info);
3551 startup_info.dwFlags = STARTF_USESTDHANDLES;
3552 startup_info.hStdInput = stdin_read;
3553 startup_info.hStdOutput = stdout_write;
3554 startup_info.hStdError = stdout_write;
3559 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3561 user_env, sud.
directory, &startup_info, &proc_info))
3567 if (!RevertToSelf())
3569 TerminateProcess(proc_info.hProcess, 1);
3580 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3582 if (input_size && (input = malloc(input_size)))
3585 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3586 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3603 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3611 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3612 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3613 if (exit_code == STILL_ACTIVE)
3615 TerminateProcess(proc_info.hProcess, 1);
3617 else if (exit_code != 0)
3620 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3628 FlushFileBuffers(pipe);
3630 DisconnectNamedPipe(pipe);
3635 DestroyEnvironmentBlock(user_env);
3656 SERVICE_STATUS *
status = ctx;
3659 case SERVICE_CONTROL_STOP:
3660 status->dwCurrentState = SERVICE_STOP_PENDING;
3668 case SERVICE_CONTROL_INTERROGATE:
3672 return ERROR_CALL_NOT_IMPLEMENTED;
3686 const WCHAR *sddlString =
3687 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)";
3689 PSECURITY_DESCRIPTOR sd = NULL;
3690 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3694 return INVALID_HANDLE_VALUE;
3698 SECURITY_ATTRIBUTES sa = { 0 };
3699 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3700 sa.lpSecurityDescriptor = sd;
3701 sa.bInheritHandle = FALSE;
3703 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3705 static BOOL first = TRUE;
3708 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3712 WCHAR pipe_name[256];
3714 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(
PACKAGE) L
"%ls\\service",
3716 HANDLE pipe = CreateNamedPipe(
3717 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3718 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3722 if (pipe == INVALID_HANDLE_VALUE)
3725 return INVALID_HANDLE_VALUE;
3736 static DWORD size = 10;
3737 static LPHANDLE handles = NULL;
3740 if (handles == NULL)
3742 handles = malloc(size *
sizeof(HANDLE));
3743 *handles_ptr = handles;
3744 if (handles == NULL)
3746 return ERROR_OUTOFMEMORY;
3750 handles[
pos++] = io_event;
3763 tmp = realloc(handles, size *
sizeof(HANDLE));
3768 return ERROR_OUTOFMEMORY;
3771 *handles_ptr = handles;
3773 handles[
pos++] = threads->
data;
3774 threads = threads->
next;
3798 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3810 BOOL changed = FALSE;
3820 if (
key != INVALID_HANDLE_VALUE)
3838 HANDLE pipe, io_event = NULL;
3839 OVERLAPPED overlapped;
3840 DWORD error = NO_ERROR;
3842 PHANDLE handles = NULL;
3852 status.dwCurrentState = SERVICE_START_PENDING;
3853 status.dwServiceSpecificExitCode = NO_ERROR;
3854 status.dwWin32ExitCode = NO_ERROR;
3855 status.dwWaitHint = 3000;
3863 if (error != ERROR_SUCCESS)
3869 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3884 if (error != NO_ERROR)
3890 if (pipe == INVALID_HANDLE_VALUE)
3895 status.dwCurrentState = SERVICE_RUNNING;
3901 if (!ConnectNamedPipe(pipe, &overlapped))
3903 DWORD connect_error = GetLastError();
3904 if (connect_error == ERROR_NO_DATA)
3911 DisconnectNamedPipe(pipe);
3915 else if (connect_error == ERROR_PIPE_CONNECTED)
3918 SetEvent(overlapped.hEvent);
3920 else if (connect_error != ERROR_IO_PENDING)
3927 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3928 if (error == WAIT_OBJECT_0)
3934 if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS)
3943 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3954 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3959 TerminateThread(thread, 1);
3965 ResumeThread(thread);
3979 if (error == WAIT_FAILED)
4009 status.dwCurrentState = SERVICE_STOPPED;
4010 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 RegWStringSize(PCWSTR string)
Return correct size for registry value to set for string.
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 LSTATUS ConvertItfDnsDomains(PCWSTR search_domains, PWSTR domains, PDWORD size, const DWORD buf_size)
Convert interface specific domain suffix(es) from comma-separated string to MULTI_SZ string.
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)