From b7b7cf62e6ad42b36b0a2c8b48e50eadb0d4279c Mon Sep 17 00:00:00 2001 From: Laszlo Magyar Date: Mon, 27 Jan 2025 00:06:51 +0100 Subject: [PATCH] bunny is right on forwarding --- tailscale/DOCS.md | 4 +- .../etc/s6-overlay/s6-rc.d/forwarding/finish | 54 ++++++------ .../etc/s6-overlay/s6-rc.d/forwarding/run | 82 ++++++++++--------- 3 files changed, 75 insertions(+), 65 deletions(-) diff --git a/tailscale/DOCS.md b/tailscale/DOCS.md index 5a824ff6..16f465d2 100644 --- a/tailscale/DOCS.md +++ b/tailscale/DOCS.md @@ -164,8 +164,8 @@ have to enable subnet routing just to access services on the host from the tailnet. **Note:** Without forwarding, services running only on the interfaces managed by -Home Assistant (ie. not on all interfaces), are not accessible directly from the -tailnet when userspace networking is disabled. +Home Assistant (i.e. not on all interfaces), are not accessible directly from +the tailnet when userspace networking is disabled. **Note:** Tailscale's serve and funnel features have priority over this plain port forwarding, those connections won't be forwarded directly to the host. diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/finish b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/finish index 04191d36..57f41f4e 100755 --- a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/finish +++ b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/finish @@ -6,30 +6,36 @@ # ============================================================================== declare from_address_ipv4 from_address_ipv6 -declare to_address - -# Tailscale's IP addresses -from_address_ipv4=$(/opt/tailscale ip -4) -from_address_ipv6=$(/opt/tailscale ip -6) # In case of non userspace networking and if enabled, remove the forwarding from tailnet to host -for to_address in $( \ - iptables -t nat -S PREROUTING \ - | { grep -E "^-A PREROUTING -d ${from_address_ipv4}/32 -j DNAT --to-destination \S+$" || true ;} \ - | sed -nr 's/^.*?--to-destination\s(\S+)$/\1/p') -do - bashio::log.info "Removing the forwarding from ${from_address_ipv4} to ${to_address} (IPv4)" - if ! iptables -t nat -D PREROUTING -d ${from_address_ipv4} -j DNAT --to-destination ${to_address}; then - bashio::log.warning "Removing forwarding is unsuccessful" - fi -done -for to_address in $( \ - ip6tables -t nat -S PREROUTING \ - | { grep -E "^-A PREROUTING -d ${from_address_ipv6}/128 -j DNAT --to-destination \S+$" || true ;} \ - | sed -nr 's/^.*?--to-destination\s(\S+)$/\1/p') -do - bashio::log.info "Removing the forwarding from ${from_address_ipv6} to ${to_address} (IPv6)" - if ! ip6tables -t nat -D PREROUTING -d ${from_address_ipv6} -j DNAT --to-destination ${to_address}; then - bashio::log.warning "Removing forwarding is unsuccessful" +function remove_forwarding() { + local cmd="$1" + local ip_version="$2" + local from_address="$3" + local from_address_bits="$4" + local to_address + + if bashio::var.has_value "${from_address}"; then + for to_address in $( \ + ${cmd} -t nat -S PREROUTING \ + | { grep -E "^-A PREROUTING -d ${from_address}/${from_address_bits} -j DNAT --to-destination \S+$" || true ;} \ + | sed -nr 's/^.*?--to-destination\s(\S+)$/\1/p') + do + bashio::log.info "Removing the forwarding from ${from_address} to ${to_address} (${ip_version})" + if ! ${cmd} -t nat -D PREROUTING -d ${from_address} -j DNAT --to-destination ${to_address}; then + bashio::log.warning "Removing forwarding is unsuccessful (${ip_version})" + fi + done fi -done +} + +# Tailscale's IP addresses +if ! from_address_ipv4=$(/opt/tailscale ip -4); then + bashio::log.warning "Failed to retrieve Tailscale's IPv4 address" +fi +if ! from_address_ipv6=$(/opt/tailscale ip -6); then + bashio::log.warning "Failed to retrieve Tailscale's IPv6 address" +fi + +remove_forwarding "iptables" "IPv4" "${from_address_ipv4}" "32" +remove_forwarding "ip6tables" "IPv6" "${from_address_ipv6}" "128" diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/run b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/run index 7816921e..71d718cf 100755 --- a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/run +++ b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/run @@ -29,60 +29,64 @@ function get_forwardable_address() { fi if ! ipinfo="$(/usr/bin/ipcalc --json "${address}")"; then + bashio::log.debug "Address ${address} is not valid: ${ipinfo}" return 1 fi bashio::jq "${ipinfo}" '.ADDRESS' } -# Tailscale's IP addresses -from_address_ipv4=$(/opt/tailscale ip -4) -from_address_ipv6=$(/opt/tailscale ip -6) # Host's IP addresses -if ! bashio::var.equals "$(bashio::network.ipv4_method)" "disabled"; then - for address in "$(bashio::network.ipv4_address)"; do - if to_address_ipv4=$(get_forwardable_address "${address}"); then - break - fi - done -fi -if ! bashio::var.equals "$(bashio::network.ipv6_method)" "disabled"; then - for address in "$(bashio::network.ipv6_address)"; do - if to_address_ipv6=$(get_forwardable_address "${address}"); then - break - fi - done -fi +function get_host_address() { + local ip_version="$1" + + if ! bashio::var.equals "$(bashio::network.${ip_version}_method)" "disabled"; then + for address in "$(bashio::network.${ip_version}_address)"; do + if get_forwardable_address "${address}"; then + break + else + bashio::log.debug "Skipping non-forwardable ${ip_version} address: ${address}" + fi + done + fi +} # In case of non userspace networking and if enabled, forward incoming tailnet connections to the host's primary interface -if bashio::var.has_value "${from_address_ipv4}" && bashio::var.has_value "${to_address_ipv4-}"; then +function setup_forwarding() { + local cmd="$1" + local ip_version="$2" + local from_address="$3" + local from_address_bits="$4" + local to_address="$5" + + if bashio::var.has_value "${from_address}" && bashio::var.has_value "${to_address}"; then bashio::log.info \ - "Forwarding incoming tailnet connections directed to ${from_address_ipv4} to the host's ${to_address_ipv4} address (IPv4)" - if iptables -t nat -S PREROUTING \ - | grep -Eq "^-A PREROUTING -d ${from_address_ipv4}/32 -j DNAT --to-destination ${to_address_ipv4}$" + "Forwarding incoming tailnet connections directed to ${from_address} to the host's ${to_address} address (${ip_version})" + if ${cmd} -t nat -S PREROUTING \ + | grep -Eq "^-A PREROUTING -d ${from_address}/${from_address_bits} -j DNAT --to-destination ${to_address}$" then - bashio::log.notice "Forwarding is already set" + bashio::log.notice "Forwarding is already set (${ip_version})" else # Difference compared to Tailscale's docker image: using only -A append, less intrusive than -I insert - # The comment is to search the entry for removal, it is too siple to match by it's structure - if ! iptables -t nat -A PREROUTING -d ${from_address_ipv4} -j DNAT --to-destination ${to_address_ipv4}; then - bashio::log.warning "Setting up forwarding is unsuccessful" + if ! ${cmd} -t nat -A PREROUTING -d ${from_address} -j DNAT --to-destination ${to_address}; then + bashio::log.warning "Setting up forwarding is unsuccessful (${ip_version})" fi fi + fi +} + +# Tailscale's IP addresses +if ! from_address_ipv4=$(/opt/tailscale ip -4); then + bashio::log.warning "Failed to retrieve Tailscale's IPv4 address" fi -if bashio::var.has_value "${from_address_ipv6}" && bashio::var.has_value "${to_address_ipv6-}"; then - bashio::log.info \ - "Forwarding incoming tailnet connections directed to ${from_address_ipv6} to the host's ${to_address_ipv6} address (IPv6)" - if ip6tables -t nat -S PREROUTING \ - | grep -Eq "^-A PREROUTING -d ${from_address_ipv6}/128 -j DNAT --to-destination ${to_address_ipv6}$" - then - bashio::log.notice "Forwarding is already set" - else - # Difference compared to Tailscale's docker image: using only -A append, less intrusive than -I insert - # The comment is to search the entry for removal, it is too siple to match by it's structure - if ! ip6tables -t nat -A PREROUTING -d ${from_address_ipv6} -j DNAT --to-destination ${to_address_ipv6}; then - bashio::log.warning "Setting up forwarding is unsuccessful" - fi - fi +if ! from_address_ipv6=$(/opt/tailscale ip -6); then + bashio::log.warning "Failed to retrieve Tailscale's IPv6 address" fi + +# Host's IP addresses +to_address_ipv4=$(get_host_address "ipv4") +to_address_ipv6=$(get_host_address "ipv6") + +setup_forwarding "iptables" "IPv4" "${from_address_ipv4}" "32" "${to_address_ipv4}" +setup_forwarding "ip6tables" "IPv6" "${from_address_ipv6}" "128" "${to_address_ipv6}"