Skip to content

Commit

Permalink
feat: create a demo for tcp/udp traversal
Browse files Browse the repository at this point in the history
  • Loading branch information
purpose233 committed May 13, 2019
0 parents commit f781fca
Show file tree
Hide file tree
Showing 17 changed files with 586 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/
node_modules/
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "socket-traversal",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/purpose233/socket-traversal.git"
},
"author": "purpose233",
"license": "ISC",
"bugs": {
"url": "https://github.com/purpose233/socket-traversal/issues"
},
"homepage": "https://github.com/purpose233/socket-traversal#readme",
"dependencies": {
"lodash": "^4.17.11",
"text-encoding": "^0.7.0"
}
}
Empty file added src/common/config.js
Empty file.
19 changes: 19 additions & 0 deletions src/common/socket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const dgram = require('dgram');

export const createUdpSocket = (port, onListening, onError) => {
const socket = dgram.createSocket('udp4');
socket.on('listening',
onListening ? onListening :
function() {
console.log("echo server is listening on port %d.", port);
}
);
socket.on('error',
onError ? onError :
function(err) {
console.log('error, msg - %s, stack - %s\n', err.message, err.stack);
}
);
socket.bind(port);
return socket;
};
46 changes: 46 additions & 0 deletions src/udpClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const dgram = require('dgram');
const _ = require('lodash');
import config from './udpClient.json';
import {createUdpSocket} from './common/socket';

// TODO: need to parse config

const ServerAddress = config.common.serverAddress;
const ServerPort = config.common.serverPort;
const UDPConfigs = config.udp;

for (const udpConfig of UDPConfigs) {

}


const clientSocket = createUdpSocket(clientSocket);

const clientSocket = dgram.createSocket('udp4');

clientSocket.on('message', function(msg, rinfo) {
console.log('recv %s(%d) from server\n', msg, msg.length);
let addr = JSON.parse(msg.slice(0, msg.indexOf('|')));
msg = msg.slice(msg.indexOf('|') + 1);

const dataSocket = dgram.createSocket('udp4');
dataSocket.on('message', function(msg, rinfo) {
console.log('recv %s from localhost\n', msg);
dataSocket.send(msg, 0, msg.length, addr.port, addr.ip);
});
dataSocket.bind(8001);
dataSocket.send(msg, 0, msg.length, addr.port, 'localhost');
});

clientSocket.on('error', function(err) {
console.log('error, msg - %s, stack - %s\n', err.message, err.stack);
});

clientSocket.bind(8000);
const bindInfo = {
bindTo: 7001,
bindFrom: 11111
};
const bindMsg = JSON.stringify(bindInfo);
clientSocket.send(bindMsg, 0, bindMsg.length, 7000, 'localhost');

12 changes: 12 additions & 0 deletions src/udpClient.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"common": {
"serverAddress": "127.0.0.1",
"serverPort": 7000
},
"udp": [
{
"localPort": 11112,
"remotePort": 7002
}
]
}
49 changes: 49 additions & 0 deletions src/udpServer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const dgram = require('dgram');
const _ = require('lodash');
import config from './udpServer.json';
import {createUdpSocket} from './common/socket';

// TODO: need to parse config
const ServerPort = config.common.bindPort;
const ClientPort = config.common.clientPort;
const UDPConfigs = config.udp;

// binders contains the info of udpClient.
const binders = {};

const mainSocket = createUdpSocket(ServerPort);

// Main socket only receive message from udpClient.
mainSocket.on('message', function (msg, rinfo) {
console.log('recv %s(%d bytes) from client %s:%d\n', msg, msg.length, rinfo.address, rinfo.port);

let bindInfo;
try {
bindInfo = JSON.parse(msg);
} catch (e) {
bindInfo = null;
}
if (bindInfo && bindInfo.bindTo && binders[bindInfo.bindTo]) {
binders[bindInfo.bindTo].remotePort = bindInfo.bindFrom;
binders[bindInfo.bindTo].remoteIP = rinfo.address;
}
});

for (const udpConfig of UDPConfigs) {
const dataSocket = createUdpSocket(udpConfig.listenPort);
dataSocket.on('message', function (msg, rinfo) {
const binder = binders[udpConfig.listenPort];
if (binder) { return; }
msg = JSON.stringify({
ip: binder.remoteIP,
port: binder.remotePort
}) + '|' + msg;
dataSocket.send(msg, 0, msg.length, addr.port, ClientPort);
});
binders[udpConfig.listenPort] = {
// localPort: udpConfig.listenPort,
socket: dataSocket,
remotePort: 0,
remoteIP: null
};
}
12 changes: 12 additions & 0 deletions src/udpServer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"common": {
"bindPort": 7000,
"dashBoardPort": 7001,
"clientPort": 8000
},
"udp": [
{
"listenPort": 7002
}
]
}
40 changes: 40 additions & 0 deletions test/tcpClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const Net = require('net');
const TextEncoding = require('text-encoding');

