0%

内网穿透

梦一场


  • Update at Sat May 11 16:49:47 CST 2019

    利用正反 SSH 隧道穿透防火墙访问内网服务器


Announce:

  1. 工具:实现内网穿透,我目前比较推荐frp和goproxy
  2. Github: frp: https://github.com/fatedier/frp
  3. Github: goproxy: https://github.com/snail007/goproxy
  4. frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。
  5. goproxy是基于golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转、TLS加密传输、协议转换、防污染DNS代理。
  6. 对于内网穿透来说frp比goproxy更功能更多,goproxy更偏向于网络代理
  7. goproxy内置了长驻后台的功能,如果想后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可。如果想防止应用异常退出,可以使用--forever参数,proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后重启子进程,该参数配合后台运行参数--daemon和日志参数--log,可以保障proxy一直在后台执行不会因为意外退出,而且可以通过日志文件看到proxy的输出日志内容

Goproxy

下载 & 安装

自动安装
  • 如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置
    1
    curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash  

    安装完成,配置目录是/etc/proxy,更详细的使用方法请参考手册目录,进一步了解你想要使用的功能.
    如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:

手动安装
  1. 下载proxy
    下载地址: https://github.com/snail007/goproxy/releases/latest
    下面以v6.2为例,如果有最新版,请使用最新版链接.

    1
    2
    cd /root/proxy/  
    wget https://github.com/snail007/goproxy/releases/download/v6.2/proxy-linux-amd64.tar.gz
  2. 下载自动安装脚本

    1
    2
    3
    4
    cd /root/proxy/  
    wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
    chmod +x install.sh
    ./install.sh
Docker安装
  • docker

  • 项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本,

  • 全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile
    或者使用参数GOPROXY_VERSION指定构建的goproxy版本.

    1
    ARG GOPROXY_VERSION=v5.3

步骤:

  1. 克隆仓库,然后cd进入仓库文件夹,执行:

    1
    sudo docker build .
  2. 镜像打标签:

    1
    sudo docker tag <上一步的结果ID> snail007/goproxy:latest
  3. 运行
    参数OPTS的值就是传递给proxy的所有参数
    比如下面的例子启动了一个http服务:

    1
    sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 snail007/goproxy:latest
  4. 查看日志:

    1
    sudo docker logs -f goproxy

Windows 直接下载 *.exe 版就行了

使用

http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,当然可以选择不加密通信通讯,本教程所有和上级通讯都采用加密,需要证书文件.
通过下面的命令生成自签名的证书和key文件。proxy keygen -C proxy

