Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="magicdns-egress-proxy"

magicdns-egress-proxy-forwarding remove forwarding

bashio::log.info \
"Service ${service} exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
Expand Down
24 changes: 20 additions & 4 deletions tailscale/rootfs/etc/s6-overlay/s6-rc.d/magicdns-egress-proxy/run
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ export LOG_FD
source /usr/lib/trace.sh

readonly DNSMASQ_EGRESS_ADDRESS_IPV4="127.100.100.100"
readonly DNSMASQ_EGRESS_PORT=53
readonly DNSMASQ_EGRESS_DEFAULT_PORT=53127
readonly DNSMASQ_BLACK_WHITE_LIST_LOCATION="/etc/dnsmasq-black-white-list"

declare hassio_dns_ipv4
declare -a white_list
declare domain
declare -a options
declare dnsmasq_egress_port

bashio::log.info "Starting MagicDNS egress proxy..."

Expand All @@ -36,6 +37,17 @@ function dig_hassio_dns() {
| head -n 1
}

# Search for unallocated port in case of collision
dnsmasq_egress_port="${DNSMASQ_EGRESS_DEFAULT_PORT}"
while netstat -lntu \
| awk '{print $4}' \
| grep -q ":${dnsmasq_egress_port}$"
do
if ((++dnsmasq_egress_port == DNSMASQ_EGRESS_DEFAULT_PORT + 1000)); then
bashio::exit.nok "Can't find free port for MagicDNS egress proxy"
fi
done
Comment thread
lmagyar marked this conversation as resolved.

options+=(--no-hosts)
options+=(--no-resolv)
options+=(--conf-file=/dev/null)
Expand All @@ -44,8 +56,11 @@ options+=(--log-facility='-')
options+=(--cache-size=0)

options+=(--listen-address="${DNSMASQ_EGRESS_ADDRESS_IPV4}")
options+=(--bind-dynamic)
options+=(--port="${DNSMASQ_EGRESS_PORT}")
# on the lo interface this bind-interfaces option has the effect that dnsmasq connects only to the specified address
# and on the lo interface bind-interfaces option doesn't result in a logged warning
# this is intentionally different from the ingress proxy, where on a non-lo interface bind-dynamic option has the same effect
options+=(--bind-interfaces)
options+=(--port="${dnsmasq_egress_port}")

# Hassio DNS's IP addresses
if ! hassio_dns_ipv4=$(dig_hassio_dns A) || \
Expand All @@ -68,10 +83,11 @@ if bashio_custom::trace; then
options+=(--log-debug)
fi

magicdns-egress-proxy-forwarding setup forwarding "${dnsmasq_egress_port}"

# We need to delay the starting of the dependent services until the conf file is written
echo "nameserver ${DNSMASQ_EGRESS_ADDRESS_IPV4}" > /etc/resolv.dnsmasq.conf
echo "" >&3

# This DNS forwards the white_list to HA's DNS, otherwise replies NXDOMAIN for everything
# It must run on port 53 to be able to specify it in a resolv.conf
exec dnsmasq "${options[@]}"
21 changes: 18 additions & 3 deletions tailscale/rootfs/etc/s6-overlay/s6-rc.d/magicdns-ingress-proxy/run
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ source /usr/lib/trace.sh

readonly MAGIC_DNS_IPV4="100.100.100.100"

readonly DNSMASQ_INGRESS_PORT=53
readonly DNSMASQ_INGRESS_DEFAULT_PORT=51100
readonly DNSMASQ_BLACK_WHITE_LIST_LOCATION="/etc/dnsmasq-black-white-list"

declare tailscale_address_ipv4
Expand All @@ -25,9 +25,21 @@ declare -a black_list
declare -a white_list
declare domain
declare -a options
declare dnsmasq_ingress_port

bashio::log.info "Starting MagicDNS ingress proxy..."

# Search for unallocated port in case of collision
dnsmasq_ingress_port="${DNSMASQ_INGRESS_DEFAULT_PORT}"
while netstat -lntu \
| awk '{print $4}' \
| grep -q ":${dnsmasq_ingress_port}$"
do
if ((++dnsmasq_ingress_port == DNSMASQ_INGRESS_DEFAULT_PORT + 1000)); then
bashio::exit.nok "Can't find free port for MagicDNS ingress proxy"
fi
done

