transparent-proxy extends the native net.createServer and it acts as a real transparent http-proxy.
This module was built on top of TCP-level to avoid header-stripping problem of nodejs http(s)-modules.
It allows to upstream client-request dynamically to other proxies, or to certain iFace, to spoof requests and more...
It supports Basic Proxy-Authentication.
Useful for debugging, crawling, security and more.
It works on Termux.
npm i transparent-proxy
const ProxyServer = require('transparent-proxy');
//init ProxyServer
const server = new ProxyServer();
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('TCP-Proxy-Server started!', server.address());
});
Param | Type | Description |
---|---|---|
options | Object |
The options object. |
[options.auth] | Function |
Activate/Handle Proxy-Authentication. Returns or solves to Boolean. |
[options.upstream] | Function |
The proxy to be used to upstreaming requests. Returns String. |
[options.tcpOutgoingAddress] | Function |
The localAddress to use while sending requests. Returns String |
[options.injectData] | Function |
The edited data to upstream. Returns Buffer or string |
[options.injectResponse] | Function |
The edited response to return to connected client. Returns Buffer or string |
[options.keys] | Function |
The keys to use while handshake. It will work only if intercept is true. Returns Object or false |
[options.verbose] | Boolean |
Activate verbose mode. |
[options.intercept] | Boolean |
Activate interception of encrypted communications. False as default. |
[options.logger] | Logger |
Must be an object implementing log(args[]) and error(args[]) . Defaults to the inbuilt logger writing to the console if verbose is true. |
[options.handleSni] | Function |
Pass SNICallback to be added to the server. See SNICallback tls.createServer options |
The options are functions having follow parameters:
Param | Type | Description |
---|---|---|
data | Buffer |
The received data. |
session | Session |
Object containing info/data about Tunnel |
- upstream-Function need to return/resolve a String with format ->
IP:PORT
orUSER:PWD@IP:PORT
of used http-proxy. If 'localhost' is returned/resolved, then the host-self will be used as proxy. - tcpOutgoingAddress-Function need to return a String with format ->
IP
.
Note: These functions will be executed before first tcp-socket-connection is established.
- injectData-Function need to return a String or buffer for the new spoofed data. This will be upstreamed as request.
- injectResponse-Function need to return a String or buffer for the new received data.
If you don't want to use the host of active instance self, then you need to upstream connections to another http-proxy.
This can be done with upstream
attribute.
const ProxyServer = require('transparent-proxy');
const server = new ProxyServer({
upstream: function () {
return 'x.x.x.x:3128'; // upstream to other proxy
}
});
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('TCP-Proxy-Server started!', server.address());
});
You can also use an async function to upstream your requests:
const ProxyServer = require('transparent-proxy');
const server = new ProxyServer({
upstream: async function () {
//make some async task before
return 'x.x.x.x:3128'; // upstream to other proxy
}
});
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('TCP-Proxy-Server started!', server.address());
});
This activate basic authorization mechanism. The Auth-function will be executed while handling Proxy-Authentications.
Param | Type | Description |
---|---|---|
username | String |
The client username. |
password | String |
The client password |
session | Session |
Object containing info/data about Tunnel |
Note: It needs to return True/False or a Promise that resolves to boolean (isAuthenticated).
const ProxyServer = require('transparent-proxy');
const server = new ProxyServer({
auth: function (username, password) {
return username === 'bar' && password === 'foo';
}
});
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('TCP-Proxy-Server started!', server.address());
});
The callbacks injectData
& injectResponse
could be used to intercept/spoof communication.
These functions are executed with the data
and session
arguments.
The boolean attribute intercept
allows to break SSL-Communication between Source & Destination.
This will activate Security-Alarm by most used browsers.
const switchWith = 'My Super Spoofed UA!';
const server = new ProxyServer({
intercept: true,
verbose: true,
injectData: (data, session) => {
if (session.isHttps) {
const modifiedData = data.toString()
.replace(session.request.headers['user-agent'], switchWith); //replacing UA-Header-Value
return Buffer.from(modifiedData);
}
return data;
}
});
curl -x localhost:8080 -k http://ifconfig.io/ua
curl/7.83.1
curl -x localhost:8080 -k https://ifconfig.me/ua
My Super Spoofed UA!
This function will work only if intercept
is set to true
.
If activated needs to return an Object {key:'String', cert:'String'}
like native tls_connect_options.key & tls_connect_options.cert or false
statement.
If no object is returned, then default keys will be used to update communication.
Param | Type | Description |
---|---|---|
session | Session |
Object containing info/data about Tunnel |
Note: This function will be executed before TLS-Handshake.
If passed a function, the proxy will call it to obtain the TLS secure context instead of using keys
.
From tls.createServer two arguments will be passed when called: servername and callback. Callback is an error-first callback that takes two optional arguments: error and ctx. ctx, if provided, is a SecureContext instance.
tls.createSecureContext() can be used to get a proper SecureContext. If callback is called with a falsy ctx argument, the default secure context of the server will be used.
You can find an example here.
The Session-Instance is an Object containing info/data about Tunnel. It has following useful attributes and methods:
-
{boolean} isHttps - Is session encrypted.
-
{object} request - The Request-Object containing info about current request. Normally defined on both
injectData
&injectResponse
Callbacks. Attributes exist only if Session is not encrypted.- {object} [request.headers] - The intercepted request headers.
- {string|undefined} [request.body] - The intercepted request body.
-
{object} response - The Response-Object containing info about current response. Normally defined on
injectResponse
Callback. Attributes exist only if Session is not encrypted.- {object} [response.headers] - The intercepted response headers.
- {string} [response.body] - The intercepted response body.
- {boolean} [response.complete] - is response completely done.
-
{buffer} rawResponse - The original body buffer.
-
{object} getTunnelStats() - Get Stats for this tunnel
-
{string} getId() - Get Own ID-Session
-
{boolean} isAuthenticated() - Is the session authenticated by user or not.
const ProxyServer = require('transparent-proxy');
const server = new ProxyServer();
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('Proxy-Server started!', server.address());
});
setInterval(function showOpenSockets() {
const bridgedConnections = server.getBridgedConnections();
console.log([new Date()], 'OPEN =>', Object.keys(bridgedConnections).length)
}, 2000);
This example upstreams only requests for ifconfig.me to another proxy, for all other requests will be used localhost.
const ProxyServer = require('transparent-proxy');
const server = new ProxyServer({
upstream: function (data, session) {
if (~(data.toString().indexOf('ifconfig.me'))) {
return 'x.x.x.x:3128'; // upstream to other proxy
} else {
return 'localhost'; //upstream to localhost
}
},
});
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('TCP-Proxy-Server started!', server.address());
});
Testing with curl
:
curl -x 127.0.0.1:8080 https://ifconfig.me
x.x.x.x
curl -x 127.0.0.1:8080 https://ifconfig.co
y.y.y.y
For more examples look here.