multiple http connections to test NAT - node.js

I'am in a project where i need to establish the most possible http connections and keep them open for nat port testing, using node.js but I'm not sure how I could do it, till now i got this:
var http = require('http');
var http_options = {
hostname: '193.136.212.161',
port: 80,
path: '/',
method: 'GET',
agent: false,
headers: {
'Connection':'keep-alive'
}
};
var req = http.request(http_options)
.on("socket", function (socket) {
console.log('got connected!');
});
req.end();
unfortunely it closes the connection not keeping it alive, if i could have some tips to advance would be great.

Related

how can a path and a host be completely different in nodejs

I'm doing research in proxies in nodejs. I came across something that blew my mind. In one of the options for a http.request connection, the source code showed this as the options object
const options = {
port: 1337,
host: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
This was a part of a far bigger code which was the whole tunneling system. But can someone just explain how the options above work? The whole code is below
const http = require('http');
const net = require('net');
const { URL } = require('url');
// Create an HTTP tunneling proxy
const proxy = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {
// Make a request to a tunneling proxy
const options = {
port: 1337,
host: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
const req = http.request(options);
req.end();
req.on('connect', (res, socket, head) => {
console.log('got connected!');
// Make a request over an HTTP tunnel
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
proxy.close();
});
});
});
Source: https://nodejs.org/api/http.html#http_event_connect
You probably have never used a network that requires you to configure a HTTP proxy. Most networks these days configure their firewall to allow HTTP traffic. This means most people these days have never needed to use a HTTP proxy to access the web.
A long-long time ago when I first started using the internet (around 1994) a lot of networks don't allow transparent internet access. Your PC does not have any connection to the outside world. But sysadmins would install a HTTP proxy that you can connect to. Your PC would only have access to the LAN (which the proxy is a part of) and only the HTTP proxy would have access to the internet.
Here's an example of how you'd configure Windows to use a HTTP proxy:
If you configure your PC as above, then when you connect to www.google.com your browser would connect to the host proxy.example.com on port 8080 and then request it to fetch data from www.google.com.
As for why it calls the requested resource path it's because it is sent in the "path" part of the packet.
For example, a normal GET request for getting this page looks something like this:
GET /questions/60498963 HTTP/1.1
Host: stackoverflow.com
And the string after GET and before protocol version is normally called the path:
.---------- this is normally called
| the "path"
v
GET /questions/60498963 HTTP/1.1
Host: stackoverflow.com
When making a proxy request the HTTP header looks like this:
CONNECT stackoverflow.com/questions/60498963 HTTP/1.1
So the url including the domain name is sent to the proxy in the part of the packet usually used to send file path.
Note that all this has nothing to do with Node.js. This is just basic networking (no programming languages involved).

Redirect http to https in Hapi.js

