一个程序员的辩白

16 Jan 2021

frp + trojan 组网提高网络质量

前段时间,家庭网络劣质化的厉害,可能是触碰到了土啬的逆鳞?

当然针对这种情况解决方法无非下面的几种情况:

  • 光猫重新拨号,大概率获得一个新的NAT IP,也许可以满血复活。
  • 换一个代理节点。
  • 用IPLC线路/IPLC转发。
  • 代理套CDN(需要代理软件的支持)。

以上除了最后一种方法其他我都试过。

针对第三点需要特殊说明一下,由于资金的限制,我试过IPLC NAT和IPLC转发,不过感觉不是太稳定,很容易受到友商DDoS照顾,体验会比较差。

针对第四点,最近百度云加速的关于严格控制使用WebSoket协议的通知也使得CDN使用门槛变高。

另外,很多人使用Clouflare CDN来加速访问,其实是不符合其服务条款的。

 

经过我一段时间的折腾,总结出了一个实际操作可行的解决方案

整个解决方案可以浓缩为下图:

frp proxy

其中VPS端运行frps(frp server),NAT device端运行frpc和代理软件,NAT device一般来说是家庭PC机、公司的VM等。

这样VPS和NAT device组成了Peer。

 

当然,上面这种方式并没有解决网络劣质化的问题,一种比较理想的方式是:

  • VPS为国内的云服务器。

  • NAT device为公司VM,并且是专线网络(不过土啬)。

这样本质上是利用云服务器穿透到公司网络转发出去,也即利用公司的网络当跳板,规避流量审查。

不过,第二点并不具备普遍性,可能只有部分互联网从业者有这种条件。

针对没有专线网络的情况,可以考虑使用家庭带宽,在移动设备上的网络QoS可能会好一些。 当然,这种情况没有解决开头说到的问题。

 

本文将演示fatedier/frp + trojan-gfw来实现图上描述的组网方式,其他代理软件原理上是类似的。

Server side setup

