segfault/router/fix-network.sh
SkyperTHC bfee848525
rc1
2023-02-21 06:49:57 +00:00

92 lines
3.7 KiB
Bash
Executable File

#! /bin/bash
# shellcheck disable=SC1091 # Do not follow
source "/sf/bin/funcs.sh"
source "/sf/bin/funcs_net.sh"
# NOTE: The iptable rules set inside this container are not visible (iptables -S) on the host
# even that 'network_mode: host' is set. Yet the rule are working on the host side (Why?).
# Furthermore, creating the correct link on the host in /var/run/netns to make the docker namespace
# show up in 'ip netns list' and entering the namespace 'ip netns exec' still wont show
# the iptable rules set inside this container. (Why?).
# See also
# - https://stackoverflow.com/questions/31265993/docker-networking-namespace-not-visible-in-ip-netns-list
# - https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg
# Once
ipt()
{
local first
first="$1"
shift 1
iptables -C "$@" 2>/dev/null && return # Rule already exists
iptables "$first" "$@"
}
# We need to use our own forwarding rules. Docker-compose otherwise spawns a separate process
# for _every_ port - which exceeds Docker's own startup timer if to many ports are forwarded
# and thus docker-compose will fail to start.
#
# Forward traffic to docker
# [UDP/TCP] [PORT-RANGE] [DSTIP]
fw2docker()
{
local proto
local range
local dstip
proto="$1"
range="$2"
dstip="$3"
# Debugging:
# iptables -t raw -I PREROUTING -p udp --dport 55372 -j TRACE
# xtables-monitor --trace
ipt -I PREROUTING -t nat -i "${dev:?}" -d "${mainip}" -p "${proto}" --dport "${range}" -j DNAT --to-destination "${dstip}"
# Accept forward in case the host's FORWARD policy is set to DROP
ipt -I DOCKER-USER -o "${dev_br:?}" -d "${dstip}" -p "${proto}" --dport "${range}" -j ACCEPT
[[ -z $SF_DEBUG ]] && return
# #1 - Special hack when connecting from localhost to 10.0.2.15
ipt -I OUTPUT -t nat -o lo -d "${mainip}" -p "${proto}" --dport "${range}" -j DNAT --to-destination "${dstip}"
# #2 - When connecting from localhost to 127.0.0.1 (#1 is also required)
ipt -I OUTPUT -t nat -o lo -s 127.0.0.1 -d 127.0.0.1 -p "${proto}" --dport "${range}" -j DNAT --to-destination "${dstip}"
ipt -A POSTROUTING -t nat -s 127.0.0.1 -d "${dstip}" -p "${proto}" --dport "${range}" -j SNAT --to "${NET_DIRECT_BRIDGE_IP:?}"
}
# This is a hack.
# - Docker sets the default route to IP of the host-side of the bridge
# - Our 'sf-router' container likes to receive all the traffic instead.
# - Remove host's bridge ip address (flush)
# - sf-router's init.sh script will take over the IP of host's bridge (and thus receiving all traffic)
# An alternative would be to assign a default gw in user's sf-shell
# and use nsenter -n to change the default route (without giving NET_ADMIN
# to the user).
dev=$(DevByIP "${NET_LG_ROUTER_IP:?}")
[[ -z $dev ]] && ERREXIT 255 "Failed to find network device on host for NET_LG_ROUTER_IP=$NET_LG_ROUTER_IP"
# Remove _any_ ip from the interface. This means LGs can never exit
# to the Internet via the host but still route packets to sf-router.
# sf-router is taking over the IP NET_LG_ROUTER_IP
ip link set "$dev" arp off
ip addr flush "$dev"
mainip=$(GetMainIP)
dev=$(DevByIP "${mainip:?}") || ERREXIT 255 "Failed to find main network device on host."
dev_br=$(DevByIP "${NET_DIRECT_BRIDGE_IP:?}") || ERREXIT 255 "Failed to find main network device on host."
## NOTE: Flushing POSTROUTING may screw up dns-doh (when dns-doh tries to reconnect)
# iptables -t nat -F PREROUTING
# iptables -t nat -F OUTPUT
# iptables -t nat -F POSTROUTING
fw2docker "udp" "32768:65535" "${NET_DIRECT_WG_IP:?}"
# MOSH forwards to sf-router (for traffic control)
fw2docker "udp" "25002:26023" "${NET_DIRECT_ROUTER_IP:?}"
# [[ -n $SF_DEBUG ]] && sysctl -w "net.ipv4.conf.${dev_br}.route_localnet=1"
# Keep this running so we can inspect iptables rules (for debugging only)
[[ -n $SF_DEBUG ]] && exec -a '[network-fix] sleep' sleep infinity
exit 0