普通视图

Received before yesterday技术博客

使用tun2socks实现全局代理

2026年6月17日 00:00

修改系统路由表的操作具有一定风险性,须谨慎操作。

有时在纯命令行环境下的linux,执行某些命令操作需要设置代理,比如新冠疫情期间居家办公时,通过git clone从公司内网拉取项目,就需要连接公司的代理服务器,一些命令可以通过追加控制台代理参数export http_proxy实现从代理服务器访问目标地址,但是并不是所有的命令都支持控制台代理。

tun2socks(https://github.com/xjasonlyu/tun2socks/)是一个基于go语言的,支持多个平台的开源项目,可以在更深的层面彻底解决代理上网的问题,不同于控制台代理或命令自身支持设置代理服务器的方式,tun2socks将虚拟网络适配器从底层拦截并发送来的tcp/ip数据进行解包,将解离出的应用层数据包发送给sock/http代理服务器,并将代理服务器返回的数据再封装为tcp/ip数据包传递给虚拟网络适配器,虚拟网络适配器继而再传递给具体进程。

例如当前的linux运行在虚拟机,地址是192.168.228.105,网关是192.168.228.2,代理服务器安装在宿主机192.168.228.1

首先ip addr查看本地网络情况,可见机器上enp2s0网卡是连接本地内网的网卡,地址是192.168.228.105

[root@java105 ~]# ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever    inet6 ::1/128 scope host        valid_lft forever preferred_lft forever2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000    link/ether 00:0c:29:8c:08:f8 brd ff:ff:ff:ff:ff:ff    inet 192.168.228.105/24 brd 192.168.228.255 scope global noprefixroute enp2s0       valid_lft forever preferred_lft forever    inet6 fe80::20c:29ff:fe8c:8f8/64 scope link noprefixroute        valid_lft forever preferred_lft forever

然后ip route查看系统路由表,通过default via 192.168.228.2 dev enp2s0可见enp2s0是默认出口,访问所有不在路由表中规定的目标地址,都通过enp2s0出站

[root@java105 ~]# ip routedefault via 192.168.228.2 dev enp2s0 proto dhcp src 192.168.228.105 metric 100 192.168.228.0/24 dev enp2s0 proto kernel scope link src 192.168.228.105 metric 100

然后,在使用tun2socks前,要先新建一个新的虚拟网卡tun0,随便分配个和现有不冲突的198.18.0.1/15网段,从网络层接管请求

# 创建 tun0 设备,模式为 tunip tuntap add mode tun dev tun0# 给它配个IP并启用ip addr add 198.18.0.1/15 dev tun0ip link set dev tun0 up

再次查看本地网卡信息和路由表,已经能见到tun0了,并且状态是state UP

[root@java105 ~]# ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever    inet6 ::1/128 scope host        valid_lft forever preferred_lft forever2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000    link/ether 00:0c:29:8c:08:f8 brd ff:ff:ff:ff:ff:ff    inet 192.168.228.105/24 brd 192.168.228.255 scope global noprefixroute enp2s0       valid_lft forever preferred_lft forever    inet6 fe80::20c:29ff:fe8c:8f8/64 scope link noprefixroute        valid_lft forever preferred_lft forever3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 500    link/none     inet 198.18.0.1/15 scope global tun0       valid_lft forever preferred_lft forever    inet6 fe80::9601:d30a:4eec:d2e5/64 scope link stable-privacy        valid_lft forever preferred_lft forever
[root@java105 ~]# ip routedefault via 192.168.228.2 dev enp2s0 proto dhcp src 192.168.228.105 metric 100 192.168.228.0/24 dev enp2s0 proto kernel scope link src 192.168.228.105 metric 100198.18.0.0/15 dev tun0 proto kernel scope link src 198.18.0.1 

将对应平台的tun2socks命令下载到任意目录,并运行起来,指定监听通往刚刚建好的虚拟网卡tun0的请求

nohup ./tun2socks-linux-amd64 -device tun0 -proxy socks5://192.168.228.1:7897 &

现在tun0已经在收集请求并由tun2socks处理了,但是系统默认路由还是指向enp2s0,各个进程的网络请求会涌向enp2s0而不是tun0,此时还要修改默认路由为tun0,将系统中各个进程的网络请求导入tun0

# 1. 删除现有默认路由ip route del default# 2. 添加新的默认路由,指向 tun0 接口ip route add default dev tun0

再次查看路由表

[root@java108 ~]# ip routedefault dev tun0 scope link192.168.228.0/24 dev enp2s0 proto kernel scope link src 192.168.228.105 metric 100198.18.0.0/15 dev tun0 proto kernel scope link src 198.18.0.1 

default已经指向了dev tun0,系统中所有tcp/udp请求都从网络层转发到dev tun0继而进入代理服务器socks5://192.168.228.1:7897

tun2socks作为一个进程当然也在不断发起网络请求到192.168.228.1,但是路由表中已经明确有了192.168.228.0/24 dev enp2s0 proto kernel scope link src 192.168.228.105 metric 100这一条,规定了通往192.168.228.0/24的请求从物理网卡dev enp2s0出站,因此不会导致死循环。

dev enp2s0是物理网卡当然是相对于dev tun0而言的

最后需注意,这种方式仅支持tcp/udp,不支持对icmp请求进行代理,因此测试验证时应该用curl或telnet而不是ping

❌