How to bypass always-on WireGuard VPN and custom system resolver to access Wi-Fi captive portal on Gentoo
On my system, Wi-Fi and WireGuard are configured and started by netifrc. wlp3s0
is the wireless interface and wg0
is the wireguard interface. dhcpcd is used as DHCP client. /etc/conf.d/net
:
modules_wlp3s0="wpa_supplicant"
config_wlp3s0="dhcp"
config_wg0="192.168.10.2/32"
wireguard_wg0="/etc/wireguard/wg0.conf"
postup() {
if [ "$IFACE" = "wg0" ]; then
wg set wg0 fwmark 1234
ip route add default dev wg0 table 2468
ip rule add not fwmark 1234 table 2468
ip rule add table main suppress_prefixlength 0
fi
}
predown() {
if [ "$IFACE" = "wg0" ]; then
ip route del default dev wg0 table 2468
ip rule del not fwmark 1234 table 2468
ip rule del table main suppress_prefixlength 0
fi
}
System resolver is dnsmasq, listening on 127.0.0.1:53. /etc/resolv.conf
:
nameserver 127.0.0.1
/etc/resolv.conf
is marked immutable by chattr +i
.
Now when I'm at some place with an open Wi-Fi that requires authentication in captive portal, I can't access it because of custom DNS resolver and routing rules that pass all traffic through wg0
.
Solution
The solution is to use separate mount and network interface with a pair of veth devices. Make sure you enabled at least CONFIG_NAMESPACES
, CONFIG_NET_NS
, CONFIG_VETH
in kernel.
Create netns and veth pair:
VETH_ADDR=10.200.1.1
VPEER_ADDR=10.200.1.2
WIFI_IFACE=wlp3s0
VETH_IFACE=vethcap1
VPEER_IFACE=vpeercap1
CAPTIVE_NS=captive
ip netns add $CAPTIVE_NS
ip link add $VETH_IFACE type veth peer name $VPEER_IFACE
ip link set $VPEER_IFACE netns $CAPTIVE_NS
ip addr add $VETH_ADDR/24 dev $VETH_IFACE
ip link set $VETH_IFACE up
ip netns exec $CAPTIVE_NS ip addr add $VPEER_ADDR/24 dev $VPEER_IFACE
ip netns exec $CAPTIVE_NS ip link set $VPEER_IFACE up
ip netns exec $CAPTIVE_NS ip link set lo up
ip netns exec $CAPTIVE_NS ip route add default via $VETH_ADDR
Firewall rules to forward traffic coming from netns directly via wlp3s0
:
iptables -t nat -A POSTROUTING -s $VPEER_ADDR/24 -o $WIFI_IFACE -j MASQUERADE
iptables -A FORWARD -i $WIFI_IFACE -o $VETH_IFACE -j ACCEPT
iptables -A FORWARD -o $WIFI_IFACE -i $VETH_IFACE -j ACCEPT
# very important: here we set the same fwmark as the one that wg0 uses
iptables -t mangle -A PREROUTING -s $VPEER_ADDR/24 -j MARK --set-mark 1234
Don't forget to enable packet forwarding in /etc/sysctl.conf
:
net.ipv4.ip_forward = 1
And apply it if needed:
# sysctl -p
Add to /etc/dhcpcd.conf
:
denyinterfaces vethcap1,vpeercap1
And the last but not least: a program that will create a mount namespace, bind-mount /etc/resolv.conf
, then enter the $CAPTIVE_NS
network namespace and launch browser (or anything else) in there.