💾 Archived View for thrig.me › tech › network › netmask.gmi captured on 2024-12-17 at 10:45:15. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
In the olden times there were class A, B, C (etc) networks, and you may still see reference to these in various documentation, or maybe an operating system comes up with a weird default netmask because it thinks it is on a "class B" network, which is true, but CIDR came into service somewhere in the 1990s, which was a while ago now. Some certificate was still teaching class A networks in the 2010s, and I was like "wow, they still require that?" so told the student to just memorize it for the test (and then mostly to forget about it).
Probably you should use a tool; only on job interviews would you really need to memorize anything. I'd still use a tool even if I did memorize netmasks, as humans are really good at making tiny mistakes that may make a huge difference to a firewall rule. Carpenters have a saying about measuring more than once before cutting, and the same may apply to network changes. ipcalc and sipcalc are two such tools.
Knowing binary counting or enough about computer networking may help.
Also relevant are special use or otherwise reserved subnets, for which one might find RFC or other such documentation detailing what these are. RFC 1918 and RFC 4193 are relevant here, as well as RFC 3330 which is easier to memorize than RFC 6890 or whatever new RFC they have created after this was written.
Masks are numbers that filter other numbers according to the bit pattern and logic involved.
$ perl -e 'printf "%08b\n", 240' 11110000 $ perl -e 'printf "%08b\n", 42' 00101010 $ perl -e 'printf "%08b\n", 240 & 42' 00100000 $ perl -e 'printf "%08b\n", 247' 11110111 $ perl -e 'printf "%08b\n", 240 & 247' 11110000
One may also see portions of a bit pattern shifted around and then masked.
$ perl -e 'printf "%08b\n", 240 >> 4' 00001111 $ perl -e 'printf "%08b\n", (240 >> 4) & (42 >> 4)' 00000010 $ perl -e 'printf "%08b\n", (240 >> 4) & (247 >> 4)' 00001111 $ perl -E 'say 0b00001111' 15 $ perl -e 'printf "0x%X\n", 15' 0xF $ perl -E 'say "okay" if 0xF == (42 >> 4)' $ perl -E 'say "okay" if 0xF == (247 >> 4)' okay
One can also join two numbers or bit patterns together,
$ perl -e 'printf "%08b\n", 240 | 1' 11110001 $ perl -e 'printf "%08b\n", 240 | 2' 11110010 $ perl -e 'printf "%08b\n", 240 | 4' 11110100
or invert a bit pattern to remove it from some other pattern.
$ perl -e 'printf "%b\n", ~240' 1111111111111111111111111111111111111111111111111111111100001111 $ perl -e 'printf "%08b\n", (~240 & 247) & 0xFF' 00000111
By these means numbers (IPv4 or IPv6 addresses, which are 32- or 64-bit numbers) can be selected on by other numbers which mask off relevant portions of the number, sort of like how one might have a filter to select for the area code of a phone number, or instead the part after the area code. However, firewalls and routers may be considered black boxes: it's not important in networking exactly how they do the masking, rather whether the mask is correct for the need at hand. (Unless you are writing firewall software, then you probably should know the low level details.)
ipcalc is a tool often available in ports or package systems, and I've been using it for decades now. Maybe there's something better out there, or you could write your own tool?
IPv4 uses 32-bit addresses, and a netmask selects some bit pattern, thus masking some portion of of address. This is usually done to divide the address into subnet and host-specific portions. For example, a firewall may want to allow all traffic for hosts on a "/24" subnet, so might use 192.0.2.0/24 in a rule to allow (or deny) all the hosts (192.0.2.0, 192.0.2.1, 192.0.2.2, ... 192.0.2.254) on that subnet.
$ ipcalc 192.0.2.0/24 Address: 192.0.2.0 11000000.00000000.00000010. 00000000 Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000 Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111 => Network: 192.0.2.0/24 11000000.00000000.00000010. 00000000 HostMin: 192.0.2.1 11000000.00000000.00000010. 00000001 HostMax: 192.0.2.254 11000000.00000000.00000010. 11111110 Broadcast: 192.0.2.255 11000000.00000000.00000010. 11111111 Hosts/Net: 254 Class C $ ipcalc 192.0.2.1 | grep Address Address: 192.0.2.1 11000000.00000000.00000010. 00000001 $ ipcalc 192.0.2.2 | grep Address Address: 192.0.2.2 11000000.00000000.00000010. 00000010 ... $ ipcalc 192.0.2.254 | grep Address Address: 192.0.2.254 11000000.00000000.00000010. 11111110
On a historical note, the "zero" (lowest) address used to be the broadcast address, but that was moved decades ago to "255" (the highest). Still, you may see some reluctant to use the .0 address. However .0 may not always be the lowest address that a netmask selects for, nor .255 the highest. 192.0.2.32/27 for example starts at 192.0.2.32, and has a broadcast address of 192.0.2.63:
$ ipcalc 192.0.2.32/27 Address: 192.0.2.32 11000000.00000000.00000010.001 00000 Netmask: 255.255.255.224 = 27 11111111.11111111.11111111.111 00000 Wildcard: 0.0.0.31 00000000.00000000.00000000.000 11111 => Network: 192.0.2.32/27 11000000.00000000.00000010.001 00000 HostMin: 192.0.2.33 11000000.00000000.00000010.001 00001 HostMax: 192.0.2.62 11000000.00000000.00000010.001 11110 Broadcast: 192.0.2.63 11000000.00000000.00000010.001 11111 Hosts/Net: 30 Class C
This is a "slash 32" mask, that selects only for the host. What use is that? With a wireguard VPN one might use the "AllowedIPs" configuration value to only allow packets from and to a single IP address for that single tunnel. Firewalls may also have an implicit netmask of /32 when an address without a mask is given.
$ ipcalc 192.0.2.99/32 Address: 192.0.2.99 11000000.00000000.00000010.01100011 Netmask: 255.255.255.255 = 32 11111111.11111111.11111111.11111111 Wildcard: 0.0.0.0 00000000.00000000.00000000.00000000 => Hostroute: 192.0.2.99 11000000.00000000.00000010.01100011 Hosts/Net: 1 Class C
This is 0.0.0.0/0, though I've seen vague mentions that some routing software does not support a /0 mask and instead needs two /1 to select for all hosts.
$ ipcalc 0.0.0.0/0 Address: 0.0.0.0 00000000.00000000.00000000.00000000 Netmask: 0.0.0.0 = 0 00000000.00000000.00000000.00000000 Wildcard: 255.255.255.255 11111111.11111111.11111111.11111111 => Network: 0.0.0.0/0 00000000.00000000.00000000.00000000 HostMin: 0.0.0.1 00000000.00000000.00000000.00000001 HostMax: 255.255.255.254 11111111.11111111.11111111.11111110 Broadcast: 255.255.255.255 11111111.11111111.11111111.11111111 Hosts/Net: 4294967294 Class A, In Part APIPA $ ipcalc 0.0.0.0/1 Address: 0.0.0.0 0 0000000.00000000.00000000.00000000 Netmask: 128.0.0.0 = 1 1 0000000.00000000.00000000.00000000 Wildcard: 127.255.255.255 0 1111111.11111111.11111111.11111111 => Network: 0.0.0.0/1 0 0000000.00000000.00000000.00000000 HostMin: 0.0.0.1 0 0000000.00000000.00000000.00000001 HostMax: 127.255.255.254 0 1111111.11111111.11111111.11111110 Broadcast: 127.255.255.255 0 1111111.11111111.11111111.11111111 Hosts/Net: 2147483646 Class A, In Part Private Internet $ ipcalc 128.0.0.0/1 Address: 128.0.0.0 1 0000000.00000000.00000000.00000000 Netmask: 128.0.0.0 = 1 1 0000000.00000000.00000000.00000000 Wildcard: 127.255.255.255 0 1111111.11111111.11111111.11111111 => Network: 128.0.0.0/1 1 0000000.00000000.00000000.00000000 HostMin: 128.0.0.1 1 0000000.00000000.00000000.00000001 HostMax: 255.255.255.254 1 1111111.11111111.11111111.11111110 Broadcast: 255.255.255.255 1 1111111.11111111.11111111.11111111 Hosts/Net: 2147483646 Class B, In Part Private Internet
There has been some corruption of the terminology where "class c" may be used to refer to a "/24" subnet, though this is strictly incorrect as "class c" is defined by the leading bit pattern, not the trailing netmask that did not exist when the class terminology was invented. However, humans evolve their language in wacky and uncontrolled ways. The following three subnets show /24 networks in the class A, B, and C networks.
$ ipcalc 10.0.0.0/24 Address: 10.0.0.0 00001010.00000000.00000000. 00000000 Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000 Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111 => Network: 10.0.0.0/24 00001010.00000000.00000000. 00000000 HostMin: 10.0.0.1 00001010.00000000.00000000. 00000001 HostMax: 10.0.0.254 00001010.00000000.00000000. 11111110 Broadcast: 10.0.0.255 00001010.00000000.00000000. 11111111 Hosts/Net: 254 Class A, Private Internet $ ipcalc 172.16.0.0/24 Address: 172.16.0.0 10101100.00010000.00000000. 00000000 Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000 Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111 => Network: 172.16.0.0/24 10101100.00010000.00000000. 00000000 HostMin: 172.16.0.1 10101100.00010000.00000000. 00000001 HostMax: 172.16.0.254 10101100.00010000.00000000. 11111110 Broadcast: 172.16.0.255 10101100.00010000.00000000. 11111111 Hosts/Net: 254 Class B, Private Internet $ ipcalc 192.168.0.0/24 Address: 192.168.0.0 11000000.10101000.00000000. 00000000 Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000 Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111 => Network: 192.168.0.0/24 11000000.10101000.00000000. 00000000 HostMin: 192.168.0.1 11000000.10101000.00000000. 00000001 HostMax: 192.168.0.254 11000000.10101000.00000000. 11111110 Broadcast: 192.168.0.255 11000000.10101000.00000000. 11111111 Hosts/Net: 254 Class C, Private Internet
Some operating systems (I am unsure if any modern ones still do this) would use the "class" to determine the default broadcast address; that is, the host would derive a subnet mask of 255.255.0.0 when given the IP address of 172.16.0.42 on the above 172.16.0.0/24 network, because that is a "class b" network. Hosts on a 172.16.0.0/24 network must instead use a subnet mask of 255.255.255.0 for broadcast packets to work correctly; the "class b" notion really is legacy information best shuffled off to the dustbin of history.
Perhaps run tcpdump(8) now and then and look for hosts sending incorrect broadcast packets? In the olden times remote hosts used to be able to send broadcast packets to your subnet, though modern routers and firewalls now typically block such unwelcome traffic. Historically there were not firewalls, and any old host could send most any old thing over the network.
Computers these days often use DHCP or SLAAC in which case there is less chance that the netmask is configured incorrectly, though good arguments can be made for having various hosts set to static IP addresses, and manual configuration could be done wrongly.
Like IPv4, only longer and more awkward and needing new code to do much the same thing. Try sipcalc, among other such tools.
$ sipcalc 2001:db8:d0c::1/64 -[ipv6 : 2001:db8:d0c::1/64] - 0 [IPV6 INFO] Expanded Address - 2001:0db8:0d0c:0000:0000:0000:0000:0001 Compressed address - 2001:db8:d0c::1 Subnet prefix (masked) - 2001:db8:d0c:0:0:0:0:0/64 Address ID (masked) - 0:0:0:0:0:0:0:1/64 Prefix address - ffff:ffff:ffff:ffff:0:0:0:0 Prefix length - 64 Address type - Aggregatable Global Unicast Addresses Network range - 2001:0db8:0d0c:0000:0000:0000:0000:0000 - 2001:0db8:0d0c:0000:ffff:ffff:ffff:ffff
A "one host" mask is /128 and the "all hosts" mask is ::/0 in IPv6.
$ sipcalc 2001:db8:d0c::1/128 -[ipv6 : 2001:db8:d0c::1/128] - 0 [IPV6 INFO] Expanded Address - 2001:0db8:0d0c:0000:0000:0000:0000:0001 Compressed address - 2001:db8:d0c::1 Subnet prefix (masked) - 2001:db8:d0c:0:0:0:0:1/128 Address ID (masked) - 0:0:0:0:0:0:0:0/128 Prefix address - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff Prefix length - 128 Address type - Aggregatable Global Unicast Addresses Network range - 2001:0db8:0d0c:0000:0000:0000:0000:0001 - 2001:0db8:0d0c:0000:0000:0000:0000:0001 - $ sipcalc ::/0 -[ipv6 : ::/0] - 0 [IPV6 INFO] Expanded Address - 0000:0000:0000:0000:0000:0000:0000:0000 Compressed address - :: Subnet prefix (masked) - 0:0:0:0:0:0:0:0/0 Address ID (masked) - 0:0:0:0:0:0:0:0/0 Prefix address - 0:0:0:0:0:0:0:0 Prefix length - 0 Address type - Reserved Comment - Unspecified Network range - 0000:0000:0000:0000:0000:0000:0000:0000 - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff