tl;dr: download netcalc—an IPv4 and IPv6 subnet calculator—to make subnetting easier.

In one of my Computer Science units last year, we did some work on subnetting. It was pretty interesting but also highly programmatic. So like any good CS student, when you have a repetitive problem to solve—such as calculating subnets—you automate the process; which I did. I first wrote a program in Python but then decided to create one in C. It was only good for IPv4, though, as that's all we worked on at university. More recently, I thought I'd expand it to include IPv6. C makes this pretty simple with the inet_pton and inet_ntop functions. I've avoided using atoi as its use has been discouraged due to its inherent vulnerability for a long time now. I would've used OpenBSD's strtonum implementation but wanted to use the calculator on macOS, too, so settled for strtol. The string to long function incorporates error checking to help protect against under- and over-flows, which is encouraged habit-forming behaviour. It might seem overly convoluted at first, but breaks down into an easily understood logical sequence:

long          num;           /* integer to hold converted number */
char          str[256];      /* character array of string to convert */
char         *ptr;           /* points to first non-digit char in str */

errno = 0;                   /* reset error number */

num = strtol(str, &ptr, 10);
if (errno == ERANGE)
        printf("error: overflow\n");
else if (errno != 0)
        printf("error: string not a number\n");
else if (*ptr != '\0')
        printf("invalid characters in string\n");
else
        printf("success!"\n);

In the first instance, strtol is passed the string str that contains the number to be converted, a pointer that points to the end of the string when converted, and the base number system (e.g., 10, in this case, for decimal). If the number is too small or large, errno is set to ERANGE; if str isn't a number at all, errno will be set to some error code other than 0; and if the end ptr doesn't point to a null character, there was invalid input in the string. This covers all bases. OpenBSD, however, has distilled this error detection during number conversion process into the much simpler strtonum(3) function, which is equally, if not more, robust—and worth further perusal.

In any case, it's a quick and simple command line app that is easy to use. At the moment, multiple subnets can be requested for a given IPv4 CIDR address:

$ ./netcalc 192.168.1.200/246 -s2

Address           :   192.168.1.200
CIDR notation     :   192.168.1.192/26
Address range     :   192.168.1.193 —— 192.168.1.254
Broadcast address :   192.168.1.255
Subnet mask       :   255.255.255.192 [0xffffffc0]
Address block     :   62 contiguous hosts

[+] subnets requested: 2
[+] subnets delivered: 2

-> subnet 1
CIDR notation     :   192.168.1.192/27
Address range     :   192.168.1.193 —— 192.168.1.222
Broadcast address :   192.168.1.223
Subnet mask       :   255.255.255.224 [0xffffffe0]
Address block     :   30 contiguous hosts

-> subnet 2
CIDR notation     :   192.168.1.224/27
Address range     :   192.168.1.225 —— 192.168.1.254
Broadcast address :   192.168.1.255
Subnet mask       :   255.255.255.224 [0xffffffe0]
Address block     :   30 contiguous hosts

Or a single network when using IPv6:

$ ./netcalc -6 c7a9:2ce5:3425:8045:7777:67b4:cd58:7494/114

Address        : c7a9:2ce5:3425:8045:7777:67b4:cd58:7494
CIDR notation  : c7a9:2ce5:3425:8045:7777:67b4:cd58:4000/114
Start address  : c7a9:2ce5:3425:8045:7777:67b4:cd58:4000
End address    : c7a9:2ce5:3425:8045:7777:67b4:cd58:7fff
Block size:    : 16,384 contiguous usable hosts

The subnet division feature for IPv6 should be added in the future. But for now, I'm working on a home alarm project and have enough schoolwork to keep busy.

The program is called netcalc, and is released under the BSD-styled ISC license. The source code can be downloaded and built locally, or there is a binary executable available. It needs to be compiled with the math library linked when building on OpenBSD:

ftp -S do https://jamsek.dev/resources/pub/netcalc/netcalc.c
cc -Werror -Wall -o netcalc netcalc.c -lm
./netcalc

netcalc 0.2 IPv4 & IPv6 CIDR Subnet Calculator
usage: netcalc [-s subnets | -6] ipaddr/prefix
 e.g.: netcalc -s 4 192.168.0.1/24
       netcalc -6 8c6b:dbfd:5c73:8f14:f815:a4a2:5dab:38b0/110

On macOS you can drop the -lm.

Alternatively, download and untar the appropriate tarball before running make on either macOS or OpenBSD.

# macOS
curl -O https://jamsek.dev/resources/pub/netcalc/netcalc_macos.tar.gz
tar -zxvf netcalc_macos.tar.gz

# OpenBSD
ftp -S do https://jamsek.dev/resources/pub/netcalc/netcalc_openbsd.tar.gz
tar -zxvf netcalc_openbsd.tar.gz

# both macOS and OpenBSD
cd netcalc/src
make
cc -c -o obj/main.o main.c -I../include -Werror -Wall
cc -c -o obj/netcalc.o netcalc.c -I../include -Werror -Wall
cc -o netcalc obj/main.o obj/netcalc.o -I../include -Werror -Wall -lm

# macOS
./netcalc

# OpenBSD
cd obj && ./netcalc

netcalc 0.2 IPv4 & IPv6 CIDR Subnet Calculator
usage: netcalc [-s subnets | -6] ipaddr/prefix
 e.g.: netcalc -s 4 192.168.0.1/24
       netcalc -6 8c6b:dbfd:5c73:8f14:f815:a4a2:5dab:38b0/110

It's only been tested on OpenBSD 6.4 & 6.5, and macOS Mojave 10.14, but should be compatible on other BSDs or even Linux.

Let me know if you find it useful!


Comments

comments powered by Disqus