38#include <versionhelpers.h>
45#define IO_TIMEOUT 2000
47#define ERROR_OPENVPN_STARTUP 0x20000000
48#define ERROR_STARTUP_DATA 0x20000001
49#define ERROR_MESSAGE_DATA 0x20000002
50#define ERROR_MESSAGE_TYPE 0x20000003
53static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
57#define RDNS_TIMEOUT 600
59#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
142 if (new_item == NULL)
144 return ERROR_OUTOFMEMORY;
147 new_item->
next = *pfirst;
148 new_item->
data = data;
162 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
165 if (!match(item->
data, ctx))
183 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
185 CloseHandle(*handle);
186 *handle = INVALID_HANDLE_VALUE;
188 return INVALID_HANDLE_VALUE;
196 UnmapViewOfFile(*ring);
211 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
212 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
213 return overlapped->hEvent;
220 HANDLE io_event = overlapped->hEvent;
221 if (!ResetEvent(io_event))
225 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
226 overlapped->hEvent = io_event;
243 DWORD res, bytes = 0;
244 OVERLAPPED overlapped;
245 LPHANDLE handles = NULL;
253 handles = malloc((count + 1) *
sizeof(HANDLE));
261 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
265 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
267 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
272 handles[0] = io_event;
273 for (i = 0; i < count; i++)
275 handles[i + 1] = events[i];
278 res = WaitForMultipleObjects(count + 1, handles, FALSE,
280 if (res != WAIT_OBJECT_0)
288 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
292 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
314WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
322 const WCHAR
msg[] = L
"Process ID";
323 WCHAR buf[22 + _countof(
msg)];
329 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
331 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
335ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
338 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
347 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
348 |FORMAT_MESSAGE_ALLOCATE_BUFFER
349 |FORMAT_MESSAGE_IGNORE_INSERTS,
350 0, error, 0, (LPWSTR) &args[2], 0, NULL);
353 result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
354 |FORMAT_MESSAGE_ALLOCATE_BUFFER
355 |FORMAT_MESSAGE_ARGUMENT_ARRAY,
356 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
357 (LPWSTR) &result, 0, (va_list *) args);
359 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
364 LocalFree((LPVOID) args[2]);
335ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events) {
…}
391 const WCHAR *msg1 = L
"You have specified a config file location (%ls relative to %ls)"
392 L
" that requires admin approval. This error may be avoided"
393 L
" by adding your account to the \"%ls\" group";
395 const WCHAR *msg2 = L
"You have specified an option (%ls) that may be used"
396 L
" only with admin approval. This error may be avoided"
397 L
" by adding your account to the \"%ls\" group";
403 swprintf(errmsg, capacity,
404 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
421 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
425 swprintf(errmsg, capacity, msg1,
argv[0], workdir,
431 for (i = 0; i < argc; ++i)
440 if (wcscmp(L
"--config",
argv[i]) == 0 && argc-i > 1)
442 swprintf(errmsg, capacity, msg1,
argv[i+1], workdir,
447 swprintf(errmsg, capacity, msg2,
argv[i],
480 size = bytes /
sizeof(*data);
488 data = malloc(bytes);
504 if (data[size - 1] != 0)
522 len = wcslen(sud->
options) + 1;
551 SOCKADDR_INET sa_inet;
552 ZeroMemory(&sa_inet,
sizeof(sa_inet));
553 sa_inet.si_family = family;
554 if (family == AF_INET)
556 sa_inet.Ipv4.sin_addr = addr->
ipv4;
558 else if (family == AF_INET6)
560 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
569 LPWSTR wide_name =
utf8to16(iface_name);
573 status = ConvertInterfaceAliasToLuid(wide_name, luid);
578 status = ERROR_OUTOFMEMORY;
586 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
592 return DeleteUnicastIpAddressEntry(addr_row);
599 PMIB_UNICASTIPADDRESS_ROW addr_row;
602 addr_row = malloc(
sizeof(*addr_row));
603 if (addr_row == NULL)
605 return ERROR_OUTOFMEMORY;
608 InitializeUnicastIpAddressEntry(addr_row);
610 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
612 if (
msg->iface.index != -1)
614 addr_row->InterfaceIndex =
msg->iface.index;
624 addr_row->InterfaceLuid = luid;
629 err = CreateUnicastIpAddressEntry(addr_row);
664 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
670 return DeleteIpForwardEntry2(fwd_row);
677 PMIB_IPFORWARD_ROW2 fwd_row;
680 fwd_row = malloc(
sizeof(*fwd_row));
683 return ERROR_OUTOFMEMORY;
686 ZeroMemory(fwd_row,
sizeof(*fwd_row));
687 fwd_row->ValidLifetime = 0xffffffff;
688 fwd_row->PreferredLifetime = 0xffffffff;
689 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
690 fwd_row->Metric =
msg->metric;
692 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
695 if (
msg->iface.index != -1)
697 fwd_row->InterfaceIndex =
msg->iface.index;
699 else if (strlen(
msg->iface.name))
707 fwd_row->InterfaceLuid = luid;
712 err = CreateIpForwardEntry2(fwd_row);
748 if (
msg->family == AF_INET)
750 return FlushIpNetTable(
msg->iface.index);
753 return FlushIpNetTable2(
msg->family,
msg->iface.index);
767 err_str = L
"Unknown Win32 Error";
769 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
770 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
771 NULL, err, 0, buf,
sizeof(buf), NULL))
820 HANDLE engine = NULL;
833 err = ERROR_OUTOFMEMORY;
836 block_data->
engine = engine;
837 block_data->
index =
msg->iface.index;
905ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
909 PROCESS_INFORMATION pi;
910 DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
911 WCHAR *cmdline_dup = NULL;
913 ZeroMemory(&si,
sizeof(si));
914 ZeroMemory(&pi,
sizeof(pi));
919 cmdline_dup = _wcsdup(cmdline);
920 if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE,
921 proc_flags, NULL, NULL, &si, &pi) )
923 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
924 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
927 exit_code = GetLastError();
929 else if (exit_code == STILL_ACTIVE)
931 exit_code = WAIT_TIMEOUT;
934 TerminateProcess(pi.hProcess, exit_code);
941 argv0, cmdline, exit_code);
948 CloseHandle(pi.hProcess);
949 CloseHandle(pi.hThread);
953 exit_code = GetLastError();
905ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout) {
…}
973 WCHAR ipcfg[MAX_PATH];
981 { ipcfg, L
"ipconfig /flushdns", timeout },
982 { ipcfg, L
"ipconfig /registerdns", timeout },
987 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
989 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
992 for (i = 0; i < _countof(cmds); ++i)
994 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
1005 err = ERROR_SEM_TIMEOUT;
1014 HANDLE thread = NULL;
1017 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
1026 CloseHandle(thread);
1030 err = GetLastError();
1049 int timeout = 30000;
1050 wchar_t argv0[MAX_PATH];
1051 wchar_t *cmdline = NULL;
1052 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1056 if (wcscmp(action, L
"delete") == 0)
1067 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1072 const wchar_t *fmt = L
"netsh interface ip %ls wins \"%ls\" %ls %ls";
1075 size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(action) + wcslen(addr)
1076 +wcslen(addr_static) + 32 + 1;
1077 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1080 err = ERROR_OUTOFMEMORY;
1084 swprintf(cmdline, ncmdline, fmt, action, if_name, addr_static, addr);
1096 return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1108 typedef NTSTATUS (__stdcall *publish_fn_t)(
1114 DWORD ExplicitScope);
1115 publish_fn_t RtlPublishWnfStateData;
1116 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1117 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1119 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1125 RtlPublishWnfStateData = (publish_fn_t) GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1126 if (RtlPublishWnfStateData == NULL)
1131 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0) != ERROR_SUCCESS)
1148 typedef NTSTATUS (*publish_fn_t)(
1152 unsigned int Length,
1153 INT64 ExplicitScope);
1154 publish_fn_t RtlPublishWnfStateData;
1155 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1157 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1163 RtlPublishWnfStateData = (publish_fn_t) GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1164 if (RtlPublishWnfStateData == NULL)
1169 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1187 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1202 SC_HANDLE scm = NULL;
1203 SC_HANDLE dnssvc = NULL;
1210 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1214 __func__, GetLastError());
1218 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1222 __func__, GetLastError());
1227 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1230 __func__, GetLastError());
1239 CloseServiceHandle(dnssvc);
1243 CloseServiceHandle(scm);
1263 PWSTR iid_str = NULL;
1271 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1278 if (StringFromIID(&guid, &iid_str) != S_OK)
1281 err = ERROR_OUTOFMEMORY;
1284 if (wcslen(iid_str) + 1 > len)
1286 err = ERROR_INVALID_PARAMETER;
1290 wcsncpy(str, iid_str, len);
1295 CoTaskMemFree(iid_str);
1317 DWORD size =
sizeof(data);
1318 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)data, &size);
1319 if (!err || err == ERROR_MORE_DATA)
1321 data[
sizeof(data) - 1] =
'\0';
1322 for (
int i = 0; i < strlen(data); ++i)
1324 if (isalnum(data[i]) || data[i] ==
'-' || data[i] ==
'.')
1358 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1359 "SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1360 0, KEY_ALL_ACCESS,
key);
1372 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1373 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1374 0, KEY_ALL_ACCESS,
key);
1392 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1393 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1394 0, KEY_ALL_ACCESS, &itfs);
1397 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1407 *
key = INVALID_HANDLE_VALUE;
1423 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1426 if (err == ERROR_FILE_NOT_FOUND)
1450 if (!list || wcslen(list) == 0)
1462 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1463 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1487 WCHAR list[2048] = {0};
1488 DWORD size =
sizeof(list);
1492 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1505 size_t listlen = (size /
sizeof(list[0])) - 1;
1506 size_t domlen = wcslen(domains);
1507 if (listlen + domlen + 2 > _countof(list))
1515 PWSTR
pos = list + listlen;
1517 wcsncpy(
pos + 1, domains, domlen + 1);
1521 wcsncpy(list, domains, wcslen(domains) + 1);
1524 size = (wcslen(list) + 1) *
sizeof(list[0]);
1525 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1553 DWORD size =
sizeof(list);
1555 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1558 if (err != ERROR_FILE_NOT_FOUND)
1566 size = (wcslen(list) + 1) *
sizeof(list[0]);
1567 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1575 RegDeleteValueA(
key,
"InitialSearchList");
1593 DWORD size =
sizeof(list);
1595 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1603 PWSTR dst = wcsstr(list, domains);
1611 size_t domlen = wcslen(domains);
1612 PCWSTR src = dst + domlen;
1614 dst = dst > list ? dst - 1 : dst;
1615 wmemmove(dst, src, domlen);
1617 size_t list_len = wcslen(list);
1621 WCHAR initial[2048];
1622 size =
sizeof(initial);
1623 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1632 if (wcsncmp(list, initial, wcslen(list)) == 0)
1639 size = (list_len + 1) *
sizeof(list[0]);
1640 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1657 HKEY dns_searchlist_key;
1659 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1662 RegCloseKey(dns_searchlist_key);
1694 DWORD err = ERROR_OUTOFMEMORY;
1698 if (list_key == INVALID_HANDLE_VALUE)
1701 return ERROR_FILE_NOT_FOUND;
1715 if (domains && *domains)
1717 wchar_t *wide_domains =
utf8to16(domains);
1723 undo_data = malloc(
sizeof(*undo_data));
1727 wide_domains = NULL;
1731 undo_data->
domains = wide_domains;
1747 RegCloseKey(list_key);
1761 PCSTR itfs_key = family == AF_INET6
1762 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1763 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1765 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1768 *
key = INVALID_HANDLE_VALUE;
1770 __func__, family, err);
1773 return err ? FALSE : TRUE;
1793 return ERROR_FILE_NOT_FOUND;
1796 HKEY itf = INVALID_HANDLE_VALUE;
1797 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1801 __func__, itf_id, family, err);
1805 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1809 __func__, value, itf_id, family, err);
1813 if (itf != INVALID_HANDLE_VALUE)
1817 if (itfs != INVALID_HANDLE_VALUE)
1858 int addr_len =
msg->addr_len;
1861 const size_t max_addrs = _countof(
msg->addr);
1862 if (addr_len > max_addrs)
1864 addr_len = max_addrs;
1867 if (!
msg->iface.name[0])
1875 msgptr->
iface.
name[_countof(
msg->iface.name)-1] =
'\0';
1876 msgptr->
domains[_countof(
msg->domains)-1] =
'\0';
1902 if (
msg->domains[0])
1911 if (
msg->addr_len > 0)
1916 CHAR addrs[_countof(
msg->addr) * 64];
1918 for (
int i = 0; i < addr_len; ++i)
1922 addrs[offset++] =
',';
1924 if (
msg->family == AF_INET6)
1926 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1930 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1932 offset += strlen(addrs);
1941 wchar_t *tmp_iid = _wcsdup(iid);
1942 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1946 return ERROR_OUTOFMEMORY;
1951 if (
msg->domains[0])
1972 DWORD size =
sizeof(
dhcp);
1975 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1976 if (err != NO_ERROR)
1982 return dhcp ? TRUE : FALSE;
1996 const short families[] = { AF_INET, AF_INET6 };
1997 for (
int i = 0; i < _countof(families); i++)
1999 short family = families[i];
2006 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
2007 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
2014 addr_list[offset++] =
',';
2016 strcpy(addr_list + offset, addresses[j]);
2017 offset += strlen(addresses[j]);
2049 addrs[*size - 1] =
'\0';
2053 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2054 if (err && err != ERROR_FILE_NOT_FOUND)
2064 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2072 if (strchr(addrs,
'.'))
2079 return ERROR_FILE_NOT_FOUND;
2094 addrs[*size - 1] =
'\0';
2098 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2099 if (err && err != ERROR_FILE_NOT_FOUND)
2108 IN6_ADDR in_addrs[8];
2109 DWORD in_addrs_size =
sizeof(in_addrs);
2110 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2111 (PBYTE)in_addrs, &in_addrs_size);
2120 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2121 for (
size_t i = 0; i < in_addrs_read; ++i)
2130 if (inet_ntop(AF_INET6, &in_addrs[i],
2134 return ERROR_MORE_DATA;
2137 size_t addr_len = strlen(
pos);
2141 s = strlen(addrs) + 1;
2144 if (strchr(addrs,
':'))
2151 return ERROR_FILE_NOT_FOUND;
2176 if (domains == NULL || size == 0)
2178 return ERROR_INVALID_PARAMETER;
2181 LSTATUS err = ERROR_FILE_NOT_FOUND;
2182 const DWORD buf_size = *size;
2183 const size_t one_glyph =
sizeof(*domains);
2184 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL};
2186 for (
int i = 0; values[i]; i++)
2189 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2190 if (!err && *size > one_glyph && wcschr(domains,
'.'))
2197 PWCHAR
pos = domains;
2198 const DWORD
buf_len = buf_size / one_glyph;
2202 PWCHAR comma = wcschr(
pos,
',');
2209 size_t converted_size =
pos - domains;
2210 size_t domain_len = wcslen(
pos) + 1;
2211 size_t domain_size = domain_len * one_glyph;
2212 size_t extra_size = 2 * one_glyph;
2213 if (converted_size + domain_size + extra_size > buf_size)
2217 *size = converted_size == 0 ? 0 : *size + 1;
2218 return ERROR_MORE_DATA;
2222 memmove(
pos + 1,
pos, buf_size - converted_size - one_glyph);
2230 *(
pos + domain_len) =
'\0';
2257 MIB_IF_ROW2 itf_row;
2260 if (IIDFromString(iid_str, &iid) != S_OK)
2267 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2273 if (GetIfEntry2(&itf_row) != NO_ERROR)
2279 if (itf_row.MediaConnectState == MediaConnectStateConnected
2280 && itf_row.OperStatus == IfOperStatusUp)
2300 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2301 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2310 DWORD enum_index = 0;
2311 while (i < data_size)
2313 WCHAR itf_guid[MAX_PATH];
2314 DWORD itf_guid_len = _countof(itf_guid);
2315 LSTATUS err = RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len,
2316 NULL, NULL, NULL, NULL);
2319 if (err != ERROR_NO_MORE_ITEMS)
2333 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2341 memset(data[i].domains, 0, data[i].domains_size);
2345 if (err != ERROR_FILE_NOT_FOUND)
2353 DWORD v4_addrs_size =
sizeof(data[0].
addresses);
2355 if (err && err != ERROR_FILE_NOT_FOUND)
2358 __func__, itf_guid, err);
2363 PSTR v6_addrs = data[i].
addresses + v4_addrs_size;
2364 DWORD v6_addrs_size =
sizeof(data[0].
addresses) - v4_addrs_size;
2368 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2374 RegCloseKey(v6_itf);
2375 if (err && err != ERROR_FILE_NOT_FOUND)
2378 __func__, itf_guid, err);
2383 if (v4_addrs_size || v6_addrs_size)
2386 for (
int j = 0; j <
sizeof(data[0].
addresses) && data[i].addresses[j]; j++)
2388 if (data[i].addresses[j] ==
',')
2397 RegCloseKey(v4_itf);
2401 RegCloseKey(v6_itfs);
2402 RegCloseKey(v4_itfs);
2419 PCWSTR domains, DWORD dom_size, BOOL dnssec)
2422 DWORD err = NO_ERROR;
2424 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2431 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2438 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address, strlen(
address) + 1);
2449 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
sizeof(reg_val));
2456 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
sizeof(reg_val));
2463 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
sizeof(reg_val));
2471 reg_val = dnssec ? 0x0000000A : 0x00000008;
2472 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2480 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2489 RegDeleteKeyW(nrpt_key, subkey);
2491 RegCloseKey(rule_key);
2507 memset(data, 0,
sizeof(data));
2511 for (
int i = 0; i < _countof(data); ++i)
2521 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2543 const char *domains, BOOL dnssec, DWORD ovpn_pid)
2545 DWORD err = NO_ERROR;
2546 PWSTR wide_domains = L
".\0";
2552 size_t domains_len = strlen(domains);
2553 dom_size = domains_len + 2;
2556 dom_size *=
sizeof(*wide_domains);
2559 return ERROR_OUTOFMEMORY;
2562 for (
size_t i = 0; i < domains_len; ++i)
2564 if (wide_domains[i] ==
',')
2566 wide_domains[i] = 0;
2577 PSTR
pos = addr_list;
2584 strcpy(
pos, addresses[i]);
2588 WCHAR subkey[MAX_PATH];
2589 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2590 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2620 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2621 static PCSTR sys_key =
"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2625 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2626 if (err == ERROR_FILE_NOT_FOUND)
2629 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, KEY_ALL_ACCESS, &nrpt);
2632 nrpt = INVALID_HANDLE_VALUE;
2666 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2667 pidlen = wcslen(pid_str);
2671 DWORD enum_index = 0;
2674 WCHAR name[MAX_PATH];
2675 DWORD namelen = _countof(name);
2676 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2679 if (err != ERROR_NO_MORE_ITEMS)
2687 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2688 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2693 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2701 return deleted ? TRUE : FALSE;
2740 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2745 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2750 if (
msg->iface.name[0] == 0)
2759 if (
msg->addresses[0][0] == 0)
2764 const char *rdom =
msg->resolve_domains;
2765 size_t rdom_size =
sizeof(
msg->resolve_domains);
2766 size_t rdom_len = strlen(rdom);
2767 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2773 BOOL gpol_nrpt = FALSE;
2774 BOOL gpol_list = FALSE;
2787 if (*undo_pid != ovpn_pid)
2790 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2791 "This is likely an error. Cleaning up anyway.",
2792 __func__, *undo_pid, ovpn_pid);
2816 PDWORD pid = malloc(
sizeof(ovpn_pid));
2819 err = ERROR_OUTOFMEMORY;
2825 err = ERROR_OUTOFMEMORY;
2846 if (
msg->search_domains[0])
2862 int addr_len =
msg->addr_len;
2865 if (addr_len > _countof(
msg->addr))
2867 addr_len = _countof(
msg->addr);
2870 if (!
msg->iface.name[0])
2878 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2884 return ERROR_OUTOFMEMORY;
2905 for (
int i = 0; i < addr_len; ++i)
2907 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2922 wchar_t *tmp_name = _wcsdup(wide_name);
2927 err = ERROR_OUTOFMEMORY;
2941 DWORD timeout = 5000;
2942 wchar_t argv0[MAX_PATH];
2945 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2950 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2955 size_t ncmdline = wcslen(fmt) + 10 + 1;
2956 wchar_t *cmdline = malloc(ncmdline*
sizeof(
wchar_t));
2959 err = ERROR_OUTOFMEMORY;
2963 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
2978 DWORD err = ERROR_SUCCESS;
2980 if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
2982 err = GetLastError();
2993 DWORD err = ERROR_SUCCESS;
2995 HANDLE dup_handle = NULL;
2998 if (err != ERROR_SUCCESS)
3002 *ring = (
struct tun_ring *)MapViewOfFile(dup_handle, FILE_MAP_ALL_ACCESS, 0, 0,
sizeof(
struct tun_ring));
3006 err = GetLastError();
3022 if (ring_buffer_maps)
3026 else if ((ring_buffer_maps = calloc(1,
sizeof(*ring_buffer_maps))) == NULL)
3028 return ERROR_OUTOFMEMORY;
3031 HANDLE device = NULL;
3032 HANDLE send_tail_moved = NULL;
3033 HANDLE receive_tail_moved = NULL;
3036 if (err != ERROR_SUCCESS)
3042 if (err != ERROR_SUCCESS)
3048 if (err != ERROR_SUCCESS)
3054 if (err != ERROR_SUCCESS)
3060 if (err != ERROR_SUCCESS)
3067 send_tail_moved, receive_tail_moved))
3069 err = GetLastError();
3077 if (err != ERROR_SUCCESS && ring_buffer_maps)
3080 free(ring_buffer_maps);
3092 MIB_IPINTERFACE_ROW ipiface;
3093 InitializeIpInterfaceEntry(&ipiface);
3094 ipiface.Family = mtu->
family;
3096 err = GetIpInterfaceEntry(&ipiface);
3097 if (err != NO_ERROR)
3101 if (mtu->
family == AF_INET)
3103 ipiface.SitePrefixLength = 0;
3105 ipiface.NlMtu = mtu->
mtu;
3107 err = SetIpInterfaceEntry(&ipiface);
3123 switch (
msg->adapter_type)
3130 hwid = L
"root\\tap0901";
3138 return ERROR_INVALID_PARAMETER;
3141 WCHAR cmd[MAX_PATH];
3142 WCHAR args[MAX_PATH];
3144 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3146 return ERROR_BUFFER_OVERFLOW;
3149 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3151 return ERROR_BUFFER_OVERFLOW;
3159 DWORD bytes, DWORD count, LPHANDLE events,
undo_lists_t *lists)
3165 .size =
sizeof(ack),
3179 switch (
msg.header.type)
3183 if (
msg.header.size ==
sizeof(
msg.address))
3191 if (
msg.header.size ==
sizeof(
msg.route))
3198 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3206 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3224 DWORD ovpn_pid = proc_info->dwProcessId;
3235 if (
msg.header.size ==
sizeof(
msg.dhcp))
3242 if (
msg.header.size ==
sizeof(
msg.rrb))
3244 HANDLE ovpn_hnd = proc_info->hProcess;
3250 if (
msg.header.size ==
sizeof(
msg.mtu))
3257 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3340 *pnext = item->
next;
3351 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3352 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3353 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3354 HANDLE stdin_read = NULL, stdin_write = NULL;
3355 HANDLE stdout_write = NULL;
3356 DWORD pipe_mode, len, exit_code = 0;
3358 STARTUPINFOW startup_info;
3359 PROCESS_INFORMATION proc_info;
3360 LPVOID user_env = NULL;
3361 WCHAR ovpn_pipe_name[256];
3363 WCHAR *cmdline = NULL;
3364 size_t cmdline_size;
3366 WCHAR errmsg[512] = L
"";
3368 SECURITY_ATTRIBUTES inheritable = {
3369 .nLength =
sizeof(inheritable),
3370 .lpSecurityDescriptor = NULL,
3371 .bInheritHandle = TRUE
3375 EXPLICIT_ACCESS ea[2];
3376 SECURITY_DESCRIPTOR ovpn_sd;
3377 SECURITY_ATTRIBUTES ovpn_sa = {
3378 .nLength =
sizeof(ovpn_sa),
3379 .lpSecurityDescriptor = &ovpn_sd,
3380 .bInheritHandle = FALSE
3383 ZeroMemory(&ea,
sizeof(ea));
3384 ZeroMemory(&startup_info,
sizeof(startup_info));
3385 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3386 ZeroMemory(&proc_info,
sizeof(proc_info));
3393 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3400 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3406 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3408 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3414 svc_user = malloc(len);
3415 if (svc_user == NULL)
3421 if (!IsValidSid(svc_user->User.Sid))
3427 if (!ImpersonateNamedPipeClient(pipe))
3432 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3438 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3440 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3446 ovpn_user = malloc(len);
3447 if (ovpn_user == NULL)
3453 if (!IsValidSid(ovpn_user->User.Sid))
3474 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3475 ea[0].grfAccessMode = SET_ACCESS;
3476 ea[0].grfInheritance = NO_INHERITANCE;
3477 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3478 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3479 ea[0].Trustee.ptstrName = (LPWSTR) svc_user->User.Sid;
3480 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ
3481 |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3482 ea[1].grfAccessMode = SET_ACCESS;
3483 ea[1].grfInheritance = NO_INHERITANCE;
3484 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3485 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3486 ea[1].Trustee.ptstrName = (LPWSTR) ovpn_user->User.Sid;
3489 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3494 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3499 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3506 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3513 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
3514 &inheritable, OPEN_EXISTING, 0, NULL);
3515 if (stdout_write == INVALID_HANDLE_VALUE)
3521 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3522 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3528 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3530 ovpn_pipe = CreateNamedPipe(ovpn_pipe_name,
3531 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3532 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
3533 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3539 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
3540 &inheritable, OPEN_EXISTING, 0, NULL);
3541 if (svc_pipe == INVALID_HANDLE_VALUE)
3547 pipe_mode = PIPE_READMODE_MESSAGE;
3548 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3554 cmdline_size = wcslen(sud.
options) + 128;
3555 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3556 if (cmdline == NULL)
3564 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR,
3565 sud.
options, (uintptr_t)svc_pipe);
3567 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3573 startup_info.cb =
sizeof(startup_info);
3574 startup_info.dwFlags = STARTF_USESTDHANDLES;
3575 startup_info.hStdInput = stdin_read;
3576 startup_info.hStdOutput = stdout_write;
3577 startup_info.hStdError = stdout_write;
3582 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3584 user_env, sud.
directory, &startup_info, &proc_info))
3590 if (!RevertToSelf())
3592 TerminateProcess(proc_info.hProcess, 1);
3603 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3605 if (input_size && (input = malloc(input_size)))
3608 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3609 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3624 MsgToEventLog(
MSG_FLAGS_ERROR, L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated", bytes);
3631 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3632 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3633 if (exit_code == STILL_ACTIVE)
3635 TerminateProcess(proc_info.hProcess, 1);
3637 else if (exit_code != 0)
3640 swprintf(buf, _countof(buf),
3641 L
"OpenVPN exited with error: exit code = %lu", exit_code);
3647 FlushFileBuffers(pipe);
3648 DisconnectNamedPipe(pipe);
3653 DestroyEnvironmentBlock(user_env);
3674 SERVICE_STATUS *
status = ctx;
3677 case SERVICE_CONTROL_STOP:
3678 status->dwCurrentState = SERVICE_STOP_PENDING;
3686 case SERVICE_CONTROL_INTERROGATE:
3690 return ERROR_CALL_NOT_IMPLEMENTED;
3704 const WCHAR *sddlString = 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)";
3706 PSECURITY_DESCRIPTOR sd = NULL;
3707 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd, NULL))
3710 return INVALID_HANDLE_VALUE;
3714 SECURITY_ATTRIBUTES sa = {0};
3715 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3716 sa.lpSecurityDescriptor = sd;
3717 sa.bInheritHandle = FALSE;
3719 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3721 static BOOL first = TRUE;
3724 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3728 WCHAR pipe_name[256];
3730 HANDLE pipe = CreateNamedPipe(pipe_name, flags,
3731 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3732 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3736 if (pipe == INVALID_HANDLE_VALUE)
3739 return INVALID_HANDLE_VALUE;
3750 static DWORD size = 10;
3751 static LPHANDLE handles = NULL;
3754 if (handles == NULL)
3756 handles = malloc(size *
sizeof(HANDLE));
3757 *handles_ptr = handles;
3758 if (handles == NULL)
3760 return ERROR_OUTOFMEMORY;
3764 handles[
pos++] = io_event;
3777 tmp = realloc(handles, size *
sizeof(HANDLE));
3782 return ERROR_OUTOFMEMORY;
3785 *handles_ptr = handles;
3787 handles[
pos++] = threads->
data;
3788 threads = threads->
next;
3812 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3824 BOOL changed = FALSE;
3834 if (
key != INVALID_HANDLE_VALUE)
3852 HANDLE pipe, io_event = NULL;
3853 OVERLAPPED overlapped;
3854 DWORD error = NO_ERROR;
3856 PHANDLE handles = NULL;
3865 status.dwCurrentState = SERVICE_START_PENDING;
3866 status.dwServiceSpecificExitCode = NO_ERROR;
3867 status.dwWin32ExitCode = NO_ERROR;
3868 status.dwWaitHint = 3000;
3876 if (error != ERROR_SUCCESS)
3882 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3897 if (error != NO_ERROR)
3903 if (pipe == INVALID_HANDLE_VALUE)
3908 status.dwCurrentState = SERVICE_RUNNING;
3914 if (ConnectNamedPipe(pipe, &overlapped) == FALSE
3915 && GetLastError() != ERROR_PIPE_CONNECTED
3916 && GetLastError() != ERROR_IO_PENDING)
3922 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3923 if (error == WAIT_OBJECT_0)
3927 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3941 TerminateThread(thread, 1);
3947 ResumeThread(thread);
3961 if (error == WAIT_FAILED)
3991 status.dwCurrentState = SERVICE_STOPPED;
3992 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 OvpnUnmapViewOfFile(struct tun_ring **ring)
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 SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid)
Set NRPT exclude rules to accompany a catch all rule.
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 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 DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL CmpWString(LPVOID item, LPVOID str)
static HANDLE CreateClientPipeInstance(VOID)
static DWORD SetNameServersValue(PCWSTR itf_id, short family, PCSTR value)
Set the DNS name servers in a registry interface configuration.
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
static DWORD DeleteWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL DeleteNrptRules(DWORD pid, PBOOL gpol)
Delete OpenVPN NRPT rules from the registry.
static VOID Undo(undo_lists_t *lists)
static BOOL ApplyDnsSettings(BOOL apply_gpol)
Signal the DNS resolver to reload its settings.
#define ERROR_STARTUP_DATA
static DWORD WINAPI RunOpenvpn(LPVOID p)
static settings_t settings
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
static SERVICE_STATUS status
static DWORD HandleDNSConfigNrptMessage(const nrpt_dns_cfg_message_t *msg, DWORD ovpn_pid, undo_lists_t *lists)
Add Name Resolution Policy Table (NRPT) rules as documented in https://msdn.microsoft....
static DWORD SetDnsSearchDomains(PCSTR itf_name, PCSTR domains, PBOOL gpol, undo_lists_t *lists)
Add or remove DNS search domains.
static DWORD DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, struct tun_ring **ring)
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 DWORD OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle)
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 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 DWORD HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc, undo_lists_t *lists)
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 LSTATUS GetItfDnsDomains(HKEY itf, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es)
static void GetNrptExcludeData(nrpt_exclude_data_t *data, size_t data_size)
Collect interface DNS settings to be used in excluding NRPT rules.
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 SetNrptRules(HKEY nrpt_key, const nrpt_address_t *addresses, const char *domains, BOOL dnssec, DWORD ovpn_pid)
Set NRPT rules for a openvpn process.
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 void UnmapRingBuffer(ring_buffer_maps_t *ring_buffer_maps)
static BOOL CmpAny(LPVOID item, LPVOID any)
static DWORD netsh_wins_cmd(const wchar_t *action, const wchar_t *if_name, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_name [static] $addr.
static DWORD HandleCreateAdapterMessage(const create_adapter_message_t *msg)
Creates a VPN adapter of the specified type by invoking tapctl.exe.
static DWORD InterfaceIdString(PCSTR itf_name, PWSTR str, size_t len)
Get the string interface UUID (with braces) for an interface alias name.
static SERVICE_STATUS_HANDLE service
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
static void UndoDnsSearchDomains(dns_domains_undo_data_t *undo_data)
Removes DNS domains from a search list they were previously added to.
char nrpt_address_t[NRPT_ADDR_SIZE]
@ msg_register_ring_buffers
static bool register_ring_buffers(HANDLE device, struct tun_ring *send_ring, struct tun_ring *receive_ring, HANDLE send_tail_moved, HANDLE receive_tail_moved)
Registers ring buffers used to exchange data between userspace openvpn process and wintun kernel driv...
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]
HANDLE receive_tail_moved
HANDLE receive_ring_handle
struct tun_ring * receive_ring
struct tun_ring * send_ring
WCHAR ovpn_admin_group[MAX_NAME]
WCHAR ovpn_service_user[MAX_NAME]
Wintun ring buffer See https://github.com/WireGuard/wintun#ring-layout.
UCHAR data[WINTUN_RING_CAPACITY+WINTUN_RING_TRAILING_BYTES]
address_message_t address
flush_neighbors_message_t flush_neighbors
wfp_block_message_t wfp_block
enable_dhcp_message_t dhcp
register_ring_buffers_message_t rrb
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)