I do have the following configuration for my hapi server
const server = new Hapi.Server();
const tls = {
cert: fs.readFileSync(path.join(__dirname, '../certificates/cert.crt')),
key: fs.readFileSync(path.join(__dirname, '../certificates/cert.key')),
};
server.connection({
port: process.env.PORT_HTTP || 80,
host: process.env.HOST || 'localhost',
});
server.connection({
port: process.env.PORT_HTTPS || 443,
host: process.env.HOST || 'localhost',
tls,
});
The server is working ok on both, http and https, but I would like to redirect all the traffic from the http to https.
How should I proceed, tried already to register the hapi-require-https npm module but the traffic still remain the same, nothing happens.
Create an extra server for http requests and bind them to redirect function.
var Hapi = require('hapi');
var http = new Hapi.Server(80);
var server = new Hapi.Server(443, { tls: {} });
var redirect = function () {
this.reply.redirect('https://your.site/' + this.params.path);
});
http.route({ method: '*', path: '/{path*}', handler: redirect });
Update(other option)
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
if(request.headers.referer.split(':')[0] == "http"){
this.reply.redirect('https://your.site' + this.params.path);
}
}
});
How about this? Binding them both
var http = new Hapi.Server(80); // our extra server
http.route({
method: '*',
path: '/{path*}',
handler:
function (request, reply) {
// if(request.headers.referer.split(':')[0] == "http"){
this.reply.redirect('https://your.site' + this.params.path);
// }
}
});
Create two server instances to handle http & https traffic seperately.
var Hapi = require('hapi');
var server = new Hapi.Server(80);
var httpsServer = new Hapi.Server(443, { tls: { // your certificates here} });
Now register the hapi-gate plugin to the base server so that it redirects the traffic to https.
server.register({
register: require('hapi-gate'),
options: {https: true} // will force https on all requests
});
You can also use the hapi-require-https plugin instead.

How can I use an https proxy with node.js https/request Client?

I need to send my client HTTPS requests through an intranet proxy to a server.
I use both https and request+global-tunnel and neither solutions seem to work.
The similar code with 'http' works. Is there other settings I missed?
The code failed with an error:
REQUEST:
problem with request: tunneling socket could not be established, cause=socket hang up
HTTPS:
events.js:72
throw er; // Unhandled 'error' event
^
Error: socket hang up
at SecurePair.error (tls.js:1011:23)
at EncryptedStream.CryptoStream._done (tls.js:703:22)
at CleartextStream.read [as _read] (tls.js:499:24)
The code is the simple https test.
var http = require("https");
var options = {
host: "proxy.myplace.com",
port: 912,
path: "https://www.google.com",
headers: {
Host: "www.google.com"
}
};
http.get(options, function(res) {
console.log(res);
res.pipe(process.stdout);
});
You probably want to establish a TLS encrypted connection between your node app and target destination through a proxy.
In order to do this you need to send a CONNECT request with the target destination host name and port. The proxy will create a TCP connection to the target host and then simply forwards packs between you and the target destination.
I highly recommend using the request client. This package simplifies the process and handling of making HTTP/S requests.
Example code using request client:
var request = require('request');
request({
url: 'https://www.google.com',
proxy: 'http://97.77.104.22:3128'
}, function (error, response, body) {
if (error) {
console.log(error);
} else {
console.log(response);
}
});
Example code using no external dependencies:
var http = require('http'),
tls = require('tls');
var req = http.request({
host: '97.77.104.22',
port: 3128,
method: 'CONNECT',
path: 'twitter.com:443'
});
req.on('connect', function (res, socket, head) {
var tlsConnection = tls.connect({
host: 'twitter.com',
socket: socket
}, function () {
tlsConnection.write('GET / HTTP/1.1\r\nHost: twitter.com\r\n\r\n');
});
tlsConnection.on('data', function (data) {
console.log(data.toString());
});
});
req.end();

How to connect to Node socket.io-server from Node socket.io-client **with HTTPS**

I've setup a socket server, like so:
/* node-server.js */
var port = 3333;
var fs = require('fs');
var options = {
key: fs.readFileSync('ssl/server.key'),
cert: fs.readFileSync('ssl/server.crt')
};
var server = require('https').Server(options);
var io = require('socket.io')(server);
console.log('Socket server listening on port ' + port + '.');
server.listen(port);
io.sockets.on('connection', function(socket) {
console.log("Client " + socket.id + " connected.");
});
And a Node client that connects to it:
/* node-client.js */
var url = 'https://localhost:3333';
console.log('Connecting to ' + url);
var io = require('socket.io-client');
var socket = io.connect(url, { reconnection: false });
socket.on('connect_error', function(error){ console.log('Error connecting to ' + url, error);});
socket.on('connect', function() {
console.log('Connected to ' + url);
});
However, when trying to connect I get an error { [Error: xhr poll error] description: 503 }.
This error goes away, and everything just works if I remove the "HTTPS" component. Here's a diff showing exactly what I mean.
However, I'm not convinced that HTTPS is the problem, because here is another client (this one in a browser instead of Node) which can connect just fine:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript"
src="https://localhost:3333/socket.io/socket.io.js"></script>
</head>
<body onload="io.connect('https://localhost:3333');">
</body>
</html>
How can I get a Node socket.io-client to connect to a Node socket.io-server over HTTPS?
On Node.js, TLS and HTTPS will validate certificates before accepting them. Therefore, to use self-signed certificates with Node, you will need to set the rejectUnauthorized option when performing requests to false, or use:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
The solution was to add this line to the client:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
I found that if I manually made HTTPS requests to the socket server:
var https = require('https');
var options = { host: 'localhost',
port: '3333',
path: '/socket.io/?EIO=3&transport=polling&t=1404103832354-0&b64=1',
method: 'GET',
headers:
{ 'User-Agent': 'node-XMLHttpRequest',
Accept: '*/*',
Host: 'localhost:3333' },
agent: false
};
https.globalAgent.options.rejectUnauthorized = false;
https.request(options, function() {
console.log(arguments);
throw 'done';
});
...then requests would fail with the error: DEPTH_ZERO_SELF_SIGNED_CERT
Socket.io, it would seem, was unable to make requests for this reason.
After Googling the error, I found this page.
On that page someone suggested the solution above, which works.
Essentially, I believe it's allowing self-signed certs which may be "insecure".

Proxying WebSockets through node-http-proxy doesn't work

These are the versions of node and required modules I am using:
Node.js: 0.10.16
Websocket Library: einaros/ws ws#0.4.28
Proxy server: nodejitsu/node-http-proxy http-proxy#0.10.3
When I run the following program my console output looks like this, and doesn't move beyond this point:
$ node app.js
proxy: got upgrade, proxying web request
wss: got connection
Here's the code:
// app.js
// A simple proxying example
//
// Setup websocket server on port 19000
// Setup proxy on port 9000 to proxy to 19000
// Make a websocket request to 9000
//
var WebSocket = require('ws'),
WebSocketServer = WebSocket.Server,
proxy = require('http-proxy');
// goes in a loop sending messages to the server as soon as
// the servers are setup
var triggerClient = function() {
var ws = new WebSocket('ws://localhost:9090/');
ws.on('open', function() {
console.log('ws: connection open');
setInterval(function() {
ws.send("Hello");
}, 1000);
});
ws.on('message', function(data) {
console.log('ws: got ' + data);
});
}
// setup websocket server and a proxy
//
var go = function() {
// setup a websocket server on port 19000
//
var wss = new WebSocketServer({ port: 19000 });
wss.on('connection', function(ws) {
console.log('wss: got connection');
ws.on('message', function(data) {
console.log('wss: got ' + data);
ws.send('wss response: ' + data);
});
});
// setup a proxy server
var server = proxy.createServer(function (req, res, proxy) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 19000
});
});
server.on('upgrade', function (req, socket, head) {
console.log('proxy: got upgrade, proxying web request');
server.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 19000
});
});
server.listen(9090, triggerClient);
};
process.nextTick(go);
My problem eventually started when I was trying to use hipache, I then simplified things to node-http-proxy and then finally to this piece of code.
If you change the port the WebSocket client is connecting to from 9090 to 19000 (thereby bypassing the proxy), things seem to work fine.
Any suggestions, pointers, feedback would be greatly appreciated.
Thanks!
The core problem is that the master branch of node-http-proxy is only compatible with node <= 0.8.x (see https://github.com/nodejitsu/node-http-proxy#when-to-use-node-http-proxy): there's a tree that implements support for 0.10.x (see https://github.com/nodejitsu/node-http-proxy/tree/caronte) but it isn't the mainline branch and I haven't found any indication of when it will be merged in and available.

Resources