你的位置:首页 > 互联网IT

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透

支持系统:Windows 64/32位系统/Linux系统

功能:NodejsTCP内网穿透

软件:node

性能:一般

Windows/linux下载地址:NodejsTCP内网穿透

windows node 下载地址:node-v12.14.0-x86.rar


项目地址:

https://gitee.com/baojuhua/node_simples/tree/master/node_simple_tcp_penetration


另一个内网穿透:NodejsTCP内网穿透

https://www.zhuguodong.com/?id=601


NodejsTCP内网穿透


用法:

服务器端

修改server.js:

const CONFIG = {

    server_addr: "0.0.0.0",//服务端地址 一般是0.0.0.0或127.0.0.1

    server_port: 10001,//服务端端口

    token: "123456",//连接令牌 

};


客户端

修改client.js:

const CONFIG = {

    server_addr: "www.baidu.com",//服务端地址

    server_port: 10001,//服务端端口

    token: "123456",//连接令牌

    timeout: 3000,//请求超时时间

    interval: 5000,//异常重试,建议设置1000

    binds: {//绑定内网应用

        ssh: {                        //名称,多条名称设置不一样

            local_ip: "www.baidu.com",//当前内网被转发的ip

            local_port: 808,//当前内网被转发的端口

            remote_port: 808,//服务端映射的端口

        },

        aria2: {

            local_ip: "www.qq.com",//当前内网被转发的ip

            local_port: 8080,//当前内网被转发的端口

            remote_port: 8080,//服务端映射的端口

        },

        aria2Ng: {

            local_ip: "8.8.8.8",//当前内网被转发的ip

            local_port: 999,//当前内网被转发的端口

            remote_port: 999,//服务端映射的端口

        }

    }

};


Windows/linux启动:

服务端

node server.js

客户端

node client.js


Windows系统:

安装:node-v12.14.0-x86.msi

查看:node -v

返回版本信息,比喻:v0.10.48

同目录下运行cmd:

服务端

node server.js或者启动server.bat

客户端

node client.js或者启动client.bat


后台隐藏运行:https://www.zhuguodong.com/?id=520


Linux系统:

第一种:nodejs安装

安装:yum -y install nodejs

查看:node -v

返回版本信息,比喻:v0.10.48

同目录下运行linux命令:

服务端

node server.js

客户端

node client.js


后台隐藏运行:https://www.zhuguodong.com/?id=498


1.升级node,下载 n管理包


npm install -g n


2.执行n 命令升级到v14.16.0

v14.16.0版本2021年2月23日

n 14.16.0 stable


v12.21.0版本2021年2月23日

n 12.21.0 stable


v10.23.3版本2021年2月9日

n 10.23.3 stable


3.重启centos7(必须).查看node版本,更新到14.16.0

reboot


第二种:nodejs安装

安装宝塔网站面板

软件商店:搜索node,安装

查看:node -v

返回版本信息,比喻:v0.10.48


Linux系统node安装:

参考文章:https://www.zhuguodong.com/?id=529


参考文章:

https://gitee.com/baojuhua/node_simples/tree/master/node_simple_tcp_penetration

https://www.jianshu.com/p/86dd17dea84d

Nodejs实现简单的TCP内网穿透

简书:https://www.jianshu.com/p/86dd17dea84d

网上关于TCP内网穿透的软件或是文章挺多的,其中通过TCP端口代理转发可以说是实现穿透最简单的方式了。

注意:文章代码只是原理示例,并没有考虑性能、安全性以及一些异常的处理,请切勿在生产环境中使用。

1.原理解析

首先了解一下,普通端口代理转发,与内网穿透的端口代理转发的区别

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第1张

为了方便大家理解,我将IP换成应用,效果如下

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第2张


整体的效果大概是这个样子的

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第3张

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第4张

1.1.具体步骤

首先穿透客户端连接上穿透服务端

TCP连接上后提交校验数据,与一些配置信息

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第5张

服务端校验成功后,服务端根据配置信息开放对应的端口监听服务

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第6张

