Netmasks

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

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.)

IPv4

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

One Host Mask

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

All Hosts Mask

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

Legacy Classes

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.

IPv6

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