Added word breaking
This commit is contained in:
parent
0d44e0aca2
commit
ecac3cb6c9
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Kristopher Ives
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,108 @@
|
||||||
|
# proxysocket
|
||||||
|
|
||||||
|
[![Join the chat at https://gitter.im/krisives/proxysocket](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/krisives/proxysocket?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
`proxysocket` is a nodejs module for seamlessly making socket connections via a
|
||||||
|
SOCKS5 proxy. Use it in place of a regular `net.Socket` to easily talk over
|
||||||
|
Tor or an SSH tunnel.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Available on npm for easy install:
|
||||||
|
|
||||||
|
npm install proxysocket
|
||||||
|
|
||||||
|
You can also download a [release](https://github.com/krisives/proxysocket/releases) manually and
|
||||||
|
extract it as `proxysocket` has no dependencies.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Because `proxysocket` provides the same API as a regular `net.Socket` object
|
||||||
|
you can use it in many places where sockets and streams are used.
|
||||||
|
|
||||||
|
### Making a Socket
|
||||||
|
|
||||||
|
Create a new socket that will use the proxy:
|
||||||
|
|
||||||
|
var proxysocket = require('proxysocket');
|
||||||
|
var socket = proxysocket.create('localhost', 9050);
|
||||||
|
|
||||||
|
The returned object behaves like an ordinary `net.Socket` object.
|
||||||
|
For example, you can call `connect()` or listen for events:
|
||||||
|
|
||||||
|
socket.connect('website.com', 80, function () {
|
||||||
|
// Connected
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('data', function (data) {
|
||||||
|
// Receive data
|
||||||
|
});
|
||||||
|
|
||||||
|
Also note if you're using Tor it's fine to pass `.onion` hosts:
|
||||||
|
|
||||||
|
socket.connect('p4fsi4ockecnea7l.onion', 6667);
|
||||||
|
|
||||||
|
|
||||||
|
### Making HTTP Requests
|
||||||
|
|
||||||
|
You can use `proxysocket.createAgent()` to create an object
|
||||||
|
like `http.Agent` which will make proxy sockets for you when using
|
||||||
|
`http.request()`. Here is an example:
|
||||||
|
|
||||||
|
var proxysocket = require('proxysocket');
|
||||||
|
var http = require('http');
|
||||||
|
var agent = proxysocket.createAgent();
|
||||||
|
|
||||||
|
http.request({
|
||||||
|
host: 'foo.com',
|
||||||
|
agent: agent
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### proxysocket.create(socksHost, socksPort, socket)
|
||||||
|
|
||||||
|
Create a new socket object that uses a SOCKS5 proxy provided.
|
||||||
|
|
||||||
|
* `socksHost` is the host of the proxy. Default is `localhost`
|
||||||
|
* `socksPort` is the port of the proxy. Default is `9050`
|
||||||
|
* `socket` can be an existing `net.Socket` object. Default is a `new Socket()`
|
||||||
|
|
||||||
|
### proxysocket.createAgent(socksHost, socksPort)
|
||||||
|
|
||||||
|
Returns an object like `http.Agent` which makes new sockets
|
||||||
|
using `proxysocket.create()` as needed.
|
||||||
|
|
||||||
|
### socket
|
||||||
|
|
||||||
|
The object returned from `proxysocket.create()` is just like a regular
|
||||||
|
`net.Socket`. This documentation lists additions to the API.
|
||||||
|
|
||||||
|
*Note This documentation doesn't list all of the methods, properties,
|
||||||
|
or events of `net.Socket`, `Readable` or `Writable`. See the nodejs
|
||||||
|
API reference for those modules.*
|
||||||
|
|
||||||
|
### socket.socksHost
|
||||||
|
|
||||||
|
Get the host address of the proxy. By default this will be `localhost`.
|
||||||
|
|
||||||
|
### socket.socksPort
|
||||||
|
|
||||||
|
Get the port of the proxy. By default this will be `9050`.
|
||||||
|
|
||||||
|
### socket.realSocket
|
||||||
|
|
||||||
|
Get the underlying raw `net.Socket` connection to the proxy. You don't need
|
||||||
|
to use this and instead should listen on `this` socket instead.
|
||||||
|
|
||||||
|
### socket 'socksdata' event
|
||||||
|
|
||||||
|
`socksdata` is emitted whenever underlying data is received from the proxy
|
||||||
|
before the socket is ready for use. This is mainly here for debugging and you
|
||||||
|
should use the `data` event instead.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please fork and make a pull request if you have anything cool to add. You're
|
||||||
|
also welcome to join the [Gitter](https://gitter.im/krisives/proxysocket?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) chat.
|
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
"_args": [
|
||||||
|
[
|
||||||
|
"proxysocket",
|
||||||
|
"/mnt/c/Users/Josua/Desktop/data/nodejs/electron/chat-project/chat-client"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"_from": "proxysocket@latest",
|
||||||
|
"_id": "proxysocket@1.2.0",
|
||||||
|
"_inCache": true,
|
||||||
|
"_installable": true,
|
||||||
|
"_location": "/proxysocket",
|
||||||
|
"_nodeVersion": "4.6.0",
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"host": "packages-12-west.internal.npmjs.com",
|
||||||
|
"tmp": "tmp/proxysocket-1.2.0.tgz_1477420117142_0.21117400820367038"
|
||||||
|
},
|
||||||
|
"_npmUser": {
|
||||||
|
"email": "kristopher.ives@gmail.com",
|
||||||
|
"name": "krisives"
|
||||||
|
},
|
||||||
|
"_npmVersion": "2.15.9",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"name": "proxysocket",
|
||||||
|
"raw": "proxysocket",
|
||||||
|
"rawSpec": "",
|
||||||
|
"scope": null,
|
||||||
|
"spec": "latest",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"#USER"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/proxysocket/-/proxysocket-1.2.0.tgz",
|
||||||
|
"_shasum": "0d654c36754a40421e7e65971d62fe1f1a6938b7",
|
||||||
|
"_shrinkwrap": null,
|
||||||
|
"_spec": "proxysocket",
|
||||||
|
"_where": "/mnt/c/Users/Josua/Desktop/data/nodejs/electron/chat-project/chat-client",
|
||||||
|
"author": {
|
||||||
|
"email": "kristopher.ives@gmail.com",
|
||||||
|
"name": "Kristopher Ives",
|
||||||
|
"url": "https://github.com/krisives"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/krisives/proxysocket/issues"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"description": "SOCKS5 client for making socket connections",
|
||||||
|
"devDependencies": {},
|
||||||
|
"directories": {},
|
||||||
|
"dist": {
|
||||||
|
"shasum": "0d654c36754a40421e7e65971d62fe1f1a6938b7",
|
||||||
|
"tarball": "https://registry.npmjs.org/proxysocket/-/proxysocket-1.2.0.tgz"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "0.x"
|
||||||
|
},
|
||||||
|
"gitHead": "156f6fa27313979126a9743ec0ec9cab21fc8915",
|
||||||
|
"homepage": "https://github.com/krisives/proxysocket",
|
||||||
|
"keywords": [
|
||||||
|
"proxy",
|
||||||
|
"socket",
|
||||||
|
"socks",
|
||||||
|
"socks4",
|
||||||
|
"socks5",
|
||||||
|
"tor"
|
||||||
|
],
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"type": "MIT",
|
||||||
|
"url": "http://mattcg.mit-license.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"main": "proxysocket.js",
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "krisives",
|
||||||
|
"email": "kristopher.ives@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "proxysocket",
|
||||||
|
"optionalDependencies": {},
|
||||||
|
"readme": "ERROR: No README data found!",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/krisives/proxysocket.git"
|
||||||
|
},
|
||||||
|
"scripts": {},
|
||||||
|
"version": "1.2.0"
|
||||||
|
}
|
|
@ -0,0 +1,459 @@
|
||||||
|
|
||||||
|
|
||||||
|
var net = require('net');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
var inherits = require('util').inherits;
|
||||||
|
|
||||||
|
function proxysocket(socksHost, socksPort, socket) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Set when we start connect()
|
||||||
|
var connecting = false;
|
||||||
|
|
||||||
|
// Set when connection stages are finished
|
||||||
|
var connected = false;
|
||||||
|
|
||||||
|
// Stages in the SOCKS5 connection
|
||||||
|
var connectionStages = [
|
||||||
|
receiveSocksAuth,
|
||||||
|
receiveSocksConnect
|
||||||
|
];
|
||||||
|
|
||||||
|
// What stage we are in currently
|
||||||
|
var stage = 0;
|
||||||
|
|
||||||
|
// Set from connect() to what host and port we are connecting to
|
||||||
|
var host = '', port = 0;
|
||||||
|
|
||||||
|
// While the SOCKS connection is going we buffer the
|
||||||
|
// requests to write()
|
||||||
|
var unsent = [];
|
||||||
|
// and to pipe()
|
||||||
|
var unpiped = [];
|
||||||
|
|
||||||
|
// While the socket is still being setup the encoding
|
||||||
|
// is saved as we expect binray encoding on the socket
|
||||||
|
// until then
|
||||||
|
var socketEncoding = null;
|
||||||
|
|
||||||
|
// Default host/ports to use if not given
|
||||||
|
self.socksHost = socksHost = socksHost || 'localhost';
|
||||||
|
self.socksPort = socksPort = socksPort || '9050';
|
||||||
|
|
||||||
|
// Users can pass their own socket if they already have one
|
||||||
|
// connected to the SOCKS proxy
|
||||||
|
self.realSocket = socket = socket || (new net.Socket({
|
||||||
|
readable: true,
|
||||||
|
writable: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
// A socket emits events like 'data' and 'connect'
|
||||||
|
EventEmitter.call(self);
|
||||||
|
|
||||||
|
self.readable = true;
|
||||||
|
self.writable = true;
|
||||||
|
|
||||||
|
// Read event for the real socket
|
||||||
|
socket.on('data', function (buffer) {
|
||||||
|
if (connected) {
|
||||||
|
self.emit('data', buffer);
|
||||||
|
} else {
|
||||||
|
// Emit an event useful for debugging the raw SOCKS data
|
||||||
|
self.emit('socksdata', buffer);
|
||||||
|
|
||||||
|
// Handle SOCKS protocol data
|
||||||
|
receiveSocksData(buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('error', function (e) {
|
||||||
|
self.emit('error', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('end', function () {
|
||||||
|
self.writable = false;
|
||||||
|
|
||||||
|
self.emit('end');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('timeout', function () {
|
||||||
|
self.emit('timeout');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('close', function () {
|
||||||
|
self.writable = false;
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
self.emit('close');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('drain', function () {
|
||||||
|
if (connected) {
|
||||||
|
self.emit('drain');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('readable', function () {
|
||||||
|
if (connected) {
|
||||||
|
self.emit('readable');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.read = function (size) {
|
||||||
|
if (!connected) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket.read(size);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.destroy = function () {
|
||||||
|
self.writable = false;
|
||||||
|
|
||||||
|
return socket.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.destroySoon = function () {
|
||||||
|
self.writable = false;
|
||||||
|
|
||||||
|
return socket.destroySoon();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ref = function () {
|
||||||
|
return socket.ref();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.unref = function () {
|
||||||
|
return socket.unref();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setKeepAlive = function (enable, initialDelay) {
|
||||||
|
return socket.setKeepAlive(enable, initialDelay);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pipe = function (dest, opts) {
|
||||||
|
if (connected) {
|
||||||
|
return socket.pipe(dest, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
unpiped.push([dest, opts]);
|
||||||
|
return dest;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle SOCKS protocol specific data
|
||||||
|
function receiveSocksData(data) {
|
||||||
|
while (data && stage < connectionStages.length) {
|
||||||
|
data = connectionStages[stage](data);
|
||||||
|
stage++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the sockets first packet
|
||||||
|
if (connected && data) {
|
||||||
|
self.emit('data', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the response after sending authentication
|
||||||
|
function receiveSocksAuth(d) {
|
||||||
|
var error;
|
||||||
|
|
||||||
|
if (d.length !== 2) {
|
||||||
|
error = new Error('SOCKS authentication failed. Unexpected number of bytes received.');
|
||||||
|
} else if (d[0] !== 0x05) {
|
||||||
|
error = new Error('SOCKS authentication failed. Unexpected SOCKS version number: ' + d[0] + '.');
|
||||||
|
} else if (d[1] !== 0x00) {
|
||||||
|
error = new Error('SOCKS authentication failed. Unexpected SOCKS authentication method: ' + d[1] + '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
self.emit('error', error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the response after sending connection request
|
||||||
|
function receiveSocksConnect(d) {
|
||||||
|
var error;
|
||||||
|
|
||||||
|
if (d[0] !== 0x05) {
|
||||||
|
error = new Error('SOCKS connection failed. Unexpected SOCKS version number: ' + d[0] + '.');
|
||||||
|
} else if (d[1] !== 0x00) {
|
||||||
|
error = new Error('SOCKS connection failed. ' + connectErrors[d[1]] + '.');
|
||||||
|
} else if (d[2] !== 0x00) {
|
||||||
|
error = new Error('SOCKS connection failed. The reserved byte must be 0x00.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
self.emit('error', error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connected = true;
|
||||||
|
|
||||||
|
// TODO map some of the addresses?
|
||||||
|
self.localPort = socket.localPort;
|
||||||
|
self.localAddress = socket.localAddress;
|
||||||
|
self.remotePort = socket.remotePort;
|
||||||
|
self.remoteAddress = socket.remoteAddress;
|
||||||
|
self.bufferSize = socket.bufferSize;
|
||||||
|
|
||||||
|
// Set the real encoding which could have been
|
||||||
|
// changed while the socket was connecting
|
||||||
|
setEncoding(socketEncoding);
|
||||||
|
|
||||||
|
if (unsent.length) {
|
||||||
|
for (var i=0; i < unsent.length; i++) {
|
||||||
|
socket.write(unsent[i][0], unsent[i][1], unsent[i][2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsent = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unpiped.length) {
|
||||||
|
for (var i=0; i < unpiped.length; i++) {
|
||||||
|
socket.pipe(unpiped[i][0], unpiped[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unpiped = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the real 'connect' event
|
||||||
|
self.emit('connect');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendAuth() {
|
||||||
|
var request = new Buffer(3);
|
||||||
|
request[0] = 0x05; // SOCKS version
|
||||||
|
request[1] = 0x01; // number of authentication methods
|
||||||
|
request[2] = 0x00; // no authentication
|
||||||
|
|
||||||
|
if (!socket.write(request)) {
|
||||||
|
throw new Error("Unable to write to SOCKS socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a domain name into a buffer
|
||||||
|
function parseDomainName(host, buffer) {
|
||||||
|
var i, c;
|
||||||
|
|
||||||
|
buffer.push(host.length);
|
||||||
|
|
||||||
|
for (i = 0; i < host.length; i++) {
|
||||||
|
c = host.charCodeAt(i);
|
||||||
|
buffer.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse an host like 1.2.3.4 into a 32-bit number
|
||||||
|
function parseIPv4(host, buffer) {
|
||||||
|
var i, n;
|
||||||
|
var parts = host.split('.');
|
||||||
|
|
||||||
|
for (i = 0; i < parts.length; ++i) {
|
||||||
|
n = parseInt(parts[i], 10);
|
||||||
|
buffer.push(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a IPv6 host into a buffer
|
||||||
|
function parseIPv6(host, buffer) {
|
||||||
|
var parts = host.split(':');
|
||||||
|
var i, ind;
|
||||||
|
var zeros = [];
|
||||||
|
|
||||||
|
parts[0] = parts[0] || '0000';
|
||||||
|
parts[parts.length - 1] = parts[parts.length - 1] || '0000';
|
||||||
|
ind = parts.indexOf('');
|
||||||
|
|
||||||
|
if (ind >= 0) {
|
||||||
|
for (i = 0; i < 8 - parts.length + 1; ++i) {
|
||||||
|
zeros.push('0000');
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = parts.slice(0, ind).concat(zeros).concat(parts.slice(ind + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
var num = parseInt(parts[i], 16);
|
||||||
|
buffer.push(num / 256 | 0);
|
||||||
|
buffer.push(num % 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendConnect() {
|
||||||
|
var request;
|
||||||
|
var buffer = [
|
||||||
|
0x05, // SOCKS version
|
||||||
|
0x01, // Command code: establish a TCP/IP stream connection
|
||||||
|
0x00 // Reserved - myst be 0x00
|
||||||
|
];
|
||||||
|
|
||||||
|
switch (net.isIP(host)) {
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
buffer.push(0x03);
|
||||||
|
parseDomainName(host, buffer);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
buffer.push(0x01);
|
||||||
|
parseIPv4(host, buffer);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
buffer.push(0x04);
|
||||||
|
parseIPv6(host, buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
htons(buffer, buffer.length, port);
|
||||||
|
request = new Buffer(buffer);
|
||||||
|
|
||||||
|
if (!socket.write(request)) {
|
||||||
|
throw new Error("Unable to write to SOCKS socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTimeout = function (timeout, f) {
|
||||||
|
return socket.setTimeout(timeout, f);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setNoDelay = function (noDelay) {
|
||||||
|
return socket.setNoDelay(noDelay);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.connect = function (connectHost, connectPort, f) {
|
||||||
|
if (connected) {
|
||||||
|
throw new Error("Socket is already connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connecting) {
|
||||||
|
throw new Error("Socket is already connecting");
|
||||||
|
}
|
||||||
|
|
||||||
|
host = connectHost;
|
||||||
|
port = connectPort;
|
||||||
|
connected = false;
|
||||||
|
connecting = true;
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
self.on('connect', f);
|
||||||
|
}
|
||||||
|
|
||||||
|
setEncoding(null);
|
||||||
|
|
||||||
|
socket.connect(socksPort, socksHost, function () {
|
||||||
|
connecting = false;
|
||||||
|
sendAuth();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.write = function (data, encoding, f) {
|
||||||
|
if (!connected) {
|
||||||
|
unsent.push([data, encoding, f]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket.write(data, encoding, f);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pause = function () {
|
||||||
|
socket.pause();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.resume = function () {
|
||||||
|
socket.resume();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.address = function () {
|
||||||
|
return socket.address();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.end = function (data, encoding) {
|
||||||
|
socket.writable = false;
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
return socket.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket.end(data, encoding);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setEncoding = function (encoding) {
|
||||||
|
if (connected) {
|
||||||
|
setEncoding(encoding);
|
||||||
|
} else {
|
||||||
|
// Save encoding to be set once connected
|
||||||
|
socketEncoding = encoding;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function setEncoding(enc) {
|
||||||
|
if (enc === null) {
|
||||||
|
// Accroding to nodejs documentation, readable.setEncoding(null)
|
||||||
|
// is a way to disable encoding.
|
||||||
|
// However, it's not. So, need to hack into readable structure.
|
||||||
|
socket.decoder = null;
|
||||||
|
socket.encoding = null;
|
||||||
|
} else {
|
||||||
|
socket.setEncoding(enc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(proxysocket, EventEmitter);
|
||||||
|
|
||||||
|
proxysocket.create = function (socksHost, socksPort, socket) {
|
||||||
|
return new proxysocket(socksHost, socksPort, socket);
|
||||||
|
};
|
||||||
|
|
||||||
|
// A simple agent so that requests can be made using http.request()
|
||||||
|
// and anything else using the same Agent API
|
||||||
|
proxysocket.createAgent = function (socksHost, socksPort) {
|
||||||
|
var http = require('http');
|
||||||
|
|
||||||
|
var agent = new http.Agent({
|
||||||
|
// keepAlive: true
|
||||||
|
});
|
||||||
|
|
||||||
|
function connect(host, port, f) {
|
||||||
|
var socket = proxysocket.create(socksHost, socksPort);
|
||||||
|
socket.connect(host, port, f);
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.createConnection = function (options, f) {
|
||||||
|
return connect(
|
||||||
|
options.host,
|
||||||
|
options.port,
|
||||||
|
f
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return agent;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = proxysocket;
|
||||||
|
|
||||||
|
// Converts a 16-bit short from Host To Network Storage
|
||||||
|
function htons(b, i, v) {
|
||||||
|
b[i] = (0xff & (v >> 8));
|
||||||
|
b[i + 1] = (0xff & (v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error messages for when the proxy responds to sendConnect() used in handleConnect()
|
||||||
|
var connectErrors = {
|
||||||
|
// Messages are taken from Wikipedia
|
||||||
|
0x00: 'request granted',
|
||||||
|
0x01: 'general failure',
|
||||||
|
0x02: 'connection not allowed by ruleset',
|
||||||
|
0x03: 'network unreachable',
|
||||||
|
0x04: 'host unreachable',
|
||||||
|
0x05: 'connection refused by destination host',
|
||||||
|
0x06: 'TTL expired',
|
||||||
|
0x07: 'command not supported / protocol error',
|
||||||
|
0x08: 'address type not supported'
|
||||||
|
};
|
|
@ -49,10 +49,10 @@
|
||||||
},
|
},
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"name": "Cat Chen"
|
"name": "John Fraser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "John Gruber"
|
"name": "Cat Chen"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Corey Innis"
|
"name": "Corey Innis"
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
"name": "Dominic Tarr"
|
"name": "Dominic Tarr"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "John Fraser"
|
"name": "John Gruber"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Titus Stone"
|
"name": "Titus Stone"
|
||||||
|
|
Loading…
Reference in New Issue