题外话

08年8月买了G1开发Android,因此买了第一个路由器,内置天线百兆LAN的W268R。后来用GoAgent知道了OpenWRT,13年买了千兆WR1041N,迷你WR703N,64M内存的迷你DIR 505,128M带USB的MW4530R……败家有点内疚,京东买WR1041N退货了(刷机后千兆经常重连),刚好W268R没多久摔坏了。虽然普通人很少挪动,没移动部件……拆了没发现哪断了,MW4530R转主力!WR703N虽很小,但再拖电源/线,就不如505适合卫生间信号覆盖了。然后15年WR703N突然点不亮,USB电涌?!…

505定位是旅行(当然现在宾馆无线很普及),但有时难免AP刚好要穿过几个墙角/一条很长的墙,除了卫生间卧室无线信号也弱……所以505一半的时间都有用,其它时间跑reaver本来也挺好,然而大部分AP并不开WPS……

到了2020年,MW4530R信号变弱了,趁618升级MiR4A。很便宜70多,比玩具(除刷机几乎没用过)WR703N还便宜20。当然,128M以下11n仍够用,320M以下WiFi5也不算瓶颈。现在除了北京,最便宜宽带都不超过100M。

网上说小米路由烂的很多。确实刷机难,MiR4A刷砖了3次,AC2100没刷成,模拟拨号成功,就是没反向shell……我通常不会反复尝试相同方法,但刷小米路由属于玄学,最后没砖的反复刷5次成功……新的MiR4A信号强,一个月之后也变弱了。MW4530R从未连不上LuCI。MiR4A开机22天就死机了,重启LuCI也没用,我设置每月1/15号重启,剩2天又死机了,而且电脑有连接无IP出不去(我改成每周日重启)……但实在很便宜(200以内WiFi5千兆刷OpenWRT唯三选MiR4A/红米/小米AC2100,200多唯一R6260还是翻新机),就当主路由备机吧……

本来就不喜欢AC2100,太厚笨,只是轻薄的MiR4A信号比它弱。不过后来知道大神固件几十兆,AC2100(128M)才能玩的起,MiR4A只有16兆闪存……然而,大神、大神除源码组件没任何文档,我也不放心用。

前言

OpenWRT不能直接装Trojan,编译教程网上很多。但对于习惯PP2P/OpenVPN全局代理的网民来说,代理类SS(R)/Trojan是一个大坑。shell系配置为扁平键值对,而JSON键值对/对象后面只要有逗号,就得再跟一个键值对/对象,否则语法错误,服务/客户端都无法启动。服务看日志就会发现问题,而我找不到OpenWRT的日志文件,查状态就是running……LuCI找日志才看到报错,而基于全局代理的经验ping/nslookup google只会更困惑,困难归纳为:

  • JSON苛刻的语法(普通码农都很少手写JSON),改配置容易出错彻底挂掉;
  • OpenWRT日志文件难找,挂了服务状态正常,Trojan也不在shell报错;
  • 代理系梯子,不能用VPN类全局的经验ping/nslookup google检查连接性;

如果下载了客户端,压缩包有个examples文件夹,你就会知道client.config怎么写(注意替换域名、密码、证书文件路径):

{
    "run_type": "client",
    "local_addr": "127.0.0.1",
    "local_port": 1080,
    "remote_addr": "domain.you",
    "remote_port": 443,
    "password": [
        "yourpasswd"
    ],
    "log_level": 1,
    "ssl": {
        "verify": true,
        "verify_hostname": true,
        "cert": "path/to/cert.pem",
        "cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
        "cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
        "sni": "",
        "alpn": [
            "h2",
            "http/1.1"
        ],
        "reuse_session": true,
        "session_ticket": false,
        "curves": ""
    },
    "tcp": {
        "no_delay": true,
        "keep_alive": true,
        "reuse_port": false,
        "fast_open": false,
        "fast_open_qlen": 20
    }
}

然而在OpenWRT+Trojan源码找不到config.json,编译后搜到的(也就是刷机后路由器中的)config.json是服务器类型……境内路由部署Trojan服务意义何在?我用server.config照网上教程删被坑很多次,从最后键值对开始删,前面键值对逗号不删,就无法启动,报错还忒简略……

DNS与分流策略