options+=(--no-hosts)
options+=(--no-resolv)
options+=(--conf-file=/dev/null)
Expand All @@ -51,8 +63,11 @@ if bashio::var.has_value "${tailscale_address_ipv6-}"; then
options+=(--listen-address=${tailscale_address_ipv6})
fi

# on a non-lo interface this bind-dynamic option has the effect that dnsmasq connects only to the specified address
# this is intentionally different from the egress proxy, where on the lo interface bind-interfaces option has the same effect
# and on the lo interface bind-interfaces option doesn't result in a logged warning
options+=(--bind-dynamic)
options+=(--port=${DNSMASQ_INGRESS_PORT})
options+=(--port=${dnsmasq_ingress_port})

if bashio::config.true "accept_dns"; then
# Black-list
Expand All @@ -79,7 +94,7 @@ if bashio_custom::trace; then
options+=(--log-debug)
fi

magicdns-ingress-proxy-forwarding setup forwarding
magicdns-ingress-proxy-forwarding setup forwarding "${dnsmasq_ingress_port}"
magicdns-ingress-proxy-forwarding remove drop

# We need to delay the starting of the dependent services until iptables are configured
Expand Down
1 change: 1 addition & 0 deletions tailscale/rootfs/etc/s6-overlay/s6-rc.d/tailscaled/run
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ if ! bashio::fs.file_exists "/etc/resolv.dnsmasq.conf"; then
else
# Using fake resolv.conf
bashio::log.info "Using dnsmasq as upstream DNS server for tailscaled"
bashio::net.wait_for 53 $(awk '{ print $2 }' < /etc/resolv.dnsmasq.conf)
mv /etc/resolv.dnsmasq.conf /etc/resolv.for-tailscaled.conf
if bashio::debug ; then
exec unshare -m bash -c "mount --bind /etc/resolv.for-tailscaled.conf /etc/resolv.conf; exec /opt/tailscaled $(printf "\"%s\" " "${options[@]}")"
Expand Down
72 changes: 72 additions & 0 deletions tailscale/rootfs/usr/bin/magicdns-egress-proxy-forwarding
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env bashio
# shellcheck shell=bash
export LOG_FD
# ==============================================================================
# Setup DNAT for outgoing MagicDNS queries toward egress dnsmasq proxy
# ==============================================================================

readonly DNSMASQ_EGRESS_ADDRESS_IPV4="127.100.100.100"

function setup_forwarding() {
local cmd="${1}"
local proto="${2}"
local ip_version="${3}"
local address_bits="${4}"
local from_address="${5}"
local to_address="${6}"
local to_port="${7}"

bashio::log.info "Setting up forwarding for MagicDNS egress proxy (${proto}, ${ip_version})"
if ${cmd} -t nat -S OUTPUT \
| grep -Eq "^-A OUTPUT -d ${from_address//[\[\]]/}/${address_bits} -p ${proto} -m ${proto} --dport 53 -j DNAT --to-destination $(sed -r 's/(\[|\])/\\\1/g' <<< "${to_address}"):${to_port}$"
then
bashio::log.notice "Forwarding is already set for MagicDNS egress proxy (${proto}, ${ip_version})"
else
if ! ${cmd} -t nat -A OUTPUT -d "${from_address//[\[\]]/}" -p "${proto}" --dport 53 -j DNAT --to-destination "${to_address}:${to_port}"; then
bashio::exit.nok "Setting up forwarding for MagicDNS egress proxy is unsuccessful (${proto}, ${ip_version})"
fi
fi
}

function remove_forwarding() {
local cmd="${1}"
local ip_version="${2}"
local address_bits="${3}"
local from_address="${4}"
local to_address="${5}"

local variables
local proto
local to_port

for variables in $( \
${cmd} -t nat -S OUTPUT \
| { grep -E "^-A OUTPUT -d ${from_address//[\[\]]/}/${address_bits} -p \S+ -m \S+ --dport 53 -j DNAT --to-destination $(sed -r 's/(\[|\])/\\\1/g' <<< "${to_address}"):\d+$" || true ;} \
| sed -nr 's/^.*?-p\s(\S+).*?:(\d+)$/\1|\2/p')
do
IFS='|' read -r proto to_port <<< "${variables}"
Comment thread
lmagyar marked this conversation as resolved.
bashio::log.info "Removing forwarding for MagicDNS egress proxy (${proto}, ${ip_version})"
if ! ${cmd} -t nat -D OUTPUT -d "${from_address//[\[\]]/}" -p "${proto}" --dport 53 -j DNAT --to-destination "${to_address}:${to_port}"; then
bashio::log.warning "Removing forwarding for MagicDNS egress proxy is unsuccessful (${proto}, ${ip_version})"
fi
done
}

