内网穿透

内网穿透,是一项可以让 NAT 设备后的主机可以被互联网访问的技术。本文介绍笔者使用过的多种内网穿透技术,希望读者能找到适合自己的一种。

frp

frp 是一个使用 go 语言开发的内网穿透工具,适合多种应用场景。像 frp 这种需要自己搭建服务器,端口对端口的是常用的一种内网穿透形式。

github 地址

使用方法可见 gofrp.org

Cloudflare Tunnels

Cloudflare Tunnels 是 Cloudflare 的一个内网穿透工具。配置简单,不需要公网服务器,备案和 https 证书,速度也相当可观,所以 Cloudflare Tunnels 适合用来搭建网站。

  1. 首先注册登录 Cloudflare Zero Trust, 打开 Access Tunnels。

  1. 点击 Create a tunnel, 填入名字,选择环境。
  2. 按照操作指引安装 connector,等待下方列表自动刷新后,应该可以看到有新的一项。

  1. 点击 Next, 填写配置信息。需要注意的是,服务类型选择的是你本机部署的服务类型,而不是用户访问时候的数据类型,例如:本机部署 http 服务,选择 http 类型,但用 https 访问。

  1. 点击 Save,保存后,就可以在你所配置的域名访问到了。

例如,本机运行一个简单的测试服务。

Cloudflare 自动加上了 https 证书。

v2ray

v2ray 虽然被大量用于科学上网,但是实际上它也可以用来内网穿透,除了类似 frp 的内网穿透(反向代理) 的一对一,v2ray 还有一个一对多的模式,我把它叫做 vpn 内网穿透模式。

使用 v2ray 的此技术,可以使内网外的机器的部分网络环境和内网相同,像校外访问校园网这样的场景可以用到此技术(也就是 vpn 最初的用处)。

假设 A 为内网内的一台电脑, 它的出站流量为 freedom, 也就是自由访问内网, 另一个出站流量是外网服务器 B, A 主动连接 B, 然后转发来自 B 的请求。

而 B 有两个入站流量, 一个监听A的连接, 一个做代理服务器,这里可以用 v2ray 支持的任意协议,例如 http,vmess,Shadowsocks。

这样, 只要使用B的代理, 就相当于和A的网络环境相同, 也就能访问内网了。

内网服务器配置

json

{  
  "reverse":{ 
    // 这是 A 的反向代理设置,必须有下面的 bridges 对象
    "bridges":[  
      {  
        "tag":"bridge", // 关于 A 的反向代理标签,在路由中会用到
        "domain":"private.cloud.com" // A 和 B 反向代理通信的域名,可以自己取一个,可以不是自己购买的域名,但必须跟下面 B 中的 reverse 配置的域名一致
      }
    ]
  },
  "outbounds": [
    {  
      //A连接B的outbound  
      "tag":"tunnel", // A 连接 B 的 outbound 的标签,在路由中会用到
      "protocol":"vmess",
      "settings":{  
        "vnext":[  
          {  
            "address":"serveraddr.com", // B 地址,IP 或 实际的域名
            "port":16823,
            "users":[  
              {  
                "id":"b831381d-6324-4d53-ad4f-8cda48b30811",
                "alterId":64
              }
            ]
          }
        ]
      }
    },
    // 另一个 outbound,最终连接内网服务    
    {  
      "protocol":"freedom",
      "settings":{  
      },
      "tag":"out"
    }    
  ],
  "routing":{   
    "rules":[  
      {  
        // 配置 A 主动连接 B 的路由规则
        "type":"field",
        "inboundTag":[  
          "bridge"
        ],
        "domain":[  
          "full:private.cloud.com"
        ],
        "outboundTag":"tunnel"
      },
      {  
        // 反向连接访问内网服务的规则
        "type":"field",
        "inboundTag":[  
          "bridge"
        ],
        "outboundTag":"out"
      }
    ]
  }
}

外网服务器配置

json

{  
  "reverse":{  //这是 B 的反向代理设置,必须有下面的 portals 对象
    "portals":[  
      {  
        "tag":"portal",
        "domain":"private.cloud.com"        // 必须和上面 A 设定的域名一样
      }
    ]
  },
  "inbounds": [
    {  
      // 接受客户端的inbound
      "tag":"external", // 标签,路由中用到
      "port":10808,
      "protocol":"http",
    },
    // 另一个 inbound,接受 A 主动发起的请求  
    {  
      "tag": "tunnel",// 标签,路由中用到
      "port":16823,
      "protocol":"vmess",
      "settings":{  
        "clients":[  
          {  
            "id":"b831381d-6324-4d53-ad4f-8cda48b30811",
            "alterId":64
          }
        ]
      }
    }
  ],
  "routing":{  
    "rules":[  
      {  //路由规则,接收客户端请求后发给 A
        "type":"field",
        "inboundTag":[  
          "external"
        ],
        "outboundTag":"portal"
      },
      {  //路由规则,让 B 能够识别这是 A 主动发起的反向代理连接
        "type":"field",
        "inboundTag":[  
          "tunnel"
        ],
        "domain":[  
          "full:private.cloud.com"
        ],
        "outboundTag":"portal"
      }
    ]
  }
}

然后分别运行 v2ray,需要访问内网的机器通过代理(本配置文件是 http 代理,实际使用时建议使用安全性更高的协议,并加入鉴权)即可访问到内网。

还可以通过编辑 v2ray 的路由规则做到只有部分流量被转发,相当灵活。

ssh Tunnels

相信大家都很熟悉 ssh,但未必知道它还可以用来网络流量的转发,其中一项功能就可以用来做内网穿透。只不过,相对于以上三种技术,ssh 相对而言没有那么稳定,但它使用简单,只要支持 ssh,不需要进行配置,用于短时的开发测试还是方便的。

注:ssh tunnels 的三种模式中,仅 Remote Port Forwarding 可用于内网穿透。

Dynamic forwarding

在本地建立一个 Socks 代理服务器,复制远程主机的网络环境(把代理的请求转发给远程主机)。

例如:

sh

ssh -D 7777 username@hostname

1

本地浏览器代理设置为 socks, localhost:7777,现在浏览器的请求均由远程主机转发。

Local Port Forwarding

将发往本地端口的流量由远程主机转发到某地址。

例如:

sh

ssh -L 7777:localhost:9999 username@hostname

1

这样,访问本机 7777 端口相当于访问远程主机localhost:9999,同理,这里的 localhost:9999 也可以换成其他地址,例如只有远程主机才能访问到的其他服务器等。

容易发现,Local Port Forwarding 是在 ssh 客户端监听端口,流量由 ssh 服务端转发。

该转发不仅仅支持 http, 其他协议例如 upd, ssh 协议也是可以转发的。

需要注意的是,想把该转发用作 http 代理是几乎行不通的,因为大部分网站使用了 https,即使没有强制使用的,大都会检查 http 中的 host,而此种方法发出的 http 请求中的 hostlocalhost, 会被认为不合法。

注:这里的 7777:localhost:9999 实际上是省略了 localhost, 实际上是 localhost:7777:localhost:9999,如果想监听非 localhost, 可改为 "*:7777:localhost:9999"(注意引号)。

Remote Port Forwarding

此技术可用于内网穿透。

Local Port Forwarding 不同的地方在于,Remote Port Forwarding 是在 ssh 服务端监听端口,流量由 ssh 客户端转发。

例如:

sh

ssh -R "*:7777:localhost:8888" username@hostname

1

这样,访问远程主机的 7777 端口相当于访问本机的 8888 端口,起到了内网穿透的效果。

假设还想通过外网服务器访问内网中的 B 主机,我可以在内网中的 A 主机 运行

sh

ssh -R "*:7777:B:8888" username@hostname

1

以 A 主机为控制端和转发桥梁。

作者 灰武士