lightsword
Version:
LightSword Secure SOCKS5 Proxy / iOS VPN Server
114 lines (87 loc) • 3.33 kB
text/typescript
//-----------------------------------
// Copyright(c) 2015 Neko
//-----------------------------------
import * as net from 'net';
import * as dgram from 'dgram';
import { Socks5Server } from './socks5Server';
import { REQUEST_CMD, ATYP } from '../../common/socks5constant';
import * as socks5Helper from '../../common/socks5helper';
export class LocalProxyServer extends Socks5Server {
handleRequest(client: net.Socket, request: Buffer): boolean {
let dst = socks5Helper.refineDestination(request);
switch (dst.cmd) {
case REQUEST_CMD.CONNECT:
LocalProxyServer.connectServer(client, dst, request, this.timeout);
break;
case REQUEST_CMD.UDP_ASSOCIATE:
LocalProxyServer.udpAssociate(client, dst);
break;
default:
return false;
}
return true;
}
static bind(client, dst: { port: number, addr: string }) {
}
static udpAssociate(client: net.Socket, dst: { port: number, addr: string }) {
let udpType = 'udp' + (net.isIP(dst.addr) || 4);
let serverUdp = dgram.createSocket(udpType);
serverUdp.bind();
serverUdp.unref();
serverUdp.on('listening', async () => {
let udpAddr = serverUdp.address();
let reply = socks5Helper.createSocks5TcpReply(0x0, udpAddr.family === 'IPv4' ? ATYP.IPV4 : ATYP.IPV6, udpAddr.address, udpAddr.port);
await client.writeAsync(reply);
});
let udpSet = new Set<dgram.Socket>();
serverUdp.on('message', (msg: Buffer, rinfo: dgram.RemoteInfo) => {
let socketId = `${rinfo.address}:${rinfo.port}`;
let dst = socks5Helper.refineDestination(msg);
let proxyUdp = dgram.createSocket(udpType);
proxyUdp.unref();
proxyUdp.on('message', (msg: Buffer) => {
let header = socks5Helper.createSocks5UdpHeader(rinfo.address, rinfo.port);
let data = Buffer.concat([header, msg]);
serverUdp.send(data, 0, data.length, rinfo.port, rinfo.address);
});
proxyUdp.on('error', (err) => console.log(err.message));
proxyUdp.send(msg, dst.headerSize, msg.length - dst.headerSize, dst.port, dst.addr);
udpSet.add(proxyUdp);
});
function dispose() {
client.dispose();
serverUdp.removeAllListeners();
serverUdp.close();
udpSet.forEach(udp => {
udp.close();
udp.removeAllListeners();
});
udpSet.clear();
}
serverUdp.on('error', dispose);
client.on('error', dispose);
client.on('end', dispose);
}
static connectServer(client: net.Socket, dst: { port: number, addr: string }, request: Buffer, timeout: number) {
let proxySocket = net.createConnection(dst.port, dst.addr, async () => {
let reply = new Buffer(request.length);
request.copy(reply);
reply[0] = 0x05;
reply[1] = 0x00;
await client.writeAsync(reply);
proxySocket.pipe(client);
client.pipe(proxySocket);
});
function dispose() {
proxySocket.dispose();
client.dispose();
}
proxySocket.on('end', dispose);
proxySocket.on('error', dispose);
client.on('end', dispose);
client.on('error', dispose);
proxySocket.setTimeout(timeout);
client.setTimeout(timeout);
}
}