diff --git a/qbittorrent/CHANGELOG.md b/qbittorrent/CHANGELOG.md index 06b4e3148b..a1786f904d 100644 --- a/qbittorrent/CHANGELOG.md +++ b/qbittorrent/CHANGELOG.md @@ -1,3 +1,6 @@ +## 5.2.0-18 (13-05-2026) +- Simplify VPN endpoint route pinning to minimal helpers (single endpoint, no tracking list). + ## 5.2.0-17 (13-05-2026) - Fix VPN endpoint routing by pinning OpenVPN/WireGuard server IPs to the pre-VPN main route, preventing recursive tunnel routing drops. diff --git a/qbittorrent/config.yaml b/qbittorrent/config.yaml index 60550d0af3..06958d0bef 100644 --- a/qbittorrent/config.yaml +++ b/qbittorrent/config.yaml @@ -143,4 +143,4 @@ schema: slug: qbittorrent udev: true url: https://github.com/alexbelgium/hassio-addons -version: "5.2.0-17" +version: "5.2.0-18" diff --git a/qbittorrent/rootfs/usr/local/sbin/vpn b/qbittorrent/rootfs/usr/local/sbin/vpn index e64b542e2f..636a4f3ff0 100755 --- a/qbittorrent/rootfs/usr/local/sbin/vpn +++ b/qbittorrent/rootfs/usr/local/sbin/vpn @@ -150,98 +150,25 @@ _resolve_hostname() { } _endpoint_route_add() { - local endpoint_ip="$1" - local route_line="" - local route_via="" - local route_dev="" - local route_prefix="" - local route_family="" - local -a route_cmd=() - local result=0 - - _check_host "${endpoint_ip}" || result=$? - if [ "${result}" -eq 1 ]; then - route_family="-4" - route_prefix="${endpoint_ip}/32" - route_line="$(ip -4 route get "${endpoint_ip}" table main 2>/dev/null | head -n1)" - elif [ "${result}" -eq 2 ]; then - route_family="-6" - route_prefix="${endpoint_ip}/128" - route_line="$(ip -6 route get "${endpoint_ip}" table main 2>/dev/null | head -n1)" + local ip="$1" + local rt via dev + rt="$(ip route get "${ip}" 2>/dev/null | head -n1)" + via="$(awk '{for(i=1;i<=NF;i++) if($i=="via"){print $(i+1);exit}}' <<< "${rt}")" + dev="$(awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1);exit}}' <<< "${rt}")" + [ -z "${dev}" ] && { bashio::log.error "No route to VPN endpoint ${ip}."; return 1; } + if [ -n "${via}" ]; then + ip route replace "${ip}" via "${via}" dev "${dev}" || return 1 else - bashio::log.error "Cannot add endpoint route. '${endpoint_ip}' is not a valid IP address." - return 1 + ip route replace "${ip}" dev "${dev}" || return 1 fi - - route_via="$(awk '{for (i=1; i<=NF; i++) if ($i=="via") {print $(i+1); exit}}' <<< "${route_line}")" - route_dev="$(awk '{for (i=1; i<=NF; i++) if ($i=="dev") {print $(i+1); exit}}' <<< "${route_line}")" - if [ -z "${route_dev}" ]; then - bashio::log.error "Unable to determine a main-table route for VPN endpoint ${endpoint_ip}." - return 1 - fi - - route_cmd=(ip "${route_family}" route replace "${route_prefix}" table main) - if [ -n "${route_via}" ]; then - route_cmd+=(via "${route_via}") - fi - route_cmd+=(dev "${route_dev}") - "${route_cmd[@]}" || return 1 - - if [ -n "${config["EndpointRoutesFile"]:-}" ]; then - touch "${config["EndpointRoutesFile"]}" || true - if ! grep -Fxq "${endpoint_ip}" "${config["EndpointRoutesFile"]}" 2>/dev/null; then - echo "${endpoint_ip}" >> "${config["EndpointRoutesFile"]}" - fi - fi - bashio::log.info "Pinned VPN endpoint ${endpoint_ip} to pre-VPN route via ${route_dev}." + bashio::log.info "Pinned VPN endpoint ${ip} to pre-VPN route (dev ${dev})." } -_endpoint_routes_del() { - local endpoint_ip="" - local result=0 - - if [ -z "${config["EndpointRoutesFile"]:-}" ] || [ ! -f "${config["EndpointRoutesFile"]}" ]; then - return 0 - fi - - while IFS= read -r endpoint_ip || [ -n "${endpoint_ip}" ]; do - [ -z "${endpoint_ip}" ] && continue - result=0 - _check_host "${endpoint_ip}" || result=$? - if [ "${result}" -eq 1 ]; then - _cmd "ip -4 route del ${endpoint_ip}/32 table main 2>/dev/null" || true - elif [ "${result}" -eq 2 ]; then - _cmd "ip -6 route del ${endpoint_ip}/128 table main 2>/dev/null" || true - fi - done < "${config["EndpointRoutesFile"]}" - - rm -f "${config["EndpointRoutesFile"]}" || true -} - -_openvpn_collect_endpoint_ips() { - local remote_host="" - local result=0 - local endpoint_ip="" - local -a remote_hosts=() - local -a resolved_ips=() - - mapfile -t remote_hosts < <(awk '/^[[:space:]]*remote[[:space:]]+/ {print $2}' "${config["ConfigFile"]}" | sort -u) - for remote_host in "${remote_hosts[@]}"; do - [ -z "${remote_host}" ] && continue - result=0 - _check_host "${remote_host}" || result=$? - if [ "${result}" -eq 1 ] || [ "${result}" -eq 2 ]; then - resolved_ips+=("${remote_host}") - elif [ "${result}" -eq 3 ]; then - for endpoint_ip in $(_resolve_hostname "${remote_host}"); do - resolved_ips+=("${endpoint_ip}") - done - fi - done - - if [ ${#resolved_ips[@]} -gt 0 ]; then - printf '%s\n' "${resolved_ips[@]}" | awk 'NF {print}' | sort -u - fi +_endpoint_route_del() { + local ip + ip="$(cat "${config["EndpointIPFile"]}" 2>/dev/null)" + [ -n "${ip}" ] && ip route del "${ip}" 2>/dev/null || true + rm -f "${config["EndpointIPFile"]}" || true } _routing_add() { @@ -439,9 +366,8 @@ _wireguard_up() { fi _cmd "ip link set ${config["Interface"]} up" || return 1 - touch "${config["EndpointRoutesFile"]}" || return 1 - > "${config["EndpointRoutesFile"]}" || return 1 _endpoint_route_add "${config["EndpointIP"]}" || return 1 + echo "${config["EndpointIP"]}" > "${config["EndpointIPFile"]}" # Add routing rules for VPN interface and DNS servers _routing_add || return 1 @@ -456,7 +382,7 @@ _wireguard_up() { } _wireguard_down() { - _endpoint_routes_del || true + _endpoint_route_del || true # Update resolv.conf to remove VPN DNS servers _resolvconf "reset" || true # Remove routing rules for VPN interface and DNS servers @@ -498,7 +424,7 @@ wireguard() { config["Interface"]="${interface}" config["ConfigFile"]="${config_file}" config["Table"]="${config["Table"]:-1000}" - config["EndpointRoutesFile"]="${WIREGUARD_STATE_DIR}/endpoint-routes" + config["EndpointIPFile"]="${WIREGUARD_STATE_DIR}/endpoint-ip" config["ListenPort"]="${config["ListenPort"]:-51820}" config["EndpointHost"]="${config["Endpoint"]%:*}" config["EndpointPort"]="${config["Endpoint"]##*:}" @@ -585,7 +511,7 @@ _openvpn_check() { } _openvpn_up() { - local endpoint_ip + local endpoint_ip result=0 bashio::log.warning "This script force OpenvPN to ignore any routes and DNS settings pushed by the server." bashio::log.warning "Default route will be inserted into custom routing table: ${config["Table"]}" @@ -600,14 +526,13 @@ _openvpn_up() { echo "${config["MySelf"]} openvpn postdown" >> ${config["PostDownScript"]} chmod 755 ${config["PostDownScript"]} - touch "${config["EndpointRoutesFile"]}" || return 1 - > "${config["EndpointRoutesFile"]}" || return 1 - while IFS= read -r endpoint_ip || [ -n "${endpoint_ip}" ]; do - [ -z "${endpoint_ip}" ] && continue - _endpoint_route_add "${endpoint_ip}" || return 1 - done < <(_openvpn_collect_endpoint_ips) - if [ ! -s "${config["EndpointRoutesFile"]}" ]; then - bashio::log.warning "No OpenVPN endpoint host route could be prepared from ${config["ConfigFile"]}." + endpoint_ip="$(awk '/^[[:space:]]*remote[[:space:]]/ {print $2; exit}' "${config["ConfigFile"]}")" + if [ -n "${endpoint_ip}" ]; then + _check_host "${endpoint_ip}" || result=$? + [ "${result}" -eq 3 ] && endpoint_ip="$(_resolve_hostname "${endpoint_ip}" | awk '{print $1}')" + if [ -n "${endpoint_ip}" ]; then + _endpoint_route_add "${endpoint_ip}" && echo "${endpoint_ip}" > "${config["EndpointIPFile"]}" + fi fi # Define logging @@ -645,7 +570,7 @@ _openvpn_up() { _openvpn_down() { # Terminate OpenVPN process pkill -f "openvpn --config ${config["ConfigFile"]}" || true - _endpoint_routes_del || true + _endpoint_route_del || true # Safety-net cleanup in case the --down callback was never invoked _routing_del || true } @@ -670,7 +595,7 @@ _openpvn_postdown() { if bashio::config.true 'vpn_upnp_enabled'; then _firewall_del || true fi - _endpoint_routes_del || true + _endpoint_route_del || true } openvpn() { @@ -700,7 +625,7 @@ openvpn() { config["Interface"]="${interface}" config["ConfigFile"]="${config_file}" config["Table"]="${config["Table"]:-1000}" - config["EndpointRoutesFile"]="${OPENVPN_STATE_DIR}/endpoint-routes" + config["EndpointIPFile"]="${OPENVPN_STATE_DIR}/endpoint-ip" config["PostUpScript"]="${OPENVPN_STATE_DIR}/up.sh" config["PostDownScript"]="${OPENVPN_STATE_DIR}/down.sh"