123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- /**
- * Module dependencies.
- */
- var tls; // lazy-loaded...
- var url = require('url');
- var dns = require('dns');
- var extend = require('extend');
- var Agent = require('agent-base');
- var SocksClient = require('socks');
- var inherits = require('util').inherits;
- /**
- * Module exports.
- */
- module.exports = SocksProxyAgent;
- /**
- * The `SocksProxyAgent`.
- *
- * @api public
- */
- function SocksProxyAgent (opts) {
- if (!(this instanceof SocksProxyAgent)) return new SocksProxyAgent(opts);
- if ('string' == typeof opts) opts = url.parse(opts);
- if (!opts) throw new Error('a SOCKS proxy server `host` and `port` must be specified!');
- Agent.call(this, connect);
- var proxy = extend({}, opts);
- // prefer `hostname` over `host`, because of `url.parse()`
- proxy.host = proxy.hostname || proxy.host;
- // SOCKS doesn't *technically* have a default port, but this is
- // the same default that `curl(1)` uses
- proxy.port = +proxy.port || 1080;
- if (proxy.host && proxy.path) {
- // if both a `host` and `path` are specified then it's most likely the
- // result of a `url.parse()` call... we need to remove the `path` portion so
- // that `net.connect()` doesn't attempt to open that as a unix socket file.
- delete proxy.path;
- delete proxy.pathname;
- }
- // figure out if we want socks v4 or v5, based on the "protocol" used.
- // Defaults to 5.
- proxy.lookup = false;
- switch (proxy.protocol) {
- case 'socks4:':
- proxy.lookup = true;
- // pass through
- case 'socks4a:':
- proxy.version = 4;
- break;
- case 'socks5:':
- proxy.lookup = true;
- // pass through
- case 'socks:': // no version specified, default to 5h
- case 'socks5h:':
- proxy.version = 5;
- break;
- default:
- throw new TypeError('A "socks" protocol must be specified! Got: ' + proxy.protocol);
- }
- this.proxy = proxy;
- }
- inherits(SocksProxyAgent, Agent);
- /**
- * Initiates a SOCKS connection to the specified SOCKS proxy server,
- * which in turn connects to the specified remote host and port.
- *
- * @api public
- */
- function connect (req, opts, fn) {
- var proxy = this.proxy;
- // called once the SOCKS proxy has connected to the specified remote endpoint
- function onhostconnect (err, socket) {
- if (err) return fn(err);
- var s = socket;
- if (opts.secureEndpoint) {
- // since the proxy is connecting to an SSL server, we have
- // to upgrade this socket connection to an SSL connection
- if (!tls) tls = require('tls');
- opts.socket = socket;
- opts.servername = opts.host;
- opts.host = null;
- opts.hostname = null;
- opts.port = null;
- s = tls.connect(opts);
- socket.resume();
- }
- fn(null, s);
- }
- // called for the `dns.lookup()` callback
- function onlookup (err, ip, type) {
- if (err) return fn(err);
- options.target.host = ip;
- SocksClient.createConnection(options, onhostconnect);
- }
- var options = {
- proxy: {
- ipaddress: proxy.host,
- port: +proxy.port,
- type: proxy.version
- },
- target: {
- port: +opts.port
- },
- command: 'connect'
- };
- if (proxy.lookup) {
- // client-side DNS resolution for "4" and "5" socks proxy versions
- dns.lookup(opts.host, onlookup);
- } else {
- // proxy hostname DNS resolution for "4a" and "5h" socks proxy servers
- options.target.host = opts.host;
- SocksClient.createConnection(options, onhostconnect);
- }
- }
|