Created
February 14, 2012 16:21
-
-
Save adammw/1827875 to your computer and use it in GitHub Desktop.
Socks library snippet for Node.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var net = require('net'), | |
util = require('util'), | |
EventEmitter = require('events').EventEmitter; | |
var SOCKSClient = module.exports = function() { | |
var args = normalizeConnectArgs(arguments); | |
this.state = 'connecting'; | |
this.socket = net.connect(args[0].port, args[0].host, onConnect.bind(this)); | |
this.socket.on('data', onData.bind(this)); | |
this.socket.on('end', onEnd.bind(this)); | |
args[1] && this.on('connect', args[1]); | |
return this; | |
}; | |
util.inherits(SOCKSClient, EventEmitter); | |
SOCKSClient.prototype.connect = SOCKSClient.prototype.createConnection = function() { | |
if (this.state != "authenticated") return; | |
var args = normalizeConnectArgs(arguments); | |
this.virtualSocket = new SOCKSSocket(this, args[0].host, args[0].port, args[1]); | |
return this.virtualSocket; | |
} | |
var SOCKSSocket = function(client, host, port, cb) { | |
this.host = host; | |
this.port = port; | |
this.client = client; | |
cb && this.on('connect', cb); | |
var portBuf = new Buffer(2); | |
portBuf.writeUInt16BE(port, 0); | |
var lenBuf = new Buffer(1); | |
lenBuf.writeUInt8(Buffer.byteLength(host), 0); | |
this.client.socket.write("\x05\x01\x00\x03" + lenBuf.toString() + host + portBuf.toString()); | |
this.client.state = "connectrequest"; | |
} | |
util.inherits(SOCKSSocket, EventEmitter); | |
SOCKSSocket.prototype.setEncoding = function(enc) { this.encoding = enc; } | |
SOCKSSocket.prototype.write = function(data) { this.client.socket.write(data); }; | |
SOCKSSocket.prototype.end = function() { this.client.socket.end(); }; | |
var normalizeConnectArgs = function(args) { | |
var options = {}; | |
if (typeof args[0] === 'object') { | |
// connect(options, [cb]) | |
options = args[0]; | |
} else { | |
// connect(port, [host], [cb]) | |
options.port = args[0]; | |
if (typeof args[1] === 'string') { | |
options.host = args[1]; | |
} | |
} | |
var cb = args[args.length - 1]; | |
return (typeof cb === 'function') ? [options, cb] : [options]; | |
}; | |
var onConnect = function() { | |
this.socket.write("\x05\x01\x00"); // We only support the "no authentication" (0x00) scheme | |
this.state = "connected"; | |
}; | |
var onData = function(data) { | |
switch (this.state) { | |
case "connected": | |
if (data[0] == 0xff) { | |
console.error("socks: no acceptable authentication methods were offered"); | |
this.socket.end(); | |
this.state = "failed"; | |
return; | |
} | |
this.state = "authenticated"; | |
this.emit("connect"); | |
break; | |
case "connectrequest": | |
if (data[1] != 0x00) { | |
console.error("socks: connect request failed: error code " + data[1]); | |
this.socket.end(); | |
this.state = "failed"; | |
return; | |
} | |
this.virtualSocket.emit("connect"); | |
this.state = "socketconnected"; | |
break; | |
case "socketconnected": | |
if (this.virtualSocket.encoding) data = data.toString(this.virtualSocket.encoding); | |
this.virtualSocket.emit("data", data); | |
break; | |
case "authenticated": | |
default: | |
console.log(this.state, data); | |
} | |
}; | |
var onEnd = function() { | |
this.virtualSocket && this.virtualSocket.emit('end'); | |
this.emit('end'); | |
}; | |
//test | |
/* | |
var socks = new SOCKSClient(9050, function() { | |
console.log('connected to socks'); | |
var socket = socks.connect(80, 'www.google.com', function() { | |
console.log('connected to host'); | |
socket.write("GET / HTTP/1.0\r\n\r\n"); | |
socket.setEncoding('utf8'); | |
socket.on('data', function(data) { | |
console.log(data); | |
}); | |
}); | |
}); //*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment