Attention is currently required from: flichtenheld, plaisthos.
Hello flichtenheld, plaisthos,
I'd like you to reexamine a change. Please visit
http://gerrit.openvpn.net/c/openvpn/+/838?usp=email
to look at the new patch set (#13).
The following approvals got outdated and were removed:
Code-Review-1 by flichtenheld
Change subject: dns: apply settings via script on unixoid systems
......................................................................
dns: apply settings via script on unixoid systems
This introduces a new script hook, the dns-script and implements such a
script for a few popular systems (and a default for the not so popular
ones). Like the name suggests this script is soleley for dealing with
modifying how names are resolved when the VPN pushes some --dns
settings.
The default dns script is part of the distribution and is installed with
openvpn. You can change the path the script is located at as a compile
time option, defaults to libexecdir. There's also a new runtime option
--dns-script, which can run a custom script.
Change-Id: Ifbe4ffb44d3bfcaa50adb38cacb3436fcdc71b10
Signed-off-by: Heiko Hund <[email protected]>
---
M .gitignore
M CMakeLists.txt
M configure.ac
M distro/Makefile.am
A distro/dns-scripts/Makefile.am
A distro/dns-scripts/haikuos_file-dns-updown.sh
A distro/dns-scripts/openresolv-dns-updown.sh
A distro/dns-scripts/resolvconf_file-dns-updown.sh
A distro/dns-scripts/systemd-dns-updown.sh
M doc/man-sections/script-options.rst
M src/openvpn/Makefile.am
M src/openvpn/dns.c
M src/openvpn/dns.h
M src/openvpn/options.c
14 files changed, 623 insertions(+), 9 deletions(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/38/838/13
diff --git a/.gitignore b/.gitignore
index db8bb73..04523af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,6 +49,7 @@
/doc/doxygen/latex/
/doc/doxygen/openvpn.doxyfile
distro/systemd/*.service
+distro/dns-scripts/dns-updown
sample/sample-keys/sample-ca/
vendor/cmocka_build
vendor/dist
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b04adce..2696691 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,7 +41,8 @@
option(USE_WERROR "Treat compiler warnings as errors (-Werror)" ON)
option(FAKE_ANDROID "Target Android but do not use actual cross
compile/Android cmake to build for simple compile checks on Linux")
-set(PLUGIN_DIR /usr/local/lib/openvpn/plugins CACHE FILEPATH "Location of the
plugin directory")
+set(DNS_UPDOWN_PATH "${CMAKE_INSTALL_PREFIX}/libexec/openvpn/dns-updown" CACHE
STRING "Default location for the DNS up/down script")
+set(PLUGIN_DIR "${CMAKE_INSTALL_PREFIX}/lib/openvpn/plugins" CACHE FILEPATH
"Location of the plugin directory")
# Create machine readable compile commands
option(ENABLE_COMPILE_COMMANDS "Generate compile_commands.json and a symlink
for clangd to find it" OFF)
@@ -577,6 +578,8 @@
add_library_deps(openvpn)
+target_compile_options(openvpn PRIVATE
-DDNS_UPDOWN_PATH=\"${DNS_UPDOWN_PATH}\")
+
if(MINGW)
target_compile_options(openvpn PRIVATE -municode -UUNICODE)
target_link_options(openvpn PRIVATE -municode)
diff --git a/configure.ac b/configure.ac
index 9777e36..45d3ac1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -315,37 +315,50 @@
plugindir="\${libdir}/openvpn/plugins"
fi
+AC_ARG_VAR([SCRIPTDIR], [Path of script directory
@<:@default=PKGLIBEXECDIR@:>@])
+if test -n "${SCRIPTDIR}"; then
+ scriptdir="${SCRIPTDIR}"
+else
+ scriptdir="\${pkglibexecdir}"
+fi
+
AC_DEFINE_UNQUOTED([TARGET_ALIAS], ["${host}"], [A string representing our
host])
-AM_CONDITIONAL([TARGET_LINUX], [false])
+AM_CONDITIONAL([ENABLE_DNS_SCRIPT],[true])
case "$host" in
*-*-linux*)
AC_DEFINE([TARGET_LINUX], [1], [Are we running on Linux?])
- AM_CONDITIONAL([TARGET_LINUX], [true])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["L"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["systemd"])
have_sitnl="yes"
pkg_config_required="yes"
;;
*-*-solaris*)
AC_DEFINE([TARGET_SOLARIS], [1], [Are we running on Solaris?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["S"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"])
CPPFLAGS="$CPPFLAGS -D_XPG4_2"
test -x /bin/bash && SHELL="/bin/bash"
;;
*-*-openbsd*)
AC_DEFINE([TARGET_OPENBSD], [1], [Are we running on OpenBSD?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["O"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"])
;;
*-*-freebsd*)
AC_DEFINE([TARGET_FREEBSD], [1], [Are we running on FreeBSD?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["F"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["openresolv"])
;;
*-*-netbsd*)
AC_DEFINE([TARGET_NETBSD], [1], [Are we running NetBSD?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["N"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["openresolv"])
;;
*-*-darwin*)
AC_DEFINE([TARGET_DARWIN], [1], [Are we running on Mac OS X?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["M"], [Target prefix])
+ AM_CONDITIONAL([ENABLE_DNS_SCRIPT],[false])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"])
have_tap_header="yes"
ac_cv_type_struct_in_pktinfo=no
;;
@@ -353,6 +366,8 @@
AC_DEFINE([TARGET_WIN32], [1], [Are we running WIN32?])
AC_DEFINE([ENABLE_DCO], [1], [DCO is always enabled on Windows])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["W"], [Target prefix])
+ AM_CONDITIONAL([ENABLE_DNS_SCRIPT],[false])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["windows"])
CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN"
CPPFLAGS="${CPPFLAGS} -DNTDDI_VERSION=NTDDI_VISTA
-D_WIN32_WINNT=_WIN32_WINNT_VISTA"
WIN32=yes
@@ -360,10 +375,12 @@
*-*-dragonfly*)
AC_DEFINE([TARGET_DRAGONFLY], [1], [Are we running on
DragonFlyBSD?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["D"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["openresolv"])
;;
*-aix*)
AC_DEFINE([TARGET_AIX], [1], [Are we running AIX?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["A"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"])
ROUTE="/usr/sbin/route"
have_tap_header="yes"
ac_cv_header_net_if_h="no" # exists, but breaks things
@@ -371,10 +388,12 @@
*-*-haiku*)
AC_DEFINE([TARGET_HAIKU], [1], [Are we running Haiku?])
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["H"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["haikuos_file"])
LIBS="${LIBS} -lnetwork"
;;
*)
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["X"], [Target prefix])
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"])
have_tap_header="yes"
;;
esac
@@ -1505,6 +1524,7 @@
sampledir="\$(docdir)/sample"
AC_SUBST([plugindir])
+AC_SUBST([scriptdir])
AC_SUBST([sampledir])
AC_SUBST([systemdunitdir])
@@ -1541,6 +1561,7 @@
Makefile
distro/Makefile
distro/systemd/Makefile
+ distro/dns-scripts/Makefile
doc/Makefile
doc/doxygen/Makefile
doc/doxygen/openvpn.doxyfile
diff --git a/distro/Makefile.am b/distro/Makefile.am
index 7a588da..b8fb85b 100644
--- a/distro/Makefile.am
+++ b/distro/Makefile.am
@@ -13,3 +13,7 @@
$(srcdir)/Makefile.in
SUBDIRS = systemd
+
+if ENABLE_DNS_SCRIPT
+SUBDIRS += dns-scripts
+endif
diff --git a/distro/dns-scripts/Makefile.am b/distro/dns-scripts/Makefile.am
new file mode 100644
index 0000000..ec7bfde
--- /dev/null
+++ b/distro/dns-scripts/Makefile.am
@@ -0,0 +1,28 @@
+#
+# OpenVPN -- An application to securely tunnel IP networks
+# over a single UDP port, with support for SSL/TLS-based
+# session authentication and key exchange,
+# packet encryption, packet authentication, and
+# packet compression.
+#
+# Copyright (C) 2002-2024 OpenVPN Inc <[email protected]>
+#
+
+MAINTAINERCLEANFILES = \
+ $(srcdir)/Makefile.in
+
+EXTRA_DIST = \
+ systemd-dns-updown.sh \
+ openresolv-dns-updown.sh \
+ haikuos_file-dns-updown.sh \
+ resolvconf_file-dns-updown.sh
+
+script_SCRIPTS = \
+ dns-updown
+
+CLEANFILES = $(script_SCRIPTS)
+
+dns-updown: @[email protected]
+ cp ${srcdir}/@[email protected] $@
+
+all: $(script_SCRIPTS)
diff --git a/distro/dns-scripts/haikuos_file-dns-updown.sh
b/distro/dns-scripts/haikuos_file-dns-updown.sh
new file mode 100644
index 0000000..1b03e9c
--- /dev/null
+++ b/distro/dns-scripts/haikuos_file-dns-updown.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Simple OpenVPN up/down script for modifying Haiku OS resolv.conf
+# (C) Copyright 2024 OpenVPN Inc <[email protected]>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Example env from openvpn (most are not applied):
+#
+# dev tun0
+# script-type dns-up
+# dns_search_domain_1 mycorp.in
+# dns_search_domain_2 eu.mycorp.com
+# dns_server_1_address_1 192.168.99.254
+# dns_server_1_address_2 fd00::99:53
+# dns_server_1_port_1 53
+# dns_server_1_port_2 53
+# dns_server_1_resolve_domain_1 mycorp.in
+# dns_server_1_resolve_domain_2 eu.mycorp.com
+# dns_server_1_dnssec true
+# dns_server_1_transport DoH
+# dns_server_1_sni dns.mycorp.in
+#
+
+set -e +u
+
+conly_standard_server_ports() {
+ i=1
+ while true; do
+ eval addr=\"\$dns_server_${n}_address_${i}\"
+ [ -n "$addr" ] || return 0
+
+ eval port=\"\$dns_server_${n}_port_${i}\"
+ [ -z "$port" -o "$port" = "53" ] || return 1
+
+ i=$(expr $i + 1)
+ done
+}
+
+onf=/boot/system/settings/network/resolv.conf
+test -e "$conf" || exit 1
+case "${script_type}" in
+dns-up)
+ n=1
+ while :; do
+ eval addr=\"\$dns_server_${n}_address_1\"
+ [ -n "$addr" ] || {
+ echo "setting DNS failed, no compatible server profile"
+ exit 1
+ }
+
+ # Skip server profiles which require DNSSEC,
+ # secure transport or use a custom port
+ eval dnssec=\"\$dns_server_${n}_dnssec\"
+ eval transport=\"\$dns_server_${n}_transport\"
+ [ -z "$transport" -o "$transport" = "plain" ] \
+ && [ -z "$dnssec" -o "$dnssec" = "no" ] \
+ && only_standard_server_ports && break
+
+ n=$(expr $n + 1)
+ done
+
+ eval addr1=\"\$dns_server_${n}_address_1\"
+ eval addr2=\"\$dns_server_${n}_address_2\"
+ eval addr3=\"\$dns_server_${n}_address_3\"
+ text="### openvpn ${dev} begin ###\n"
+ text="${text}nameserver $addr1\n"
+ test -z "$addr2" || text="${text}nameserver $addr2\n"
+ test -z "$addr3" || text="${text}nameserver $addr3\n"
+
+ test -z "$dns_search_domain_1" || {
+ for i in $(seq 1 6); do
+ eval domains=\"$domains\$dns_search_domain_${i} \" || break
+ done
+ text="${text}search $domains\n"
+ }
+ text="${text}### openvpn ${dev} end ###"
+
+ sed -i "1i${text}" "$conf"
+ ;;
+dns-down)
+ sed -i "/### openvpn ${dev} begin ###/,/### openvpn ${dev} end ###/d"
"$conf"
+ ;;
+esac
diff --git a/distro/dns-scripts/openresolv-dns-updown.sh
b/distro/dns-scripts/openresolv-dns-updown.sh
new file mode 100644
index 0000000..1b218f5
--- /dev/null
+++ b/distro/dns-scripts/openresolv-dns-updown.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# Simple OpenVPN up/down script for openresolv integration
+# (C) Copyright 2016 Baptiste Daroussin
+# 2024 OpenVPN Inc <[email protected]>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Example env from openvpn (most are not applied):
+#
+# dev tun0
+# script-type dns-up
+# dns_search_domain_1 mycorp.in
+# dns_search_domain_2 eu.mycorp.com
+# dns_server_1_address_1 192.168.99.254
+# dns_server_1_address_2 fd00::99:53
+# dns_server_1_port_1 53
+# dns_server_1_port_2 53
+# dns_server_1_resolve_domain_1 mycorp.in
+# dns_server_1_resolve_domain_2 eu.mycorp.com
+# dns_server_1_dnssec true
+# dns_server_1_transport DoH
+# dns_server_1_sni dns.mycorp.in
+#
+
+set -e +u
+
+only_standard_server_ports() {
+ i=1
+ while true; do
+ eval addr=\"\$dns_server_${n}_address_${i}\"
+ [ -n "$addr" ] || return 0
+
+ eval port=\"\$dns_server_${n}_port_${i}\"
+ [ -z "$port" -o "$port" = "53" ] || return 1
+
+ i=$(expr $i + 1)
+ done
+}
+
+: ${script_type:=dns-down}
+case "${script_type}" in
+dns-up)
+ n=1
+ while :; do
+ eval addr=\"\$dns_server_${n}_address_1\"
+ [ -n "$addr" ] || {
+ echo "setting DNS failed, no compatible server profile"
+ exit 1
+ }
+
+ # Skip server profiles which require DNSSEC,
+ # secure transport or use a custom port
+ eval dnssec=\"\$dns_server_${n}_dnssec\"
+ eval transport=\"\$dns_server_${n}_transport\"
+ [ -z "$transport" -o "$transport" = "plain" ] \
+ && [ -z "$dnssec" -o "$dnssec" = "no" ] \
+ && only_standard_server_ports && break
+
+ n=$(expr $n + 1)
+ done
+
+ {
+ i=1
+ maxns=3
+ while :; do
+ maxns=$((maxns - 1))
+ [ $maxns -gt 0 ] || break
+ eval option=\"\$dns_server_${n}_address_${i}\" || break
+ [ "${option}" ] || break
+ i=$((i + 1))
+ echo "nameserver ${option}"
+ done
+ i=1
+ maxdom=6
+ while :; do
+ maxdom=$((maxdom - 1))
+ [ $maxdom -gt 0 ] || break
+ eval option=\"\$dns_search_domain_${i}\" || break
+ [ "${option}" ] || break
+ i=$((i + 1))
+ echo "search ${option}"
+ done
+ } | /sbin/resolvconf -a "${dev}"
+ ;;
+dns-down)
+ /sbin/resolvconf -d "${dev}" -f
+ ;;
+esac
diff --git a/distro/dns-scripts/resolvconf_file-dns-updown.sh
b/distro/dns-scripts/resolvconf_file-dns-updown.sh
new file mode 100644
index 0000000..c469490
--- /dev/null
+++ b/distro/dns-scripts/resolvconf_file-dns-updown.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Simple OpenVPN up/down script for modifying /etc/resolv.conf
+# (C) Copyright 2024 OpenVPN Inc <[email protected]>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Example env from openvpn (most are not applied):
+#
+# dev tun0
+# script-type dns-up
+# dns_search_domain_1 mycorp.in
+# dns_search_domain_2 eu.mycorp.com
+# dns_server_1_address_1 192.168.99.254
+# dns_server_1_address_2 fd00::99:53
+# dns_server_1_port_1 53
+# dns_server_1_port_2 53
+# dns_server_1_resolve_domain_1 mycorp.in
+# dns_server_1_resolve_domain_2 eu.mycorp.com
+# dns_server_1_dnssec true
+# dns_server_1_transport DoH
+# dns_server_1_sni dns.mycorp.in
+#
+
+set -e +u
+
+only_standard_server_ports() {
+ i=1
+ while true; do
+ eval addr=\"\$dns_server_${n}_address_${i}\"
+ [ -n "$addr" ] || return 0
+
+ eval port=\"\$dns_server_${n}_port_${i}\"
+ [ -z "$port" -o "$port" = "53" ] || return 1
+
+ i=$(expr $i + 1)
+ done
+}
+
+conf=/etc/resolv.conf
+test -e "$conf" || exit 1
+case "${script_type}" in
+dns-up)
+ n=1
+ while :; do
+ eval addr=\"\$dns_server_${n}_address_1\"
+ [ -n "$addr" ] || {
+ echo "setting DNS failed, no compatible server profile"
+ exit 1
+ }
+
+ # Skip server profiles which require DNSSEC,
+ # secure transport or use a custom port
+ eval dnssec=\"\$dns_server_${n}_dnssec\"
+ eval transport=\"\$dns_server_${n}_transport\"
+ [ -z "$transport" -o "$transport" = "plain" ] \
+ && [ -z "$dnssec" -o "$dnssec" = "no" ] \
+ && only_standard_server_ports && break
+
+ n=$(expr $n + 1)
+ done
+
+ eval addr1=\"\$dns_server_${n}_address_1\"
+ eval addr2=\"\$dns_server_${n}_address_2\"
+ eval addr3=\"\$dns_server_${n}_address_3\"
+ text="### openvpn ${dev} begin ###\n"
+ text="${text}nameserver $addr1\n"
+ test -z "$addr2" || text="${text}nameserver $addr2\n"
+ test -z "$addr3" || text="${text}nameserver $addr3\n"
+
+ test -z "$dns_search_domain_1" || {
+ for i in $(seq 1 6); do
+ eval domains=\"$domains\$dns_search_domain_${i} \" || break
+ done
+ text="${text}search $domains\n"
+ }
+ text="${text}### openvpn ${dev} end ###"
+
+ sed -i "1i${text}" "$conf"
+ ;;
+dns-down)
+ sed -i "/### openvpn ${dev} begin ###/,/### openvpn ${dev} end ###/d"
"$conf"
+ ;;
+esac
diff --git a/distro/dns-scripts/systemd-dns-updown.sh
b/distro/dns-scripts/systemd-dns-updown.sh
new file mode 100644
index 0000000..69bbebf
--- /dev/null
+++ b/distro/dns-scripts/systemd-dns-updown.sh
@@ -0,0 +1,194 @@
+#!/bin/bash
+#
+# dns-updown - add/remove openvpn provided DNS information
+#
+# Copyright (C) 2024 OpenVPN Inc <[email protected]>
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# Add/remove openvpn DNS settings from the env into/from
+# the system. Supported backends in this order:
+#
+# * systemd-resolved
+# * resolvconf
+#
+# Example env from openvpn (not all are always applied):
+#
+# dev tun0
+# script-type dns-up
+# dns_search_domain_1 mycorp.in
+# dns_search_domain_2 eu.mycorp.com
+# dns_server_1_address_1 192.168.99.254
+# dns_server_1_address_2 fd00::99:53
+# dns_server_1_port_1 53
+# dns_server_1_port_2 53
+# dns_server_1_resolve_domain_1 mycorp.in
+# dns_server_1_resolve_domain_2 eu.mycorp.com
+# dns_server_1_dnssec true
+# dns_server_1_transport DoH
+# dns_server_1_sni dns.mycorp.in
+#
+
+function do_resolved_servers {
+ local sni=""
+ local transport_var=dns_server_${n}_transport
+ local sni_var=dns_server_${n}_sni
+ [ "${!transport_var}" = "DoT" ] && sni="#${!sni_var}"
+
+ local i=1
+ local addrs=""
+ while :; do
+ local addr_var=dns_server_${n}_address_${i}
+ local addr="${!addr_var}"
+ [ -n "$addr" ] || break
+
+ local port_var=dns_server_${n}_port_${i}
+ if [ -n "${!port_var}" ]; then
+ if [[ "$addr" =~ : ]]; then
+ addr="[$addr]"
+ fi
+ addrs+="${addr}:${!port_var}${sni} "
+ else
+ addrs+="${addr}${sni} "
+ fi
+ i=$((i+1))
+ done
+
+ resolvectl dns "$dev" $addrs
+}
+
+function do_resolved_domains {
+ local list=""
+ for domain_var in ${!dns_search_domain_*}; do
+ list+="${!domain_var} "
+ done
+ local domain_var=dns_server_${n}_resolve_domain_1
+ if [ -z "${!domain_var}" ]; then
+ resolvectl default-route "$dev" true
+ list+="~."
+ else
+ resolvectl default-route "$dev" false
+ local i=1
+ while :; do
+ domain_var=dns_server_${n}_resolve_domain_${i}
+ [ -n "${!domain_var}" ] || break
+ # Add as split domain (~ prefix), if it doesn't already exist
+ [[ "$list" =~ (^| )"${!domain_var}"( |$) ]] \
+ || list+="~${!domain_var} "
+ i=$((i+1))
+ done
+ fi
+
+ resolvectl domain "$dev" $list
+}
+
+function do_resolved_dnssec {
+ local dnssec_var=dns_server_${n}_dnssec
+ if [ "${!dnssec_var}" = "optional" ]; then
+ resolvectl dnssec "$dev" allow-downgrade
+ elif [ "${!dnssec_var}" = "yes" ]; then
+ resolvectl dnssec "$dev" true
+ else
+ resolvectl dnssec "$dev" false
+ fi
+}
+
+function do_resolved_dnsovertls {
+ local transport_var=dns_server_${n}_transport
+ if [ "${!transport_var}" = "DoT" ]; then
+ resolvectl dnsovertls "$dev" true
+ else
+ resolvectl dnsovertls "$dev" false
+ fi
+}
+
+function do_resolved {
+ [[ "$(readlink /etc/resolv.conf)" =~ systemd ]] || return 1
+
+ n=1
+ while :; do
+ local addr_var=dns_server_${n}_address_1
+ [ -n "${!addr_var}" ] || {
+ echo "setting DNS failed, no compatible server profile"
+ return 1
+ }
+
+ # Skip server profiles which require DNS-over-HTTPS
+ local transport_var=dns_server_${n}_transport
+ [ -n "${!transport_var}" -a "${!transport_var}" = "DoH" ] || break
+
+ n=$((n+1))
+ done
+
+ if [ "$script_type" = "dns-up" ]; then
+ echo "setting DNS using resolvectl"
+ do_resolved_servers
+ do_resolved_domains
+ do_resolved_dnssec
+ do_resolved_dnsovertls
+ else
+ echo "unsetting DNS using resolvectl"
+ resolvectl revert "$dev"
+ fi
+
+ return 0
+}
+
+function only_standard_server_ports {
+ local i=1
+ while :; do
+ local addr_var=dns_server_${n}_address_${i}
+ [ -n "${!addr_var}" ] || return 0
+
+ local port_var=dns_server_${n}_port_${i}
+ [ -z "${!port_var}" -o "${!port_var}" = "53" ] || return 1
+
+ i=$((i+1))
+ done
+}
+
+function do_resolvconf {
+ [ -x /sbin/resolvconf ] || return 1
+
+ n=1
+ while :; do
+ local server_addr_var=dns_server_${n}_address_1
+ [ -n "${!server_addr_var}" ] || {
+ echo "setting DNS failed, no compatible server profile"
+ return 1
+ }
+
+ # Skip server profiles which require DNSSEC,
+ # secure transport or use a custom port
+ local dnssec_var=dns_server_${n}_dnssec
+ local transport_var=dns_server_${n}_transport
+ [ -z "${!transport_var}" -o "${!transport_var}" = "plain" ] \
+ && [ -z "${!dnssec_var}" -o "${!dnssec_var}" = "no" ] \
+ && only_standard_server_ports && break
+
+ n=$((n+1))
+ done
+
+ if [ "$script_type" = "dns-up" ]; then
+ echo "setting DNS using resolvconf"
+ local domains=""
+ for domain_var in ${!dns_search_domain_*}; do
+ domains+="${!domain_var} "
+ done
+ {
+ local maxns=3
+ for addr_var in ${!dns_server_1_address_*}; do
+ [ $((maxns--)) -gt 0 ] || break
+ echo "nameserver ${!addr_var}"
+ done
+ [ -z "$domains" ] || echo "search $domains"
+ } | /sbin/resolvconf -a "$dev"
+ else
+ echo "unsetting DNS using resolvconf"
+ /sbin/resolvconf -d "$dev"
+ fi
+
+ return 0
+}
+
+do_resolved || do_resolvconf
diff --git a/doc/man-sections/script-options.rst
b/doc/man-sections/script-options.rst
index 0d1f9ae..99db19c 100644
--- a/doc/man-sections/script-options.rst
+++ b/doc/man-sections/script-options.rst
@@ -8,9 +8,13 @@
Script Order of Execution
-------------------------
+#. ``--dns-script``
+
+ Executed after TCP/UDP socket bind and TUN/TAP open, before ``--up``.
+
#. ``--up``
- Executed after TCP/UDP socket bind and TUN/TAP open.
+ Executed after TCP/UDP socket bind and TUN/TAP open, after ``--dns-script``.
#. ``--tls-verify``
@@ -38,9 +42,13 @@
Executed in ``--mode server`` mode on client instance shutdown.
+#. ``--dns-script``
+
+ Executed before TCP/UDP and TUN/TAP close, before ``--down``.
+
#. ``--down``
- Executed after TCP/UDP and TUN/TAP close.
+ Executed after TCP/UDP and TUN/TAP close, after ``--dns-script``.
#. ``--learn-address``
@@ -173,7 +181,7 @@
client-crresponse cmd
OpenVPN will write the response of the client into a temporary file.
- The filename will be passed as an argument to ``cmd``, and the file will be
+ The filename will be passed as an argument to ``cmd``, and the file will
automatically deleted by OpenVPN after the script returns.
The response is passed as is from the client. The script needs to check
@@ -235,6 +243,23 @@
The ``--client-disconnect`` command is not passed any extra arguments
(only those arguments specified in cmd, if any).
+--dns-script cmd
+ Run command ``cmd``, instead of the default DNS command that comes with
+ openvpn. If ``cmd`` is ``disable`` no command is executed to set ``--dns``
+ options. If you write your own command, please make sure to ignore ``--dns``
+ server profiles that cannot be applied. Port, DNSSEC and secure transport
+ settings need to be adhered to. If split DNS is not possible a full redirect
+ can be used as a fallback. If not all of the server addresses or search
domains
+ can be configured, apply them in the order they are listed in.
+
+ Note that ``--dns-script`` is not supported on Windows. DNS will
+ always be set by the service there.
+
+ Note that DNS-related ``--dhcp-option``\ s will not be handled by this hook.
+ If any ``--dns server`` option is present, DNS-related ``--dhcp-option``\ s
will
+ be ignored. Otherwise foreign_option environment variables will be passed to
+ ``--up`` and ``--down`` hooks for backward compatibility.
+
--down cmd
Run command ``cmd`` after TUN/TAP device close (post ``--user`` UID
change and/or ``--chroot`` ). ``cmd`` consists of a path to script (or
@@ -661,7 +686,7 @@
names). Set prior to ``--up`` or ``--down`` script execution.
:code:`dns_*`
- The ``--dns`` configuration options will be made available to script
+ The ``--dns`` configuration options will be made available to
``--dns-script``
execution through this set of environment variables. Variables appear
only if the corresponding option has a value assigned. For the semantics
of each individual variable, please refer to the documentation for
``--dns``.
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index 37af683..6664aae 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -30,7 +30,8 @@
$(OPTIONAL_LZ4_CFLAGS) \
$(OPTIONAL_PKCS11_HELPER_CFLAGS) \
$(OPTIONAL_INOTIFY_CFLAGS) \
- -DPLUGIN_LIBDIR=\"${plugindir}\"
+ -DPLUGIN_LIBDIR=\"${plugindir}\" \
+ -DDNS_UPDOWN_PATH=\"${scriptdir}/dns-updown\"
if WIN32
# we want unicode entry point but not the macro
diff --git a/src/openvpn/dns.c b/src/openvpn/dns.c
index b6e524f..6a4669f 100644
--- a/src/openvpn/dns.c
+++ b/src/openvpn/dns.c
@@ -30,6 +30,7 @@
#include "dns.h"
#include "socket.h"
#include "options.h"
+#include "run_command.h"
#ifdef _WIN32
#include "win32.h"
@@ -262,6 +263,8 @@
clone.search_domains = clone_dns_domains(o->search_domains, gc);
clone.servers = clone_dns_servers(o->servers, gc);
clone.servers_prepull = clone_dns_servers(o->servers_prepull, gc);
+ clone.script = o->script;
+ clone.user_defined_script = o->user_defined_script;
return clone;
}
@@ -548,6 +551,54 @@
send_msg_iservice(o->msg_channel, &nrpt, sizeof(nrpt), &ack, "DNS");
}
+#else /* ifdef _WIN32 */
+
+static void
+script_env_set(bool up, const struct dns_options *o, const struct tuntap *tt,
struct env_set *es)
+{
+ setenv_str(es, "dev", tt->actual_name);
+ setenv_str(es, "script_type", up ? "dns-up" : "dns-down");
+ setenv_dns_options(o, es);
+}
+
+static int
+do_run_up_down_script(bool up, const struct dns_options *o, const struct
tuntap *tt)
+{
+ struct gc_arena gc = gc_new();
+ struct argv argv = argv_new();
+ struct env_set *es = env_set_create(&gc);
+
+ script_env_set(up, o, tt, es);
+
+ argv_printf(&argv, "%s", o->script);
+ argv_msg(M_INFO, &argv);
+ int res;
+ if (o->user_defined_script)
+ {
+ res = openvpn_run_script(&argv, es, S_EXITCODE, "dns script");
+ }
+ else
+ {
+ res = openvpn_execve_check(&argv, es, S_EXITCODE, "WARNING: Failed
running dns script");
+ }
+ argv_free(&argv);
+ gc_free(&gc);
+ return res;
+}
+
+static void
+run_up_down_script(bool up, struct options *o, const struct tuntap *tt)
+{
+ if (!o->dns_options.script)
+ {
+ return;
+ }
+
+ int status;
+ status = do_run_up_down_script(up, &o->dns_options, tt);
+ msg(M_INFO, "dns script exited with status %d", status);
+}
+
#endif /* _WIN32 */
void
@@ -666,5 +717,7 @@
#ifdef _WIN32
run_up_down_service(up, o, tt);
+#else
+ run_up_down_script(up, o, tt);
#endif /* ifdef _WIN32 */
}
diff --git a/src/openvpn/dns.h b/src/openvpn/dns.h
index f24e30b..38ced79 100644
--- a/src/openvpn/dns.h
+++ b/src/openvpn/dns.h
@@ -73,6 +73,8 @@
struct dns_server *servers_prepull;
struct dns_server *servers;
struct gc_arena gc;
+ const char *script;
+ bool user_defined_script;
};
/**
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 31000e9..cd9244c 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -526,10 +526,11 @@
" address <addr[:port]> [addr[:port] ...] : server
addresses 4/6\n"
" resolve-domains <domain> [domain ...] : split domains\n"
" dnssec <yes|no|optional> : option to use DNSSEC\n"
- " type <DoH|DoT> : query server over HTTPS / TLS\n"
+ " transport <DoH|DoT> : query server over HTTPS / TLS\n"
" sni <domain> : DNS server name indication\n"
"--dns search-domains <domain> [domain ...]:\n"
" Add domains to DNS domain search list\n"
+ "--dns-script cmd|disable : Run cmd as user defined dns configuration
script or disable it\n"
"--auth-retry t : How to handle auth failures. Set t to\n"
" none (default), interact, or nointeract.\n"
"--static-challenge t e [<scrv1|concat>]: Enable static challenge/response
protocol using\n"
@@ -921,6 +922,8 @@
#ifndef ENABLE_DCO
o->disable_dco = true;
#endif /* ENABLE_DCO */
+
+ o->dns_options.script = DNS_UPDOWN_PATH;
}
void
@@ -8212,6 +8215,28 @@
to->ip_win32_defined = true;
}
#endif /* ifdef _WIN32 */
+ else if (streq(p[0], "dns-script") && p[1])
+ {
+ VERIFY_PERMISSION(OPT_P_SCRIPT);
+ if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT))
+ {
+ goto err;
+ }
+ if (streq(p[1], "disable"))
+ {
+ options->dns_options.script = NULL;
+ }
+ else
+ {
+ if (options->dns_options.user_defined_script == false)
+ {
+ /* Unset the default script to prevent warnings */
+ options->dns_options.script = NULL;
+ }
+ set_user_script(options, &options->dns_options.script, p[1], p[0],
false);
+ options->dns_options.user_defined_script = true;
+ }
+ }
else if (streq(p[0], "dns") && p[1])
{
VERIFY_PERMISSION(OPT_P_DHCPDNS);
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/838?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: Ifbe4ffb44d3bfcaa50adb38cacb3436fcdc71b10
Gerrit-Change-Number: 838
Gerrit-PatchSet: 13
Gerrit-Owner: d12fk <[email protected]>
Gerrit-Reviewer: flichtenheld <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>
Gerrit-Attention: flichtenheld <[email protected]>
Gerrit-MessageType: newpatchset
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel