远程访问内网机器的Node.js应用

在需要远程连接到私有网络中的多台机器时,可能会遇到一些障碍,比如TeamViewer、Hamachi、SSH隧道、VPN等工具被封锁。为了解决这个问题,决定构建一个Node.js应用程序来满足需求。

本地运行

首先,会介绍运行应用程序所需的最少操作步骤,并对其进行一些探索。

需要Node.js(测试版本为8),以及git客户端。

git clone https://github.com/mgrybyk/node-tunnel.git cd node-tunnel npm install

接下来,需要创建一个最小的配置文件。将提供两个示例:一个用于有SSH的用户,另一个用于使用浏览器的用户。

注意:".env"文件应该在项目根目录下创建,即node-tunnel目录下。

N_T_AGENT_DATA_HOST=localhost N_T_AGENT_DATA_PORT=22 N_T_CLIENT_PORT=2222 N_T_AGENT_DATA_HOST=inplainsite.org N_T_AGENT_DATA_PORT=80 N_T_CLIENT_PORT=8000

需要启动三个终端窗口,因为需要启动3个Node实例,并运行:

node server node agent node client

连接到localhost:2222:

ssh -p 2222 localhost

打开浏览器并访问localhost:8000。

就是这样!这是一个最小工作示例。所有的流量都通过客户端->服务器->代理并返回。

实际案例:两台PC

在这个例子中,有两台PC,一台有公网IP,另一台没有。目标是使用SSH/RDP等方式连接到它。

现在,在每台机器上克隆仓库并安装模块。

在这个例子中,使用的是RDP端口,可以根据需要更改为其他端口。

N_T_SERVER_HOST=有公网IP的机器的IP N_T_SERVER_PORT=1337 N_T_SERVER_PORTS_FROM=1338 N_T_SERVER_PORTS_TO=1340 N_T_AGENT_DATA_HOST=localhost N_T_AGENT_DATA_PORT=3389 node agent N_T_SERVER_HOST=localhost N_T_SERVER_PORT=1337 N_T_SERVER_PORTS_FROM=1338 N_T_SERVER_PORTS_TO=1340 N_T_CLIENT_PORT=8000 node server node client

一旦完成,可以使用RDP客户端连接到localhost:8000,这将打开到远程PC的连接。

实际案例:两台PC和服务器

看起来不错,但如果本地PC没有公网IP怎么办?需要通过有公网IP的PC转发所有流量。如果没有这样的PC,可以在AWS上创建一个免费的容器。

在每台机器上安装Node.js,克隆仓库并安装模块。

N_T_SERVER_HOST=localhost N_T_SERVER_PORT=1337 N_T_SERVER_PORTS_FROM=1338 N_T_SERVER_PORTS_TO=1340 node server

在这个例子中,使用的是SSH端口,但可以更改为其他端口。同时,会给代理起一个名字(这应该与客户端的名字匹配)。

N_T_SERVER_HOST=有公网IP的机器的IP N_T_SERVER_PORT=1337 N_T_AGENT_DATA_HOST=localhost N_T_AGENT_DATA_PORT=22 N_T_AGENT_NAME=test-ssh node agent

客户端的名字应该与代理的名字匹配。

N_T_SERVER_HOST=有公网IP的机器的IP N_T_SERVER_PORT=1337 N_T_CLIENT_PORT=8000 N_T_CLIENT_NAME=test-ssh node client

现在,可以打开SSH连接到localhost:8000,这将打开到远程PC的SSH连接。

通过服务器机器创建了一个隧道,就像之前做的那样。所有的数据都按照以下方式传输:

SSH客户端 -> 客户端 -> 服务器 -> 代理 -> SSH服务器

然后返回SSH服务器 -> 代理 -> 服务器 -> 客户端 -> SSH客户端

代理和客户端之间没有直接连接。

更多的代理和客户端

一个服务器可以通过多个代理和客户端。例如:

可以运行一个代理来处理SSH,另一个来处理RDP。请注意,每个代理都应该有一个名字(N_T_AGENT_NAME)。

每个代理可以与多个客户端一起工作,所以可以在机器上运行客户端,其他人可以连接到特定的代理。不要忘记指定客户端应该使用哪个代理,通过提供名字(N_T_CLIENT_NAME)。

多个.env文件

如果需要运行多个代理/客户端/服务器,可以创建多个.env文件,例如:

.env.rdp .env.ssh .env.test

有了这样的.env.*文件,可以通过传递.env文件名作为参数来启动服务器/客户端/代理:

node server .env.rdp node agent .env.ssh node client .env.test

注意:".env"文件应该在项目根目录下创建,即node-tunnel目录下。

工作原理

核心内容在这里:

Net允许创建基于流的TCP服务器/客户端和流管道。

为了将数据从一个套接字转发到另一个套接字并返回,简单地将它们像这样管道:

JavaScript agentSocket.pipe(clientSocket) clientSocket.pipe(agentSocket)

让看看这个例子:

在SSH的例子中,发生了以下事情:

SSH客户端连接到客户端(在某个端口上监听)

客户端将所有数据转发到服务器

服务器知道它需要将数据转发到特定的代理

代理打开到SSH服务器的连接,并将数据从服务器转发到它

SSH服务器的响应返回到代理,服务器,客户端,最后到达SSH客户端。

让试着解释应用程序的每个部分的作用。

默认情况下,服务器监听客户端和代理连接。

一旦新的代理连接 - 服务器为其创建一个专用服务器。

一旦新的客户端连接 - 服务器通知它有一个专用服务器用于代理及其端口。

客户端和代理的名字应该匹配才能开始数据转发,不允许有同名的代理。

可能有多个代理,每个代理可能有多个客户端(可能有多个同名的客户端)。

代理的专用服务器的行为是这样的:

在客户端服务器的新连接上,打开到代理专用服务器的新连接。

一旦客户端连接 - 向代理发送通知,以便它可以打开到服务器的连接。

与此同时:客户端套接字现在存储并等待代理套接字。

一旦代理连接 - 专用服务器将代理连接到客户端并返回,然后删除客户端和代理套接字的数据侦听器。

专用服务器向客户端发送通知,说管道已创建,准备好了。

客户端创建服务器并在.env文件中提供的端口上监听传入连接。

在新连接上,客户端开始将数据转发到服务器(见服务器部分的详细信息)。

代理等待有关客户端连接的通知。当发生这种情况时 - 代理连接到.env文件中指定的host:port,并将数据转发到服务器。

接下来是什么?

加密!目前数据没有加密,对于SSH,RDP来说这不是问题,但对于纯文本协议来说是个问题。

目前,只有服务消息是加密的。

当然,修复一些缺陷,清理代码,提高稳定性。

如果有任何想法 - 请随时分享。

感谢阅读!

希望这在某种程度上是有趣的,可以理解的,甚至可能是有用的。

感兴趣的点

在处理管道时有用的模块可能是though2。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485