Create an xray/sing-box configuration with dokodemo-door/tproxy inbound listening on 127.0.0.1 port 12345. Run xray systemd service, or sing-box using the systemd service below.
/etc/systemd/system/[email protected]/99-transparent-proxy.conf
[Service]
ExecStartPost=/usr/sbin/ip rule add fwmark 1 table 1
ExecStartPost=/usr/sbin/ip route add local default dev lo table 1
ExecStartPost=/usr/sbin/nft -f /etc/nftables/bsbf_bonding.nft
ExecStopPost=/usr/sbin/nft delete table bsbf_bonding
ExecStopPost=/usr/sbin/ip route flush table 1
ExecStopPost=/usr/sbin/ip rule delete fwmark 1 table 1
/usr/lib/systemd/system/[email protected]
[Unit]
Description=sing-box service
Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target network-online.target
[Service]
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
ExecStart=/usr/bin/sing-box -D /var/lib/sing-box-%i -c /etc/sing-box/%i.json run
ExecStartPost=/usr/sbin/ip rule add fwmark 1 table 1 priority 0
ExecStartPost=/usr/sbin/ip route add local default dev lo table 1
ExecStartPost=/usr/sbin/nft -f /etc/nftables/transparent_proxy.nft
ExecStopPost=/usr/sbin/nft delete table transparent_proxy
ExecStopPost=/usr/sbin/ip route flush table 1
ExecStopPost=/usr/sbin/ip rule delete fwmark 1 table 1
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10s
LimitNOFILE=infinity
[Install]
WantedBy=multi-user.target
/etc/nftables/transparent_proxy.nft
# Make packets from client destined to an IPv4 address that is local to the
# system bypass the proxy. This includes unicast DHCP Request packets with the
# IPv4 daddr not being a private IPv4 address, for which we had to put the 'udp
# dport 67' rule to have it bypass the proxy. This rule ensures that all traffic
# from client that is destined to the router bypasses the proxy. This covers the
# case that if the LAN IP address of the router is not a private IPv4 address,
# it wouldn't bypass the proxy.
#
# This makes it so that all packets that are supposed to be routed will be
# tproxied, except packets with a private IPv4 address as daddr.
#
# Author: Chester A. Unal <[email protected]>
table ip transparent_proxy {
set byp4 {
typeof ip daddr
flags interval
elements = { 0.0.0.0/8, 10.0.0.0/8,
100.64.0.0/10, 127.0.0.0/8,
169.254.0.0/16, 172.16.0.0/12,
192.0.0.0/24, 192.0.2.0/24,
192.88.99.0/24, 192.168.0.0/16,
198.18.0.0/15, 198.51.100.0/24,
203.0.113.0/24, 224.0.0.0/4,
240.0.0.0/4 }
}
chain prerouting_mangle {
type filter hook prerouting priority mangle; policy accept;
ip daddr @byp4 return
fib daddr type != local meta l4proto { tcp, udp } tproxy ip to 127.0.0.1:12345 meta mark set 0x00000001
}
chain output_mangle {
type route hook output priority mangle; policy accept;
meta mark 0x00000002 return
oifname != "lo" meta l4proto { tcp, udp } meta mark set 0x00000001
}
}