注意:接下来这一步有两种做法

假设服务端有内网客户端访问到某个端口了

我一开始是直接将请求数据通过已经连接好的Socket连接发送给穿透客户端

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第7张

然后,穿透客户端动态创建访问客户端去连接内网的服务或App

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第8张

结果我发现,上面这种做法在Socket标识上需要做好多处理,而且可能涉及到修改数据包的操作

于是我改用下面的这种做法

穿透客户端只负责提交配置数据,与接收服务端发送的对应的端口访问请求

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第9张

穿透客户端接收到请求后,开放两个新的客户端用于双向的数据传输

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第10张

这样服务端与客户端的数据基本就打通了

2.编写穿透客户连接端程序与穿透服务端监听程序

根据原理编写起来其实就很简单了

注意:我这边为了方便理解,在示例代码中使用了json字符串来传输数据,实际情况一般都是使用字节

2.1.穿透客户端

通过net.createConnection创建Socket连接,在连接成功后发送相关数据到服务端

代码:

const net = require('net');// 配置const CONFIG = {     //一些配置....};// 用于校验请求的codelet CODE;// 创建用于连接校验服务端的 客户端连接let linkClient = net.createConnection({ port: CONFIG.server_port, host: CONFIG.server_addr }, () => {    // 创建用于校验请求的code    CODE = (+new Date());    // 发送数据校验    linkClient.write(JSON.stringify({ token: CONFIG.token, code: CODE, type: 'register', binds: CONFIG.binds }));    console.log(`[${(new Date()).toLocaleString()}] 正在尝试连接...`);});linkClient.setTimeout(CONFIG.timeout);linkClient.on('data', (data) => {    try {        data = JSON.parse(data);        // 校验请求        if (data.code == CODE) {            if (data.type == 'register') {                console.log(`[${(new Date()).toLocaleString()}] 已连接到服务器 ${CONFIG.server_addr}:${CONFIG.server_port}`);            } else {                // ....               }            return;        }    } catch (error) {        // 异常    }    return linkClient.end();});linkClient.on('error', (err) => { });linkClient.on('end', () => { });

2.2.穿透服务端

通过net.createServer创建端口监听服务

在接收到数据对数据进行校验与绑定处理

const net = require('net');// 配置const CONFIG = {     //...};// 客户端链接集let linkClients = {};// 客户端绑定的应用let clientBings = {};// 连接记录let socketRecords = {}; // 远程监听访问 用于穿透const listenServer = net.createServer((socket) => {    let id = [socket.remoteAddress, socket.remoteFamily, socket.remotePort].join("_");    console.log(`[${(new Date()).toLocaleString()}] ${socket.remoteAddress}:${socket.remotePort} 上线...`);    if (!linkClients[id]) {        // 保存连接        linkClients[id] = socket;        socket.on('data', (data) => {            try {                data = JSON.parse(data);                let [token, type, code, binds] = [data.token, data.type, data.code, data.binds];                if (token != token) return socket.end();                if (type == 'register') {// 客户端注册                    for (let k in binds) {                        let d = binds[k];                        if (!clientBings[k]) {                            [d.code, d.name, d.linkSocket, d.linkId] = [data.code, k, socket, id];                            //d.forwardServer = createForwardServer(d);//绑定客户端App对应服务端开放的端口服务                            clientBings[k] = d;                        }                    }                    return socket.write(JSON.stringify({ code: code, type: type, id: id }));                }              } catch (error) {                //                 removeInfo(id);            }            socket.end();        });        socket.on('error', (err) => {        })        socket.on('end', (data) => {        });    }});// 启动服务端监听listenServer.listen(CONFIG.server_port, CONFIG.server_addr);

3.完善功能

3.1.给穿透客户端添加动态创建Socket连接与异常重试功能

动态创建Socket很简单,就是根据服务端数据new Socket两个,一个连接服务端,一个用来连接局域网的应用。

而异常重试功能只不过是加了个定时器进行定时状态检查罢了

代码:

const net = require('net');// 配置const CONFIG = {    server_addr: "xxx.xxx.xxx.xxx",//服务端地址    server_port: 10001,//服务端端口    token: "hello server",//连接令牌    timeout: 3000,//请求超时时间    interval: 5000,//异常重试    binds: {//绑定内网应用        ssh: {            local_ip: "192.168.199.193",//当前内网被转发的ip            local_port: 22,//当前内网被转发的端口            remote_port: 10002,//服务端映射的端口        },        aria2: {            local_ip: "192.168.199.193",//当前内网被转发的ip            local_port: 6800,//当前内网被转发的端口            remote_port: 10003,//服务端映射的端口        },        aria2Ng: {            local_ip: "127.0.0.1",//当前内网被转发的ip            local_port: 80,//当前内网被转发的端口            remote_port: 10004,//服务端映射的端口        }    }};// 用于校验请求的codelet CODE;let linkClient;function listenClient() {    // 创建用于连接校验服务端的 客户端连接    linkClient = net.createConnection({ port: CONFIG.server_port, host: CONFIG.server_addr }, () => {        // 创建用于校验请求的code        CODE = (+new Date());        // 发送数据校验        linkClient.write(JSON.stringify({ token: CONFIG.token, code: CODE, type: 'register', binds: CONFIG.binds }));        console.log(`[${(new Date()).toLocaleString()}] 正在尝试连接...`);    });    linkClient.setTimeout(CONFIG.timeout);    linkClient.on('data', (data) => {        try {            data = JSON.parse(data);            // 校验请求            if (data.code == CODE) {                if (data.type == 'register') {                    console.log(`[${(new Date()).toLocaleString()}] 已连接到服务器 ${CONFIG.server_addr}:${CONFIG.server_port}`);                } else {                    // 请求标识                    let key = data.key;                    // 应用名称                    let name = data.name;                    // 本地的应用                    let localApp = CONFIG.binds[name];                    if (!localApp) linkClient.end();                    // 创建服务端用的Socket                    let serverClient = new net.Socket();                    serverClient.setTimeout(CONFIG.timeout);                    // 创建局域网内的Socket                    let localClient = new net.Socket();                    localClient.setTimeout(CONFIG.timeout);                    // 连接服务端                    serverClient.connect(CONFIG.server_port, CONFIG.server_addr, function () {                        serverClient.write(JSON.stringify({ type: 'connect', key: key }));                        // 连接本地服务器                        localClient.connect(localApp.local_port, localApp.local_ip, function () {                            console.log(`[${(new Date()).toLocaleString()}] [${name}] ${localApp.local_port}<===>${localApp.remote_port}`);                        });                        // 本地数据转发服务端                        localClient.pipe(serverClient);                        localClient.on('end', function (data) {                            serverClient.end();                        });                    })                    serverClient.on('error', function (err) {                        console.error(`[${(new Date()).toLocaleString()}] 访问服务器异常,${err.message}`);                        localClient.end();                    })                    localClient.on('error', function (err) {                        console.error(`[${(new Date()).toLocaleString()}] 局域网访问异常,${err.message}`);                        serverClient.end();                    });                    // 服务端数据转发本地                    serverClient.pipe(localClient);                    serverClient.on('end', function (data) {                        localClient.end();                    });                }                return;            }        } catch (error) {            // 异常        }        return linkClient.end();    });    linkClient.on('error', (err) => {        console.error(`[${(new Date()).toLocaleString()}] 异常:` + err.message);    });    linkClient.on('end', () => {        console.log(`[${(new Date()).toLocaleString()}] 已从服务器 ${CONFIG.server_port}:${CONFIG.server_port} 断开`);    });}listenClient();//异常重试setInterval(() => {    if (linkClient.readyState == "closed") {        linkClient.end();        console.log(`[${(new Date()).toLocaleString()}] 正在重新连接服务器...`);        listenClient();    }}, CONFIG.interval);

3.2.给穿透服务端添加绑定端口转发服务

