Skip to content

Commit

Permalink
Merge pull request #118 from YunoHost-Apps/openvpn-hooks
Browse files Browse the repository at this point in the history
Add openvpn hooks feature
  • Loading branch information
hidrarga committed Jan 2, 2024
2 parents abbe0a1 + 8156263 commit 80c6b21
Show file tree
Hide file tree
Showing 16 changed files with 384 additions and 410 deletions.
40 changes: 40 additions & 0 deletions conf/scripts/route-down.d/10-vpnclient-unset-firewall
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash

is_firewall_set() {
ip6tables -w -nvL OUTPUT | grep vpnclient_out | grep -q "${wired_device}" \
&& iptables -w -nvL OUTPUT | grep vpnclient_out | grep -q "${wired_device}"
}

wired_device=$(ip route | awk '/default via/ { print $5; }')

if is_firewall_set; then
rm -f /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient

# IPv4

iptables -w -D INPUT -i "${wired_device}" -j vpnclient_in
iptables -w -D OUTPUT -o "${wired_device}" -j vpnclient_out
iptables -w -D FORWARD -o "${wired_device}" -j vpnclient_fwd

iptables -w -F vpnclient_in
iptables -w -F vpnclient_out
iptables -w -F vpnclient_fwd

iptables -w -X vpnclient_in
iptables -w -X vpnclient_out
iptables -w -X vpnclient_fwd

# IPv6

ip6tables -w -D INPUT -i "${wired_device}" -j vpnclient_in
ip6tables -w -D OUTPUT -o "${wired_device}" -j vpnclient_out
ip6tables -w -D FORWARD -o "${wired_device}" -j vpnclient_fwd

ip6tables -w -F vpnclient_in
ip6tables -w -F vpnclient_out
ip6tables -w -F vpnclient_fwd

ip6tables -w -X vpnclient_in
ip6tables -w -X vpnclient_out
ip6tables -w -X vpnclient_fwd
fi
28 changes: 28 additions & 0 deletions conf/scripts/route-down.d/20-vpnclient-unset-dns
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash

is_dns_set() {
if [[ "$ynh_dns_method" != "custom" ]]; then
return 0
fi

current_dns=$(grep -o -P '^\s*nameserver\s+\K[abcdefABCDEF\d.:]+$' /etc/resolv.dnsmasq.conf | sort | uniq)
wanted_dns=$(echo "${ynh_dns}" | sed 's/,/\n/g' | sort | uniq)
[[ -e /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient ]] \
&& [[ "$current_dns" == "$wanted_dns" ]]
}

if is_dns_set; then
resolvconf=/etc/resolv.dnsmasq.conf

rm -f /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient
if [[ -e "${resolvconf}.ynh" ]]; then
mv "${resolvconf}.ynh" "${resolvconf}"
fi

# FIXME : this situation happened to a user ...
# We could try to force regen the dns conf
# (though for now it's tightly coupled to dnsmasq)
if ! grep -q "^nameserver\s" "${resolvconf}"; then
echo "${resolvconf} does not have any nameserver line !?" >&2
fi
fi
36 changes: 36 additions & 0 deletions conf/scripts/route-down.d/30-vpnclient-unset-server-ipv6-route
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash

is_serverip6route_set() {
local server_ip6s=${1}

if [[ -z "${server_ip6s}" ]]; then
return 0
fi

for server_ip6 in ${server_ip6s}; do
if ! ip -6 route | grep -q "^${server_ip6}"; then
return 1
fi
done
}

unset_serverip6route() {
local server_ip6s=${1}
local ip6_gw=${2}
local wired_device=${3}

for server_ip6 in ${server_ip6s}; do
ip route delete "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
done
}

old_ip6_gw=$(yunohost app setting vpnclient ip6_gw)
old_wired_device=$(yunohost app setting vpnclient wired_device)
old_server_ip6=$(yunohost app setting vpnclient server_ip6)

# Check old state of the server ipv6 route
if [[ -n "${old_server_ip6}" && -n "${old_ip6_gw}" && -n "${old_wired_device}" ]]; then
if is_serverip6route_set "${old_server_ip6}"; then
unset_serverip6route "${old_server_ip6}" "${old_ip6_gw}" "${old_wired_device}"
fi
fi
File renamed without changes.
20 changes: 20 additions & 0 deletions conf/scripts/route-up.d/10-vpnclient-set-firewall
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

is_firewall_set() {
local wired_device=$(ip route | awk '/default via/ { print $5; }')

ip6tables -w -nvL OUTPUT | grep vpnclient_out | grep -q "${wired_device}" \
&& iptables -w -nvL OUTPUT | grep vpnclient_out | grep -q "${wired_device}"
}

if ! is_firewall_set; then
bash /etc/yunohost/apps/vpnclient/conf/hook_post-iptable-rules
cp /etc/yunohost/apps/vpnclient/conf/hook_post-iptable-rules /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
fi

if is_firewall_set; then
echo "[ OK ] IPv6/IPv4 firewall set"
else
echo "[FAIL] No IPv6/IPv4 firewall set" >&2
exit 1
fi
35 changes: 35 additions & 0 deletions conf/scripts/route-up.d/20-vpnclient-set-dns
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash

is_dns_set() {
if [[ "$ynh_dns_method" != "custom" ]]; then
return 0
fi

current_dns=$(grep -o -P '^\s*nameserver\s+\K[a-fA-F\d.:]+$' /etc/resolv.dnsmasq.conf | sort | uniq)
wanted_dns=$(echo "${ynh_dns}" | sed 's/,/\n/g' | sort | uniq)
[[ -e /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient ]] \
&& [[ "$current_dns" == "$wanted_dns" ]]
}

