Having taught both A+ and Python courses, I have used IP subnetting as a topic to teach some fundamentals about logic. This is an important skill for IT professionals and developers to understand, yet there are so many that have not picked up these concepts.
In this post, I will explain:
- What is subnetting?
- Why do we use a subnet mask?
- How do we use ANDing?
What is Subnetting?
Subnetting is capability of IPv4 addressing that allows us to divide up our address space (or consolidate it in the case of the related concept of supernetting). This divided address space can be used to create separate networks. In IPv4 we are given a 32-bit address space and we have what is known as a variable length subnet mask (VLSM). When we review the addresses, we often read them in dotted-decimal notation (e.g. 192.168.100.152). Each of these separated numbers is an octet, or a byte… 8-bits. 8-bits can be easily represented in many formats, such as:
- Decimal: a value from 0-255
- Hexadecimal: a value from 00 – ff
- Binary: 00000000 – 11111111
Our computers and infrastructure use binary which is what we are going to be looking at.
IPv4 comes in a number of classes, three of which are important to us. There is also some logic behind how we divide up these classes that is often overlooked or glossed over. We determine our classes by reviewing the first octet (e.g. the 192 in 192.168.100.152):
- Class A: the first octet is from 0 – 127
- Class B: the first octet is from 128 – 191
- Class C: the first octet is from 192 – 223
- Class D: the first octet is from 224 – 239
- Class E: the first octet is from 240 – 255
We are concerned with Classes A – C when dealing with subnetting. Class D is for multicast addresses and Class E is an experimental range. With respect to the logic, there is a pattern to why these ranges have been selected. When we convert the addresses to binary, each class has a certain beginning pattern:
- Class A: 0nnnnnnn
- Class B: 10nnnnnn
- Class C: 110nnnnn
- Class D: 1110nnnn
- Class E: 1111nnnn
When we review it, this pattern is what makes the ranges what they are. There are some impossible values in those ranges because of some other rules, such as:
- The first octet cannot be 0
- Nor can it be 255 (in an IP address)
The relevance of the classes are the default subnet masks assigned to each network.
Why Do We Use a Subnet Mask?
The subnet mask is used to divide up which portion of the address represents the network ID and which part is used for the hosts on the network. Class A networks have the most hosts available as they have the remaining 3 octets to be divided up, but they are the most scarce, which only only 128 possible values, minus the reserved networks for localhost (127), and RFC 1918 (10), and the unusable address of 0; its available host space is 2 ^ 24 – 2, or 16,777,214. Class C only uses the final octet for the hosts, which is 2 ^ 8 – 2, or 254. Whereas Class B uses the last two octets for the hosts, which is 2 ^ 16 -2, or 65,534.
The default subnet masks for each Class are:
- Class A: 255.0.0.0 or 11111111.00000000.00000000.00000000
- Class B: 255.255.0.0 or 11111111.11111111.00000000.00000000
- Class C: 255.255.255.0 or 11111111.11111111.11111111.00000000
We can choose to use our host bits for more network bits, which means we give ourselves additional networks by sacrificing some available hosts. Why we would want to do that is beyond the scope of this post.
The purpose of the subnet mask, however, is so that our computers can determine if the destination IP to which we wish to communicate is on our network or not; that is it. If it is on our network, we are free to communicate directly with that destination. If it is not on our network, we need to send it to a gateway or router. Quite commonly, it will just be our default gateway unless we have a more complex routing table.
A Note About Masks
Masks are always consecutive bits. You will never have a mask that is 129, for instance, which would be translated into 10000001, in binary.
With our mask, the decimal values can only be:
- 0: 00000000
- 128: 10000000
- 192: 11000000
- 224: 11100000
- 240: 11110000
- 248: 11111000
- 252: 11111100
- 254: 11111110
- 255: 11111111
Likewise, each octet is used similarly, if the second octet is has any portion of the subnet mask, then the first octet must be 255. Similarly, if the third octet has an portion of the subnet mask, then both the first and second octets each will be 255.
We use the subnet mask to compare the source and destination addresses to determine if they are on the same network.
Let’s consider our example address of 192.168.100.152. If we have a subnet mask of 255.255.255.0, then the first three octets represent the network address, 192.168.100.0. It gets more complicated when the subnet mask does not align directly with an octet. It will be your task to take these skills and apply them to those more complex scenarios.
We determine this by using ANDing.
How Do We Use ANDing?
ANDing is a process from basic logic and logic gates. A full explanation of these processes is beyond the scope of this post, but we have many different basic logic gates that are available to us in logic, some of which are:
AND and OR are very basic and are roughly equivalent to multiplication and addition, respectively (though OR is like addition in binary by keeping the carry and not rolling it over). We are concerned with AND, however.
Let’s look at our example address of 192.168.100.152 and the subnet mask of 255.255.255.0. We need to convert these both to binary:
- IP address: 11000000.10101000.01110000.10011000
- Subnet mask: 11111111.11111111.11111111.00000000
In order to determine what the Network ID is, we need to AND each bit, or multiply them. The result of doing so will leave us with the binary representation of the Network ID. Simply put, we are comparing two values. If both values are 1, then the value is a 1. If either value, or both, are 0, then the value is 0.
I am not going to review the basics of multiplication here. What should be evident is that the 0s at the end mean that we will be fully ignoring the host bits; they will all be 0. We will go through and methodically multiply each bit and the product will be our Network ID:
- 192.168.100.0: 11000000.10101000.01110000.00000000
We do this for the source (ourselves) and the destination. If the Network IDs are not the same, we are on different networks and we need to send the packet to the appropriate next hop in our routing table; if it is the default routing table on a host, then it will be the default gateway.
So, all of this logic is to arrive at an answer to a seemingly simple question of:
Is the destination on my network, or not?
I created some tools that work through this logic:
- Excel spreadsheet
- Python function: link to Gist to follow shortly
- PowerShell function: list to Gist to follow shortly