服务端在Socket管理上,已经数据转发的过程上理解起来比客户端稍微复杂

代码:

const net = require('net');// 配置const CONFIG = {    server_addr: "0.0.0.0",//服务端地址 一般是0.0.0.0或127.0.0.1    server_port: 10001,//服务端端口    token: "hello server",//连接令牌 };// 客户端链接集let linkClients = {};// 客户端绑定的应用let clientBings = {};// 连接记录let socketRecords = {};// 删除相关信息const removeInfo = function (id) {    if (linkClients[id]) {        linkClients[id] = null;        delete linkClients[id];    }    for (let k in clientBings) {        let d = clientBings[k];        if (id == d.linkId) {            d.forwardServer.close();            clientBings[k] = null;            delete clientBings[k];        }    }};// 端口转发服务 用于开放访问function createForwardServer(conf) {    let forwardServer = net.createServer((socket) => {        // 判断客户是否在线        if (!linkClients[conf.linkId]) return socket.end();        let id = [socket.remoteAddress, socket.remoteFamily, socket.remotePort].join("_");        if (!socketRecords[id]) socketRecords[id] = { bind: socket };        // 发送需要数据 告诉客户端 开启新的连接用于访问        conf.linkSocket.write(JSON.stringify({ key: id, name: conf.name, code: conf.code }));        socket.on('error', () => {            socket.end();        });        socket.on('end', () => {            if (socketRecords[id]) {                if (socketRecords[id].bind) socketRecords[id].client.end();                if (socketRecords[id].client) socketRecords[id].bind.end();                delete socketRecords[id];            }        })    });    forwardServer.listen(conf.remote_port, () => {        console.log(`[${(new Date()).toLocaleString()}] [${conf.name}] 转发服务开启  ${conf.local_port}<===>${conf.remote_port}`);    });    return forwardServer;}// 远程监听访问 用于穿透const listenServer = net.createServer((socket) => {    let id = [socket.remoteAddress, socket.remoteFamily, socket.remotePort].join("_");    console.log(`[${(new Date()).toLocaleString()}] ${socket.remoteAddress}:${socket.remotePort} 上线...`);    if (!linkClients[id]) {        // 保存连接        linkClients[id] = socket;        socket.on('data', (data) => {            try {                data = JSON.parse(data);                let [token, type, code, binds] = [data.token, data.type, data.code, data.binds];                if (token != token) return socket.end();                if (type == 'register') {// 客户端注册                    for (let k in binds) {                        let d = binds[k];                        if (!clientBings[k]) {                            [d.code, d.name, d.linkSocket, d.linkId] = [data.code, k, socket, id];                            d.forwardServer = createForwardServer(d);//绑定客户端App对应服务端开放的端口服务                            clientBings[k] = d;                        }                    }                    return socket.write(JSON.stringify({ code: code, type: type, id: id }));                } else if (type == 'connect') {// 客户端连接                     let id = data.key;                    let socketRecord = socketRecords[id];                    if (socketRecord && socketRecord.bind && !socketRecord.client) {                        socket.firstConnection = false;                        socketRecord.client = socket;//设置 客户端连接soket                        // 数据转发                        socket.pipe(socketRecord.bind);                        socketRecord.bind.pipe(socket);                        socketRecord.bind.on('end', () => {                            socket.end();                        });                        socketRecord.bind.on('error', (err) => {                            socket.end();                        });                        return;                    }                }            } catch (error) {                //                 removeInfo(id);            }            socket.end();        });        socket.on('error', (err) => {            //             removeInfo(id);        })        socket.on('end', (data) => {            removeInfo(id);        });    }});// 启动服务端监听listenServer.listen(CONFIG.server_port, CONFIG.server_addr);

4.测试

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第11张

Nodejs实现简单的TCP内网穿透,Nodejs内网穿透,Node内网穿透,NodejsTCP内网穿透,NodeTCP内网穿透,内网穿透 互联网IT 第12张



  • 发表评论
  • 查看评论
【暂无评论!】

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。