node.js and IPv6

Sat, 13 Aug 2011 09:46:35 +0000
node.js ipv6 tech

tl;dr

OK, my last few posts on node.js may have seemed a little negative. While there are some things in node.js that seem a little more complicated than necessary, there are some things that are nice and simple, such as getting your server to run on both IPv4 and IPv6. This post is a little late for World IPv6 Day, but better late than never!

So this post isn’t about configuring IPv6 on your machine in general. I’m going to assume that your local network interface has an IPv6 address. You can probably check this with the output of ifconfig. On my Darwin box it looks something like:

benno@ff:~% ifconfig lo0
lo0: flags=8049 mtu 16384
	inet6 ::1 prefixlen 128 
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
	inet 127.0.0.1 netmask 0xff000000 

You should see the local interface bound to the IPv6 localhost address ::1 as well the IPv4 localhost address 127.0.0.1. So lets get started with a simple little IPv4 server.

var http = require('http')
var server

function onRequest(req, res) {
    console.log(req.method, req.url)
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end('Hello World\n')
}

function onListening() {
    console.log('Listening at http://' + this.address().address + ':' + this.address().port + '/')
}

server = http.createServer()
server.on('request', onRequest)
server.on('listening', onListening)
server.listen(1337, '127.0.0.1')

This is a slight variation on the canonical node.js Hello World example. A few things worth noting:

So, apart from my stylistic quirks, the above should be fairly straight forward. The only new thing functionality wise compared to the normal node.js example is the addition of some trivial logging in the request handler.

So our quest is going to be to add support for IPv6. Before we do that though, I’m going to improve our logging a bit. Just because we are supporting IPv6, doesn’t mean we want to stop our server running on IPv4, so we are going to end up with multiple servers running at once. Once this happens, our logging might get a bit confusing. So we’re going to give our servers a name, and include that in the logging.

var http = require('http')
var server

function onRequest(req, res) {
    console.log('[' + this.name + ']', req.method, req.url)
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end('Hello World\n')
}

function onListening() {
    console.log('[' + this.name + '] Listening at http://' + this.address().address + ':' + this.address().port + '/')
}

server = http.createServer()
server.name = 'ipv4server'
server.on('request', onRequest)
server.on('listening', onListening)
server.listen(1337, '127.0.0.1')

Because Javascript objects are open we can trivially add a name field to our objects, and then use this when logging. In general I avoid messing with objects created by other modules, but it is the quick and easy approach in this case.

OK, so on to IPv6. As a first stab at it, we get something like this:

var http = require('http')
var server

function onRequest(req, res) {
    console.log('[' + this.name + ']', req.method, req.url)
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end('Hello World\n')
}

function onListening() {
    console.log('[' + this.name + '] Listening at http://' + this.address().address + ':' + this.address().port + '/')
}

ipv4server = http.createServer()
ipv6server = http.createServer()

ipv4server.name = 'ipv4server'
ipv6server.name = 'ipv6server'

ipv4server.on('request', onRequest)
ipv6server.on('request', onRequest)

ipv4server.on('listening', onListening)
ipv6server.on('listening', onListening)

ipv4server.listen(1337, '127.0.0.1')
ipv6server.listen(1337, '::1')

Basically, creating an IPv6 server is exactly the same as creating an IPv4 server, except you use an IPv6 address literal (i.e: ::1) to specify the local address to bind to, rather than an IPv4 address literal. You can see that there is absolutely no problem sharing the event handlers between the two different servers. The this variable in each event handler function refers to the server itself, so you can handle cases that are server specific if necessary.

When you run this you should get some output like:

[ipv4server] Listening at http://127.0.0.1:1337/
[ipv6server] Listening at http://::1:1337/

Which looks pretty good. You can try going to the IPv4 server URL in your browser. If you try the IPv6 URL, you will probably run in to some problems. This is because you need some escaping of the IPv6 literal address in the URL, or it can’t be parsed correctly (what with there being all those colons which are usually used for separating the port number). So the correct URL should be: http://[::1]:1337/. We better fix this bug in the code:

function onListening() {
    var hostname = this.type === 'tcp4' ? this.address().address : '[' + this.address().address + ']'

    console.log('[' + this.name + '] Listening at http://' + hostname + ':' + this.address().port + '/')
}

OK, that’s looking pretty good now, if you start hitting those URLs on the different address you should get some useful output such as:

[ipv4server] Listening at http://127.0.0.1:1337/
[ipv6server] Listening at http://[::1]:1337/
[ipv4server] GET /
[ipv4server] GET /favicon.ico
[ipv6server] GET /
[ipv6server] GET /favicon.ico

Now, I mentioned earlier I don’t like duplicating data. I also don’t like duplicating code either, so let’s refactor this a little:

function startServer(name, address, port) {
    var server = http.createServer()
    server.name = name
    server.on('request', onRequest)
    server.on('listening', onListening)
    server.listen(port, address)
    return server
}

startServer('ipv4server', '127.0.0.1', 1337)
startServer('ipv6server', '::1', 1337)

So, in conclusion it is easy-peasy to run your web application on IPv6, and even on IPv4 and IPv6 using the exact same script.

Safely dropping privileges in node.js

Tue, 09 Aug 2011 15:12:25 +0000
node.js setuid security

tl;dr

So, you want to run some kind of TCP server, and you’d like to run it on one of those fancy ports with a number less-than 1024. Well, unfortunately you got to be root to bind to a low-numbered port. Of course, we don’t want to run our network server as root, because that would be, well, really silly, wouldn’t it! Luckily, POSIX gives us a simple way of breaking this little problem. You start your program running with root privileges, grab all the resources you need, and then drop back to running as an unprivileged user using the setuid syscall.

Now, if you are writing a network server you probably know the drill, you create a socket(), then you bind(), and then you starts to listen() for connections, occasionally calling accept() when you decide you want to actually do something with an incoming request. So, the question is, at which point do you drop the privileges? Well, the important part is that you need privileges to bind(), but once you have bound to an address and port, you no longer need root privileges. So ideally, you call setuid() after you bind(). You want to get this right. Drop privileges too early and you can’t correctly bind to the address, drop too late and you unnecessarily expose yourself to potential exploits.

Now, if you are doing something in normal synchronous programming you would do something like:

fd = socket(...)
bind(fd, ...)
setuid(...)
listen(fd, ...)

But good luck on things being so simple in node.js. In my last post I described these semi-asynchronous functions, which you probably thought was just a bit of an academic exercise. Well, it turns out that, depending on the arguments, the listen method behaves in this semi-asynchronous manner.

Specifically, when the listen function returns, the bind() operation has completed, but the listen() operation hasn’t. Which means that calling process.setuid() immediately after server.listen() will end up dropping privileges at the ideal time.

This technique is explained in this excellent post on the subject. However, I’m not 100% satisfied with this solution. My unease with this approach comes down to the fact that there is no documented guarantee that the bind() must have occurred when the function returns, it could change in the next version. In fact, depending on the arguments passed to listen, it may not happen that way. If instead of using an IP address to specify the local address to bind to, you use a domain name, then an asynchronous DNS lookup occurs before the call to bind(), which means that when server.listen() returns the bind call has not yet happened, if you drop the privileges at this point then you will hit an exception later when the bind() happens. Of course, specifying the local address to which your server binds using a DNS name is a little bits silly in the first place, but that is another matter.

So, if we can’t rely on the bind() having occurred when server.listen() returns then the only other option is to call setuid in the listen callback function. This is probably a reasonable approach, but it does mean that we hold privileges longer than strictly necessary. In this case, there probably isn’t really very much that happens between the bind() call and when the listen event triggers, so it doesn’t really matter, but I’d still like to find a solution that avoids both of these problems.

Thankfully, node.js is pretty flexible and provides a listenFD() method that we can take advantage of. This lets us set up our own socket first, with whatever exact timings we want, and then let the class know about the socket we created.

