lightsword
Version:
LightSword Secure SOCKS5 Proxy / iOS VPN Server
87 lines (70 loc) • 2.75 kB
text/typescript
//-----------------------------------
// Copyright(c) 2016 Neko
//-----------------------------------
import * as net from 'net';
import * as crypto from 'crypto';
import { IP_VER, Protocols } from './protocols';
import * as cryptoEx from '../../common/cipher';
import * as addrHelper from '../lib/addressHelper';
import { HandshakeOptions } from '../../common/constant';
import { handleUDP } from './udp';
import { handleTCP } from './tcp';
export type VpnHandshake = {
ipVer: IP_VER,
payloadProtocol: Protocols,
flags: number,
destAddress: number[],
destHost: string,
destPort: number,
extra: Buffer,
}
const SupportedIPVers = [IP_VER.V4, IP_VER.V6];
const SupportedProtocols = [Protocols.TCP, Protocols.UDP];
export async function handleAppleVPN(client: net.Socket, handshakeData: Buffer, options: HandshakeOptions): Promise<boolean> {
if (handshakeData.length < 9) return false;
let handshake: VpnHandshake = null;
try {
handshake = extractHandeshake(handshakeData);
if (!SupportedIPVers.contains(handshake.ipVer)) return false;
if (!SupportedProtocols.contains(handshake.payloadProtocol)) return false;
} catch (error) {
return false;
}
if (handshake.flags === 0x00 && handshake.destHost === '0.0.0.0' && handshake.destPort === 0) {
try { await handleHandshake(client, handshake, options); } catch (error) { return false; }
return true;
}
if (addrHelper.isIllegalAddress(handshake.destHost)) {
client.dispose();
return true;
}
switch(handshake.payloadProtocol) {
case Protocols.TCP:
handleTCP(client, handshake, options);
return true;
case Protocols.UDP:
handleUDP(client, handshake, options);
return true;
}
return false;
}
function extractHandeshake(data: Buffer): VpnHandshake {
let ipVer = data[0];
let payloadProtocol = data[1];
let flags = data[2];
let ipLength = ipVer == IP_VER.V4 ? 4 : 16;
let destAddress = data.skip(3).take(ipLength).toArray();
let destPort = data.readUInt16BE(3 + ipLength);
let extra = data.slice(3 + ipLength + 2);
let destHost = addrHelper.ntoa(destAddress);
return { ipVer, payloadProtocol, flags, destAddress, destHost, destPort, extra }
}
async function handleHandshake(client: net.Socket, handshake: VpnHandshake, options: HandshakeOptions) {
let cipher = cryptoEx.createCipher(options.cipherAlgorithm, options.password, handshake.extra).cipher;
let md5 = crypto.createHash('md5').update(handshake.extra).digest();
let randomPadding = new Buffer(Number((Math.random() * 128).toFixed()));
client.on('error', () => {});
await client.writeAsync(Buffer.concat([cipher.update(md5), cipher.update(randomPadding)]));
client.dispose();
}