Total Pageviews

Saturday, 5 August 2017

x86 软路由透明代理构建方案

基本架构

网络配置:
双网卡 + NAT(iptable)+ DHCP
DNS 解析防污染:
overture(解析)+ dnsmasq(缓存)
代理:
shadowsocks(普通 Python 版即可)+ redsocks
透明代理:
iptable + ipset(国内 IP 段)

网络环境

主机是安装了 Ubuntu 14.04 的 x86 机器。双网卡分别是对接外网的网卡 p2p1,分配 IP 是 2.3.3.3(瞎说的);接内网的网卡 eth0,分配的 IP 是 192.168.3.1,也就是后面的 192.168.3.0/24 的子网的网关。

网络配置

开启双网卡

首先是装上双网卡肯定的。确保在系统里新装的网卡已经启用了,在 ifconfig 里能看到两个网卡。顺便记住并记牢接内外网的网卡的名字,我这里是内网 eth0,外网 p2p1。
接内网的网卡 eth0 可以自己配置静态 IP,这里不说了,网上一堆教程,无非就是在 /etc/network/interfaces 改配置。改完之后不知道怎么生效的就直接重启机器吧。

DHCP

先安装 DHCP 的服务器 sudo apt-get install isc-dhcp-server。然后配置 DHCP 网卡 /etc/default/isc-dhcp-server 将INTERFACES=""配置为对应内网网卡。
配置 /etc/dhcp/dhcpd.conf 更新 DHCP 服务器相关参数:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
subnet 192.168.3.0 netmask 255.255.255.0 {
//当DHCP客户端主机启动网络时服务器能够分配给他的IP地址的范围
range 192.168.3.60 192.168.3.240;
//客户端能使用该IP地址的时间,以秒计算
default-lease-time 86400;
max-lease-time 86400;
//客户端默认网关
option routers 192.168.3.1;
//不从一个网口向另一个网口转发 DHCP 请求
option ip-forwarding off;
//设置客户端广播地址和子网掩码
option broadcast-address 192.168.3.255;
option subnet-mask 255.255.255.0;
//设置客户端DNS服务器,防止被上层的 DNS 污染
option domain-name-servers 192.168.3.1;
}

重新启动 DHCP 服务 sudo service isc-dhcp-server restart

NAT

首先,修改配置文件 /etc/sysctl.conf 里的net.ipv4.ip_forward=1。要么取消注释,要么新加一行,然后 sysctl -p 让修改生效。
然后开始要动 iptables 了。iptables 这个东西很魔幻,遇到奇怪的坑很正常。
建议先 sudo apt-get install iptables-persistent 安装 iptables-persistent来 save/reload/restart/restore 保存/重新加载/重启 iptable/重新加载配置。基本用法就是形如 sudo service iptables-persistent save。玩溜了之后就开始搞 NAT。规则如下:


1
2
3
4
5
EXTIF="p2p1"
INTIF="eth0"
iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

上面的 EXTIF 就是外网网卡,INTIF 就是内网网卡,不要搞错了。
正常情况下,save 配置并重启 iptables 之后,在 192.168.3.0/24 的子网里应该就可以连通外网了。

DNS 解析防污染

接下来要解决 DNS 解析结果被污染的问题。这里的坑不多。

overture

overture 是一个 Go 写的 DNS 解析器,支持中国特色社会主义的 DNS 解析。坑不大,到 github 上下载对应系统和架构的二进制包,解压出来就行了。然后把二进制程序丢到 /usr/local/bin 里面,顺便创建一个配置文件目录 /etc/overture,然后把解压出来的其他文件放到配置文件目录里去。
我们的配置文件是让 overture 监听在 54 端口上,用来做 dnsmasq 的上游。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
"BindAddress": ":54",
"PrimaryDNS": [
{
"Name": "DNSPod",
"Address": "119.29.29.29:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 6,
"EDNSClientSubnet": {
"Policy": "disable",
"ExternalIP": ""
}
}
],
"AlternativeDNS":[
{
"Name": "OpenDNS",
"Address": "208.67.222.222:443",
"Protocol": "tcp",
"SOCKS5Address": "",
"Timeout": 6,
"EDNSClientSubnet":{
"Policy": "disable",
"ExternalIP": ""
}
},
{
"Name": "google",
"Address": "8.8.8.8:53",
"Protocol": "tcp",
"Timeout": 6,
"MinimumTTL": 0,
"CacheSize" : 0,
"EDNSClientSubnet":{
"Policy": "enable",
"ExternalIP": ""
}
}
],
"OnlyPrimaryDNS": false,
"RedirectIPv6Record": true,
"IPNetworkFile": "/etc/overture/ip_network_sample",
"DomainFile": "/etc/overture/domain_sample",
"DomainBase64Decode": true,
"HostsFile": "/etc/overture/hosts_sample",
"MinimumTTL": 0,
"CacheSize" : 0,
"RejectQtype": [255]
}

