Files
packages/net/openvpn/files/usr/libexec/openvpn-hotplug
T
Chen Minqiang bb02e8b734 openvpn: handler: refine netifd routing and config
Introduce a new `ipv6` proto option for OpenVPN netifd integration and
export it to the hotplug environment. IPv6 remains enabled by default,
but can now be explicitly disabled per instance.

Update the hotplug helper to apply IPv6 addresses and routes only when
IPv6 is enabled, allowing cleaner IPv4-only tunnel deployments.

Also improve route handling by:
- ignoring invalid default gateway values (0.0.0.0 / ::)
- replacing fixed `seq` loops with shell-safe while loops
- keeping trusted peer host routes conditional on valid gateways

Signed-off-by: Chen Minqiang <ptpt52@gmail.com>
2026-04-17 08:48:33 +02:00

132 lines
2.8 KiB
Bash

#!/bin/sh
[ -z "$script_type" ] && {
logger -t "openvpn(proto)" -p daemon.warn "hotplug: variable 'script_type' not found"
exit
}
[ -z "$INTERFACE" ] && {
logger -t "openvpn(proto)" -p daemon.warn "hotplug: variable 'INTERFACE' not found"
exit
}
. /lib/functions.sh
. /lib/netifd/netifd-proto.sh
mask2prefix() {
local mask="$1"
local n=0
local IFS=.
for o in $mask; do
case $o in
255) n=$((n+8)) ;;
254) n=$((n+7)) ;;
252) n=$((n+6)) ;;
248) n=$((n+5)) ;;
240) n=$((n+4)) ;;
224) n=$((n+3)) ;;
192) n=$((n+2)) ;;
128) n=$((n+1)) ;;
0) break ;;
*) break ;;
esac
done
echo "$n"
}
parse_cidr6() {
local val="$1"
local def_plen="$2"
local addr="${val%/*}"
local plen="${val#*/}"
[ "$addr" = "$plen" ] && plen="$def_plen"
echo "$addr $plen"
}
case "$script_type" in
up)
proto_init_update "$dev" 1
[ -n "$ifconfig_local" ] && proto_add_ipv4_address "$ifconfig_local" "${ifconfig_netmask:-255.255.255.255}"
[ -n "$trusted_ip" ] && {
if [ -n "$route_net_gateway" -a "$route_net_gateway" != "0.0.0.0" ]; then
proto_add_ipv4_route "$trusted_ip" 32 "$route_net_gateway"
fi
}
[ -n "$route_vpn_gateway" ] && proto_add_ipv4_route "0.0.0.0" 0 "$route_vpn_gateway"
i=0
while :; do
i=$((i+1))
eval "net=\$route_network_$i mask=\$route_netmask_$i gw=\$route_gateway_$i"
[ -z "$net" ] && break
[ -z "$mask" ] && continue
plen=$(mask2prefix "$mask")
proto_add_ipv4_route "$net" "$plen" "$gw"
done
if [ "$IPV6" = "1" ]; then
if [ -n "$ifconfig_ipv6_local" ]; then
read -r v6addr v6plen <<-EOF
$(parse_cidr6 "$ifconfig_ipv6_local" "${ifconfig_ipv6_netbits:-128}")
EOF
proto_add_ipv6_address "$v6addr" "$v6plen"
fi
[ -n "$trusted_ip6" ] && {
if [ -n "$route_ipv6_gateway" -a "$route_ipv6_gateway" != "::" ]; then
proto_add_ipv6_route "$trusted_ip6" 128 "$route_ipv6_gateway"
fi
}
[ -n "$ifconfig_ipv6_remote" ] && proto_add_ipv6_route "::" 0 "$ifconfig_ipv6_remote"
i=0
while :; do
i=$((i+1))
eval "net=\$route_ipv6_network_$i gw=\$route_ipv6_gateway_$i"
[ -z "$net" ] && break
read -r v6net v6plen <<-EOF
$(parse_cidr6 "$net" 128)
EOF
proto_add_ipv6_route "$v6net" "$v6plen" "$gw"
done
fi
[ -n "$tun_mtu" ] && json_add_int mtu "$tun_mtu"
i=0
while :; do
i=$((i+1))
eval "option=\$foreign_option_$i"
[ -z "$option" ] && break
set -- $option
[ "$1" != "dhcp-option" ] && continue
case "$2" in
DNS) proto_add_dns_server "$3" ;;
DOMAIN*) proto_add_dns_search "$3" ;; # Matches DOMAIN and DOMAIN-SEARCH
esac
done
proto_send_update "$INTERFACE"
;;
down)
proto_init_update "$dev" 0
proto_send_update "$INTERFACE"
;;
esac
ACTION="$script_type"
INSTANCE="$INTERFACE"
export ACTION="$ACTION"
export INSTANCE="$INSTANCE"
exec /sbin/hotplug-call openvpn "$@"