diff --git a/example/cks5-hostname b/example/cks5-hostname new file mode 100644 index 0000000..3e6a4ef --- /dev/null +++ b/example/cks5-hostname @@ -0,0 +1,6 @@ + +301 Moved +

301 Moved

+The document has moved +here. + diff --git a/example/index.js b/example/index.js index 01c542b..3fb6d29 100644 --- a/example/index.js +++ b/example/index.js @@ -1,30 +1,29 @@ -const socks5Stream = require("../src/index"); -const net = require("net"); -// Server mock +const socks5Stream = require('../src/index'); +const net = require('net'); +// Server mock var server = net.createServer((socket) => { // Create a new socks5 stream without Authentication var sockStream = new socks5Stream(socket); - //Create a new socks5 stream with Type as "username" and Auth details as Username and Password - + //Create a new socks5 stream with Username and Password Authentication var sockStreamAuth = new socks5Stream(socket, { - authType:"username", - username:"username", - password:"password" + username: "username", + password: "password", + authType: "username" }); //Piping the data to sock5 stream - socket.pipe(sockStream).once("data", (data) => { - console.log(", ==> " + data.toString()); + socket.pipe(sockStream).once('data', (data) => { + console.log(', ==> ' + data.toString()); sockStream.acceptConnection(true); - sockStream.on("data", (chunk) => { - console.log(chunk.toString()); - }); - }); + sockStream.on('data', (chunk) => { + // console.log(chunk.toString()); + }) + }) }); server.listen(8124, () => { - console.log("server bound"); + console.log('server bound'); }); diff --git a/package.json b/package.json index 3eb9173..a137ea1 100644 --- a/package.json +++ b/package.json @@ -21,4 +21,4 @@ "url": "https://github.com/nimit95/socks5-stream/issues" }, "homepage": "https://github.com/nimit95/socks5-stream#readme" -} +} \ No newline at end of file diff --git a/src/constants.js b/src/constants.js index 76205b3..1694c00 100644 --- a/src/constants.js +++ b/src/constants.js @@ -3,28 +3,19 @@ module.exports.socksVersion = 0x05; module.exports.states = { - NO_CONNECTION:0, - CONNECTING:1, + NO_CONNECTION: 0, + CONNECTING: 1, CONNECTED: 3, DISCONNECTED: 4, AUTHENTICATION: 5 -}; +} module.exports.authTypes = { - username:1 -}; + username: 1 +} module.exports.SOCKS_ADDRESS = { IPV4: 0x01, HOSTNAME: 0x03, IPV6: 0x04 -}; - -module.exports.SOCKET_ERRORS = { - NOT_DEFINED : "Socket is not defined or valid", - WRONG_AUTH : "Wrong Authentication Details givem", - INITIAL_HANSHAKE : "Got Wrong initial Handshake(not 5,0,x)", - INVALID_AUTH_PACKET: "Invalid Authentication Packet received", - INVALID_CONNECT: "Got Wrong Handshake(not 5,1,x,x,x...)", - NO_CONNECTION : "Connection not established yet" -}; +} diff --git a/src/index.js b/src/index.js index 3f11abe..77c7b57 100644 --- a/src/index.js +++ b/src/index.js @@ -1,25 +1,25 @@ -const { Transform } = require("stream"); -const util = require("util"); -const constants = require("./constants"); -const socksUtils = require("./socksUtils"); -const utils = require("./utils"); +const { Transform } = require('stream'); +const util = require('util'); +const constants = require('./constants'); +const socksUtils = require('./socksUtils'); +const utils = require('./utils') /** - * @param {net.Socket} socket + * @param {net.Socket} socket * Socket from which the Socks stream is comming. * @param {Object} authDetails * Optional for authorization if any, Defaults to undefined * { - * //In case of username and password + * //In case of username and password * authType:"username", * username:, * password: - * - * + * + * * } */ -const socks5Stream = function(socket, authDetails) { +const socks5Stream = function (socket, authDetails) { this.authDetails = authDetails || false; this._socket = socket; @@ -28,87 +28,89 @@ const socks5Stream = function(socket, authDetails) { this.state = constants.states.NO_CONNECTION; - if(this.authDetails) { - this.authType = constants.authTypes[this.authDetails.authType]; + if (this.authDetails) { + this.authType = constants.authTypes[this.authDetails.authType] } else { this.authType = false; } -}; + +} util.inherits(socks5Stream, Transform); -socks5Stream.prototype._transform = function(chunk, encoding, callback) { +socks5Stream.prototype._transform = function (chunk, encoding, callback) { - if(!utils.isSocketObjValid(this._socket)) { - return callback(new Error(constants.SOCKET_ERRORS.NOT_DEFINED)); + if (!utils.isSocketObjValid(this._socket)) { + return callback(new Error("Socket is not defined or valid")); } - if(this.authDetails && !utils.validateAuth(this.authDetails)) { - return callback(new Error(constants.SOCKET_ERRORS.WRONG_AUTH)); + if (this.authDetails && !utils.validateAuth(this.authDetails)) { + return callback(new Error("Wrong Authentication Details")); } // console.log(chunk); - if(this.state === constants.states.NO_CONNECTION) { - - if(!socksUtils.checkIntialSocksChunk(chunk)) { - return callback(new Error(constants.SOCKET_ERRORS.INITIAL_HANSHAKE)); + if (this.state === constants.states.NO_CONNECTION) { + + if (!socksUtils.checkIntialSocksChunk(chunk)) { + return callback(new Error("Got Wrong initial Handshake(not 5,0,x)")); } - //We need to conect + //We need to conect this._socket.write(socksUtils.generateInitialHandshakeResponse(this.authType), () => { - - this.state = this.authDetails? constants.states.AUTHENTICATION : constants.states.CONNECTING; + + this.state = this.authDetails ? constants.states.AUTHENTICATION : constants.states.CONNECTING; callback(null); }); + } - if(this.state === constants.states.AUTHENTICATION) { - if(!socksUtils.checkAuthRequest(chunk, this.authType)) { - return callback(new Error(constants.SOCKET_ERRORS.INVALID_AUTH_PACKET)); + if (this.state === constants.states.AUTHENTICATION) { + if (!socksUtils.checkAuthRequest(chunk, this.authType)) { + return callback(new Error("Wrong Authentication Details")); } var authDetailRequest = socksUtils.getUsernamePassFromRequest(chunk, this.authType); - if(this.authDetails.username == authDetailRequest.username && this.authDetails.password == authDetailRequest.password) { + if (this.authDetails.username == authDetailRequest.username && this.authDetails.password == authDetailRequest.password) { this._socket.write(socksUtils.generateSuccessSocksAuthResponse(), () => { this.state = constants.states.CONNECTING; - }); + }) callback(null); } else { this._socket.write(socksUtils.generateFailSocksAuthResponse(), () => { this.state = constants.states.DISCONNECTED; - }); + }) //Closing the connection in case of wrong username/password this._socket.end(); } } - if(this.state === constants.states.CONNECTING) { - if(!socksUtils.checkConnectResponse(chunk)) { - return callback(new Error(constants.SOCKET_ERRORS.INVALID_CONNECT)); + if (this.state === constants.states.CONNECTING) { + if (!socksUtils.checkConnectResponse(chunk)) { + return callback(new Error("Got Wrong Handshake(not 5,1,x,x,x...)")); } let hostnamePortObj = socksUtils.getHostnamePort(chunk); - return callback(null, `${hostnamePortObj.hostname}, ${hostnamePortObj.port}`); + return callback(null, `${hostnamePortObj.hostname},${hostnamePortObj.port}`); } - if(this.state === constants.states.CONNECTED) { + if (this.state === constants.states.CONNECTED) { // console.log('connected', chunk.toString()); callback(null, chunk); } - if(this.state === constants.states.DISCONNECTED) { + if (this.state === constants.states.DISCONNECTED) { callback(null); } - this.acceptConnection = function(flag) { - if(this.state === constants.states.NO_CONNECTION) { - return callback(new Error(constants.SOCKET_ERRORS.NO_CONNECTION)); + this.acceptConnection = function (flag) { + if (this.state === constants.states.NO_CONNECTION) { + return callback(new Error("Connection not established yet.")); } - if(flag) { + if (flag) { this._socket.write(socksUtils.connectionSuccessfulResponse(), () => { this.state = constants.states.CONNECTED; }); @@ -119,15 +121,15 @@ socks5Stream.prototype._transform = function(chunk, encoding, callback) { //return callback(null); }); } - }; + } - this._socket.on("close", () => { + this._socket.on('close', () => { this.state = constants.states.DISCONNECTED; }); - this._socket.on("error", () => { + this._socket.on('error', () => { this.state = constants.states.DISCONNECTED; }); - -}; + +} module.exports = socks5Stream; diff --git a/src/socksUtils.js b/src/socksUtils.js index 43028b0..4d5f5c0 100644 --- a/src/socksUtils.js +++ b/src/socksUtils.js @@ -1,143 +1,135 @@ -const constants = require("./constants"); -var checkIntialSocksChunk = function(chunk) { - if(chunk.length < 3 || chunk[0]!=constants.socksVersion || chunk[1] == 0x00 || chunk.length !== parseInt(chunk[1]) + 2) - return false; - return true; -}; +const constants = require('./constants'); +var checkIntialSocksChunk = function (chunk) { + if (chunk.length < 3 || chunk[0] != constants.socksVersion || chunk[1] == 0x00 || chunk.length !== parseInt(chunk[1]) + 2) + return false + return true +} -var checkConnectResponse = function(chunk) { - if(chunk.length < 4 || chunk[0]!== constants.socksVersion || chunk[2] !== 0x00) return false; +var checkConnectResponse = function (chunk) { + if (chunk.length < 4 || chunk[0] !== constants.socksVersion || chunk[2] !== 0x00) return false; - if(chunk[3] === constants.SOCKS_ADDRESS.IPV4) { + if (chunk[3] === constants.SOCKS_ADDRESS.IPV4) { return chunk.length === 10; - } else if(chunk[3] === constants.SOCKS_ADDRESS.IPV6) { + } else if (chunk[3] === constants.SOCKS_ADDRESS.IPV6) { return chunk.length === 22; - } else if(chunk[3] === constants.SOCKS_ADDRESS.HOSTNAME){ + } else if (chunk[3] === constants.SOCKS_ADDRESS.HOSTNAME) { return chunk.length > 3 && chunk.length === 7 + parseInt(chunk[4]); } else { return false; } -}; +} -var generateInitialHandshakeResponse = function(authType) { - var buf = new Buffer.alloc(2,0x00, "hex"); +var generateInitialHandshakeResponse = function (authType) { + var buf = new Buffer.alloc(2, 0x00, 'hex'); buf[0] = constants.socksVersion; - if(authType == constants.authTypes.username) { + if (authType == constants.authTypes.username) { buf[1] = 0x02; } else { buf[1] = 0x00; } return buf; -}; +} -var connectionSuccessfulResponse = function() { - var buf = new Buffer.alloc(4 + this.buf.length, 0x00, "hex"); +var connectionSuccessfulResponse = function () { + var buf = new Buffer.alloc(4 + this.buf.length, 0x00, 'hex'); buf[0] = constants.socksVersion; buf[1] = 0x00; buf[2] = 0x00; buf[3] = 0x01; this.buf.copy(buf, 4, 0); return buf; -}; +} -var connectionUnsuccessfulResponse = function() { - var buf = new Buffer.alloc(4 + this.buf.length, 0x00, "hex"); +var connectionUnsuccessfulResponse = function () { + var buf = new Buffer.alloc(4 + this.buf.length, 0x00, 'hex'); buf[0] = constants.socksVersion; buf[1] = 0x00; buf[2] = 0x00; buf[3] = 0x01; this.buf.copy(buf, 4, 0); return buf; -}; +} -var getHostnamePort = function(chunk) { +var getHostnamePort = function (chunk) { + console.log(chunk); this.addressType = chunk[3]; - if(chunk[3] === constants.SOCKS_ADDRESS.IPV4) { - let hostname = "", port = ""; + if (chunk[3] === constants.SOCKS_ADDRESS.IPV4) { + let hostname = "", port = parseInt(chunk.slice(8).toString("hex"), 16); this.buf = chunk.slice(4); chunk.slice(4, 8).forEach(value => { - hostname += parseInt(value) + "."; - }); - chunk.slice(8).forEach(value => { - port += parseInt(value); + hostname += parseInt(value) + '.'; }); return { hostname: hostname.slice(0, -1), port: port }; - } - if(chunk[3] === constants.SOCKS_ADDRESS.IPV6) { - let hostname = "", port = ""; + } + if (chunk[3] === constants.SOCKS_ADDRESS.IPV6) { + let hostname = "", port = parseInt(chunk.slice(chunk.length - 2).toString("hex"), 16); this.buf = chunk.slice(4); - chunk.toString("hex", 4, chunk.length - 2).split("").forEach((value, idx) => { - + chunk.toString('hex', 4, chunk.length - 2).split('').forEach((value, idx) => { + hostname += value; - - if(idx%4 === 3){ + + if (idx % 4 === 3) { // console.log(idx); - hostname = hostname + "."; + hostname = hostname + '.' } }); - chunk.slice(chunk.length - 2).forEach(value => { - port += parseInt(value); - }); return { hostname: hostname.slice(0, -1), port: port }; - } - if(chunk[3] === constants.SOCKS_ADDRESS.HOSTNAME){ - let port = ""; + } + if (chunk[3] === constants.SOCKS_ADDRESS.HOSTNAME) { + let hostname = "", port = parseInt(chunk.slice(chunk.length - 2).toString("hex"), 16); this.buf = chunk.slice(4); - chunk.slice(chunk.length - 2).forEach(value => { - port += parseInt(value); - }); return { - hostname: chunk.toString("ascii", 5, 5 + parseInt(chunk[4])), + hostname: chunk.toString('ascii', 5, 5 + parseInt(chunk[4])), port: port }; } return null; -}; +} -var checkAuthRequest = function(chunk, authType) { - if(authType == constants.authTypes.username) { - return chunk.length > 3 && parseInt(chunk[1]) > 0 && chunk.length == 3 + parseInt(chunk[1]) + parseInt(chunk[parseInt(chunk[1]) + 2]); +var checkAuthRequest = function (chunk, authType) { + if (authType == constants.authTypes.username) { + return chunk.length > 3 && parseInt(chunk[1]) > 0 && chunk.length == 3 + parseInt(chunk[1]) + parseInt(chunk[parseInt(chunk[1]) + 2]) } -}; +} -var getUsernamePassFromRequest = function(chunk, authType) { - if(authType == constants.authTypes.username) { - var uName = chunk.toString("ascii", 2, parseInt(chunk[1])+2); - var pass = chunk.toString("ascii", 3 + parseInt(chunk[1])); +var getUsernamePassFromRequest = function (chunk, authType) { + if (authType == constants.authTypes.username) { + var uName = chunk.toString('ascii', 2, parseInt(chunk[1]) + 2); + var pass = chunk.toString('ascii', 3 + parseInt(chunk[1])); console.log(uName, pass); return { username: uName, password: pass - }; + } } -}; +} -var generateSuccessSocksAuthResponse = function() { - var buf = new Buffer.alloc(2, 0x00, "hex"); +var generateSuccessSocksAuthResponse = function () { + var buf = new Buffer.alloc(2, 0x00, 'hex'); buf[0] = constants.socksVersion; buf[1] = 0x00; return buf; -}; +} -var generateFailSocksAuthResponse = function() { - var buf = new Buffer.alloc(2, 0x00, "hex"); +var generateFailSocksAuthResponse = function () { + var buf = new Buffer.alloc(2, 0x00, 'hex'); buf[0] = constants.socksVersion; buf[1] = 0x01; return buf; -}; +} module.exports.checkIntialSocksChunk = checkIntialSocksChunk; module.exports.checkConnectResponse = checkConnectResponse; diff --git a/src/utils.js b/src/utils.js index 72b3414..4b6b112 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,19 +1,19 @@ -const constants = require("./constants"); +const constants = require('./constants'); const utils = { - isSocketObjValid: function(socket) { - return socket && typeof socket == "object"; + isSocketObjValid: function (socket) { + return socket && typeof socket == 'object' }, - validateAuth: function(authDetails) { - if(typeof authDetails != "object"){ + validateAuth: function (authDetails) { + if (typeof authDetails != 'object') { return false; } - if(constants.authTypes[authDetails.authType] === constants.authTypes["username"]) { - return typeof authDetails.username == "string" && typeof authDetails.password == "string" - && authDetails.username.length > 0; + if (constants.authTypes[authDetails.authType] === constants.authTypes["username"]) { + return typeof authDetails.username == 'string' && typeof authDetails.password == 'string' + && authDetails.username.length > 0; } } -}; +} module.exports = utils; \ No newline at end of file