不需要旁路由也能稳定透明访问互联网

网上有很多关于软路由、旁路由(旁路网关)的文章,但是说真的,即便是很多程序员也不太能玩得转这一套。而且软硬件总有失灵的时候,一旦出问题,就只能等着你一个人来修,影响家庭成员的正常网络访问,
为了更好的将科学上网&网络加速的需求透明无感地融入到家庭网络中,需要仔细选择。
先列出该方案的优缺点供诸君参考。

 优势

1、不需要给路由器刷机、买软路由,任意一个单网口Linux主机即可;
2、不动网络拓扑,完全不影响国内流量,稳定性高,可插拔(物理意义上的);
3、按需配置,按照域名精细化控制是否需要加速;
4、界面化操作,普通人也可以维护;
5、不需要研究复杂的iptables规则!;

 缺点

1、基本上只支持标准端口的 http & https 协议;
2、除了已有的gfwlist列表外,需要手动添加个人常用的域名列表;
3、如果部分硬件设备或app指定了dns,不使用dhcp分配的,不生效;
4、部分网站可能由于奇奇怪怪的问题无法访问,例如 dash.cloudflare.com 页面经常加载静态资源失败

 适合场景

1、对 Linux 和 网络配置相关不够熟悉;
2、没有太多精力维护,希望足够简单并且尽可能稳定,不会影响家人的正常使用;
3、主要是访问网站,玩外网游戏有专门的加速器

 需求

1、一个普普通通的路由器
2、一个Linux小主机,这是所有透明代理方案下都必须的
3、一个支持 V2ray 协议的代理(当然其他也可以啊,这里就不列了)

 原理

将需要加速的网站域名解析到Linux主机,然后走加密&混淆通道出国,其他正常解析

 步骤

  • 现在习惯了用docker来运行程序,所以后续大多数服务使用docker启动,供参考。
  • 假设Linux主机的局域网地址为192.168.7.6,后续配置需要参照修改
1
2
# 可以使用该命令来安装 Docker
curl -fsSL https://get.docker.com | sh
1、部署、配置DNS服务(AdGuardHome)
1
2
3
4
5
6
7
8
9
10
11
12
sudo mkdir -p /data/adh/work/
sudo mkdir -p /data/adh/conf/

sudo docker run \
-d \
--restart always \
--name adguardhome \
--mount type=bind,src=/data/adh/work/,dst=/opt/adguardhome/work/ \
--mount type=bind,src=/data/adh/conf/,dst=/opt/adguardhome/conf/ \
-p 53:53/udp \
-p 3000:3000/tcp \
adguard/adguardhome
访问 http://192.168.7.6:3000 进行初始化,并将上游DNS服务器配置为 114.114.114.114。(为了提升可用性,可以再添加其他的国内DNS服务器,如 223.5.5.5)
Setup upstream DNS servers
参考如下图,添加需要加速的域名,后面的IP地址为 192.168.7.6 。可以基于 gfwlist 生成一个初始的配置,后续再慢慢添加。
Add domains need acceleration
这里贴一个脚本来处理gfwlist文件,并且通过API更新到 AdGuardHome 中。
1
2
3
4
5
6
7
8
9
wget 'https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt'

cat gfwlist.txt | base64 -d > gfwlist.txt.decoded

cat gfwlist.txt.decoded | grep -v '^!' | grep '\.' | grep -v '@@|' | grep -v '/' | grep -v '\[' > gfwlist.txt.blocked

cat gfwlist.txt.blocked | sed 's/^\.//g' | sed 's/||//g' | sort | uniq > gfwlist.txt.domains

cat gfwlist.txt.domains | rev | sort | rev | grep -v '%' | grep -v ':' | grep -v '\.xn--' > gfwlist.txt.list
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
51
52
53
54
55
56
57
58
59
60
# 保存成python文件,然后执行,IP地址、用户名、账号记得填
import requests
import json

base_url = "http://192.168.7.6:3000"
USERNAME=""
PASSWORD=""
target_ip = '192.168.7.6'

login_url = base_url + "/control/login"
list_url = base_url + "/control/rewrite/list"
add_url = base_url + "/control/rewrite/add"
del_url = base_url + "/control/rewrite/delete"

target_domains = {}
session = requests.Session()
# login
headers = {'Content-Type': 'application/json'}
auth = json.dumps({'name': USERNAME, 'password': PASSWORD})
response = session.request('POST', login_url, headers=headers, data = auth)
assert(response.status_code == requests.codes.ok)

response = session.request('GET', list_url)
assert(response.status_code == requests.codes.ok)

current_list = json.loads(response.text)
file1 = open('backup.list', 'w')
for item in current_list:
target_domains[item['domain']] = True
# do backup
file1.writelines(item['domain']+"\n")
file1.close()

# delete current
index = 0
count = len(target_domains)
for domain in target_domains.keys():
index+=1
print(f"delete {index} of {count}: {domain}")
item = json.dumps({'domain': domain, 'answer': target_ip})
response = session.request('POST', del_url, headers=headers, data = item)
assert(response.status_code == requests.codes.ok)

file1 = open('gfwlist.txt.list', 'r')
lines = file1.readlines()
for line in lines:
domain = line.strip()
target_domains[domain] = True
if not domain.startswith("*."):
target_domains["*."+domain] = True

# add new
index = 0
count = len(target_domains)
for domain in target_domains.keys():
index+=1
print(f"add {index} of {count}: {domain}")
item = json.dumps({'domain': domain, 'answer': target_ip})
response = session.request('POST', add_url, headers=headers, data = item)
assert(response.status_code == requests.codes.ok)
2、部署、配置V2ray代理
这里不过多介绍V2ray是什么以及如何部署服务器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sudo mkdir -p /data/v2ray/config/

wget 'https://code.newnius.com/snippets/Conf/raw/branch/master/v2ray/gateway.json'
# 根据模版修改配置,主要是 proxy.example.com 和 UUID ,共三处位置
# 输入i进入编辑模式;按esc退出编辑模式,然后输入 :wq 这三个字母保存并退出
vim gateway.json

sudo mv gateway.json /data/v2ray/config/

sudo docker run \
--name v2ray-gateway \
-d \
--restart always \
--dns 114.114.114.114 \
--publish mode=host,published=80,target=80 \
--publish mode=host,published=443,target=443 \
--mount type=bind,source=/data/v2ray/config/,target=/etc/v2ray/,readonly \
v2fly/v2fly-core run -config=/etc/v2ray/gateway.json
主要是用到了 V2ray 的 Dokodemo-door(任意门)协议: https://www.v2fly.org/config/protocols/dokodemo.html
其他安装方式可以参考: https://www.v2fly.org/guide/install.html
3、路由器配置 DNS & NAT
根据具体的路由器,将DHCP中的主DNS服务器配置为 192.168.7.6,备DNS服务器维持 0.0.0.0 (即自动获取)。
通常情况下设备会使用主DNS来解析域名,在主dns服务器无法使用的情况下会切换到备DNS服务器,这样的配置可以使得即便在Linux主机掉线的情况下,也会回落到原始的方案,不影响访问大局域网。
另外就是记得路由器里不要开启AP隔离,不然内网各个设备无法互相访问。(不过既然已经可以连接到Linux主机了,大概率不会遇到这个问题,仅作参考)
4、重启路由器或重新连接生效
重启路由器,或者重新连接Wi-Fi使得重新获取.