bsdbox

ipv4 and ipv6 cidr subnet calculator

<2019-09-21>

UPDATE: netcalc has a newer version available.

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

In one of my Computer Science units we studied subnetting. It was interesting but also highly programmatic. So like any good CS student, when faced with a repetitive problem to solve—such as calculating subnets—you automate the process, which I did! I wrote a program in Python but then decided to rewrite it in C. Initially, it only supported IPv4 because that was the only requirement at school. More recently, however, I thought to add IPv6 support; this is simple enough in C with inet_pton(3) and inet_ntop(3). I avoided using atoi because of its inherent vulnerability. I would have liked to use OpenBSD's strtonum implementation but also wanted to use the calculator on macOS, so settled for strtol. The string to long function at least incorporates error checking to help protect against under- and over-flows. It might seem convoluted, but is simple enough:

long	 num;		/* converted number */
char	 str[256];	/* 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);

strtol is passed three arguments: (1) the string str containing the number to be converted; (2) the address of the pointer &ptr that will point to the first non-numeric character in str (which will be NUL at the end of str in a successful conversion); and (3) the base number system–in this case, 10 for decimal. The input is subjected to a series of tests: (1) if the number is too small or large, LONGMIN or LONGMAX, respectively, is returned and errno is set to ERANGE; (2) if str isn't an actual number, 0 is returned, errno is set to some error code other than 0, and the original value of str is stored in ptr; and (3) if ptr does not point to NUL at the end of str, an invalid (i.e., non-numeric) character was found 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, back to the subnet calculator: it is a small and simple command line utility that is easy to use. At the moment, multiple subnets can be requested for the specified IPv4 CIDR address by passing an integer to the -s option:

$ ./netcalc 192.168.1.200/26 -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

Subnet division for IPv6 may be added in the future.

The program is called netcalc, and is released under the BSD-styled ISC license. The repository can be cloned to compile netcalc from source. Alternatively, a binary executable is available. If building on OpenBSD, the math library needs to be linked:

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 and run make:

# clone the repository
$ fossil clone https://cvs.bsdbox.org/netcalc
$ got clone https://got.jamsek.net/netcalc.git

# 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.3, 6.4, 6.5, & 6.6, and macOS Mojave 10.14 & Catalina 10.15, but should be compatible on other BSDs (or even Linux).

Let me know if you find it useful!

Tags: code c
send comments to mark AT jamsek DOT net

Generated by emacs org mode

Copyright © 2023 Mark Jamsek