Friday, November 11, 2016

局域网下免设置路由全局透明代理

如果你不想光为了透明代理而单独买一个可刷OpenWRT固件的路由器, 同时你在局域网内有至少一台linux机器(可虚拟机),那以下内容可以帮助你在不需要设置路由的情况下实现透明代理(当然本质上就是把那台机器当成路由来用)。

首先你需要一台linux机器,ubuntu/debian/centos等均可,能编译ss-libev,使用iptables(于是不能centos7,我不会调教那个firewall)。你可以使用真实机器(如树莓派)或虚拟机。如果使用虚拟机,网络类型需要设置为桥接到物理网络,如果是VMware,不要对“复制物理网络连接状态”打钩。我建议使用虚拟机或性能不差的真实机器,这样网速不会受到性能上的限制。

接下来,安装操作系统、安装编译依赖包、git clone ss-libev、configure、make等这里就不说了,网上说明有很多(虽然大多数是过时了)。

编译好后,如果你clone的是ssr的libev版本,里面自带了一个ssrlink.py,可以通过此脚本快速生成一个客户端使用的配置文件,例如执行:

python ssrlink.py ssr://MTkyLjE2OC4xLjI6MTA4MDphdXRoX2FlczEyOF9tZDU6YWVzLTEyOC1jZmI6dGxzMS4yX3RpY2tldF9hdXRoOk1USXpORFUyLz9vYmZzcGFyYW09ZEdWemRDNWpiMjAmZ3JvdXA9ZEdWemRB > config.json
即可生成一个配置好了的config.json

东西都准备好了,现在开始配置。首先是开启ipv4转发,编辑/etc/sysctl.conf,解除net.ipv4.ip_forward = 1的注释,或直接添加这么一行,保存文件,并执行sysctl -p使修改立即生效。然后,设置IP为静态的,例如你的路由器地址为192.168.0.1,那么你可以设置为192.168.0.2,具体设置方法参考linux文档。设置好以后,在需要全局代理的机器上,把网关地址改为192.168.0.2,测试能不能正常上网(现在还没有通过代理),如果不能,那检查防火墙配置,或尝试重启它再测试。能正常上网后再进行后面的配置。



然后,创建一个ipt.sh文件,文件内容如下:

#!/bin/bash

subnet="192.168.0.0/16"           # your subnet config
localaddr="192.168.0.2"           # this server ip (must be subnet ip)
boardcastaddr="192.168.0.255"
listenport=1080                   # local listen port (tcp)
    udplistenport=0               # set it if not the same udp port
NAT_OUTPUT=0                      # if 0: do not need to set server ip
if [ $NAT_OUTPUT -eq 1 ]; then
    serverip="100.86.100.10"          # ss server ip (tcp)
    serverip_udp=""                   # ss server ip (for udp), keep empty if the same
fi

iptables -t nat -D PREROUTING -p tcp -j SHADOWSOCKS
if [ $NAT_OUTPUT -eq 1 ]; then
    iptables -t nat -D OUTPUT -p tcp -j SHADOWSOCKS
fi
iptables -t nat -F SHADOWSOCKS
iptables -t nat -X SHADOWSOCKS

iptables -t mangle -D PREROUTING -p udp -j SHADOWSOCKS
iptables -t mangle -F SHADOWSOCKS
iptables -t mangle -X SHADOWSOCKS

ip rule del fwmark 0x01/0x01 table 100
ip route del local 0.0.0.0/0 dev lo table 100


if [ $udplistenport -eq 0 ]; then
    udplistenport=`expr $listenport`
fi

iptables -t nat -N SHADOWSOCKS
iptables -t nat -I PREROUTING -p tcp -j SHADOWSOCKS
if [ $NAT_OUTPUT -eq 1 ]; then
    iptables -t nat -I OUTPUT -p tcp -j SHADOWSOCKS
fi