上面在 /etc/overture 的文件名自己对应修改。
至于 overture 怎么跑起来就见仁见智了。可以做 service 启动项,只不过我习惯用 supervisor 开机启动,因为配置文件简单好写。
到这里可以通过命令 dig @127.0.0.1 -p 54 www.google.com 看 overture 好使不。

dnsmasq

dnsmasq 我这里仅仅用来做缓存了,没有用其他功能。
先安装,sudo apt-get install dnsmasq。然后到 /etc/dnsmasq.conf 里改一发配置:


1
2
3
4
5
6
7
8
9
10
# 不读取 /etc/resolv.conf或者其他文件,取消注释即可,这样就可以在本文件里配置上游服务器
no-resolv
no-poll
# 添加上游服务器为overture,那个#54代表端口号,千万别删了。。。。
server=127.0.0.1#54
# 在所有网卡上关闭 DHCP,用不着这个功能。如果有多个网卡那么一行一个。
# 我的DHCP是交给了别的程序
no-dhcp-interface=eth0
no-dhcp-interface=p2p1
cache-size=15000 # 缓存DNS的数目

重启 sudo service dnsmasq restart
这里就可以简单的通过 dig www.facebook.com 选择一个以前没解析过的域名来看缓存生效么,第一次应该一两百毫秒,第二次开始就应该是 1-2 毫秒了。

代理

shadowsocks

之所以选择 shadowsocks(Python版) 而不是 C语言版的 shadowsocks-libev,一个是 x86 机器性能不是问题;二是 shadowsocks-libev 3.0 版以后在密码库的依赖上越走越远,导致各种依赖、编译特别麻烦;三是我这里用 redsocks 来做 tcp 到 sockv5 的转换,所以用不到 ss-redir 之类的东西。
这里没什么好说的,启动一个 sslocal 就好了,也像上面一样在 supervisor 里启动。但是有个坑,似乎 DNS 的解析逻辑有问题,最好 shadowsocks 的配置文件的 server 写 IP 地址,不要写域名。

redsocks

redsocks 是用来把普通的 tcp 流量转成 sockv5 的一个东西,承接 tcp 流量,转到 sslocal 里,功能和 ss-redir 一样的。
先安装,sudo apt-get install redsocks
然后改配置文件 /etc/redsocks.conf,把 redsocks 部分里面的 port 改成你 sslocal 监听的地址,一般是 1080 吧。如果有奇怪的问题,可以把里面的 ip 和 local_ip 改成 0.0.0.0。
UPDATE:
使用过程中遇到一个问题,用着用着莫名其妙的翻不了了。看系统日志发现 redsocks 的 fd 用完,于是修改 /etc/init.d/redsocks 文件,在里面添加一条 ulimit -n 51200。并且重启 redsocks 就好了。

透明代理

我的透明代理策略是国内 IP 不走代理,国外 IP 不管墙不墙都走代理。

ipset

ipset 是用来建立一个 IP 地址段的集合。用来存国内 IP 段的。
先把国内 IP 段搞出来,最新版可以这么搞来


1
curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > chnroute.txt

然后创建 ipset 并添加国内的 IP 段


1
2
sudo ipset create chnroute hash:net
cat chnroute.txt | sudo xargs -I ip ipset add chnroute ip

iptable

接下来就要把流量做相应的转发了。
不要无脑粘贴,看一下注释。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
iptables -t nat -N SHADOWSOCKS
# 在 nat 表中创建新链
iptables -t nat -A SHADOWSOCKS -p tcp --dport 23596 -j RETURN
# 23596 是 ss 代理服务器的端口,即远程 shadowsocks 服务器提供服务的端口,如果你有多个 ip 可用,但端口一致,就设置这个
iptables -t nat -A SHADOWSOCKS -d 123.456.789.111 -j RETURN
# 123.456.789.111 是 ss 代理服务器的 ip, 如果你只有一个 ss服务器的 ip,却能选择不同端口,就设置此条
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
# 过滤局域网段
iptables -t nat -A SHADOWSOCKS -p tcp -m set --match-set chnroute dst -j RETURN
# ipset 过滤国内 IP 段
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345
# 12345 是 redsocks 的监听端口
iptables -t nat -I PREROUTING -p tcp -j SHADOWSOCKS
# 在 PREROUTING 链前插入 SHADOWSOCKS 链,使其生效

然后还是用 iptables-persistent 保存配置并重启 iptables。
至此就应该 OK 了,要是还有什么坑,就没法管了。

至于效果嘛,现在路由翻墙可以跑满我们家百兆带宽了

No comments:

Post a Comment

Note: only a member of this blog may post a comment.