38#include <versionhelpers.h>
44#define IO_TIMEOUT 2000
46#define ERROR_OPENVPN_STARTUP 0x20000000
47#define ERROR_STARTUP_DATA 0x20000001
48#define ERROR_MESSAGE_DATA 0x20000002
49#define ERROR_MESSAGE_TYPE 0x20000003
52static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
56#define RDNS_TIMEOUT 600
58#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
134 if (new_item == NULL)
136 return ERROR_OUTOFMEMORY;
139 new_item->
next = *pfirst;
140 new_item->
data = data;
154 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
157 if (!match(item->
data, ctx))
175 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
177 CloseHandle(*handle);
178 *handle = INVALID_HANDLE_VALUE;
180 return INVALID_HANDLE_VALUE;
186 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
187 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
188 return overlapped->hEvent;
194 HANDLE io_event = overlapped->hEvent;
195 if (!ResetEvent(io_event))
199 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
200 overlapped->hEvent = io_event;
217 DWORD res, bytes = 0;
218 OVERLAPPED overlapped;
219 LPHANDLE handles = NULL;
227 handles = malloc((count + 1) *
sizeof(HANDLE));
235 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
239 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
241 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
246 handles[0] = io_event;
247 for (i = 0; i < count; i++)
249 handles[i + 1] = events[i];
252 res = WaitForMultipleObjects(count + 1, handles, FALSE,
254 if (res != WAIT_OBJECT_0)
262 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
266 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
288WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
296 const WCHAR
msg[] = L
"Process ID";
297 WCHAR buf[22 + _countof(
msg)];
303 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
305 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
309ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
312 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
321 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
322 |FORMAT_MESSAGE_ALLOCATE_BUFFER
323 |FORMAT_MESSAGE_IGNORE_INSERTS,
324 0, error, 0, (LPWSTR) &args[2], 0, NULL);
327 result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
328 |FORMAT_MESSAGE_ALLOCATE_BUFFER
329 |FORMAT_MESSAGE_ARGUMENT_ARRAY,
330 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
331 (LPWSTR) &result, 0, (va_list *) args);
333 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
338 LocalFree((LPVOID) args[2]);
309ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events) {
…}
365 const WCHAR *msg1 = L
"You have specified a config file location (%ls relative to %ls)"
366 L
" that requires admin approval. This error may be avoided"
367 L
" by adding your account to the \"%ls\" group";
369 const WCHAR *msg2 = L
"You have specified an option (%ls) that may be used"
370 L
" only with admin approval. This error may be avoided"
371 L
" by adding your account to the \"%ls\" group";
377 swprintf(errmsg, capacity,
378 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
395 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
399 swprintf(errmsg, capacity, msg1,
argv[0], workdir,
405 for (i = 0; i < argc; ++i)
414 if (wcscmp(L
"--config",
argv[i]) == 0 && argc-i > 1)
416 swprintf(errmsg, capacity, msg1,
argv[i+1], workdir,
421 swprintf(errmsg, capacity, msg2,
argv[i],
454 size = bytes /
sizeof(*data);
462 data = malloc(bytes);
478 if (data[size - 1] != 0)
496 len = wcslen(sud->
options) + 1;
525 SOCKADDR_INET sa_inet;
526 ZeroMemory(&sa_inet,
sizeof(sa_inet));
527 sa_inet.si_family = family;
528 if (family == AF_INET)
530 sa_inet.Ipv4.sin_addr = addr->
ipv4;
532 else if (family == AF_INET6)
534 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
543 LPWSTR wide_name =
utf8to16(iface_name);
547 status = ConvertInterfaceAliasToLuid(wide_name, luid);
552 status = ERROR_OUTOFMEMORY;
560 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
566 return DeleteUnicastIpAddressEntry(addr_row);
573 PMIB_UNICASTIPADDRESS_ROW addr_row;
576 addr_row = malloc(
sizeof(*addr_row));
577 if (addr_row == NULL)
579 return ERROR_OUTOFMEMORY;
582 InitializeUnicastIpAddressEntry(addr_row);
584 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
586 if (
msg->iface.index != -1)
588 addr_row->InterfaceIndex =
msg->iface.index;
598 addr_row->InterfaceLuid = luid;
603 err = CreateUnicastIpAddressEntry(addr_row);
638 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
644 return DeleteIpForwardEntry2(fwd_row);
651 PMIB_IPFORWARD_ROW2 fwd_row;
654 fwd_row = malloc(
sizeof(*fwd_row));
657 return ERROR_OUTOFMEMORY;
660 ZeroMemory(fwd_row,
sizeof(*fwd_row));
661 fwd_row->ValidLifetime = 0xffffffff;
662 fwd_row->PreferredLifetime = 0xffffffff;
663 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
664 fwd_row->Metric =
msg->metric;
666 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
669 if (
msg->iface.index != -1)
671 fwd_row->InterfaceIndex =
msg->iface.index;
673 else if (strlen(
msg->iface.name))
681 fwd_row->InterfaceLuid = luid;
686 err = CreateIpForwardEntry2(fwd_row);
722 if (
msg->family == AF_INET)
724 return FlushIpNetTable(
msg->iface.index);
727 return FlushIpNetTable2(
msg->family,
msg->iface.index);
741 err_str = L
"Unknown Win32 Error";
743 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
744 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
745 NULL, err, 0, buf,
sizeof(buf), NULL))
794 HANDLE engine = NULL;
807 err = ERROR_OUTOFMEMORY;
810 block_data->
engine = engine;
811 block_data->
index =
msg->iface.index;
879ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
883 PROCESS_INFORMATION pi;
884 DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
885 WCHAR *cmdline_dup = NULL;
887 ZeroMemory(&si,
sizeof(si));
888 ZeroMemory(&pi,
sizeof(pi));
893 cmdline_dup = _wcsdup(cmdline);
894 if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE,
895 proc_flags, NULL, NULL, &si, &pi) )
897 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
898 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
901 exit_code = GetLastError();
903 else if (exit_code == STILL_ACTIVE)
905 exit_code = WAIT_TIMEOUT;
908 TerminateProcess(pi.hProcess, exit_code);
915 argv0, cmdline, exit_code);
922 CloseHandle(pi.hProcess);
923 CloseHandle(pi.hThread);
927 exit_code = GetLastError();
879ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout) {
…}
947 WCHAR ipcfg[MAX_PATH];
955 { ipcfg, L
"ipconfig /flushdns", timeout },
956 { ipcfg, L
"ipconfig /registerdns", timeout },
961 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
963 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
966 for (i = 0; i < _countof(cmds); ++i)
968 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
979 err = ERROR_SEM_TIMEOUT;
988 HANDLE thread = NULL;
991 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
1000 CloseHandle(thread);
1004 err = GetLastError();
1023 int timeout = 30000;
1024 wchar_t argv0[MAX_PATH];
1025 wchar_t *cmdline = NULL;
1026 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1030 if (wcscmp(action, L
"delete") == 0)
1041 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1046 const wchar_t *fmt = L
"netsh interface ip %ls wins \"%ls\" %ls %ls";
1049 size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(action) + wcslen(addr)
1050 +wcslen(addr_static) + 32 + 1;
1051 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1054 err = ERROR_OUTOFMEMORY;
1058 swprintf(cmdline, ncmdline, fmt, action, if_name, addr_static, addr);
1070 return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1082 typedef NTSTATUS (__stdcall *publish_fn_t)(
1088 DWORD ExplicitScope);
1089 publish_fn_t RtlPublishWnfStateData;
1090 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1091 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1093 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1099 RtlPublishWnfStateData = (publish_fn_t) GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1100 if (RtlPublishWnfStateData == NULL)
1105 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0) != ERROR_SUCCESS)
1122 typedef NTSTATUS (*publish_fn_t)(
1126 unsigned int Length,
1127 INT64 ExplicitScope);
1128 publish_fn_t RtlPublishWnfStateData;
1129 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1131 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1137 RtlPublishWnfStateData = (publish_fn_t) GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1138 if (RtlPublishWnfStateData == NULL)
1143 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1161 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1176 SC_HANDLE scm = NULL;
1177 SC_HANDLE dnssvc = NULL;
1184 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1188 __func__, GetLastError());
1192 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1196 __func__, GetLastError());
1201 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1204 __func__, GetLastError());
1213 CloseServiceHandle(dnssvc);
1217 CloseServiceHandle(scm);
1237 PWSTR iid_str = NULL;
1245 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1252 if (StringFromIID(&guid, &iid_str) != S_OK)
1255 err = ERROR_OUTOFMEMORY;
1258 if (wcslen(iid_str) + 1 > len)
1260 err = ERROR_INVALID_PARAMETER;
1264 wcsncpy(str, iid_str, len);
1269 CoTaskMemFree(iid_str);
1291 DWORD size =
sizeof(data);
1292 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)data, &size);
1293 if (!err || err == ERROR_MORE_DATA)
1295 data[
sizeof(data) - 1] =
'\0';
1296 for (
int i = 0; i < strlen(data); ++i)
1298 if (isalnum(data[i]) || data[i] ==
'-' || data[i] ==
'.')
1332 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1333 "SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1334 0, KEY_ALL_ACCESS,
key);
1346 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1347 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1348 0, KEY_ALL_ACCESS,
key);
1366 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1367 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1368 0, KEY_ALL_ACCESS, &itfs);
1371 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1381 *
key = INVALID_HANDLE_VALUE;
1397 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1400 if (err == ERROR_FILE_NOT_FOUND)
1424 if (!list || wcslen(list) == 0)
1436 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1437 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1461 WCHAR list[2048] = {0};
1462 DWORD size =
sizeof(list);
1466 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1479 size_t listlen = (size /
sizeof(list[0])) - 1;
1480 size_t domlen = wcslen(domains);
1481 if (listlen + domlen + 2 > _countof(list))
1489 PWSTR
pos = list + listlen;
1491 wcsncpy(
pos + 1, domains, domlen + 1);
1495 wcsncpy(list, domains, wcslen(domains) + 1);
1498 size = (wcslen(list) + 1) *
sizeof(list[0]);
1499 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1527 DWORD size =
sizeof(list);
1529 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1532 if (err != ERROR_FILE_NOT_FOUND)
1540 size = (wcslen(list) + 1) *
sizeof(list[0]);
1541 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1549 RegDeleteValueA(
key,
"InitialSearchList");
1567 DWORD size =
sizeof(list);
1569 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1577 PWSTR dst = wcsstr(list, domains);
1585 size_t domlen = wcslen(domains);
1586 PCWSTR src = dst + domlen;
1588 dst = dst > list ? dst - 1 : dst;
1589 wmemmove(dst, src, domlen);
1591 size_t list_len = wcslen(list);
1595 WCHAR initial[2048];
1596 size =
sizeof(initial);
1597 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1606 if (wcsncmp(list, initial, wcslen(list)) == 0)
1613 size = (list_len + 1) *
sizeof(list[0]);
1614 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1631 HKEY dns_searchlist_key;
1633 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1636 RegCloseKey(dns_searchlist_key);
1668 DWORD err = ERROR_OUTOFMEMORY;
1672 if (list_key == INVALID_HANDLE_VALUE)
1675 return ERROR_FILE_NOT_FOUND;
1689 if (domains && *domains)
1691 wchar_t *wide_domains =
utf8to16(domains);
1697 undo_data = malloc(
sizeof(*undo_data));
1701 wide_domains = NULL;
1705 undo_data->
domains = wide_domains;
1721 RegCloseKey(list_key);
1735 PCSTR itfs_key = family == AF_INET6
1736 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1737 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1739 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1742 *
key = INVALID_HANDLE_VALUE;
1744 __func__, family, err);
1747 return err ? FALSE : TRUE;
1767 return ERROR_FILE_NOT_FOUND;
1770 HKEY itf = INVALID_HANDLE_VALUE;
1771 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1775 __func__, itf_id, family, err);
1779 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1783 __func__, value, itf_id, family, err);
1787 if (itf != INVALID_HANDLE_VALUE)
1791 if (itfs != INVALID_HANDLE_VALUE)
1832 int addr_len =
msg->addr_len;
1835 const size_t max_addrs = _countof(
msg->addr);
1836 if (addr_len > max_addrs)
1838 addr_len = max_addrs;
1841 if (!
msg->iface.name[0])
1849 msgptr->
iface.
name[_countof(
msg->iface.name)-1] =
'\0';
1850 msgptr->
domains[_countof(
msg->domains)-1] =
'\0';
1876 if (
msg->domains[0])
1885 if (
msg->addr_len > 0)
1890 CHAR addrs[_countof(
msg->addr) * 64];
1892 for (
int i = 0; i < addr_len; ++i)
1896 addrs[offset++] =
',';
1898 if (
msg->family == AF_INET6)
1900 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1904 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1906 offset += strlen(addrs);
1915 wchar_t *tmp_iid = _wcsdup(iid);
1916 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1920 return ERROR_OUTOFMEMORY;
1925 if (
msg->domains[0])
1946 DWORD size =
sizeof(
dhcp);
1949 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1950 if (err != NO_ERROR)
1956 return dhcp ? TRUE : FALSE;
1970 const short families[] = { AF_INET, AF_INET6 };
1971 for (
int i = 0; i < _countof(families); i++)
1973 short family = families[i];
1980 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1981 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1988 addr_list[offset++] =
',';
1990 strcpy(addr_list + offset, addresses[j]);
1991 offset += strlen(addresses[j]);
2023 addrs[*size - 1] =
'\0';
2027 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2028 if (err && err != ERROR_FILE_NOT_FOUND)
2038 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2046 if (strchr(addrs,
'.'))
2053 return ERROR_FILE_NOT_FOUND;
2068 addrs[*size - 1] =
'\0';
2072 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2073 if (err && err != ERROR_FILE_NOT_FOUND)
2082 IN6_ADDR in_addrs[8];
2083 DWORD in_addrs_size =
sizeof(in_addrs);
2084 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2085 (PBYTE)in_addrs, &in_addrs_size);
2094 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2095 for (
size_t i = 0; i < in_addrs_read; ++i)
2104 if (inet_ntop(AF_INET6, &in_addrs[i],
2108 return ERROR_MORE_DATA;
2111 size_t addr_len = strlen(
pos);
2115 s = strlen(addrs) + 1;
2118 if (strchr(addrs,
':'))
2125 return ERROR_FILE_NOT_FOUND;
2140 PCWSTR match = list;
2143 match = wcsstr(match, domain);
2149 if ((match == list || *(match - 1) ==
',')
2150 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2184 if (domains == NULL || size == 0)
2186 return ERROR_INVALID_PARAMETER;
2189 LSTATUS err = ERROR_FILE_NOT_FOUND;
2190 const DWORD buf_size = *size;
2191 const size_t one_glyph =
sizeof(*domains);
2192 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL};
2194 for (
int i = 0; values[i]; i++)
2197 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2198 if (!err && *size > one_glyph && wcschr(domains,
'.'))
2205 PWCHAR
pos = domains;
2206 const DWORD
buf_len = buf_size / one_glyph;
2210 PWCHAR comma = wcschr(
pos,
',');
2217 size_t domain_len = wcslen(
pos);
2230 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2236 size_t converted_size =
pos - domains;
2237 size_t domain_size = domain_len * one_glyph;
2238 size_t extra_size = 2 * one_glyph;
2239 if (converted_size + domain_size + extra_size > buf_size)
2243 *size = converted_size == 0 ? 0 : *size + 1;
2244 return ERROR_MORE_DATA;
2248 memmove(
pos + 1,
pos, buf_size - converted_size - one_glyph);
2256 *(
pos + domain_len) =
'\0';
2283 MIB_IF_ROW2 itf_row;
2286 if (IIDFromString(iid_str, &iid) != S_OK)
2293 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2299 if (GetIfEntry2(&itf_row) != NO_ERROR)
2305 if (itf_row.MediaConnectState == MediaConnectStateConnected
2306 && itf_row.OperStatus == IfOperStatusUp)
2327 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2328 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2337 DWORD enum_index = 0;
2338 while (i < data_size)
2340 WCHAR itf_guid[MAX_PATH];
2341 DWORD itf_guid_len = _countof(itf_guid);
2342 LSTATUS err = RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len,
2343 NULL, NULL, NULL, NULL);
2346 if (err != ERROR_NO_MORE_ITEMS)
2360 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2368 memset(data[i].domains, 0, data[i].domains_size);
2369 err =
GetItfDnsDomains(v4_itf, search_domains, data[i].domains, &data[i].domains_size);
2372 if (err != ERROR_FILE_NOT_FOUND)
2380 DWORD v4_addrs_size =
sizeof(data[0].
addresses);
2382 if (err && err != ERROR_FILE_NOT_FOUND)
2385 __func__, itf_guid, err);
2390 PSTR v6_addrs = data[i].
addresses + v4_addrs_size;
2391 DWORD v6_addrs_size =
sizeof(data[0].
addresses) - v4_addrs_size;
2395 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2401 RegCloseKey(v6_itf);
2402 if (err && err != ERROR_FILE_NOT_FOUND)
2405 __func__, itf_guid, err);
2410 if (v4_addrs_size || v6_addrs_size)
2413 for (
int j = 0; j <
sizeof(data[0].
addresses) && data[i].addresses[j]; j++)
2415 if (data[i].addresses[j] ==
',' || data[i].addresses[j] ==
' ')
2424 RegCloseKey(v4_itf);
2428 RegCloseKey(v6_itfs);
2429 RegCloseKey(v4_itfs);
2446 PCWSTR domains, DWORD dom_size, BOOL dnssec)
2449 DWORD err = NO_ERROR;
2451 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2458 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2465 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address, strlen(
address) + 1);
2476 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
sizeof(reg_val));
2483 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
sizeof(reg_val));
2490 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
sizeof(reg_val));
2498 reg_val = dnssec ? 0x0000000A : 0x00000008;
2499 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2507 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2516 RegDeleteKeyW(nrpt_key, subkey);
2518 RegCloseKey(rule_key);
2535 memset(data, 0,
sizeof(data));
2539 for (
int i = 0; i < _countof(data); ++i)
2549 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2572 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2574 DWORD err = NO_ERROR;
2575 PWSTR wide_domains = L
".\0";
2581 size_t domains_len = strlen(domains);
2582 dom_size = domains_len + 2;
2585 dom_size *=
sizeof(*wide_domains);
2588 return ERROR_OUTOFMEMORY;
2591 for (
size_t i = 0; i < domains_len; ++i)
2593 if (wide_domains[i] ==
',')
2595 wide_domains[i] = 0;
2601 PWSTR wide_search_domains;
2602 wide_search_domains =
utf8to16(search_domains);
2603 if (!wide_search_domains)
2605 return ERROR_OUTOFMEMORY;
2608 free(wide_search_domains);
2613 PSTR
pos = addr_list;
2620 strcpy(
pos, addresses[i]);
2624 WCHAR subkey[MAX_PATH];
2625 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2626 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2656 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2657 static PCSTR sys_key =
"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2661 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2662 if (err == ERROR_FILE_NOT_FOUND)
2665 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, KEY_ALL_ACCESS, &nrpt);
2668 nrpt = INVALID_HANDLE_VALUE;
2702 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2703 pidlen = wcslen(pid_str);
2707 DWORD enum_index = 0;
2710 WCHAR name[MAX_PATH];
2711 DWORD namelen = _countof(name);
2712 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2715 if (err != ERROR_NO_MORE_ITEMS)
2723 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2724 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2729 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2737 return deleted ? TRUE : FALSE;
2776 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2781 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2786 if (
msg->iface.name[0] == 0)
2795 if (
msg->addresses[0][0] == 0)
2800 const char *rdom =
msg->resolve_domains;
2801 size_t rdom_size =
sizeof(
msg->resolve_domains);
2802 size_t rdom_len = strlen(rdom);
2803 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2809 BOOL gpol_nrpt = FALSE;
2810 BOOL gpol_list = FALSE;
2823 if (*undo_pid != ovpn_pid)
2826 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2827 "This is likely an error. Cleaning up anyway.",
2828 __func__, *undo_pid, ovpn_pid);
2852 PDWORD pid = malloc(
sizeof(ovpn_pid));
2855 err = ERROR_OUTOFMEMORY;
2861 err = ERROR_OUTOFMEMORY;
2882 if (
msg->search_domains[0])
2898 int addr_len =
msg->addr_len;
2901 if (addr_len > _countof(
msg->addr))
2903 addr_len = _countof(
msg->addr);
2906 if (!
msg->iface.name[0])
2914 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2920 return ERROR_OUTOFMEMORY;
2941 for (
int i = 0; i < addr_len; ++i)
2943 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2958 wchar_t *tmp_name = _wcsdup(wide_name);
2963 err = ERROR_OUTOFMEMORY;
2977 DWORD timeout = 5000;
2978 wchar_t argv0[MAX_PATH];
2981 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2986 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2991 size_t ncmdline = wcslen(fmt) + 10 + 1;
2992 wchar_t *cmdline = malloc(ncmdline*
sizeof(
wchar_t));
2995 err = ERROR_OUTOFMEMORY;
2999 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3015 MIB_IPINTERFACE_ROW ipiface;
3016 InitializeIpInterfaceEntry(&ipiface);
3017 ipiface.Family = mtu->
family;
3019 err = GetIpInterfaceEntry(&ipiface);
3020 if (err != NO_ERROR)
3024 if (mtu->
family == AF_INET)
3026 ipiface.SitePrefixLength = 0;
3028 ipiface.NlMtu = mtu->
mtu;
3030 err = SetIpInterfaceEntry(&ipiface);
3046 switch (
msg->adapter_type)
3053 hwid = L
"root\\tap0901";
3057 return ERROR_INVALID_PARAMETER;
3060 WCHAR cmd[MAX_PATH];
3061 WCHAR args[MAX_PATH];
3063 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3065 return ERROR_BUFFER_OVERFLOW;
3068 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3070 return ERROR_BUFFER_OVERFLOW;
3078 DWORD bytes, DWORD count, LPHANDLE events,
undo_lists_t *lists)
3084 .size =
sizeof(ack),
3098 switch (
msg.header.type)
3102 if (
msg.header.size ==
sizeof(
msg.address))
3110 if (
msg.header.size ==
sizeof(
msg.route))
3117 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3125 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3143 DWORD ovpn_pid = proc_info->dwProcessId;
3154 if (
msg.header.size ==
sizeof(
msg.dhcp))
3161 if (
msg.header.size ==
sizeof(
msg.mtu))
3168 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3247 *pnext = item->
next;
3258 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3259 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3260 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3261 HANDLE stdin_read = NULL, stdin_write = NULL;
3262 HANDLE stdout_write = NULL;
3263 DWORD pipe_mode, len, exit_code = 0;
3265 STARTUPINFOW startup_info;
3266 PROCESS_INFORMATION proc_info;
3267 LPVOID user_env = NULL;
3268 WCHAR ovpn_pipe_name[256];
3270 WCHAR *cmdline = NULL;
3271 size_t cmdline_size;
3273 WCHAR errmsg[512] = L
"";
3275 SECURITY_ATTRIBUTES inheritable = {
3276 .nLength =
sizeof(inheritable),
3277 .lpSecurityDescriptor = NULL,
3278 .bInheritHandle = TRUE
3282 EXPLICIT_ACCESS ea[2];
3283 SECURITY_DESCRIPTOR ovpn_sd;
3284 SECURITY_ATTRIBUTES ovpn_sa = {
3285 .nLength =
sizeof(ovpn_sa),
3286 .lpSecurityDescriptor = &ovpn_sd,
3287 .bInheritHandle = FALSE
3290 ZeroMemory(&ea,
sizeof(ea));
3291 ZeroMemory(&startup_info,
sizeof(startup_info));
3292 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3293 ZeroMemory(&proc_info,
sizeof(proc_info));
3300 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3307 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3313 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3315 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3321 svc_user = malloc(len);
3322 if (svc_user == NULL)
3328 if (!IsValidSid(svc_user->User.Sid))
3334 if (!ImpersonateNamedPipeClient(pipe))
3339 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3345 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3347 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3353 ovpn_user = malloc(len);
3354 if (ovpn_user == NULL)
3360 if (!IsValidSid(ovpn_user->User.Sid))
3381 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3382 ea[0].grfAccessMode = SET_ACCESS;
3383 ea[0].grfInheritance = NO_INHERITANCE;
3384 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3385 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3386 ea[0].Trustee.ptstrName = (LPWSTR) svc_user->User.Sid;
3387 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ
3388 |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3389 ea[1].grfAccessMode = SET_ACCESS;
3390 ea[1].grfInheritance = NO_INHERITANCE;
3391 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3392 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3393 ea[1].Trustee.ptstrName = (LPWSTR) ovpn_user->User.Sid;
3396 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3401 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3406 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3413 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3420 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
3421 &inheritable, OPEN_EXISTING, 0, NULL);
3422 if (stdout_write == INVALID_HANDLE_VALUE)
3428 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3429 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3435 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3437 ovpn_pipe = CreateNamedPipe(ovpn_pipe_name,
3438 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3439 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
3440 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3446 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
3447 &inheritable, 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,
3472 sud.
options, (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);
3531 MsgToEventLog(
MSG_FLAGS_ERROR, L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated", bytes);
3538 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3539 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3540 if (exit_code == STILL_ACTIVE)
3542 TerminateProcess(proc_info.hProcess, 1);
3544 else if (exit_code != 0)
3547 swprintf(buf, _countof(buf),
3548 L
"OpenVPN exited with error: exit code = %lu", exit_code);
3554 FlushFileBuffers(pipe);
3555 DisconnectNamedPipe(pipe);
3560 DestroyEnvironmentBlock(user_env);
3581 SERVICE_STATUS *
status = ctx;
3584 case SERVICE_CONTROL_STOP:
3585 status->dwCurrentState = SERVICE_STOP_PENDING;
3593 case SERVICE_CONTROL_INTERROGATE:
3597 return ERROR_CALL_NOT_IMPLEMENTED;
3611 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)";
3613 PSECURITY_DESCRIPTOR sd = NULL;
3614 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd, NULL))
3617 return INVALID_HANDLE_VALUE;
3621 SECURITY_ATTRIBUTES sa = {0};
3622 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3623 sa.lpSecurityDescriptor = sd;
3624 sa.bInheritHandle = FALSE;
3626 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3628 static BOOL first = TRUE;
3631 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3635 WCHAR pipe_name[256];
3637 HANDLE pipe = CreateNamedPipe(pipe_name, flags,
3638 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3639 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3643 if (pipe == INVALID_HANDLE_VALUE)
3646 return INVALID_HANDLE_VALUE;
3657 static DWORD size = 10;
3658 static LPHANDLE handles = NULL;
3661 if (handles == NULL)
3663 handles = malloc(size *
sizeof(HANDLE));
3664 *handles_ptr = handles;
3665 if (handles == NULL)
3667 return ERROR_OUTOFMEMORY;
3671 handles[
pos++] = io_event;
3684 tmp = realloc(handles, size *
sizeof(HANDLE));
3689 return ERROR_OUTOFMEMORY;
3692 *handles_ptr = handles;
3694 handles[
pos++] = threads->
data;
3695 threads = threads->
next;
3719 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3731 BOOL changed = FALSE;
3741 if (
key != INVALID_HANDLE_VALUE)
3759 HANDLE pipe, io_event = NULL;
3760 OVERLAPPED overlapped;
3761 DWORD error = NO_ERROR;
3763 PHANDLE handles = NULL;
3772 status.dwCurrentState = SERVICE_START_PENDING;
3773 status.dwServiceSpecificExitCode = NO_ERROR;
3774 status.dwWin32ExitCode = NO_ERROR;
3775 status.dwWaitHint = 3000;
3783 if (error != ERROR_SUCCESS)
3789 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3804 if (error != NO_ERROR)
3810 if (pipe == INVALID_HANDLE_VALUE)
3815 status.dwCurrentState = SERVICE_RUNNING;
3821 if (ConnectNamedPipe(pipe, &overlapped) == FALSE
3822 && GetLastError() != ERROR_PIPE_CONNECTED
3823 && GetLastError() != ERROR_IO_PENDING)
3829 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3830 if (error == WAIT_OBJECT_0)
3834 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3848 TerminateThread(thread, 1);
3854 ResumeThread(thread);
3868 if (error == WAIT_FAILED)
3898 status.dwCurrentState = SERVICE_STOPPED;
3899 status.dwWin32ExitCode = error;
static int buf_len(const struct buffer *buf)
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static LSTATUS GetItfDnsServersV4(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv4 addresses of an interface.
static LSTATUS SetNameServerAddresses(PWSTR itf_id, const nrpt_address_t *addresses)
Set name servers from a NRPT address list.
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static BOOL GetInterfacesKey(short family, PHKEY key)
Return the interfaces registry key for the specified address family.
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static void UndoNrptRules(DWORD ovpn_pid)
Delete a process' NRPT rules and apply the reduced set of rules.
static BOOL ApplyGpolSettings(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings.
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static BOOL GetDnsSearchListKey(PCSTR itf_name, PBOOL gpol, PHKEY key)
Find the registry key for storing the DNS domains for the VPN interface.
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static LSTATUS GetItfDnsDomains(HKEY itf, PCWSTR search_domains, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD SetNameServers(PCWSTR itf_id, short family, PCSTR addrs)
Set the DNS name servers in a registry interface configuration.
static void SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid, PCWSTR search_domains)
Set NRPT exclude rules to accompany a catch all rule.
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL CmpWString(LPVOID item, LPVOID str)
static HANDLE CreateClientPipeInstance(VOID)
static void GetNrptExcludeData(PCWSTR search_domains, nrpt_exclude_data_t *data, size_t data_size)
Collect interface DNS settings to be used in excluding NRPT rules.
static DWORD SetNameServersValue(PCWSTR itf_id, short family, PCSTR value)
Set the DNS name servers in a registry interface configuration.
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
static DWORD DeleteWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL DeleteNrptRules(DWORD pid, PBOOL gpol)
Delete OpenVPN NRPT rules from the registry.
static VOID Undo(undo_lists_t *lists)
static BOOL ApplyDnsSettings(BOOL apply_gpol)
Signal the DNS resolver to reload its settings.
#define ERROR_STARTUP_DATA
static DWORD WINAPI RunOpenvpn(LPVOID p)
static settings_t settings
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
static SERVICE_STATUS status
static DWORD HandleDNSConfigNrptMessage(const nrpt_dns_cfg_message_t *msg, DWORD ovpn_pid, undo_lists_t *lists)
Add Name Resolution Policy Table (NRPT) rules as documented in https://msdn.microsoft....
static DWORD SetDnsSearchDomains(PCSTR itf_name, PCSTR domains, PBOOL gpol, undo_lists_t *lists)
Add or remove DNS search domains.
static void CleanupRegistry(void)
Clean up remains of previous sessions in registry.
#define ERROR_MESSAGE_TYPE
static SOCKADDR_INET sockaddr_inet(short family, inet_address_t *addr)
static LPVOID RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
static BOOL CmpHandle(LPVOID item, LPVOID hnd)
static BOOL ApplyGpolSettings64(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 64 bit ...
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
static VOID ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
static DWORD AddListItem(list_item_t **pfirst, LPVOID data)
static void BlockDNSErrHandler(DWORD err, const char *msg)
static DWORD ResetNameServers(PCWSTR itf_id, short family)
Delete all DNS name servers from a registry interface configuration.
static LSTATUS OpenNrptBaseKey(PHKEY key, PBOOL gpol)
Return the registry key where NRPT rules are stored.
static BOOL HasValidSearchList(HKEY key)
Check for a valid search list in a certain key of the registry.
static DWORD HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
static DWORD WINAPI RegisterDNS(LPVOID unused)
static HANDLE InitOverlapped(LPOVERLAPPED overlapped)
BOOL(* match_fn_t)(LPVOID item, LPVOID ctx)
static HANDLE CloseHandleEx(LPHANDLE handle)
static DWORD WINAPI ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
static BOOL StoreInitialDnsSearchList(HKEY key, PCWSTR list)
Prepare DNS domain "SearchList" registry value, so additional VPN domains can be added and its origin...
struct _list_item list_item_t
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
static BOOL IsInterfaceConnected(PWSTR iid_str)
Check if an interface is connected and up.
#define ERROR_OPENVPN_STARTUP
static DWORD SetNrptRules(HKEY nrpt_key, const nrpt_address_t *addresses, const char *domains, const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
Set NRPT rules for a openvpn process.
static LSTATUS GetItfDnsServersV6(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv6 addresses of an interface.
static DWORD SetNrptRule(HKEY nrpt_key, PCWSTR subkey, PCSTR address, PCWSTR domains, DWORD dom_size, BOOL dnssec)
Set a NRPT rule (subkey) and its values in the registry.
static BOOL AddDnsSearchDomains(HKEY key, BOOL have_list, PCWSTR domains)
Append domain suffixes to an existing search list.
static VOID FreeWaitHandles(LPHANDLE h)
openvpn_service_t interactive_service
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static BOOL ListContainsDomain(PCWSTR list, PCWSTR domain, size_t len)
Check if a domain is contained in a comma separated list of domains.
static BOOL IsDhcpEnabled(HKEY key)
Checks if DHCP is enabled for an interface.
static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
static BOOL ApplyGpolSettings32(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 32 bit ...
static DWORD HandleMTUMessage(const set_mtu_message_t *mtu)
list_item_t * undo_lists_t[_undo_type_max]
static VOID HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
static DWORD HandleRegisterDNSMessage(void)
static void RemoveDnsSearchDomains(HKEY key, PCWSTR domains)
Remove domain suffixes from an existing search list.
static BOOL InitialSearchListExists(HKEY key)
Check if a initial list had already been created.
#define ERROR_MESSAGE_DATA
static VOID FreeStartupData(STARTUP_DATA *sud)
static DWORD HandleWfpBlockMessage(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE rdns_semaphore
static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid)
static BOOL ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
static DWORD UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, HANDLE io_event, HANDLE exit_event, list_item_t *threads)
static BOOL CmpRoute(LPVOID item, LPVOID route)
static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAny(LPVOID item, LPVOID any)
static DWORD netsh_wins_cmd(const wchar_t *action, const wchar_t *if_name, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_name [static] $addr.
static DWORD HandleCreateAdapterMessage(const create_adapter_message_t *msg)
Creates a VPN adapter of the specified type by invoking tapctl.exe.
static DWORD InterfaceIdString(PCSTR itf_name, PWSTR str, size_t len)
Get the string interface UUID (with braces) for an interface alias name.
static SERVICE_STATUS_HANDLE service
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
static void UndoDnsSearchDomains(dns_domains_undo_data_t *undo_data)
Removes DNS domains from a search list they were previously added to.
char nrpt_address_t[NRPT_ADDR_SIZE]
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
#define SERVICE_DEPENDENCIES
static wchar_t * utf8to16(const char *utf8)
Convert a zero terminated UTF-8 string to UTF-16.
Wrapper structure for dynamically allocated memory.
Container for unidirectional cipher and HMAC key material.
char resolve_domains[512]
nrpt_address_t addresses[NRPT_ADDR_NUM]
CHAR addresses[NRPT_ADDR_NUM *NRPT_ADDR_SIZE]
WCHAR ovpn_admin_group[MAX_NAME]
WCHAR ovpn_service_user[MAX_NAME]
address_message_t address
flush_neighbors_message_t flush_neighbors
wfp_block_message_t wfp_block
enable_dhcp_message_t dhcp
nrpt_dns_cfg_message_t nrpt_dns
create_adapter_message_t create_adapter
BOOL IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group, const WCHAR *ovpn_service_user)
BOOL CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
static BOOL IsOption(const WCHAR *o)
int get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, int *is_auto)
Return interface metric value for the specified interface index.
DWORD set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, const ULONG metric)
Sets interface metric value for specified interface index.
DWORD delete_wfp_block_filters(HANDLE engine_handle)
DWORD add_wfp_block_filters(HANDLE *engine_handle, int index, const WCHAR *exe_path, wfp_block_msg_handler_t msg_handler, BOOL dns_only)
#define WFP_BLOCK_IFACE_METRIC
char * get_win_sys_path(void)