Skip to content

Instantly share code, notes, and snippets.

@numpde
Created October 8, 2024 06:56
Show Gist options
  • Save numpde/bb9756d50eb7ccd39ed0acd400b33f0d to your computer and use it in GitHub Desktop.
Save numpde/bb9756d50eb7ccd39ed0acd400b33f0d to your computer and use it in GitHub Desktop.
/etc/openvpn/update-systemd-resolved
#!/bin/bash
#
# This script configures DNS settings for OpenVPN using systemd-resolved
# It uses D-Bus via busctl to communicate with systemd-resolved
# Ensure that systemd-resolved is running before using this script.
# Place this script at: /etc/openvpn/update-systemd-resolved
#
# Example OpenVPN config usage:
# up /etc/openvpn/update-systemd-resolved
# down /etc/openvpn/update-systemd-resolved
#
# Exit if any command fails
set -e
# Validate environment variables
if [ -z "$script_type" ] || [ -z "$dev" ]; then
logger "[OpenVPN] Missing script_type or dev environment variables"
exit 1
fi
# Split DHCP option string into components
split_into_parts() {
part1="$1"
part2="$2"
part3="$3"
}
# Configure DNS and search domains in systemd-resolved
configure_systemd_resolved() {
# Check if systemd-resolved is running
if ! busctl --no-pager list | grep -q 'org.freedesktop.resolve1'; then
logger "[OpenVPN] systemd-resolved is not running"
exit 1
fi
local DNS_SERVERS=()
local SEARCH_DOMAINS=()
# Parse foreign_option_* variables
foreign_options=$(printf '%s\n' ${!foreign_option_*} | sort -t _ -k 3 -g)
for optionvarname in ${foreign_options}; do
option="${!optionvarname}"
split_into_parts $option
if [ "$part1" = "dhcp-option" ]; then
if [ "$part2" = "DNS" ]; then
DNS_SERVERS+=("$part3")
elif [ "$part2" = "DOMAIN" ]; then
SEARCH_DOMAINS+=("$part3")
fi
fi
done
# Set DNS servers
if [ ${#DNS_SERVERS[@]} -gt 0 ]; then
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDNS \
"ia(iay)" "$dev" "${#DNS_SERVERS[@]}" $(for dns in "${DNS_SERVERS[@]}"; do echo "(iay) 2 1 $dns 0"; done)
fi
# Set search domains
if [ ${#SEARCH_DOMAINS[@]} -gt 0 ]; then
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDomains \
"ia(sb)" "$dev" "${#SEARCH_DOMAINS[@]}" $(for domain in "${SEARCH_DOMAINS[@]}"; do echo "(sb) $domain 0"; done)
fi
}
# Clear DNS and search domain settings in systemd-resolved
clear_systemd_resolved() {
# Revert DNS settings for the network device
if busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager RevertLink "i" "$dev"; then
logger "[OpenVPN] Cleared DNS settings for $dev"
else
logger "[OpenVPN] Failed to clear DNS settings for $dev"
fi
}
# Execute the appropriate action based on script type (up or down)
case "$script_type" in
up)
configure_systemd_resolved
;;
down)
clear_systemd_resolved
;;
*)
logger "[OpenVPN] Unknown script_type: $script_type"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment