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!