我的OpenVPN始终离不开hosts文件,自己搭DNS很复杂,一直懒得折腾。几乎只用搜索也没问题,Youtube这种疯狂跳转的不行,今年不得不寻求彻底解决方案。

DNS污染有两大解决思路:

策略A:白名单直接用国内DNS/连国内线路,黑名单用境外加密DNS/连境外线路,其他用ChinaDNS,国内IP连国内线路,国外IP连国内或境外线路。若白名单漏选,ChinaDNS应该可以保证合适的IP(连本地CDN)、连国内线路(有些政府网站屏蔽了境外IP),如果运营商没DNS劫持国内网站;若黑名单漏选,如果运营商DNS劫持你看广告(国内IP),那你就去不了目标网站。所以要看具体情况:

  • 如果你在境外上学/在外企工作,脱离中国社会,白名单之外全部出国
  • 如果没这么“国际化”/西化,那你要权衡连不上国外,还是连不上国内更不利(维护更麻烦)
  • 同样的,经过黑名单/白名单/ChinaDNS筛选后,可能没被封的国外IP连国内还是境外线路,也要权衡速度和连通性,如果目标线路不拥堵,直连肯定比绕圈快,但如果黑名单漏选,你会连不上

这里的连通性当然说的是“一次设置智能梯子”,尽量少维护,你当然可以手动修改黑名单/白名单/ChinaDNS(判断为国外IP连国内还是境外线路)。

ChinaDNS可补充黑名单漏选的情况,但如果黑名单漏选的域名被运营商DNS劫持就没办法。反过来单独用ChinaDNS更容易被劫持,黑名单没漏选的情况下,对ChinaDNS也是一种补充。而白名单更适合单独使用,查完“国内常用的域名表”还要连国内DNS,比只用ChinaDNS还多查一次表。这个表不大,但增加了复杂性和更新/维护的成本。

策略B:黑名单用境外DNS/连境外线路,其他用ChinaDNS判断为国内IP连国内线路,否则用境外DNS/连境外线路我看到有人同时用了ChinaDNS+ChinaList,不明白原因,国内网站解析到国外CDN是因为部署ChinaDNS到VPS了?

策略C:用ChinaDNS判断为国内IP连国内线路,否则用境外DNS/连境外线路宽带为联通/电信,而非宽带通/歌华等二级运营商,DNS劫持很少见。

透明代理

倘若你用过代理类梯子,就知道需要设置系统或浏览器,应用(比如浏览器)很清楚你在用代理。而透明代理工作在底层,应用(比如浏览器)对其一无所知(也就不用麻烦每个都设置)。如果你用惯了全局类VPN,会发现socks代理每个应用都要设置,而并非所有应用都支持socks代理。我在ubuntu设置了apt、3个firefox(各用于noscript/gifblock/java plugin),github update还是非常卡……

操作指导网上很多,深入浅出讲原理的很少。我们以Trojan配置文档关于透明代理iptables规则设置为例进行学习。

不难从前一节域名解析策略推测出,对国内/境外上网分流,需要对流量设置规则。而在操作层面会具体到每一个数据包(网络传输内容的数据分片),这些规则按执行顺序划分的列表称之为(规则集),这些链按功能划分为(链集)。iptables包含5个(功能)表,raw/filter(用于防火墙)/nat(网络地址转换,例如端口转发)/mangle(修改数据包)/security。

# Create new chain
iptables -t nat -N SHADOWSOCKS
iptables -t mangle -N SHADOWSOCKS

# Ignore your shadowsocks server's addresses
# It's very IMPORTANT, just be careful.
iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN

# Ignore LANs and any other addresses you'd like to bypass the proxy
# See Wikipedia and RFC5735 for full list of reserved networks.
# See ashi009/bestroutetb for a highly optimized CHN route list.
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

用户自定义了一个链/规则集SHADOWSOCKS,每一条规则中,-j(–jump)指定了满足条件的数据包接下来应用的目标/下一条规则目标/下一条规则可以是自定义链/规则集,或者内置的链/规则集,例如:ACCEPT(放行数据包,默认)、DROP(丢弃数据包)、RETURN(停止应用该链/规则集)、REJECT(丢弃数据包,返回错误包)、REDIRECT(重定向数据包到指定端口)、TPROXY(标记目标端口数据包并导向指定端口)。

