summaryrefslogtreecommitdiff
path: root/src/openvpnserv
diff options
context:
space:
mode:
authorAlberto Gonzalez Iniesta <agi@inittab.org>2016-12-07 13:14:25 +0100
committerAlberto Gonzalez Iniesta <agi@inittab.org>2016-12-07 13:14:25 +0100
commit820804a01d365f6d4f9305b9e072f8393f443fcb (patch)
treefa122587cf4af5ccd339fa4c127c5374ea9fe3b3 /src/openvpnserv
parent354d158b7ea85b6e60c0de67000b1673361904a0 (diff)
parentd53dba59e78da865c4fe820386ff2f4f76925f3b (diff)
Merge tag 'upstream/2.4_rc1'
Upstream version 2.4~rc1
Diffstat (limited to 'src/openvpnserv')
-rw-r--r--src/openvpnserv/Makefile.am2
-rw-r--r--src/openvpnserv/Makefile.in8
-rw-r--r--src/openvpnserv/common.c12
-rw-r--r--src/openvpnserv/interactive.c180
-rw-r--r--src/openvpnserv/service.h3
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