/vnet

Virtual network - #多端虚拟组网 #内网穿透 #合并远程局域网

Primary LanguageGoMIT LicenseMIT

vnet

golang编写的 虚拟组网工具

由一个部署在公共网的 route 端和部署在私网的多个 vnet 端组成

流量可以由一个 vnet 端转发至另一个 vnet 端,以达成虚拟组网的目的

使用注册服务路由的方式来进行流量流转

route端[组件]

转发vnet的流量

维护一些配置项

vnet端[组件]

通过配置可以将一些本地服务注册到route端

可查询route端维护的所有服务信息,并开启某一个服务在本地的映射

本地应用可访问本vnet端开启的这个映射服务,来达成访问远端vnet注册的远端服务的目的

使用

route端

route端部署在有公网ip[或公共网域]的机器上

配置文件

config.ini

[route] ; route端的配置,是route端的监听设置,也是vnet端连接route端的设置
ip=127.0.0.1 ; ip地址,必填项
port=7749 ; 端口号,必填项

ip 为必填项,route端监听的ip,如果是 127.0.0.1,则只能本机器访问,如果是 0.0.0.0 则外网可访问

port 为必填项,route端监听的端口,默认为 7749

运行route

./route

默认读取运行环境目录下的 config.ini

或指定配置文件

./route config.ini

配置文件可更改路径及文件名

vnet端

vnet端部署在需要虚拟组网的私网机器中

配置文件

config.ini

[route] ; route端的配置,是route端的监听设置,也是vnet端连接route端的设置
ip=127.0.0.1 ; ip地址,必填项
port=7749 ; 端口号,必填项

[vnet] ; vnet端的配置
name=xiao ; vnet名称
group=default ; 分组,只能共享同分组连接组网 ;不写则默认 default
terminal=true ; 是否开启命令行交互 ; 不开启则完全以配置文件为根据提供服务,startserve和startuse配置不生效 ; 开启则可在命令行界面进行额外配置,且startserve和startuse配置会生效 ; 不写则默认 false
startserve=false ; 是否启动时自动开启serve服务 ; 不写则默认 true
startuse=false ; 是否启动时自动映射use服务 ; 不写则默认 true
allow_unserve=false ; 是否允许被访问本vnet端未注册的服务 ; 不写则默认 false
unserve_remote=false ; 是否允许被访问本vnet端非localhost地址的未注册服务 ; 不写则默认 false
unserve_num=1 ; 允许被访问未注册服务总数量 ; 不写则默认 1

[serve.xrdp] ; 远程服务配置,serve字为标志字,后面的字符为服务名称,在配置文件中不可重复
serveid=999 ; 服务唯一标识,取值范围[1,499],其中[500,999]为静态标识,服务端不会更改,其他为动态标识,如果冲突,会被服务端动态修改 ; 可不写此项,默认000,在启动后,服务端自动分配
type=tcp ; 服务协议,vnet只支持tcp传输协议,基于tcp的其他协议也可借tcp链路传输 ; 可不写此项
ip=127.0.0.1 ; ip地址 ; 可不写此项,默认127.0.0.1
port=3389 ; 端口号,必填项
name=xrdp ; 服务名称,name配置项不存在的话,以serve标志字后的服务名称为name配置名称 ; 可不写此项
info=Microsoft remote desktop protocol ; 服务补充信息 ; 可不写此项
active=false ; 是否激活,其作用在于是否在vnet端启动时被自动化处理,如果不激活,则需在命令行手动处理 ; 可不写此项,默认激活

[use.xrdp] ; 映射服务配置,use字为标志字,后面的字符为服务名称,在配置文件中不可重复,use服务名称无实际意义,仅作区分其他use配置意义
serveid=999 ; 服务唯一标识,必填项,取值范围[1,999],是识别和获取远程服务的唯一根据,获取到则开启映射,为获取到则待命 ; 不写或写000则不会开启此项配置
ip=127.0.0.1 ; ip地址 ; 可不写此项,默认127.0.0.1
port=33389 ; 端口号,映射服务监听端口 ; 可不写此项,默认使用原端口
active=false ; 是否激活,其作用在于是否在vnet端启动时被自动化处理,如果不激活,则需在命令行手动处理 ; 可不写此项,默认激活