ACCEPTRETURN的区别,相当于编程循环的continue和break,只要发向内网IP和代理服务器IP的数据包不会再经过SHADOWSOCKS链/规则集处理。

除了代理服务器和内网IP,也可以RETURN全部的国内IP段,实现内外分流。

# Anything else should be redirected to shadowsocks's local port
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345

这里将所有前面没RETURN的TCP流量导向代理服务器,没必要,你不想电骡/torrent从韩国/呆弯/夯康的下载/上传消耗服务器流量吧?53/80/443可满足大部分需求,但Youtube或其它你需要的应用,可能要开一些非标准端口。当网站不能正常使用,可通过HttpFox查看哪些端口连不上,再增加对这些端口的重定向。

# Add any UDP rules
ip route add local default dev lo table 100
ip rule add fwmark 1 lookup 100
iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 12345 --tproxy-mark 0x01/0x01

这里将本地DNS查询(UDP 53)加上透明代理标记,重定向到代理客户端,由代理客户端执行DNS策略。

# Apply the rules
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
iptables -t mangle -A PREROUTING -j SHADOWSOCKS

这里以ShadowSocks为例,自定义了一个SHADOWSOCKS链/规则集,当然也可以指定其它名字(比如TROJAN)。iptables其实很复杂,这里只求看懂几条命令。

网上有一个Trojan透明代理手动配置,不过用的黑名单策略:黑名单中的域名解析/流量和谷歌DNS查询重定向到代理客户端。因为只编译了dns-forwarder,只接受谷歌DNS的查询结果,没完全实现内外分流。尽管只定义黑名单域名走境外代理,但对于出海的中国互联网企业(阿里/京东/抖音……),也会因为谷歌DNS返回境外的IP而上了一个用不上的网站。其价值在于可以参考实现策略B(黑名单+ChinaDNS)。当然如果你在深圳,VPS在中国香港,内容/延迟差别不大(高峰期有可能被限速)。此外,如果黑名单未及时收录,即使通过正确IP也可能上不了(封IP)。

我决定先实现策略C(only ChinaDNS),需要先编译ChinaDNSDNS-Forwarder for OpenWRT(强烈建议把nano也加入编译,vi反复i/Esc实在太反人性)。据说ChinaDNS-NG维护更好更新,但没提OpenWRT,感觉不易上手。编译好刷机完,ssh登录,先设置Trojan:nano /etc/trojan.json

{
    "run_type": "nat",
    "local_addr": "127.0.0.1",
    "local_port": 1080,
    "remote_addr": "domain.you",
    "remote_port": 443,
    "password": [
        "yourpasswd"
    ],
    "log_level": 1,
    "ssl": {
        "verify": true,
        "verify_hostname": true,
        "cert": "path/to/cert.pem",
        "cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
        "cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
        "sni": "",
        "alpn": [
            "h2",
            "http/1.1"
        ],
        "reuse_session": true,
        "session_ticket": false,
        "curves": ""
    },
    "tcp": {
        "no_delay": true,
        "keep_alive": true,
        "reuse_port": false,
        "fast_open": false,
        "fast_open_qlen": 20
    }
}

跟前面客户端配置client.config只有run_type不同是nat,注意替换域名、密码、证书文件路径。

设置ChinaDNS:mv /etc/chinadns_chnroute.txt /etc/chinadns_chnroute && nano /etc/config/chinadns

config chinadns
        option enable '1'
        option bidirectional '1'
        option chnroute '/etc/chinadns_chnroute'
        option addr '0.0.0.0'
        option port '5353'
        option server '119.29.29.29,localhost#5300'

开启双向过滤,则丢弃境外DNS返回的国内IP,未必离你最近。

设置DNS-Forwarder:nano /etc/config/dns-forwarder

config dns-forwarder
        option enable '1'
        option listen_addr '0.0.0.0'
        option listen_port '5300'
        option dns_servers '1.1.1.1'

我选择Cloudflare,因为真正的自由主义对监控资本主义(谷歌)也充满警惕,在西方反乌托邦影视剧中大公司比威权政府更邪恶。不过Cloudflare也是最快的详细评测在此

设置dnsmasq:nano /etc/config/dhcp

config dnsmasq
        option domainneeded '1'
        option boguspriv '1'
        option filterwin2k '0'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option nonegcache '0'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option nonwildcard '1'
        option localservice '1'

以上默认配置高亮为与ChinaDNS和DNS-Forwarder 的设置示例不一样的部分。大部分留着没问题,authoritative深入看手册。因为要通过dnsmasq配置/etc/config/dhcp或命令行设置上游DNS,要用noresolv替换resolvfilelocal/lan/改成127.0.0.1:5353 ,最后加nohosts(费这么大劲就为了永别/etc/hosts),ipset(每次换节点不用改IP)。改2加2。

config dnsmasq
        option domainneeded '1'
        option boguspriv '1'
        option filterwin2k '0'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '127.0.0.1#5353'
        option domain 'lan'
        option expandhosts '1'
        option nonegcache '0'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option noresolv '1'
        option nonwildcard '1'
        option localservice '1'
        option nohosts '1'
        list ipset 'domain.you'

ChinaDNS在UDP 5353提供纯净的DNS,需要通过境外DNS将污染过滤;而现在从境外DNS无论UDP还是TCP查询都会被DROP/REJECT,因此需要通过DNS-Forwarder在5300提供UDP转TCP的DNS,最后DNS on TCP通过iptables重定向到代理Trojan发出。

此命令换节点/IP就得手动修改,嫌麻烦:

# Ignore your shadowsocks server's addresses
# It's very IMPORTANT, just be careful.
iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN

可以用dnsmasq+ipset实现iptables对代理服务器RETURN。dnsmasq在DNS时匹配指定域名集,就把其IP存在ipset集,这样iptables就可以对这个ipset包含的全部IP匹配和处理。这样换节点、变IP可以自动对代理服务器RETURN

iptables规则设置示例是个简易的透明代理,本地DNS和全部TCP流量都重定向到代理,没内外分流/本地CDN加速;Trojan透明代理手动配置用黑名单策略没完全实现内外分流,如果黑名单未及时收录,即使通过正确IP也可能上不了(封IP)。前节ChinaDNS/DNS-Forwarder已经实现了DNS策略,所以这里比iptables规则设置示例简单了很多:

iptables -t nat -N FKCCP

ipset -N private iphash
iptables -t nat -A FKCCP -m set --match-set private dst -j RETURN
iptables -t nat -A FKCCP -d 0.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 10.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 127.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 169.254.0.0/16 -j RETURN
iptables -t nat -A FKCCP -d 172.16.0.0/12 -j RETURN
iptables -t nat -A FKCCP -d 192.168.0.0/16 -j RETURN
iptables -t nat -A FKCCP -d 224.0.0.0/4 -j RETURN
iptables -t nat -A FKCCP -d 240.0.0.0/4 -j RETURN

iptables -t nat -A FKCCP -p tcp -m multiport --dports 53,80,443 -j REDIRECT --to-ports 1080

iptables -t nat -A PREROUTING -p tcp -j FKCCP

编译和测试

默认编译的dnsmasq不包含ipset模块,需编译dnsmasq-full(默认含ipset模块)。MiR4A/AC2100尚无稳定版(不能opkg install),选以下模块(根据目录查找),切记取消勾选默认dnsmasq(与dnsmasq-full只能二选一)

Base/dnsmasq-full
LuCI
Network/Firewall/iptables-mod-nat-extra
Network/ChinaDNS,dns-forwarder,ipset,trojan
Utilities/Editors/nano

OpenWRT日志在LuCI>Status>System Log看到类似于(^F查找trojan)的以下内容,就表示Trojan代理成功运行:

Wed Aug  5 19:49:10 2020 daemon.err trojan[1964]: [2020-08-05 19:49:10] [WARN] trojan service (nat) started at 127.0.0.1:1080

ChinaDNS/DNS-Forwarder配置很简单,没JSON苛刻的语法,一次过:

root@MiR4A:~# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 0.0.0.0:www             0.0.0.0:*               LISTEN      
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN      
tcp        0      0 :::www                  :::*                    LISTEN      
tcp        0      0 :::ssh                  :::*                    LISTEN      
udp        0      0 0.0.0.0:5300            0.0.0.0:*                           
udp        0      0 0.0.0.0:mdns            0.0.0.0:*                           
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     STREAM     LISTENING       1024 /var/run/ubus.sock

5300为DNS-Forwarder,mdns(Multicast DNS,与前面www/ssh类似标准端口)即5353,为ChinaDNS。netstat只确保ChinaDNS/DNS-Forwarder运行,ChinaDNS只执行过滤DNS污染的逻辑,DNS-Forwarder只提供UDP转TCP的DNS,iptables则承担最关键DNS on TCP on Trojan,以保证可信的DNS:

root@MiR4A:~# iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 1080
root@MiR4A:~# iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 1080
root@MiR4A:~# nslookup www.google.com 127.0.0.1#5353
Server:		127.0.0.1
Address:	127.0.0.1#5353

Name:      www.google.com
Address 1: 172.217.160.100
Address 2: 2001::8079:926b

对比Trojan文档关于透明代理iptables规则设置Trojan透明代理手动配置,会发现Trojan文档推荐配置修改UDP 53,重定向到代理服务完成DNS,而Trojan透明代理手动配置则通过DNS-Forwarder将DNS on UDP转为DNS on TCP,再重定向给代理服务完成DNS。如果将DNS on TCP视为和80/443的HTTP/HTTPS(on TCP)一样的数据包,只有PREROUTINGOUTPUT,就没有过滤DNS污染的效果。

root@MiR4A:~# nslookup www.google.com
Server:		8.8.8.8
Address:	8.8.8.8#53

*** Can't find www.google.com: Parse error
Name:      www.google.com
Address 1: 69.63.190.26

运营商DNS有时候会挂,以前在wwan设置了custom DNS。虽然会被污染,1.1.1.1根本不解析。删掉8.8.8.8再试就正常:

root@MiR4A:~# nslookup www.google.com
Server:		127.0.0.1
Address:	127.0.0.1#53

Name:      www.google.com
Address 1: 172.217.19.67
Address 2: 2001::ae24:c4f2

有时候会出现:

root@MiR4A:~# nslookup www.google.com
Server:		127.0.0.1
Address:	127.0.0.1#53

*** Can't find www.google.com: No answer
Name:      www.google.com
Address 1: 2001::1f0d:500f
root@MiR4A:~# nslookup www.google.com 127.0.0.1#5353
Server:		127.0.0.1
Address:	127.0.0.1#5353

*** Can't find www.google.com: No answer
Name:      www.google.com
Address 1: 2001::1f0d:4a11

通过LuCI的Status>System Log检查Trojan/ChinaDNS都正常运行,重定向DNS on TCP要用5~9″才返回区区约100字节,等一会正常了。但再等一会儿又不正常了,大部分时间都不正常,境外域名全都连不上:

Thu Aug  6 11:19:49 2020 daemon.err trojan[1885]: [INFO] 192.168.10.55:58608 forwarding to 1.1.1.1:53 via domain.you:443
Thu Aug  6 11:19:50 2020 daemon.err trojan[1885]: [ERROR] 192.168.10.55:58608 cannot resolve remote server hostname domain.you: Host not found (non-authoritative), try again later
Thu Aug  6 11:19:50 2020 daemon.err trojan[1885]: [INFO] 192.168.10.55:58608 disconnected, 0 bytes received, 35 bytes sent, lasted for 5 seconds

形成了死锁,对代理服务DNS要通过代理服务解析成IP才能进行代理服务DNS……

ChinaDNS机制是国内DNS若返回化外IP则DROP,等境外DNS返回。如果路由器刚重启dnsmasq没来及缓存,你马上设置iptables重定向境外DNS on TCP到代理服务,境内DNS来不及伪装成境外DNS返回代理服务IP就锁死DNS……

ChinaDNS/DNS-Forwarder只要设置了iptables重定向境外DNS on TCP就能正常运行,因为测试前dnsmasq已经被代理服务客户端对代理服务DNS缓存了代理服务的IP,而整合dnsmasq再重启破坏了这个前提。

Trojan透明代理手动配置基于dnsmasq在DNS时匹配指定域名集,就把其IP存在ipset集,这样iptables就可以对这个ipset包含的全部IP匹配和处理,因为采用了策略A(黑名单),没采用ChinaDNS对国内DNS返回的化外IP直接DROP,所以dnsmasq确保会缓存一份国内DNS查询的结果,若在黑名单上会被后返回的境外DNS on TCP查询结果替代。而对于策略C(only ChinaDNS),dnsmasq-full(with ipset support)要先DNS存ipset,再根据ipset对代理服务RETURN,用dnsmasq+ipset实现iptables对代理域名RETURN,除非ChinaDNS改进对国内DNS返回的化外IP直接DROP

策略C只比策略A对黑名单多查一次国内DNS,毫秒级而已,而境外代理至少几十/几百毫秒延迟。策略A还有黑名单未及时收录,即使通过正确IP也可能上不了(封IP),连通性不好的问题。

LuCI
Network/ChinaDNS,dns-forwarder,trojan
Utilities/Editors/nano

如果路由器空间紧张(MiR4A可以省64K:),可取消打包Base/dnsmasq-full(切记要勾选Base/dnsmasq)、Network/Firewall/iptables-mod-nat-extra、Network/ipset,很少需要经常换代理服务节点/IP。以前在vultr达拉斯5年只换2次IP,没必要为省这点修改/维护,浪费更多时间(已经浪费很多时间了:)。

root@MiR4A:~# iptables -t nat -A PREROUTING -d $IPtoTrojanProxy -j RETURN
root@MiR4A:~# iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 1080
root@MiR4A:~# iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 1080
root@MiR4A:~# nslookup www.google.com 127.0.0.1#5353
Server:		127.0.0.1
Address:	127.0.0.1#5353

*** Can't find www.google.com: No answer
Name:      www.google.com
Address 1: 1949::1967:2020

还是不解析代理服务……ChinaDNS对国内DNS返回的化外IP直接DROP,而非替换太反人性了!不能直接改/etc/trojan.json,因为证书绑定了域名(地址改ip会报错),只能改hosts和dnsmasq:

echo "$IPtoTrojanProxy $domain" >> /etc/hosts
sed -i -e '/nohosts/d' -e '/ipset/d' /etc/config/dhcp

至此域名解析策略C终于完结了……

root@MiR4A:~# nslookup www.google.com
Server:		127.0.0.1
Address:	127.0.0.1#53

Name:      www.google.com
Address 1: 216.58.200.68
Address 2: 2001::c710:9eb6

复杂的3层DNS(dnsmasq/ChinaDNS/DNS-Forwarder)过滤都成功了,而且DNS on TCP也REDIRECT成功了,关键就一句REDIRECT还不简单吗?然而就上不了谷歌,那照猫画虎加一句OUTPUT

iptables -t nat -N FKCCP

iptables -t nat -A FKCCP -d $IPtoTrojanProxy -j RETURN
iptables -t nat -A FKCCP -d 0.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 10.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 127.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 169.254.0.0/16 -j RETURN
iptables -t nat -A FKCCP -d 172.16.0.0/12 -j RETURN
iptables -t nat -A FKCCP -d 192.168.0.0/16 -j RETURN
iptables -t nat -A FKCCP -d 224.0.0.0/4 -j RETURN
iptables -t nat -A FKCCP -d 240.0.0.0/4 -j RETURN

iptables -t nat -A FKCCP -p tcp -m multiport --dports 80,443 -j REDIRECT --to-ports 1080

iptables -t nat -A PREROUTING -p tcp -j FKCCP
iptables -t nat -A OUTPUT -p tcp -j FKCCP

还是上不了,而且看日志trojan只收到转发DNS on TCP。几十个网页看得欲仙欲死,文档惜字如金,一图胜千言还是看不懂。最关键内网在哪外网在哪?此图进出口没问题,但区分内外网是基础。

不过也非自愿明白了PREROUTINGOUTPUT的区别:内网进/出路由的流量。所以重定向DNS on TCP不需要PREROUTING。DNS标准也支持TCP,但通常只有报文长度超过UDP最大512字节,或域名服务器之间同步才用到。内网DNS皆UDP,根本不调用PREROUTING。如果调用了PREROUTING,复杂的3层DNS(dnsmasq/ChinaDNS/DNS-Forwarder)过滤就失效了,CDN加速/内外分流都白折腾了。

#iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 1080
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 1080

清楚这并不够,还只有DNS正常……折腾一天多总算用日志解决了:

#iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 1080
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 1080

iptables -t nat -N FKCCP
#iptables -t nat -A FKCCP -j ACCEPT

iptables -t nat -A FKCCP -d $IPtoTrojanProxy -j RETURN
iptables -t nat -A FKCCP -d 0.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 10.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 127.0.0.0/8 -j RETURN
iptables -t nat -A FKCCP -d 169.254.0.0/16 -j RETURN
iptables -t nat -A FKCCP -d 172.16.0.0/12 -j RETURN
iptables -t nat -A FKCCP -d 192.168.0.0/16 -j RETURN
iptables -t nat -A FKCCP -d 224.0.0.0/4 -j RETURN
iptables -t nat -A FKCCP -d 240.0.0.0/4 -j RETURN

iptables -t mangle -A INPUT -p tcp -j LOG --log-prefix "mangle "
iptables -t nat -A FKCCP -p tcp -j LOG --log-prefix "before "
#iptables -t nat -A FKCCP -p tcp -j REDIRECT --to-ports 1080
#iptables -t nat -A FKCCP -p tcp -m multiport --dports 53,80,443 -j REDIRECT --to-ports 1080
iptables -t nat -A FKCCP -p tcp -m multiport --dports 80,443 -j REDIRECT --to-ports 1080
iptables -t nat -A FKCCP -p tcp -j LOG --log-prefix "after "
iptables -t mangle -A OUTPUT -p tcp -j LOG --log-prefix "MANGLE "

iptables -t nat -A PREROUTING -p tcp -j FKCCP
#iptables -t nat -A OUTPUT -p tcp -j FKCCP
#iptables -t nat -A PREROUTING -p tcp -s 10/8 -j FKCCP
#iptables -t nat -A POSTROUTING -p tcp -s 10/8 -j MASQUERADE

原来参考的Trojan透明代理手动配置端口从127.0.0.1改到了0.0.0.0却没有标注,而Trojan配置文档默认端口为127.0.0.1,因为没标注没注意就没改。PREROUTING重定向127.0.0.1:1080127.0.0.1只有路由器的进程能访问(环回地址不经过物理端口),非自愿被鞭策复习重定向(要客户端重新请求)和转发(代发)的区别……大部分文档都写转发,Trojan透明代理手动配置漏这一句话,坑我一天多……

root@MiR4A:~# logread | grep 205
Fri Aug 7 19:49:67 2020 kern.warn kernel: [ 1063.956423] before IN=br-lan OUT= MAC=54:48:e6:a8:a0:00:00:d8:61:a6:a7:72:08:00 SRC=10.0.0.205 DST=172.217.20.20 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=43172 DF PROTO=TCP SPT=54698 DPT=443 WINDOW=64240 RES=0x00 SYN URGP=0
Fri Aug 7 19:49:67 2020 kern.warn kernel: [ 1063.990896] mangle IN=br-lan OUT= MAC=54:48:e6:a8:a0:00:00:d8:61:a6:a7:72:08:00 SRC=10.0.0.205 DST=10.0.0.235 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=43172 DF PROTO=TCP SPT=54698 DPT=1080 WINDOW=64240 RES=0x00 SYN URGP=0
Fri Aug 7 19:49:67 2020 kern.warn kernel: [ 1064.029443] MANGLE IN= OUT=br-lan SRC=10.0.0.235 DST=10.0.0.205 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=1080 DPT=54698 WINDOW=0 RES=0x00 ACK RST URGP=0

127.0.0.1改成0.0.0.0127.0.0.1改成0.0.0.0127.0.0.1改成0.0.0.0

{
    "run_type": "nat",
    "local_addr": "0.0.0.0",
    "local_port": 1080,
    "remote_addr": "domain.you",
    "remote_port": 443,
    "password": [
        "yourpasswd"
    ],
    "log_level": 1,
    "ssl": {
        "verify": true,
        "verify_hostname": true,
        "cert": "path/to/cert.pem",
        "cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
        "cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
        "sni": "",
        "alpn": [
            "h2",
            "http/1.1"
        ],
        "reuse_session": true,
        "session_ticket": false,
        "curves": ""
    },
    "tcp": {
        "no_delay": true,
        "keep_alive": true,
        "reuse_port": false,
        "fast_open": false,
        "fast_open_qlen": 20
    }
}

如果TCP流量全重定向,测速成绩接近浏览器socks代理。如果只重定向80/443,测速会很差,实际使用能到16~25M/s。

P2P晚上速度快,白天都要用网开的少,看你嫌不嫌麻烦每天(自动)切换。比如8~22重定向全部TCP流量,夜里重定向80/443/…

#!/bin/bash
iptables -t nat -N FKCCP

