Measuring traffic with node.js http-proxy - javascript

I wrote a small reverse proxy for hosting my applications on the same computer using http and node-http-proxy modules. For example:
I have:
proxy running on port 80
website1.com running on port 3000
website2.com running on port 3001
website3.com running on port 3002
If I access the website1.com domain, the proxy will serve the contents from server running on port 3000 using node-http-proxy.
But now I need to measure the bandwidth used for each domain (both incoming/outgoing, or at least outgoing)
I've tried listening for 'data' events on request object, but in documentation they said that readable events isn't emitted on IncomignMessage for some reason.
I wrote a little module for the "base" functionality too, it can be found here:
https://npmjs.org/package/reproxy
See example/example.js
So, how can I accomplish this measure, using the current setup?

The solution I found was setting and 'end' event on RoutingProxy object and grabbing the socket information in the event callback.
var proxy = new require('http-proxy').RoutingProxy();
proxy.on('end', function(req, res, response) {
var host = req.headers.host;
var bytesIn = response.socket._bytesDispatched;
var bytesOut = response.socket.bytesRead;
console.log('request to ' + host);
console.log('request: ' + bytesIn + ' bytes.');
console.log('response: ' + bytesOut + ' bytes.');
});
Note that this is not optimal solution, because the request size includes the headers added by the reverse proxy, such as "x-" headers.

Related

Socket.IO Handshake Secure Flag Always False

I want my sockets to communicate securely. I think I'm requesting communication over https. So why is the secure flag always false? I've tried a bunch of different flag settings with no effect so far.
Sample site developed on glitch.com here: https://glitch.com/edit/#!/sponge-tablecloth.
Landing page is here: https://sponge-tablecloth.glitch.me/
Client page code:
<div id="div"></div>
<script src="/socket.io/socket.io.js"></script>
<script>
socket = io("https://sponge-tablecloth.glitch.me/");
socket.on('message', function(message) { div.innerHTML += message + "<br>"; });
</script>
Node.js server code:
var express = require('express');
var app = express();
let http = require('http').Server(app);
app.use(express.static('public'));
app.get("/", function (request, response) {
response.sendFile(__dirname + '/views/index.html');
});
let io = require('socket.io')(http);
io.on('connection', function(socket) {
console.log("checking connection, secure: " + socket.handshake.secure);
io.emit('message', "checking a connection, secure: " + socket.handshake.secure);
});
let listener = http.listen(process.env.PORT, function(){
console.log('Your app is listening on port ' + listener.address().port);
});
Problem is most likely that a reverse proxy is terminating TLS before proxying the requests to your application. It is common to have a setup that looks like this:
User -[HTTPS]-> Nginx(terminate TLS) -[HTTP]-> Application
This means that your application thinks that the transport was always insecure, while in fact it's just been terminated by the proxy (in this case Nginx). Glitch.io likely does this exact thing since your application is only offering insecure HTTP connections.
If you want end-to-end encryption you need to use the https package from stdlib instead of the http package, and setup certificates.

Send XMPP notification from Node.js script