const TunnelServerPort = 7001;
const ServerIP = '127.0.0.1';

const BindingPort = 11111;

const decoder = new TextEncoding.TextDecoder('utf-8');

const tunnelSockets = {};

// TODO: set interval time to reconnect
const mainClientSocket = Net.createConnection(TunnelServerPort, ServerIP);

// data: {type: 'createTunnel', uuid: int}
mainClientSocket.on('data', (data) => {
console.log('mainClientSocket receive data: ' + data);
const receiveInfo = JSON.parse(decoder.decode(data));
const uuid = receiveInfo.uuid;

const tunnelSocket = Net.createConnection(TunnelServerPort, ServerIP);
tunnelSockets[uuid] = tunnelSocket;
tunnelSocket.on('close', () => {
delete tunnelSockets[uuid];
});
tunnelSocket.on('connect', () => {
const replyInfo = {type: 'tunnel', uuid};
tunnelSocket.write(JSON.stringify(replyInfo));
});

const dataSocket = Net.createConnection(BindingPort, '127.0.0.1');
tunnelSocket.pipe(dataSocket).pipe(tunnelSocket);
});

mainClientSocket.on('connect', () => {
mainClientSocket.write(JSON.stringify({type: 'main'}));
});

mainClientSocket.on('error', (e) => {console.log(e)});
53 changes: 53 additions & 0 deletions test/tcpServer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const Net = require('net');
const TextEncoding = require('text-encoding');

const RemoteServerPort = 7000;
const TunnelServerPort = 7001;

const decoder = new TextEncoding.TextDecoder('utf-8');

let UUID = 0;
let mainClientSocket = null;
const remoteSockets = {};
const tunnelSockets = {};

const remoteServer = Net.createServer(function (socket) {
socket.on('error', (e) => {console.log(e);});

const socketId = UUID++;
remoteSockets[socketId] = socket;
socket.on('close', () => {
delete remoteSockets[socketId];
});
socket.pause();
const info = {type: 'createTunnel', uuid: socketId};
mainClientSocket.write(JSON.stringify(info));
});

remoteServer.listen(RemoteServerPort, '127.0.0.1');

const tunnelServer = Net.createServer((socket) => {
let isPiping = false;
socket.on('error', (e) => {console.log(e);});
// data: {type: 'main'|'tunnel', uuid: int}
socket.on('data', (data) => {
if (isPiping) { return; }
console.log('Tunnel receive data: ' + data);
const info = JSON.parse(decoder.decode(data));
const uuid = info.uuid;
if (info.type === 'main') {
mainClientSocket = socket;
} else if (info.type === 'tunnel') {
tunnelSockets[uuid] = socket;
socket.on('close', () => {
delete tunnelSockets[uuid];
});
remoteSockets[uuid].pipe(socket).pipe(remoteSockets[uuid]);
remoteSockets[uuid].resume();
isPiping = true;
}
});
});

tunnelServer.listen(TunnelServerPort, '127.0.0.1');

27 changes: 27 additions & 0 deletions test/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import socket

ipPort = ('127.0.0.1', 11111)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(ipPort)
s.listen(5)

while True:
conn, addr = s.accept();
print('got connected from', addr)

receivedMsg = conn.recv(1024)
print(receivedMsg.decode('utf-8'))
conn.send('bye'.encode())
conn.close()

s.close()

# ipPort = ('127.0.0.1', 11111)
# s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# s.bind(ipPort)

# while(True):
# byteMsg, addr = s.recvfrom(1024)
# strMsg = byteMsg.decode("utf-8")
# print(strMsg, addr)
# # s.sendto('hi'.encode(), addr)
16 changes: 16 additions & 0 deletions test/test2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1', 7000))
s.send('hi'.encode())
receivedMsg = s.recv(1024)
print(receivedMsg.decode('utf-8'))
s.close()

# s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# s.sendto('exit'.encode(), ('127.0.0.1', 7001))
# # byteMsg, addr = s.recvfrom(1024)
# # strMsg = byteMsg.decode("utf-8")
# # print(strMsg, addr)
# s.close()
11 changes: 11 additions & 0 deletions test/test3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import socket

ipPort = ('127.0.0.1', 11112)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(ipPort)

while(True):
byteMsg, addr = s.recvfrom(1024)
strMsg = byteMsg.decode('utf-8')
print(strMsg, addr)
s.sendto('bye'.encode(), addr)
9 changes: 9 additions & 0 deletions test/test4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.sendto('hi'.encode(), ('127.0.0.1', 7003))
byteMsg, addr = s.recvfrom(1024)
strMsg = byteMsg.decode('utf-8')
print(strMsg, addr)
s.close()
Loading

0 comments on commit f781fca

Please sign in to comment.