iptables -t nat -A FKCCP -d $IPtoTrojanProxy -j RETURN
iptables -t nat -A FKCCP -d 0/8 -j RETURN
iptables -t nat -A FKCCP -d 10/8 -j RETURN
iptables -t nat -A FKCCP -d 127/8 -j RETURN
iptables -t nat -A FKCCP -d 169.254/16 -j RETURN
iptables -t nat -A FKCCP -d 172.16/12 -j RETURN
iptables -t nat -A FKCCP -d 192.168/16 -j RETURN
iptables -t nat -A FKCCP -d 224/4 -j RETURN
iptables -t nat -A FKCCP -d 240/4 -j RETURN

date && while read block; do
	iptables -t nat -A FKCCP -d $block -j RETURN
done < /etc/chinadns_chnroute && date

#iptables -t nat -A FKCCP -p tcp -j REDIRECT --to-ports 1080
iptables -t nat -A FKCCP -p tcp -m multiport --dports 80,443 -j REDIRECT --to-ports 1080

iptables -t nat -A PREROUTING -p tcp -j FKCCP
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 1080

至此内外分流终于完结了……

while逐行读兲朝IP网段并RETURN很慢(MiR4A:10’23”),别急躁以为出错取消/重启。通常都卡在IO,但MT7621(MIPS)真慢,就算把chnroute写成iptables.sh上传到/tmp(RAM)也耗时10’29″……可以把chnroute分割成4段,4线程同时执行,但得上4把锁,后边的重定向等4个锁文件删除才执行,没必要。就算每天重启,夜里或午餐,还没10分钟空闲嘛。如果路由器很稳定,一年都执行不了一次。

chmod u+x tproxy && scp tproxy $IPtoOpenWRT:/usr/bin/ && ssh $IPtoOpenWRT

iptables重启就没了,把上面的内容保存为tproxy,加执行权限,scp到路由,重启自动运行:

root@MiR4A:~# nano /etc/rc.local

# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.
tproxy
exit 0

我用letsencrypt颁发的证书90天过期(非3月),只能每俩月(初凌晨3:01)续一次(服务器3点renew):

yuangg@picasso:~$ echo "1 3 1 */2 * scp pinshu.ren:/etc/letsencrypt/archive/$domain/cert1.pem client/path/cert.pem && scp client/path/cert.pem root@$IPtoOpenWRT:/etc/" | crontab -

然而letsencrypt每60天自动renew,crontab太难写,干脆每天更新一次:

yuangg@picasso:~$ echo "32 21 * * * scp $domain:/etc/letsencrypt/live/$domain/cert.pem client/path/ && scp client/path/cert.pem root@$IPtoOpenWRT:/etc/" | crontab -

我的letsencrypt每60天21:31自动renew,你哪天梯子坏了服务器看一下,当然撑到凌晨3点renew一次,能保证以后都在凌晨更新,一点也不影响上网。

策略C实际使用有域名无法解析,比如著名技术博客阮一峰,DNS-Forwarder可以解析出11个日本IP,ChinaDNS/dnsmasq就不行,可能还需要黑名单助攻。黑名单不能直接查阮一峰在不在上面,不好说改进ChinaDNS/换ChinaDNS-NG,还是策略B更好(所以说可能)。

总结

罗嗦了半天,只为理解掌握大部分配置,可以自由修改(可见自由在于掌握了多少信息,否则只是自以为没被操控)。当然,你可以花钱买现成,也可以省心刷大神固件,还可以照葫芦画瓢,但出了问题无法维护,也无法优化。大多数不开机/反复自动关机,只需要换主板电池/清理内存插槽即可,小白却只能换掉整台电脑。

从7.25到8.8很多反复之处,相比照抄版的教程可以自定义域名过滤/内外分流,熟悉调试方法/日志。有空再写一个简洁改进版。15天经历5个大坑:

  1. Trojan客户端:JSON语法很苛刻/OpenWRT看日志不容易/status总是running不报错
  2. OpenWRT编译:多线程容易死锁出错/停滞,单线程就算开电驴,慢但肯定成功
  3. ipset:并不省维护,如果不需要黑名单助攻,划不来折腾
  4. ChinaDNS:对DNS过滤太死板,导致代理服务DNS死锁……
  5. Trojan透明代理手动配置:不标注127.0.0.1改成0.0.0.0也不说,折腾一天多欲仙欲死……