IPv4 Network Calculator


There is a plethora of online calculators. I couldn’t find one that met my needs so I decided to write something simple in JavaScript based on Node.js. The code should be easy to adapt to run inside the browser.

The calculator below requires you to specify the network address, number of subnets, number of hosts per subnet, and prints the subnet mask, the network address of each subnet, and the address range of the hosts in the subnet. Thus…

node netcalc --n 10.0.0.0 --ns 12 --hs 1

Will result in

Subnet mask: 255.255.255.252
Subnet #1
    Network: 10.0.0.4
    Host range: 10.0.0.5 - 10.0.0.6
Subnet #2
    Network: 10.0.0.8
    Host range: 10.0.0.9 - 10.0.0.10
Subnet #3
    Network: 10.0.0.12
    Host range: 10.0.0.13 - 10.0.0.14
Subnet #4
    Network: 10.0.0.16
    Host range: 10.0.0.17 - 10.0.0.18
Subnet #5
    Network: 10.0.0.20
    Host range: 10.0.0.21 - 10.0.0.22
Subnet #6
    Network: 10.0.0.24
    Host range: 10.0.0.25 - 10.0.0.26
Subnet #7
    Network: 10.0.0.28
    Host range: 10.0.0.29 - 10.0.0.30
Subnet #8
    Network: 10.0.0.32
    Host range: 10.0.0.33 - 10.0.0.34
Subnet #9
    Network: 10.0.0.36
    Host range: 10.0.0.37 - 10.0.0.38
Subnet #10
    Network: 10.0.0.40
    Host range: 10.0.0.41 - 10.0.0.42
Subnet #11
    Network: 10.0.0.44
    Host range: 10.0.0.45 - 10.0.0.46
Subnet #12
    Network: 10.0.0.48
    Host range: 10.0.0.49 - 10.0.0.50

Let’s proceed to the code. You’ll need to install Node.js, and the optimist module using npm, to test it. I have used array and string manipulation functions instead of bitwise operators.

var argv = require("optimist").argv;

netcalc(argv.n, argv.ns, argv.hs);

function netcalc(n, ns, hs) {

    if (n == undefined || ns == undefined || hs == undefined) {
        console.log('options: --n <network> --ns <number_of_subnets> --hs <hosts_per_subnet>');
        process.exit(-1);
    }

    var bitsForSubnet = (ns.toString(2)).length;

    var numHosts = hs + 1;
        // The address 0 and all ones are special so need to ensure host
        // address is not one of those by adding one

    var bitsForHost = (numHosts.toString(2)).length;

    // Calculate and print subnet mask

    var netMaskb = Array(32-bitsForHost+1).join('1')
        + Array(bitsForHost+1).join('0');

    console.log('Subnet mask: ' + bstoip(netMaskb));

    // Calculate and print subnet info

    for (var i = 0; i < ns ; i++) {
        console.log("Subnet #" + (i+1));

        var nsb = (i+1).toString(2);

        var networkb = iptobs(n);

        var subnetb = networkb.substring(0, networkb.length - nsb.length - bitsForHost)
            + nsb + Array(bitsForHost+1).join('0');

        console.log('    Network: ' + bstoip(subnetb));

        var minhb = subnetb.substring(0, 32 - bitsForHost)
            + Array(bitsForHost).join('0') + '1';

        var maxhb = subnetb.substring(0, 32 - bitsForHost)
            + Array(bitsForHost).join('1') + '0';

        console.log('    Host range: ' + bstoip(minhb) + ' - ' + bstoip(maxhb));
    }
}

// ipv4 to binary string
function iptobs(ip) {
    var ipsplit = ip.split('.');
    if (ipsplit.length != 4) {
        console.log('Network address should be in the IPv4 address format e.g. 10.0.0.0');
        process.exit(-1);
    }
    var b = parseInt(ipsplit[0]).toString(2);
    var bs = Array(8 - b.length + 1).join('0') + b;
    b = parseInt(ipsplit[1]).toString(2);
    bs = bs + Array(8 - b.length + 1).join('0') + b;
    b = parseInt(ipsplit[2]).toString(2);
    bs = bs + Array(8 - b.length + 1).join('0') + b;
    b = parseInt(ipsplit[3]).toString(2);
    bs = bs + Array(8 - b.length + 1).join('0') + b;
    return bs;
}

// binary string to ipv4 format
function bstoip(bs) {
    return parseInt(bs.substring(0, 8), 2) + '.'
        + parseInt(bs.substring(8, 16), 2) + '.'
        + parseInt(bs.substring(16, 24), 2) + '.'
        + parseInt(bs.substring(24, 32), 2);
}

If the provided network address does not allow for the specified number of subnets and hosts per subnets it will be truncated without any warning.

A simple read-only configuration module for Node.js


There are already a few configuration modules available for Node.js. I built myself a simple read-only configuration module for Node.js as a learning experience. The module reads configuration information from a JSON file like the following

{
    "db":
    {
        "host": "localhost",
        "port": "1433"
    }
}

The module, called config.js, is initialized by calling the init method. The callback function passed to the init method is called when the initialization is complete. All the objects in the JSON file, which we have called config.json, can be accessed from the module object.

var fs = require('fs');

var config = function() {
    // constructor
}

