Featured image of post 家庭网络无公网 IPv4 地址异地无感知远程访问家中服务的一个解决方案(NATMap+OpenWrt+Surgio+GitHub Action+Gist+Surge/Stash/Clash)

家庭网络无公网 IPv4 地址异地无感知远程访问家中服务的一个解决方案(NATMap+OpenWrt+Surgio+GitHub Action+Gist+Surge/Stash/Clash)

题图:https://unsplash.com/photos/JfknhSgANFQ

前提,如果 IPv6 足够普及,那么这篇文章就不需要了。

前提,如果你的家庭网络有公网 IPv4 地址,那么这篇文章也不需要了。

可惜,我家的网络没有公网 IPv4 地址,同时 IPv6 的普及率也不高,所以有了这篇文章。

思路

如果家中有公网 IPv4 地址或者 IPv6 地址并且当前网络环境支持 IPv6,可以在家中架设一个 VPN 服务,配置家中网络的网段通过该 VPN 访问即可。

没有公网 IPv4 地址的情况下, 解决如何从外网访问到该 VPN 服务即可。

最终结果是通过 Surge/Stash/Clash 等客户端连接到家中的 VPN 服务,然后通过该 VPN 访问家中的网络。

用到的工具

  1. NATMap - 用于打洞并得知公网 IP 和端口,同时可以在端口更新时执行脚本。
  2. OpenWrt - 路由器固件,用于配置防火墙规则,转发数据,同时可以运行 NATMap。
  3. Surgio - 用于生成 Surge/Stash/Clash 配置文件,期中包含了 NATMap 返回的公网 IP 和端口。
  4. Github Action - 在配置更新时运行 Surgio,生成配置文件。
  5. Gist - 用于存放配置文件。Surgio 生成的配置文件会自动提交到 gist。
  6. Surge/Stash/Clash - 使用 gist 中最新的配置文件连接到家中的 VPN 服务。

实现

首先在家中架设一个 VPN 服务,我用的 Trojan-Go,因为我要和其他类型的代理如 Shadowsocks 同时使用,所以我选择了 Trojan-Go,传统 VPN 如 OpenVPN 不好做到这一点。

假设该 trojan-go 服务的 IP 地址为 192.168.1.152,端口为 12879。

在局域网中运行 NATMap,作用是打洞并得知公网 IP 和端口。在端口更新时,更新路由器防火墙的转发规则。这样就可以从外网访问到家中的 VPN 服务了。

运行命令如下:

1
natmap -s 52.50.47.4 -h qq.com -b 2125 -e /path/to/update.sh

-s 是 stun 服务器,用于打洞,可以得到公网 IP 和端口。 -h -b 是 NATMap 用于维持连接的服务器,可以是任意一个可以访问的服务器,NATMap 会不断向该服务器发送数据以维持连接。 -e 是当端口更新时,执行的脚本。

脚本如下:

 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
#!/bin/sh

# NATMap
protocol=$5
inner_port=$4
outter_ip=$1
outter_port=$2
ip4p=$3

echo "[Script] - Trojan NATMap: ${protocol} ${inner_port} -> ${outter_ip}:${outter_port}"


# ipv4 redirect
uci set firewall.redirecttrojanv4=redirect
uci set firewall.redirecttrojanv4.name='Trojan'
uci set firewall.redirecttrojanv4.proto='tcp'
uci set firewall.redirecttrojanv4.src='wan'
uci set firewall.redirecttrojanv4.dest='lan'
uci set firewall.redirecttrojanv4.target='DNAT'
uci set firewall.redirecttrojanv4.src_dport="${inner_port}"
uci set firewall.redirecttrojanv4.dest_ip="192.168.1.152"
uci set firewall.redirecttrojanv4.dest_port="12879"
# reload
uci commit firewall
/etc/init.d/firewall reload

假设 NATMap 返回的外网 IP 和端口为 123.1.1.1 和 12345,那么在访问 123.1.1.1:12345 时,对于路由器来说,相当于访问 2125(NATMap 监听的端口),然后由于脚本中的防火墙配置,数据会被路由器转发到 192.168.1.152:12879,即 trojan-go 服务,这样就可以从外网访问到家中的 VPN 服务了。

NATMap 通常会是一个常驻进程,当重新拔号或者运营商更换 IP 时,NATMap 会自动更新端口,然后执行脚本更新防火墙规则。

现在能通过 IP 和端口访问 trojan 了,但是我们不能每次都去查看最新 IP 和端口并修改配置文件吧,所以我们需要一个自动化的方案。

所以要解决两个问题:

  1. 如何得到最新的 IP,通常有域名的话,配一个 DDNS 客户端即可。
  2. 如何得到最新的端口,这个就比较麻烦了。

下面重点介绍第二个问题。

自动更新端口

假设 Surgio 当前配置如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
'use strict';

module.exports = {
  type: 'custom',
  nodeList: [
    {
      type: 'trojan',
      nodeName: 'home-trojan-v4',
      hostname: 'home-gateway-v4-d595c.ahh.com',
      port: 4617, //dynamic port
      password: 'password',
      sni: 'home-gateway-v4-d595c.ahh.com', // 可选
      alpn: ['http/1.1'], // 可选
      skipCertVerify: false, // 可选
      'udp-relay': true, // 可选
      tls13: true, // TLS 1.3
    }
  ],
};

在 NATMap 更新端口时,执行脚本,修改 Surgio 配置文件,用如下命令

1
sed -i '/dynamic/ c\      port: '"$new_port"', //dynamic port' ./provider/home.js

dynamic port 关键字用于匹配,$new_port 是 NATMap 返回的新端口。

更新后,通过 git 提交到 Github,Github Action 会自动运行 Surgio,生成 Surge/Stash/Clash 配置文件,然后提交到 Gist

Gist 文件可以通过固定的 URL 访问,所以 Surge/Stash/Clash 可以通过该 URL 访问到最新的配置文件。

比如 https://gist.github.com/EkkoG/20a52db0169c4a4769689521b1c5500e

其固定 URL 为 https://gist.githubusercontent.com/EkkoG/20a52db0169c4a4769689521b1c5500e/raw/clash_example.yaml 还可以加上代理 https://ghproxy.com/https://gist.githubusercontent.com/EkkoG/20a52db0169c4a4769689521b1c5500e/raw/clash_example.yaml

这里可以选择将 Surgeio 放在 NATMap 所在的机器上,这样可以直接修改 Surgeio 配置文件,也可以选择将 Surgeio 放在其他机器上,我是放在另一台机上通过 SSH 执行修改 Surgeio 配置文件的命令。

最后通过 Clash 的 provider 功能,可以设置一个较短的时间,以得到最新的配置文件。

相关配置精简如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
proxy-providers:
  gohome:
    type: http
    url: http://ghproxy.ahh.com/https://gist.github.com/ekkog/20a52db0169c4a4769689521b1c5500e/raw/clash-with-tohome-provider.yaml
    interval: 60

{% endif %}
proxy-groups:
- name: Home-Relay
  type: select
  use:
    - gohome

rules:
- IP-CIDR,192.168.1.1/24,Home-Relay

这样就可以通过 Clash 的 Home-Relay 组来访问家中的 VPN 服务了。

总结

比较麻烦,但是可以实现。

Built with Hugo
主题 StackJimmy 设计