Skip to content

Instantly share code, notes, and snippets.

@dbouras
Last active April 12, 2024 15:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbouras/d390bc3511280aaf717fbb976e20447e to your computer and use it in GitHub Desktop.
Save dbouras/d390bc3511280aaf717fbb976e20447e to your computer and use it in GitHub Desktop.
Add support to AWS VPN for distributions (such as OpenSUSE) that use NetworkManager/netconfig for configuring DNS resolution

After installing AWS VPN client from: client-vpn-connect-linux-install, replace:

   /opt/awsvpnclient/Service/Resources/openvpn/configure-dns

with the modified configure-dns script below. If you would like to to review the modifications, see file configure-dns.patch.

If you are running OpenSUSE Leap or Tumbleweed, you will need to have dpkg installed; after you install awsvpnclient_amd64.deb using dpkg -i, you will also need to edit:

   /usr/share/applications/awsvpnclient.desktop

and replace:

   Exec=/opt/awsvpnclient/AWS\ VPN\ Client %u

with:

   Exec=/opt/awsvpnclient/AWS\\ VPN\\ Client %u

for the desktop entry to work properly.

#!/usr/bin/env bash
#
# Modified to support distributions that rely either on systemd-resolve
# (such as Ubuntu 18.04 or 20.04) or on NetworkManager/netconfig (such
# as OpenSUSE Leap/Tumbleweed) for DNS resolver setup
configure_logging() {
log_folder="/var/log/aws-vpn-client"
mkdir -p $log_folder
# $script_type is set by OpenVPN
if [[ $script_type == *up* ]]; then
log_file=$log_folder/configure-dns-up.log
elif [[ $script_type == *down* ]]; then
log_file=$log_folder/configure-dns-down.log
fi
if [[ -f "$log_file" ]]; then
rm -f "$log_file"
fi
}
log() {
echo "$(date) $1" >> "$log_file"
}
# Get distribution via lsb-release in order to support more
# than just Ubuntu 18.04 LTS (bionic) and 20.04 LTS (focal)
get_distribution() {
# if available, use LSB release utility
LSBREL=$(type -p lsb-release)
test -n "${LSBREL}" && dist=$("${LSBREL}" -s -i) || dist=""
}
check_systemd_resolve_status() {
output=$(systemd-resolve --status 2>&1)
exit_code=$?
log "'systemd-resolve --status' exit code: $exit_code output:"
log "$output"
}
call_systemd_resolved() {
log "Calling busctl with parameters '$*'"
output=$(busctl call "org.freedesktop.resolve1" "/org/freedesktop/resolve1" "org.freedesktop.resolve1.Manager" "$@" 2>&1)
exit_code=$?
log "busctl command exit code: $exit_code, output: $output"
if [[ $exit_code -ne 0 ]]; then
exit $exit_code
fi
}
# Remove DNS name servers from the resolver config
# file and add the ones passed on the argument list
edit_resolv_conf_servers() {
cp ${rslvcnf} ${rslvcnf}.ovpnsave
grep -v -e nameserver ${rslvcnf}.ovpnsave > ${rslvcnf}
for dsrv in "$@"; do
log "Adding DNS server: ${dsrv}"
echo "nameserver ${dsrv}" >> ${rslvcnf}
done
rm -f ${rslvcnf}.ovpnsave
}
# Remove DNS domain search list from the resolver
# config file and add new one from the argument list
edit_resolv_conf_search() {
cp ${rslvcnf} ${rslvcnf}.ovpnsave
grep -v -e search ${rslvcnf}.ovpnsave > ${rslvcnf}
log "Adding domain search list: ${*}"
echo "search ${@}" >> ${rslvcnf}
rm -f ${rslvcnf}.ovpnsave
}
# Refresh the Name Service Cache by restarting the nscd daemon
refresh_nscd() {
log "Refreshing the name service cache"
output=$(systemctl restart nscd 2>&1)
exit_code=$?
log "systemctl restart nscd exit code: $exit_code, output: $output"
}
# $foreign_option_<n> is set by OpenVPN.
# Currently we support DNS and DOMAIN types.
# Search domains are used in the order they appear in the OpenVPN config
# Example:
# "dhcp-option DNS 172.168.0.1"
# "dhcp-option DOMAIN amazon.com"
# "dhcp-option DOMAIN amazonaws.com"
# Domains will be set in the order 1) amazon.com, 2) amazonaws.com
# Client VPN service doesn't support IPv6.
get_dns_from_server() {
log "Getting DNS servers from OpenVPN"
for fopt in "${!foreign_option_@}"; do
fopt_val="${!fopt}"
log "$fopt from OpenVPN: $fopt_val"
if [[ "${fopt_val}" == *dhcp-option\ DNS* ]]; then
dns_server_count=$((dns_server_count + 1))
# dhcp-option DNS 172.168.0.1 -> 172.168.0.1
dns_server_ip="${fopt_val#dhcp-option DNS }"
#
# Append: 2 4 172 168 0 1 for the systemd-resolve case
# or simply the DNS server IP address for netconfig
#
test "${namesrv}" = "netconfig" && \
dns_servers+=(${dns_server_ip}) || \
dns_servers+=(2 4 ${dns_server_ip//./ })
elif [[ "${fopt_val}" == *dhcp-option\ DOMAIN\ * ]]; then
dns_domain_count=$((dns_domain_count + 1))
# dhcp-option DOMAIN example.com -> example.com
dns_domain="${fopt_val#dhcp-option DOMAIN }"
#
# For the netconfig case simply add the domain to the list
#
# For the systemd-resolve case [1]:
# "It takes a network interface index and an array of domains, each with
# a boolean parameter indicating whether the specified domain shall be
# used as a search domain (false), or just as a routing domain (true)"
# [1] https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html
#
test "${namesrv}" = "netconfig" && \
dns_domains+=(${dns_domain}) || \
dns_domains+=("${dns_domain}" false)
elif [[ "${fopt_val}" == *dhcp-option\ DOMAIN-ROUTE* ]]; then
dns_domain_count=$((dns_domain_count + 1))
# dhcp-option DOMAIN-ROUTE . -> .
dns_domain="${fopt_val#dhcp-option DOMAIN-ROUTE }"
#
# Domain route '~.' needs to be added to prevent DNS leakage
# https://github.com/systemd/systemd/issues/6076#issuecomment-387332572
#
test "${namesrv}" = "netconfig" && \
dns_domains+=(${dns_domain}) || \
dns_domains+=("${dns_domain}" true)
fi
done
}
# $dev is set by OpenVPN
# "The actual name of the TUN/TAP device, including a unit number if it exists."
get_device_index() {
log "Getting device index for $dev"
device_info="$(ip link show dev "$dev")"
exit_code=$?
log "'ip link show dev "$dev"' exit code: $exit_code, output: $device_info"
if [[ $exit_code -ne 0 ]]; then
exit $exit_code
fi
device_index="${device_info%%:*}"
log "Device index for $dev: $device_index"
}
configure_dns() {
local -a dns_servers=() dns_domains=()
local -i dns_server_count=0 dns_domain_count=0
local device_index
log "Configuring to use DNS servers from OpenVPN"
get_dns_from_server
if [[ $dns_server_count -eq 0 && $dns_domain_count -eq 0 ]]; then
log "No DNS configured for the endpoint"
return 0
fi
# The device index is not needed for the netconfig case
test "${namesrv}" != "netconfig" && get_device_index
if [[ $dns_server_count -gt 0 ]]; then
case "${namesrv}" in
"netconfig")
log "Updating ${rslvcnf} DNS servers with: '${dns_servers[*]}'"
edit_resolv_conf_servers "${dns_servers[@]}"
;;
"systemd-resolve")
params=("$device_index" "$dns_server_count" "${dns_servers[@]}")
log "Calling SetLinkDNS with parameters: '${params[*]}'"
# Example: SetLinkDNS 'ia(iay)' 125 2 2 4 172 31 29 109 2 4 172 31 4 164
call_systemd_resolved SetLinkDNS 'ia(iay)' "${params[@]}"
;;
*)
;;
esac
fi
if [[ $dns_domain_count -gt 0 ]]; then
case "${namesrv}" in
"netconfig")
log "Updating ${rslvcnf} domain search list with: '${dns_domains[*]}'"
edit_resolv_conf_search "${dns_domains[@]}"
;;
"systemd-resolve")
params=("$device_index" "$dns_domain_count" "${dns_domains[@]}")
log "Calling SetLinkDomains with parameters: '${params[*]}'"
# Example: SetLinkDomains 'ia(sb)' amazon.com false example.com false
call_systemd_resolved SetLinkDomains 'ia(sb)' "${params[@]}"
;;
*)
;;
esac
fi
test "${namesrv}" = "netconfig" && refresh_nscd || check_systemd_resolve_status
}
reset_dns() {
log "Restoring DNS setting to the state before VPN connection"
case "${namesrv}" in
"netconfig")
${netconf} update -f
;;
"systemd-resolve")
local device_index
get_device_index
call_systemd_resolved RevertLink i "$device_index"
check_systemd_resolve_status
;;
*)
;;
esac
}
# Script args example: tun0 1500 1552 10.0.1.2 255.255.255.224 init
main() {
local dist
declare namesrv
declare rslvcnf
declare netconf
configure_logging
get_distribution
case "${dist}" in
"openSUSE")
namesrv="netconfig"
rslvcnf="/etc/resolv.conf"
netconf="/sbin/netconfig"
;;
"Ubuntu")
namesrv="systemd-resolve"
;;
*)
log "Unsupported distribution: ${dist}"
exit 1
;;
esac
# $script_type is set by OpenVPN
log "Executing $script_type script with parameters '$*' under $dist"
if [[ $script_type == *up* ]]; then
configure_dns
elif [[ $script_type == *down* ]]; then
reset_dns
fi
}
main "$@"
--- configure-dns.orig 2023-02-13 11:40:47.000000000 -0800
+++ configure-dns 2023-04-14 22:08:29.517441148 -0700
@@ -1,4 +1,8 @@
#!/usr/bin/env bash
+#
+# Modified to support distributions that rely either on systemd-resolve
+# (such as Ubuntu 18.04 or 20.04) or on NetworkManager/netconfig (such
+# as OpenSUSE Leap/Tumbleweed) for DNS resolver setup
configure_logging() {
log_folder="/var/log/aws-vpn-client"
@@ -20,6 +24,14 @@
echo "$(date) $1" >> "$log_file"
}
+# Get distribution via lsb-release in order to support more
+# than just Ubuntu 18.04 LTS (bionic) and 20.04 LTS (focal)
+get_distribution() {
+ # if available, use LSB release utility
+ LSBREL=$(type -p lsb-release)
+ test -n "${LSBREL}" && dist=$("${LSBREL}" -s -i) || dist=""
+}
+
check_systemd_resolve_status() {
output=$(systemd-resolve --status 2>&1)
exit_code=$?
@@ -38,6 +50,36 @@
fi
}
+# Remove DNS name servers from the resolver config
+# file and add the ones passed on the argument list
+edit_resolv_conf_servers() {
+ cp ${rslvcnf} ${rslvcnf}.ovpnsave
+ grep -v -e nameserver ${rslvcnf}.ovpnsave > ${rslvcnf}
+ for dsrv in "$@"; do
+ log "Adding DNS server: ${dsrv}"
+ echo "nameserver ${dsrv}" >> ${rslvcnf}
+ done
+ rm -f ${rslvcnf}.ovpnsave
+}
+
+# Remove DNS domain search list from the resolver
+# config file and add new one from the argument list
+edit_resolv_conf_search() {
+ cp ${rslvcnf} ${rslvcnf}.ovpnsave
+ grep -v -e search ${rslvcnf}.ovpnsave > ${rslvcnf}
+ log "Adding domain search list: ${*}"
+ echo "search ${@}" >> ${rslvcnf}
+ rm -f ${rslvcnf}.ovpnsave
+}
+
+# Refresh the Name Service Cache by restarting the nscd daemon
+refresh_nscd() {
+ log "Refreshing the name service cache"
+ output=$(systemctl restart nscd 2>&1)
+ exit_code=$?
+ log "systemctl restart nscd exit code: $exit_code, output: $output"
+}
+
# $foreign_option_<n> is set by OpenVPN.
# Currently we support DNS and DOMAIN types.
# Search domains are used in the order they appear in the OpenVPN config
@@ -57,23 +99,40 @@
dns_server_count=$((dns_server_count + 1))
# dhcp-option DNS 172.168.0.1 -> 172.168.0.1
dns_server_ip="${fopt_val#dhcp-option DNS }"
- # Append: 2 4 172 168 0 1
- dns_servers+=(2 4 ${dns_server_ip//./ })
+ #
+ # Append: 2 4 172 168 0 1 for the systemd-resolve case
+ # or simply the DNS server IP address for netconfig
+ #
+ test "${namesrv}" = "netconfig" && \
+ dns_servers+=(${dns_server_ip}) || \
+ dns_servers+=(2 4 ${dns_server_ip//./ })
elif [[ "${fopt_val}" == *dhcp-option\ DOMAIN\ * ]]; then
dns_domain_count=$((dns_domain_count + 1))
# dhcp-option DOMAIN example.com -> example.com
dns_domain="${fopt_val#dhcp-option DOMAIN }"
- # https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html
- # "It takes a network interface index and an array of domains, each with a boolean parameter indicating
- # whether the specified domain shall be used as a search domain (false), or just as a routing domain (true)"
- dns_domains+=("${dns_domain}" false)
+ #
+ # For the netconfig case simply add the domain to the list
+ #
+ # For the systemd-resolve case [1]:
+ # "It takes a network interface index and an array of domains, each with
+ # a boolean parameter indicating whether the specified domain shall be
+ # used as a search domain (false), or just as a routing domain (true)"
+ # [1] https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html
+ #
+ test "${namesrv}" = "netconfig" && \
+ dns_domains+=(${dns_domain}) || \
+ dns_domains+=("${dns_domain}" false)
elif [[ "${fopt_val}" == *dhcp-option\ DOMAIN-ROUTE* ]]; then
dns_domain_count=$((dns_domain_count + 1))
# dhcp-option DOMAIN-ROUTE . -> .
dns_domain="${fopt_val#dhcp-option DOMAIN-ROUTE }"
+ #
# Domain route '~.' needs to be added to prevent DNS leakage
# https://github.com/systemd/systemd/issues/6076#issuecomment-387332572
- dns_domains+=("${dns_domain}" true)
+ #
+ test "${namesrv}" = "netconfig" && \
+ dns_domains+=(${dns_domain}) || \
+ dns_domains+=("${dns_domain}" true)
fi
done
}
@@ -107,36 +166,88 @@
return 0
fi
- get_device_index
+ # The device index is not needed for the netconfig case
+ test "${namesrv}" != "netconfig" && get_device_index
+
if [[ $dns_server_count -gt 0 ]]; then
- params=("$device_index" "$dns_server_count" "${dns_servers[@]}")
- log "Calling SetLinkDNS with parameters: '${params[*]}'"
- # Example: SetLinkDNS 'ia(iay)' 125 2 2 4 172 31 29 109 2 4 172 31 4 164
- call_systemd_resolved SetLinkDNS 'ia(iay)' "${params[@]}"
+ case "${namesrv}" in
+ "netconfig")
+ log "Updating ${rslvcnf} DNS servers with: '${dns_servers[*]}'"
+ edit_resolv_conf_servers "${dns_servers[@]}"
+ ;;
+ "systemd-resolve")
+ params=("$device_index" "$dns_server_count" "${dns_servers[@]}")
+ log "Calling SetLinkDNS with parameters: '${params[*]}'"
+ # Example: SetLinkDNS 'ia(iay)' 125 2 2 4 172 31 29 109 2 4 172 31 4 164
+ call_systemd_resolved SetLinkDNS 'ia(iay)' "${params[@]}"
+ ;;
+ *)
+ ;;
+ esac
fi
if [[ $dns_domain_count -gt 0 ]]; then
- params=("$device_index" "$dns_domain_count" "${dns_domains[@]}")
- log "Calling SetLinkDomains with parameters: '${params[*]}'"
- # Example: SetLinkDomains 'ia(sb)' amazon.com false example.com false
- call_systemd_resolved SetLinkDomains 'ia(sb)' "${params[@]}"
+ case "${namesrv}" in
+ "netconfig")
+ log "Updating ${rslvcnf} domain search list with: '${dns_domains[*]}'"
+ edit_resolv_conf_search "${dns_domains[@]}"
+ ;;
+ "systemd-resolve")
+ params=("$device_index" "$dns_domain_count" "${dns_domains[@]}")
+ log "Calling SetLinkDomains with parameters: '${params[*]}'"
+ # Example: SetLinkDomains 'ia(sb)' amazon.com false example.com false
+ call_systemd_resolved SetLinkDomains 'ia(sb)' "${params[@]}"
+ ;;
+ *)
+ ;;
+ esac
fi
- check_systemd_resolve_status
+ test "${namesrv}" = "netconfig" && refresh_nscd || check_systemd_resolve_status
}
reset_dns() {
log "Restoring DNS setting to the state before VPN connection"
- local device_index
- get_device_index
- call_systemd_resolved RevertLink i "$device_index"
- check_systemd_resolve_status
+ case "${namesrv}" in
+ "netconfig")
+ ${netconf} update -f
+ ;;
+ "systemd-resolve")
+ local device_index
+ get_device_index
+ call_systemd_resolved RevertLink i "$device_index"
+ check_systemd_resolve_status
+ ;;
+ *)
+ ;;
+ esac
}
# Script args example: tun0 1500 1552 10.0.1.2 255.255.255.224 init
main() {
+ local dist
+ declare namesrv
+ declare rslvcnf
+ declare netconf
+
configure_logging
-
+ get_distribution
+
+ case "${dist}" in
+ "openSUSE")
+ namesrv="netconfig"
+ rslvcnf="/etc/resolv.conf"
+ netconf="/sbin/netconfig"
+ ;;
+ "Ubuntu")
+ namesrv="systemd-resolve"
+ ;;
+ *)
+ log "Unsupported distribution: ${dist}"
+ exit 1
+ ;;
+ esac
+
# $script_type is set by OpenVPN
- log "Executing $script_type script with parameters '$*'"
+ log "Executing $script_type script with parameters '$*' under $dist"
if [[ $script_type == *up* ]]; then
configure_dns
@@ -146,3 +257,4 @@
}
main "$@"
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment