题外话

Trojan路由手动配置太难了,折腾15天一边摸索一边记录,很多反复之处。简洁版照做应该很顺,出问题可参考Trojan路由手动配置(摸索版),^F问题关键字。有耐心仔细看可学习调试方法,怎样自定义域名过滤/内外分流

前言

提前打预防针,我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也不说,折腾一天多欲仙欲死……

Trojan路由手动配置(摸索版)基于Trojan配置文档关于透明代理iptables规则设置Trojan透明代理手动配置,选了代码少的DNS on TCP(Trojan透明代理手动配置),实际使用性能问题严重。内存要有数据结构保持TCP连接,网络拥堵或大量并发查询,trojan就会挂(毕竟主流的OpenWRT最大内存才128M)。后面会提到一些优化,没用,还得上UDP。所以才要写改进版。

DNS与分流策略

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还是非常卡……

我决定先实现策略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
    }
}

注意替换域名、密码、证书文件路径,注意run_type不同是natlocal_addr127.0.0.1(这是个大坑)

设置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 '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 cachesize '10000'
        option dnsforwardmax '1000'

因为要通过dnsmasq配置/etc/config/dhcp或命令行设置上游DNS,要用noresolv替换resolvfilelocal/lan/改成127.0.0.1:5353cachesizednsforwardmax本为解决网络拥堵或大量并发查询时DNS on TCP超时,导致trojan进程占内存太多被杀掉,然并卵还得上UDP。

echo "$IPtoTrojanProxy $domain" >> /etc/hosts

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

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

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

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

exit 0

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

scp tproxy $IPtoOpenWRT:/etc/rc.local

iptables重启就没了,把上面的内容保存为tproxy替换OpenWRT的/etc/rc.local,启动就能自动记载。尝试过加执行权限,放到/usr/bin或/root,但/etc/rc.local不调用……

iptables -t nat -N FKCCP
iptables -t mangle -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

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

#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

ip route add local default dev lo table 100
ip rule add fwmark 1 lookup 100
iptables -t mangle -A FKCCP -p udp -d 1.1.1.1 --dport 53 -j TPROXY --on-port 1080 #--tproxy-mark 0x01/0x01
#iptables -t mangle -A OUTPUT -p udp --dport 53 -j MARK --set-mark 1

iptables -t nat -A PREROUTING -p tcp -j FKCCP
#iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 1080
iptables -t mangle -A PREROUTING -j FKCCP
iptables -t mangle -A OUTPUT -p udp -d 1.1.1.1 --dport 53 -j MARK --set-mark 1

exit 0

尝试过代理DNS on UDP,原理也懂点,但无论本地/转发都试过,要么无应答,要么被污染。OpenWRT日志看不到Trojan对DNS on UDP的转发,TPROXY流程很复杂,日志看得晕头转向:DNS on UDP(1.1.1.1)没重定向到1080就发出去了、或不知所踪、或SRC/DST逆转(不知道无应答/被污染还是彻底反了),总之追踪路由/网络编程源码(还是C语言)超出了效费比下限……

据说TPROXY只能应用于PREROUTING链的mangle表,只能透明代理来自内网的UDP流量,对于本机的UDP则无能为力……等于说需要2台路由器或linux主机,一台透明代理Trojan,一台dnsmasq/ChinaDNS作专用DNS……

开p2p下载,trojan在2’/10’内耗尽内存被杀掉,服务端timeout从10’改30″也无济于事(MiR4A峰值load超过17了…)。考虑过supervisor,但supervisor基于python,32M闪存都装不下。busybox编译可选的runit太简陋,monit挺麻烦还要占900+K闪存。可以用以下命令切换(也可以写成alias)。

cat .ssh/id_rsa.pub | ssh $IPtoOpenWRT "sed -i 's/127.0.0.1#5353/119.29.29.29/' /etc/config/dhcp && /etc/init.d/dnsmasq reload"
cat .ssh/id_rsa.pub | ssh $IPtoOpenWRT "sed -i 's/119.29.29.29/127.0.0.1#5353/' /etc/config/dhcp && /etc/init.d/dnsmasq reload"

如果p2p时还想留梯子,可以让transmission/amule启动/退出时,启动trojan并切换firefox代理配置文件。

su - $usr -c "sed -i 's/network.proxy.type\", 0/network.proxy.type\", 1/' .mozilla/firefox/*/prefs.js && cd Downloads/trojan && ./trojan &" && cat .ssh/id_rsa.pub | ssh $IPtoOpenWRT "sed -i 's/127.0.0.1#5353/119.29.29.29/' /etc/config/dhcp && /etc/init.d/dnsmasq reload" && su - $usr -c 'transmission-gtk' && cat .ssh/id_rsa.pub | ssh $IPtoOpenWRT "sed -i 's/119.29.29.29/127.0.0.1#5353/' /etc/config/dhcp && /etc/init.d/dnsmasq reload" && kill `pidof trojan` && su - $usr -c "sed -i 's/network.proxy.type\", 1/network.proxy.type\", 0/' .mozilla/firefox/*/prefs.js"

然而prefs.js不重启firefox没reload方法,只能手动切,多点几下吧……

cat .ssh/id_rsa.pub | ssh $IPToOpenWRT "sed -i 's/127.0.0.1#5353/119.29.29.29/' /etc/config/dhcp && mv /etc/rc.local . && reboot" && su - $usr -c "cd $Path2Trojan && ./trojan &" && su - $usr -c 'transmission-gtk' && cat .ssh/id_rsa.pub | ssh $IPToOpenWRT "sed -i 's/119.29.29.29/127.0.0.1#5353/' /etc/config/dhcp && mv rc.local /etc && reboot" && kill `pidof trojan`

先启动trojan客户端,ChinaDNS换国内DNS/重载dnsmasq;再启动p2p;退出时换回ChinaDNS/重载dnsmasq,关掉trojan客户端。

编译和测试

按目录选择以下包,编译OpenWRT:

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

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

我用letsencrypt颁发的证书90天过期(非3月),每60天自动renew,干脆每天更新一次:

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更好(所以说可能)。

全设置脚本

MiR4A不稳定,p2p下载会挂掉LuCI、连不上wwan、偶尔自动重启。升级因为测速更快,长期使用差别不大。重新编译刷MW4530R,懒得重新设置。注意不同路由/版本,resolv.conf.auto路径可能不同。

ssh-keygen -f /root/.ssh/known_hosts -R 192.168.1.1 && ssh-keygen -f /root/.ssh/known_hosts -R 10.0.0.239 && scp Downloads/trojan/config.json 192.168.1.1:/etc/trojan.json && scp Downloads/trojan/cert.pem 192.168.1.1:/etc/ && scp Documents/deploy/tproxy 192.168.1.1:/etc/rc.local && cat .ssh/id_rsa.pub | ssh 192.168.1.1 "cat > /etc/dropbear/authorized_keys && sed -i -e 's/OpenWrt/MW4530R/' -e 's/UTC/CST-8/' -e '5i\option zonename Asia/Shanghai' /etc/config/system && sed -i 's/192.168.1.1/10.0.0.239/' /etc/config/network && sed -i -e 's/\/lan\//127.0.0.1#5353/' -e 's/resolvfile/noresolv/' -e 's/\/tmp\/resolv.conf.auto/1/' -e '19i\option cachesize 10000' /etc/config/dhcp && echo -e '\n34.92.185.251 pinshu.ren' >> /etc/hosts && sed -i -e 's/0/1/' -e 's/1.0/0.0/' -e 's/.txt//' -e 's/114.114.114.114,8.8.4.4/119.29.29.29,localhost#5300/' /etc/config/chinadns && sed -i -e 's/0/1/' -e 's/1.0/0.0/' -e 's/10/00/' -e 's/8/1/g' /etc/config/dns-forwarder && mv /etc/chinadns_chnroute.txt /etc/chinadns_chnroute && sed -i 's/0/1/' /etc/config/trojan && sed -i -e 's/client/nat/' -e 's/127.0.0.1/0.0.0.0/' -e 's/cert.pem/\/etc\/cert.pem/' /etc/trojan.json" && ssh 192.168.1.1 'passwd root && reboot'

曾设想mwan多线,11n 2×2上限约128M,俩100M wwan就成瓶颈了,但手机只有极少情形,譬如同时升级系统/下载APP/下载离线地图,能用满3线路。电脑p2p下载通过有线连接,要达到1000M的瓶颈需要10×100M线路,实际上wwan很少会超过65M……通常可用的wwan不超仨……当然双/多线HA还是有用的,但对手机银行、京东、淘宝等应用,增加了复杂性。因为只能通过相同的线路登录,使用中线路A变差切换到B就会出问题,而固定线路未必始终可用……

总结

OpenWRT透明代理日常上网没问题,p2p下载DNS on TCP(网络拥堵或大量并发查询)会导致trojan在2’/10’内耗尽内存被杀掉(MiR4A峰值load超过17了…),内存/系统/闪存/CPU局限太多了。这些对电脑根本不是问题(除了能效差),玩到最后都会上软路由,我觉得我不会MIPS>ARM>Intel NANO>Intel移动U,MIPS/ARM高端路由缺乏性价比,技术还落伍。如果我需要WiFi6VR流视频,AX200比2.5G有线网卡便宜。毕竟160MHz的WiFi6峰值1.6G有线千兆已成瓶颈,广域网才普及100M,WiFi6软路由不会长时间运行。这需求有线网太贵了,用NAS俩万兆网卡就超过1600了,618/双11不到1000攒2×32G内存不香吗?