It turns out that writing function to create an appropriate socket isn’t too hard as most of the low-level functions are available if you know where to look. So I present you with safeListen

function safeListen(server, port, address, user) {
    var ip_ver = net_binding.isIP(address)
    var fd
    var type

    switch (ip_ver) {
    case 4:
	type = 'tcp4'
	break
    case 6:
	type = 'tcp6'
	break
    default:
	throw new Error("Address must be a valid IPv4 or IPv6 address.")
    }

    fd = net_binding.socket(type)

    net_binding.bind(fd, port, address)

    if (user) {
	process.setuid(user)
    }

    net_binding.listen(fd, server._backlog || 128)

    /* Following the net.js listen implementation we do this in the
     nextTick so that people potentially have time to register
     'listening' listeners. */
    process.nextTick(function() {
	server.listenFD(fd, type)
    })
}

Instead of using server.listen(address, port) use safeListen(server, address, port, user). If you like monkey patching you can probably attach the function as a method to the server object and then make the call look like server.safeListen(address, port, user). This function essentially does the same thing as listen but if a user argument is specified, it will call setuid to drop privileges after calling bind(). The main limitation compared to the normal listen() method is that the address must be specified, and must be an IP address, rather than a hostname.

node.js semi-asynchronous functions

Mon, 08 Aug 2011 19:19:28 +0000
tech node.js

tl;dr

Last time I wrote about some of the idiosyncrasies in the way in which you deal with exceptions in node.js. This time, I’m looking at a phenomenon I’m calling semi-asynchronous functions.

Let’s start with a simple asynchronous function. We have a function x which sets the value of two global variables. Of course global variables are bad, so you could imagine that x is a method and it is updating some fields on the current object if it makes you feel better. Of course some will argue that any mutable state is bad, but now we are getting side-tracked!

var a = 0
var b = 0

function x(new_a, new_b) {
    a = new_a
    b = new_b
}

So, here was have a pretty simple function, and it is pretty easy to state the post-condition that we expect, specifically that when x returns a will have the value of the first argument and b will have the value of the second argument.

So, let’s just write some code to quickly test our expectations:

x(5, 6)
console.log(a, b)

As expected this will print 5 6 to the console.

Now, if x is changed to be an asynchronous function things get a little bit more interesting. We’ll make x asynchronous by doing the work on the next tick:

function x(new_a, new_b, callback) {
    function doIt() {
	a = new_a
	b = new_b
	callback()
    }
    process.nextTick(doIt)
}

Now, we can guarantee something about the values of a and b when the callback is executed, but what about immediately after calling? Well, with this particular implementation, we can guarantee that a and b will be unchanged.

function done() {
    console.log("Done", a, b)
}

x(5, 6, done)
console.log("Called", a, b)

Running this we see that our expectations hold. a and b are 0 after x is called, but are 5 and 6 by the time the callback is executed.

Of course, another valid implementation of x could really mess up some of these assumptions. We could instead implement it like so:

function x(new_a, new_b, callback) {
    a = new_a
    function doIt() {
	b = new_b
	callback()
    }
    process.nextTick(doIt)
}

Now we get quite a different result. After x is called a has been modified, but b remains unchanged. This is what I call a semi-asynchronous asynchronous function; part of the work is done synchronously, while the remainder happens some time later.

Just in case you are thinking at this point that this is slightly academic, there are real functions in the node.js library that are implemented in this semi-asynchronous fashion.

Now as a caller, faced with this semi-asynchronous functions, how exactly should you use it? If it is clearly documented which parts happen asynchronously and which parts happen synchronously and that is part of the interface, then it is relatively simple, however most functions are not documented this way, so we can only make assumptions.

If we are conservative, then we really need to assume that anything modified by the function must be in an undefined state until the callback is executed. Hopefully the documentation makes it clear what is being mutated so we don’t have to assume the state of the entire program is undefined.

Put another way, after calling x we should not rely on the values a and b in anyway, and the implementer of x should feel free to change when in the program flow a and/or b is updated.