case "${1-}-${2-}" in
setup-forwarding)
if ! bashio::var.has_value "${3-}"; then
echo "Port is missing" 1>&2
echo "Usage: $(basename "$0") setup forwarding port" 1>&2
exit 1
fi
setup_forwarding "iptables" "udp" "IPv4" "32" "${DNSMASQ_EGRESS_ADDRESS_IPV4}" "${DNSMASQ_EGRESS_ADDRESS_IPV4}" "${3}"
setup_forwarding "iptables" "tcp" "IPv4" "32" "${DNSMASQ_EGRESS_ADDRESS_IPV4}" "${DNSMASQ_EGRESS_ADDRESS_IPV4}" "${3}"
;;
remove-forwarding)
remove_forwarding "iptables" "IPv4" "32" "${DNSMASQ_EGRESS_ADDRESS_IPV4}" "${DNSMASQ_EGRESS_ADDRESS_IPV4}"
;;
*)
echo "Usage: $(basename "$0") setup|remove forwarding [port in case of setup forwarding]" 1>&2
exit 1
;;
esac
55 changes: 30 additions & 25 deletions tailscale/rootfs/usr/bin/magicdns-ingress-proxy-forwarding
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ export LOG_FD
readonly MAGIC_DNS_IPV4="100.100.100.100"
readonly MAGIC_DNS_IPV6="fd7a:115c:a1e0::53"

readonly DNSMASQ_INGRESS_PORT=53