[route] 为需要连接的route端的地址

ip 为必填项,route端监听的ip,vnet端访问route端的ip地址

port 为必填项,route端监听的端口,默认为 7749,vnet端访问route端的port端口

[vnet] 为本端vnet的一些配置:

vnet名称:

  • name=xiao:提供简单的名称以帮助分辨,主要在需要辨别服务来源和请求未注册服务的场景使用

vnet分组:

  • group=default:使用分组名称来区别,同时区分开不同的分组,仅可见同分组的服务和vnet终端

vnet终端形态:

  • terminal=false:简单形态,仅使用配置文件中的配置,不提供其他终端命令操作
  • terminal=true:命令行形态,相比简单形态,额外提供其他终端命令进行操作

访问未注册服务:

  • allow_unserve=false:不允许访问未注册服务
  • allow_unserve=true:允许访问未注册服务,收到请求后先尝试建立无serveid服务,然后向route端申请和注册这个服务,如果成功则向请求方返回这个serveid,否则返回空serveid

允许未注册服务为远端:

  • unserve_remote=true:允许未注册服务ip为非127.0.0.1的unserve执行
  • unserve_remote=false:仅允许未注册服务ip为127.0.0.1的unserve执行

允许访问多少个未注册服务:

  • unserve_num=1:由提供方计数,超过的一律响应为准备失败

[serve.] 本端vnet向route端注册的服务

注意:[serve.] 使用时因为中括号内的字符不能重复,所以需要在小数点后面增加一些字符,充当这个serve的名称,如 [serve.xrdp]、[serve.ssh]

serveid=999 ; 服务唯一标识,取值范围[1,499],其中[500,999]为静态标识,服务端不会更改,其他为动态标识,如果冲突,会被服务端动态修改 ; 可不写此项,默认000,在启动后,服务端自动分配

type=tcp ; 服务协议,vnet只支持tcp传输协议,基于tcp的其他协议也可借tcp链路传输 ; 可不写此项

ip=127.0.0.1 ; ip地址 ; 可不写此项,默认127.0.0.1

port=3389 ; 端口号,必填项

name=xrdp ; 服务名称,name配置项不存在的话,以serve标志字后的服务名称为name配置名称 ; 可不写此项

info=Microsoft remote desktop protocol ; 服务补充信息 ; 可不写此项

active=false ; 是否激活,其作用在于是否在vnet端启动时被自动化处理,如果不激活,则需在命令行手动处理 ; 可不写此项,默认激活

[use.] 本端vnet将使用的映射服务

注意:[use.] 使用时因为中括号内的字符不能重复,所以需要在小数点后面增加一些字符,充当这个use的名称,如 [use.xrdp]、[use.ssh]

serveid=999 ; 服务唯一标识,必填项,取值范围[1,999],是识别和获取远程服务的唯一根据,获取到则开启映射,未获取到则待命 ; 不写或写000则不会开启此项配置

ip=127.0.0.1 ; ip地址 ; 可不写此项,默认127.0.0.1

port=33389 ; 端口号,映射服务监听端口 ; 可不写此项,默认使用原端口

active=false ; 是否激活,其作用在于是否在vnet端启动时被自动化处理,如果不激活,则需在命令行手动处理 ; 可不写此项,默认激活

注意:serve和use中的serveid最大只能是3位字符,为数字的0~999,vnet默认将500以上的serveid当做静态处理,使用期间不会被更改,而500以下的serveid在运行时遇到冲突,则可能会被更改和重新分配

运行vnet

./vnet

默认读取运行环境目录下的 config.ini

