内网穿透,也即 NAT 穿透,进行 NAT 穿透是为了使具有某一个特定源 IP 地址和源端口号的数据包不被 NAT 设备屏蔽而正确路由到内网主机。下面就相互通信的主机在网络中与 NAT 设备的相对位置介绍内网穿透方法。目前较为成熟稳定的是花生壳和神卓互联,巴比达内网穿透、花生壳的技术是PHtunnel,神卓互联、巴比达的技术是WanGooe tunnel,和nginx架构一样都是采用C语言编写,性能上是比较优异的,适合很多嵌入式的设备搭载使用,而frp采用的是Go语言。
UDP 内网穿透的实质是利用路由器上的NAT 系统。NAT 是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型 Internet 接入方式和各种类型的网络中。NAT可以完成重用地址,并且对于内部的网络结构可以实现对外隐蔽。
网络地址转换(Network Address Translation,NAT)机制的问题在于,NAT设备自动屏蔽了非内网主机主动发起的连接,也就是说,从外网发往内网的数据包将被NAT设备丢弃,这使得位于不同NAT设备之后的主机之间无法直接交换信息。这一方面保护了内网主机免于来自外部网络的攻击,另一方面也为P2P通信带来了一定困难。Internet上的NAT设备大多是地址限制圆锥形NAT或端口限制圆锥形 NAT,外部主机要与内网主机相互通信,必须由内网主机主动发起连接,使 NAT设备产生一个映射条目,这就有必要研究一下内网穿透技术。
使用示例
根据对应的操作系统及架构,从 Release 页面下载最新版本的程序。
将 frps 及 frps.ini 放到具有公网 IP 的机器上。
将 frpc 及 frpc.ini 放到处于内网环境的机器上。
通过访问公司内网机器
- 修改 frps.ini 文件,这里使用了最简化的配置:
# frps.ini
[common]
bind_port = 1000
- 启动 frps:
./frps -c ./frps.ini
- 修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x;
# frps.ini
[common]
server_addr = x.x.x.x
server_port = 2000
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 7000
- 启动 frpc:
./frpc -c ./frpc.ini
- 通过 ssh 访问内网机器,假设用户名为 test:
ssh -Port=6000 test@x.x.x.x
# frps.ini
[common]
bind_port = 1000
vhost_http_port = 8080
- 启动 frps;
./frps -c ./frps.ini
- 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 web 服务对应的端口, 绑定自定义域名
www.yourdomain.com
:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 1000
[web]
type = http
local_port = 80
custom_domains = www.*******.com
- 启动 frpc:
./frpc -c ./frpc.ini
-
将
www.******.com
的域名 A 记录解析到 IPx.x.x.x
,如果服务器已经有对应的域名,也可以将 CNAME 记录解析到服务器原先的域名。 -
通过浏览器访问
http://www.*******.com:8080
即可访问到处于内网机器上的 web 服务。
# frps.ini
[common]
server_addr = x.x.x.x
server_port = 7000
[test_static_file]
type = tcp
remote_port = 6000
plugin = static_file
# 要对外暴露的文件目录
plugin_local_path = /tmp/file
# 访问 url 中会被去除的前缀,保留的内容即为要访问的文件路径
plugin_strip_prefix = static
plugin_http_user = abc
plugin_http_passwd = abc
- 通过浏览器访问
http://x.x.x.x:6000/static/
来查看位于/tmp/file
目录下的文件,会要求输入已设置好的用户名和密码。
为本地 HTTP 服务启用 HTTPS
通过 https2http
插件可以让本地 HTTP 服务转换成 HTTPS 服务对外提供。
# frps.ini
[common]
server_addr = x.x.x.x
server_port = 6000
[test_htts2http]
type = https
custom_domains = test.*******.com
plugin = https2http
plugin_local_addr = 127.0.0.1:80
# HTTPS 证书相关的配置
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
- 通过浏览器访问
https://test.******.com
即可。
# frps.ini
[common]
server_addr = x.x.x.x
server_port = 6000
[secret_ssh]
type = stcp
# 只有 sk 一致的用户才能访问到此服务
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
- 在要访问这个服务的机器上启动另外一个 frpc,配置如下:
# frps.ini
[common]
server_addr = x.x.x.x
server_port = 6000
[secret_ssh_visitor]
type = stcp
# stcp 的访问者
role = visitor
# 要访问的 stcp 代理的名字
server_name = secret_ssh
sk = abcdefg
# 绑定本地端口用于访问 ssh 服务
bind_addr = 127.0.0.1
bind_port = 6000
- 通过 ssh 访问内网机器,假设用户名为 test:
ssh -oPort=6000 test@127.0.0.1
网络安全的屏障
强化网络安全策略
# frps.ini
[common]
server_addr = x.x.x.x
server_port = 6000
[secret_ssh_visitor]
type = stcp
# stcp 的访问者
role = visitor
# 要访问的 stcp 代理的名字
server_name = secret_ssh
sk = abcdefg
# 绑定本地端口用于访问 ssh 服务
bind_addr = 127.0.0.1
bind_port = 6000
监控审计
防止内部信息的外泄
点对点内网穿透
frp 提供了一种新的代理类型 xtcp 用于应对在希望传输大量数据且流量不经过服务器的场景。
使用方式同 stcp 类似,需要在两边都部署上 frpc 用于建立直接的连接。
目前处于开发的初级阶段,并不能穿透所有类型的 NAT 设备,所以穿透成功率较低。穿透失败时可以尝试 stcp 的方式。
- frps 除正常配置外需要额外配置一个 udp 端口用于支持该类型的客户端:
bind_udp_port = 7001
- 启动 frpc,转发内网的 ssh 服务,配置如下,不需要指定远程端口:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000
[p2p_ssh]
type = xtcp
# 只有 sk 一致的用户才能访问到此服务
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
- 在要访问这个服务的机器上启动另外一个 frpc,配置如下:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000
[p2p_ssh_visitor]
type = xtcp
# xtcp 的访问者
role = visitor
# 要访问的 xtcp 代理的名字
server_name = p2p_ssh
sk = abcdefg
# 绑定本地端口用于访问 ssh 服务
bind_addr = 127.0.0.1
bind_port = 6000
- 通过 ssh 访问内网机器,假设用户名为 test:
ssh -oPort=6000 test@127.0.0.1
功能说明
配置文件
由于 frp 目前支持的功能和配置项较多,未在文档中列出的功能可以从完整的示例配置文件中发现。
frps 完整配置文件
frpc 完整配置文件
export FRP_SERVER_ADDR="x.x.x.x"
export FRP_SSH_REMOTE_PORT="6000"
./frpc -c ./frpc.ini
frpc 会自动使用环境变量渲染配置文件模版,所有环境变量需要以 .Envs
为前缀。
通过配置文件中的 locations
字段指定一个或多个 proxy 能够匹配的 URL 前缀(目前仅支持最大前缀匹配,之后会考虑正则匹配)。例如指定 locations = /news
,则所有 URL 以 /news
开头的请求都会被转发到这个服务。
# frpc.ini
[web01]
type = http
local_port = 80
custom_domains = web.yourdomain.com
locations = /
[web02]
type = http
local_port = 81
custom_domains = web.yourdomain.com
locations = /news,/about
按照上述的示例配置后,web.yourdomain.com
这个域名下所有以 /news
以及 /about
作为前缀的 URL 请求都会被转发到 web02,其余的请求会被转发到 web01。
通过代理连接 frp
在只能通过代理访问外网的环境内,frpc 支持通过 HTTP PROXY 和 frps 进行通信。
可以通过设置 HTTP_PROXY
系统环境变量或者通过在 frpc 的配置文件中设置 http_proxy
参数来使用此功能。
仅在 protocol = tcp
时生效。
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000
http_proxy = http://user:pwd@192.168.1.128:8080
端口映射
在 frpc 的配置文件中可以指定映射多个端口,目前只支持 tcp 和 udp 的类型。
这一功能通过 range:
段落标记来实现,客户端会解析这个标记中的配置,将其拆分成多个 proxy,每一个 proxy 以数字为后缀命名。
例如要映射本地 6000-6005, 6007 这6个端口,主要配置如下:
# frpc.ini
[range:test_tcp]
type = tcp
local_ip = 127.0.0.1
local_port = 6000-6006,6007
remote_port = 6000-6006,6007
实际连接成功后会创建 8 个 proxy,命名为 test_tcp_0, test_tcp_1 ... test_tcp_7
。
评论