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 \
59 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
138 if (new_item == NULL)
140 return ERROR_OUTOFMEMORY;
143 new_item->
next = *pfirst;
158 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
161 if (!match(item->
data, ctx))
179 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
181 CloseHandle(*handle);
182 *handle = INVALID_HANDLE_VALUE;
184 return INVALID_HANDLE_VALUE;
190 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
191 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
192 return overlapped->hEvent;
198 HANDLE io_event = overlapped->hEvent;
199 if (!ResetEvent(io_event))
203 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
204 overlapped->hEvent = io_event;
223 DWORD res, bytes = 0;
224 OVERLAPPED overlapped;
225 LPHANDLE handles = NULL;
233 handles = malloc((count + 1) *
sizeof(HANDLE));
241 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
245 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
247 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
252 handles[0] = io_event;
253 for (i = 0; i < count; i++)
255 handles[i + 1] = events[i];
258 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
259 if (res != WAIT_OBJECT_0)
267 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
271 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
307 const WCHAR
msg[] = L
"Process ID";
308 WCHAR buf[22 + _countof(
msg)];
314 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
316 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
320ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
323 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
324 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
328 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
329 | FORMAT_MESSAGE_IGNORE_INSERTS,
330 0, error, 0, (LPWSTR)&args[2], 0, NULL);
333 result_len = FormatMessageW(
334 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
335 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
337 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
342 LocalFree((LPVOID)args[2]);
370 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
371 L
" that requires admin approval. This error may be avoided"
372 L
" by adding your account to the \"%ls\" group";
374 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
375 L
" only with admin approval. This error may be avoided"
376 L
" by adding your account to the \"%ls\" group";
382 swprintf(errmsg, capacity,
383 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
400 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
409 for (i = 0; i < argc; ++i)
418 if (wcscmp(L
"--config",
argv[i]) == 0 && argc - i > 1)
456 size = bytes /
sizeof(*data);
457 if ((size == 0) || (size > 4096))
464 data = malloc(bytes);
480 if (
data[size - 1] != 0)
498 len = wcslen(sud->
options) + 1;
527 SOCKADDR_INET sa_inet;
528 ZeroMemory(&sa_inet,
sizeof(sa_inet));
529 sa_inet.si_family = family;
530 if (family == AF_INET)
532 sa_inet.Ipv4.sin_addr = addr->
ipv4;
534 else if (family == AF_INET6)
536 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
544 NETIO_STATUS convert_status;
545 LPWSTR wide_name =
utf8to16(iface_name);
549 convert_status = ConvertInterfaceAliasToLuid(wide_name, luid);
554 convert_status = ERROR_OUTOFMEMORY;
556 return convert_status;
562 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
568 return DeleteUnicastIpAddressEntry(addr_row);
575 PMIB_UNICASTIPADDRESS_ROW addr_row;
578 addr_row = malloc(
sizeof(*addr_row));
579 if (addr_row == NULL)
581 return ERROR_OUTOFMEMORY;
584 InitializeUnicastIpAddressEntry(addr_row);
586 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
590 addr_row->InterfaceIndex =
msg->iface.index;
600 addr_row->InterfaceLuid = luid;
605 err = CreateUnicastIpAddressEntry(addr_row);
640 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
646 return DeleteIpForwardEntry2(fwd_row);
653 PMIB_IPFORWARD_ROW2 fwd_row;
656 fwd_row = malloc(
sizeof(*fwd_row));
659 return ERROR_OUTOFMEMORY;
662 ZeroMemory(fwd_row,
sizeof(*fwd_row));
663 fwd_row->ValidLifetime = 0xffffffff;
664 fwd_row->PreferredLifetime = 0xffffffff;
665 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
666 fwd_row->Metric =
msg->metric;
668 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
673 fwd_row->InterfaceIndex =
msg->iface.index;
675 else if (strlen(
msg->iface.name))
683 fwd_row->InterfaceLuid = luid;
688 err = CreateIpForwardEntry2(fwd_row);
724 if (
msg->family == AF_INET)
726 return FlushIpNetTable(
msg->iface.index);
729 return FlushIpNetTable2(
msg->family,
msg->iface.index);
743 err_str = L
"Unknown Win32 Error";
745 if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
746 NULL, err, 0, buf, _countof(buf), NULL))
793 HANDLE engine = NULL;
806 err = ERROR_OUTOFMEMORY;
809 block_data->
engine = engine;
810 block_data->
index =
msg->iface.index;
874ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
878 PROCESS_INFORMATION pi;
879 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
880 WCHAR *cmdline_dup = NULL;
882 ZeroMemory(&si,
sizeof(si));
883 ZeroMemory(&pi,
sizeof(pi));
888 cmdline_dup = _wcsdup(cmdline);
890 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
892 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
893 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
896 exit_code = GetLastError();
898 else if (exit_code == STILL_ACTIVE)
900 exit_code = WAIT_TIMEOUT;
903 TerminateProcess(pi.hProcess, exit_code);
904 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
916 CloseHandle(pi.hProcess);
917 CloseHandle(pi.hThread);
921 exit_code = GetLastError();
940 WCHAR ipcfg[MAX_PATH];
948 { ipcfg, L
"ipconfig /flushdns", timeout },
949 { ipcfg, L
"ipconfig /registerdns", timeout },
954 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
956 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
959 for (i = 0; i < _countof(cmds); ++i)
961 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
973 err = ERROR_SEM_TIMEOUT;
982 HANDLE thread = NULL;
985 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
998 err = GetLastError();
1017 int timeout = 30000;
1018 wchar_t argv0[MAX_PATH];
1019 wchar_t *cmdline = NULL;
1020 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1024 if (wcscmp(action, L
"delete") == 0)
1035 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1040 const wchar_t *fmt = L
"netsh interface ip %ls wins %lu %ls %ls";
1043 size_t ncmdline = wcslen(fmt) + 11 + wcslen(action) + wcslen(addr)
1044 + wcslen(addr_static) + 32 + 1;
1045 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1048 err = ERROR_OUTOFMEMORY;
1052 swprintf(cmdline, ncmdline, fmt, action, if_index, addr_static, addr);
1070 typedef NTSTATUS(__stdcall * publish_fn_t)(DWORD StateNameLo, DWORD StateNameHi, DWORD TypeId,
1071 DWORD Buffer, DWORD Length, DWORD ExplicitScope);
1072 publish_fn_t RtlPublishWnfStateData;
1073 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1074 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1077 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1083 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1084 if (RtlPublishWnfStateData == NULL)
1089 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0)
1110 typedef NTSTATUS (*publish_fn_t)(INT64 StateName, INT64 TypeId, INT64 Buffer,
1111 unsigned int Length, INT64 ExplicitScope);
1112 publish_fn_t RtlPublishWnfStateData;
1113 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1116 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1122 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1123 if (RtlPublishWnfStateData == NULL)
1128 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1149 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1164 SC_HANDLE scm = NULL;
1165 SC_HANDLE dnssvc = NULL;
1172 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1175 MsgToEventLog(
M_ERR, L
"%S: OpenSCManager call failed (%lu)", __func__, GetLastError());
1179 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1182 MsgToEventLog(
M_ERR, L
"%S: OpenService call failed (%lu)", __func__, GetLastError());
1186 SERVICE_STATUS control_status;
1187 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &control_status) == 0)
1189 MsgToEventLog(
M_ERR, L
"%S: ControlService call failed (%lu)", __func__, GetLastError());
1198 CloseServiceHandle(dnssvc);
1202 CloseServiceHandle(scm);
1222 PWSTR iid_str = NULL;
1227 PWSTR wide_name =
utf8to16(itf_name);
1232 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1235 PWSTR wide_name =
utf8to16(itf_name);
1241 if (StringFromIID(&guid, &iid_str) != S_OK)
1243 PWSTR wide_name =
utf8to16(itf_name);
1246 err = ERROR_OUTOFMEMORY;
1249 if (wcslen(iid_str) + 1 > len)
1251 err = ERROR_INVALID_PARAMETER;
1255 wcsncpy(str, iid_str, len);
1260 CoTaskMemFree(iid_str);
1282 DWORD size =
sizeof(
data);
1283 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1284 if (!err || err == ERROR_MORE_DATA)
1287 for (
size_t i = 0; i < strlen(
data); ++i)
1289 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1323 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1324 0, KEY_ALL_ACCESS,
key);
1337 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1338 0, KEY_ALL_ACCESS,
key);
1357 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1358 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1359 0, KEY_ALL_ACCESS, &itfs);
1362 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1372 *
key = INVALID_HANDLE_VALUE;
1388 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1391 if (err == ERROR_FILE_NOT_FOUND)
1408 size_t length = (wcslen(
string) + 1) *
sizeof(
wchar_t);
1409 if (length > UINT_MAX)
1413 return (DWORD)length;
1429 if (!list || wcslen(list) == 0)
1442 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1445 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1469 size_t list_len = wcslen(list);
1470 size_t add_len = wcslen(add);
1476 size_t sep_len = (list_len > 0) ? 1 : 0;
1477 if (list_len + sep_len + add_len + 1 > list_cap)
1484 list[list_len++] = L
',';
1486 wmemcpy(list + list_len, add, add_len + 1);
1517 PCWSTR domain = remove;
1520 PCWSTR comma = wcschr(domain, L
',');
1521 size_t domain_len = comma ? (size_t)(comma - domain) : wcslen(domain);
1526 PWSTR match_end = NULL;
1527 for (PWSTR p = list; *p;)
1529 PWSTR tok_end = wcschr(p, L
',');
1530 size_t tok_len = tok_end ? (size_t)(tok_end - p) : wcslen(p);
1531 if (tok_len == domain_len && wcsncmp(p, domain, domain_len) == 0)
1534 match_end = tok_end;
1546 PWSTR cut_start, cut_end;
1550 cut_end = match_end ? match_end + 1 : match + domain_len;
1554 cut_start = match - 1;
1555 cut_end = match + domain_len;
1557 wmemmove(cut_start, cut_end, wcslen(cut_end) + 1);
1589 WCHAR list[2048] = { 0 };
1593 DWORD size =
sizeof(list);
1595 RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1616 LSTATUS err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1643 DWORD size =
sizeof(list);
1645 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1648 if (err != ERROR_FILE_NOT_FOUND)
1657 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1664 RegDeleteValueA(
key,
"InitialSearchList");
1689 DWORD size =
sizeof(list);
1690 LSTATUS err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1703 if (list[0] != L
'\0')
1708 WCHAR initial[2048];
1709 size =
sizeof(initial);
1710 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1711 if (!err && wcscmp(list, initial) == 0)
1716 if (err && err != ERROR_FILE_NOT_FOUND)
1725 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1741 HKEY dns_searchlist_key;
1743 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1746 RegCloseKey(dns_searchlist_key);
1778 DWORD err = ERROR_OUTOFMEMORY;
1782 if (list_key == INVALID_HANDLE_VALUE)
1785 return ERROR_FILE_NOT_FOUND;
1799 if (domains && *domains)
1801 wchar_t *wide_domains =
utf8to16(domains);
1807 undo_data = malloc(
sizeof(*undo_data));
1811 wide_domains = NULL;
1815 undo_data->
domains = wide_domains;
1831 RegCloseKey(list_key);
1845 PCSTR itfs_key = family == AF_INET6
1846 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1847 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1849 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1852 *
key = INVALID_HANDLE_VALUE;
1854 __func__, family, err);
1857 return err ? FALSE : TRUE;
1877 return ERROR_FILE_NOT_FOUND;
1880 HKEY itf = INVALID_HANDLE_VALUE;
1881 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1885 __func__, itf_id, family, err);
1889 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, (DWORD)strlen(value) + 1);
1893 __func__, value, itf_id, family, err);
1897 if (itf != INVALID_HANDLE_VALUE)
1901 if (itfs != INVALID_HANDLE_VALUE)
1942 unsigned int addr_len =
msg->addr_len;
1945 const unsigned int max_addrs = _countof(
msg->addr);
1946 if (addr_len > max_addrs)
1948 addr_len = max_addrs;
1951 if (!
msg->iface.name[0])
1960 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1961 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1987 if (
msg->domains[0])
2001 CHAR addrs[_countof(
msg->addr) * 64];
2003 for (
unsigned int i = 0; i < addr_len; ++i)
2007 addrs[offset++] =
',';
2009 if (
msg->family == AF_INET6)
2011 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
2015 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
2017 offset = strlen(addrs);
2026 wchar_t *tmp_iid = _wcsdup(iid);
2027 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
2031 return ERROR_OUTOFMEMORY;
2036 if (
msg->domains[0])
2057 DWORD size =
sizeof(
dhcp);
2060 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
2061 if (err != NO_ERROR)
2067 return dhcp ? TRUE : FALSE;
2081 const short families[] = { AF_INET, AF_INET6 };
2082 for (
size_t i = 0; i < _countof(families); i++)
2084 short family = families[i];
2091 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
2092 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
2099 addr_list[offset++] =
',';
2101 strcpy(addr_list + offset, addresses[j]);
2102 offset += strlen(addresses[j]);
2134 addrs[*size - 1] =
'\0';
2138 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2139 if (err && err != ERROR_FILE_NOT_FOUND)
2149 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2157 if (strchr(addrs,
'.'))
2164 return ERROR_FILE_NOT_FOUND;
2179 addrs[*size - 1] =
'\0';
2183 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2184 if (err && err != ERROR_FILE_NOT_FOUND)
2193 IN6_ADDR in_addrs[8];
2194 DWORD in_addrs_size =
sizeof(in_addrs);
2195 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2196 (PBYTE)in_addrs, &in_addrs_size);
2205 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2206 for (
size_t i = 0; i < in_addrs_read; ++i)
2215 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2218 return ERROR_MORE_DATA;
2221 size_t addr_len = strlen(
pos);
2223 s -= (DWORD)addr_len;
2225 s = (DWORD)strlen(addrs) + 1;
2228 if (strchr(addrs,
':'))
2235 return ERROR_FILE_NOT_FOUND;
2250 PCWSTR entry = list;
2251 while (entry && *entry)
2253 PCWSTR comma = wcschr(entry, L
',');
2254 size_t entry_len = comma ? (size_t)(comma - entry) : wcslen(entry);
2255 if (entry_len == len && wcsncmp(entry, domain, len) == 0)
2293 const size_t glyph_size =
sizeof(*domains);
2294 const size_t max_len = (size_t)capacity / glyph_size;
2297 const size_t dot_len = 1;
2298 const size_t term_len = 2;
2300 LSTATUS ret = NO_ERROR;
2302 WCHAR *tmp = malloc(capacity);
2305 ret = ERROR_OUTOFMEMORY;
2309 PWCHAR tmp_pos = tmp;
2310 PCWCHAR domain = domains;
2312 while (domain && *domain)
2314 PWCHAR comma = wcschr(domain, L
',');
2315 size_t domain_len = comma ? (size_t)(comma - domain) : wcslen(domain);
2320 domain = comma ? comma + 1 : domain + domain_len;
2325 if (tmp_len + dot_len + domain_len + term_len > max_len)
2333 ret = ERROR_MORE_DATA;
2339 wcsncpy(tmp_pos, domain, domain_len);
2340 tmp_pos += domain_len;
2342 tmp_len += dot_len + domain_len + 1;
2344 domain = comma ? comma + 1 : domain + domain_len;
2349 ret = ERROR_FILE_NOT_FOUND;
2360 wmemcpy(domains, tmp, tmp_len);
2363 *size = (DWORD)(tmp_len * glyph_size);
2391 if (domains == NULL || size == NULL || *size == 0)
2393 return ERROR_INVALID_PARAMETER;
2396 LSTATUS err = ERROR_FILE_NOT_FOUND;
2397 const DWORD buf_size = *size;
2398 const DWORD glyph_size =
sizeof(*domains);
2399 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2401 for (
int i = 0; values[i]; i++)
2404 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2405 if (!err && *size > glyph_size && domains[(*size / glyph_size) - 1] ==
'\0' && wcschr(domains,
'.'))
2428 MIB_IF_ROW2 itf_row;
2431 if (IIDFromString(iid_str, &iid) != S_OK)
2439 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2445 if (GetIfEntry2(&itf_row) != NO_ERROR)
2451 if (itf_row.MediaConnectState == MediaConnectStateConnected
2452 && itf_row.OperStatus == IfOperStatusUp)
2473 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2474 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2482 DWORD enum_index = 0;
2483 while (i < data_size)
2485 WCHAR itf_guid[MAX_PATH];
2486 DWORD itf_guid_len = _countof(itf_guid);
2488 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2491 if (err != ERROR_NO_MORE_ITEMS)
2505 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2513 data[i].domains_size =
sizeof(
data[0].domains);
2514 memset(
data[i].domains, 0,
data[i].domains_size);
2518 if (err != ERROR_FILE_NOT_FOUND)
2527 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2529 if (err && err != ERROR_FILE_NOT_FOUND)
2532 __func__, itf_guid, err);
2537 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2538 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2542 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2545 __func__, itf_guid);
2549 RegCloseKey(v6_itf);
2550 if (err && err != ERROR_FILE_NOT_FOUND)
2553 __func__, itf_guid, err);
2558 if (v4_addrs_size || v6_addrs_size)
2561 for (
size_t j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2563 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2565 data[i].addresses[j] =
';';
2572 RegCloseKey(v4_itf);
2576 RegCloseKey(v6_itfs);
2577 RegCloseKey(v4_itfs);
2597 DWORD err = NO_ERROR;
2599 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2606 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2613 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2625 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2633 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2641 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2650 reg_val = dnssec ? 0x0000000A : 0x00000008;
2651 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2660 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2669 RegDeleteKeyW(nrpt_key, subkey);
2671 RegCloseKey(rule_key);
2692 for (
size_t i = 0; i < _countof(
data); ++i)
2702 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2725 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2727 DWORD err = NO_ERROR;
2728 PWSTR wide_domains = L
".\0";
2734 size_t domains_len = strlen(domains);
2735 dom_size = (DWORD)domains_len + 2;
2740 return ERROR_OUTOFMEMORY;
2742 domains_len = wcslen(wide_domains);
2743 dom_size = (DWORD)(domains_len + 2) *
sizeof(*wide_domains);
2746 for (
size_t i = 0; i < domains_len; ++i)
2748 if (wide_domains[i] ==
',')
2750 wide_domains[i] = 0;
2756 PWSTR wide_search_domains;
2757 wide_search_domains =
utf8to16(search_domains);
2758 if (!wide_search_domains)
2760 return ERROR_OUTOFMEMORY;
2763 free(wide_search_domains);
2766 if (addresses[0][0])
2770 PSTR
pos = addr_list;
2777 strcpy(
pos, addresses[i]);
2781 WCHAR subkey[MAX_PATH];
2782 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2783 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2814 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2815 static PCSTR sys_key =
2816 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2820 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2821 if (err == ERROR_FILE_NOT_FOUND)
2824 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2828 nrpt = INVALID_HANDLE_VALUE;
2862 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2863 pidlen = wcslen(pid_str);
2867 DWORD enum_index = 0;
2870 WCHAR name[MAX_PATH];
2871 DWORD namelen = _countof(name);
2872 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2875 if (err != ERROR_NO_MORE_ITEMS)
2883 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2884 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2889 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2897 return deleted ? TRUE : FALSE;
2935 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2940 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2945 if (
msg->iface.name[0] == 0)
2954 if (
msg->addresses[0][0] == 0)
2959 const char *rdom =
msg->resolve_domains;
2960 size_t rdom_size =
sizeof(
msg->resolve_domains);
2961 size_t rdom_len = strlen(rdom);
2962 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 1] != 0))
2968 BOOL gpol_nrpt = FALSE;
2969 BOOL gpol_list = FALSE;
2982 if (*undo_pid != ovpn_pid)
2985 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2986 "This is likely an error. Cleaning up anyway.",
2987 __func__, *undo_pid, ovpn_pid);
3011 PDWORD pid = malloc(
sizeof(ovpn_pid));
3014 err = ERROR_OUTOFMEMORY;
3020 err = ERROR_OUTOFMEMORY;
3040 if (
msg->search_domains[0] || !
msg->resolve_domains[0])
3050 if (
msg->search_domains[0])
3064 DWORD err = NO_ERROR;
3066 unsigned int addr_len =
msg->addr_len;
3069 if (addr_len > _countof(
msg->addr))
3071 addr_len = _countof(
msg->addr);
3074 if (!
msg->iface.index)
3097 for (
unsigned int i = 0; i < addr_len; ++i)
3099 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
3110 PDWORD if_index = malloc(
sizeof(
msg->iface.index));
3113 *if_index =
msg->iface.index;
3120 err = ERROR_OUTOFMEMORY;
3134 DWORD timeout = 5000;
3135 wchar_t argv0[MAX_PATH];
3138 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
3143 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%lu\" source=dhcp";
3148 size_t ncmdline = wcslen(fmt) + 10 + 1;
3149 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
3152 err = ERROR_OUTOFMEMORY;
3156 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3172 MIB_IPINTERFACE_ROW ipiface;
3173 InitializeIpInterfaceEntry(&ipiface);
3174 ipiface.Family = mtu->
family;
3176 err = GetIpInterfaceEntry(&ipiface);
3177 if (err != NO_ERROR)
3181 if (mtu->
family == AF_INET)
3183 ipiface.SitePrefixLength = 0;
3185 ipiface.NlMtu = mtu->
mtu;
3187 err = SetIpInterfaceEntry(&ipiface);
3203 switch (
msg->adapter_type)
3210 hwid = L
"root\\tap0901";
3214 return ERROR_INVALID_PARAMETER;
3217 WCHAR cmd[MAX_PATH];
3218 WCHAR args[MAX_PATH];
3220 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3222 return ERROR_BUFFER_OVERFLOW;
3225 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3227 return ERROR_BUFFER_OVERFLOW;
3234HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3251 switch (
msg.header.type)
3255 if (
msg.header.size ==
sizeof(
msg.address))
3263 if (
msg.header.size ==
sizeof(
msg.route))
3270 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3278 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3296 DWORD ovpn_pid = proc_info->dwProcessId;
3307 if (
msg.header.size ==
sizeof(
msg.dhcp))
3314 if (
msg.header.size ==
sizeof(
msg.mtu))
3321 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3400 *pnext = item->
next;
3411 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3412 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3413 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3414 HANDLE stdin_read = NULL, stdin_write = NULL;
3415 HANDLE stdout_write = NULL;
3416 DWORD pipe_mode, len, exit_code = 0;
3418 STARTUPINFOW startup_info;
3419 PROCESS_INFORMATION proc_info;
3420 LPVOID user_env = NULL;
3421 WCHAR ovpn_pipe_name[256];
3424 WCHAR *cmdline = NULL;
3425 size_t cmdline_size;
3427 WCHAR errmsg[512] = L
"";
3428 BOOL flush_pipe = TRUE;
3430 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3431 .lpSecurityDescriptor = NULL,
3432 .bInheritHandle = TRUE };
3435 EXPLICIT_ACCESS ea[2];
3436 SECURITY_DESCRIPTOR ovpn_sd;
3437 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3438 .lpSecurityDescriptor = &ovpn_sd,
3439 .bInheritHandle = FALSE };
3441 ZeroMemory(&ea,
sizeof(ea));
3442 ZeroMemory(&startup_info,
sizeof(startup_info));
3443 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3444 ZeroMemory(&proc_info,
sizeof(proc_info));
3452 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3459 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3465 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3467 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3473 svc_user = malloc(len);
3474 if (svc_user == NULL)
3480 if (!IsValidSid(svc_user->User.Sid))
3486 if (!ImpersonateNamedPipeClient(pipe))
3491 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3497 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3499 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3505 ovpn_user = malloc(len);
3506 if (ovpn_user == NULL)
3512 if (!IsValidSid(ovpn_user->User.Sid))
3534 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3535 ea[0].grfAccessMode = SET_ACCESS;
3536 ea[0].grfInheritance = NO_INHERITANCE;
3537 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3538 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3539 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3540 ea[1].grfAccessPermissions = READ_CONTROL | PROCESS_VM_READ | SYNCHRONIZE
3541 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3542 ea[1].grfAccessMode = SET_ACCESS;
3543 ea[1].grfInheritance = NO_INHERITANCE;
3544 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3545 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3546 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3549 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3554 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3559 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3566 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3573 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3574 OPEN_EXISTING, 0, NULL);
3575 if (stdout_write == INVALID_HANDLE_VALUE)
3581 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3582 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3589 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3590 if (rpc_stat != RPC_S_OK)
3596 RPC_WSTR pipe_uuid_str = NULL;
3597 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3598 if (rpc_stat != RPC_S_OK)
3603 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3605 GetCurrentThreadId(), pipe_uuid_str);
3606 RpcStringFreeW(&pipe_uuid_str);
3612 SECURITY_ATTRIBUTES sa;
3613 PSECURITY_DESCRIPTOR pSD = NULL;
3614 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3615 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3616 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3621 sa.nLength =
sizeof(sa);
3622 sa.lpSecurityDescriptor = pSD;
3623 sa.bInheritHandle = FALSE;
3625 ovpn_pipe = CreateNamedPipe(
3626 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3627 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3628 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3634 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3635 OPEN_EXISTING, 0, NULL);
3636 if (svc_pipe == INVALID_HANDLE_VALUE)
3642 pipe_mode = PIPE_READMODE_MESSAGE;
3643 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3649 cmdline_size = wcslen(sud.
options) + 128;
3650 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3651 if (cmdline == NULL)
3659 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3660 (uintptr_t)svc_pipe);
3662 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3668 startup_info.cb =
sizeof(startup_info);
3669 startup_info.dwFlags = STARTF_USESTDHANDLES;
3670 startup_info.hStdInput = stdin_read;
3671 startup_info.hStdOutput = stdout_write;
3672 startup_info.hStdError = stdout_write;
3677 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3679 user_env, sud.
directory, &startup_info, &proc_info))
3685 if (!RevertToSelf())
3687 TerminateProcess(proc_info.hProcess, 1);
3698 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3700 if (input_size && (input = malloc(input_size)))
3703 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3704 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3721 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3729 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3730 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3731 if (exit_code == STILL_ACTIVE)
3733 TerminateProcess(proc_info.hProcess, 1);
3735 else if (exit_code != 0)
3738 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3746 FlushFileBuffers(pipe);
3748 DisconnectNamedPipe(pipe);
3753 DestroyEnvironmentBlock(user_env);
3774 SERVICE_STATUS *svc_status = ctx;
3777 case SERVICE_CONTROL_STOP:
3778 svc_status->dwCurrentState = SERVICE_STOP_PENDING;
3786 case SERVICE_CONTROL_INTERROGATE:
3790 return ERROR_CALL_NOT_IMPLEMENTED;
3804 const WCHAR *sddlString =
3805 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)";
3807 PSECURITY_DESCRIPTOR sd = NULL;
3808 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3812 return INVALID_HANDLE_VALUE;
3816 SECURITY_ATTRIBUTES sa = { 0 };
3817 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3818 sa.lpSecurityDescriptor = sd;
3819 sa.bInheritHandle = FALSE;
3821 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3823 static BOOL first = TRUE;
3826 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3830 WCHAR pipe_name[256];
3832 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(
PACKAGE) L
"%ls\\service",
3834 HANDLE pipe = CreateNamedPipe(
3835 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3836 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3840 if (pipe == INVALID_HANDLE_VALUE)
3843 return INVALID_HANDLE_VALUE;
3854 static DWORD size = 10;
3855 static LPHANDLE handles = NULL;
3858 if (handles == NULL)
3860 handles = malloc(size *
sizeof(HANDLE));
3861 *handles_ptr = handles;
3862 if (handles == NULL)
3864 return ERROR_OUTOFMEMORY;
3868 handles[
pos++] = io_event;
3881 tmp = realloc(handles, size *
sizeof(HANDLE));
3886 return ERROR_OUTOFMEMORY;
3889 *handles_ptr = handles;
3891 handles[
pos++] = threads->
data;
3892 threads = threads->
next;
3916 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3928 BOOL changed = FALSE;
3938 if (
key != INVALID_HANDLE_VALUE)
3956 HANDLE pipe, io_event = NULL;
3957 OVERLAPPED overlapped;
3958 DWORD error = NO_ERROR;
3960 PHANDLE handles = NULL;
3970 status.dwCurrentState = SERVICE_START_PENDING;
3971 status.dwServiceSpecificExitCode = NO_ERROR;
3972 status.dwWin32ExitCode = NO_ERROR;
3973 status.dwWaitHint = 3000;
3981 if (error != ERROR_SUCCESS)
3987 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
4002 if (error != NO_ERROR)
4008 if (pipe == INVALID_HANDLE_VALUE)
4013 status.dwCurrentState = SERVICE_RUNNING;
4019 if (!ConnectNamedPipe(pipe, &overlapped))
4021 DWORD connect_error = GetLastError();
4022 if (connect_error == ERROR_NO_DATA)
4029 DisconnectNamedPipe(pipe);
4033 else if (connect_error == ERROR_PIPE_CONNECTED)
4036 SetEvent(overlapped.hEvent);
4038 else if (connect_error != ERROR_IO_PENDING)
4045 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
4046 if (error == WAIT_OBJECT_0)
4052 if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS)
4061 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
4072 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
4077 TerminateThread(thread, 1);
4083 ResumeThread(thread);
4097 if (error == WAIT_FAILED)
4127 status.dwCurrentState = SERVICE_STOPPED;
4128 status.dwWin32ExitCode = error;
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static LSTATUS GetItfDnsServersV4(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv4 addresses of an interface.
static LSTATUS SetNameServerAddresses(PWSTR itf_id, const nrpt_address_t *addresses)
Set name servers from a NRPT address list.
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static BOOL GetInterfacesKey(short family, PHKEY key)
Return the interfaces registry key for the specified address family.
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static void UndoNrptRules(DWORD ovpn_pid)
Delete a process' NRPT rules and apply the reduced set of rules.
static BOOL ApplyGpolSettings(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings.
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static BOOL GetDnsSearchListKey(PCSTR itf_name, PBOOL gpol, PHKEY key)
Find the registry key for storing the DNS domains for the VPN interface.
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static LSTATUS GetItfDnsDomains(HKEY itf, PCWSTR search_domains, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es)
static DWORD PeekNamedPipeAsyncTimed(HANDLE pipe, DWORD count, LPHANDLE events)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD SetNameServers(PCWSTR itf_id, short family, PCSTR addrs)
Set the DNS name servers in a registry interface configuration.
static void SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid, PCWSTR search_domains)
Set NRPT exclude rules to accompany a catch all rule.
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE CreateClientPipeInstance(VOID)
static DWORD DeleteWfpBlock(undo_lists_t *lists)
static void GetNrptExcludeData(PCWSTR search_domains, nrpt_exclude_data_t *data, size_t data_size)
Collect interface DNS settings to be used in excluding NRPT rules.
static DWORD 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.
static DWORD netsh_wins_cmd(const wchar_t *action, DWORD if_index, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_index [static] $addr.
#define ERROR_MESSAGE_TYPE
static SOCKADDR_INET sockaddr_inet(short family, inet_address_t *addr)
static LPVOID RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
static BOOL CmpHandle(LPVOID item, LPVOID hnd)
static BOOL ApplyGpolSettings64(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 64 bit ...
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
static VOID ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
static DWORD AddListItem(list_item_t **pfirst, LPVOID data)
static void BlockDNSErrHandler(DWORD err, const char *msg)
static DWORD ResetNameServers(PCWSTR itf_id, short family)
Delete all DNS name servers from a registry interface configuration.
static LSTATUS OpenNrptBaseKey(PHKEY key, PBOOL gpol)
Return the registry key where NRPT rules are stored.
static BOOL HasValidSearchList(HKEY key)
Check for a valid search list in a certain key of the registry.
static DWORD HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
static DWORD WINAPI RegisterDNS(LPVOID unused)
static HANDLE InitOverlapped(LPOVERLAPPED overlapped)
BOOL(* match_fn_t)(LPVOID item, LPVOID ctx)
static HANDLE CloseHandleEx(LPHANDLE handle)
static DWORD WINAPI ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
static BOOL StoreInitialDnsSearchList(HKEY key, PCWSTR list)
Prepare DNS domain "SearchList" registry value, so additional VPN domains can be added and its origin...
struct _list_item list_item_t
static DWORD RegWStringSize(PCWSTR string)
Return correct size for registry value to set for string.
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
static BOOL IsInterfaceConnected(PWSTR iid_str)
Check if an interface is connected and up.
#define ERROR_OPENVPN_STARTUP
static DWORD SetNrptRules(HKEY nrpt_key, const nrpt_address_t *addresses, const char *domains, const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
Set NRPT rules for a openvpn process.
static LSTATUS GetItfDnsServersV6(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv6 addresses of an interface.
static BOOL AppendSearchList(PWSTR list, size_t list_cap, PCWSTR add)
Append a comma-separated list of domains to another comma-separated list, in place.
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 size_t RemoveSearchListTokens(PWSTR list, PCWSTR remove)
Remove tokens from a comma-separated search list with multiset semantics: for each comma-separated to...
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 LSTATUS ConvertItfDnsDomains(PCWSTR search_domains, PWSTR domains, PDWORD size, const DWORD capacity)
Convert interface specific domain suffix(es) from comma-separated string to MULTI_SZ string.
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.
#define TUN_ADAPTER_INDEX_INVALID
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]
static int cleanup(void **state)
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)