So can we rely on anything? Well, it might be nice to rely on the order in which some code is executed. With both the implementation of x so far, we have been able to guarantee that the code immediately following the function executes before the asynchronous callback executes. Well, that would be nice, but what if x is implemented like so:

function x(new_a, new_b, callback) {
    a = new_a
    b = new_b
    callback()
}

In this case, the callback will be executed before the code following the call to x. So, there are two questions to think about. Is the current formulation of x a valid approach? And secondly, is it valid to rely on the code ordering?

While you think about that, let me introduce another interesting issue. Let’s say we want to execute x many times in series (i.e: don’t start the next x operation until the previous one has finished, i.e: it has executed the callback.). Well, of course, you can’t just use something as simple as a for loop that would be far too easy, and it would be difficult to prove how cool you are at programming if you could just use a for loop. No instead, you need to do something like this:

var length = 100000;
function repeater(i) {
  if( i < length ) {
      x(i, i,  function(){
	  repeater(i + 1)
      })
  }
}
repeater(0)

This appears to be the most widely used approach. Well there is at least one blog post about this technique, and it has been tied up into a nice library. Now, this works great with our original implementations of x. But try it with the latest one (i.e: the one that does the callback immediately). What happens? Stack overflow happens:

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
RangeError: Maximum call stack size exceeded

So now the question isn’t just about whether the code ordering is a reasonable assumption to make, now we need to work out whether it is a reasonable assumption to make that the callback gets a new stack each time it is called! Once again, if it is clearly documented it isn’t that much of a problem, but none of the standard library functions document whether they create a new stack or not.

The problem here is that common usage is conflicting. There is a lot of advice and existing libraries that make the assumption that a callback implies a new stack. At the same time there is existing code within the standard library that does not create a new stack each time. To make matters worse, this is not always consistent either, it can often depend on the actual arguments passed to the function as to whether a new stack is created, or the callback is executed on the existing stack!

What then can we make of this mess? Well, once again, as a caller you need to make sure you understand when the state is going to be mutated by the function, and also exactly when, and on which stack your callback will be executed.

As an API provider as always, you need to document this stuff, but lets try to stick to some common ground; callback should always be executed in a new stack, not on the existing one.

node.js exceptions

Mon, 08 Aug 2011 16:10:28 +0000
tech node.js

tl;dr

One of the best things about asynchronous, callback based programming is that basically all those regular flow control constructs you are used to are completely broken. However, the one I find most broken is the handling of exceptions.

Javascript provides a fairly familiar try...catch construct for dealing with exceptions. The problems with exceptions is that they provide a great way of short-cutting errors up a call stack, but end up being completely useless of the error happens on a different stack.

Here is a simple example to get started:

function x() {
    throw new Error('my silly error')
}

x()

If we run this in node, the result is fairly intuitive, we get a nasty traceback:

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: my silly error
    at x (/Users/benno/apkudo/test.js:2:11)
    at Object. (/Users/benno/apkudo/test.js:5:1)
    at Module._compile (module.js:402:26)
    at Object..js (module.js:408:10)
    at Module.load (module.js:334:31)
    at Function._load (module.js:293:12)
    at Array. (module.js:421:10)
    at EventEmitter._tickCallback (node.js:126:26)

Now if we ignore the first few lines of junk, the rest is a fairly familiar traceback. You’ll note that we are already pretty deep in a stack trace even for this very simple function. You can mostly ignore everything from Module._compile onwards.

Now instead of doing this we might want to, instead, catch this error and write some code to handle the error. We aren’t going to do anything earth shattering in the handler, just print out the exception and continue on our merry way.

function x() {
    throw new Error('my silly error')
}

try {
    x()
} catch (err) {
    console.log("Error:", err)
}

Now, if you run this you get:

Error: { stack: [Getter/Setter],
  arguments: undefined,
  type: undefined,
  message: 'my silly error' }

