diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-12-07 13:14:25 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-12-07 13:14:25 +0100 |
commit | 820804a01d365f6d4f9305b9e072f8393f443fcb (patch) | |
tree | fa122587cf4af5ccd339fa4c127c5374ea9fe3b3 /src/openvpnserv | |
parent | 354d158b7ea85b6e60c0de67000b1673361904a0 (diff) | |
parent | d53dba59e78da865c4fe820386ff2f4f76925f3b (diff) |
Merge tag 'upstream/2.4_rc1'
Upstream version 2.4~rc1
Diffstat (limited to 'src/openvpnserv')
-rw-r--r-- | src/openvpnserv/Makefile.am | 2 | ||||
-rw-r--r-- | src/openvpnserv/Makefile.in | 8 | ||||
-rw-r--r-- | src/openvpnserv/common.c | 12 | ||||
-rw-r--r-- | src/openvpnserv/interactive.c | 180 | ||||
-rw-r--r-- | src/openvpnserv/service.h | 3 |
5 files changed, 193 insertions, 12 deletions
diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 3521a34..58ecd91 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -26,7 +26,7 @@ openvpnserv_CFLAGS = \ -municode -D_UNICODE \ -UNTDDI_VERSION -U_WIN32_WINNT \ -D_WIN32_WINNT=_WIN32_WINNT_VISTA -openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 +openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 -lntdll endif openvpnserv_SOURCES = \ diff --git a/src/openvpnserv/Makefile.in b/src/openvpnserv/Makefile.in index 74a802b..b38a76a 100644 --- a/src/openvpnserv/Makefile.in +++ b/src/openvpnserv/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -387,7 +387,7 @@ AM_CPPFLAGS = \ @WIN32_TRUE@ -UNTDDI_VERSION -U_WIN32_WINNT \ @WIN32_TRUE@ -D_WIN32_WINNT=_WIN32_WINNT_VISTA -@WIN32_TRUE@openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 +@WIN32_TRUE@openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 -lntdll openvpnserv_SOURCES = \ common.c \ automatic.c \ @@ -504,14 +504,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c index dba4724..eafee20 100644 --- a/src/openvpnserv/common.c +++ b/src/openvpnserv/common.c @@ -216,3 +216,15 @@ MsgToEventLog (DWORD flags, LPCTSTR format, ...) return error; } + +/* Convert a utf8 string to utf16. Caller should free the result */ +wchar_t * +utf8to16 (const char *utf8) +{ + int n = MultiByteToWideChar (CP_UTF8, 0, utf8, -1, NULL, 0); + wchar_t *utf16 = malloc (n * sizeof (wchar_t)); + if (!utf16) + return NULL; + MultiByteToWideChar (CP_UTF8, 0, utf8, -1, utf16, n); + return utf16; +} diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index ffaa171..ec54216 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -35,6 +35,12 @@ #include <sddl.h> #include <shellapi.h> +#ifdef HAVE_VERSIONHELPERS_H +#include <versionhelpers.h> +#else +#include "compat-versionhelpers.h" +#endif + #include "openvpn-msg.h" #include "validate.h" #include "block_dns.h" @@ -82,6 +88,8 @@ typedef enum { address, route, block_dns, + undo_dns4, + undo_dns6, _undo_type_max } undo_type_t; typedef list_item_t* undo_lists_t[_undo_type_max]; @@ -891,8 +899,7 @@ RegisterDNS (LPVOID unused) WCHAR sys_path[MAX_PATH]; DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */ - /* default paths of net and ipconfig commands */ - WCHAR net[MAX_PATH] = L"C:\\Windows\\system32\\net.exe"; + /* default path of ipconfig command */ WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe"; struct @@ -901,8 +908,6 @@ RegisterDNS (LPVOID unused) WCHAR *cmdline; DWORD timeout; } cmds [] = { - { net, L"net stop dnscache", timeout }, - { net, L"net start dnscache", timeout }, { ipcfg, L"ipconfig /flushdns", timeout }, { ipcfg, L"ipconfig /registerdns", timeout }, }; @@ -912,9 +917,6 @@ RegisterDNS (LPVOID unused) if(GetSystemDirectory(sys_path, MAX_PATH)) { - _snwprintf (net, MAX_PATH, L"%s\\%s", sys_path, L"net.exe"); - net[MAX_PATH-1] = L'\0'; - _snwprintf (ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe"); ipcfg[MAX_PATH-1] = L'\0'; } @@ -962,6 +964,156 @@ HandleRegisterDNSMessage (void) return err; } +/** + * Run the command: netsh interface $proto $action dns $if_name $addr [validate=no] + * @param action "delete" or "add" + * @param proto "ipv6" or "ip" + * @param if_name "name_of_interface" + * @param addr IPv4 (for proto = ip) or IPv6 address as a string + * + * If addr is null and action = "delete" all addresses are deleted. + */ +static DWORD +netsh_dns_cmd (const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr) +{ + DWORD err = 0; + int timeout = 30000; /* in msec */ + wchar_t argv0[MAX_PATH]; + + if (!addr) + { + if (wcscmp(action, L"delete") == 0) + addr = L"all"; + else /* nothing to do -- return success*/ + goto out; + } + + /* Path of netsh */ + int n = GetSystemDirectory (argv0, MAX_PATH); + if (n > 0 && n < MAX_PATH) /* got system directory */ + { + wcsncat(argv0, L"\\netsh.exe", MAX_PATH - n - 1); + } + else + { + wcsncpy(argv0, L"C:\\Windows\\system32\\netsh.exe", MAX_PATH); + } + + /* cmd template: + * netsh interface $proto $action dns $if_name $addr [validate=no] + */ + const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s"; + + /* max cmdline length in wchars -- include room for worst case and some */ + int ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1; + wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); + if (!cmdline) + { + err = ERROR_OUTOFMEMORY; + goto out; + } + + openvpn_sntprintf (cmdline, ncmdline, fmt, proto, action, if_name, addr); + + if (IsWindows7OrGreater()) + { + wcsncat(cmdline, L" validate=no", ncmdline - wcslen(cmdline) - 1); + } + err = ExecCommand (argv0, cmdline, timeout); + +out: + free (cmdline); + return err; +} + +/* Delete all IPv4 or IPv6 dns servers for an interface */ +static DWORD +DeleteDNS(short family, wchar_t *if_name) +{ + wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; + return netsh_dns_cmd (L"delete", proto, if_name, NULL); +} + +/* Add an IPv4 or IPv6 dns server to an interface */ +static DWORD +AddDNS(short family, wchar_t *if_name, wchar_t *addr) +{ + wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; + return netsh_dns_cmd (L"add", proto, if_name, addr); +} + +static BOOL +CmpWString (LPVOID item, LPVOID str) +{ + return (wcscmp (item, str) == 0) ? TRUE : FALSE; +} + +static DWORD +HandleDNSConfigMessage (const dns_cfg_message_t *msg, undo_lists_t *lists) +{ + DWORD err = 0; + wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */ + undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6; + int addr_len = msg->addr_len; + + /* sanity check */ + if (addr_len > _countof(msg->addr)) + addr_len = _countof(msg->addr); + + if (!msg->iface.name[0]) /* interface name is required */ + return ERROR_MESSAGE_DATA; + + wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */ + if (!wide_name) + return ERROR_OUTOFMEMORY; + + /* We delete all current addresses before adding any + * OR if the message type is del_dns_cfg + */ + if (addr_len > 0 || msg->header.type == msg_del_dns_cfg) + { + err = DeleteDNS(msg->family, wide_name); + if (err) + goto out; + free (RemoveListItem (&(*lists)[undo_type], CmpWString, wide_name)); + } + + if (msg->header.type == msg_del_dns_cfg) /* job done */ + goto out; + + for (int i = 0; i < addr_len; ++i) + { + if (msg->family == AF_INET6) + RtlIpv6AddressToStringW (&msg->addr[i].ipv6, addr); + else + RtlIpv4AddressToStringW (&msg->addr[i].ipv4, addr); + err = AddDNS(msg->family, wide_name, addr); + if (i == 0 && err) + goto out; + /* We do not check for duplicate addresses, so any error in adding + * additional addresses is ignored. + */ + } + + if (msg->addr_len > 0) + { + wchar_t *tmp_name = wcsdup(wide_name); + if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name)) + { + free(tmp_name); + DeleteDNS(msg->family, wide_name); + err = ERROR_OUTOFMEMORY; + goto out; + } + } + + err = 0; + +out: + free(wide_name); + return err; +} + static VOID HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { @@ -972,6 +1124,7 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list route_message_t route; flush_neighbors_message_t flush_neighbors; block_dns_message_t block_dns; + dns_cfg_message_t dns; } msg; ack_message_t ack = { .header = { @@ -1017,6 +1170,11 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list ack.error_number = HandleRegisterDNSMessage (); break; + case msg_add_dns_cfg: + case msg_del_dns_cfg: + ack.error_number = HandleDNSConfigMessage (&msg.dns, lists); + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog (MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1048,6 +1206,14 @@ Undo (undo_lists_t *lists) DeleteRoute (item->data); break; + case undo_dns4: + DeleteDNS(AF_INET, item->data); + break; + + case undo_dns6: + DeleteDNS(AF_INET6, item->data); + break; + case block_dns: delete_block_dns_filters (item->data); item->data = NULL; diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index 94bfb07..c5d745f 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -89,4 +89,7 @@ BOOL ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) LPCTSTR GetLastErrorText (); DWORD MsgToEventLog (DWORD flags, LPCTSTR lpszMsg, ...); +/* Convert a utf8 string to utf16. Caller should free the result */ +wchar_t *utf8to16 (const char *utf8); + #endif |