或指定配置文件

./vnet config.ini

配置文件可更改路径及文件名

开机启动

建议使用vnet.sh或vnet.cmd来使用

linux vnet.sh

cd /home/xiao/my/vnet
./vnet config.ini

windows vnet.cmd

cd /d D:\my\vnet
vnet.exe config.ini

自启动:

linux可选择新建service来自启动

自行查询service文件新建和使用方法

windows可选择将vnet.cmd的快捷方式放到启动文件夹

win+R,输入shell:startup回车,就是启动文件夹

使用场景示例

在办公室连接家中的主机:使用远端ssh服务,以及临时使用远程jupyter工具

  • 处于家中的主机A开启ssh服务

  • A运行vnet终端,配置文件为

[route]
ip=10.12.140.180
port=7749

[vnet]
name=remote-ssh
group=default-ssh
terminal=false
startserve=true
startuse=false
allow_unserve=true
unserve_remote=false
unserve_num=3

[serve.ssh]
serveid=700
type=tcp
ip=127.0.0.1
port=22
name=ssh
info=home-ssh
active=true
  • ip 为10.12.140.180[胡编的]的公网服务器运行route端,配置文件为
[route]
ip=0.0.0.0
port=7749
  • 位于公司办公室的主机B运行vnet终端,配置文件为
[route]
ip=10.12.140.180
port=7749

[vnet]
name=local-ssh
group=default-ssh
terminal=true
startserve=false
startuse=true
allow_unserve=false
unserve_remote=false
unserve_num=3

[use.ssh]
serveid=700
ip=127.0.0.1
port=1122
active=true
  • 在主机B中连接ssh服务
ssh user@127.0.0.1 -p 1122
  • 在主机B中还想访问主机A中的jupyter服务,但是[show serves]发现主机A没有注册这个服务

首先,远程ssh中打开jupyter服务

jupyter notebook

然后,vnet终端中使用unserve

>: show serves

请求route的服务列表 ...
route服务列表:
serveid vnet    name    type    ip      port    info
700     01      ssh     tcp     127.0.0.1       22    home-ssh
-  1 个vnet终端, 共注册 1 个服务 -

>: unserve

    to vnetid: 01
    ip(127.0.0.1):
    port: 8888
unservemap_local [[01 map[127.0.0.1:8888:000]]]
已向 vnetid: 01 的vnet终端请求其未注册的 127.0.0.1:8888 服务,等待回应 ...
注意:unserve服务保质期为 3min ...
成功获取到 vnetid: 01 的vnet终端的服务 - 已注册serveid: 001 继续开启 ...

    ip(127.0.0.1):
    port: 18888
newunserveuse {001 127.0.0.1 18888 true}

>:
  • 此时浏览器中访问localhost:18888,则可以成功打开jupyter

其他场景举例

目前我使用过的场景:

  • windows的远程桌面

  • code-serve 这个是微软vscode的web版,部署在wsl中,超好用

  • filemanager 这个是简单的前端文件管理工具,可以查看,下载,上传,删除文件,在线视频就是用这个测试的

  • 当然还有众多的内网web服务

  • 多端虚拟组网:通过多vnet端部署,可让这些客户机组建一张虚拟局域网

  • 内网穿透:可以在公网服务器上同时部署一个route端和一个vnet端来实现经典的内网穿透

  • 合并远程局域网:在互不可访问的多个局域网中部署vnet,可使多个不同局域网中的服务互通,达到局域网合并效果

vnet终端交互

配置文件中[vnet]terminal=true开启本vnet端的终端交互

  • help

reload 重新加载配置,可指定配置文件 serve 本地服务操作,创建、执行、开始、暂停、删除等 use 映射服务操作,创建、执行、开始、暂停、删除等 show 显示信息,本端vnet、本端serve、本端use、route端serves、route端vnets等 ping 测试与route端的回传延迟 unserve 请求非注册服务 exit 退出本端vnet

  • reload

