January 20, 2011 archive

Testing Node.js With IPv6 – First Step, Does It Work?

Given all the writing I’ve been doing lately about IPv6 and about Node.js, it was only natural for me to try combining them. I pay for a VPS over at RapidXen and upon request they will provide you with an IPv6 address block (for free). So I’ve been using it as a base for my IPv6 experiments.

I should note that my home network is set up with IPv6 via a IPv6-to-IPv4 tunnel from Tunnelbroker.net. I previously wrote up how I configured IPv6 this way using an Apple Time Capsule WiFi access point

Testing Apache First

After using IPv6-test.com to verify that I have HTTP connectivity over IPv6 from my system at home, I tested connectivity to my VPS running a stock CentOS 5.5 Apache server. Here was the IPv4 result (and yes, I cover up IP addresses… a certain degree of paranoia comes with the territory of being in the security space):

apachev4.jpg

Here was the same result with IPv6:

apacheipv6.jpg

(If you aren’t familiar with using IPv6 addresses in web browsers, you just enclose the IPv6 address in square brackets. The specific browser I’m using is Google Chrome on a Mac, but this should work in all browsers.)

Testing Node.js

The next step was to shut down Apache and start up Node.js. For this experiment, I’m purely using the HTTP module in Node.js and not getting into any of the frameworks. Here’s the very basic code I’m using (also on Github):

[js]
var http = require(‘http’);

var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type":"text/plain"});
response.end ("Hello World!n");
console.log("Got a connection");
});

server.listen(80);

console.log("Server running on localhost at port 80");
[/js]

After firing it up, connecting to the site via IPv4 was no problem:

nodejsipv4.jpg

And this is shown in the console:

bash-3.2# node httpsample.js
Server running on localhost at port 80
Got a connection
Got a connection

Next I tried the IPv6 connection:

nodeipv6.jpg

Oops. Predictably, the console log also did not show a new connection. I duplicated the test to make sure there wasn’t anything else funky going on, but had the same issue. Node.js wasn’t accepting HTTP connections via IPv6.

UPDATE: See below for the answer…

Testing the ‘net’ module

I was curious to see if the issue might be with the “http” module or if it was a broader issue. So I fired up a really basic TCP server example:

[js]
var net = require("net");

var s = net.createServer( function(c) {
c.addListener("connect", function () {
console.log("Connection from " + c.remoteAddress);
c.end("Hello Worldn");
});
});

s.listen(8000);

console.log("TCP server running on port 8000")
[/js]

From my Mac, I then tried connecting via IPv4 and IPv6:

$ telnet 69.xxx.xxx.xxx 8000
Trying 69.xxx.xxx.xxx...
Connected to rapidxen.net.
Escape character is '^]'.
Hello World
Connection closed by foreign host.

$ telnet -6 2607:xxxx:xxxx:xxxx::2 8000
Trying 2607:xxxx:xxxx:xxxx::2...
telnet: connect to address 2607:xxxx:xxxx:xxxx::2: Connection refused
telnet: Unable to connect to remote host
$

and found that IPv6 connectivity wasn’t supported in the “net” module.

Just to verify my testing method, I restarted Apache on the VPS box and used the same “telnet -6” command to hit port 80 on the box. I was able to connect and issue HTTP commands without a problem.

In the end…

So it would seem that Node.js doesn’t work with IPv6, which is not terribly surprising given that (Node.js founder) Ryan Dahl indicated in the #node.js IRC chat yesterday that basically no IPv6 testing had been done. Looking in the Node.js ChangeLog, IPv6 support was added in some form back in June 2009:

2009.06.18, Version 0.0.5, 3a2b41de74b6c343b8464a68eff04c4bfd9aebea

Support for IPv6

But without looking at code diffs, it’s not clear to me what exactly was changed to support IPv6.

The next step is obviously to start digging around in code… given that I’m picturing it as a bigger task, I’m not sure when I’ll get the chance to do, but it would be a good excuse to take a look inside the Node.js code.

In the meantime, if anyone else reading this has some Node.js modules they’d like me to test with IPv6, or other ideas around this, I’m glad to help. Just drop me a note or hit me on Twitter.

THE ANSWER

UPDATE:The answer that I couldn’t find anywhere online came in a comment to this post from none other than Ryan Dahl… Node.js DOES work with IPv6, provided you give it the address!

All I had to do to make the original code work with IPv6 was add the IPv6 address to the “.listen(80)”, like this:

[js]
var http = require(‘http’);

var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type":"text/plain"});
response.end ("Hello World!n");
console.log("Got a connection");
});

server.listen(80, "2607:xxxx:xxxx:xxxx::2");

console.log("Server running on localhost at port 80");
[/js]

But of course this only listens on the IPv6 address and not on the IPv4 address, so I needed to refactor the code a bit and run two servers:

[js]
var http = require(‘http’);

var handler = function (request, response) {
response.writeHead(200, {"Content-Type":"text/plain"});
response.end ("Hello World!n");
console.log("Got a connection");
};

var server6= http.createServer();
server6.addListener("request",handler);
server6.listen(80,"2607:xxxx:xxxx:xxxx::2");

var server= http.createServer();
server.addListener("request",handler);
server.listen(80,"69.xxx.xxx.xxx&");

console.log("Server running on localhost at port 80");
[/js]

With that in place, it’s now answering on both the IPv4 and IPv6 addresses!

Many thanks, Ryan, for the answer!