socksv5-master/000077500000000000000000000000001264411760300137505ustar00rootroot00000000000000socksv5-master/LICENSE000066400000000000000000000020601264411760300147530ustar00rootroot00000000000000Copyright 2014 Brian White. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.socksv5-master/README.md000066400000000000000000000212261264411760300152320ustar00rootroot00000000000000Description =========== SOCKS protocol version 5 server and client implementations for node.js Requirements ============ * [node.js](http://nodejs.org/) -- v0.10.0 or newer Install ======= npm install socksv5 Examples ======== * Server with no authentication and allowing all connections: ```javascript var socks = require('socksv5'); var srv = socks.createServer(function(info, accept, deny) { accept(); }); srv.listen(1080, 'localhost', function() { console.log('SOCKS server listening on port 1080'); }); srv.useAuth(socks.auth.None()); ``` * Server with username/password authentication and allowing all (authenticated) connections: ```javascript var socks = require('socksv5'); var srv = socks.createServer(function(info, accept, deny) { accept(); }); srv.listen(1080, 'localhost', function() { console.log('SOCKS server listening on port 1080'); }); srv.useAuth(socks.auth.UserPassword(function(user, password, cb) { cb(user === 'nodejs' && password === 'rules!'); })); ``` * Server with no authentication and redirecting all connections to localhost: ```javascript var socks = require('socksv5'); var srv = socks.createServer(function(info, accept, deny) { info.dstAddr = 'localhost'; accept(); }); srv.listen(1080, 'localhost', function() { console.log('SOCKS server listening on port 1080'); }); srv.useAuth(socks.auth.None()); ``` * Server with no authentication and denying all connections not made to port 80: ```javascript var socks = require('socksv5'); var srv = socks.createServer(function(info, accept, deny) { if (info.dstPort === 80) accept(); else deny(); }); srv.listen(1080, 'localhost', function() { console.log('SOCKS server listening on port 1080'); }); srv.useAuth(socks.auth.None()); ``` * Server with no authentication, intercepting all connections to port 80, and passing through all others: ```javascript var socks = require('socksv5'); var srv = socks.createServer(function(info, accept, deny) { if (info.dstPort === 80) { var socket; if (socket = accept(true)) { var body = 'Hello ' + info.srcAddr + '!\n\nToday is: ' + (new Date()); socket.end([ 'HTTP/1.1 200 OK', 'Connection: close', 'Content-Type: text/plain', 'Content-Length: ' + Buffer.byteLength(body), '', body ].join('\r\n')); } } else accept(); }); srv.listen(1080, 'localhost', function() { console.log('SOCKS server listening on port 1080'); }); srv.useAuth(socks.auth.None()); ``` * Client with no authentication: ```javascript var socks = require('socksv5'); var client = socks.connect({ host: 'google.com', port: 80, proxyHost: '127.0.0.1', proxyPort: 1080, auths: [ socks.auth.None() ] }, function(socket) { console.log('>> Connection successful'); socket.write('GET /node.js/rules HTTP/1.0\r\n\r\n'); socket.pipe(process.stdout); }); ``` * HTTP(s) client requests using a SOCKS Agent: ```javascript var socks = require('socksv5'); var http = require('http'); var socksConfig = { proxyHost: 'localhost', proxyPort: 1080, auths: [ socks.auth.None() ] }; http.get({ host: 'google.com', port: 80, method: 'HEAD', path: '/', agent: new socks.HttpAgent(socksConfig) }, function(res) { res.resume(); console.log(res.statusCode, res.headers); }); // and https too: var https = require('https'); https.get({ host: 'google.com', port: 443, method: 'HEAD', path: '/', agent: new socks.HttpsAgent(socksConfig) }, function(res) { res.resume(); console.log(res.statusCode, res.headers); }); ``` API === Exports ------- * **Server** - A class representing a SOCKS server. * **createServer**([< _function_ >connectionListener]) - _Server_ - Similar to `net.createServer()`. * **Client** - A class representing a SOCKS client. * **connect**(< _object_ >options[, < _function_ >connectListener]) - _Client_ - `options` must contain `port`, `proxyHost`, and `proxyPort`. If `host` is not provided, it defaults to 'localhost'. * **createConnection**(< _object_ >options[, < _function_ >connectListener]) - _Client_ - Aliased to `connect()`. * **auth** - An object containing built-in authentication handlers for Client and Server instances: * **(Server usage)** * **None**() - Returns an authentication handler that permits no authentication. * **UserPassword**(< _function_ >validateUser) - Returns an authentication handler that permits username/password authentication. `validateUser` is passed the username, password, and a callback that you call with a boolean indicating whether the username/password is valid. * **(Client usage)** * **None**() - Returns an authentication handler that uses no authentication. * **UserPassword**(< _string_ >username, < _string_ >password) - Returns an authentication handler that uses username/password authentication. * **HttpAgent** - An Agent class you can use with `http.request()`/`http.get()`. Just pass in a configuration object like you would to the Client constructor or `connect()`. * **HttpsAgent** - Same as `HttpAgent` except it is for use with `https.request()`/`https.get()`. Server events ------------- These are the same as [net.Server](http://nodejs.org/docs/latest/api/net.html#net_class_net_server) events, with the following exception(s): * **connection**(< _object_ >connInfo, < _function_ >accept, < _function_ >deny) - Emitted for each new (authenticated, if applicable) connection request. `connInfo` has the properties: * **srcAddr** - _string_ - The remote IP address of the client that sent the request. * **srcPort** - _integer_ - The remote port of the client that sent the request. * **dstAddr** - _string_ - The destination address that the client has requested. This can be a hostname or an IP address. * **dstPort** - _integer_ - The destination port that the client has requested. `accept` has a boolean parameter which if set to `true`, will return the underlying `net.Socket` for you to read from/write to, allowing you to intercept the request instead of proxying the connection to its intended destination. Server methods -------------- These are the same as [net.Server](http://nodejs.org/docs/latest/api/net.html#net_class_net_server) methods, with the following exception(s): * **(constructor)**([< _object_ >options[, < _function_ >connectionListener]]) - Similar to `net.Server` constructor with the following extra `options` available: * **auths** - _array_ - A pre-defined list of authentication handlers to use (instead of manually calling `useAuth()` multiple times). * **useAuth**(< _function_ >authHandler) - _Server_ - Appends the `authHandler` to a list of authentication methods to allow for clients. This list's order is preserved and the first authentication method to match that of the client's list "wins." Returns the Server instance for chaining. Client events ------------- * **connect**(< _Socket_ >connection) - Emitted when handshaking/negotiation is complete and you are free to read from/write to the connected socket. * **error**(< _Error_ >err) - Emitted when a parser, socket (during handshaking/negotiation), or DNS (if `localDNS` and `strictLocalDNS` are `true`) error occurs. * **close**(< _boolean_ >had_error) - Emitted when the client is closed (due to error and/or socket closed). Client methods -------------- * **(constructor)**(< _object_ >config) - Returns a new Client instance using these possible `config` properties: * **proxyHost** - _string_ - The address of the proxy to connect to (defaults to 'localhost'). * **proxyPort** - _integer_ - The port of the proxy to connect to (defaults to 1080). * **localDNS** - _boolean_ - If `true`, the client will try to resolve the destination hostname locally. Otherwise, the client will always pass the destination hostname to the proxy server for resolving (defaults to true). * **strictLocalDNS** - _boolean_ - If `true`, the client gives up if the destination hostname cannot be resolved locally. Otherwise, the client will continue and pass the destination hostname to the proxy server for resolving (defaults to true). * **auths** - _array_ - A pre-defined list of authentication handlers to use (instead of manually calling `useAuth()` multiple times). * **connect**(< _mixed_ >options[, < _function_ >connectListener]) - _Client_ - Similar to `net.Socket.connect()`. Additionally, if `options` is an object, you can also set the same settings passed to the constructor. * **useAuth**(< _function_ >authHandler) - _Server_ - Appends the `authHandler` to a list of authentication methods to allow for clients. This list's order is preserved and the first authentication method to match that of the client's list "wins." Returns the Server instance for chaining. socksv5-master/index.js000066400000000000000000000006721264411760300154220ustar00rootroot00000000000000var fs = require('fs'), path = require('path'); ['server', 'client', 'Agents'].forEach(function(f) { var exp = require(__dirname + '/lib/' + f), keys = Object.keys(exp); for (var i = 0, len = keys.length; i < len; ++i) exports[keys[i]] = exp[keys[i]]; }); exports.auth = {}; fs.readdirSync(__dirname + '/lib/auth').forEach(function(f) { exports.auth[path.basename(f, '.js')] = require(__dirname + '/lib/auth/' + f); });socksv5-master/lib/000077500000000000000000000000001264411760300145165ustar00rootroot00000000000000socksv5-master/lib/Agents.js000066400000000000000000000250551264411760300163040ustar00rootroot00000000000000// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // Modifications made by Brian White to work with socksv5 var socks = require('../index'); var net = require('net'); var tls = require('tls'); var util = require('util'); var EventEmitter = require('events').EventEmitter; if (!util.debuglog) { var debugs = {}; var debugEnviron; util.debuglog = function(set) { if (debugEnviron === void 0) debugEnviron = process.env.NODE_DEBUG || ''; set = set.toUpperCase(); if (!debugs[set]) { if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { var pid = process.pid; debugs[set] = function() { var msg = util.format.apply(util, arguments); console.error('%s %d: %s', set, pid, msg); }; } else { debugs[set] = function() {}; } } return debugs[set]; }; } var debug = util.debuglog('http'); // New Agent code. // The largest departure from the previous implementation is that // an Agent instance holds connections for a variable number of host:ports. // Surprisingly, this is still API compatible as far as third parties are // concerned. The only code that really notices the difference is the // request object. // Another departure is that all code related to HTTP parsing is in // ClientRequest.onSocket(). The Agent is now *strictly* // concerned with managing a connection pool. function Agent(options) { if (!(this instanceof Agent)) return new Agent(options); EventEmitter.call(this); var self = this; self.defaultPort = 80; self.protocol = 'http:'; self.options = util._extend({}, options); // don't confuse net and make it think that we're connecting to a pipe self.options.path = null; self.requests = {}; self.sockets = {}; self.freeSockets = {}; self.keepAliveMsecs = self.options.keepAliveMsecs || 1000; self.keepAlive = self.options.keepAlive || false; self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets; self.maxFreeSockets = self.options.maxFreeSockets || 256; self.on('free', function(socket, options) { var name = self.getName(options); debug('agent.on(free)', name); if (!socket.destroyed && self.requests[name] && self.requests[name].length) { self.requests[name].shift().onSocket(socket); if (self.requests[name].length === 0) { // don't leak delete self.requests[name]; } } else { // If there are no pending requests, then put it in // the freeSockets pool, but only if we're allowed to do so. var req = socket._httpMessage; if (req && req.shouldKeepAlive && !socket.destroyed && self.options.keepAlive) { var freeSockets = self.freeSockets[name]; var freeLen = freeSockets ? freeSockets.length : 0; var count = freeLen; if (self.sockets[name]) count += self.sockets[name].length; if (count >= self.maxSockets || freeLen >= self.maxFreeSockets) { self.removeSocket(socket, options); socket.destroy(); } else { freeSockets = freeSockets || []; self.freeSockets[name] = freeSockets; socket.setKeepAlive(true, self.keepAliveMsecs); socket.unref(); socket._httpMessage = null; self.removeSocket(socket, options); freeSockets.push(socket); } } else { self.removeSocket(socket, options); socket.destroy(); } } }); } util.inherits(Agent, EventEmitter); exports.HttpAgent = Agent; Agent.defaultMaxSockets = Infinity; Agent.prototype.createConnection = socks.createConnection; // Get the key for a given set of request options Agent.prototype.getName = function(options) { var name = ''; if (options.host) name += options.host; else name += 'localhost'; name += ':'; if (options.port) name += options.port; name += ':'; if (options.localAddress) name += options.localAddress; name += ':'; return name; }; Agent.prototype.addRequest = function(req, options) { // Legacy API: addRequest(req, host, port, path) if (typeof options === 'string') { options = { host: options, port: arguments[2], path: arguments[3] }; } var name = this.getName(options); if (!this.sockets[name]) { this.sockets[name] = []; } var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0; var sockLen = freeLen + this.sockets[name].length; if (freeLen) { // we have a free socket, so use that. var socket = this.freeSockets[name].shift(); debug('have free socket'); // don't leak if (!this.freeSockets[name].length) delete this.freeSockets[name]; socket.ref(); req.onSocket(socket); this.sockets[name].push(socket); } else if (sockLen < this.maxSockets) { debug('call onSocket', sockLen, freeLen); // If we are under maxSockets create a new one. var client = this.createSocket(req, options); client.once('connect', function(s) { req.onSocket(s._tlssock || s); }); } else { debug('wait for socket'); // We are over limit so we'll add it to the queue. if (!this.requests[name]) { this.requests[name] = []; } this.requests[name].push(req); } }; Agent.prototype.createSocket = function(req, options) { var self = this; options = util._extend({}, options); options = util._extend(options, self.options); options.servername = options.host; if (req) { var hostHeader = req.getHeader('host'); if (hostHeader) { options.servername = hostHeader.replace(/:.*$/, ''); } } var name = self.getName(options); debug('createConnection', name, options); options.encoding = null; var client = self.createConnection(options); client.once('connect', function(s) { if (isHttpsAgent(self)) { var upgradeOptions = util._extend({}, options); upgradeOptions.socket = s; s = s._tlssock = tls.connect(upgradeOptions); } if (!self.sockets[name]) { self.sockets[name] = []; } self.sockets[name].push(s); debug('sockets', name, self.sockets[name].length); function onFree() { self.emit('free', s, options); } s.on('free', onFree); function onClose(err) { debug('CLIENT socket onClose'); // This is the only place where sockets get removed from the Agent. // If you want to remove a socket from the pool, just close it. // All socket errors end in a close event anyway. self.removeSocket(s, options); } s.on('close', onClose); function onRemove() { // We need this function for cases like HTTP 'upgrade' // (defined by WebSockets) where we need to remove a socket from the // pool because it'll be locked up indefinitely debug('CLIENT socket onRemove'); self.removeSocket(s, options); s.removeListener('close', onClose); s.removeListener('free', onFree); s.removeListener('agentRemove', onRemove); } s.on('agentRemove', onRemove); }); return client; }; Agent.prototype.removeSocket = function(s, options) { var name = this.getName(options); debug('removeSocket', name, 'destroyed:', s.destroyed); var sets = [this.sockets]; // If the socket was destroyed, remove it from the free buffers too. if (s.destroyed) sets.push(this.freeSockets); sets.forEach(function(sockets) { if (sockets[name]) { var index = sockets[name].indexOf(s); if (index !== -1) { sockets[name].splice(index, 1); // Don't leak if (sockets[name].length === 0) delete sockets[name]; } } }); if (this.requests[name] && this.requests[name].length) { debug('removeSocket, have a request, make a socket'); var req = this.requests[name][0]; // If we have pending requests and a socket gets closed make a new one var client = this.createSocket(req, options); client.once('connect', function(s) { (s._tlssock || s).emit('free'); }); } }; Agent.prototype.destroy = function() { var sets = [this.freeSockets, this.sockets]; sets.forEach(function(set) { Object.keys(set).forEach(function(name) { set[name].forEach(function(socket) { socket.destroy(); }); }); }); }; function HttpsAgent(options) { Agent.call(this, options); this.defaultPort = 443; this.protocol = 'https:'; } util.inherits(HttpsAgent, Agent); exports.HttpsAgent = HttpsAgent; HttpsAgent.prototype.createConnection = function(port, host, options) { if (typeof port === 'object' && port !== null) { options = port; } else if (typeof host === 'object' && host !== null) { options = host; } else if (typeof options === 'object' && options !== null) { options = options; } else { options = {}; } if (typeof port === 'number') { options.port = port; } if (typeof host === 'string') { options.host = host; } debug('createConnection', options); return socks.createConnection(options); }; HttpsAgent.prototype.getName = function(options) { var name = Agent.prototype.getName.call(this, options); name += ':'; if (options.ca) name += options.ca; name += ':'; if (options.cert) name += options.cert; name += ':'; if (options.ciphers) name += options.ciphers; name += ':'; if (options.key) name += options.key; name += ':'; if (options.pfx) name += options.pfx; name += ':'; if (options.rejectUnauthorized !== void 0) name += options.rejectUnauthorized; return name; }; function isHttpsAgent(agent) { return (agent.createConnection === HttpsAgent.prototype.createConnection); } socksv5-master/lib/auth/000077500000000000000000000000001264411760300154575ustar00rootroot00000000000000socksv5-master/lib/auth/None.js000066400000000000000000000003431264411760300167140ustar00rootroot00000000000000module.exports = function NoneAuthHandlers() { return { METHOD: 0x00, server: function serverHandler(stream, cb) { cb(true); }, client: function clientHandler(stream, cb) { cb(true); } }; }; socksv5-master/lib/auth/UserPassword.js000066400000000000000000000131201264411760300204530ustar00rootroot00000000000000var STATE_VERSION = 0, // server STATE_ULEN = 1, STATE_UNAME = 2, STATE_PLEN = 3, STATE_PASSWD = 4, // client STATE_STATUS = 5; // server var BUF_SUCCESS = new Buffer([0x01, 0x00]), BUF_FAILURE = new Buffer([0x01, 0x01]); module.exports = function UserPasswordAuthHandlers() { var authcb, user, pass, userlen, passlen; if (arguments.length === 1 && typeof arguments[0] === 'function') authcb = arguments[0]; else if (arguments.length === 2 && typeof arguments[0] === 'string' && typeof arguments[1] === 'string') { user = arguments[0]; pass = arguments[1]; userlen = Buffer.byteLength(user); passlen = Buffer.byteLength(pass); if (userlen > 255) throw new Error('Username too long (limited to 255 bytes)'); else if (passlen > 255) throw new Error('Password too long (limited to 255 bytes)'); } else throw new Error('Wrong arguments'); return { METHOD: 0x02, server: function serverHandler(stream, cb) { var state = STATE_VERSION, userp = 0, passp = 0; function onData(chunk) { var i = 0, len = chunk.length, left, chunkLeft, minLen; while (i < len) { switch (state) { /* +----+------+----------+------+----------+ |VER | ULEN | UNAME | PLEN | PASSWD | +----+------+----------+------+----------+ | 1 | 1 | 1 to 255 | 1 | 1 to 255 | +----+------+----------+------+----------+ */ case STATE_VERSION: if (chunk[i] !== 0x01) { stream.removeListener('data', onData); cb(new Error('Unsupported auth request version: ' + chunk[i])); return; } ++i; ++state; break; case STATE_ULEN: var ulen = chunk[i]; if (ulen === 0) { stream.removeListener('data', onData); cb(new Error('Bad username length (0)')); return; } ++i; ++state; user = new Buffer(ulen); userp = 0; break; case STATE_UNAME: left = user.length - userp; chunkLeft = len - i; minLen = (left < chunkLeft ? left : chunkLeft); chunk.copy(user, userp, i, i + minLen); userp += minLen; i += minLen; if (userp === user.length) { user = user.toString('utf8'); ++state; } break; case STATE_PLEN: var plen = chunk[i]; if (plen === 0) { stream.removeListener('data', onData); cb(new Error('Bad password length (0)')); return; } ++i; ++state; pass = new Buffer(plen); passp = 0; break; case STATE_PASSWD: left = pass.length - passp; chunkLeft = len - i; minLen = (left < chunkLeft ? left : chunkLeft); chunk.copy(pass, passp, i, i + minLen); passp += minLen; i += minLen; if (passp === pass.length) { stream.removeListener('data', onData); pass = pass.toString('utf8'); state = STATE_VERSION; if (i < len) stream.unshift(chunk.slice(i)); authcb(user, pass, function(success) { if (stream.writable) { if (success) stream.write(BUF_SUCCESS); else stream.write(BUF_FAILURE); cb(success); } }); return; } break; // =================================================================== } } } stream.on('data', onData); }, client: function clientHandler(stream, cb) { var state = STATE_VERSION; function onData(chunk) { var i = 0, len = chunk.length; while (i < len) { switch (state) { /* +----+--------+ |VER | STATUS | +----+--------+ | 1 | 1 | +----+--------+ */ case STATE_VERSION: if (chunk[i] !== 0x01) { stream.removeListener('data', onData); cb(new Error('Unsupported auth request version: ' + chunk[i])); return; } ++i; state = STATE_STATUS; break; case STATE_STATUS: var status = chunk[i]; ++i; state = STATE_VERSION; if (i < len) stream.unshift(chunk.slice(i)); stream.removeListener('data', onData); cb(status === 0); return; break; } } } stream.on('data', onData); var buf = new Buffer(3 + userlen + passlen); buf[0] = 0x01; buf[1] = userlen; buf.write(user, 2, userlen); buf[2 + userlen] = passlen; buf.write(pass, 3 + userlen, passlen); stream.write(buf); } }; }; socksv5-master/lib/client.js000066400000000000000000000143731264411760300163420ustar00rootroot00000000000000var net = require('net'), normalizeConnectArgs = net._normalizeConnectArgs, dns = require('dns'), util = require('util'), inherits = util.inherits, EventEmitter = require('events').EventEmitter; var Parser = require('./client.parser'), ipbytes = require('./utils').ipbytes; var CMD = require('./constants').CMD, ATYP = require('./constants').ATYP; function Client(options) { if (!(this instanceof Client)) return new Client(options); var self = this; EventEmitter.call(this); this._hadError = false; this._ready = false; this._sock = new net.Socket(); this._sock.on('connect', function() { self._onConnect(); }).on('error', function(err) { if (!self._hadError && !self._ready) { self._hadError = true; self.emit('error', err); } }).on('close', function(had_err) { self.emit('close', self._hadError || had_err); }); this._parser = undefined; this._proxyaddr = options && options.proxyHost; this._proxyport = options && options.proxyPort; if (typeof this._proxyaddr !== 'string') this._proxyaddr = 'localhost'; else if (typeof this._proxyport !== 'number') this._proxyport = 1080; this._dstaddr = undefined; this._dstport = undefined; this._localDNS = (options && typeof options.localDNS === 'boolean' ? options.localDNS : true); this._strictLocalDNS = (options && typeof options.strictLocalDNS === 'boolean' ? options.strictLocalDNS : true); this._auths = []; if (options && Array.isArray(options.auths)) { for (var i = 0, len = options.auths.length; i < len; ++i) this.useAuth(options.auths[i]); } } inherits(Client, EventEmitter); Client.prototype._onConnect = function() { var self = this, parser = this._parser, socket = this._sock; var auths = self._auths, alen = auths.length, authsbuf = new Buffer(2 + alen); authsbuf[0] = 0x05; authsbuf[1] = alen; for (var a = 0, p = 2; a < alen; ++a, ++p) authsbuf[p] = auths[a].METHOD; socket.write(authsbuf); parser.on('method', function(method) { alen = auths.length; for (var i = 0; i < alen; ++i) { if (auths[i].METHOD === method) { auths[i].client(socket, function(result) { if (result === true) { parser.authed = true; parser.start(); self._sendRequest(); } else { self._hadError = true; if (util.isError(result)) self.emit('error', result); else { var err = new Error('Authentication failed'); err.code = 'EAUTHFAILED'; self.emit('error', err); } socket.end(); } }); self._sock.resume(); return; } } var err = new Error('Authentication method mismatch'); err.code = 'EAUTHNOTSUPPORT'; self._hadError = true; self.emit('error', err); socket.end(); }).on('error', function(err) { self._hadError = true; self.emit('error', err); if (socket.writable) socket.end(); }).on('reply', function(repInfo) { self._ready = true; self.emit('connect', self._sock); self._sock.resume(); }); }; Client.prototype._sendRequest = function() { var self = this, iptype = net.isIP(this._dstaddr); var addrlen = (iptype === 0 ? Buffer.byteLength(self._dstaddr) : (iptype === 4 ? 4 : 16)), reqbuf = new Buffer(6 + (iptype === 0 ? 1 : 0) + addrlen), p; reqbuf[0] = 0x05; reqbuf[1] = CMD.CONNECT; reqbuf[2] = 0x00; if (iptype > 0) { var addrbytes = ipbytes(self._dstaddr); reqbuf[3] = (iptype === 4 ? ATYP.IPv4 : ATYP.IPv6); p = 4; for (var i = 0; i < addrlen; ++i, ++p) reqbuf[p] = addrbytes[i]; } else { reqbuf[3] = ATYP.NAME; reqbuf[4] = addrlen; reqbuf.write(self._dstaddr, 5, addrlen); p = 5 + addrlen; } reqbuf.writeUInt16BE(self._dstport, p, true); self._sock.write(reqbuf); }; Client.prototype.useAuth = function(auth) { if (typeof auth !== 'object' || typeof auth.client !== 'function' || auth.client.length !== 2) throw new Error('Invalid authentication handler'); else if (this._auths.length >= 255) throw new Error('Too many authentication handlers (limited to 255).'); this._auths.push(auth); return this; }; Client.prototype.connect = function(options, cb) { var self = this; if (this._auths.length === 0) throw new Error('Missing client authentication method(s)'); if (typeof options !== 'object') { // Old API: // connect(port, [host], [cb]) // connect(path, [cb]); var args = normalizeConnectArgs(arguments); return Client.prototype.connect.apply(this, args); } if (!options.port) throw new Error('Can only connect to TCP hosts'); if (typeof cb === 'function') this.once('connect', cb); this._dstaddr = options.host || 'localhost'; this._dstport = +options.port; if (typeof options.localDNS === 'boolean') this._localDNS = options.localDNS; if (typeof options.strictLocalDNS === 'boolean') this._strictLocalDNS = options.strictLocalDNS; if (typeof options.proxyHost === 'string') this._proxyhost = options.proxyHost; if (typeof options.proxyPort === 'string') this._proxyport = options.proxyPort; if (this._parser) this._parser.stop(); this._parser = new Parser(this._sock); this._hadError = this._ready = false; var realOptions = { host: this._proxyhost, port: this._proxyport, localAddress: options.localAddress // TODO: remove? }; if (net.isIP(this._dstaddr) === 0 && this._localDNS) { dns.lookup(this._dstaddr, function(err, addr) { if (err && self._strictLocalDNS) { self._hadError = true; self.emit('error', err); self.emit('close', true); return; } if (addr) self._dstaddr = addr; self._sock.connect(realOptions); }); } else this._sock.connect(realOptions); return this; }; exports.Client = Client; exports.connect = exports.createConnection = function() { var args = normalizeConnectArgs(arguments), client = new Client(args[0]); process.nextTick(function() { Client.prototype.connect.apply(client, args); }); return client; }; socksv5-master/lib/client.parser.js000066400000000000000000000146571264411760300176420ustar00rootroot00000000000000var inherits = require('util').inherits, EventEmitter = require('events').EventEmitter; var ATYP = require('./constants').ATYP, REP = require('./constants').REP; var STATE_VERSION = 0, STATE_METHOD = 1, STATE_REP_STATUS = 2, STATE_REP_RSV = 3, STATE_REP_ATYP = 4, STATE_REP_BNDADDR = 5, STATE_REP_BNDADDR_VARLEN = 6, STATE_REP_BNDPORT = 7; var ERRORS = {}, ERROR_UNKNOWN = ['unknown error', 'EUNKNOWN']; ERRORS[REP.GENFAIL] = ['general SOCKS server failure', 'EGENFAIL']; ERRORS[REP.DISALLOW] = ['connection not allowed by ruleset', 'EACCES']; ERRORS[REP.NETUNREACH] = ['network is unreachable', 'ENETUNREACH']; ERRORS[REP.HOSTUNREACH] = ['host is unreachable', 'EHOSTUNREACH']; ERRORS[REP.CONNREFUSED] = ['connection refused', 'ECONNREFUSED']; ERRORS[REP.TTLEXPIRED] = ['ttl expired', 'ETTLEXPIRED']; ERRORS[REP.CMDUNSUPP] = ['command not supported', 'ECMDNOSUPPORT']; ERRORS[REP.ATYPUNSUPP] = ['address type not supported', 'EATYPNOSUPPORT']; function Parser(stream) { var self = this; this._stream = stream; this._listening = false; this.__onData = function(chunk) { self._onData(chunk); }; this._state = STATE_VERSION; this._atyp = 0; this._bndaddr = undefined; this._bndaddrp = 0; this._bndport = undefined; this.authed = false; this.start(); } inherits(Parser, EventEmitter); Parser.prototype._onData = function(chunk) { var state = this._state, i = 0, len = chunk.length, left, chunkLeft, minLen; while (i < len) { switch (state) { /* +----+--------+ |VER | METHOD | +----+--------+ | 1 | 1 | +----+--------+ */ case STATE_VERSION: if (chunk[i] !== 0x05) { this.emit('error', new Error('Incompatible SOCKS protocol version: ' + chunk[i])); return; } ++i; if (this.authed) state = STATE_REP_STATUS; else ++state; break; case STATE_METHOD: var method = chunk[i]; ++i; this.stop(); this._state = STATE_VERSION; if (i < len) this._stream.unshift(chunk.slice(i)); this.emit('method', method); return; break; // ======================================================================= /* +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ Where: o VER protocol version: X'05' o REP Reply field: o X'00' succeeded o X'01' general SOCKS server failure o X'02' connection not allowed by ruleset o X'03' Network unreachable o X'04' Host unreachable o X'05' Connection refused o X'06' TTL expired o X'07' Command not supported o X'08' Address type not supported o X'09' to X'FF' unassigned o RSV RESERVED o ATYP address type of following address o IP V4 address: X'01' o DOMAINNAME: X'03' o IP V6 address: X'04' o BND.ADDR server bound address o BND.PORT server bound port in network octet order */ case STATE_REP_STATUS: var status = chunk[i]; if (status !== REP.SUCCESS) { var errinfo = ERRORS[status] || ERROR_UNKNOWN, err = new Error(errinfo[0]); err.code = errinfo[1]; this.stop(); this.emit('error', err); return; } ++i; ++state; break; case STATE_REP_RSV: ++i; ++state; break; case STATE_REP_ATYP: var atyp = chunk[i]; state = STATE_REP_BNDADDR; if (atyp === ATYP.IPv4) this._bndaddr = new Buffer(4); else if (atyp === ATYP.IPv6) this._bndaddr = new Buffer(16); else if (atyp === ATYP.NAME) state = STATE_REP_BNDADDR_VARLEN; else { this.stop(); this.emit('error', new Error('Invalid request address type: ' + atyp)); return; } this._atyp = atyp; ++i; break; case STATE_REP_BNDADDR: left = this._bndaddr.length - this._bndaddrp; chunkLeft = len - i; minLen = (left < chunkLeft ? left : chunkLeft); chunk.copy(this._bndaddr, this._bndaddrp, i, i + minLen); this._bndaddrp += minLen; i += minLen; if (this._bndaddrp === this._bndaddr.length) state = STATE_REP_BNDPORT; break; case STATE_REP_BNDADDR_VARLEN: this._bndaddr = new Buffer(chunk[i]); state = STATE_REP_BNDADDR; ++i; break; case STATE_REP_BNDPORT: if (this._bndport === undefined) this._bndport = chunk[i]; else { this._bndport <<= 8; this._bndport += chunk[i]; ++i; this.stop(); if (i < len) this._stream.unshift(chunk.slice(i)); if (this._atyp === ATYP.IPv4) this._bndaddr = Array.prototype.join.call(this._bndaddr, '.'); else if (this._atyp === ATYP.IPv6) { var ipv6str = '', addr = this._bndaddr; for (var b = 0; b < 16; ++b) { if (b % 2 === 0 && b > 0) ipv6str += ':'; ipv6str += addr[b].toString(16); } this._bndaddr = ipv6str; } else this._bndaddr = this._bndaddr.toString(); this.emit('reply', { bndAddr: this._bndaddr, bndPort: this._bndport }); return; } ++i; break; // =================================================================== } } this._state = state; }; Parser.prototype.start = function() { if (this._listening) return; this._listening = true; this._stream.on('data', this.__onData); this._stream.resume(); }; Parser.prototype.stop = function() { if (!this._listening) return; this._listening = false; this._stream.removeListener('data', this.__onData); this._stream.pause(); }; module.exports = Parser; socksv5-master/lib/constants.js000066400000000000000000000004741264411760300170750ustar00rootroot00000000000000exports.CMD = { CONNECT: 0x01, BIND: 0x02, UDP: 0x03 }; exports.ATYP = { IPv4: 0x01, NAME: 0x03, IPv6: 0x04 }; exports.REP = { SUCCESS: 0x00, GENFAIL: 0x01, DISALLOW: 0x02, NETUNREACH: 0x03, HOSTUNREACH: 0x04, CONNREFUSED: 0x05, TTLEXPIRED: 0x06, CMDUNSUPP: 0x07, ATYPUNSUPP: 0x08 }; socksv5-master/lib/server.js000066400000000000000000000154121264411760300163650ustar00rootroot00000000000000var net = require('net'), dns = require('dns'), util = require('util'), inherits = util.inherits, EventEmitter = require('events').EventEmitter; var Parser = require('./server.parser'), ipbytes = require('./utils').ipbytes; var ATYP = require('./constants').ATYP, REP = require('./constants').REP; var BUF_AUTH_NO_ACCEPT = new Buffer([0x05, 0xFF]), BUF_REP_INTR_SUCCESS = new Buffer([0x05, REP.SUCCESS, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), BUF_REP_DISALLOW = new Buffer([0x05, REP.DISALLOW]), BUF_REP_CMDUNSUPP = new Buffer([0x05, REP.CMDUNSUPP]); function Server(options, listener) { if (!(this instanceof Server)) return new Server(options, listener); var self = this; if (typeof options === 'function') { self.on('connection', options); options = undefined; } else if (typeof listener === 'function') self.on('connection', listener); EventEmitter.call(this); this._srv = new net.Server(function(socket) { if (self._connections >= self.maxConnections) { socket.destroy(); return; } ++self._connections; socket.once('close', function(had_err) { --self._connections; }); self._onConnection(socket); }).on('error', function(err) { self.emit('error', err); }).on('listening', function() { self.emit('listening'); }).on('close', function() { self.emit('close'); }); this._auths = []; if (options && Array.isArray(options.auths)) { for (var i = 0, len = options.auths.length; i < len; ++i) this.useAuth(options.auths[i]); } this._debug = (options && typeof options.debug === 'function' ? options.debug : undefined); this._connections = 0; this.maxConnections = Infinity; } inherits(Server, EventEmitter); Server.prototype._onConnection = function(socket) { var self = this, parser = new Parser(socket); parser.on('error', function(err) { if (socket.writable) socket.end(); }).on('methods', function(methods) { var auths = self._auths; for (var a = 0, alen = auths.length; a < alen; ++a) { for (var m = 0, mlen = methods.length; m < mlen; ++m) { if (methods[m] === auths[a].METHOD) { auths[a].server(socket, function(result) { if (result === true) { parser.authed = true; parser.start(); } else { if (util.isError(result)) self._debug && self._debug('Error: ' + result.message); socket.end(); } }); socket.write(new Buffer([0x05, auths[a].METHOD])); socket.resume(); return; } } } socket.end(BUF_AUTH_NO_ACCEPT); }).on('request', function(reqInfo) { if (reqInfo.cmd !== 'connect') return socket.end(BUF_REP_CMDUNSUPP); reqInfo.srcAddr = socket.remoteAddress; reqInfo.srcPort = socket.remotePort; var handled = false; function accept(intercept) { if (handled) return; handled = true; if (socket.writable) { if (intercept) { socket.write(BUF_REP_INTR_SUCCESS); socket.removeListener('error', onErrorNoop); process.nextTick(function() { socket.resume(); }); return socket; } else proxySocket(socket, reqInfo); } } function deny() { if (handled) return; handled = true; if (socket.writable) socket.end(BUF_REP_DISALLOW); } if (self._events.connection) { self.emit('connection', reqInfo, accept, deny); return; } proxySocket(socket, reqInfo); }); function onClose() { if (socket.dstSock && socket.dstSock.writable) socket.dstSock.end(); socket.dstSock = undefined; } socket.on('error', onErrorNoop) .on('end', onClose) .on('close', onClose); }; Server.prototype.useAuth = function(auth) { if (typeof auth !== 'object' || typeof auth.server !== 'function' || auth.server.length !== 2) throw new Error('Invalid authentication handler'); else if (this._auths.length >= 255) throw new Error('Too many authentication handlers (limited to 255).'); this._auths.push(auth); return this; }; Server.prototype.listen = function() { this._srv.listen.apply(this._srv, arguments); return this; }; Server.prototype.address = function() { return this._srv.address(); }; Server.prototype.getConnections = function(cb) { this._srv.getConnections(cb); }; Server.prototype.close = function(cb) { this._srv.close(cb); return this; }; Server.prototype.ref = function() { this._srv.ref(); }; Server.prototype.unref = function() { this._srv.unref(); }; exports.Server = Server; exports.createServer = function(opts, listener) { return new Server(opts, listener); }; function onErrorNoop(err) {} function proxySocket(socket, req) { dns.lookup(req.dstAddr, function(err, dstIP) { if (err) { handleProxyError(socket, err); return; } function onError(err) { if (!connected) handleProxyError(socket, err); } var dstSock = new net.Socket(), connected = false; dstSock.setKeepAlive(false); dstSock.on('error', onError) .on('connect', function() { connected = true; if (socket.writable) { var localbytes = ipbytes(dstSock.localAddress || '127.0.0.1'), len = localbytes.length, bufrep = new Buffer(6 + len), p = 4; bufrep[0] = 0x05; bufrep[1] = REP.SUCCESS; bufrep[2] = 0x00; bufrep[3] = (len === 4 ? ATYP.IPv4 : ATYP.IPv6); for (var i = 0; i < len; ++i, ++p) bufrep[p] = localbytes[i]; bufrep.writeUInt16BE(dstSock.localPort, p, true); socket.write(bufrep); socket.pipe(dstSock).pipe(socket); socket.resume(); } else if (dstSock.writable) dstSock.end(); }) .connect(req.dstPort, dstIP); socket.dstSock = dstSock; }); } function handleProxyError(socket, err) { if (socket.writable) { var errbuf = new Buffer([0x05, REP.GENFAIL]); if (err.code) { switch (err.code) { case 'ENOENT': case 'ENOTFOUND': case 'ETIMEDOUT': case 'EHOSTUNREACH': errbuf[1] = REP.HOSTUNREACH; break; case 'ENETUNREACH': errbuf[1] = REP.NETUNREACH; break; case 'ECONNREFUSED': errbuf[1] = REP.CONNREFUSED; break; } } socket.end(errbuf); } }socksv5-master/lib/server.parser.js000066400000000000000000000151611264411760300176610ustar00rootroot00000000000000var inherits = require('util').inherits, EventEmitter = require('events').EventEmitter; var CMD = require('./constants').CMD, ATYP = require('./constants').ATYP; var STATE_VERSION = 0, STATE_NMETHODS = 1, STATE_METHODS = 2, STATE_REQ_CMD = 3, STATE_REQ_RSV = 4, STATE_REQ_ATYP = 5, STATE_REQ_DSTADDR = 6, STATE_REQ_DSTADDR_VARLEN = 7, STATE_REQ_DSTPORT = 8; function Parser(stream) { var self = this; this._stream = stream; this._listening = false; this.__onData = function(chunk) { self._onData(chunk); }; this._state = STATE_VERSION; this._methods = undefined; this._methodsp = 0; this._cmd = 0; this._atyp = 0; this._dstaddr = undefined; this._dstaddrp = 0; this._dstport = undefined; this.authed = false; this.start(); } inherits(Parser, EventEmitter); Parser.prototype._onData = function(chunk) { var state = this._state, i = 0, len = chunk.length, left, chunkLeft, minLen; while (i < len) { switch (state) { /* +----+----------+----------+ |VER | NMETHODS | METHODS | +----+----------+----------+ | 1 | 1 | 1 to 255 | +----+----------+----------+ */ case STATE_VERSION: if (chunk[i] !== 0x05) { this.emit('error', new Error('Incompatible SOCKS protocol version: ' + chunk[i])); return; } ++i; if (this.authed) state = STATE_REQ_CMD; else ++state; break; case STATE_NMETHODS: var nmethods = chunk[i]; if (nmethods === 0) { this.emit('error', new Error('Unexpected empty methods list')); return; } ++i; ++state; this._methods = new Buffer(nmethods); this._methodsp = 0; break; case STATE_METHODS: left = this._methods.length - this._methodsp; chunkLeft = len - i; minLen = (left < chunkLeft ? left : chunkLeft); chunk.copy(this._methods, this._methodsp, i, i + minLen); this._methodsp += minLen; i += minLen; if (this._methodsp === this._methods.length) { this.stop(); this._state = STATE_VERSION; if (i < len) this._stream.unshift(chunk.slice(i)); var methods = this._methods; this._methods = undefined; this.emit('methods', methods); return; } break; // ======================================================================= /* +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ Where: o VER protocol version: X'05' o CMD o CONNECT X'01' o BIND X'02' o UDP ASSOCIATE X'03' o RSV RESERVED o ATYP address type of following address o IP V4 address: X'01' o DOMAINNAME: X'03' o IP V6 address: X'04' o DST.ADDR desired destination address o DST.PORT desired destination port in network octet order */ case STATE_REQ_CMD: var cmd = chunk[i]; if (cmd === CMD.CONNECT) this._cmd = 'connect'; else if (cmd === CMD.BIND) this._cmd = 'bind'; else if (cmd === CMD.UDP) this._cmd = 'udp'; else { this.stop(); this.emit('error', new Error('Invalid request command: ' + cmd)); return; } ++i; ++state; break; case STATE_REQ_RSV: ++i; ++state; break; case STATE_REQ_ATYP: var atyp = chunk[i]; state = STATE_REQ_DSTADDR; if (atyp === ATYP.IPv4) this._dstaddr = new Buffer(4); else if (atyp === ATYP.IPv6) this._dstaddr = new Buffer(16); else if (atyp === ATYP.NAME) state = STATE_REQ_DSTADDR_VARLEN; else { this.stop(); this.emit('error', new Error('Invalid request address type: ' + atyp)); return; } this._atyp = atyp; ++i; break; case STATE_REQ_DSTADDR: left = this._dstaddr.length - this._dstaddrp; chunkLeft = len - i; minLen = (left < chunkLeft ? left : chunkLeft); chunk.copy(this._dstaddr, this._dstaddrp, i, i + minLen); this._dstaddrp += minLen; i += minLen; if (this._dstaddrp === this._dstaddr.length) state = STATE_REQ_DSTPORT; break; case STATE_REQ_DSTADDR_VARLEN: this._dstaddr = new Buffer(chunk[i]); state = STATE_REQ_DSTADDR; ++i; break; case STATE_REQ_DSTPORT: if (this._dstport === undefined) this._dstport = chunk[i]; else { this._dstport <<= 8; this._dstport += chunk[i]; ++i; this.stop(); if (i < len) this._stream.unshift(chunk.slice(i)); if (this._atyp === ATYP.IPv4) this._dstaddr = Array.prototype.join.call(this._dstaddr, '.'); else if (this._atyp === ATYP.IPv6) { var ipv6str = '', addr = this._dstaddr; for (var b = 0; b < 16; ++b) { if (b % 2 === 0 && b > 0) ipv6str += ':'; ipv6str += (addr[b] < 16 ? '0' : '') + addr[b].toString(16); } this._dstaddr = ipv6str; } else this._dstaddr = this._dstaddr.toString(); this.emit('request', { cmd: this._cmd, srcAddr: undefined, srcPort: undefined, dstAddr: this._dstaddr, dstPort: this._dstport }); return; } ++i; break; // =================================================================== } } this._state = state; }; Parser.prototype.start = function() { if (this._listening) return; this._listening = true; this._stream.on('data', this.__onData); this._stream.resume(); }; Parser.prototype.stop = function() { if (!this._listening) return; this._listening = false; this._stream.removeListener('data', this.__onData); this._stream.pause(); }; module.exports = Parser; socksv5-master/lib/utils.js000066400000000000000000000013611264411760300162150ustar00rootroot00000000000000var net = require('net'), ipv6 = require('ipv6').v6; exports.ipbytes = function(str) { var type = net.isIP(str), nums, bytes, i; if (type === 4) { nums = str.split('.', 4); bytes = new Array(4); for (i = 0; i < 4; ++i) { if (isNaN(bytes[i] = +nums[i])) throw new Error('Error parsing IP: ' + str); } } else if (type === 6) { var addr = new ipv6.Address(str), b = 0, group; if (!addr.valid) throw new Error('Error parsing IP: ' + str); nums = addr.parsedAddress; bytes = new Array(16); for (i = 0; i < 8; ++i, b += 2) { group = parseInt(nums[i], 16); bytes[b] = group >>> 8; bytes[b + 1] = group & 0xFF; } } return bytes; }; socksv5-master/package.json000066400000000000000000000011471264411760300162410ustar00rootroot00000000000000{ "name": "socksv5", "version": "0.0.6", "author": "Brian White ", "description": "SOCKS protocol version 5 server and client implementations for node.js", "main": "./index", "scripts": { "test": "node test/test.js" }, "dependencies": { "ipv6": "*" }, "bundledDependencies": [ "ipv6" ], "engines": { "node": ">=0.10.0" }, "keywords": [ "socks", "socks5", "socksv5", "proxy" ], "licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/socksv5/raw/master/LICENSE" } ], "repository" : { "type": "git", "url": "http://github.com/mscdex/socksv5.git" } } socksv5-master/test/000077500000000000000000000000001264411760300147275ustar00rootroot00000000000000socksv5-master/test/test-client-parser.js000066400000000000000000000227021264411760300210150ustar00rootroot00000000000000var Parser = require('../lib/client.parser'); var EventEmitter = require('events').EventEmitter, path = require('path'), assert = require('assert'), inherits = require('util').inherits; var t = -1, group = path.basename(__filename, '.js') + '/'; var tests = [ { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), method; parser.on('method', function(m) { method = m; }).on('reply', function() { assert(false, makeMsg(what, 'Unexpected reply event')); }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0xFF])); assert(method === 0xFF, makeMsg(what, 'Unexpected method: ' + method)); next(); }, what: 'Phase 1 - Valid (whole)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), method; parser.on('method', function(m) { method = m; }).on('reply', function() { assert(false, makeMsg(what, 'Unexpected reply event')); }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05])); stream.emit('data', new Buffer([0x09])); assert(method === 0x09, makeMsg(what, 'Unexpected method: ' + method)); next(); }, what: 'Phase 1 - Valid (split)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function() { assert(false, makeMsg(what, 'Unexpected reply event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x04, 0x09])); assert(errors.length === 1 && /Incompatible SOCKS protocol version: 4/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 1 - Bad version' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), reply; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function(r) { reply = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x00, 0x00, 0x01, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert.deepEqual(reply, { bndAddr: '192.168.100.1', bndPort: 80 }, makeMsg(what, 'Reply mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - Success (IPv4)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), reply; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function(r) { reply = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x00, 0x00, 0x04, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0x08, 0x40])); assert.deepEqual(reply, { bndAddr: 'fffe:fdfc:fbfa:f9f8:f7f6:f5f4:f3f2:f1f0', bndPort: 2112 }, makeMsg(what, 'Reply mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - Success (IPv6)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), reply; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function(r) { reply = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x00, 0x00, 0x03, 0x0A, 0x6E, 0x6F, 0x64, 0x65, 0x6A, 0x73, 0x2E, 0x6F, 0x72, 0x67, 0x05, 0x39])); assert.deepEqual(reply, { bndAddr: 'nodejs.org', bndPort: 1337 }, makeMsg(what, 'Reply mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - Success (Hostname)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), reply; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function(r) { reply = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x00])); stream.emit('data', new Buffer([0x00, 0x03, 0x0A, 0x6E, 0x6F, 0x64, 0x65])); stream.emit('data', new Buffer([0x6A, 0x73, 0x2E, 0x6F, 0x72])); stream.emit('data', new Buffer([0x67, 0x05])); stream.emit('data', new Buffer([0x39])); assert.deepEqual(reply, { bndAddr: 'nodejs.org', bndPort: 1337 }, makeMsg(what, 'Reply mismatch')); next(); }, what: 'Phase 2 - Valid (split) - Success (Hostname)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function() { assert(false, makeMsg(what, 'Unexpected reply event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x05, 0x02])); assert(errors.length === 1 && /connection not allowed by ruleset/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 2 - Valid - Error' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function() { assert(false, makeMsg(what, 'Unexpected reply event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x04, 0x02])); assert(errors.length === 1 && /Incompatible SOCKS protocol version: 4/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 2 - Bad version' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.authed = true; parser.on('method', function() { assert(false, makeMsg(what, 'Unexpected method event')); }).on('reply', function() { assert(false, makeMsg(what, 'Unexpected reply event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x05, 0x00])); stream.emit('data', new Buffer([0x00, 0xFF, 0x0A, 0x6E, 0x6F, 0x64, 0x65])); stream.emit('data', new Buffer([0x6A, 0x73, 0x2E, 0x6F, 0x72])); stream.emit('data', new Buffer([0x67, 0x05])); stream.emit('data', new Buffer([0x39])); assert(errors.length === 1 && /Invalid request address type: 255/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 2 - Bad address type' }, ]; function next() { if (t === tests.length - 1) return; var v = tests[++t]; v.run.call(v); } function makeMsg(what, msg) { return '[' + group + what + ']: ' + msg; } process.once('uncaughtException', function(err) { if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err)) console.log(makeMsg(tests[t].what, 'Unexpected Exception:')); throw err; }); process.once('exit', function() { assert(t === tests.length - 1, makeMsg('_exit', 'Only finished ' + (t + 1) + '/' + tests.length + ' tests')); }); function FakeStream() { EventEmitter.call(this); } inherits(FakeStream, EventEmitter); FakeStream.prototype.pause = function() {}; FakeStream.prototype.resume = function() {}; next(); socksv5-master/test/test-client.js000066400000000000000000000160651264411760300175300ustar00rootroot00000000000000var auth = require('../index').auth, createServer = require('../index').createServer, connect = require('../index').connect; var path = require('path'), assert = require('assert'); var t = -1, group = path.basename(__filename, '.js') + '/'; var PROXY_RESPONSE = 'hello from the node.js proxy server!'; var tests = [ { run: function() { var what = this.what, conns = 0, response, server; server = createServer(function(info, accept) { ++conns; var socket; if (socket = accept(true)) socket.end(PROXY_RESPONSE); }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { connect({ host: 'localhost', port: 1, proxyHost: 'localhost', proxyPort: server.address().port }, function(socket) { bufferStream(socket, 'ascii', function(data) { response = data; }); }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }).on('close', function() { server.close(); // allow bufferStream() callback to be called first process.nextTick(function() { assert(response === PROXY_RESPONSE, makeMsg(what, 'Response mismatch')); assert(conns === 1, makeMsg(what, 'Wrong number of connections')); next(); }); }).useAuth(auth.None()); }); }, what: 'No authentication' }, { run: function() { var what = this.what, conns = 0, response, server; server = createServer(function(info, accept) { ++conns; var socket; if (socket = accept(true)) socket.end(PROXY_RESPONSE); }); server.useAuth(auth.UserPassword(function(user, pass, cb) { cb(user === 'nodejs' && pass === 'rules'); })); server.listen(0, 'localhost', function() { connect({ host: 'localhost', port: 1, proxyHost: 'localhost', proxyPort: server.address().port }, function(socket) { bufferStream(socket, 'ascii', function(data) { response = data; }); }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }).on('close', function() { server.close(); // allow bufferStream() callback to be called first process.nextTick(function() { assert(response === PROXY_RESPONSE, makeMsg(what, 'Response mismatch')); assert(conns === 1, makeMsg(what, 'Wrong number of connections')); next(); }); }).useAuth(auth.UserPassword('nodejs', 'rules')); }); }, what: 'User/Password authentication (valid credentials)' }, { run: function() { var what = this.what, errors = [], server; server = createServer(function() { assert(false, makeMsg(what, 'Unexpected connection')); }); server.useAuth(auth.UserPassword(function(user, pass, cb) { cb(user === 'nodejs' && pass === 'rules'); })); server.listen(0, 'localhost', function() { connect({ host: 'localhost', port: 1, proxyHost: 'localhost', proxyPort: server.address().port }, function() { assert(false, makeMsg(what, 'Unexpected connect callback')); }).on('error', function(err) { errors.push(err); }).on('close', function() { server.close(); assert(errors.length === 1 && /authentication failed/i.test(errors[0].message), makeMsg(what, 'Expected 1 error')); next(); }).useAuth(auth.UserPassword('php', 'rules')); }); }, what: 'User/Password authentication (invalid credentials)' }, { run: function() { var what = this.what, errors = [], server; server = createServer(function() { assert(false, makeMsg(what, 'Unexpected connection')); }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { connect({ host: 'localhost', port: 1, proxyHost: 'localhost', proxyPort: server.address().port }, function() { assert(false, makeMsg(what, 'Unexpected connect callback')); }).on('error', function(err) { errors.push(err); }).on('close', function() { server.close(); assert(errors.length === 1 && /Authentication method mismatch/i.test(errors[0].message), makeMsg(what, 'Expected 1 error')); next(); }).useAuth(auth.UserPassword('nodejs', 'rules')); }); }, what: 'No matching authentication method' }, { run: function() { var what = this.what, conns = 0, errors = [], server; server = createServer(function(info, accept, deny) { ++conns; deny(); }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { connect({ host: 'localhost', port: 1, proxyHost: 'localhost', proxyPort: server.address().port }, function() { assert(false, makeMsg(what, 'Unexpected connect callback')); }).on('error', function(err) { errors.push(err); }).on('close', function() { server.close(); assert(errors.length === 1 && /not allowed by ruleset/i.test(errors[0].message), makeMsg(what, 'Expected 1 error')); assert(conns === 1, makeMsg(what, 'Wrong number of connections')); next(); }).useAuth(auth.None()); }); }, what: 'Denied connection' }, ]; function bufferStream(stream, encoding, cb) { var buf; if (typeof encoding === 'function') { cb = encoding; encoding = undefined; } if (!encoding) { var nb = 0; stream.on('data', function(d) { if (nb === 0) buf = [ d ]; else buf.push(d); nb += d.length; }).on((stream.writable ? 'close' : 'end'), function() { cb(nb ? Buffer.concat(buf, nb) : buf); }); } else { stream.on('data', function(d) { if (!buf) buf = d; else buf += d; }).on((stream.writable ? 'close' : 'end'), function() { cb(buf); }).setEncoding(encoding); } } function next() { if (t === tests.length - 1) return; var v = tests[++t]; v.run.call(v); } function makeMsg(what, msg) { return '[' + group + what + ']: ' + msg; } process.once('uncaughtException', function(err) { if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err)) console.log(makeMsg(tests[t].what, 'Unexpected Exception:')); throw err; }); process.once('exit', function() { assert(t === tests.length - 1, makeMsg('_exit', 'Only finished ' + (t + 1) + '/' + tests.length + ' tests')); }); next();socksv5-master/test/test-server-parser.js000066400000000000000000000334261264411760300210520ustar00rootroot00000000000000var Parser = require('../lib/server.parser'); var EventEmitter = require('events').EventEmitter, path = require('path'), assert = require('assert'), inspect = require('util').inspect, inherits = require('util').inherits; var t = -1, group = path.basename(__filename, '.js') + '/'; var tests = [ { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), methods; parser.on('methods', function(m) { methods = m; }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x01, 0x00])); assert.deepEqual(methods, new Buffer([0x00]), makeMsg(what, 'Unexpected methods: ' + inspect(methods))); next(); }, what: 'Phase 1 - Valid (whole)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), methods; parser.on('methods', function(m) { methods = m; }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05])); stream.emit('data', new Buffer([0x01])); stream.emit('data', new Buffer([0x00])); assert.deepEqual(methods, new Buffer([0x00]), makeMsg(what, 'Unexpected methods: ' + inspect(methods))); next(); }, what: 'Phase 1 - Valid (split)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x04, 0x01, 0x00])); assert(errors.length === 1 && /Incompatible SOCKS protocol version: 4/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 1 - Bad version' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x05, 0x00])); assert(errors.length === 1 && /empty methods list/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 1 - Bad method count' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), request; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function(r) { request = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x01, 0x00, 0x01, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert.deepEqual(request, { cmd: 'connect', srcAddr: undefined, srcPort: undefined, dstAddr: '192.168.100.1', dstPort: 80 }, makeMsg(what, 'Request mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - CONNECT (IPv4)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), request; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function(r) { request = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x02, 0x00, 0x01, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert.deepEqual(request, { cmd: 'bind', srcAddr: undefined, srcPort: undefined, dstAddr: '192.168.100.1', dstPort: 80 }, makeMsg(what, 'Request mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - BIND (IPv4)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), request; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function(r) { request = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x03, 0x00, 0x01, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert.deepEqual(request, { cmd: 'udp', srcAddr: undefined, srcPort: undefined, dstAddr: '192.168.100.1', dstPort: 80 }, makeMsg(what, 'Request mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - UDP ASSOCIATE (IPv4)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), request; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function(r) { request = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x01, 0x00, 0x04, 0xFF, 0xFE, 0xE0, 0xD0, 0x00, 0x0C, 0x00, 0xA0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xB0, 0x01, 0x08, 0x40])); assert.deepEqual(request, { cmd: 'connect', srcAddr: undefined, srcPort: undefined, dstAddr: 'fffe:e0d0:000c:00a0:0000:0300:0002:b001', dstPort: 2112 }, makeMsg(what, 'Request mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - CONNECT (IPv6)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), request; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function(r) { request = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05, 0x01, 0x00, 0x03, 0x0A, 0x6E, 0x6F, 0x64, 0x65, 0x6A, 0x73, 0x2E, 0x6F, 0x72, 0x67, 0x05, 0x39])); assert.deepEqual(request, { cmd: 'connect', srcAddr: undefined, srcPort: undefined, dstAddr: 'nodejs.org', dstPort: 1337 }, makeMsg(what, 'Request mismatch')); next(); }, what: 'Phase 2 - Valid (whole) - CONNECT (Hostname)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), request; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function(r) { request = r; }).on('error', function(err) { assert(false, makeMsg(what, 'Unexpected error: ' + err)); }); stream.emit('data', new Buffer([0x05])); stream.emit('data', new Buffer([0x01, 0x00, 0x03])); stream.emit('data', new Buffer([0x0A])); stream.emit('data', new Buffer([0x6E, 0x6F, 0x64, 0x65, 0x6A, 0x73])); stream.emit('data', new Buffer([0x2E, 0x6F, 0x72])); stream.emit('data', new Buffer([0x67])); stream.emit('data', new Buffer([0x05])); stream.emit('data', new Buffer([0x39])); assert.deepEqual(request, { cmd: 'connect', srcAddr: undefined, srcPort: undefined, dstAddr: 'nodejs.org', dstPort: 1337 }, makeMsg(what, 'Request mismatch')); next(); }, what: 'Phase 2 - Valid (split) - CONNECT (Hostname)' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x04, 0x01, 0x00, 0x01, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert(errors.length === 1 && /Incompatible SOCKS protocol version: 4/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 2 - Bad version' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x05, 0xFE, 0x00, 0x01, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert(errors.length === 1 && /invalid request command: 254/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 2 - Bad command' }, { run: function() { var what = this.what, stream = new FakeStream(), parser = new Parser(stream), errors = []; parser.authed = true; parser.on('methods', function() { assert(false, makeMsg(what, 'Unexpected methods event')); }).on('request', function() { assert(false, makeMsg(what, 'Unexpected request event')); }).on('error', function(err) { errors.push(err); }); stream.emit('data', new Buffer([0x05, 0x01, 0x00, 0xFF, 0xC0, 0xA8, 0x64, 0x01, 0x00, 0x50])); assert(errors.length === 1 && /Invalid request address type: 255/i.test(errors[0].message), makeMsg(what, 'Error(s) mismatch')); next(); }, what: 'Phase 2 - Bad address type' }, ]; function next() { if (t === tests.length - 1) return; var v = tests[++t]; v.run.call(v); } function makeMsg(what, msg) { return '[' + group + what + ']: ' + msg; } process.once('uncaughtException', function(err) { if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err)) console.log(makeMsg(tests[t].what, 'Unexpected Exception:')); throw err; }); process.once('exit', function() { assert(t === tests.length - 1, makeMsg('_exit', 'Only finished ' + (t + 1) + '/' + tests.length + ' tests')); }); function FakeStream() { EventEmitter.call(this); } inherits(FakeStream, EventEmitter); FakeStream.prototype.pause = function() {}; FakeStream.prototype.resume = function() {}; next(); socksv5-master/test/test-server.js000066400000000000000000000261731264411760300175610ustar00rootroot00000000000000var auth = require('../index').auth, createServer = require('../index').createServer; var Socket = require('net').Socket, cpexec = require('child_process').execFile, http = require('http'), path = require('path'), assert = require('assert'); var t = -1, group = path.basename(__filename, '.js') + '/', httpServer, httpAddr, httpPort; var HTTP_RESPONSE = 'hello from the node.js http server!'; var tests = [ { run: function() { var what = this.what, conns = [], server; server = createServer(function(info, accept) { assert(info.cmd === 'connect', makeMsg(what, 'Unexpected command: ' + info.cmd)); assert(typeof info.srcAddr === 'string' && info.srcAddr.length, makeMsg(what, 'Bad srcAddr')); assert(typeof info.srcPort === 'number' && info.srcPort > 0, makeMsg(what, 'Bad srcPort')); assert(typeof info.dstAddr === 'string' && info.dstAddr.length, makeMsg(what, 'Bad dstAddr')); assert(typeof info.dstPort === 'number' && info.dstPort > 0, makeMsg(what, 'Bad dstPort')); conns.push(info); accept(); }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err, stdout, stderr) { server.close(); assert(!err, makeMsg(what, 'Unexpected client error: ' + extractCurlError(stderr))); assert(stdout === HTTP_RESPONSE, makeMsg(what, 'Response mismatch')); assert(conns.length === 1, makeMsg(what, 'Wrong number of connections')); next(); }); }); }, what: 'No authentication, normal accept' }, { run: function() { var what = this.what, conns = [], server; server = createServer(function(info, accept) { assert(info.cmd === 'connect', makeMsg(what, 'Unexpected command: ' + info.cmd)); assert(typeof info.srcAddr === 'string' && info.srcAddr.length, makeMsg(what, 'Bad srcAddr')); assert(typeof info.srcPort === 'number' && info.srcPort > 0, makeMsg(what, 'Bad srcPort')); assert(typeof info.dstAddr === 'string' && info.dstAddr.length, makeMsg(what, 'Bad dstAddr')); assert(typeof info.dstPort === 'number' && info.dstPort > 0, makeMsg(what, 'Bad dstPort')); conns.push(info); accept(); }); server.useAuth(auth.UserPassword(function(user, pass, cb) { cb(user === 'nodejs' && pass === 'rules'); })); server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, '-U', 'nodejs:rules', 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err, stdout, stderr) { server.close(); assert(!err, makeMsg(what, 'Unexpected client error: ' + extractCurlError(stderr))); assert(stdout === HTTP_RESPONSE, makeMsg(what, 'Response mismatch')); assert(conns.length === 1, makeMsg(what, 'Wrong number of connections')); next(); }); }); }, what: 'User/Password authentication (valid credentials), normal accept' }, { run: function() { var what = this.what, conns = [], server; server = createServer(function() { assert(false, makeMsg(what, 'Unexpected connection')); }); server.useAuth(auth.UserPassword(function(user, pass, cb) { cb(user === 'nodejs' && pass === 'rules'); })); server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, '-U', 'php:rules', 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err) { server.close(); assert(err, makeMsg(what, 'Expected client error')); assert(conns.length === 0, makeMsg(what, 'Unexpected connection(s)')); next(); }); }); }, what: 'User/Password authentication (invalid credentials)' }, { run: function() { var what = this.what, conns = [], server; server = createServer(function() { assert(false, makeMsg(what, 'Unexpected connection')); }); server.useAuth(auth.UserPassword(function() { assert(false, makeMsg(what, 'Unexpected User/Password auth')); })); server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err) { server.close(); assert(err, makeMsg(what, 'Expected client error')); assert(conns.length === 0, makeMsg(what, 'Unexpected connection(s)')); next(); }); }); }, what: 'No matching authentication method' }, { run: function() { var what = this.what, conns = [], server; server = createServer(function(info, accept, deny) { conns.push(info); deny(); }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err) { server.close(); assert(err, makeMsg(what, 'Expected client error')); assert(conns.length === 1, makeMsg(what, 'Wrong number of connections')); next(); }); }); }, what: 'Deny connection' }, { run: function() { var what = this.what, conns = [], server, body = 'Interception!'; server = createServer(function(info, accept) { conns.push(info); var socket; if (socket = accept(true)) { socket.end([ 'HTTP/1.1 200 OK', 'Connection: close', 'Content-Type: text/plain', 'Content-Length: ' + Buffer.byteLength(body), '', body ].join('\r\n')); } }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err, stdout, stderr) { server.close(); assert(!err, makeMsg(what, 'Unexpected client error: ' + extractCurlError(stderr))); assert(stdout === body, makeMsg(what, 'Response mismatch')); assert(conns.length === 1, makeMsg(what, 'Wrong number of connections')); next(); }); }); }, what: 'Intercept connection' }, { run: function() { var what = this.what, conns = [], server; server = createServer(function(info, accept) { assert(info.cmd === 'connect', makeMsg(what, 'Unexpected command: ' + info.cmd)); assert(typeof info.srcAddr === 'string' && info.srcAddr.length, makeMsg(what, 'Bad srcAddr')); assert(typeof info.srcPort === 'number' && info.srcPort > 0, makeMsg(what, 'Bad srcPort')); assert(typeof info.dstAddr === 'string' && info.dstAddr.length, makeMsg(what, 'Bad dstAddr')); assert(typeof info.dstPort === 'number' && info.dstPort > 0, makeMsg(what, 'Bad dstPort')); conns.push(info); accept(); }); server.useAuth(auth.None()); server.maxConnections = 0; server.listen(0, 'localhost', function() { var args = ['--socks5', this.address().address + ':' + this.address().port, 'http://' + httpAddr + ':' + httpPort]; cpexec('curl', args, function(err, stdout, stderr) { server.close(); assert(err, makeMsg(what, 'Expected client error')); assert(conns.length === 0, makeMsg(what, 'Wrong number of connections')); next(); }); }); }, what: 'maxConnections' }, { run: function() { var what = this.what, conns = [], server; server = createServer(function(info, accept) { assert(false, makeMsg(what, 'Should not get here for bad client version')); }); server.useAuth(auth.None()); server.listen(0, 'localhost', function() { var clientSock, tmr; clientSock = new Socket(); clientSock.on('error', function(err) { // ignore errors }).on('close', function() { assert(tmr !== undefined, makeMsg(what, 'Socket did not connect')); clearTimeout(tmr); server.close(); next(); }).on('connect', function() { tmr = setTimeout(function() { assert(false, makeMsg(what, 'Timeout while waiting for bad client socket end')); }, 100); clientSock.write(new Buffer([0x04, 0x01, 0x00])); }).connect(this.address().port, 'localhost'); }); }, what: 'Disconnect socket on parser error' }, ]; function extractCurlError(stderr) { var m; return ((m = /(curl: \(\d+\)[\s\S]+)/i.exec(stderr)) && m[1].trim()) || stderr; } function next() { if (t === tests.length - 1) return destroyHttpServer(); var v = tests[++t]; v.run.call(v); } function makeMsg(what, msg) { return '[' + group + what + ']: ' + msg; } function destroyHttpServer() { if (httpServer) { httpServer.close(); httpServer = undefined; } } process.once('uncaughtException', function(err) { destroyHttpServer(); if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err)) console.log(makeMsg(tests[t].what, 'Unexpected Exception:')); throw err; }); process.once('exit', function() { destroyHttpServer(); assert(t === tests.length - 1, makeMsg('_exit', 'Only finished ' + (t + 1) + '/' + tests.length + ' tests')); }); cpexec('curl', ['--help'], function(err) { if (err) { console.error('curl is required to run server tests'); return; } // start an http server for cURL to use when passing connections through httpServer = http.createServer(function(req, res) { req.resume(); res.statusCode = 200; res.end(HTTP_RESPONSE); }); httpServer.listen(0, 'localhost', function() { httpAddr = this.address().address; httpPort = this.address().port; next(); }); }); socksv5-master/test/test.js000066400000000000000000000007601264411760300162470ustar00rootroot00000000000000var spawn = require('child_process').spawn, join = require('path').join; var files = require('fs').readdirSync(__dirname).filter(function(f) { return (f.substr(0, 5) === 'test-'); }).map(function(f) { return join(__dirname, f); }), f = -1; function next() { if (++f < files.length) { spawn(process.argv[0], [ files[f] ], { stdio: 'inherit' }) .on('exit', function(code) { if (code === 0) process.nextTick(next); }); } } next();