37#include <versionhelpers.h>
43#define IO_TIMEOUT 2000
45#define ERROR_OPENVPN_STARTUP 0x20000000
46#define ERROR_STARTUP_DATA 0x20000001
47#define ERROR_MESSAGE_DATA 0x20000002
48#define ERROR_MESSAGE_TYPE 0x20000003
51static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
55#define RDNS_TIMEOUT 600
57#define TUN_IOCTL_REGISTER_RINGS \
58 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
137 if (new_item == NULL)
139 return ERROR_OUTOFMEMORY;
142 new_item->
next = *pfirst;
157 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
160 if (!match(item->
data, ctx))
178 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
180 CloseHandle(*handle);
181 *handle = INVALID_HANDLE_VALUE;
183 return INVALID_HANDLE_VALUE;
189 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
190 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
191 return overlapped->hEvent;
197 HANDLE io_event = overlapped->hEvent;
198 if (!ResetEvent(io_event))
202 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
203 overlapped->hEvent = io_event;
222 DWORD res, bytes = 0;
223 OVERLAPPED overlapped;
224 LPHANDLE handles = NULL;
232 handles = malloc((count + 1) *
sizeof(HANDLE));
240 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
244 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
246 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
251 handles[0] = io_event;
252 for (i = 0; i < count; i++)
254 handles[i + 1] = events[i];
257 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
258 if (res != WAIT_OBJECT_0)
266 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
270 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
306 const WCHAR
msg[] = L
"Process ID";
307 WCHAR buf[22 + _countof(
msg)];
313 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
315 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
319ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
322 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
323 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
327 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
328 | FORMAT_MESSAGE_IGNORE_INSERTS,
329 0, error, 0, (LPWSTR)&args[2], 0, NULL);
332 result_len = FormatMessageW(
333 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
334 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
336 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
341 LocalFree((LPVOID)args[2]);
369 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
370 L
" that requires admin approval. This error may be avoided"
371 L
" by adding your account to the \"%ls\" group";
373 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
374 L
" only with admin approval. This error may be avoided"
375 L
" by adding your account to the \"%ls\" group";
381 swprintf(errmsg, capacity,
382 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
399 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
408 for (i = 0; i < argc; ++i)
417 if (wcscmp(L
"--config",
argv[i]) == 0 && argc - i > 1)
455 size = bytes /
sizeof(*data);
456 if ((size == 0) || (size > 4096))
463 data = malloc(bytes);
479 if (
data[size - 1] != 0)
497 len = wcslen(sud->
options) + 1;
526 SOCKADDR_INET sa_inet;
527 ZeroMemory(&sa_inet,
sizeof(sa_inet));
528 sa_inet.si_family = family;
529 if (family == AF_INET)
531 sa_inet.Ipv4.sin_addr = addr->
ipv4;
533 else if (family == AF_INET6)
535 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
544 LPWSTR wide_name =
utf8to16(iface_name);
548 status = ConvertInterfaceAliasToLuid(wide_name, luid);
553 status = ERROR_OUTOFMEMORY;
561 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
567 return DeleteUnicastIpAddressEntry(addr_row);
574 PMIB_UNICASTIPADDRESS_ROW addr_row;
577 addr_row = malloc(
sizeof(*addr_row));
578 if (addr_row == NULL)
580 return ERROR_OUTOFMEMORY;
583 InitializeUnicastIpAddressEntry(addr_row);
585 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
587 if (
msg->iface.index != -1)
589 addr_row->InterfaceIndex =
msg->iface.index;
599 addr_row->InterfaceLuid = luid;
604 err = CreateUnicastIpAddressEntry(addr_row);
639 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
645 return DeleteIpForwardEntry2(fwd_row);
652 PMIB_IPFORWARD_ROW2 fwd_row;
655 fwd_row = malloc(
sizeof(*fwd_row));
658 return ERROR_OUTOFMEMORY;
661 ZeroMemory(fwd_row,
sizeof(*fwd_row));
662 fwd_row->ValidLifetime = 0xffffffff;
663 fwd_row->PreferredLifetime = 0xffffffff;
664 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
665 fwd_row->Metric =
msg->metric;
667 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
670 if (
msg->iface.index != -1)
672 fwd_row->InterfaceIndex =
msg->iface.index;
674 else if (strlen(
msg->iface.name))
682 fwd_row->InterfaceLuid = luid;
687 err = CreateIpForwardEntry2(fwd_row);
723 if (
msg->family == AF_INET)
725 return FlushIpNetTable(
msg->iface.index);
728 return FlushIpNetTable2(
msg->family,
msg->iface.index);
742 err_str = L
"Unknown Win32 Error";
744 if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
745 NULL, err, 0, buf, _countof(buf), NULL))
792 HANDLE engine = NULL;
805 err = ERROR_OUTOFMEMORY;
808 block_data->
engine = engine;
809 block_data->
index =
msg->iface.index;
873ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
877 PROCESS_INFORMATION pi;
878 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
879 WCHAR *cmdline_dup = NULL;
881 ZeroMemory(&si,
sizeof(si));
882 ZeroMemory(&pi,
sizeof(pi));
887 cmdline_dup = _wcsdup(cmdline);
889 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
891 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
892 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
895 exit_code = GetLastError();
897 else if (exit_code == STILL_ACTIVE)
899 exit_code = WAIT_TIMEOUT;
902 TerminateProcess(pi.hProcess, exit_code);
903 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
915 CloseHandle(pi.hProcess);
916 CloseHandle(pi.hThread);
920 exit_code = GetLastError();
939 WCHAR ipcfg[MAX_PATH];
947 { ipcfg, L
"ipconfig /flushdns", timeout },
948 { ipcfg, L
"ipconfig /registerdns", timeout },
953 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
955 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
958 for (i = 0; i < _countof(cmds); ++i)
960 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
972 err = ERROR_SEM_TIMEOUT;
981 HANDLE thread = NULL;
984 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
997 err = GetLastError();
1016 int timeout = 30000;
1017 wchar_t argv0[MAX_PATH];
1018 wchar_t *cmdline = NULL;
1019 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1023 if (wcscmp(action, L
"delete") == 0)
1034 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1039 const wchar_t *fmt = L
"netsh interface ip %ls wins %d %ls %ls";
1042 size_t ncmdline = wcslen(fmt) + 11 + wcslen(action) + wcslen(addr)
1043 + wcslen(addr_static) + 32 + 1;
1044 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1047 err = ERROR_OUTOFMEMORY;
1051 swprintf(cmdline, ncmdline, fmt, action, if_index, addr_static, addr);
1069 typedef NTSTATUS(__stdcall * publish_fn_t)(DWORD StateNameLo, DWORD StateNameHi, DWORD TypeId,
1070 DWORD Buffer, DWORD Length, DWORD ExplicitScope);
1071 publish_fn_t RtlPublishWnfStateData;
1072 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1073 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1075 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1081 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1082 if (RtlPublishWnfStateData == NULL)
1087 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0)
1105 typedef NTSTATUS (*publish_fn_t)(INT64 StateName, INT64 TypeId, INT64 Buffer,
1106 unsigned int Length, INT64 ExplicitScope);
1107 publish_fn_t RtlPublishWnfStateData;
1108 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1110 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1116 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1117 if (RtlPublishWnfStateData == NULL)
1122 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1140 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1155 SC_HANDLE scm = NULL;
1156 SC_HANDLE dnssvc = NULL;
1163 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1166 MsgToEventLog(
M_ERR, L
"%S: OpenSCManager call failed (%lu)", __func__, GetLastError());
1170 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1173 MsgToEventLog(
M_ERR, L
"%S: OpenService call failed (%lu)", __func__, GetLastError());
1178 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1180 MsgToEventLog(
M_ERR, L
"%S: ControlService call failed (%lu)", __func__, GetLastError());
1189 CloseServiceHandle(dnssvc);
1193 CloseServiceHandle(scm);
1213 PWSTR iid_str = NULL;
1221 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1228 if (StringFromIID(&guid, &iid_str) != S_OK)
1231 err = ERROR_OUTOFMEMORY;
1234 if (wcslen(iid_str) + 1 > len)
1236 err = ERROR_INVALID_PARAMETER;
1240 wcsncpy(str, iid_str, len);
1245 CoTaskMemFree(iid_str);
1267 DWORD size =
sizeof(
data);
1268 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1269 if (!err || err == ERROR_MORE_DATA)
1272 for (
int i = 0; i < strlen(
data); ++i)
1274 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1308 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1309 0, KEY_ALL_ACCESS,
key);
1322 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1323 0, KEY_ALL_ACCESS,
key);
1342 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1343 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1344 0, KEY_ALL_ACCESS, &itfs);
1347 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1357 *
key = INVALID_HANDLE_VALUE;
1373 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1376 if (err == ERROR_FILE_NOT_FOUND)
1393 size_t length = (wcslen(
string) + 1) *
sizeof(
wchar_t);
1394 if (length > UINT_MAX)
1398 return (DWORD)length;
1414 if (!list || wcslen(list) == 0)
1427 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1430 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1450 WCHAR list[2048] = { 0 };
1451 DWORD size =
sizeof(list);
1455 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1468 size_t listlen = (size /
sizeof(list[0])) - 1;
1469 size_t domlen = wcslen(domains);
1470 if (listlen + domlen + 2 > _countof(list))
1478 PWSTR
pos = list + listlen;
1480 wcsncpy(
pos + 1, domains, domlen + 1);
1484 wcsncpy(list, domains, wcslen(domains) + 1);
1488 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1515 DWORD size =
sizeof(list);
1517 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1520 if (err != ERROR_FILE_NOT_FOUND)
1529 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1536 RegDeleteValueA(
key,
"InitialSearchList");
1554 DWORD size =
sizeof(list);
1556 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1563 PWSTR dst = wcsstr(list, domains);
1571 size_t domlen = wcslen(domains);
1572 PCWSTR src = dst + domlen;
1574 dst = dst > list ? dst - 1 : dst;
1575 wmemmove(dst, src, domlen);
1577 size_t list_len = wcslen(list);
1581 WCHAR initial[2048];
1582 size =
sizeof(initial);
1583 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1592 if (wcsncmp(list, initial, list_len) == 0)
1600 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1616 HKEY dns_searchlist_key;
1618 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1621 RegCloseKey(dns_searchlist_key);
1653 DWORD err = ERROR_OUTOFMEMORY;
1657 if (list_key == INVALID_HANDLE_VALUE)
1660 return ERROR_FILE_NOT_FOUND;
1674 if (domains && *domains)
1676 wchar_t *wide_domains =
utf8to16(domains);
1682 undo_data = malloc(
sizeof(*undo_data));
1686 wide_domains = NULL;
1690 undo_data->
domains = wide_domains;
1706 RegCloseKey(list_key);
1720 PCSTR itfs_key = family == AF_INET6
1721 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1722 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1724 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1727 *
key = INVALID_HANDLE_VALUE;
1729 __func__, family, err);
1732 return err ? FALSE : TRUE;
1752 return ERROR_FILE_NOT_FOUND;
1755 HKEY itf = INVALID_HANDLE_VALUE;
1756 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1760 __func__, itf_id, family, err);
1764 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, (DWORD)strlen(value) + 1);
1768 __func__, value, itf_id, family, err);
1772 if (itf != INVALID_HANDLE_VALUE)
1776 if (itfs != INVALID_HANDLE_VALUE)
1817 int addr_len =
msg->addr_len;
1820 const int max_addrs = _countof(
msg->addr);
1821 if (addr_len > max_addrs)
1823 addr_len = max_addrs;
1826 if (!
msg->iface.name[0])
1835 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1836 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1862 if (
msg->domains[0])
1871 if (
msg->addr_len > 0)
1876 CHAR addrs[_countof(
msg->addr) * 64];
1878 for (
int i = 0; i < addr_len; ++i)
1882 addrs[offset++] =
',';
1884 if (
msg->family == AF_INET6)
1886 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1890 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1892 offset = strlen(addrs);
1901 wchar_t *tmp_iid = _wcsdup(iid);
1902 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1906 return ERROR_OUTOFMEMORY;
1911 if (
msg->domains[0])
1932 DWORD size =
sizeof(
dhcp);
1935 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1936 if (err != NO_ERROR)
1942 return dhcp ? TRUE : FALSE;
1956 const short families[] = { AF_INET, AF_INET6 };
1957 for (
int i = 0; i < _countof(families); i++)
1959 short family = families[i];
1966 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1967 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1974 addr_list[offset++] =
',';
1976 strcpy(addr_list + offset, addresses[j]);
1977 offset += strlen(addresses[j]);
2009 addrs[*size - 1] =
'\0';
2013 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2014 if (err && err != ERROR_FILE_NOT_FOUND)
2024 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2032 if (strchr(addrs,
'.'))
2039 return ERROR_FILE_NOT_FOUND;
2054 addrs[*size - 1] =
'\0';
2058 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2059 if (err && err != ERROR_FILE_NOT_FOUND)
2068 IN6_ADDR in_addrs[8];
2069 DWORD in_addrs_size =
sizeof(in_addrs);
2070 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2071 (PBYTE)in_addrs, &in_addrs_size);
2080 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2081 for (
size_t i = 0; i < in_addrs_read; ++i)
2090 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2093 return ERROR_MORE_DATA;
2096 size_t addr_len = strlen(
pos);
2098 s -= (DWORD)addr_len;
2100 s = (DWORD)strlen(addrs) + 1;
2103 if (strchr(addrs,
':'))
2110 return ERROR_FILE_NOT_FOUND;
2125 PCWSTR match = list;
2128 match = wcsstr(match, domain);
2134 if ((match == list || *(match - 1) ==
',')
2135 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2169 const DWORD glyph_size =
sizeof(*domains);
2170 const DWORD
buf_len = buf_size / glyph_size;
2177 PWCHAR
pos = domains;
2181 PWCHAR comma = wcschr(
pos,
',');
2187 DWORD domain_len = (DWORD)wcslen(
pos);
2188 DWORD domain_size = domain_len * glyph_size;
2189 DWORD converted_size = (DWORD)(
pos - domains) * glyph_size;
2197 memmove(
pos, comma + 1, buf_size - converted_size);
2198 *size -= domain_size + glyph_size;
2205 *size -= domain_size;
2206 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2212 domain_size += glyph_size;
2215 const DWORD extra_size = 2 * glyph_size;
2218 if (converted_size + domain_size + extra_size > buf_size)
2222 *size = converted_size == 0 ? 0 : converted_size + glyph_size;
2223 return ERROR_MORE_DATA;
2227 memmove(
pos + 1,
pos, buf_size - converted_size - glyph_size);
2230 *size += glyph_size;
2235 *(
pos + domain_len) =
'\0';
2236 *size += glyph_size;
2269 if (domains == NULL || size == NULL || *size == 0)
2271 return ERROR_INVALID_PARAMETER;
2274 LSTATUS err = ERROR_FILE_NOT_FOUND;
2275 const DWORD buf_size = *size;
2276 const DWORD glyph_size =
sizeof(*domains);
2277 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2279 for (
int i = 0; values[i]; i++)
2282 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2283 if (!err && *size > glyph_size && domains[(*size / glyph_size) - 1] ==
'\0' && wcschr(domains,
'.'))
2306 MIB_IF_ROW2 itf_row;
2309 if (IIDFromString(iid_str, &iid) != S_OK)
2317 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2323 if (GetIfEntry2(&itf_row) != NO_ERROR)
2329 if (itf_row.MediaConnectState == MediaConnectStateConnected
2330 && itf_row.OperStatus == IfOperStatusUp)
2351 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2352 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2360 DWORD enum_index = 0;
2361 while (i < data_size)
2363 WCHAR itf_guid[MAX_PATH];
2364 DWORD itf_guid_len = _countof(itf_guid);
2366 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2369 if (err != ERROR_NO_MORE_ITEMS)
2383 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2391 data[i].domains_size =
sizeof(
data[0].domains);
2392 memset(
data[i].domains, 0,
data[i].domains_size);
2396 if (err != ERROR_FILE_NOT_FOUND)
2405 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2407 if (err && err != ERROR_FILE_NOT_FOUND)
2410 __func__, itf_guid, err);
2415 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2416 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2420 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2423 __func__, itf_guid);
2427 RegCloseKey(v6_itf);
2428 if (err && err != ERROR_FILE_NOT_FOUND)
2431 __func__, itf_guid, err);
2436 if (v4_addrs_size || v6_addrs_size)
2439 for (
int j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2441 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2443 data[i].addresses[j] =
';';
2450 RegCloseKey(v4_itf);
2454 RegCloseKey(v6_itfs);
2455 RegCloseKey(v4_itfs);
2475 DWORD err = NO_ERROR;
2477 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2484 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2491 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2503 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2511 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2519 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2528 reg_val = dnssec ? 0x0000000A : 0x00000008;
2529 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2538 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2547 RegDeleteKeyW(nrpt_key, subkey);
2549 RegCloseKey(rule_key);
2570 for (
int i = 0; i < _countof(
data); ++i)
2580 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2603 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2605 DWORD err = NO_ERROR;
2606 PWSTR wide_domains = L
".\0";
2612 size_t domains_len = strlen(domains);
2613 dom_size = (DWORD)domains_len + 2;
2616 dom_size *=
sizeof(*wide_domains);
2619 return ERROR_OUTOFMEMORY;
2622 for (
size_t i = 0; i < domains_len; ++i)
2624 if (wide_domains[i] ==
',')
2626 wide_domains[i] = 0;
2632 PWSTR wide_search_domains;
2633 wide_search_domains =
utf8to16(search_domains);
2634 if (!wide_search_domains)
2636 return ERROR_OUTOFMEMORY;
2639 free(wide_search_domains);
2644 PSTR
pos = addr_list;
2651 strcpy(
pos, addresses[i]);
2655 WCHAR subkey[MAX_PATH];
2656 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2657 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2687 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2688 static PCSTR sys_key =
2689 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2693 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2694 if (err == ERROR_FILE_NOT_FOUND)
2697 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2701 nrpt = INVALID_HANDLE_VALUE;
2735 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2736 pidlen = wcslen(pid_str);
2740 DWORD enum_index = 0;
2743 WCHAR name[MAX_PATH];
2744 DWORD namelen = _countof(name);
2745 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2748 if (err != ERROR_NO_MORE_ITEMS)
2756 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2757 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2762 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2770 return deleted ? TRUE : FALSE;
2808 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2813 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2818 if (
msg->iface.name[0] == 0)
2827 if (
msg->addresses[0][0] == 0)
2832 const char *rdom =
msg->resolve_domains;
2833 size_t rdom_size =
sizeof(
msg->resolve_domains);
2834 size_t rdom_len = strlen(rdom);
2835 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2841 BOOL gpol_nrpt = FALSE;
2842 BOOL gpol_list = FALSE;
2855 if (*undo_pid != ovpn_pid)
2858 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2859 "This is likely an error. Cleaning up anyway.",
2860 __func__, *undo_pid, ovpn_pid);
2884 PDWORD pid = malloc(
sizeof(ovpn_pid));
2887 err = ERROR_OUTOFMEMORY;
2893 err = ERROR_OUTOFMEMORY;
2913 if (
msg->search_domains[0] || !
msg->resolve_domains[0])
2923 if (
msg->search_domains[0])
2937 DWORD err = NO_ERROR;
2939 int addr_len =
msg->addr_len;
2942 if (addr_len > _countof(
msg->addr))
2944 addr_len = _countof(
msg->addr);
2947 if (!
msg->iface.index)
2970 for (
int i = 0; i < addr_len; ++i)
2972 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2983 int *if_index = malloc(
sizeof(
msg->iface.index));
2986 *if_index =
msg->iface.index;
2993 err = ERROR_OUTOFMEMORY;
3007 DWORD timeout = 5000;
3008 wchar_t argv0[MAX_PATH];
3011 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
3016 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
3021 size_t ncmdline = wcslen(fmt) + 10 + 1;
3022 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
3025 err = ERROR_OUTOFMEMORY;
3029 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3045 MIB_IPINTERFACE_ROW ipiface;
3046 InitializeIpInterfaceEntry(&ipiface);
3047 ipiface.Family = mtu->
family;
3049 err = GetIpInterfaceEntry(&ipiface);
3050 if (err != NO_ERROR)
3054 if (mtu->
family == AF_INET)
3056 ipiface.SitePrefixLength = 0;
3058 ipiface.NlMtu = mtu->
mtu;
3060 err = SetIpInterfaceEntry(&ipiface);
3076 switch (
msg->adapter_type)
3083 hwid = L
"root\\tap0901";
3087 return ERROR_INVALID_PARAMETER;
3090 WCHAR cmd[MAX_PATH];
3091 WCHAR args[MAX_PATH];
3093 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3095 return ERROR_BUFFER_OVERFLOW;
3098 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3100 return ERROR_BUFFER_OVERFLOW;
3107HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3124 switch (
msg.header.type)
3128 if (
msg.header.size ==
sizeof(
msg.address))
3136 if (
msg.header.size ==
sizeof(
msg.route))
3143 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3151 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3169 DWORD ovpn_pid = proc_info->dwProcessId;
3180 if (
msg.header.size ==
sizeof(
msg.dhcp))
3187 if (
msg.header.size ==
sizeof(
msg.mtu))
3194 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3273 *pnext = item->
next;
3284 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3285 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3286 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3287 HANDLE stdin_read = NULL, stdin_write = NULL;
3288 HANDLE stdout_write = NULL;
3289 DWORD pipe_mode, len, exit_code = 0;
3291 STARTUPINFOW startup_info;
3292 PROCESS_INFORMATION proc_info;
3293 LPVOID user_env = NULL;
3294 WCHAR ovpn_pipe_name[256];
3297 WCHAR *cmdline = NULL;
3298 size_t cmdline_size;
3300 WCHAR errmsg[512] = L
"";
3301 BOOL flush_pipe = TRUE;
3303 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3304 .lpSecurityDescriptor = NULL,
3305 .bInheritHandle = TRUE };
3308 EXPLICIT_ACCESS ea[2];
3309 SECURITY_DESCRIPTOR ovpn_sd;
3310 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3311 .lpSecurityDescriptor = &ovpn_sd,
3312 .bInheritHandle = FALSE };
3314 ZeroMemory(&ea,
sizeof(ea));
3315 ZeroMemory(&startup_info,
sizeof(startup_info));
3316 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3317 ZeroMemory(&proc_info,
sizeof(proc_info));
3325 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3332 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3338 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3340 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3346 svc_user = malloc(len);
3347 if (svc_user == NULL)
3353 if (!IsValidSid(svc_user->User.Sid))
3359 if (!ImpersonateNamedPipeClient(pipe))
3364 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3370 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3372 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3378 ovpn_user = malloc(len);
3379 if (ovpn_user == NULL)
3385 if (!IsValidSid(ovpn_user->User.Sid))
3407 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3408 ea[0].grfAccessMode = SET_ACCESS;
3409 ea[0].grfInheritance = NO_INHERITANCE;
3410 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3411 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3412 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3413 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | SYNCHRONIZE
3414 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3415 ea[1].grfAccessMode = SET_ACCESS;
3416 ea[1].grfInheritance = NO_INHERITANCE;
3417 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3418 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3419 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3422 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3427 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3432 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3439 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3446 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3447 OPEN_EXISTING, 0, NULL);
3448 if (stdout_write == INVALID_HANDLE_VALUE)
3454 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3455 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3462 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3463 if (rpc_stat != RPC_S_OK)
3469 RPC_WSTR pipe_uuid_str = NULL;
3470 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3471 if (rpc_stat != RPC_S_OK)
3476 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3478 GetCurrentThreadId(), pipe_uuid_str);
3479 RpcStringFree(&pipe_uuid_str);
3485 SECURITY_ATTRIBUTES sa;
3486 PSECURITY_DESCRIPTOR pSD = NULL;
3487 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3488 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3489 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3494 sa.nLength =
sizeof(sa);
3495 sa.lpSecurityDescriptor = pSD;
3496 sa.bInheritHandle = FALSE;
3498 ovpn_pipe = CreateNamedPipe(
3499 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3500 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3501 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3507 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3508 OPEN_EXISTING, 0, NULL);
3509 if (svc_pipe == INVALID_HANDLE_VALUE)
3515 pipe_mode = PIPE_READMODE_MESSAGE;
3516 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3522 cmdline_size = wcslen(sud.
options) + 128;
3523 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3524 if (cmdline == NULL)
3532 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3533 (uintptr_t)svc_pipe);
3535 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3541 startup_info.cb =
sizeof(startup_info);
3542 startup_info.dwFlags = STARTF_USESTDHANDLES;
3543 startup_info.hStdInput = stdin_read;
3544 startup_info.hStdOutput = stdout_write;
3545 startup_info.hStdError = stdout_write;
3550 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3552 user_env, sud.
directory, &startup_info, &proc_info))
3558 if (!RevertToSelf())
3560 TerminateProcess(proc_info.hProcess, 1);
3571 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3573 if (input_size && (input = malloc(input_size)))
3576 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3577 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3594 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3602 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3603 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3604 if (exit_code == STILL_ACTIVE)
3606 TerminateProcess(proc_info.hProcess, 1);
3608 else if (exit_code != 0)
3611 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3619 FlushFileBuffers(pipe);
3621 DisconnectNamedPipe(pipe);
3626 DestroyEnvironmentBlock(user_env);
3647 SERVICE_STATUS *
status = ctx;
3650 case SERVICE_CONTROL_STOP:
3651 status->dwCurrentState = SERVICE_STOP_PENDING;
3659 case SERVICE_CONTROL_INTERROGATE:
3663 return ERROR_CALL_NOT_IMPLEMENTED;
3677 const WCHAR *sddlString =
3678 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)";
3680 PSECURITY_DESCRIPTOR sd = NULL;
3681 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3685 return INVALID_HANDLE_VALUE;
3689 SECURITY_ATTRIBUTES sa = { 0 };
3690 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3691 sa.lpSecurityDescriptor = sd;
3692 sa.bInheritHandle = FALSE;
3694 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3696 static BOOL first = TRUE;
3699 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3703 WCHAR pipe_name[256];
3705 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(
PACKAGE) L
"%ls\\service",
3707 HANDLE pipe = CreateNamedPipe(
3708 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3709 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3713 if (pipe == INVALID_HANDLE_VALUE)
3716 return INVALID_HANDLE_VALUE;
3727 static DWORD size = 10;
3728 static LPHANDLE handles = NULL;
3731 if (handles == NULL)
3733 handles = malloc(size *
sizeof(HANDLE));
3734 *handles_ptr = handles;
3735 if (handles == NULL)
3737 return ERROR_OUTOFMEMORY;
3741 handles[
pos++] = io_event;
3754 tmp = realloc(handles, size *
sizeof(HANDLE));
3759 return ERROR_OUTOFMEMORY;
3762 *handles_ptr = handles;
3764 handles[
pos++] = threads->
data;
3765 threads = threads->
next;
3789 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3801 BOOL changed = FALSE;
3811 if (
key != INVALID_HANDLE_VALUE)
3829 HANDLE pipe, io_event = NULL;
3830 OVERLAPPED overlapped;
3831 DWORD error = NO_ERROR;
3833 PHANDLE handles = NULL;
3843 status.dwCurrentState = SERVICE_START_PENDING;
3844 status.dwServiceSpecificExitCode = NO_ERROR;
3845 status.dwWin32ExitCode = NO_ERROR;
3846 status.dwWaitHint = 3000;
3854 if (error != ERROR_SUCCESS)
3860 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3875 if (error != NO_ERROR)
3881 if (pipe == INVALID_HANDLE_VALUE)
3886 status.dwCurrentState = SERVICE_RUNNING;
3892 if (!ConnectNamedPipe(pipe, &overlapped))
3894 DWORD connect_error = GetLastError();
3895 if (connect_error == ERROR_NO_DATA)
3902 DisconnectNamedPipe(pipe);
3906 else if (connect_error == ERROR_PIPE_CONNECTED)
3909 SetEvent(overlapped.hEvent);
3911 else if (connect_error != ERROR_IO_PENDING)
3918 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3919 if (error == WAIT_OBJECT_0)
3925 if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS)
3934 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3945 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3950 TerminateThread(thread, 1);
3956 ResumeThread(thread);
3970 if (error == WAIT_FAILED)
4000 status.dwCurrentState = SERVICE_STOPPED;
4001 status.dwWin32ExitCode = error;
static int buf_len(const struct buffer *buf)
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static LSTATUS GetItfDnsServersV4(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv4 addresses of an interface.
static LSTATUS SetNameServerAddresses(PWSTR itf_id, const nrpt_address_t *addresses)
Set name servers from a NRPT address list.
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static BOOL GetInterfacesKey(short family, PHKEY key)
Return the interfaces registry key for the specified address family.
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static void UndoNrptRules(DWORD ovpn_pid)
Delete a process' NRPT rules and apply the reduced set of rules.
static BOOL ApplyGpolSettings(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings.
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static BOOL GetDnsSearchListKey(PCSTR itf_name, PBOOL gpol, PHKEY key)
Find the registry key for storing the DNS domains for the VPN interface.
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static LSTATUS GetItfDnsDomains(HKEY itf, PCWSTR search_domains, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es)
static DWORD PeekNamedPipeAsyncTimed(HANDLE pipe, DWORD count, LPHANDLE events)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD SetNameServers(PCWSTR itf_id, short family, PCSTR addrs)
Set the DNS name servers in a registry interface configuration.
static void SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid, PCWSTR search_domains)
Set NRPT exclude rules to accompany a catch all rule.
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE CreateClientPipeInstance(VOID)
static DWORD DeleteWfpBlock(undo_lists_t *lists)
static void GetNrptExcludeData(PCWSTR search_domains, nrpt_exclude_data_t *data, size_t data_size)
Collect interface DNS settings to be used in excluding NRPT rules.
static DWORD netsh_wins_cmd(const wchar_t *action, int if_index, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_index [static] $addr.
static DWORD SetNameServersValue(PCWSTR itf_id, short family, PCSTR value)
Set the DNS name servers in a registry interface configuration.
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
static BOOL DeleteNrptRules(DWORD pid, PBOOL gpol)
Delete OpenVPN NRPT rules from the registry.
static VOID Undo(undo_lists_t *lists)
static BOOL ApplyDnsSettings(BOOL apply_gpol)
Signal the DNS resolver to reload its settings.
#define ERROR_STARTUP_DATA
static DWORD WINAPI RunOpenvpn(LPVOID p)
static settings_t settings
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
static SERVICE_STATUS status
static DWORD HandleDNSConfigNrptMessage(const nrpt_dns_cfg_message_t *msg, DWORD ovpn_pid, undo_lists_t *lists)
Add Name Resolution Policy Table (NRPT) rules as documented in https://msdn.microsoft....
static DWORD SetDnsSearchDomains(PCSTR itf_name, PCSTR domains, PBOOL gpol, undo_lists_t *lists)
Add or remove DNS search domains.
static void CleanupRegistry(void)
Clean up remains of previous sessions in registry.
#define ERROR_MESSAGE_TYPE
static SOCKADDR_INET sockaddr_inet(short family, inet_address_t *addr)
static LPVOID RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
static BOOL CmpHandle(LPVOID item, LPVOID hnd)
static BOOL ApplyGpolSettings64(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 64 bit ...
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
static VOID ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
static DWORD AddListItem(list_item_t **pfirst, LPVOID data)
static void BlockDNSErrHandler(DWORD err, const char *msg)
static DWORD ResetNameServers(PCWSTR itf_id, short family)
Delete all DNS name servers from a registry interface configuration.
static LSTATUS OpenNrptBaseKey(PHKEY key, PBOOL gpol)
Return the registry key where NRPT rules are stored.
static BOOL HasValidSearchList(HKEY key)
Check for a valid search list in a certain key of the registry.
static DWORD HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
static DWORD WINAPI RegisterDNS(LPVOID unused)
static HANDLE InitOverlapped(LPOVERLAPPED overlapped)
BOOL(* match_fn_t)(LPVOID item, LPVOID ctx)
static HANDLE CloseHandleEx(LPHANDLE handle)
static DWORD WINAPI ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
static BOOL StoreInitialDnsSearchList(HKEY key, PCWSTR list)
Prepare DNS domain "SearchList" registry value, so additional VPN domains can be added and its origin...
struct _list_item list_item_t
static DWORD RegWStringSize(PCWSTR string)
Return correct size for registry value to set for string.
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
static BOOL IsInterfaceConnected(PWSTR iid_str)
Check if an interface is connected and up.
#define ERROR_OPENVPN_STARTUP
static DWORD SetNrptRules(HKEY nrpt_key, const nrpt_address_t *addresses, const char *domains, const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
Set NRPT rules for a openvpn process.
static LSTATUS GetItfDnsServersV6(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv6 addresses of an interface.
static DWORD SetNrptRule(HKEY nrpt_key, PCWSTR subkey, PCSTR address, PCWSTR domains, DWORD dom_size, BOOL dnssec)
Set a NRPT rule (subkey) and its values in the registry.
static BOOL AddDnsSearchDomains(HKEY key, BOOL have_list, PCWSTR domains)
Append domain suffixes to an existing search list.
static VOID FreeWaitHandles(LPHANDLE h)
openvpn_service_t interactive_service
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static BOOL ListContainsDomain(PCWSTR list, PCWSTR domain, size_t len)
Check if a domain is contained in a comma separated list of domains.
static BOOL IsDhcpEnabled(HKEY key)
Checks if DHCP is enabled for an interface.
static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
static BOOL ApplyGpolSettings32(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 32 bit ...
static DWORD HandleMTUMessage(const set_mtu_message_t *mtu)
list_item_t * undo_lists_t[_undo_type_max]
static VOID HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
static LSTATUS ConvertItfDnsDomains(PCWSTR search_domains, PWSTR domains, PDWORD size, const DWORD buf_size)
Convert interface specific domain suffix(es) from comma-separated string to MULTI_SZ string.
static DWORD HandleRegisterDNSMessage(void)
static void RemoveDnsSearchDomains(HKEY key, PCWSTR domains)
Remove domain suffixes from an existing search list.
static BOOL InitialSearchListExists(HKEY key)
Check if a initial list had already been created.
#define ERROR_MESSAGE_DATA
static VOID FreeStartupData(STARTUP_DATA *sud)
static DWORD HandleWfpBlockMessage(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE rdns_semaphore
static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid)
static BOOL ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
static DWORD UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, HANDLE io_event, HANDLE exit_event, list_item_t *threads)
static BOOL CmpRoute(LPVOID item, LPVOID route)
static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAny(LPVOID item, LPVOID any)
static DWORD HandleCreateAdapterMessage(const create_adapter_message_t *msg)
Creates a VPN adapter of the specified type by invoking tapctl.exe.
static DWORD InterfaceIdString(PCSTR itf_name, PWSTR str, size_t len)
Get the string interface UUID (with braces) for an interface alias name.
static SERVICE_STATUS_HANDLE service
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
static void UndoDnsSearchDomains(dns_domains_undo_data_t *undo_data)
Removes DNS domains from a search list they were previously added to.
char nrpt_address_t[NRPT_ADDR_SIZE]
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
#define SERVICE_DEPENDENCIES
static wchar_t * utf8to16(const char *utf8)
Convert a zero terminated UTF-8 string to UTF-16.
Wrapper structure for dynamically allocated memory.
Container for unidirectional cipher and HMAC key material.
char resolve_domains[512]
nrpt_address_t addresses[NRPT_ADDR_NUM]
CHAR addresses[NRPT_ADDR_NUM *NRPT_ADDR_SIZE]
WCHAR ovpn_admin_group[MAX_NAME]
WCHAR ovpn_service_user[MAX_NAME]
address_message_t address
flush_neighbors_message_t flush_neighbors
wfp_block_message_t wfp_block
enable_dhcp_message_t dhcp
nrpt_dns_cfg_message_t nrpt_dns
create_adapter_message_t create_adapter
BOOL IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group, const WCHAR *ovpn_service_user)
BOOL CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
static BOOL IsOption(const WCHAR *o)
int get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, int *is_auto)
Return interface metric value for the specified interface index.
DWORD set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, const ULONG metric)
Sets interface metric value for specified interface index.
DWORD delete_wfp_block_filters(HANDLE engine_handle)
DWORD add_wfp_block_filters(HANDLE *engine_handle, int index, const WCHAR *exe_path, wfp_block_msg_handler_t msg_handler, BOOL dns_only)
#define WFP_BLOCK_IFACE_METRIC
char * get_win_sys_path(void)