This introduces a new script hook, the dns-updown, and implements such a
command script for a few popular systems (and a default for the not so
popular ones). Like the name suggests this hook is soleley for dealing
with modifying how names are resolved when the VPN pushes some --dns
settings.
The default dns updown command is part of the distribution and is
installed with openvpn. You can change the path the command is located
at as a compile time option, defaults to libexecdir.
You can compile-time disable that the default dns-updown hook is
run by passing --disable-dns-updown-by-default to configure or
ccmake ENABLE_DNS_UPDOWN_BY_DEFAULT to OFF.
There's also a new runtime option --dns-updown, which can run a custom
command, force running the default when disabled or disable execution
of the dns-updown altogether.
Change-Id: Ifbe4ffb44d3bfcaa50adb38cacb3436fcdc71b10
Signed-off-by: Heiko Hund <heiko@ist.eigentlich.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20250514135334.14377-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg31639.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -41,7 +41,10 @@ option(ENABLE_PKCS11 "BUILD with pkcs11-helper" ON) |
| 41 | 41 |
option(USE_WERROR "Treat compiler warnings as errors (-Werror)" ON) |
| 42 | 42 |
option(FAKE_ANDROID "Target Android but do not use actual cross compile/Android cmake to build for simple compile checks on Linux") |
| 43 | 43 |
|
| 44 |
-set(PLUGIN_DIR /usr/local/lib/openvpn/plugins CACHE FILEPATH "Location of the plugin directory") |
|
| 44 |
+option(ENABLE_DNS_UPDOWN_BY_DEFAULT "Run --dns-updown hook by default" ON) |
|
| 45 |
+set(DNS_UPDOWN_PATH "${CMAKE_INSTALL_PREFIX}/libexec/openvpn/dns-updown" CACHE STRING "Default location for the DNS up/down script")
|
|
| 46 |
+ |
|
| 47 |
+set(PLUGIN_DIR "${CMAKE_INSTALL_PREFIX}/lib/openvpn/plugins" CACHE FILEPATH "Location of the plugin directory")
|
|
| 45 | 48 |
|
| 46 | 49 |
# Create machine readable compile commands |
| 47 | 50 |
option(ENABLE_COMPILE_COMMANDS "Generate compile_commands.json and a symlink for clangd to find it" OFF) |
| ... | ... |
@@ -601,6 +604,8 @@ add_executable(openvpn ${SOURCE_FILES})
|
| 601 | 601 |
|
| 602 | 602 |
add_library_deps(openvpn) |
| 603 | 603 |
|
| 604 |
+target_compile_options(openvpn PRIVATE -DDEFAULT_DNS_UPDOWN=\"${DNS_UPDOWN_PATH}\")
|
|
| 605 |
+ |
|
| 604 | 606 |
if(MINGW) |
| 605 | 607 |
target_compile_options(openvpn PRIVATE -municode -UUNICODE) |
| 606 | 608 |
target_link_options(openvpn PRIVATE -municode) |
| ... | ... |
@@ -96,6 +96,13 @@ AC_ARG_ENABLE( |
| 96 | 96 |
) |
| 97 | 97 |
|
| 98 | 98 |
AC_ARG_ENABLE( |
| 99 |
+ [dns-updown-by-default], |
|
| 100 |
+ [AS_HELP_STRING([--disable-dns-updown-by-default], [disable running --dns-updown by default @<:@default=yes@:>@])], |
|
| 101 |
+ , |
|
| 102 |
+ [enable_dns_updown_by_default="yes"] |
|
| 103 |
+) |
|
| 104 |
+ |
|
| 105 |
+AC_ARG_ENABLE( |
|
| 99 | 106 |
[ntlm], |
| 100 | 107 |
[AS_HELP_STRING([--disable-ntlm], [disable NTLMv2 proxy support @<:@default=yes@:>@])], |
| 101 | 108 |
, |
| ... | ... |
@@ -315,37 +322,50 @@ else |
| 315 | 315 |
plugindir="\${libdir}/openvpn/plugins"
|
| 316 | 316 |
fi |
| 317 | 317 |
|
| 318 |
+AC_ARG_VAR([SCRIPTDIR], [Path of script directory @<:@default=PKGLIBEXECDIR@:>@]) |
|
| 319 |
+if test -n "${SCRIPTDIR}"; then
|
|
| 320 |
+ scriptdir="${SCRIPTDIR}"
|
|
| 321 |
+else |
|
| 322 |
+ scriptdir="\${pkglibexecdir}"
|
|
| 323 |
+fi |
|
| 324 |
+ |
|
| 318 | 325 |
AC_DEFINE_UNQUOTED([TARGET_ALIAS], ["${host}"], [A string representing our host])
|
| 319 |
-AM_CONDITIONAL([TARGET_LINUX], [false]) |
|
| 326 |
+AM_CONDITIONAL([ENABLE_DNS_UPDOWN],[true]) |
|
| 320 | 327 |
case "$host" in |
| 321 | 328 |
*-*-linux*) |
| 322 | 329 |
AC_DEFINE([TARGET_LINUX], [1], [Are we running on Linux?]) |
| 323 |
- AM_CONDITIONAL([TARGET_LINUX], [true]) |
|
| 324 | 330 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["L"], [Target prefix]) |
| 331 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["systemd"]) |
|
| 325 | 332 |
have_sitnl="yes" |
| 326 | 333 |
pkg_config_required="yes" |
| 327 | 334 |
;; |
| 328 | 335 |
*-*-solaris*) |
| 329 | 336 |
AC_DEFINE([TARGET_SOLARIS], [1], [Are we running on Solaris?]) |
| 330 | 337 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["S"], [Target prefix]) |
| 338 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"]) |
|
| 331 | 339 |
CPPFLAGS="$CPPFLAGS -D_XPG4_2" |
| 332 | 340 |
test -x /bin/bash && SHELL="/bin/bash" |
| 333 | 341 |
;; |
| 334 | 342 |
*-*-openbsd*) |
| 335 | 343 |
AC_DEFINE([TARGET_OPENBSD], [1], [Are we running on OpenBSD?]) |
| 336 | 344 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["O"], [Target prefix]) |
| 345 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"]) |
|
| 337 | 346 |
;; |
| 338 | 347 |
*-*-freebsd*) |
| 339 | 348 |
AC_DEFINE([TARGET_FREEBSD], [1], [Are we running on FreeBSD?]) |
| 340 | 349 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["F"], [Target prefix]) |
| 350 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["openresolv"]) |
|
| 341 | 351 |
;; |
| 342 | 352 |
*-*-netbsd*) |
| 343 | 353 |
AC_DEFINE([TARGET_NETBSD], [1], [Are we running NetBSD?]) |
| 344 | 354 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["N"], [Target prefix]) |
| 355 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["openresolv"]) |
|
| 345 | 356 |
;; |
| 346 | 357 |
*-*-darwin*) |
| 347 | 358 |
AC_DEFINE([TARGET_DARWIN], [1], [Are we running on Mac OS X?]) |
| 348 | 359 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["M"], [Target prefix]) |
| 360 |
+ AM_CONDITIONAL([ENABLE_DNS_UPDOWN], [false]) |
|
| 361 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"]) |
|
| 349 | 362 |
have_tap_header="yes" |
| 350 | 363 |
ac_cv_type_struct_in_pktinfo=no |
| 351 | 364 |
;; |
| ... | ... |
@@ -353,6 +373,8 @@ case "$host" in |
| 353 | 353 |
AC_DEFINE([TARGET_WIN32], [1], [Are we running WIN32?]) |
| 354 | 354 |
AC_DEFINE([ENABLE_DCO], [1], [DCO is always enabled on Windows]) |
| 355 | 355 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["W"], [Target prefix]) |
| 356 |
+ AM_CONDITIONAL([ENABLE_DNS_UPDOWN], [false]) |
|
| 357 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["windows"]) |
|
| 356 | 358 |
CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN"
|
| 357 | 359 |
CPPFLAGS="${CPPFLAGS} -DNTDDI_VERSION=NTDDI_VISTA -D_WIN32_WINNT=_WIN32_WINNT_VISTA"
|
| 358 | 360 |
WIN32=yes |
| ... | ... |
@@ -360,10 +382,12 @@ case "$host" in |
| 360 | 360 |
*-*-dragonfly*) |
| 361 | 361 |
AC_DEFINE([TARGET_DRAGONFLY], [1], [Are we running on DragonFlyBSD?]) |
| 362 | 362 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["D"], [Target prefix]) |
| 363 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["openresolv"]) |
|
| 363 | 364 |
;; |
| 364 | 365 |
*-aix*) |
| 365 | 366 |
AC_DEFINE([TARGET_AIX], [1], [Are we running AIX?]) |
| 366 | 367 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["A"], [Target prefix]) |
| 368 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"]) |
|
| 367 | 369 |
ROUTE="/usr/sbin/route" |
| 368 | 370 |
have_tap_header="yes" |
| 369 | 371 |
ac_cv_header_net_if_h="no" # exists, but breaks things |
| ... | ... |
@@ -371,10 +395,12 @@ case "$host" in |
| 371 | 371 |
*-*-haiku*) |
| 372 | 372 |
AC_DEFINE([TARGET_HAIKU], [1], [Are we running Haiku?]) |
| 373 | 373 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["H"], [Target prefix]) |
| 374 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["haikuos_file"]) |
|
| 374 | 375 |
LIBS="${LIBS} -lnetwork"
|
| 375 | 376 |
;; |
| 376 | 377 |
*) |
| 377 | 378 |
AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["X"], [Target prefix]) |
| 379 |
+ AC_SUBST([DNS_UPDOWN_TYPE], ["resolvconf_file"]) |
|
| 378 | 380 |
have_tap_header="yes" |
| 379 | 381 |
;; |
| 380 | 382 |
esac |
| ... | ... |
@@ -1317,7 +1343,7 @@ test "${enable_debug}" = "yes" && AC_DEFINE([ENABLE_DEBUG], [1], [Enable debuggi
|
| 1317 | 1317 |
test "${enable_small}" = "yes" && AC_DEFINE([ENABLE_SMALL], [1], [Enable smaller executable size])
|
| 1318 | 1318 |
test "${enable_fragment}" = "yes" && AC_DEFINE([ENABLE_FRAGMENT], [1], [Enable internal fragmentation support])
|
| 1319 | 1319 |
test "${enable_port_share}" = "yes" && AC_DEFINE([ENABLE_PORT_SHARE], [1], [Enable TCP Server port sharing])
|
| 1320 |
- |
|
| 1320 |
+test "${enable_dns_updown_by_default}" = "yes" && AC_DEFINE([ENABLE_DNS_UPDOWN_BY_DEFAULT], [1], [Enable dns-updown hook by default])
|
|
| 1321 | 1321 |
test "${enable_ntlm}" = "yes" && AC_DEFINE([ENABLE_NTLM], [1], [Enable NTLMv2 proxy support])
|
| 1322 | 1322 |
test "${enable_crypto_ofb_cfb}" = "yes" && AC_DEFINE([ENABLE_OFB_CFB_MODE], [1], [Enable OFB and CFB cipher modes])
|
| 1323 | 1323 |
if test "${have_export_keying_material}" = "yes"; then
|
| ... | ... |
@@ -1505,6 +1531,7 @@ AM_CONDITIONAL([OPENSSL_ENGINE], [test "${have_openssl_engine}" = "yes"])
|
| 1505 | 1505 |
|
| 1506 | 1506 |
sampledir="\$(docdir)/sample" |
| 1507 | 1507 |
AC_SUBST([plugindir]) |
| 1508 |
+AC_SUBST([scriptdir]) |
|
| 1508 | 1509 |
AC_SUBST([sampledir]) |
| 1509 | 1510 |
|
| 1510 | 1511 |
AC_SUBST([systemdunitdir]) |
| ... | ... |
@@ -1541,6 +1568,7 @@ AC_CONFIG_FILES([ |
| 1541 | 1541 |
Makefile |
| 1542 | 1542 |
distro/Makefile |
| 1543 | 1543 |
distro/systemd/Makefile |
| 1544 |
+ distro/dns-scripts/Makefile |
|
| 1544 | 1545 |
doc/Makefile |
| 1545 | 1546 |
doc/doxygen/Makefile |
| 1546 | 1547 |
doc/doxygen/openvpn.doxyfile |
| 16 | 20 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,29 @@ |
| 0 |
+# |
|
| 1 |
+# OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+# over a single UDP port, with support for SSL/TLS-based |
|
| 3 |
+# session authentication and key exchange, |
|
| 4 |
+# packet encryption, packet authentication, and |
|
| 5 |
+# packet compression. |
|
| 6 |
+# |
|
| 7 |
+# Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net> |
|
| 8 |
+# |
|
| 9 |
+ |
|
| 10 |
+MAINTAINERCLEANFILES = \ |
|
| 11 |
+ $(srcdir)/Makefile.in |
|
| 12 |
+ |
|
| 13 |
+EXTRA_DIST = \ |
|
| 14 |
+ systemd-dns-updown.sh \ |
|
| 15 |
+ openresolv-dns-updown.sh \ |
|
| 16 |
+ haikuos_file-dns-updown.sh \ |
|
| 17 |
+ resolvconf_file-dns-updown.sh |
|
| 18 |
+ |
|
| 19 |
+script_SCRIPTS = \ |
|
| 20 |
+ dns-updown |
|
| 21 |
+ |
|
| 22 |
+CLEANFILES = $(script_SCRIPTS) |
|
| 23 |
+ |
|
| 24 |
+dns-updown: @DNS_UPDOWN_TYPE@-dns-updown.sh |
|
| 25 |
+ cp ${srcdir}/@DNS_UPDOWN_TYPE@-dns-updown.sh $@
|
|
| 26 |
+ chmod +x $@ |
|
| 27 |
+ |
|
| 28 |
+all: $(script_SCRIPTS) |
| 0 | 29 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,85 @@ |
| 0 |
+#!/bin/sh |
|
| 1 |
+# |
|
| 2 |
+# Simple OpenVPN up/down script for modifying Haiku OS resolv.conf |
|
| 3 |
+# (C) Copyright 2024 OpenVPN Inc <sales@openvpn.net> |
|
| 4 |
+# |
|
| 5 |
+# SPDX-License-Identifier: BSD-2-Clause |
|
| 6 |
+# |
|
| 7 |
+# Example env from openvpn (most are not applied): |
|
| 8 |
+# |
|
| 9 |
+# dev tun0 |
|
| 10 |
+# script_type dns-up |
|
| 11 |
+# dns_search_domain_1 mycorp.in |
|
| 12 |
+# dns_search_domain_2 eu.mycorp.com |
|
| 13 |
+# dns_server_1_address_1 192.168.99.254 |
|
| 14 |
+# dns_server_1_address_2 fd00::99:53 |
|
| 15 |
+# dns_server_1_port_1 53 |
|
| 16 |
+# dns_server_1_port_2 53 |
|
| 17 |
+# dns_server_1_resolve_domain_1 mycorp.in |
|
| 18 |
+# dns_server_1_resolve_domain_2 eu.mycorp.com |
|
| 19 |
+# dns_server_1_dnssec true |
|
| 20 |
+# dns_server_1_transport DoH |
|
| 21 |
+# dns_server_1_sni dns.mycorp.in |
|
| 22 |
+# |
|
| 23 |
+ |
|
| 24 |
+set -e +u |
|
| 25 |
+ |
|
| 26 |
+conly_standard_server_ports() {
|
|
| 27 |
+ i=1 |
|
| 28 |
+ while true; do |
|
| 29 |
+ eval addr=\"\$dns_server_${n}_address_${i}\"
|
|
| 30 |
+ [ -n "$addr" ] || return 0 |
|
| 31 |
+ |
|
| 32 |
+ eval port=\"\$dns_server_${n}_port_${i}\"
|
|
| 33 |
+ [ -z "$port" -o "$port" = "53" ] || return 1 |
|
| 34 |
+ |
|
| 35 |
+ i=$(expr $i + 1) |
|
| 36 |
+ done |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+onf=/boot/system/settings/network/resolv.conf |
|
| 40 |
+test -e "$conf" || exit 1 |
|
| 41 |
+case "${script_type}" in
|
|
| 42 |
+dns-up) |
|
| 43 |
+ n=1 |
|
| 44 |
+ while :; do |
|
| 45 |
+ eval addr=\"\$dns_server_${n}_address_1\"
|
|
| 46 |
+ [ -n "$addr" ] || {
|
|
| 47 |
+ echo "setting DNS failed, no compatible server profile" |
|
| 48 |
+ exit 1 |
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ # Skip server profiles which require DNSSEC, |
|
| 52 |
+ # secure transport or use a custom port |
|
| 53 |
+ eval dnssec=\"\$dns_server_${n}_dnssec\"
|
|
| 54 |
+ eval transport=\"\$dns_server_${n}_transport\"
|
|
| 55 |
+ [ -z "$transport" -o "$transport" = "plain" ] \ |
|
| 56 |
+ && [ -z "$dnssec" -o "$dnssec" = "no" ] \ |
|
| 57 |
+ && only_standard_server_ports && break |
|
| 58 |
+ |
|
| 59 |
+ n=$(expr $n + 1) |
|
| 60 |
+ done |
|
| 61 |
+ |
|
| 62 |
+ eval addr1=\"\$dns_server_${n}_address_1\"
|
|
| 63 |
+ eval addr2=\"\$dns_server_${n}_address_2\"
|
|
| 64 |
+ eval addr3=\"\$dns_server_${n}_address_3\"
|
|
| 65 |
+ text="### openvpn ${dev} begin ###\n"
|
|
| 66 |
+ text="${text}nameserver $addr1\n"
|
|
| 67 |
+ test -z "$addr2" || text="${text}nameserver $addr2\n"
|
|
| 68 |
+ test -z "$addr3" || text="${text}nameserver $addr3\n"
|
|
| 69 |
+ |
|
| 70 |
+ test -z "$dns_search_domain_1" || {
|
|
| 71 |
+ for i in $(seq 1 6); do |
|
| 72 |
+ eval domains=\"$domains\$dns_search_domain_${i} \" || break
|
|
| 73 |
+ done |
|
| 74 |
+ text="${text}search $domains\n"
|
|
| 75 |
+ } |
|
| 76 |
+ text="${text}### openvpn ${dev} end ###"
|
|
| 77 |
+ text="${text}\n$(cat ${conf})"
|
|
| 78 |
+ |
|
| 79 |
+ echo "${text}" > "${conf}"
|
|
| 80 |
+ ;; |
|
| 81 |
+dns-down) |
|
| 82 |
+ sed -i'' -e "/### openvpn ${dev} begin ###/,/### openvpn ${dev} end ###/d" "$conf"
|
|
| 83 |
+ ;; |
|
| 84 |
+esac |
| 0 | 85 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,89 @@ |
| 0 |
+#!/bin/sh |
|
| 1 |
+# |
|
| 2 |
+# Simple OpenVPN up/down script for openresolv integration |
|
| 3 |
+# (C) Copyright 2016 Baptiste Daroussin |
|
| 4 |
+# 2024 OpenVPN Inc <sales@openvpn.net> |
|
| 5 |
+# |
|
| 6 |
+# SPDX-License-Identifier: BSD-2-Clause |
|
| 7 |
+# |
|
| 8 |
+# Example env from openvpn (most are not applied): |
|
| 9 |
+# |
|
| 10 |
+# dev tun0 |
|
| 11 |
+# script_type dns-up |
|
| 12 |
+# dns_search_domain_1 mycorp.in |
|
| 13 |
+# dns_search_domain_2 eu.mycorp.com |
|
| 14 |
+# dns_server_1_address_1 192.168.99.254 |
|
| 15 |
+# dns_server_1_address_2 fd00::99:53 |
|
| 16 |
+# dns_server_1_port_1 53 |
|
| 17 |
+# dns_server_1_port_2 53 |
|
| 18 |
+# dns_server_1_resolve_domain_1 mycorp.in |
|
| 19 |
+# dns_server_1_resolve_domain_2 eu.mycorp.com |
|
| 20 |
+# dns_server_1_dnssec true |
|
| 21 |
+# dns_server_1_transport DoH |
|
| 22 |
+# dns_server_1_sni dns.mycorp.in |
|
| 23 |
+# |
|
| 24 |
+ |
|
| 25 |
+set -e +u |
|
| 26 |
+ |
|
| 27 |
+only_standard_server_ports() {
|
|
| 28 |
+ i=1 |
|
| 29 |
+ while true; do |
|
| 30 |
+ eval addr=\"\$dns_server_${n}_address_${i}\"
|
|
| 31 |
+ [ -n "$addr" ] || return 0 |
|
| 32 |
+ |
|
| 33 |
+ eval port=\"\$dns_server_${n}_port_${i}\"
|
|
| 34 |
+ [ -z "$port" -o "$port" = "53" ] || return 1 |
|
| 35 |
+ |
|
| 36 |
+ i=$(expr $i + 1) |
|
| 37 |
+ done |
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+: ${script_type:=dns-down}
|
|
| 41 |
+case "${script_type}" in
|
|
| 42 |
+dns-up) |
|
| 43 |
+ n=1 |
|
| 44 |
+ while :; do |
|
| 45 |
+ eval addr=\"\$dns_server_${n}_address_1\"
|
|
| 46 |
+ [ -n "$addr" ] || {
|
|
| 47 |
+ echo "setting DNS failed, no compatible server profile" |
|
| 48 |
+ exit 1 |
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ # Skip server profiles which require DNSSEC, |
|
| 52 |
+ # secure transport or use a custom port |
|
| 53 |
+ eval dnssec=\"\$dns_server_${n}_dnssec\"
|
|
| 54 |
+ eval transport=\"\$dns_server_${n}_transport\"
|
|
| 55 |
+ [ -z "$transport" -o "$transport" = "plain" ] \ |
|
| 56 |
+ && [ -z "$dnssec" -o "$dnssec" = "no" ] \ |
|
| 57 |
+ && only_standard_server_ports && break |
|
| 58 |
+ |
|
| 59 |
+ n=$(expr $n + 1) |
|
| 60 |
+ done |
|
| 61 |
+ |
|
| 62 |
+ {
|
|
| 63 |
+ i=1 |
|
| 64 |
+ maxns=3 |
|
| 65 |
+ while :; do |
|
| 66 |
+ maxns=$((maxns - 1)) |
|
| 67 |
+ [ $maxns -gt 0 ] || break |
|
| 68 |
+ eval option=\"\$dns_server_${n}_address_${i}\" || break
|
|
| 69 |
+ [ "${option}" ] || break
|
|
| 70 |
+ i=$((i + 1)) |
|
| 71 |
+ echo "nameserver ${option}"
|
|
| 72 |
+ done |
|
| 73 |
+ i=1 |
|
| 74 |
+ maxdom=6 |
|
| 75 |
+ while :; do |
|
| 76 |
+ maxdom=$((maxdom - 1)) |
|
| 77 |
+ [ $maxdom -gt 0 ] || break |
|
| 78 |
+ eval option=\"\$dns_search_domain_${i}\" || break
|
|
| 79 |
+ [ "${option}" ] || break
|
|
| 80 |
+ i=$((i + 1)) |
|
| 81 |
+ echo "search ${option}"
|
|
| 82 |
+ done |
|
| 83 |
+ } | /sbin/resolvconf -a "${dev}"
|
|
| 84 |
+ ;; |
|
| 85 |
+dns-down) |
|
| 86 |
+ /sbin/resolvconf -d "${dev}" -f
|
|
| 87 |
+ ;; |
|
| 88 |
+esac |
| 0 | 89 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,85 @@ |
| 0 |
+#!/bin/sh |
|
| 1 |
+# |
|
| 2 |
+# Simple OpenVPN up/down script for modifying /etc/resolv.conf |
|
| 3 |
+# (C) Copyright 2024 OpenVPN Inc <sales@openvpn.net> |
|
| 4 |
+# |
|
| 5 |
+# SPDX-License-Identifier: BSD-2-Clause |
|
| 6 |
+# |
|
| 7 |
+# Example env from openvpn (most are not applied): |
|
| 8 |
+# |
|
| 9 |
+# dev tun0 |
|
| 10 |
+# script_type dns-up |
|
| 11 |
+# dns_search_domain_1 mycorp.in |
|
| 12 |
+# dns_search_domain_2 eu.mycorp.com |
|
| 13 |
+# dns_server_1_address_1 192.168.99.254 |
|
| 14 |
+# dns_server_1_address_2 fd00::99:53 |
|
| 15 |
+# dns_server_1_port_1 53 |
|
| 16 |
+# dns_server_1_port_2 53 |
|
| 17 |
+# dns_server_1_resolve_domain_1 mycorp.in |
|
| 18 |
+# dns_server_1_resolve_domain_2 eu.mycorp.com |
|
| 19 |
+# dns_server_1_dnssec true |
|
| 20 |
+# dns_server_1_transport DoH |
|
| 21 |
+# dns_server_1_sni dns.mycorp.in |
|
| 22 |
+# |
|
| 23 |
+ |
|
| 24 |
+set -e +u |
|
| 25 |
+ |
|
| 26 |
+only_standard_server_ports() {
|
|
| 27 |
+ i=1 |
|
| 28 |
+ while true; do |
|
| 29 |
+ eval addr=\"\$dns_server_${n}_address_${i}\"
|
|
| 30 |
+ [ -n "$addr" ] || return 0 |
|
| 31 |
+ |
|
| 32 |
+ eval port=\"\$dns_server_${n}_port_${i}\"
|
|
| 33 |
+ [ -z "$port" -o "$port" = "53" ] || return 1 |
|
| 34 |
+ |
|
| 35 |
+ i=$(expr $i + 1) |
|
| 36 |
+ done |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+conf=/etc/resolv.conf |
|
| 40 |
+test -e "$conf" || exit 1 |
|
| 41 |
+case "${script_type}" in
|
|
| 42 |
+dns-up) |
|
| 43 |
+ n=1 |
|
| 44 |
+ while :; do |
|
| 45 |
+ eval addr=\"\$dns_server_${n}_address_1\"
|
|
| 46 |
+ [ -n "$addr" ] || {
|
|
| 47 |
+ echo "setting DNS failed, no compatible server profile" |
|
| 48 |
+ exit 1 |
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ # Skip server profiles which require DNSSEC, |
|
| 52 |
+ # secure transport or use a custom port |
|
| 53 |
+ eval dnssec=\"\$dns_server_${n}_dnssec\"
|
|
| 54 |
+ eval transport=\"\$dns_server_${n}_transport\"
|
|
| 55 |
+ [ -z "$transport" -o "$transport" = "plain" ] \ |
|
| 56 |
+ && [ -z "$dnssec" -o "$dnssec" = "no" ] \ |
|
| 57 |
+ && only_standard_server_ports && break |
|
| 58 |
+ |
|
| 59 |
+ n=$(expr $n + 1) |
|
| 60 |
+ done |
|
| 61 |
+ |
|
| 62 |
+ eval addr1=\"\$dns_server_${n}_address_1\"
|
|
| 63 |
+ eval addr2=\"\$dns_server_${n}_address_2\"
|
|
| 64 |
+ eval addr3=\"\$dns_server_${n}_address_3\"
|
|
| 65 |
+ text="### openvpn ${dev} begin ###\n"
|
|
| 66 |
+ text="${text}nameserver $addr1\n"
|
|
| 67 |
+ test -z "$addr2" || text="${text}nameserver $addr2\n"
|
|
| 68 |
+ test -z "$addr3" || text="${text}nameserver $addr3\n"
|
|
| 69 |
+ |
|
| 70 |
+ test -z "$dns_search_domain_1" || {
|
|
| 71 |
+ for i in $(seq 1 6); do |
|
| 72 |
+ eval domains=\"$domains\$dns_search_domain_${i} \" || break
|
|
| 73 |
+ done |
|
| 74 |
+ text="${text}search $domains\n"
|
|
| 75 |
+ } |
|
| 76 |
+ text="${text}### openvpn ${dev} end ###"
|
|
| 77 |
+ text="${text}\n$(cat ${conf})"
|
|
| 78 |
+ |
|
| 79 |
+ echo "${text}" > "${conf}"
|
|
| 80 |
+ ;; |
|
| 81 |
+dns-down) |
|
| 82 |
+ sed -i'' -e "/### openvpn ${dev} begin ###/,/### openvpn ${dev} end ###/d" "$conf"
|
|
| 83 |
+ ;; |
|
| 84 |
+esac |
| 0 | 85 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,240 @@ |
| 0 |
+#!/bin/bash |
|
| 1 |
+# |
|
| 2 |
+# dns-updown - add/remove openvpn provided DNS information |
|
| 3 |
+# |
|
| 4 |
+# Copyright (C) 2024 OpenVPN Inc <sales@openvpn.net> |
|
| 5 |
+# |
|
| 6 |
+# SPDX-License-Identifier: GPL-2.0 |
|
| 7 |
+# |
|
| 8 |
+# Add/remove openvpn DNS settings from the env into/from |
|
| 9 |
+# the system. Supported backends in this order: |
|
| 10 |
+# |
|
| 11 |
+# * systemd-resolved |
|
| 12 |
+# * resolvconf |
|
| 13 |
+# * /etc/resolv.conf file |
|
| 14 |
+# |
|
| 15 |
+# Example env from openvpn (not all are always applied): |
|
| 16 |
+# |
|
| 17 |
+# dev tun0 |
|
| 18 |
+# script_type dns-up |
|
| 19 |
+# dns_search_domain_1 mycorp.in |
|
| 20 |
+# dns_search_domain_2 eu.mycorp.com |
|
| 21 |
+# dns_server_1_address_1 192.168.99.254 |
|
| 22 |
+# dns_server_1_address_2 fd00::99:53 |
|
| 23 |
+# dns_server_1_port_1 53 |
|
| 24 |
+# dns_server_1_port_2 53 |
|
| 25 |
+# dns_server_1_resolve_domain_1 mycorp.in |
|
| 26 |
+# dns_server_1_resolve_domain_2 eu.mycorp.com |
|
| 27 |
+# dns_server_1_dnssec true |
|
| 28 |
+# dns_server_1_transport DoH |
|
| 29 |
+# dns_server_1_sni dns.mycorp.in |
|
| 30 |
+# |
|
| 31 |
+ |
|
| 32 |
+function do_resolved_servers {
|
|
| 33 |
+ local sni="" |
|
| 34 |
+ local transport_var=dns_server_${n}_transport
|
|
| 35 |
+ local sni_var=dns_server_${n}_sni
|
|
| 36 |
+ [ "${!transport_var}" = "DoT" ] && sni="#${!sni_var}"
|
|
| 37 |
+ |
|
| 38 |
+ local i=1 |
|
| 39 |
+ local addrs="" |
|
| 40 |
+ while :; do |
|
| 41 |
+ local addr_var=dns_server_${n}_address_${i}
|
|
| 42 |
+ local addr="${!addr_var}"
|
|
| 43 |
+ [ -n "$addr" ] || break |
|
| 44 |
+ |
|
| 45 |
+ local port_var=dns_server_${n}_port_${i}
|
|
| 46 |
+ if [ -n "${!port_var}" ]; then
|
|
| 47 |
+ if [[ "$addr" =~ : ]]; then |
|
| 48 |
+ addr="[$addr]" |
|
| 49 |
+ fi |
|
| 50 |
+ addrs+="${addr}:${!port_var}${sni} "
|
|
| 51 |
+ else |
|
| 52 |
+ addrs+="${addr}${sni} "
|
|
| 53 |
+ fi |
|
| 54 |
+ i=$((i+1)) |
|
| 55 |
+ done |
|
| 56 |
+ |
|
| 57 |
+ resolvectl dns "$dev" $addrs |
|
| 58 |
+} |
|
| 59 |
+ |
|
| 60 |
+function do_resolved_domains {
|
|
| 61 |
+ local list="" |
|
| 62 |
+ for domain_var in ${!dns_search_domain_*}; do
|
|
| 63 |
+ list+="${!domain_var} "
|
|
| 64 |
+ done |
|
| 65 |
+ local domain_var=dns_server_${n}_resolve_domain_1
|
|
| 66 |
+ if [ -z "${!domain_var}" ]; then
|
|
| 67 |
+ resolvectl default-route "$dev" true |
|
| 68 |
+ list+="~." |
|
| 69 |
+ else |
|
| 70 |
+ resolvectl default-route "$dev" false |
|
| 71 |
+ local i=1 |
|
| 72 |
+ while :; do |
|
| 73 |
+ domain_var=dns_server_${n}_resolve_domain_${i}
|
|
| 74 |
+ [ -n "${!domain_var}" ] || break
|
|
| 75 |
+ # Add as split domain (~ prefix), if it doesn't already exist |
|
| 76 |
+ [[ "$list" =~ (^| )"${!domain_var}"( |$) ]] \
|
|
| 77 |
+ || list+="~${!domain_var} "
|
|
| 78 |
+ i=$((i+1)) |
|
| 79 |
+ done |
|
| 80 |
+ fi |
|
| 81 |
+ |
|
| 82 |
+ resolvectl domain "$dev" $list |
|
| 83 |
+} |
|
| 84 |
+ |
|
| 85 |
+function do_resolved_dnssec {
|
|
| 86 |
+ local dnssec_var=dns_server_${n}_dnssec
|
|
| 87 |
+ if [ "${!dnssec_var}" = "optional" ]; then
|
|
| 88 |
+ resolvectl dnssec "$dev" allow-downgrade |
|
| 89 |
+ elif [ "${!dnssec_var}" = "yes" ]; then
|
|
| 90 |
+ resolvectl dnssec "$dev" true |
|
| 91 |
+ else |
|
| 92 |
+ resolvectl dnssec "$dev" false |
|
| 93 |
+ fi |
|
| 94 |
+} |
|
| 95 |
+ |
|
| 96 |
+function do_resolved_dnsovertls {
|
|
| 97 |
+ local transport_var=dns_server_${n}_transport
|
|
| 98 |
+ if [ "${!transport_var}" = "DoT" ]; then
|
|
| 99 |
+ resolvectl dnsovertls "$dev" true |
|
| 100 |
+ else |
|
| 101 |
+ resolvectl dnsovertls "$dev" false |
|
| 102 |
+ fi |
|
| 103 |
+} |
|
| 104 |
+ |
|
| 105 |
+function do_resolved {
|
|
| 106 |
+ [[ "$(readlink /etc/resolv.conf)" =~ systemd ]] || return 1 |
|
| 107 |
+ |
|
| 108 |
+ n=1 |
|
| 109 |
+ while :; do |
|
| 110 |
+ local addr_var=dns_server_${n}_address_1
|
|
| 111 |
+ [ -n "${!addr_var}" ] || {
|
|
| 112 |
+ echo "setting DNS failed, no compatible server profile" |
|
| 113 |
+ return 1 |
|
| 114 |
+ } |
|
| 115 |
+ |
|
| 116 |
+ # Skip server profiles which require DNS-over-HTTPS |
|
| 117 |
+ local transport_var=dns_server_${n}_transport
|
|
| 118 |
+ [ -n "${!transport_var}" -a "${!transport_var}" = "DoH" ] || break
|
|
| 119 |
+ |
|
| 120 |
+ n=$((n+1)) |
|
| 121 |
+ done |
|
| 122 |
+ |
|
| 123 |
+ if [ "$script_type" = "dns-up" ]; then |
|
| 124 |
+ echo "setting DNS using resolvectl" |
|
| 125 |
+ do_resolved_servers |
|
| 126 |
+ do_resolved_domains |
|
| 127 |
+ do_resolved_dnssec |
|
| 128 |
+ do_resolved_dnsovertls |
|
| 129 |
+ else |
|
| 130 |
+ echo "unsetting DNS using resolvectl" |
|
| 131 |
+ resolvectl revert "$dev" |
|
| 132 |
+ fi |
|
| 133 |
+ |
|
| 134 |
+ return 0 |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+function only_standard_server_ports {
|
|
| 138 |
+ local i=1 |
|
| 139 |
+ while :; do |
|
| 140 |
+ local addr_var=dns_server_${n}_address_${i}
|
|
| 141 |
+ [ -n "${!addr_var}" ] || return 0
|
|
| 142 |
+ |
|
| 143 |
+ local port_var=dns_server_${n}_port_${i}
|
|
| 144 |
+ [ -z "${!port_var}" -o "${!port_var}" = "53" ] || return 1
|
|
| 145 |
+ |
|
| 146 |
+ i=$((i+1)) |
|
| 147 |
+ done |
|
| 148 |
+} |
|
| 149 |
+ |
|
| 150 |
+function resolv_conf_compat_profile {
|
|
| 151 |
+ local n=1 |
|
| 152 |
+ while :; do |
|
| 153 |
+ local server_addr_var=dns_server_${n}_address_1
|
|
| 154 |
+ [ -n "${!server_addr_var}" ] || {
|
|
| 155 |
+ echo "setting DNS failed, no compatible server profile" |
|
| 156 |
+ exit 1 |
|
| 157 |
+ } |
|
| 158 |
+ |
|
| 159 |
+ # Skip server profiles which require DNSSEC, |
|
| 160 |
+ # secure transport or use a custom port |
|
| 161 |
+ local dnssec_var=dns_server_${n}_dnssec
|
|
| 162 |
+ local transport_var=dns_server_${n}_transport
|
|
| 163 |
+ [ -z "${!transport_var}" -o "${!transport_var}" = "plain" ] \
|
|
| 164 |
+ && [ -z "${!dnssec_var}" -o "${!dnssec_var}" = "no" ] \
|
|
| 165 |
+ && only_standard_server_ports && break |
|
| 166 |
+ |
|
| 167 |
+ n=$((n+1)) |
|
| 168 |
+ done |
|
| 169 |
+ return $n |
|
| 170 |
+} |
|
| 171 |
+ |
|
| 172 |
+function do_resolvconf {
|
|
| 173 |
+ [ -x /sbin/resolvconf ] || return 1 |
|
| 174 |
+ |
|
| 175 |
+ resolv_conf_compat_profile |
|
| 176 |
+ local n=$? |
|
| 177 |
+ |
|
| 178 |
+ if [ "$script_type" = "dns-up" ]; then |
|
| 179 |
+ echo "setting DNS using resolvconf" |
|
| 180 |
+ local domains="" |
|
| 181 |
+ for domain_var in ${!dns_search_domain_*}; do
|
|
| 182 |
+ domains+="${!domain_var} "
|
|
| 183 |
+ done |
|
| 184 |
+ {
|
|
| 185 |
+ local maxns=3 |
|
| 186 |
+ local server_var=dns_server_${n}_address_*
|
|
| 187 |
+ for addr_var in ${!server_var}; do
|
|
| 188 |
+ [ $((maxns--)) -gt 0 ] || break |
|
| 189 |
+ echo "nameserver ${!addr_var}"
|
|
| 190 |
+ done |
|
| 191 |
+ [ -z "$domains" ] || echo "search $domains" |
|
| 192 |
+ } | /sbin/resolvconf -a "$dev" |
|
| 193 |
+ else |
|
| 194 |
+ echo "unsetting DNS using resolvconf" |
|
| 195 |
+ /sbin/resolvconf -d "$dev" |
|
| 196 |
+ fi |
|
| 197 |
+ |
|
| 198 |
+ return 0 |
|
| 199 |
+} |
|
| 200 |
+ |
|
| 201 |
+function do_resolv_conf_file {
|
|
| 202 |
+ conf=/etc/resolv.conf |
|
| 203 |
+ test -e "$conf" || exit 1 |
|
| 204 |
+ |
|
| 205 |
+ resolv_conf_compat_profile |
|
| 206 |
+ local n=$? |
|
| 207 |
+ |
|
| 208 |
+ if [ "$script_type" = "dns-up" ]; then |
|
| 209 |
+ echo "setting DNS using resolv.conf file" |
|
| 210 |
+ |
|
| 211 |
+ local addr1_var=dns_server_${n}_address_1
|
|
| 212 |
+ local addr2_var=dns_server_${n}_address_2
|
|
| 213 |
+ local addr3_var=dns_server_${n}_address_3
|
|
| 214 |
+ text="### openvpn ${dev} begin ###\n"
|
|
| 215 |
+ text="${text}nameserver ${!addr1_var}\n"
|
|
| 216 |
+ test -z "${!addr2_var}" || text="${text}nameserver ${!addr2_var}\n"
|
|
| 217 |
+ test -z "${!addr3_var}" || text="${text}nameserver ${!addr3_var}\n"
|
|
| 218 |
+ |
|
| 219 |
+ test -z "$dns_search_domain_1" || {
|
|
| 220 |
+ for i in $(seq 1 6); do |
|
| 221 |
+ eval domains=\"$domains\$dns_search_domain_${i} \" || break
|
|
| 222 |
+ done |
|
| 223 |
+ text="${text}search $domains\n"
|
|
| 224 |
+ } |
|
| 225 |
+ text="${text}### openvpn ${dev} end ###"
|
|
| 226 |
+ |
|
| 227 |
+ sed -i "1i${text}" "$conf"
|
|
| 228 |
+ else |
|
| 229 |
+ echo "unsetting DNS using resolv.conf file" |
|
| 230 |
+ sed -i "/### openvpn ${dev} begin ###/,/### openvpn ${dev} end ###/d" "$conf"
|
|
| 231 |
+ fi |
|
| 232 |
+ |
|
| 233 |
+ return 0 |
|
| 234 |
+} |
|
| 235 |
+ |
|
| 236 |
+do_resolved || do_resolvconf || do_resolv_conf_file || {
|
|
| 237 |
+ echo "setting DNS failed, no method succeeded" |
|
| 238 |
+ exit 1 |
|
| 239 |
+} |
| ... | ... |
@@ -8,9 +8,13 @@ the OpenVPN process. |
| 8 | 8 |
Script Order of Execution |
| 9 | 9 |
------------------------- |
| 10 | 10 |
|
| 11 |
+#. ``--dns-updown`` |
|
| 12 |
+ |
|
| 13 |
+ Executed after TCP/UDP socket bind and TUN/TAP open, before ``--up``. |
|
| 14 |
+ |
|
| 11 | 15 |
#. ``--up`` |
| 12 | 16 |
|
| 13 |
- Executed after TCP/UDP socket bind and TUN/TAP open. |
|
| 17 |
+ Executed after TCP/UDP socket bind and TUN/TAP open, after ``--dns-updown``. |
|
| 14 | 18 |
|
| 15 | 19 |
#. ``--tls-verify`` |
| 16 | 20 |
|
| ... | ... |
@@ -38,9 +42,13 @@ Script Order of Execution |
| 38 | 38 |
|
| 39 | 39 |
Executed in ``--mode server`` mode on client instance shutdown. |
| 40 | 40 |
|
| 41 |
+#. ``--dns-updown`` |
|
| 42 |
+ |
|
| 43 |
+ Executed before TCP/UDP and TUN/TAP close, before ``--down``. |
|
| 44 |
+ |
|
| 41 | 45 |
#. ``--down`` |
| 42 | 46 |
|
| 43 |
- Executed after TCP/UDP and TUN/TAP close. |
|
| 47 |
+ Executed after TCP/UDP and TUN/TAP close, after ``--dns-updown``. |
|
| 44 | 48 |
|
| 45 | 49 |
#. ``--learn-address`` |
| 46 | 50 |
|
| ... | ... |
@@ -171,7 +179,7 @@ SCRIPT HOOKS |
| 171 | 171 |
client-crresponse cmd |
| 172 | 172 |
|
| 173 | 173 |
OpenVPN will write the response of the client into a temporary file. |
| 174 |
- The filename will be passed as an argument to ``cmd``, and the file will be |
|
| 174 |
+ The filename will be passed as an argument to ``cmd``, and the file will |
|
| 175 | 175 |
automatically deleted by OpenVPN after the script returns. |
| 176 | 176 |
|
| 177 | 177 |
The response is passed as is from the client. The script needs to check |
| ... | ... |
@@ -233,6 +241,31 @@ SCRIPT HOOKS |
| 233 | 233 |
The ``--client-disconnect`` command is not passed any extra arguments |
| 234 | 234 |
(only those arguments specified in cmd, if any). |
| 235 | 235 |
|
| 236 |
+--dns-updown cmd |
|
| 237 |
+ Run command ``cmd``, instead of the default DNS up/down command that comes |
|
| 238 |
+ with openvpn. If ``cmd`` is ``disable`` the ``--dns-updown`` command is not run. |
|
| 239 |
+ |
|
| 240 |
+ If you write your own command, please make sure to ignore ``--dns`` |
|
| 241 |
+ server profiles that cannot be applied. Port, DNSSEC and secure transport |
|
| 242 |
+ settings need to be adhered to. If split DNS is not possible a full redirect |
|
| 243 |
+ can be used as a fallback. If not all of the server addresses or search domains |
|
| 244 |
+ can be configured, apply them in the order they are listed in. |
|
| 245 |
+ |
|
| 246 |
+ Note that ``--dns-updown`` is not supported on all platforms. On Windows DNS |
|
| 247 |
+ will always be set by the service. On Android DNS will be passed via management |
|
| 248 |
+ interface. |
|
| 249 |
+ |
|
| 250 |
+ Note that DNS-related ``--dhcp-option``\ s might be converted so that they are |
|
| 251 |
+ available to this hook if no ``--dns`` options exist. If any ``--dns server`` |
|
| 252 |
+ option is present, DNS-related ``--dhcp-option``\ s will always be ignored. |
|
| 253 |
+ If an ``--up`` script is defined, foreign_option env vars will be generated |
|
| 254 |
+ from ``--dns`` options and passed to the script. The default ``--dns-updown`` |
|
| 255 |
+ command is not run if an ``--up`` script is defined. Both is done for backward |
|
| 256 |
+ compatibility. In case you want to run the ``--dns-updown`` command even if |
|
| 257 |
+ there is an ``--up`` defined, you can define a custom command or use ``force`` |
|
| 258 |
+ as ``cmd`` to run the default command. No DNS env vars will be passed to ``--up`` |
|
| 259 |
+ in this case. |
|
| 260 |
+ |
|
| 236 | 261 |
--down cmd |
| 237 | 262 |
Run command ``cmd`` after TUN/TAP device close (post ``--user`` UID |
| 238 | 263 |
change and/or ``--chroot`` ). ``cmd`` consists of a path to script (or |
| ... | ... |
@@ -659,7 +692,7 @@ instances. |
| 659 | 659 |
names). Set prior to ``--up`` or ``--down`` script execution. |
| 660 | 660 |
|
| 661 | 661 |
:code:`dns_*` |
| 662 |
- The ``--dns`` configuration options will be made available to script |
|
| 662 |
+ The ``--dns`` configuration options will be made available to ``--dns-updown`` |
|
| 663 | 663 |
execution through this set of environment variables. Variables appear |
| 664 | 664 |
only if the corresponding option has a value assigned. For the semantics |
| 665 | 665 |
of each individual variable, please refer to the documentation for ``--dns``. |
| ... | ... |
@@ -30,7 +30,8 @@ AM_CFLAGS = \ |
| 30 | 30 |
$(OPTIONAL_LZ4_CFLAGS) \ |
| 31 | 31 |
$(OPTIONAL_PKCS11_HELPER_CFLAGS) \ |
| 32 | 32 |
$(OPTIONAL_INOTIFY_CFLAGS) \ |
| 33 |
- -DPLUGIN_LIBDIR=\"${plugindir}\"
|
|
| 33 |
+ -DPLUGIN_LIBDIR=\"${plugindir}\" \
|
|
| 34 |
+ -DDEFAULT_DNS_UPDOWN=\"${scriptdir}/dns-updown\"
|
|
| 34 | 35 |
|
| 35 | 36 |
if WIN32 |
| 36 | 37 |
# we want unicode entry point but not the macro |
| ... | ... |
@@ -30,6 +30,7 @@ |
| 30 | 30 |
#include "dns.h" |
| 31 | 31 |
#include "socket.h" |
| 32 | 32 |
#include "options.h" |
| 33 |
+#include "run_command.h" |
|
| 33 | 34 |
|
| 34 | 35 |
#ifdef _WIN32 |
| 35 | 36 |
#include "win32.h" |
| ... | ... |
@@ -262,6 +263,8 @@ clone_dns_options(const struct dns_options *o, struct gc_arena *gc) |
| 262 | 262 |
clone.search_domains = clone_dns_domains(o->search_domains, gc); |
| 263 | 263 |
clone.servers = clone_dns_servers(o->servers, gc); |
| 264 | 264 |
clone.servers_prepull = clone_dns_servers(o->servers_prepull, gc); |
| 265 |
+ clone.updown = o->updown; |
|
| 266 |
+ clone.user_set_updown = o->user_set_updown; |
|
| 265 | 267 |
|
| 266 | 268 |
return clone; |
| 267 | 269 |
} |
| ... | ... |
@@ -548,6 +551,54 @@ run_up_down_service(bool add, const struct options *o, const struct tuntap *tt) |
| 548 | 548 |
send_msg_iservice(o->msg_channel, &nrpt, sizeof(nrpt), &ack, "DNS"); |
| 549 | 549 |
} |
| 550 | 550 |
|
| 551 |
+#else /* ifdef _WIN32 */ |
|
| 552 |
+ |
|
| 553 |
+static void |
|
| 554 |
+updown_env_set(bool up, const struct dns_options *o, const struct tuntap *tt, struct env_set *es) |
|
| 555 |
+{
|
|
| 556 |
+ setenv_str(es, "dev", tt->actual_name); |
|
| 557 |
+ setenv_str(es, "script_type", up ? "dns-up" : "dns-down"); |
|
| 558 |
+ setenv_dns_options(o, es); |
|
| 559 |
+} |
|
| 560 |
+ |
|
| 561 |
+static int |
|
| 562 |
+do_run_up_down_command(bool up, const struct dns_options *o, const struct tuntap *tt) |
|
| 563 |
+{
|
|
| 564 |
+ struct gc_arena gc = gc_new(); |
|
| 565 |
+ struct argv argv = argv_new(); |
|
| 566 |
+ struct env_set *es = env_set_create(&gc); |
|
| 567 |
+ |
|
| 568 |
+ updown_env_set(up, o, tt, es); |
|
| 569 |
+ |
|
| 570 |
+ argv_printf(&argv, "%s", o->updown); |
|
| 571 |
+ argv_msg(M_INFO, &argv); |
|
| 572 |
+ int res; |
|
| 573 |
+ if (o->user_set_updown) |
|
| 574 |
+ {
|
|
| 575 |
+ res = openvpn_run_script(&argv, es, S_EXITCODE, "dns updown"); |
|
| 576 |
+ } |
|
| 577 |
+ else |
|
| 578 |
+ {
|
|
| 579 |
+ res = openvpn_execve_check(&argv, es, S_EXITCODE, "WARNING: Failed running dns updown"); |
|
| 580 |
+ } |
|
| 581 |
+ argv_free(&argv); |
|
| 582 |
+ gc_free(&gc); |
|
| 583 |
+ return res; |
|
| 584 |
+} |
|
| 585 |
+ |
|
| 586 |
+static void |
|
| 587 |
+run_up_down_command(bool up, struct options *o, const struct tuntap *tt) |
|
| 588 |
+{
|
|
| 589 |
+ if (!o->dns_options.updown) |
|
| 590 |
+ {
|
|
| 591 |
+ return; |
|
| 592 |
+ } |
|
| 593 |
+ |
|
| 594 |
+ int status; |
|
| 595 |
+ status = do_run_up_down_command(up, &o->dns_options, tt); |
|
| 596 |
+ msg(M_INFO, "dns %s command exited with status %d", up ? "up" : "down", status); |
|
| 597 |
+} |
|
| 598 |
+ |
|
| 551 | 599 |
#endif /* _WIN32 */ |
| 552 | 600 |
|
| 553 | 601 |
void |
| ... | ... |
@@ -666,5 +717,7 @@ run_dns_up_down(bool up, struct options *o, const struct tuntap *tt) |
| 666 | 666 |
|
| 667 | 667 |
#ifdef _WIN32 |
| 668 | 668 |
run_up_down_service(up, o, tt); |
| 669 |
+#else |
|
| 670 |
+ run_up_down_command(up, o, tt); |
|
| 669 | 671 |
#endif /* ifdef _WIN32 */ |
| 670 | 672 |
} |
| ... | ... |
@@ -526,10 +526,12 @@ static const char usage_message[] = |
| 526 | 526 |
" address <addr[:port]> [addr[:port] ...] : server addresses 4/6\n" |
| 527 | 527 |
" resolve-domains <domain> [domain ...] : split domains\n" |
| 528 | 528 |
" dnssec <yes|no|optional> : option to use DNSSEC\n" |
| 529 |
- " type <DoH|DoT> : query server over HTTPS / TLS\n" |
|
| 529 |
+ " transport <DoH|DoT> : query server over HTTPS / TLS\n" |
|
| 530 | 530 |
" sni <domain> : DNS server name indication\n" |
| 531 | 531 |
"--dns search-domains <domain> [domain ...]:\n" |
| 532 | 532 |
" Add domains to DNS domain search list\n" |
| 533 |
+ "--dns-updown cmd|force|disable : Run cmd as user defined dns config command,\n" |
|
| 534 |
+ " force running the default script or disable running it.\n" |
|
| 533 | 535 |
"--auth-retry t : How to handle auth failures. Set t to\n" |
| 534 | 536 |
" none (default), interact, or nointeract.\n" |
| 535 | 537 |
"--static-challenge t e [<scrv1|concat>]: Enable static challenge/response protocol using\n" |
| ... | ... |
@@ -918,6 +920,10 @@ init_options(struct options *o, const bool init_gc) |
| 918 | 918 |
#ifndef ENABLE_DCO |
| 919 | 919 |
o->disable_dco = true; |
| 920 | 920 |
#endif /* ENABLE_DCO */ |
| 921 |
+ |
|
| 922 |
+#ifdef ENABLE_DNS_UPDOWN_BY_DEFAULT |
|
| 923 |
+ o->dns_options.updown = DEFAULT_DNS_UPDOWN; |
|
| 924 |
+#endif /* ENABLE_DNS_UPDOWN_BY_DEFAULT */ |
|
| 921 | 925 |
} |
| 922 | 926 |
|
| 923 | 927 |
void |
| ... | ... |
@@ -8046,6 +8052,39 @@ add_option(struct options *options, |
| 8046 | 8046 |
to->ip_win32_defined = true; |
| 8047 | 8047 |
} |
| 8048 | 8048 |
#endif /* ifdef _WIN32 */ |
| 8049 |
+ else if (streq(p[0], "dns-updown") && p[1]) |
|
| 8050 |
+ {
|
|
| 8051 |
+ VERIFY_PERMISSION(OPT_P_SCRIPT); |
|
| 8052 |
+ if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) |
|
| 8053 |
+ {
|
|
| 8054 |
+ goto err; |
|
| 8055 |
+ } |
|
| 8056 |
+ struct dns_options *dns = &options->dns_options; |
|
| 8057 |
+ if (streq(p[1], "disable")) |
|
| 8058 |
+ {
|
|
| 8059 |
+ dns->updown = NULL; |
|
| 8060 |
+ dns->user_set_updown = false; |
|
| 8061 |
+ } |
|
| 8062 |
+ else if (streq(p[1], "force")) |
|
| 8063 |
+ {
|
|
| 8064 |
+ /* force dns-updown run, even if a --up script is defined */ |
|
| 8065 |
+ if (dns->user_set_updown == false) |
|
| 8066 |
+ {
|
|
| 8067 |
+ dns->updown = DEFAULT_DNS_UPDOWN; |
|
| 8068 |
+ dns->user_set_updown = true; |
|
| 8069 |
+ } |
|
| 8070 |
+ } |
|
| 8071 |
+ else |
|
| 8072 |
+ {
|
|
| 8073 |
+ if (streq(dns->updown, DEFAULT_DNS_UPDOWN)) |
|
| 8074 |
+ {
|
|
| 8075 |
+ /* Unset the default command to prevent warnings */ |
|
| 8076 |
+ dns->updown = NULL; |
|
| 8077 |
+ } |
|
| 8078 |
+ set_user_script(options, &dns->updown, p[1], p[0], false); |
|
| 8079 |
+ dns->user_set_updown = true; |
|
| 8080 |
+ } |
|
| 8081 |
+ } |
|
| 8049 | 8082 |
else if (streq(p[0], "dns") && p[1]) |
| 8050 | 8083 |
{
|
| 8051 | 8084 |
VERIFY_PERMISSION(OPT_P_DHCPDNS); |