config.prototype.init = function(file, cb) {
    fs.readFile(file, function (err, data) {
        if (err) {
            console.log(err);
            cb(-1);
        } else {
            var json = JSON.parse(data);
            for (o in json) {
                config.prototype[o] = json[o];
            }
            cb(0); // no error
        }
    });
}

module.exports = new config();

This is how the module can be used.

var config = require('./config.js');
config.init('config.json', function(resp) {
    if (resp != 0) {
        console.log('Could not load config file.');
        return;
    }
    console.log('host: ' + config.db.host);
    console.log('port: ' + config.db.port);
});

Once initialized, the module can be required by any script file of your Node.js application.

Why you don’t want to use the module above

Node.js already provides a neat mechanism to read JSON, you can simply require the JSON file:

var config = require('./config.json');
console.log(config.db.port);

The module system caches the file, so subsequent requires don’t parse the file again. If you need to read the file after it has been modified, you’ll need to use require.cache to delete it before invoking require.

delete require.cache('./config.json');

You can invoke require.cache when the file changes by using the watchFile function exported by the File System module.

Node.js client to server with socket.io


Socket.io is usually employed by browser apps communicating with a Node.js server application. It is however possible to create a client in Node.js if you need to call the same server application. It is also possible for the server to return values by calling a function that the client passes to it.

You’ll need to install socket.io and socket.io-client using npm as shown below. Additionally, we also use express for serving static HTTP content.

npm -g install socket.io socket.io-client express errorhandler

This is how a client connection can be established. The namespace ns is used for communicating with the server. Client emits the event call with parameter p1, and a function parameter that receives a response code and additional data.

var io = require('socket.io-client');
var serverUrl = 'http://localhost:8080/ns';
var conn = io.connect(serverUrl);

var p1 = 'hello';
conn.emit('call', p1, function(resp, data) {
    console.log('server sent resp code ' + resp);
});

Remember to export global node_modules folder in NODE_PATH before running the script

export NODE_PATH=/usr/local/lib/node_modules/
node 

Newer versions of node, don’t require NODE_PATH to be set to the global module path used by npm i -g.

This is how a server can serve the client above.

var http = require('http');
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/'));
var errorhandler = require('errorhandler');
app.use(errorhandler()); // development only
var server = http.createServer(app);

var io = require('socket.io').listen(server);
var ns = io.of('/ns');
ns.on('connection', function (socket) {
    socket.on('call', function (p1, fn) {
	console.log('client sent '+p1);
        // do something useful
        fn(0, 'some data'); // success
    });
});

server.listen(8080);

Socket.io makes event-based communication really easy.

Broadcast to all sockets


The broadcast server example from the socket.io how-to is reproduced below:

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});

io.sockets.emit('to all');

The user connected event will be broadcast to all sockets except the one that just connected. The to all event is broadcast to all the sockets.

You can also broadcast some event to all the sockets in a namespace. For example:

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});

var ns1 = io.of('/ns1');
ns1.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});

ns1.emit('to all');

The to all event is emitted to all the sockets in ns1. If you were to emit using io.sockets.emit instead, the event would not be received by any of the sockets in ns1.

The client script that receives messages for namespace ns1 may look like this:

<script>
  var ns1 = io.connect('http://localhost/ns1');
  
  ns1.on('to all', function () {
    console.log('to all');
  });
</script>

Awesome things about Mac OS X


Mac OS X, like iOS, has the ability to grow upon you due to its painfully perfected visuals and tools. I mention a few of these below.

The Dock

Windows 7 has borrowed some of its ideas and so has Ubuntu, but the Mac OS X dock is just blows you away with its fluidity, sharpness and utility.

The App Store

Just like iOS, Mac OS X now has an app store with several paid and free apps. This is such a huge convenience, you just have to go to one place to look for apps. You can also trust Apple to do due diligence so you know an app will not harm your Mac.

The Viewer

The Viewer along with the Writer app can be used to view several common file types. One feature of the Viewer, that I particularly like, is the ability to join PDF files. Just drop PDFs on top of another PDF document in the Contact Sheet view and they are joined. Save as a new PDF document when you are done.

And the not so awesome things…

Mac OS X does not come with a native image or photo editor. Fret not, there are several free and open source alternatives. I particularly like PaintBrush. It also does not have a text editor but TextWrangler from Bare Bones Software is a nice free alternative.

Xcode


I find that Xcode (version 4) is a great IDE but I wish someone had told me a few things about it before I got started.

Adding a Framework or Library

Click on the project name. Settings appear on the center pane. Select a target. Head over to the Build Phases tab. Add library at Link Binary with Libraries.

The Build Output

The default Xcode build output is not saved under the project directory. If you want to do that you have to go to Xcode preferences, in the Locations tab change the Derived Data option to Relative.

Enable support for RNDIS Ethernet devices in the Linux kernel


Use make menuconfig (or linux-menuconfig when using Buildroot) to invoke the kernel configuration wizard. Then, enable the following modules under Device Drivers, Network device support, USB Network Adapters

  • Multi-purpose USB Networking Framework
  • CDC Ethernet support
  • Host for RNDIS and ActiveSync devices

Host for RNDIS and ActiveSync devices

If the device you’re using provides an IP address using DHCP, there’s a bug in some Linux kernel versions that hinders obtaining an IP address from the device. You might want to patch or upgrade the kernel.