final
This commit is contained in:
parent
2962448bb1
commit
e41c4d99a4
|
@ -4,6 +4,10 @@ EXPOSE 9050
|
||||||
|
|
||||||
EXPOSE 53
|
EXPOSE 53
|
||||||
|
|
||||||
|
ENV DNS_PORT 53
|
||||||
|
|
||||||
|
ENV SOCKS_PORT 9050
|
||||||
|
|
||||||
ADD https://deb.nodesource.com/setup_7.x /nodejs_install
|
ADD https://deb.nodesource.com/setup_7.x /nodejs_install
|
||||||
|
|
||||||
RUN bash /nodejs_install
|
RUN bash /nodejs_install
|
||||||
|
|
54
bin/tor-router
Executable file
54
bin/tor-router
Executable file
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
var program = require('commander');
|
||||||
|
var TorRouter = require('../');
|
||||||
|
var SOCKSServer = TorRouter.SOCKSServer;
|
||||||
|
var DNSServer = TorRouter.DNSServer;
|
||||||
|
var TorPool = TorRouter.TorPool;
|
||||||
|
var winston = require('winston')
|
||||||
|
|
||||||
|
program
|
||||||
|
.version('0.0.1')
|
||||||
|
.option('-j, --instances <1>', 'Number of tor instances', Number)
|
||||||
|
.option('-s, --socksPort [9050]', 'SOCKS Server port', Number)
|
||||||
|
.option('-d, --dnsPort [9053]', 'DNS Server port', Number)
|
||||||
|
.option('-l, --logLevel [info]', 'Log level (defaults to "info") set to "null" to disable logging', Number)
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
|
var logger = new (winston.Logger)({
|
||||||
|
transports: [
|
||||||
|
new (winston.transports.Console)({ level: (program.logLevel || 'info') })
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
let instances = program.instances || Number(process.env.INSTANCES);
|
||||||
|
let log_level = program.logLevel || process.env.LOG_LEVEL;
|
||||||
|
let socks_port = program.socksPort || Number(process.env.SOCKS_PORT);
|
||||||
|
let dns_port = program.dnsPort || Number(process.env.DNS_PORT);
|
||||||
|
|
||||||
|
if (!instances) {
|
||||||
|
logger.error('Number of instances not specified');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pool = new TorPool('tor', null, logger);
|
||||||
|
|
||||||
|
if (log_level === 'null')
|
||||||
|
logger = void(0);
|
||||||
|
|
||||||
|
if (socks_port) {
|
||||||
|
let socks = new SOCKSServer(pool, logger);
|
||||||
|
logger && logger.info(`[socks]: Listening on ${socks_port}`);
|
||||||
|
socks.listen((socks_port || 9050));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dns_port) {
|
||||||
|
let dns = new DNSServer(pool, logger);
|
||||||
|
logger && logger.info(`[dns]: Listening on ${socks_port}`);
|
||||||
|
dns.serve((dns_port || 9050));
|
||||||
|
}
|
||||||
|
|
||||||
|
logger && logger.info('[tor]: starting tor...')
|
||||||
|
pool.create(instances, (err) => {
|
||||||
|
logger && logger.info('[tor]: tor started');
|
||||||
|
});
|
|
@ -7,4 +7,4 @@ services:
|
||||||
- "./test:/app/test"
|
- "./test:/app/test"
|
||||||
ports:
|
ports:
|
||||||
- "9050:9050"
|
- "9050:9050"
|
||||||
- "53:53"
|
- "53:53/udp"
|
|
@ -16,11 +16,12 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^2.1.4",
|
"async": "^2.1.4",
|
||||||
|
"commander": "^2.9.0",
|
||||||
"eventemitter2": "^3.0.0",
|
"eventemitter2": "^3.0.0",
|
||||||
"get-port": "^2.1.0",
|
"get-port": "^2.1.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"native-dns": "https://github.com/znetstar/node-dns.git",
|
"native-dns": "https://github.com/znetstar/node-dns.git",
|
||||||
"socksv5": "^0.0.6",
|
"socksv5": "git+https://github.com/lee-elenbaas/socksv5.git",
|
||||||
"temp": "^0.8.3",
|
"temp": "^0.8.3",
|
||||||
"winston": "^2.3.1"
|
"winston": "^2.3.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,28 @@ const dns = require('native-dns');
|
||||||
const UDPServer = require('native-dns').UDPServer;
|
const UDPServer = require('native-dns').UDPServer;
|
||||||
|
|
||||||
class DNSServer extends UDPServer {
|
class DNSServer extends UDPServer {
|
||||||
constructor(tor_pool, options, timeout) {
|
constructor(tor_pool, logger, options, timeout) {
|
||||||
super(options || {});
|
super(options || {});
|
||||||
|
this.logger = logger;
|
||||||
this.tor_pool = tor_pool;
|
this.tor_pool = tor_pool;
|
||||||
|
|
||||||
this.on('request', (req, res) => {
|
this.on('request', (req, res) => {
|
||||||
for (let question of req.question) {
|
for (let question of req.question) {
|
||||||
|
let dns_port = (tor_pool.next().dns_port);
|
||||||
|
|
||||||
let outbound_req = dns.Request({
|
let outbound_req = dns.Request({
|
||||||
question,
|
question,
|
||||||
server: { address: '127.0.0.1', port: (tor_pool.next().dns_port), type: 'udp' },
|
server: { address: '127.0.0.1', port: dns_port, type: 'udp' },
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
});
|
});
|
||||||
|
|
||||||
outbound_req.on('message', (err, answer) => {
|
outbound_req.on('message', (err, answer) => {
|
||||||
if (!err && answer)
|
if (!err && answer) {
|
||||||
answer.answer.forEach((a) => res.answer.push(a));
|
for (let a of answer.answer){
|
||||||
|
res.answer.push(a);
|
||||||
|
this.logger && this.logger.info(`[dns]: ${question.name} type ${dns.consts.QTYPE_TO_NAME[question.type]} → 127.0.0.1:${dns_port} → ${JSON.stringify(a)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
outbound_req.on('error', (err) => {
|
outbound_req.on('error', (err) => {
|
||||||
|
|
63
src/SOCKSServer.js
Normal file
63
src/SOCKSServer.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
const socks = require('socksv5');
|
||||||
|
const SOCKS5Server = socks.Server;
|
||||||
|
|
||||||
|
class SOCKSServer extends SOCKS5Server{
|
||||||
|
constructor(tor_pool, logger) {
|
||||||
|
super((info, accept, deny) => {
|
||||||
|
let inbound_socket = accept(true);
|
||||||
|
var outbound_socket;
|
||||||
|
let buffer = [];
|
||||||
|
|
||||||
|
let socks_port = (tor_pool.next().socks_port);
|
||||||
|
logger && logger.info(`[socks]: ${info.srcAddr}:${info.srcPort} → 127.0.0.1:${socks_port} → ${info.dstAddr}:${info.dstPort}`)
|
||||||
|
|
||||||
|
let onClose = () => {
|
||||||
|
inbound_socket && inbound_socket.end();
|
||||||
|
outbound_socket && outbound_socket.end();
|
||||||
|
|
||||||
|
inbound_socket = outbound_socket = buffer = void(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
let onInboundData = (data) => buffer.push(data)
|
||||||
|
|
||||||
|
if (!inbound_socket) return;
|
||||||
|
|
||||||
|
inbound_socket.on('close', onClose);
|
||||||
|
inbound_socket.on('data', onInboundData);
|
||||||
|
inbound_socket.on('error', onClose);
|
||||||
|
|
||||||
|
socks.connect({
|
||||||
|
host: info.dstAddr,
|
||||||
|
port: info.dstPort,
|
||||||
|
proxyHost: '127.0.0.1',
|
||||||
|
proxyPort: socks_port,
|
||||||
|
localDNS: false,
|
||||||
|
auths: [ socks.auth.None() ]
|
||||||
|
}, ($outbound_socket) => {
|
||||||
|
outbound_socket = $outbound_socket;
|
||||||
|
outbound_socket && outbound_socket.on('close', onClose);
|
||||||
|
|
||||||
|
inbound_socket && inbound_socket.removeListener('data', onInboundData);
|
||||||
|
inbound_socket && inbound_socket.on('data', (data) => {
|
||||||
|
outbound_socket && outbound_socket.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
outbound_socket && outbound_socket.on('data', (data) => {
|
||||||
|
inbound_socket && inbound_socket.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
outbound_socket && outbound_socket.on('error', onClose);
|
||||||
|
|
||||||
|
while (buffer && buffer.length && outbound_socket) {
|
||||||
|
outbound_socket.write(buffer.shift());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger = logger;
|
||||||
|
|
||||||
|
this.useAuth(socks.auth.None());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = SOCKSServer;
|
|
@ -26,7 +26,7 @@ const _ = require('lodash');
|
||||||
temp.track();
|
temp.track();
|
||||||
|
|
||||||
class TorPool extends EventEmitter {
|
class TorPool extends EventEmitter {
|
||||||
constructor(tor_path, config) {
|
constructor(tor_path, config, logger) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
config = config || {};
|
config = config || {};
|
||||||
|
@ -34,20 +34,21 @@ class TorPool extends EventEmitter {
|
||||||
this.tor_config = config;
|
this.tor_config = config;
|
||||||
this.tor_path = tor_path || 'tor';
|
this.tor_path = tor_path || 'tor';
|
||||||
this._instances = [];
|
this._instances = [];
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
get instances() { return this._instances.slice(0); }
|
get instances() { return this._instances.slice(0); }
|
||||||
|
|
||||||
create_instance(callback) {
|
create_instance(callback) {
|
||||||
let config = _.extend({}, this.tor_config)
|
let config = _.extend({}, this.tor_config)
|
||||||
let instance = new TorProcess(this.tor_path, config);
|
let instance = new TorProcess(this.tor_path, config, this.logger);
|
||||||
instance.create((error) => {
|
instance.create((error) => {
|
||||||
if (error) return callback(error);
|
if (error) return callback(error);
|
||||||
|
|
||||||
this._instances.push(instance);
|
this._instances.push(instance);
|
||||||
instance.once('error', callback)
|
instance.once('error', callback)
|
||||||
instance.once('ready', () => {
|
instance.once('ready', () => {
|
||||||
callback(null, instance);
|
callback && callback(null, instance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -57,11 +58,11 @@ class TorPool extends EventEmitter {
|
||||||
|
|
||||||
async.map(Array.from(Array(Number(instances))), (nothing, next) => {
|
async.map(Array.from(Array(Number(instances))), (nothing, next) => {
|
||||||
this.create_instance(next);
|
this.create_instance(next);
|
||||||
}, callback);
|
}, (callback || (() => {})));
|
||||||
}
|
}
|
||||||
|
|
||||||
next() {
|
next() {
|
||||||
this._instances.rotate();
|
this._instances = this._instances.rotate(1);
|
||||||
return this.instances[0];
|
return this.instances[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,11 @@ const EventEmitter = require('eventemitter2').EventEmitter2;
|
||||||
temp.track();
|
temp.track();
|
||||||
|
|
||||||
class TorProcess extends EventEmitter {
|
class TorProcess extends EventEmitter {
|
||||||
constructor(tor_path, config) {
|
constructor(tor_path, config, logger) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.tor_path = tor_path || 'tor';
|
this.tor_path = tor_path || 'tor';
|
||||||
|
this.logger = logger;
|
||||||
|
|
||||||
this.tor_config = _.extend({
|
this.tor_config = _.extend({
|
||||||
Log: 'notice stdout',
|
Log: 'notice stdout',
|
||||||
|
@ -78,15 +79,28 @@ class TorProcess extends EventEmitter {
|
||||||
this.emit('error', new Error(error_message));
|
this.emit('error', new Error(error_message));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.once('ready', () => {
|
||||||
|
this.logger && this.logger.info(`[tor-${tor.pid}]: tor is ready`);
|
||||||
|
});
|
||||||
|
|
||||||
tor.stdout.on('data', (data) => {
|
tor.stdout.on('data', (data) => {
|
||||||
let text = new Buffer(data).toString('utf8');
|
let text = new Buffer(data).toString('utf8');
|
||||||
|
let msg = text.split('] ').pop();
|
||||||
if (text.indexOf('Bootstrapped 100%: Done') !== -1){
|
if (text.indexOf('Bootstrapped 100%: Done') !== -1){
|
||||||
this.emit('ready');
|
this.emit('ready');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.indexOf('[err]') !== -1) {
|
if (text.indexOf('[err]') !== -1) {
|
||||||
this.emit('error', new Error(text.split('] ').pop()));
|
this.emit('error', new Error(msg));
|
||||||
|
this.logger && this.logger.error(`[tor-${tor.pid}]: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (text.indexOf('[notice]') !== -1) {
|
||||||
|
this.logger && this.logger.debug(`[tor-${tor.pid}]: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (text.indexOf('[warn]') !== -1) {
|
||||||
|
this.logger && this.logger.warn(`[tor-${tor.pid}]: ${msg}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
TorProcess: require('./TorProcess'),
|
TorProcess: require('./TorProcess'),
|
||||||
TorPool: require('./TorPool'),
|
TorPool: require('./TorPool'),
|
||||||
DNSServer: require('./DNSServer')
|
DNSServer: require('./DNSServer'),
|
||||||
|
SOCKSServer: require('./SOCKSServer')
|
||||||
};
|
};
|
134
test/test.js
134
test/test.js
|
@ -7,6 +7,24 @@ const TorRouter = require('../');
|
||||||
const getPort = require('get-port');
|
const getPort = require('get-port');
|
||||||
const dns = require('native-dns');
|
const dns = require('native-dns');
|
||||||
|
|
||||||
|
const get_ip = function (callback) {
|
||||||
|
request({
|
||||||
|
url: 'http://monip.org',
|
||||||
|
agentClass: SocksAgent,
|
||||||
|
agentOptions: {
|
||||||
|
socksHost: '127.0.0.1',
|
||||||
|
socksPort: this.socks_port
|
||||||
|
}
|
||||||
|
}, (error, res, body) => {
|
||||||
|
var ip;
|
||||||
|
if (body)
|
||||||
|
ip = body.split('IP : ').pop().split('<').shift();
|
||||||
|
|
||||||
|
callback(error || (!body && new Error("Couldn't grab IP")), ip)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
describe('TorProcess', function () {
|
describe('TorProcess', function () {
|
||||||
const TOR_DATA_DIR = temp.mkdirSync();
|
const TOR_DATA_DIR = temp.mkdirSync();
|
||||||
const TorProcess = TorRouter.TorProcess;
|
const TorProcess = TorRouter.TorProcess;
|
||||||
|
@ -35,22 +53,6 @@ describe('TorProcess', function () {
|
||||||
var old_ip = null;
|
var old_ip = null;
|
||||||
this.timeout(Infinity);
|
this.timeout(Infinity);
|
||||||
|
|
||||||
var get_ip = (callback) => {
|
|
||||||
request({
|
|
||||||
url: 'http://monip.org',
|
|
||||||
agentClass: SocksAgent,
|
|
||||||
agentOptions: {
|
|
||||||
socksHost: '127.0.0.1',
|
|
||||||
socksPort: tor.socks_port
|
|
||||||
}
|
|
||||||
}, (error, res, body) => {
|
|
||||||
var ip;
|
|
||||||
if (body)
|
|
||||||
ip = body.split('IP : ').pop().split('<').shift();
|
|
||||||
|
|
||||||
callback(error || (!body && new Error("Couldn't grab IP")), ip)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
before('create a tor instance', function (done) {
|
before('create a tor instance', function (done) {
|
||||||
tor.once('error', done);
|
tor.once('error', done);
|
||||||
|
@ -59,7 +61,7 @@ describe('TorProcess', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have an ip address', function (done) {
|
it('should have an ip address', function (done) {
|
||||||
get_ip((err, ip) => {
|
get_ip.call({ socks_port: tor.socks_port }, (err, ip) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
|
||||||
old_ip = ip;
|
old_ip = ip;
|
||||||
|
@ -70,7 +72,7 @@ describe('TorProcess', function () {
|
||||||
it('should have a new ip address after sending HUP', function (done) {
|
it('should have a new ip address after sending HUP', function (done) {
|
||||||
tor.new_ip();
|
tor.new_ip();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
get_ip((err, ip) => {
|
get_ip.call({ socks_port: tor.socks_port }, (err, ip) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
|
||||||
if (ip === old_ip)
|
if (ip === old_ip)
|
||||||
|
@ -108,38 +110,46 @@ describe('TorPool', function () {
|
||||||
describe('DNSServer', function () {
|
describe('DNSServer', function () {
|
||||||
var TorPool = TorRouter.TorPool;
|
var TorPool = TorRouter.TorPool;
|
||||||
var DNSServer = TorRouter.DNSServer;
|
var DNSServer = TorRouter.DNSServer;
|
||||||
|
var port;
|
||||||
var pool = new TorPool('tor');
|
var pool = new TorPool('tor');
|
||||||
var dns_server = new DNSServer(pool);
|
var dns_server = new DNSServer(pool);
|
||||||
describe('#on("request")', function () {
|
describe('#on("request")', function () {
|
||||||
this.timeout(Infinity);
|
this.timeout(Infinity);
|
||||||
|
|
||||||
it('should startup a tor pool with two instances', function (done) {
|
|
||||||
|
before((done) => {
|
||||||
|
getPort().then(($port) => {
|
||||||
|
port = $port;
|
||||||
|
dns_server.serve(port);
|
||||||
|
done()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should startup tor', (done) => {
|
||||||
|
|
||||||
pool.create(2, done);
|
pool.create(2, done);
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should be able to resolve "google.com" ', function (done) {
|
it('should be able to resolve "google.com" ', function (done) {
|
||||||
getPort().then((port) => {
|
|
||||||
dns_server.serve(port);
|
|
||||||
|
|
||||||
let req = dns.Request({
|
|
||||||
question: dns.Question({ name: 'google.com', type: 'A' }),
|
|
||||||
server: { address: '127.0.0.1', port: port, type: 'udp' },
|
|
||||||
timeout: 5000
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('timeout', () => {
|
let req = dns.Request({
|
||||||
done && done(new Error("Request timed out"));
|
question: dns.Question({ name: 'google.com', type: 'A' }),
|
||||||
done = null;
|
server: { address: '127.0.0.1', port: port, type: 'udp' },
|
||||||
});
|
timeout: 5000
|
||||||
|
|
||||||
req.on('message', (e, m) => {
|
|
||||||
done && done(((!m) || (!m.answer.length)) && new Error('Unable to resolve host'));
|
|
||||||
done = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
req.send();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
req.on('timeout', () => {
|
||||||
|
done && done(new Error("Request timed out"));
|
||||||
|
done = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('message', (e, m) => {
|
||||||
|
done && done(((!m) || (!m.answer.length)) && new Error('Unable to resolve host'));
|
||||||
|
done = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
req.send();
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function () {
|
after(function () {
|
||||||
|
@ -148,3 +158,49 @@ describe('DNSServer', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('SOCKSServer', function () {
|
||||||
|
var TorPool = TorRouter.TorPool;
|
||||||
|
var SOCKSServer = TorRouter.SOCKSServer;
|
||||||
|
|
||||||
|
var pool = new TorPool('tor');
|
||||||
|
var socks = new SOCKSServer(pool);
|
||||||
|
|
||||||
|
this.timeout(Infinity);
|
||||||
|
|
||||||
|
var port;
|
||||||
|
|
||||||
|
before((done) => {
|
||||||
|
getPort().then(($port) => {
|
||||||
|
port = $port;
|
||||||
|
socks.listen(port, (done));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#on("connection")', function () {
|
||||||
|
var ip;
|
||||||
|
|
||||||
|
it('should startup tor ', (done) => {
|
||||||
|
pool.create(2, done);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should get an ip address', function (done) {
|
||||||
|
get_ip.call({ socks_port: port }, (err, _ip) => {
|
||||||
|
ip = _ip;
|
||||||
|
done(err || (!ip && new Error('could not get an ip')))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a different ip', function (done) {
|
||||||
|
get_ip.call({ socks_port: port }, (err, _ip) => {
|
||||||
|
|
||||||
|
done(err || (!ip && new Error('could not get an ip')) || ((_ip === ip) && new Error('IP has not changed')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
pool.exit();
|
||||||
|
socks.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
9
x.js
Normal file
9
x.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
const S = require('./').SOCKSServer;
|
||||||
|
const P = require('./').TorPool;
|
||||||
|
|
||||||
|
let p = new P('tor', null, require('winston'));
|
||||||
|
let s = new S(p, require('winston'));
|
||||||
|
|
||||||
|
p.create(3, () => {
|
||||||
|
s.listen(9050);
|
||||||
|
});
|
|
@ -748,9 +748,9 @@ socks5-http-client@^1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
socks5-client "~1.1.0"
|
socks5-client "~1.1.0"
|
||||||
|
|
||||||
socksv5@^0.0.6:
|
"socksv5@git+https://github.com/lee-elenbaas/socksv5.git":
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/socksv5/-/socksv5-0.0.6.tgz#1327235ff7e8de21ac434a0a579dc69c3f071061"
|
resolved "git+https://github.com/lee-elenbaas/socksv5.git#7039cb6aeb39fa3187b327bb2de5d1aedaae6a56"
|
||||||
dependencies:
|
dependencies:
|
||||||
ipv6 "*"
|
ipv6 "*"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue