37#include <versionhelpers.h>
43#define IO_TIMEOUT 2000
45#define ERROR_OPENVPN_STARTUP 0x20000000
46#define ERROR_STARTUP_DATA 0x20000001
47#define ERROR_MESSAGE_DATA 0x20000002
48#define ERROR_MESSAGE_TYPE 0x20000003
51static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
55#define RDNS_TIMEOUT 600
57#define TUN_IOCTL_REGISTER_RINGS \
58 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
61 _L(PACKAGE_NAME) L
" Interactive Service",
137 if (new_item == NULL)
139 return ERROR_OUTOFMEMORY;
142 new_item->
next = *pfirst;
157 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
160 if (!match(item->
data, ctx))
178 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
180 CloseHandle(*handle);
181 *handle = INVALID_HANDLE_VALUE;
183 return INVALID_HANDLE_VALUE;
189 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
190 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
191 return overlapped->hEvent;
197 HANDLE io_event = overlapped->hEvent;
198 if (!ResetEvent(io_event))
202 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
203 overlapped->hEvent = io_event;
221 DWORD res, bytes = 0;
222 OVERLAPPED overlapped;
223 LPHANDLE handles = NULL;
231 handles = malloc((count + 1) *
sizeof(HANDLE));
239 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
243 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
245 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
250 handles[0] = io_event;
251 for (i = 0; i < count; i++)
253 handles[i + 1] = events[i];
256 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
257 if (res != WAIT_OBJECT_0)
265 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
269 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
299 const WCHAR
msg[] = L
"Process ID";
300 WCHAR buf[22 + _countof(
msg)];
306 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
308 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
312ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
315 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
316 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
320 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
321 | FORMAT_MESSAGE_IGNORE_INSERTS,
322 0, error, 0, (LPWSTR)&args[2], 0, NULL);
325 result_len = FormatMessageW(
326 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
327 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
329 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
334 LocalFree((LPVOID)args[2]);
362 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
363 L
" that requires admin approval. This error may be avoided"
364 L
" by adding your account to the \"%ls\" group";
366 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
367 L
" only with admin approval. This error may be avoided"
368 L
" by adding your account to the \"%ls\" group";
374 swprintf(errmsg, capacity,
375 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
392 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
401 for (i = 0; i < argc; ++i)
410 if (wcscmp(L
"--config",
argv[i]) == 0 && argc - i > 1)
448 size = bytes /
sizeof(*data);
449 if ((size == 0) || (size > 4096))
456 data = malloc(bytes);
472 if (
data[size - 1] != 0)
490 len = wcslen(sud->
options) + 1;
519 SOCKADDR_INET sa_inet;
520 ZeroMemory(&sa_inet,
sizeof(sa_inet));
521 sa_inet.si_family = family;
522 if (family == AF_INET)
524 sa_inet.Ipv4.sin_addr = addr->
ipv4;
526 else if (family == AF_INET6)
528 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
537 LPWSTR wide_name =
utf8to16(iface_name);
541 status = ConvertInterfaceAliasToLuid(wide_name, luid);
546 status = ERROR_OUTOFMEMORY;
554 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
560 return DeleteUnicastIpAddressEntry(addr_row);
567 PMIB_UNICASTIPADDRESS_ROW addr_row;
570 addr_row = malloc(
sizeof(*addr_row));
571 if (addr_row == NULL)
573 return ERROR_OUTOFMEMORY;
576 InitializeUnicastIpAddressEntry(addr_row);
578 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
580 if (
msg->iface.index != -1)
582 addr_row->InterfaceIndex =
msg->iface.index;
592 addr_row->InterfaceLuid = luid;
597 err = CreateUnicastIpAddressEntry(addr_row);
632 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
638 return DeleteIpForwardEntry2(fwd_row);
645 PMIB_IPFORWARD_ROW2 fwd_row;
648 fwd_row = malloc(
sizeof(*fwd_row));
651 return ERROR_OUTOFMEMORY;
654 ZeroMemory(fwd_row,
sizeof(*fwd_row));
655 fwd_row->ValidLifetime = 0xffffffff;
656 fwd_row->PreferredLifetime = 0xffffffff;
657 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
658 fwd_row->Metric =
msg->metric;
660 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
663 if (
msg->iface.index != -1)
665 fwd_row->InterfaceIndex =
msg->iface.index;
667 else if (strlen(
msg->iface.name))
675 fwd_row->InterfaceLuid = luid;
680 err = CreateIpForwardEntry2(fwd_row);
716 if (
msg->family == AF_INET)
718 return FlushIpNetTable(
msg->iface.index);
721 return FlushIpNetTable2(
msg->family,
msg->iface.index);
735 err_str = L
"Unknown Win32 Error";
737 if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
738 NULL, err, 0, buf, _countof(buf), NULL))
785 HANDLE engine = NULL;
798 err = ERROR_OUTOFMEMORY;
801 block_data->
engine = engine;
802 block_data->
index =
msg->iface.index;
866ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
870 PROCESS_INFORMATION pi;
871 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
872 WCHAR *cmdline_dup = NULL;
874 ZeroMemory(&si,
sizeof(si));
875 ZeroMemory(&pi,
sizeof(pi));
880 cmdline_dup = _wcsdup(cmdline);
882 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
884 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
885 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
888 exit_code = GetLastError();
890 else if (exit_code == STILL_ACTIVE)
892 exit_code = WAIT_TIMEOUT;
895 TerminateProcess(pi.hProcess, exit_code);
896 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
908 CloseHandle(pi.hProcess);
909 CloseHandle(pi.hThread);
913 exit_code = GetLastError();
932 WCHAR ipcfg[MAX_PATH];
940 { ipcfg, L
"ipconfig /flushdns", timeout },
941 { ipcfg, L
"ipconfig /registerdns", timeout },
946 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
948 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
951 for (i = 0; i < _countof(cmds); ++i)
953 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
965 err = ERROR_SEM_TIMEOUT;
974 HANDLE thread = NULL;
977 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
990 err = GetLastError();
1009 int timeout = 30000;
1010 wchar_t argv0[MAX_PATH];
1011 wchar_t *cmdline = NULL;
1012 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1016 if (wcscmp(action, L
"delete") == 0)
1027 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1032 const wchar_t *fmt = L
"netsh interface ip %ls wins %d %ls %ls";
1035 size_t ncmdline = wcslen(fmt) + 11 + wcslen(action) + wcslen(addr)
1036 + wcslen(addr_static) + 32 + 1;
1037 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1040 err = ERROR_OUTOFMEMORY;
1044 swprintf(cmdline, ncmdline, fmt, action, if_index, addr_static, addr);
1062 typedef NTSTATUS(__stdcall * publish_fn_t)(DWORD StateNameLo, DWORD StateNameHi, DWORD TypeId,
1063 DWORD Buffer, DWORD Length, DWORD ExplicitScope);
1064 publish_fn_t RtlPublishWnfStateData;
1065 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1066 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1068 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1074 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1075 if (RtlPublishWnfStateData == NULL)
1080 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0)
1098 typedef NTSTATUS (*publish_fn_t)(INT64 StateName, INT64 TypeId, INT64 Buffer,
1099 unsigned int Length, INT64 ExplicitScope);
1100 publish_fn_t RtlPublishWnfStateData;
1101 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1103 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1109 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1110 if (RtlPublishWnfStateData == NULL)
1115 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1133 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1148 SC_HANDLE scm = NULL;
1149 SC_HANDLE dnssvc = NULL;
1156 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1159 MsgToEventLog(
M_ERR, L
"%S: OpenSCManager call failed (%lu)", __func__, GetLastError());
1163 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1166 MsgToEventLog(
M_ERR, L
"%S: OpenService call failed (%lu)", __func__, GetLastError());
1171 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1173 MsgToEventLog(
M_ERR, L
"%S: ControlService call failed (%lu)", __func__, GetLastError());
1182 CloseServiceHandle(dnssvc);
1186 CloseServiceHandle(scm);
1206 PWSTR iid_str = NULL;
1214 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1221 if (StringFromIID(&guid, &iid_str) != S_OK)
1224 err = ERROR_OUTOFMEMORY;
1227 if (wcslen(iid_str) + 1 > len)
1229 err = ERROR_INVALID_PARAMETER;
1233 wcsncpy(str, iid_str, len);
1238 CoTaskMemFree(iid_str);
1260 DWORD size =
sizeof(
data);
1261 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1262 if (!err || err == ERROR_MORE_DATA)
1265 for (
int i = 0; i < strlen(
data); ++i)
1267 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1301 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1302 0, KEY_ALL_ACCESS,
key);
1315 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1316 0, KEY_ALL_ACCESS,
key);
1335 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1336 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1337 0, KEY_ALL_ACCESS, &itfs);
1340 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1350 *
key = INVALID_HANDLE_VALUE;
1366 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1369 if (err == ERROR_FILE_NOT_FOUND)
1379#if defined(__GNUC__) || defined(__clang__)
1380#pragma GCC diagnostic push
1381#pragma GCC diagnostic ignored "-Wconversion"
1397 if (!list || wcslen(list) == 0)
1409 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1410 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1413 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1433 WCHAR list[2048] = { 0 };
1434 DWORD size =
sizeof(list);
1438 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1451 size_t listlen = (size /
sizeof(list[0])) - 1;
1452 size_t domlen = wcslen(domains);
1453 if (listlen + domlen + 2 > _countof(list))
1461 PWSTR
pos = list + listlen;
1463 wcsncpy(
pos + 1, domains, domlen + 1);
1467 wcsncpy(list, domains, wcslen(domains) + 1);
1470 size = (wcslen(list) + 1) *
sizeof(list[0]);
1471 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1498 DWORD size =
sizeof(list);
1500 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1503 if (err != ERROR_FILE_NOT_FOUND)
1511 size = (wcslen(list) + 1) *
sizeof(list[0]);
1512 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1519 RegDeleteValueA(
key,
"InitialSearchList");
1537 DWORD size =
sizeof(list);
1539 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1546 PWSTR dst = wcsstr(list, domains);
1554 size_t domlen = wcslen(domains);
1555 PCWSTR src = dst + domlen;
1557 dst = dst > list ? dst - 1 : dst;
1558 wmemmove(dst, src, domlen);
1560 size_t list_len = wcslen(list);
1564 WCHAR initial[2048];
1565 size =
sizeof(initial);
1566 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1575 if (wcsncmp(list, initial, wcslen(list)) == 0)
1582 size = (list_len + 1) *
sizeof(list[0]);
1583 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1599 HKEY dns_searchlist_key;
1601 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1604 RegCloseKey(dns_searchlist_key);
1636 DWORD err = ERROR_OUTOFMEMORY;
1640 if (list_key == INVALID_HANDLE_VALUE)
1643 return ERROR_FILE_NOT_FOUND;
1657 if (domains && *domains)
1659 wchar_t *wide_domains =
utf8to16(domains);
1665 undo_data = malloc(
sizeof(*undo_data));
1669 wide_domains = NULL;
1673 undo_data->
domains = wide_domains;
1689 RegCloseKey(list_key);
1703 PCSTR itfs_key = family == AF_INET6
1704 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1705 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1707 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1710 *
key = INVALID_HANDLE_VALUE;
1712 __func__, family, err);
1715 return err ? FALSE : TRUE;
1735 return ERROR_FILE_NOT_FOUND;
1738 HKEY itf = INVALID_HANDLE_VALUE;
1739 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1743 __func__, itf_id, family, err);
1747 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1751 __func__, value, itf_id, family, err);
1755 if (itf != INVALID_HANDLE_VALUE)
1759 if (itfs != INVALID_HANDLE_VALUE)
1800 int addr_len =
msg->addr_len;
1803 const size_t max_addrs = _countof(
msg->addr);
1804 if (addr_len > max_addrs)
1806 addr_len = max_addrs;
1809 if (!
msg->iface.name[0])
1818 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1819 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1845 if (
msg->domains[0])
1854 if (
msg->addr_len > 0)
1859 CHAR addrs[_countof(
msg->addr) * 64];
1861 for (
int i = 0; i < addr_len; ++i)
1865 addrs[offset++] =
',';
1867 if (
msg->family == AF_INET6)
1869 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1873 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1875 offset = strlen(addrs);
1884 wchar_t *tmp_iid = _wcsdup(iid);
1885 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1889 return ERROR_OUTOFMEMORY;
1894 if (
msg->domains[0])
1915 DWORD size =
sizeof(
dhcp);
1918 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1919 if (err != NO_ERROR)
1925 return dhcp ? TRUE : FALSE;
1939 const short families[] = { AF_INET, AF_INET6 };
1940 for (
int i = 0; i < _countof(families); i++)
1942 short family = families[i];
1949 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1950 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1957 addr_list[offset++] =
',';
1959 strcpy(addr_list + offset, addresses[j]);
1960 offset += strlen(addresses[j]);
1992 addrs[*size - 1] =
'\0';
1996 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
1997 if (err && err != ERROR_FILE_NOT_FOUND)
2007 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2015 if (strchr(addrs,
'.'))
2022 return ERROR_FILE_NOT_FOUND;
2037 addrs[*size - 1] =
'\0';
2041 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2042 if (err && err != ERROR_FILE_NOT_FOUND)
2051 IN6_ADDR in_addrs[8];
2052 DWORD in_addrs_size =
sizeof(in_addrs);
2053 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2054 (PBYTE)in_addrs, &in_addrs_size);
2063 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2064 for (
size_t i = 0; i < in_addrs_read; ++i)
2073 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2076 return ERROR_MORE_DATA;
2079 size_t addr_len = strlen(
pos);
2083 s = strlen(addrs) + 1;
2086 if (strchr(addrs,
':'))
2093 return ERROR_FILE_NOT_FOUND;
2108 PCWSTR match = list;
2111 match = wcsstr(match, domain);
2117 if ((match == list || *(match - 1) ==
',')
2118 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2152 if (domains == NULL || size == NULL || *size == 0)
2154 return ERROR_INVALID_PARAMETER;
2157 LSTATUS err = ERROR_FILE_NOT_FOUND;
2158 const DWORD buf_size = *size;
2159 const size_t one_glyph =
sizeof(*domains);
2160 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2162 for (
int i = 0; values[i]; i++)
2165 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2166 if (!err && *size > one_glyph && domains[(*size / one_glyph) - 1] ==
'\0' && wcschr(domains,
'.'))
2173 PWCHAR
pos = domains;
2174 const DWORD
buf_len = buf_size / one_glyph;
2178 PWCHAR comma = wcschr(
pos,
',');
2185 size_t domain_len = wcslen(
pos);
2198 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2204 size_t converted_size =
pos - domains;
2205 size_t domain_size = domain_len * one_glyph;
2206 size_t extra_size = 2 * one_glyph;
2207 if (converted_size + domain_size + extra_size > buf_size)
2211 *size = converted_size == 0 ? 0 : *size + 1;
2212 return ERROR_MORE_DATA;
2216 memmove(
pos + 1,
pos, buf_size - converted_size - one_glyph);
2224 *(
pos + domain_len) =
'\0';
2251 MIB_IF_ROW2 itf_row;
2254 if (IIDFromString(iid_str, &iid) != S_OK)
2262 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2268 if (GetIfEntry2(&itf_row) != NO_ERROR)
2274 if (itf_row.MediaConnectState == MediaConnectStateConnected
2275 && itf_row.OperStatus == IfOperStatusUp)
2296 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2297 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2305 DWORD enum_index = 0;
2306 while (i < data_size)
2308 WCHAR itf_guid[MAX_PATH];
2309 DWORD itf_guid_len = _countof(itf_guid);
2311 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2314 if (err != ERROR_NO_MORE_ITEMS)
2328 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2336 data[i].domains_size =
sizeof(
data[0].domains);
2337 memset(
data[i].domains, 0,
data[i].domains_size);
2341 if (err != ERROR_FILE_NOT_FOUND)
2350 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2352 if (err && err != ERROR_FILE_NOT_FOUND)
2355 __func__, itf_guid, err);
2360 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2361 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2365 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2368 __func__, itf_guid);
2372 RegCloseKey(v6_itf);
2373 if (err && err != ERROR_FILE_NOT_FOUND)
2376 __func__, itf_guid, err);
2381 if (v4_addrs_size || v6_addrs_size)
2384 for (
int j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2386 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2388 data[i].addresses[j] =
';';
2395 RegCloseKey(v4_itf);
2399 RegCloseKey(v6_itfs);
2400 RegCloseKey(v4_itfs);
2420 DWORD err = NO_ERROR;
2422 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2429 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2436 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2448 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2456 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2464 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2473 reg_val = dnssec ? 0x0000000A : 0x00000008;
2474 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2483 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2492 RegDeleteKeyW(nrpt_key, subkey);
2494 RegCloseKey(rule_key);
2515 for (
int i = 0; i < _countof(
data); ++i)
2525 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2548 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2550 DWORD err = NO_ERROR;
2551 PWSTR wide_domains = L
".\0";
2557 size_t domains_len = strlen(domains);
2558 dom_size = domains_len + 2;
2561 dom_size *=
sizeof(*wide_domains);
2564 return ERROR_OUTOFMEMORY;
2567 for (
size_t i = 0; i < domains_len; ++i)
2569 if (wide_domains[i] ==
',')
2571 wide_domains[i] = 0;
2577 PWSTR wide_search_domains;
2578 wide_search_domains =
utf8to16(search_domains);
2579 if (!wide_search_domains)
2581 return ERROR_OUTOFMEMORY;
2584 free(wide_search_domains);
2589 PSTR
pos = addr_list;
2596 strcpy(
pos, addresses[i]);
2600 WCHAR subkey[MAX_PATH];
2601 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2602 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2615#if defined(__GNUC__) || defined(__clang__)
2616#pragma GCC diagnostic pop
2636 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2637 static PCSTR sys_key =
2638 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2642 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2643 if (err == ERROR_FILE_NOT_FOUND)
2646 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2650 nrpt = INVALID_HANDLE_VALUE;
2684 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2685 pidlen = wcslen(pid_str);
2689 DWORD enum_index = 0;
2692 WCHAR name[MAX_PATH];
2693 DWORD namelen = _countof(name);
2694 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2697 if (err != ERROR_NO_MORE_ITEMS)
2705 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2706 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2711 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2719 return deleted ? TRUE : FALSE;
2757 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2762 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2767 if (
msg->iface.name[0] == 0)
2776 if (
msg->addresses[0][0] == 0)
2781 const char *rdom =
msg->resolve_domains;
2782 size_t rdom_size =
sizeof(
msg->resolve_domains);
2783 size_t rdom_len = strlen(rdom);
2784 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2790 BOOL gpol_nrpt = FALSE;
2791 BOOL gpol_list = FALSE;
2804 if (*undo_pid != ovpn_pid)
2807 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2808 "This is likely an error. Cleaning up anyway.",
2809 __func__, *undo_pid, ovpn_pid);
2833 PDWORD pid = malloc(
sizeof(ovpn_pid));
2836 err = ERROR_OUTOFMEMORY;
2842 err = ERROR_OUTOFMEMORY;
2864 if (
msg->search_domains[0])
2878 DWORD err = NO_ERROR;
2880 int addr_len =
msg->addr_len;
2883 if (addr_len > _countof(
msg->addr))
2885 addr_len = _countof(
msg->addr);
2888 if (!
msg->iface.index)
2911 for (
int i = 0; i < addr_len; ++i)
2913 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2924 int *if_index = malloc(
sizeof(
msg->iface.index));
2927 *if_index =
msg->iface.index;
2934 err = ERROR_OUTOFMEMORY;
2948 DWORD timeout = 5000;
2949 wchar_t argv0[MAX_PATH];
2952 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2957 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2962 size_t ncmdline = wcslen(fmt) + 10 + 1;
2963 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
2966 err = ERROR_OUTOFMEMORY;
2970 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
2986 MIB_IPINTERFACE_ROW ipiface;
2987 InitializeIpInterfaceEntry(&ipiface);
2988 ipiface.Family = mtu->
family;
2990 err = GetIpInterfaceEntry(&ipiface);
2991 if (err != NO_ERROR)
2995 if (mtu->
family == AF_INET)
2997 ipiface.SitePrefixLength = 0;
2999 ipiface.NlMtu = mtu->
mtu;
3001 err = SetIpInterfaceEntry(&ipiface);
3017 switch (
msg->adapter_type)
3024 hwid = L
"root\\tap0901";
3028 return ERROR_INVALID_PARAMETER;
3031 WCHAR cmd[MAX_PATH];
3032 WCHAR args[MAX_PATH];
3034 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3036 return ERROR_BUFFER_OVERFLOW;
3039 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3041 return ERROR_BUFFER_OVERFLOW;
3048HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3065 switch (
msg.header.type)
3069 if (
msg.header.size ==
sizeof(
msg.address))
3077 if (
msg.header.size ==
sizeof(
msg.route))
3084 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3092 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3110 DWORD ovpn_pid = proc_info->dwProcessId;
3121 if (
msg.header.size ==
sizeof(
msg.dhcp))
3128 if (
msg.header.size ==
sizeof(
msg.mtu))
3135 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3214 *pnext = item->
next;
3225 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3226 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3227 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3228 HANDLE stdin_read = NULL, stdin_write = NULL;
3229 HANDLE stdout_write = NULL;
3230 DWORD pipe_mode, len, exit_code = 0;
3232 STARTUPINFOW startup_info;
3233 PROCESS_INFORMATION proc_info;
3234 LPVOID user_env = NULL;
3235 WCHAR ovpn_pipe_name[256];
3238 WCHAR *cmdline = NULL;
3239 size_t cmdline_size;
3241 WCHAR errmsg[512] = L
"";
3243 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3244 .lpSecurityDescriptor = NULL,
3245 .bInheritHandle = TRUE };
3248 EXPLICIT_ACCESS ea[2];
3249 SECURITY_DESCRIPTOR ovpn_sd;
3250 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3251 .lpSecurityDescriptor = &ovpn_sd,
3252 .bInheritHandle = FALSE };
3254 ZeroMemory(&ea,
sizeof(ea));
3255 ZeroMemory(&startup_info,
sizeof(startup_info));
3256 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3257 ZeroMemory(&proc_info,
sizeof(proc_info));
3264 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3271 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3277 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3279 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3285 svc_user = malloc(len);
3286 if (svc_user == NULL)
3292 if (!IsValidSid(svc_user->User.Sid))
3298 if (!ImpersonateNamedPipeClient(pipe))
3303 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3309 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3311 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3317 ovpn_user = malloc(len);
3318 if (ovpn_user == NULL)
3324 if (!IsValidSid(ovpn_user->User.Sid))
3346 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3347 ea[0].grfAccessMode = SET_ACCESS;
3348 ea[0].grfInheritance = NO_INHERITANCE;
3349 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3350 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3351 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3352 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3353 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3354 ea[1].grfAccessMode = SET_ACCESS;
3355 ea[1].grfInheritance = NO_INHERITANCE;
3356 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3357 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3358 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3361 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3366 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3371 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3378 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3385 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3386 OPEN_EXISTING, 0, NULL);
3387 if (stdout_write == INVALID_HANDLE_VALUE)
3393 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3394 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3401 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3402 if (rpc_stat != RPC_S_OK)
3408 RPC_WSTR pipe_uuid_str = NULL;
3409 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3410 if (rpc_stat != RPC_S_OK)
3415 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3417 GetCurrentThreadId(), pipe_uuid_str);
3418 RpcStringFree(&pipe_uuid_str);
3424 SECURITY_ATTRIBUTES sa;
3425 PSECURITY_DESCRIPTOR pSD = NULL;
3426 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3427 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3428 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3433 sa.nLength =
sizeof(sa);
3434 sa.lpSecurityDescriptor = pSD;
3435 sa.bInheritHandle = FALSE;
3437 ovpn_pipe = CreateNamedPipe(
3438 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3439 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3440 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3446 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3447 OPEN_EXISTING, 0, NULL);
3448 if (svc_pipe == INVALID_HANDLE_VALUE)
3454 pipe_mode = PIPE_READMODE_MESSAGE;
3455 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3461 cmdline_size = wcslen(sud.
options) + 128;
3462 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3463 if (cmdline == NULL)
3471 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3472 (uintptr_t)svc_pipe);
3474 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3480 startup_info.cb =
sizeof(startup_info);
3481 startup_info.dwFlags = STARTF_USESTDHANDLES;
3482 startup_info.hStdInput = stdin_read;
3483 startup_info.hStdOutput = stdout_write;
3484 startup_info.hStdError = stdout_write;
3489 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3491 user_env, sud.
directory, &startup_info, &proc_info))
3497 if (!RevertToSelf())
3499 TerminateProcess(proc_info.hProcess, 1);
3510 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3512 if (input_size && (input = malloc(input_size)))
3515 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3516 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3533 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3541 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3542 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3543 if (exit_code == STILL_ACTIVE)
3545 TerminateProcess(proc_info.hProcess, 1);
3547 else if (exit_code != 0)
3550 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3556 FlushFileBuffers(pipe);
3557 DisconnectNamedPipe(pipe);
3562 DestroyEnvironmentBlock(user_env);
3583 SERVICE_STATUS *
status = ctx;
3586 case SERVICE_CONTROL_STOP:
3587 status->dwCurrentState = SERVICE_STOP_PENDING;
3595 case SERVICE_CONTROL_INTERROGATE:
3599 return ERROR_CALL_NOT_IMPLEMENTED;
3613 const WCHAR *sddlString =
3614 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)";
3616 PSECURITY_DESCRIPTOR sd = NULL;
3617 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3621 return INVALID_HANDLE_VALUE;
3625 SECURITY_ATTRIBUTES sa = { 0 };
3626 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3627 sa.lpSecurityDescriptor = sd;
3628 sa.bInheritHandle = FALSE;
3630 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3632 static BOOL first = TRUE;
3635 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3639 WCHAR pipe_name[256];
3641 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(PACKAGE) L
"%ls\\service",
3643 HANDLE pipe = CreateNamedPipe(
3644 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3645 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3649 if (pipe == INVALID_HANDLE_VALUE)
3652 return INVALID_HANDLE_VALUE;
3663 static DWORD size = 10;
3664 static LPHANDLE handles = NULL;
3667 if (handles == NULL)
3669 handles = malloc(size *
sizeof(HANDLE));
3670 *handles_ptr = handles;
3671 if (handles == NULL)
3673 return ERROR_OUTOFMEMORY;
3677 handles[
pos++] = io_event;
3690 tmp = realloc(handles, size *
sizeof(HANDLE));
3695 return ERROR_OUTOFMEMORY;
3698 *handles_ptr = handles;
3700 handles[
pos++] = threads->
data;
3701 threads = threads->
next;
3725 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3737 BOOL changed = FALSE;
3747 if (
key != INVALID_HANDLE_VALUE)
3765 HANDLE pipe, io_event = NULL;
3766 OVERLAPPED overlapped;
3767 DWORD error = NO_ERROR;
3769 PHANDLE handles = NULL;
3779 status.dwCurrentState = SERVICE_START_PENDING;
3780 status.dwServiceSpecificExitCode = NO_ERROR;
3781 status.dwWin32ExitCode = NO_ERROR;
3782 status.dwWaitHint = 3000;
3790 if (error != ERROR_SUCCESS)
3796 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3811 if (error != NO_ERROR)
3817 if (pipe == INVALID_HANDLE_VALUE)
3822 status.dwCurrentState = SERVICE_RUNNING;
3828 if (ConnectNamedPipe(pipe, &overlapped) == FALSE && GetLastError() != ERROR_PIPE_CONNECTED
3829 && GetLastError() != ERROR_IO_PENDING)
3835 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3836 if (error == WAIT_OBJECT_0)
3840 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3851 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3856 TerminateThread(thread, 1);
3862 ResumeThread(thread);
3876 if (error == WAIT_FAILED)
3906 status.dwCurrentState = SERVICE_STOPPED;
3907 status.dwWin32ExitCode = error;
static int buf_len(const struct buffer *buf)
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static LSTATUS GetItfDnsServersV4(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv4 addresses of an interface.
static LSTATUS SetNameServerAddresses(PWSTR itf_id, const nrpt_address_t *addresses)
Set name servers from a NRPT address list.
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static BOOL GetInterfacesKey(short family, PHKEY key)
Return the interfaces registry key for the specified address family.
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static void UndoNrptRules(DWORD ovpn_pid)
Delete a process' NRPT rules and apply the reduced set of rules.
static BOOL ApplyGpolSettings(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings.
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static BOOL GetDnsSearchListKey(PCSTR itf_name, PBOOL gpol, PHKEY key)
Find the registry key for storing the DNS domains for the VPN interface.
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static LSTATUS GetItfDnsDomains(HKEY itf, PCWSTR search_domains, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD SetNameServers(PCWSTR itf_id, short family, PCSTR addrs)
Set the DNS name servers in a registry interface configuration.
static void SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid, PCWSTR search_domains)
Set NRPT exclude rules to accompany a catch all rule.
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE CreateClientPipeInstance(VOID)
static 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)