declare hassio_dns_ipv4
declare hassio_dns_ipv6
declare hassio_supervisor_ipv4
Expand Down Expand Up @@ -55,17 +53,19 @@ function remove_forwarding() {
local source_address="${4}"
local from_address="${5}"
local to_address="${6}"
local to_port="${7}"
local name="${8}"
local source_name="${9}"
local name="${7}"
local source_name="${8}"

local variables
local proto
local to_port

for proto in $( \
for variables in $( \
${cmd} -t nat -S PREROUTING \
| { grep -E "^-A PREROUTING -s ${source_address//[\[\]]/}/${address_bits} -d ${from_address//[\[\]]/}/${address_bits} -i hassio -p \S+ -m \S+ --dport 53 -j DNAT --to-destination $(sed -r 's/(\[|\])/\\\1/g' <<< "${to_address}"):${to_port}$" || true ;} \
| sed -nr 's/^.*?-p\s(\S+).*$/\1/p')
| { grep -E "^-A PREROUTING -s ${source_address//[\[\]]/}/${address_bits} -d ${from_address//[\[\]]/}/${address_bits} -i hassio -p \S+ -m \S+ --dport 53 -j DNAT --to-destination $(sed -r 's/(\[|\])/\\\1/g' <<< "${to_address}"):\d+$" || true ;} \
| sed -nr 's/^.*?-p\s(\S+).*?:(\d+)$/\1|\2/p')
do
IFS='|' read -r proto to_port <<< "${variables}"
Comment thread
lmagyar marked this conversation as resolved.
bashio::log.info "Removing ${name} for MagicDNS ingress proxy (${proto}, ${ip_version}, ${source_name})"
if ! ${cmd} -t nat -D PREROUTING -s "${source_address//[\[\]]/}" -d "${from_address//[\[\]]/}" -i hassio -p "${proto}" --dport 53 -j DNAT --to-destination "${to_address}:${to_port}"; then
bashio::log.warning "Removing ${name} for MagicDNS ingress proxy is unsuccessful (${proto}, ${ip_version}, ${source_name})"
Expand Down Expand Up @@ -158,53 +158,58 @@ case "${1-}-${2-}" in
fi
;;
setup-forwarding)
if ! bashio::var.has_value "${3-}"; then
echo "Port is missing" 1>&2
echo "Usage: $(basename "$0") setup forwarding port" 1>&2
exit 1
fi
if bashio::var.has_value "${hassio_dns_ipv4-}"; then
setup_forwarding "iptables" "A" "udp" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${DNSMASQ_INGRESS_PORT}" "${2}" "DNS"
setup_forwarding "iptables" "A" "tcp" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${DNSMASQ_INGRESS_PORT}" "${2}" "DNS"
setup_forwarding "iptables" "A" "udp" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${3}" "${2}" "DNS"
setup_forwarding "iptables" "A" "tcp" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${3}" "${2}" "DNS"
fi
if bashio::var.has_value "${hassio_dns_ipv6-}"; then
setup_forwarding "ip6tables" "A" "udp" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${DNSMASQ_INGRESS_PORT}" "${2}" "DNS"
setup_forwarding "ip6tables" "A" "tcp" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${DNSMASQ_INGRESS_PORT}" "${2}" "DNS"
setup_forwarding "ip6tables" "A" "udp" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${3}" "${2}" "DNS"
setup_forwarding "ip6tables" "A" "tcp" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${3}" "${2}" "DNS"
fi
if bashio::var.has_value "${hassio_supervisor_ipv4-}"; then
setup_forwarding "iptables" "A" "udp" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${DNSMASQ_INGRESS_PORT}" "${2}" "Supervisor"
setup_forwarding "iptables" "A" "tcp" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${DNSMASQ_INGRESS_PORT}" "${2}" "Supervisor"
setup_forwarding "iptables" "A" "udp" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${3}" "${2}" "Supervisor"
setup_forwarding "iptables" "A" "tcp" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${3}" "${2}" "Supervisor"
fi
if bashio::var.has_value "${hassio_supervisor_ipv6-}"; then
setup_forwarding "ip6tables" "A" "udp" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${DNSMASQ_INGRESS_PORT}" "${2}" "Supervisor"
setup_forwarding "ip6tables" "A" "tcp" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${DNSMASQ_INGRESS_PORT}" "${2}" "Supervisor"
setup_forwarding "ip6tables" "A" "udp" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${3}" "${2}" "Supervisor"
setup_forwarding "ip6tables" "A" "tcp" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${3}" "${2}" "Supervisor"
fi
;;
remove-drop)
if bashio::var.has_value "${hassio_dns_ipv4-}"; then
remove_forwarding "iptables" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "127.0.0.1" "0" "${2}" "DNS"
remove_forwarding "iptables" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "127.0.0.1" "${2}" "DNS"
fi
if bashio::var.has_value "${hassio_dns_ipv6-}"; then
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[::1]" "0" "${2}" "DNS"
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[::1]" "${2}" "DNS"
fi
if bashio::var.has_value "${hassio_supervisor_ipv4-}"; then
remove_forwarding "iptables" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "127.0.0.1" "0" "${2}" "Supervisor"
remove_forwarding "iptables" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "127.0.0.1" "${2}" "Supervisor"
fi
if bashio::var.has_value "${hassio_supervisor_ipv6-}"; then
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[::1]" "0" "${2}" "Supervisor"
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[::1]" "${2}" "Supervisor"
fi
;;
remove-forwarding)
if bashio::var.has_value "${hassio_dns_ipv4-}"; then
remove_forwarding "iptables" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${DNSMASQ_INGRESS_PORT}" "${2}" "DNS"
remove_forwarding "iptables" "IPv4" "32" "${hassio_dns_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${2}" "DNS"
fi
if bashio::var.has_value "${hassio_dns_ipv6-}"; then
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${DNSMASQ_INGRESS_PORT}" "${2}" "DNS"
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_dns_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${2}" "DNS"
fi
if bashio::var.has_value "${hassio_supervisor_ipv4-}"; then
remove_forwarding "iptables" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${DNSMASQ_INGRESS_PORT}" "${2}" "Supervisor"
remove_forwarding "iptables" "IPv4" "32" "${hassio_supervisor_ipv4}" "${MAGIC_DNS_IPV4}" "${tailscale_address_ipv4}" "${2}" "Supervisor"
fi
if bashio::var.has_value "${hassio_supervisor_ipv6-}"; then
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${DNSMASQ_INGRESS_PORT}" "${2}" "Supervisor"
remove_forwarding "ip6tables" "IPv6" "128" "${hassio_supervisor_ipv6}" "${MAGIC_DNS_IPV6}" "[${tailscale_address_ipv6}]" "${2}" "Supervisor"
fi
;;
*)
echo "Usage: $(basename "$0") setup|remove drop|forwarding" 1>&2
echo "Usage: $(basename "$0") setup|remove drop|forwarding [port in case of setup forwarding]" 1>&2
exit 1
;;
esac
Loading