ip rule add fwmark 0x01/0x01 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N SHADOWSOCKS
iptables -t mangle -A SHADOWSOCKS -d ${boardcastaddr} -j RETURN
iptables -t mangle -A SHADOWSOCKS -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A SHADOWSOCKS -p udp --dport 137 -j RETURN
iptables -t mangle -A SHADOWSOCKS -p udp --dport 138 -j RETURN
iptables -t mangle -A SHADOWSOCKS -p udp -d ${localaddr} -j RETURN
iptables -t mangle -A SHADOWSOCKS -p udp -s ${localaddr} -j RETURN
iptables -t mangle -A SHADOWSOCKS -p udp -s ${subnet} -j TPROXY --on-port ${udplistenport} --tproxy-mark 0x01/0x01
iptables -t mangle -I PREROUTING -p udp -j SHADOWSOCKS

if [ $NAT_OUTPUT -eq 0 ]; then
    iptables -t nat -A SHADOWSOCKS -d ${localaddr} -j RETURN
    iptables -t nat -A SHADOWSOCKS -s ${localaddr} -j RETURN
else
    iptables -t nat -A SHADOWSOCKS -d ${serverip} -j RETURN
    iptables -t nat -A SHADOWSOCKS -s ${serverip} -j RETURN
    if [ -z $serverip_udp ]; then
   
    iptables -t nat -A SHADOWSOCKS -d ${serverip} -j RETURN
   
    iptables -t nat -A SHADOWSOCKS -s ${serverip} -j RETURN
    fi
fi

iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d ${subnet} -j RETURN

iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports ${listenport}


注意你应该按你的本地设定修改前四行的配置,一般你也只需要修改前四行的配置项就行了,然后保存并执行。执行后,它可以重定向你所有的出网TCP和UDP包。

最后,运行ss-redir:./ss-redir -c config.json -u
此时便应该是全局,可以愉快地玩耍了

注意的一点:UDP包如果不能成功转发,可能是被GFW拦截,那么这时只能更换服务器了。而这可能导致DNS查询失败,可以先把DNS设置为路由的DNS地址以便于排查问题。

ipt.sh参数说明:
listenport 应该与你的ss配置文件所配置的local_port一致
localaddr 你的这台linux机器的静态IP地址

subnet 你的局域网网络地址段
boardcastaddr 你的局域网的广播地址(地址段中最大的地址,由网络掩码决定)

其它说明:如果你不需要全局代理,你可以在ipt.sh中模仿以下指令
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
在此后面添加你不需要代理的地址段即可

16 comments:

  1. 然而centos7能安装iptables再关掉friewalld

    ReplyDelete
  2. 貌似买支持OpenWrt的路由器更简单直接

    ReplyDelete
    Replies
    1. 不想花时间就花钱,不过有时候花钱也并非更快

      Delete
  3. 我直接虚拟机装openwrt,占用地方也不大=_-

    ReplyDelete
  4. 好妖的字体和背景,快被掰歪了。。。
    firewalld转发更简单
    firewall-cmd --permanent --add-masquerade
    firewall-cmd --permanent --add-forward-port=port=【本地端口】:proto=tcp:toport=【目标端口】:toaddr=【目标地址】
    firewall-cmd --reload
    udp同理。参考地址 https://www.rootusers.com/how-to-use-firewalld-rich-rules-and-zones-for-filtering-and-nat/

    另外想问下python版client有没有PAC 如何使用

    ReplyDelete
    Replies
    1. 谢谢啊,不过UDP同理?UDP有着和TCP不一样的地方啊。。。关于PAC你可以弄一个PAC生成服务器

      Delete
    2. udp具体的我也没有研究,但是在中转服务器上按tcp的方式写了。中转服务器上没有运行SSR,只对ssr端口进行转发到ssr服务器。PC C#客户端中服务器ip填中转服务器ip。测试udp tcp均正常使用。

      Delete
    3. 哦 我说的不是局域网的设置。我中转是直接用的--add-forward-port。文中的局域网规则可能要用到rich-rules。还没研究过

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
  6. 既然linux可以实现那么用虚拟机装openwrt应该也能实现吧 虽然我没有成功过

    ReplyDelete
  7. 我也觉得这字体有毒,尤其是命令相关用这种字体....

    ReplyDelete
  8. 问一个不太相关的问题,我的路由器安装了Python但不支持多线程(提示can't start new thread),该怎么办?

    ReplyDelete