Skip to content

Redirecting dumbproxy into a tunnel or other network interface

Snawoot edited this page Apr 1, 2023 · 3 revisions

There is a quite common need for a proxy to have its outgoing connection redirected somewhere else via some tunnel or other network interface without affecting all other connections from the system. For example you might want to forward connections via your proxy into some VPN connection, but you don't want this VPN connection to affect all your system traffic. For such cases I suggest use of Linux VRF feature to create multiple forwarding domains.

Let's say we have upstream wireguard VPN connection defined by /etc/wireguard/proton.conf configuration file like this:

[Interface]
PrivateKey = xxxxxxxxxxxxxxx
Address = 10.2.0.2/32
DNS = 10.2.0.1

[Peer]
# NL-FREE#381133
PublicKey = xxxxxxxxxx
AllowedIPs = 0.0.0.0/0
Endpoint = xxx.xxx.xxx.xx:xxxxx

Let's modify it in a way to attach it to a separate forwarding domain. First, we need to define separate name routing table for it. Add following line to /etc/iproute2/rt_tables:

1000	proton

Next, let's make connection scripts to create and setup VRF for wireguard interface:

[Interface]
PrivateKey = xxxxxxxxxxxxxxx
Address = 10.2.0.2/32
DNS = 1.1.1.1
Table = proton
PreUp = ip link add dev %i-vrf type vrf table proton
PreUp = ip link set dev %i-vrf up
PostUp =  ip link set dev %i master %i-vrf
PostUp = ip -4 route add default dev proton vrf %i-vrf
PostDown = ip link del dev %i-vrf

[Peer]
# NL-FREE#381133
PublicKey = xxxxxxxxxx
AllowedIPs = 0.0.0.0/0
Endpoint = xxx.xxx.xxx.xx:xxxxx

Scripts do the following:

  1. Create a VRF domain.
  2. Activate it.
  3. Enslave wireguard interface to VRF domain.
  4. Re-populate default route to VRF route table (local routes of enslaved interface are getting migrated to VRF table, other routes vanish).

Now we can start VPN connection with wg-quick up proton or systemctl start wg-quick@proton. It should bring up all interfaces, but won't affect actual routing. We can check that both default VRF and proton-vrf are usable.

Request with usual direct connection:

user@hp:~> curl -4 ifconfig.co
89.251.30.210

Using VRF domain with wireguard VPN hooked into it:

user@hp:~> curl -4 --interface proton-vrf ifconfig.co
169.150.218.57

Next, we need to operate dumbproxy inside that new VRF, but having its listen socket in default VRF to accept connections from outside normally. systemd socket activation can help us with that.

Create separate dumbproxy user to run daemon with low privileges: adduser --system --home /var/lib/dumbproxy --shell /bin/false --group --disabled-login dumbproxy

Put following systemd units.

/etc/systemd/system/dumbproxy.socket:

[Socket]
ListenStream=443

[Install]
WantedBy=sockets.target

/etc/systemd/system/dumbproxy.service:

[Unit]
Description=Dumb Proxy
Documentation=https://github.com/Snawoot/dumbproxy/
After=network.target network-online.target
Requires=network-online.target

[Service]
EnvironmentFile=/etc/default/dumbproxy
Environment=HOME=/var/lib/dumbproxy
User=root
Group=root
ExecStart=/usr/sbin/ip vrf exec proton-vrf \
	/usr/bin/setpriv --reuid dumbproxy --regid dumbproxy --clear-groups -- \
	/usr/local/bin/dumbproxy --bind-address='' $OPTIONS
TimeoutStopSec=5s
PrivateTmp=true
ProtectSystem=full

[Install]
WantedBy=default.target

/etc/default/dumbproxy:

OPTIONS=-auth basicfile://?path=/var/lib/dumbproxy/dumbproxy.htpasswd \
	-autocert

Finally, lets enable it and start!

systemctl daemon-reload
systemctl enable dumbproxy.socket
systemctl start dumbproxy.socket

Socket unit will invoke service automatically on first connection to it. That's it, it should work and forward incoming connections into VPN. If it doesn't, check logs with journalctl -u dumbproxy -n 100. Also make sure if DNS in /etc/resolv.conf file is reachable from that VRF. Try some public ones like 1.1.1.1 or 8.8.8.8 if in doubt.

Alternatively, it is possible to run dumbproxy with socket activation and custom VRF from command line like this:

sudo systemd-socket-activate -E HOME=/var/lib/dumbproxy -l 0.0.0.0:443 \
    ip vrf exec proton-vrf \
    setpriv --reuid dumbproxy --regid dumbproxy --clear-groups \
    /usr/local/bin/dumbproxy --bind-address=''