# 下载最新版frp
V1=$(curl -sL https://api.github.com/repos/fatedier/frp/releases/latest | grep '"tag_name":' | cut -d'"' -f4)
V2=$(echo $V1 | cut -c2-)
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
AR=$(uname -m | sed 's/^x86_64$/amd64/')
wget "https://github.com/fatedier/frp/releases/download/$V1/frp_${V2}_${OS}_$AR.tar.gz"

tar xf frp_${V2}_${OS}_$AR.tar.gz
cd frp_${V2}_${OS}_$AR

新建frps-trojan.ini

[common]
bind_port = 7000
authentication_method = token
token = dummy_passw0rd

frps监听在云服务器的7000端口,采用了密码认证。

运行frps

./frps frps-trojan.ini

 

Client side setup

客户端的配置稍稍麻烦一点,除了frpc之外,还需要额外配置trojan-gfw

下载并解压frp如前述,不再赘述。

新建frpc-trojan.ini

[common]
server_addr = $VPS_IP
server_port = 7000
authentication_method = token
token = dummy_passw0rd

[trojan-tcp]
type = tcp
remote_port = 443
local_ip = 127.0.0.1
local_port = 1080

[trojan-udp]
type = udp
remote_port = 443
local_ip = 127.0.0.1
local_port = 1080

其中,$VPS_IP为云服务器公网IP,来自VPS frps443端口的流量最终将发送到NAT device的127.0.0.1:1080所在的进程。

运行frpc

./frpc frpc-trojan.ini

安装trojan-gfw

在我们的示例中,需要将trojan绑定(bind)到127.0.0.1:1080

参考trojan-gfw/trojan-quickstart,也可以直接去trojan-gfw/trojan下载。

trojan示例配置文件forward.json

{
    "run_type": "forward",
    "local_addr": "127.0.0.1",
    "local_port": 1080,
    "remote_addr": "$DOMAIN_NAME",
    "remote_port": 443,
    "target_addr": "$DOMAIN_NAME",
    "target_port": 443,
    "password": [
        "$PASSWORD"
    ],
    "log_level": 1,
    "ssl": {
        "verify": true,
        "verify_hostname": true,
        "sni": "",
        "alpn": [
            "h2",
            "http/1.1"
        ],
        "reuse_session": true,
        "session_ticket": false
    },
    "tcp": {
        "no_delay": true,
        "keep_alive": true,
        "reuse_port": true,
        "fast_open": false
    }
}

注意run_type必须是forward,不然路由包无法被正确识别并处理。

其他的按照自己的配置填写即可,forward.json用的是域名解析方式来连接Trojan server,也可以使用IP + SNI的模式,具体参考trojan/config

最后运行trojan即可完成整个组网。

./trojan -c forward.json

然后就可以在终端设备上(比如手机)测试了。

至此也就完成了整个组网的过程啦。

 

为远程办公赋能

(并不是所有公司都会为员工建立Tunnel打通到公司,更多是出于风险的考量。)

上面讲到的方法是将服务器作为跳板,也就是说来自终端用户的请求最终是由我们的Trojan server响应的,而不是NAT device(比如公司的机器)。

一个常见的场景是在家访问公司内部网络,这样需要将公司的网络作为代理响应者,而不是跳板。

(以下操作均在NAT device端完成)

第一步需要设置DNS转发,以正确解析公司内部服务的地址。

将以下配置追加到 frpc-trojan.ini

[dns-tcp]
type = tcp
remote_port = 5353
local_ip = 127.0.0.53
local_port = 53

[dns-udp]
type = udp
remote_port = 5353
local_ip = 127.0.0.53
local_port = 53

如果使用的是Debian/Ubuntu的话,127.0.0.53:53是由NetworkManager生成的聚合DNS地址,可以自动识别到上游真实的DNS,而不需要显式地填入多个地址。

如果不是这种情况的话,请参考/etc/resolv.conf里面给出的值。

第二步是在公司的机器上配置代理服务器,比如ss/trojan/v2 server。

这样公司的服务器就作为了代理的响应者,也就是由公司的网络负责响应你的网络请求。

然后在frpc-trojan.ini追加Proxy server信息:

[company-proxy-tcp]
type = tcp
local_ip = 127.0.0.1
local_port = ...
remote_port = ...
...

[company-proxy-udp]
type = udp
local_ip = 127.0.0.1
local_port = ...
remote_port = ...
...

然后配置下家庭网络,就可以为远程办公赋能啦。🌚

需要注意的是针对以TLS流量为载体的proxy,域名需要绑定NAT VPS的IP,然后利用frp穿透转发到内网(公司/家庭)网络,然后内网的proxy再去验证证书的有效性。

针对透明代理,需要操作iptables,将家庭网络所有请求公司内部网络(LAN)的网段开启NAT转发。

 

注意事项

  • 出于安全的考虑,可以更换frp的端口,而不是使用默认的7000,并设置一个高强度的密码。

  • 也可以考虑frp服务端使用TLS证书加密流量,以提升安全性。

  • 可以在frps.ini设置allow_ports,仅允许frpc绑定指定的端口,详见服务端配置

  • 前述说到,VPS和NAT device组成了Peer,可以在NAT device设置防火墙,针对frpc,只允许来自$VPS_IP的访问。

  • 推荐NAT device一端配置静态IP,这样从家里穿透到公司使用内网服务不用担心IP发生会变化。

    当然,如果你的NAT device部署了暴露在公网的服务,那么可以使用robertdavidgraham/masscan扫描你的机器内网的IP,这样就可以做到动态LAN IP发现。

    (静态IP的问题是如果公司内部的LAN网段发生了变化,可能会导致我们与这台NAT device失去联系)

  • 如果你的云服务器的带宽比较小,可以考虑购买NAT服务器,一般来说有50M以上的带宽速率,另外VPS和NAT device的包路由都在国内,QoS也会比较好。

  • 开启BBR拥塞控制算法,再Optimize the shadowsocks server on Linux,优化两端服务器的链路质量。

  • 为了保证高SLA,记得用systemd来管理frptrojan/ss/v2

  • 如果是在公司内虚拟化集群的VM部署的服务,需要确保你的VM在虚拟化集群重启之后会自动开机,可以参考这个例子

  • 专线网络转发的方法仍然有被审查的风险,请合理并正确地使用。

  • 针对在NAT device上跑的服务(比如trojan),建议将Bind Address设置为127.0.0.1以加强安全性。

  • 从部署难以程度来说,ss应该是最省事的。当然也可以考虑将整个流程写一个Dockerfile来完成部署。

  • 公司内网网段不要和家庭网络的内网网段有冲突(交集),不然可能会由于路由规则导致流量路由到本地内网从而连不上公司内网。

    比如注意VMWare/Virtualbox的内网虚拟网络IP地址范围。

  • 使用落地代理的方式(比如上面的company-proxy),需要注意证书到期的情况。 如果忘记更换证书,可以关闭TLS证书验证,临时登录上去更换证书,另外一个比较好的方式是使用acme.sh托管。

 

最后

结尾说一下本人目前的配置,仅供参考。

  • 入口(VPS)是一台200M速率的NAT主机。
  • 中继(NAT device)是公司Proxmox上创建的一个VM,运行Ubuntu server。
  • 入口和中继节点之间的ping值小于10ms,理论上肯定越近越好。
  • 公司网络是专线。
  • 落地是Azure。
  • Trojan-Igniter连接Google用时500ms附近。

本文受限于作者的水平,可能有描述不准确或错误的地方,请不要吝啬在评论区指出可能存在的问题。🤣

 

参考资料

『原创』Shadowsocks iptables 中继(中转/端口转发) 便捷管理脚本

Optimize the shadowsocks server on Linux

文档 | frp

Config | trojan