Skip to content

Commit

Permalink
bunny is right on forwarding
Browse files Browse the repository at this point in the history
  • Loading branch information
lmagyar committed Jan 27, 2025
1 parent c2c128d commit b7b7cf6
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 65 deletions.
4 changes: 2 additions & 2 deletions tailscale/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
54 changes: 30 additions & 24 deletions tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/finish
Original file line number Diff line number Diff line change
Expand Up @@ -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"
82 changes: 43 additions & 39 deletions tailscale/rootfs/etc/s6-overlay/s6-rc.d/forwarding/run
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

0 comments on commit b7b7cf6

Please sign in to comment.