golang编写的 虚拟组网工具
由一个部署在公共网的 route 端和部署在私网的多个 vnet 端组成
流量可以由一个 vnet 端转发至另一个 vnet 端,以达成虚拟组网的目的
使用注册服务路由的方式来进行流量流转
route端[组件]
转发vnet的流量
维护一些配置项
vnet端[组件]
通过配置可以将一些本地服务注册到route端
可查询route端维护的所有服务信息,并开启某一个服务在本地的映射
本地应用可访问本vnet端开启的这个映射服务,来达成访问远端vnet注册的远端服务的目的
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端部署在需要虚拟组网的私网机器中
配置文件
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]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虚拟融合多个远程局域网的功能更完善哦。。。