TCP普通用法
  • 需求:可以通过服务器的28080端口访问到位于本地服务器上的web服务
  • 条件:
    • 本地机器A提供了web服务80端口
    • 有VPS一个,公网IP:22.22.22.22
  • 步骤:
    1. 在vps上执行
      1
      2
      proxy bridge -p ":33080" -C proxy.crt -K proxy.key
      proxy server -r ":28080@:80" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key
    2. 在本地机器A上面执行
      1
      proxy client -P "22.22.22.22:33080" -C proxy.crt -K proxy.key` 
    3. 完成
UDP普通用法
  • 背景:

    • 公司机器A提供了DNS解析服务,UDP:53端口
    • 有VPS一个,公网IP:22.22.22.22
  • 需求:
    在家里能够通过设置本地dns为22.22.22.22,使用公司机器A进行域名解析服务.

  • 步骤:

    1. 在vps上执行

      1
      2
      proxy bridge -p ":33080" -C proxy.crt -K proxy.key
      proxy server --udp -r ":53@:53" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key
    2. 在公司机器A上面执行

      1
      proxy client -P "22.22.22.22:33080" -C proxy.crt -K proxy.key
    3. 完成

frp

下载 & 安装

  • 根据对应的操作系统及架构,从 Release 页面下载最新版本的程序。

  • frpsfrps.ini 放到具有公网 IP 的机器上。

  • frpcfrpc.ini 放到处于内网环境的机器上。

使用


Contents


通过自定义域名访问部署于内网的web服务

有时想要让其他人通过域名访问或者测试我们在本地搭建的 web 服务,但是由于本地机器没有公网 IP,无法将域名解析到本地的机器,通过 frp 就可以实现这一功能,以下示例为 http 服务,https 服务配置方法相同, vhost_http_port 替换为 vhost_https_port, type 设置为 https 即可。

  1. 修改 frps.ini 文件,设置 http 访问端口为 8080:

    1
    2
    3
    4
    # frps.ini
    [common]
    bind_port = 7000
    vhost_http_port = 8080
  2. 启动 frps;

    ./frps -c ./frps.ini

  3. 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 web 服务对应的端口, 绑定自定义域名 www.yourdomain.com:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # frpc.ini
    [common]
    server_addr = x.x.x.x
    server_port = 7000

    [web]
    type = http
    local_port = 80
    custom_domains = www.yourdomain.com
  4. 启动 frpc:

    ./frpc -c ./frpc.ini

  5. www.yourdomain.com 的域名 A 记录解析到 IP x.x.x.x,如果服务器已经有对应的域名,也可以将 CNAME 记录解析到服务器原先的域名。

  6. 通过浏览器访问 http://www.yourdomain.com:8080 即可访问到处于内网机器上的 web 服务。

通过ssh访问内网机器
  1. 修改 frps.ini 文件,这里使用了最简化的配置:

    1
    2
    3
    # frps.ini
    [common]
    bind_port = 7000
  2. 启动 frps:

    ./frps -c ./frps.ini

  3. 修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # frpc.ini
    [common]
    server_addr = x.x.x.x
    server_port = 7000

    [ssh]
    type = tcp
    local_ip = 127.0.0.1
    local_port = 22
    remote_port = 6000
  4. 启动 frpc:

    ./frpc -c ./frpc.ini

  5. 通过 ssh 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@x.x.x.x

转发DNS查询请求

DNS 查询请求通常使用 UDP 协议,frp 支持对内网 UDP 服务的穿透,配置方式和 TCP 基本一致。

  1. frps 的部署步骤同上。

  2. 启动 frps:

    ./frps -c ./frps.ini

  3. 修改 frpc.ini 文件,设置 frps 所在服务器的 IP 为 x.x.x.x,转发到 Google 的 DNS 查询服务器 8.8.8.8 的 udp 53 端口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # frpc.ini
    [common]
    server_addr = x.x.x.x
    server_port = 7000

    [dns]
    type = udp
    local_ip = 8.8.8.8
    local_port = 53
    remote_port = 6000
  4. 启动 frpc:

    ./frpc -c ./frpc.ini

  5. 通过 dig 测试 UDP 包转发是否成功,预期会返回 www.google.com 域名的解析结果:

    dig @x.x.x.x -p 6000 www.google.com

对外提供简单的文件访问服务
  • 通过 static_file 插件可以对外提供一个简单的基于 HTTP 的文件访问服务。

  • frps 的部署步骤同上。

    1. 启动 frpc,启用 static_file 插件,配置如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # frpc.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
  1. 通过浏览器访问 http://x.x.x.x:6000/static/ 来查看位于 /tmp/file 目录下的文件,会要求输入已设置好的用户名和密码。
安全地暴露内网服务
  • 对于某些服务来说如果直接暴露于公网上将会存在安全隐患。

  • 使用 stcp(secret tcp) 类型的代理可以避免让任何人都能访问到要穿透的服务,但是访问者也需要运行另外一个 frpc。

  • 以下示例将会创建一个只有自己能访问到的 ssh 服务代理。

    1. 启动 frpc,转发内网的 ssh 服务,配置如下,不需要指定远程端口:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # frpc.ini
      [common]
      server_addr = x.x.x.x
      server_port = 7000

      [secret_ssh]
      type = stcp
      # 只有 sk 一致的用户才能访问到此服务
      sk = abcdefg
      local_ip = 127.0.0.1
      local_port = 22
    2. 在要访问这个服务的机器上启动另外一个 frpc,配置如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # frpc.ini
      [common]
      server_addr = x.x.x.x
      server_port = 7000

      [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
    3. 通过 ssh 访问内网机器,假设用户名为 test:

      ssh -oPort=6000 test@127.0.0.1

点对点内网穿透
  • frp 提供了一种新的代理类型 xtcp 用于应对在希望传输大量数据且流量不经过服务器的场景。

  • 使用方式同 stcp 类似,需要在两边都部署上 frpc 用于建立直接的连接。

  • 目前处于开发的初级阶段,并不能穿透所有类型的 NAT 设备,所以穿透成功率较低。穿透失败时可以尝试 stcp 的方式。

    1. frps 除正常配置外需要额外配置一个 udp 端口用于支持该类型的客户端:

      1
      2
      3
      4
      # frps.ini
      [common]
      bind_port = 7000
      bind_udp_port = 7001
    2. 启动 frpc,转发内网的 ssh 服务,配置如下,不需要指定远程端口:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # 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
    3. 在要访问这个服务的机器上启动另外一个 frpc,配置如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # 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
    4. 通过 ssh 访问内网机器,假设用户名为 test:

      ssh -oPort=6000 test@127.0.0.1

总结
  1. 如果我们想要frp承载TCP类型的流量,可以参考 通过ssh访问内网机器,只需要将frpc配置文件里面的端口修改为需要进行代理的端口就行了。再将第6行修改一下就行了,中括号里面内容虽然可以随意填,但是为了鲜明,最好认真命名

  2. UDP可以参考 转发DNS查询请求


frp 配置文件支持使用系统环境变量进行模版渲染,模版格式采用 Go 的标准格式。
由于 frp 目前支持的功能和配置项较多,未在文档中列出的功能可以从完整的示例配置文件中发现。

  • frps 完整配置文件
  • frpc 完整配置文件

参见

  1. frp README: https://github.com/fatedier/frp/blob/master/README.md
  2. goproxy README: https://github.com/snail007/goproxy/blob/master/README.md
2019年情人节
-------------本文结束再接再厉-------------

本文标题:内网穿透

文章作者:IITII

发布时间:2019年02月13日 - 23:02

最后更新:2019年12月11日 - 02:12

原始链接:https://iitii.github.io/2019/02/13/1/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。