diff --git a/README.md b/README.md index 8fcf0478..288770e8 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,7 @@ The proxy-chain package is developed by [Apify](https://apify.com/), the full-st which provides an easy access to a large pool of datacenter and residential IP addresses all around the world. The proxy-chain package is also used by [Crawlee](https://crawlee.dev/), the world's most popular web craling library for Node.js. -Note that the proxy-chain package currently only supports HTTP forwarding and HTTP CONNECT tunneling to forward arbitrary protocols such as HTTPS or FTP ([learn more](https://blog.apify.com/tunneling-arbitrary-protocols-over-http-proxy-with-static-ip-address-b3a2222191ff)). The SOCKS protocol is not supported yet. -Also, proxy-chain only supports the Basic [Proxy-Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization). +The proxy-chain package currently supports HTTP/SOCKS forwarding and HTTP CONNECT tunneling to forward arbitrary protocols such as HTTPS or FTP ([learn more](https://blog.apify.com/tunneling-arbitrary-protocols-over-http-proxy-with-static-ip-address-b3a2222191ff)). The HTTP CONNECT tunneling also supports the SOCKS protocol. Also, proxy-chain only supports the Basic [Proxy-Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization). ## Run a simple HTTP/HTTPS proxy server diff --git a/package.json b/package.json index e7977d1d..8a9af319 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "proxy-chain", - "version": "2.5.0", + "version": "2.5.1", "description": "Node.js implementation of a proxy server (think Squid) with support for SSL, authentication, upstream proxy chaining, and protocol tunneling.", "main": "dist/index.js", "keywords": [ @@ -69,6 +69,7 @@ "rimraf": "^4.1.2", "sinon": "^13.0.2", "sinon-stub-promise": "^4.0.0", + "socksv5": "^0.0.6", "through": "^2.3.8", "ts-node": "^10.2.1", "typescript": "^4.4.3", diff --git a/test/socks.js b/test/socks.js new file mode 100644 index 00000000..e19aa23c --- /dev/null +++ b/test/socks.js @@ -0,0 +1,65 @@ +const portastic = require('portastic'); +const socksv5 = require('socksv5'); +const { gotScraping } = require('got-scraping'); +const { expect } = require('chai'); +const ProxyChain = require('../src/index'); + +describe('SOCKS protocol', () => { + it('works without auth', (done) => { + portastic.find({ min: 50000, max: 50250 }).then((ports) => { + const [socksPort, proxyPort] = ports; + const socksServer = socksv5.createServer((info, accept) => { + accept(); + }); + socksServer.listen(socksPort, 'localhost'); + socksServer.useAuth(socksv5.auth.None()); + + const proxyServer = new ProxyChain.Server({ + port: proxyPort, + prepareRequestFunction() { + return { + upstreamProxyUrl: `socks://localhost:${socksPort}`, + }; + }, + }); + proxyServer.listen(); + + gotScraping.get({ url: 'https://example.com', proxyUrl: `http://127.0.0.1:${proxyPort}` }) + .then((response) => { + expect(response.body).to.contain('Example Domain'); + done(); + }) + .catch(done); + }); + }).timeout(5 * 1000); + + it('work with auth', (done) => { + portastic.find({ min: 50250, max: 50500 }).then((ports) => { + const [socksPort, proxyPort] = ports; + const socksServer = socksv5.createServer((info, accept) => { + accept(); + }); + socksServer.listen(socksPort, 'localhost'); + socksServer.useAuth(socksv5.auth.UserPassword((user, password, cb) => { + cb(user === 'proxy-chain' && password === 'rules!'); + })); + + const proxyServer = new ProxyChain.Server({ + port: proxyPort, + prepareRequestFunction() { + return { + upstreamProxyUrl: `socks://proxy-chain:rules!@localhost:${socksPort}`, + }; + }, + }); + proxyServer.listen(); + + gotScraping.get({ url: 'https://example.com', proxyUrl: `http://127.0.0.1:${proxyPort}` }) + .then((response) => { + expect(response.body).to.contain('Example Domain'); + done(); + }) + .catch(done); + }); + }).timeout(5 * 1000); +});