How can a Node script send a notification via XMPP to a Jabber user (e.g. via Google Hangouts)? I've looked at libraries like xmpp/client but they seem overkill. Is there a simpler solution?
Simplest way to send a message via XMPP in Node
There is probably no other simpler XMPP client library for Node than node-simple-xmpp.
In this case the minimal Node.js script to send a message to another Jabber user is:
var xmpp = require('simple-xmpp');
var jid = 'testjs#xmpp.jp';
var pwd = 'xyz';
var server = 'xmpp.jp';
var port = 5222;
xmpp.on('online', function(data) {
console.log('Connected with JID: ' + data.jid.user);
xmpp.send('testjs#007jabber.com', 'hello! time is '+new Date(), false);
});
xmpp.on('error', function(err) {
console.error("error:", JSON.stringify(err));
});
xmpp.connect({
jid: jid,
password: pwd,
host: server,
port: port
});
If the two account have never spoken together, a preliminary 'subscribe' is also required:
xmpp.subscribe('testjs#007jabber.com');
As you can see in package.json node-simple-xmpp lib has a dependency on [node-xmpp-client] (https://github.com/xmppjs/xmpp.js/tree/node-xmpp/packages/node-xmpp-client).
Usage with Google Talk/Hangouts
The script above is working (tested) also with Google Talk/Hangouts, you just have to replace xmpp.jpserver with talk.google.com and use a Google account. Turn on https://myaccount.google.com/lesssecureapps to enable Node.js script to sign in with Google account.
Other XMPP libraries
As of https://npms.io/search?q=node-xmpp there are a few other XMPP Client libraries for Node, however almost all of them are dependent on node-xmpp-client or limited to BOSH connection (polling over HTTP).
One interesting lib for those used to Strophe.js on client side seems node-strophe. It is based on Strophe.js release 1.0.2 which is a library for applications that run in any browser. Unfortunately that version didn't support other than BOSH (see Strophe.js changelog), websocket is available only since release 1.1.0.
Exploring alternatives without specific XMPP libraries
An alternative solution without specific XMPP libraries could be using Net module, but in this case you need to manage all XMPP interactions to establish the connection to the server, see https://wiki.xmpp.org/web/Programming_XMPP_Clients .
Below is a very raw example of script trying to initiate the connection with a Jabber server using Net module:
var net = require('net');
var jid = 'testjs#xmpp.jp';
var pwd = 'xyz';
var server = 'xmpp.jp';
var port = 5222;
var msg = '<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0" to="'+server+'">';
var client = new net.Socket();
client.connect(port, server, function() {
console.log('Connected');
client.write(msg);
});
client.on('data', function(data) {
console.log('Received: ' + data);
});
You can see in the console log the correct answer of Jabber server, however from then on it's a mess: you should begin exchanging TLS messages (see https://xmpp.org/rfcs/rfc3920.html#tls)
Conclusions
I think the only feasible alternative is the first one using node-simple-xmpp library.

Customize cors-anywhere

I have deployed (hosted) cors-anywhere in Heroku, but i don't know how to customize it.
For example, I want to add a site link in whitelist.
I get data from this link: http://fmon.asti.dost.gov.ph/dataloc.php?param=rv&dfrm=null&dto=null&numloc=1&data24=1&locs[]=711
How will I do it? I have tried touching the server.js file:
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || '0.0.0.0';
// Listen on a specific port via the PORT environment variable
//var port = process.env.PORT || 443;
var port = process.env.PORT || 8080;
// Grab the blacklist from the command-line so that we can update the blacklist without deploying
// again. CORS Anywhere is open by design, and this blacklist is not used, except for countering
// immediate abuse (e.g. denial of service). If you want to block all origins except for some,
// use originWhitelist instead.
var originBlacklist = parseEnvList(process.env.CORSANYWHERE_BLACKLIST);
//var originWhitelist = ['http://fmon.asti.dost.gov.ph/dataloc.php','https://fmon.asti.dost.gov.ph/dataloc.php','http://fmon.asti.dost.gov.ph','https://fmon.asti.dost.gov.ph'];
var originWhitelist = parseEnvList(process.env.CORSANYWHERE_WHITELIST);
function parseEnvList(env) {
if (!env) {
return [];
}
return env.split(',');
}
// Set up rate-limiting to avoid abuse of the public CORS Anywhere server.
var checkRateLimit = require('./lib/rate-limit')(process.env.CORSANYWHERE_RATELIMIT);
var cors_proxy = require('./lib/cors-anywhere');
cors_proxy.createServer({
originBlacklist: originBlacklist,
originWhitelist: originWhitelist,
requireHeader: ['origin', 'x-requested-with'],
checkRateLimit: checkRateLimit,
removeHeaders: [
'cookie',
'cookie2',
// Strip Heroku-specific headers
'x-heroku-queue-wait-time',
'x-heroku-queue-depth',
'x-heroku-dynos-in-use',
'x-request-start',
],
redirectSameOrigin: true,
httpProxyOptions: {
// Do not add X-Forwarded-For, etc. headers, because Heroku already adds it.
xfwd: false,
},
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
but when I access the data and look at the console log, it returns a 403 error which is forbidden.
NOTE: When you say self hosted CORS it will only work for your site to
proxy. CORS setting on your server is for you not for the list of
sites you mentioned. They will be having their own CORS filters setup.
403 actually refers to the forbidden resource rather than a CORS Issue. Cors issue will look something like as follows:-
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'yourUrl' is therefore not allowed access. The response had HTTP status code 400
For cors-anywhere the whitelisting code is pretty simple as mentioned below:-
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || '0.0.0.0';
// Listen on a specific port via the PORT environment variable
var port = process.env.PORT || 8080;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
originWhitelist: ['http://fmon.asti.dost.gov.ph'], // Allow all origins
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
This should Ideally work for you with your application calling this somewhere.
If you are getting 403 while accessing this URL from your application
then be sure the URL you mentioned is protected and you must get
proper authentication done before requesting it.
I spent 3 days looking for the cause, got a 403 error for some sites and realized that the problem may be that they can not accept requests from "origin" different from theirs.
I just tried removing those headers on the proxy server and everything worked!
removeHeaders: ['origin', 'referer']

Node HTTP resolution

So you can make a node HTTP GET request like so:
var http = require('http');
var options = {
host: 'stackoverflow.com',
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
I want to see what IP address that http.get is going to? How does the node HTTP lib determine which IP address to use if a given DNS resolves to multiple IPs?
By multiple IPs i mean something like:
dig +short stackoverflow.com
151.101.129.69
151.101.1.69
151.101.193.69
151.101.65.6
Does the node request lib differ?
Your req object should have a connection object on it, which will have the remote address of the server you were connected to.
req.connection.remoteAddress
Of course, you need to wait until you actually have a connection, so I would just use the connect event which has what you need. Untested, but try this:
req.on('connect', (res, socket, head) => {
console.log(socket.remoteAddress);
});
https://nodejs.org/api/net.html#net_socket_remoteaddress
In node 6.x.x as far as I understand it comes down too:
http module uses
net module uses
dns module uses
native module libuv#getaddrinfo (http://docs.libuv.org/en/v1.x/dns.html#c.uv_getaddrinfo)
And specifically your questions which IP to use:
https://github.com/nodejs/node/blob/cd439465cc8b408eb88822c7695def611acfaaf7/lib/dns.js#L82
Very straightforward algorithm which goes like: "If multiple IP addresses are present take first one" :)

Using an IP address parameter in the creation of a Socket.io socket

In the following snippet, a tutorial author shows how to alter the original tutorial to include an http server. Here's the snippet.
var http = require(‘http’),
fs = require(‘fs’),
io = require(‘socket.io’),
index;
fs.readFile(‘./chat.html’, function (err, data) {
if (err) {
throw err;
}
index = data;
});
var server = http.createServer(function(request, response) {
response.writeHeader(200, {“Content-Type”: “text/html”});
response.write(index);
response.end();
}).listen(1223);
//and replace var socket = io.listen(1223, "1.2.3.4"); with:
var socket = io.listen(server);
The code in the original tutorial didn't include the http server, and socket was defined as simply:
var socket = io.listen(1223, "1.2.3.4");
I noticed that he replaces the variable's content io.listen(1223, "1.2.3.4"); with server which doesn't include the ip (1.2.3.4) anywhere.
My Question:
What is the purpose/effect of the referenced IP address?
Why is it excluded when passing an http server to create the socket?
When you are listening on a port, you can optionally include the IP address of a specific interface to listen on. For example, you might have several network interfaces with several IP addresses, and only want your service running on one of them. A more common use case is that you only want your server accessible on localhost, so you might have it listen only on 127.0.0.1.
Now, when you call io.listen(server) where server is an existing Node.js HTTP server, Socket.IO isn't actually opening a new listening connection at all. This is a shortcut for Socket.IO to wrap its methods on the existing HTTP server. If you wanted to specify a specific interface address to listen on, you would need to do it where .listen() is called on the HTTP server, above where you call io.listen(server).
More info in the documentation for raw network sockets in Node.js: http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback

Categories