UNPKG

@kloak-it/tq-proxy

Version:
384 lines (378 loc) 14.8 kB
"use strict"; /*! * Copyright 2018 CoNET Technology Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sockt4 = exports.socks5 = void 0; const Rfc1928 = __importStar(require("./rfc1928")); const res = __importStar(require("./res")); const Crypto = __importStar(require("crypto")); const httpProxy_1 = __importDefault(require("./httpProxy")); const Util = __importStar(require("util")); const log_1 = require("../GateWay/log"); const safe_1 = __importDefault(require("colors/safe")); // socks 5 headers const server_res = { NO_AUTHENTICATION_REQUIRED: Buffer.from('0500', 'hex') }; const isSslFromBuffer = (buffer) => { const ret = buffer[0] === 0x16 && buffer[1] === 0x03; return ret; }; const getHostNameFromSslConnection = (buffer) => { if (!isSslFromBuffer(buffer)) { return null; } const lengthPoint = buffer.readInt16BE(0x95); const serverName = buffer.slice(0x97, 0x97 + lengthPoint); // 00000090 00 02 01 00 00 0A 00 08 00 06 00 1D 00 17 00 18 ................ // use IP address if (lengthPoint === 0x0A00 && serverName[0] === 0x8 && serverName[1] === 0x0) { return null; } (0, log_1.hexDebug)(serverName); (0, log_1.logger)(`getHostNameFromSslConnection lengthPoint[${lengthPoint.toString(16)}] === 0x0A ${lengthPoint === 0x0A00} serverName[0] [${serverName[0].toString(16)}] serverName[0] === 0x8 ${serverName[0] === 0x8} && serverName[1] [${serverName[1].toString(16)}] === 0x06 [${serverName[1] === 0x0}] `); return serverName.toString(); }; class socks5 { stopConnection(req) { req.REP = Rfc1928.Replies.COMMAND_NOT_SUPPORTED_or_PROTOCOL_ERROR; return this.socket.write(req.buffer); } closeSocks5(buffer) { //console.log (`close proxy socket!`) if (this.socket) { if (this.socket.writable) { this.socket.end(buffer); } if (typeof this.socket.removeAllListeners === 'function') this.socket.removeAllListeners(); } } connectStat3(req) { let userAgent = ''; switch (req.cmd) { case Rfc1928.CMD.CONNECT: { break; } case Rfc1928.CMD.BIND: { } case Rfc1928.CMD.UDP_ASSOCIATE: { } default: { return this.stopConnection(req); } } const uuuu = { uuid: this.uuid, host: req.host, hostIPAddress: req.hostAddress, buffer: '', cmd: this._cmd, port: req.port, ssl: false }; const requestObj = { remotePort: this.socket.remotePort, remoteAddress: this.socket.remoteAddress, targetHost: uuuu.host, targetPort: uuuu.port, methods: '', socks: 'Sock5', uuid: uuuu.uuid }; this.socket.once('data', (_data) => { // gateway shutdown if (!this.proxyServer.gateway) { //console.log (`SOCK5 !this.proxyServer.gateway STOP sokcet! res.HTTP_403`) return this.socket.end(res._HTTP_PROXY_302()); } if (this.debug) { (0, log_1.logger)(`connectStat3 buffer`); (0, log_1.hexDebug)(_data); } uuuu.ssl = isSslFromBuffer(_data); if (!uuuu.ssl) { const httpHeader = new httpProxy_1.default(_data); uuuu.host = httpHeader.host || uuuu.host; if (!httpHeader.host) { (0, log_1.logger)(safe_1.default.red(`Socks 5 have no host [header]`)); (0, log_1.logger)(Util.inspect(httpHeader.headers, false, 3, true)); } userAgent = httpHeader.headers['user-agent']; requestObj.methods = httpHeader.methods; } uuuu.buffer = _data.toString('base64'); if (this.debug) { (0, log_1.logger)(Util.inspect(uuuu)); (0, log_1.logger)(Util.inspect(requestObj)); } return this.proxyServer.gateway.requestGetWay(requestObj, uuuu, userAgent, this.socket); }); req.REP = Rfc1928.Replies.GRANTED; return this.socket.write(req.buffer); } udpProcess(data) { data.REP = Rfc1928.Replies.GRANTED; return this.socket.write(data.buffer); } connectStat2(data) { if (this.debug) { (0, log_1.hexDebug)(data); } const req = new Rfc1928.Requests(data); this.ATYP = req.ATYP; this.host = req.domainName; this.port = req.port; this.cmd = req.cmd; this.targetIpV4 = req.ATYP_IP4Address; //.serverIP = this.socket.localAddress.split (':')[3] // IPv6 not support! switch (this.cmd) { case Rfc1928.CMD.CONNECT: { this.keep = true; this._cmd = 'CONNECT'; break; } case Rfc1928.CMD.BIND: { this._cmd = 'BIND'; break; } case Rfc1928.CMD.UDP_ASSOCIATE: { this._cmd = 'UDP_ASSOCIATE'; //logger( `Rfc1928.CMD.UDP_ASSOCIATE data[${ data.toString ('hex')}]` ) break; } default: { this._cmd = 'UNKNOW'; (0, log_1.logger)(`Socks 5 unknow cmd: `, data.toString('hex'), Util.inspect(req, false, 3, true)); break; } } // IPv6 not support // if ( req.IPv6 ) { // this.keep = false // } const obj = { ATYP: this.ATYP, host: this.host, hostType: typeof this.host, port: this.port, targetIpV4: this.targetIpV4, cmd: this._cmd, buffer: data.toString('hex') }; if (!this.keep) { req.REP = Rfc1928.Replies.COMMAND_NOT_SUPPORTED_or_PROTOCOL_ERROR; if (this.debug) { (0, log_1.logger)(safe_1.default.red(`Rfc1928.Replies.COMMAND_NOT_SUPPORTED_or_PROTOCOL_ERROR STOP socks 5 connecting.`)); (0, log_1.logger)(Util.inspect(obj)); } return this.closeSocks5(req.buffer); } if (this.cmd === Rfc1928.CMD.UDP_ASSOCIATE) { return (0, log_1.logger)('this.cmd === Rfc1928.CMD.UDP_ASSOCIATE skip!'); } return this.connectStat3(req); } constructor(socket, data, agent, proxyServer) { this.socket = socket; this.data = data; this.agent = agent; this.proxyServer = proxyServer; this.host = null; this.ATYP = null; this.port = null; this.cmd = null; this._cmd = ''; this.targetIpV4 = null; this.keep = false; this.clientIP = this.socket.remoteAddress.split(':')[3] || this.socket.remoteAddress; this.debug = this.proxyServer.debug; this.uuid = Crypto.randomBytes(10).toString('hex'); if (this.debug) { (0, log_1.logger)(safe_1.default.yellow(`new socks v5`)); (0, log_1.hexDebug)(data); } this.socket.once('data', (chunk) => { return this.connectStat2(chunk); }); this.socket.write(server_res.NO_AUTHENTICATION_REQUIRED); this.socket.resume(); } } exports.socks5 = socks5; class sockt4 { constructor(socket, buffer, agent, proxyServer) { this.socket = socket; this.buffer = buffer; this.agent = agent; this.proxyServer = proxyServer; this.req = new Rfc1928.socket4Requests(this.buffer); this.host = this.req.domainName; this.port = this.req.port; this.uuid = Crypto.randomBytes(10).toString('hex'); this.cmd = this.req.cmd; this._cmd = ''; this.targetIpV4 = this.req.targetIp; this.keep = false; this.debug = false; this.id = safe_1.default.blue(`[${this.uuid}] [${this.socket.remoteAddress}:${this.socket.remotePort}] --> [${this.host}:${this.port}]`); this.debug = proxyServer.debug; this.socket.pause(); if (this.debug) { (0, log_1.logger)(safe_1.default.yellow(`new socks v4`)); (0, log_1.hexDebug)(buffer); } switch (this.cmd) { case Rfc1928.CMD.CONNECT: { this.keep = true; this._cmd = 'CONNECT'; if (this.debug) { (0, log_1.logger)(safe_1.default.gray(`${this.id} sockt4 got Rfc1928 command ${safe_1.default.magenta('CONNECT')}`)); } break; } case Rfc1928.CMD.BIND: { this._cmd = 'BIND'; if (this.debug) { (0, log_1.logger)(safe_1.default.gray(`${this.id} sockt4 got Rfc1928 command ${safe_1.default.magenta('BIND')}`)); } break; } case Rfc1928.CMD.UDP_ASSOCIATE: { if (this.debug) { (0, log_1.logger)(safe_1.default.gray(`${this.id} sockt4 got Rfc1928 command ${safe_1.default.magenta('UDP_ASSOCIATE')}`)); } this._cmd = 'UDP_ASSOCIATE'; break; } default: { (0, log_1.logger)(safe_1.default.red(`${this.id} sockt4 got Rfc1928 unknow command [${this.cmd}]`)); this._cmd = 'UNKNOW'; break; } } if (!this.keep) { this.debug ? (0, log_1.logger)(safe_1.default.red(`STOP session`)) : null; this.socket.end(this.req.request_failed); return; } this.connectStat2(); } connectStat2() { this.socket.once('data', (_data) => { if (this.debug) { (0, log_1.logger)(`SOCK4 connectStat2 [${this.host || this.targetIpV4}] get data`); (0, log_1.hexDebug)(_data); } if (!this.proxyServer.gateway) { (0, log_1.logger)(safe_1.default.red(`SOCK4 !this.proxyServer.gateway STOP sokcet! res.HTTP_403`)); return this.socket.end(res._HTTP_PROXY_302()); } this.connect(_data); }); const buffer = this.req.request_4_granted('0.0.0.255', this.port); this.socket.write(buffer); return this.socket.resume(); } connect(buffer) { const isSsl = isSslFromBuffer(buffer); let userAgent = ''; let methods = 'GET'; let httpHeader = null; const uuuu = { uuid: this.uuid, host: this.host, hostIPAddress: this.req.targetIp, buffer: buffer.toString('base64'), cmd: this._cmd, port: this.req.port, ssl: isSslFromBuffer(buffer) }; if (!isSsl) { httpHeader = new httpProxy_1.default(buffer); uuuu.host = httpHeader.host; userAgent = httpHeader.headers['user-agent']; methods = httpHeader.methods; } const requestObj = { remotePort: this.socket.remotePort, remoteAddress: this.socket.remoteAddress, targetHost: uuuu.host, targetPort: uuuu.port, methods: httpHeader ? httpHeader.methods : 'CONNECT', socks: this.req.targetIp ? 'Sock4' : 'Sock4a', uuid: uuuu.uuid }; if (this.debug) { (0, log_1.logger)(Util.inspect(uuuu, false, 3, true)); (0, log_1.logger)(Util.inspect(requestObj, false, 3, true)); } if (this.proxyServer.gateway && typeof this.proxyServer.gateway.requestGetWay === 'function') { return this.proxyServer.gateway.requestGetWay(requestObj, uuuu, userAgent, this.socket); } return this.socket.end(this.req.request_failed); } } exports.sockt4 = sockt4; /* export class UdpDgram { private server: Dgram.Socket = null public port = 0 private createDgram () { this.server = Dgram.createSocket ( 'udp4' ) this.server.once ( 'error', err => { console.log ( 'server.once error close server!', err ) this.server.close () }) this.server.on ( 'message', ( msg: Buffer, rinfo ) => { console.log(`UdpDgram server msg: ${ msg.toString('hex') } from ${ rinfo.address }:${ rinfo.port }`) }) this.server.once ( 'listening', () => { const address = this.server.address() this.port = address.port console.log ( `server listening ${ address.address }:${ address.port }` ) }) this.server.bind ({ port: 0 } , ( err, kkk ) => { if ( err ) { return console.log ( `server.bind ERROR`, err ) } console.log ( kkk ) }) } constructor () { this.createDgram () } } */