ynh_dns_method=$(yunohost app setting vpnclient dns_method)
ynh_dns=$(yunohost app setting vpnclient nameservers)

# Set host DNS resolvers
if ! is_dns_set; then
resolvconf=/etc/resolv.dnsmasq.conf

cp -fa "${resolvconf}" "${resolvconf}.ynh"
if [[ "$ynh_dns_method" == "custom" ]]; then
cat << EOF > /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient
echo "${ynh_dns}" | sed 's/,/\n/g' | sort | uniq | sed 's/^/nameserver /g' > ${resolvconf}
EOF
bash /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient
fi
fi

if is_dns_set; then
echo "[ OK ] Host DNS correctly set"
else
echo "[FAIL] No host DNS set" >&2
exit 1
fi
90 changes: 90 additions & 0 deletions conf/scripts/route-up.d/30-vpnclient-set-server-ipv6-route
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/bin/bash

has_nativeip6() {
ip -6 route | grep -q "default via"
}

is_serverip6route_set() {
local server_ip6s=${1}

if [[ -z "${server_ip6s}" ]]; then
return 0
fi

for server_ip6 in ${server_ip6s}; do
if ! ip -6 route | grep -q "^${server_ip6}"; then
return 1
fi
done
}

set_serverip6route() {
local server_ip6s=${1}
local ip6_gw=${2}
local wired_device=${3}

for server_ip6 in ${server_ip6s}; do
ip route add "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
done
}

unset_serverip6route() {
local server_ip6s=${1}
local ip6_gw=${2}
local wired_device=${3}

for server_ip6 in ${server_ip6s}; do
ip route delete "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
done
}

old_ip6_gw=$(yunohost app setting vpnclient ip6_gw)
old_wired_device=$(yunohost app setting vpnclient wired_device)
old_server_ip6=$(yunohost app setting vpnclient server_ip6)

new_ip6_gw=$(ip -6 route | awk '/default via/ { print $3 }')
new_wired_device=$(ip route | awk '/default via/ { print $5; }')
ynh_server_names=$(grep -o -P '^\s*remote\s+\K([^\s]+)' /etc/openvpn/client.conf | sort | uniq)
new_server_ip6=$(dig AAAA +short $ynh_server_names @127.0.0.1 | grep -v '\.$' | grep -v "timed out" | sort | uniq)

for i in $ynh_server_names; do
if [[ "${i}" =~ : ]] && [[ ! "$new_server_ip6" == *"${i}"* ]] ; then
new_server_ip6+=" ${i}"
fi
done

echo "[INFO] Autodetected internet interface: ${new_wired_device} (last start: ${old_wired_device})"
echo "[INFO] Autodetected IPv6 address for the VPN server: ${new_server_ip6} (last start: ${old_server_ip6})"

# Check old state of the server ipv6 route
if [[ -n "${old_server_ip6}" && -n "${old_ip6_gw}" && -n "${old_wired_device}" ]]; then
if [[ "${new_server_ip6}" != "${old_server_ip6}" || "${new_ip6_gw}" != "${old_ip6_gw}" || "${new_wired_device}" != "${old_wired_device}" ]]; then
if is_serverip6route_set "${old_server_ip6}"; then
unset_serverip6route "${old_server_ip6}" "${old_ip6_gw}" "${old_wired_device}"
fi
fi
fi

# Set the new server ipv6 route
if has_nativeip6; then
if ! is_serverip6route_set "${new_server_ip6}"; then
set_serverip6route "${new_server_ip6}" "${new_ip6_gw}" "${new_wired_device}"
fi

echo "[INFO] Native IPv6 detected"
echo "[INFO] Autodetected native IPv6 gateway: ${new_ip6_gw} (last start: ${old_ip6_gw})"

if is_serverip6route_set "${new_server_ip6}"; then
echo "[ OK ] IPv6 server route correctly set"
else
echo "[FAIL] No IPv6 server route set" >&2
exit 1
fi
else
echo "[INFO] No native IPv6 detected"
echo "[INFO] No IPv6 server route to set"
fi

yunohost app setting vpnclient server_ip6 --value "${new_server_ip6}"
yunohost app setting vpnclient ip6_gw --value "${new_ip6_gw}"
yunohost app setting vpnclient wired_device --value "${new_wired_device}"
11 changes: 0 additions & 11 deletions conf/scripts/route-up.d/40-set-ipv6

This file was deleted.

25 changes: 25 additions & 0 deletions conf/scripts/route-up.d/40-vpnclient-set-ipv6
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

is_ip6addr_set() {
local ip6_addr=${1}
ip address show dev tun0 2> /dev/null | grep -q "${ip6_addr}/"
}

ip6_addr=$(yunohost app setting "vpnclient" "ip6_addr")
if [[ -n "${ip6_addr}" ]] && [[ "${ip6_addr}" != none ]]; then
if ! is_ip6addr_set "${ip6_addr}"; then
ip address add "${ip6_addr}/64" dev tun0
fi

echo "[INFO] IPv6 delegated prefix found"
echo "[INFO] IPv6 address computed from the delegated prefix: ${ip6_addr}"

if is_ip6addr_set "${ip6_addr}"; then
echo "[ OK ] IPv6 address correctly set"
else
echo "[FAIL] No IPv6 address set" >&2
exit 1
fi
else
echo "[INFO] No IPv6 delegated prefix found"
fi

0 comments on commit 80c6b21

Please sign in to comment.