So far, so good. Just what you would expect in the normal world of programming. Let’s spice things up a bit; let’s make x asynchronous. We’ll create a wrapper function y which will take two arguments. The first argument indicates whether to execute x synchronously or asynchronously. The second argument is a function that will be called on completion. Something like this:

function y(arg, callback) {
    if (arg === 1) {
	x()
	callback()
    } else {
	function onTick() {
	    x()
	    callback()
	}
	process.nextTick(onTick())
    }
}

Now this setup may seem a tad contrived, but in the real world we get situations not all that different to this. For example the built-in listen method may do a DNS lookup on the host argument if it is not a dotted decimal. If it is a dotted decimal though, no lookup is required. So, we change our calling code appropriately:

try {
    y(1, function () { console.log("Callback") })
} catch (err) {
    console.log("Error:", err)
}

Running this gets us essentially the same output as before: we successfully catch the exception and then we are on our way. Let’s change our calling code slightly though, so that we hit the asynchronous path:

try {
    y(0, function () { console.log("Callback") })
} catch (err) {
    console.log("Error:", err)
}

Running this we now find that we get an ugly traceback. We completely failed in catching the exception:

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: my silly error
    at x (/Users/benno/apkudo/test.js:2:11)
    at Array.onTick (/Users/benno/apkudo/test.js:11:6)
    at EventEmitter._tickCallback (node.js:126:26)

What happened here is that when y hits the asynchronous path it creates an entirely new call stack, on that isn’t protected by a try..catch block at the top of the call stack. So we end up with the default node exception handling code. You can see how the call stack in this case is much shorter.

How can we deal with this? Well, one way is that we just don’t do exception like things, and always explicitly return errors or pass them as arguments to callbacks. The other option is to use the event system provided by node.js. That is what we will look at next as it is what node.js uses internally. We are going to change our code so that y emits a myerror event rather than the exception bubbling up.

var events = require('events')
emitter = new events.EventEmitter()

function y(arg, callback) {
    if (arg === 1) {
	x()
	callback()
    } else {
	function onTick() {
	    try {
		x()
	    } catch(err) {
		emitter.emit('myerror', err)
		return
	    }
	    callback()
	}
	process.nextTick(onTick)
    }
}

In this example we are just using a global emitter object. In a real example x would likely be a method on an object that sub-classed the EventEmitter class. If we run the code now don’t get any output at all! This is because we haven’t yet attached a listener to the myerror event. We can do that like so:

emitter.on('myerror', function(err) { console.log("Error:", err) })
y(0, function () { console.log("Callback") })

Now, when we run it we get the same type of output as we did when we were catching exceptions:

Error: { stack: [Getter/Setter],
  arguments: undefined,
  type: undefined,
  message: 'my silly error' }

Now, you might have picked up a slight problem with the above approach. If we don’t catch the exception by registering a handler for the myerror event nothing happens; the exception is essentially ignored. This is different to normal exceptions in Javascript that will bubble right up to the run-time for reporting.

Now, we could ensure that there is always a default handler for the myerror event which dumped the traceback and exits, but you would also need to work out if another listener already handled the error or not, and so on. It turns out that node.js has already solved this problem, so instead of inventing our own event name we can use the special error event. Events called error are treated very specially by the node code. From the emit code in event.js:

  if (type === 'error') {
    if (!this._events || !this._events.error ||
        (isArray(this._events.error) && !this._events.error.length))
    {
      if (arguments[1] instanceof Error) {
        throw arguments[1]; // Unhandled 'error' event
      } else {
        throw new Error("Uncaught, unspecified 'error' event.");
      }
      return false;
    }
  }

Of course, registering an error event listener doesn’t magically trap any exceptions that might be raised in the old fashioned way. This means if you are writing code, you really need to understand which type of error handling approach the code you are calling uses and ensure you handle it appropriatley.

Unfortunately, most APIs don’t actually document this error handling behaviour, so you are forced to go and read the code to work out exactly what is going on. If you are writing an API, please make it easy on your fellow developer by documenting this kind of thing.