reload不指定配置文件的话,则默认读取运行环境目录下的config.ini

不会全部关闭现有的所有serve或use,只会对变动项做出反应

  • serve

注册服务配置,使用 serve open|close|new|run|delete

open 则打开一个active=false的serve,并注册

close 则关闭一个注册的serve,并active=false

new 新建一个serve,并active=false

run 新建一个serve,并active=true,并注册

delete 删除一个serve,并注销

  • use

映射服务配置,使用 use open|close|new|run|delete

open 则打开一个active=false的use,并监听

close 则关闭一个监听的use,并active=false

new 新建一个use,并active=false

run 新建一个use,并active=true,并监听

delete 删除一个use,并解除监听

  • show

查询route端维护的相关信息和展示本vnet端的相关信息

使用 show serve|use|serves|vnet|vnets

serve 展示本vnet端的所有serve配置

use 展示本vnet端的所有use配置

serves 查询route端维护的所有serve配置

vnet 展示本vnet端的相关配置

vnets 查询route端维护的所有vnet配置

  • ping

向route端发送心跳,并记录回传时间

注意,如果vnet忙,则这个时间包含消息流转时的排队[阻塞]时间

  • unserve

请求对方vnet端的未注册服务,需要对方vnet端配置中[vnet]allow_unserve=true

会要求输入对方vnetid,ip,port

ip不输入则默认 127.0.0.1,vnetid必须是已和route端连接的vnet终端

如果对方vnet端开启unserve成功,则本端vnet还会继续要求输入开启映射服务的ip和port

如果开启成功,则对方vnet会保留这个unserve 3分钟时间,未使用则自动注销

被使用后,当所有连接被关闭,则这个unserve会在1分钟后自动注销

注意:因为延迟和消息阻塞的因素,提示失败时也可能是开启延时,可以稍后使用 [show serves]查询

  • exit

关闭本端vnet

使用的其他外部库

  • gopkg.in/ini.v1 用来读取ini配置文件

注意事项

  • 所有连接使用tcp链路,因此vnet只支持tcp相关流量的转发,例如http协议也可,udp类型则不行。
  • vnet有分组规则,即使是连接同一个route端,但服务仅同组vnet终端可见。只需要设置同一个group名就能处于同一个分组。
  • 因为vnet的route端使用了注册路由来流转vnet终端的流量,所以各vnet终端和route端仅建立了一条tcp链路,因此,当vnet端有高tcp流量的服务运行时,流量的通行会稍有阻塞。
  • 某些场景中可能会存在大问题!!!目前遇到的如 浏览器在线播放视频 的场景,浏览器会控制接收流量的速度,这会导致整个链路被卡,使用ping或者show serves等命令时,有可能会出现失败
  • 目前vnet没有密码 。。。,但可使用复杂分组名称简单识别

后续版本

vnet整体框架写差不多了才关注到frp这个项目,连接绑定的流量传递方式真是简洁优雅,避免了很多需要同步的坑,也不会出现一个连接阻塞,整个终端被卡的现象,我想着也可以让vnet的route端和vnet终端间也建立多条连接绑定,不过这是后续版本的事了。

这个版本中,我觉得route端还是尽量简单的好,使其能很好的在配置简陋的服务端运行,将更多的能力使用在转发流量上。而且真的只要不是像浏览器在线视频那样奇葩的场景,vnet的使用还是很稳定的,任务繁重也只会让单个服务速度降低些罢了,不至于不可忍受。

当然,我也计划这后面有时间了写个vnet-v2,就使用连接绑定来做,毕竟vnet的同步真的费了好多功夫,有简洁优雅的方式为啥不去做呢?毕竟,浏览器看视频它不卡顿啊 。。。

还有

用另外的一个portsmap工具,一个filemanager工具,来搭配vnet使用,可以使vnet虚拟融合多个远程局域网的功能更完善哦。。。