I recently noticed that my own knowledge of CIDR and ip-addresses was smaller than I thought, not that I don’t
understand the basics, but rather the more… deep info.
CIDR’s have been an issue in my head, as I naturally fall back to thinking that higher numbers means more, not less…
But thanks to some reading I now have an easier time to think right! And now I thought I’d try to enlighten you as well!
Wtf is CIDR
So, CIDR (Classless Inter-Domain Routing) is a concept for ip addresses and routing. It’s not new, first introduction was back in 1993, so most of us have probably heard of it or used the notation we are talking about here before, even though we might not really have thought too much about it.
When we define ip-ranges, we often use what is called “cidr notation”, and it looks something like this:
Where the first part (prefix) is the IP-Address and the last part (suffix) is the size of the range.
This notation is what I will try to explain in this post, it will get quite a bit technical, as it have a lot to do with bits and all that fun stuff, but bare with me and I’ll hopefully explain it in an easy way so that we all become experts on ip ranges (cause that’s totally what we all want!).
IP Addresses (oh no bits and bytes!)
So, an IP address is basically a 32 bit integer. In this section I will focus on specific addresses and not ranges, as
an address makes use of the full integer (I will explain this a bit more later).
We will use the IP Address 192.168.0.1 in this description, a very common private IP address and probably used by one or many of the routers that we use daily!
So, how can a 4-part dot-notation IP-address be a 32 bit integer value? Well, it’s quite simple…
All data types in their most basic form consists of bits. A bit is either on or off (0 or 1), when a data type is 32 bits it contains 32 0’s or 1’s which can be changed to on or off to set the specific value. How it’s displayed to us humans is just to make it easier to read.
So, a 32 bit integer can easily be split up in four parts, where each part is 8 bit (a byte), and that’s basically what an ip-address is:
 byte one,
 byte two,
 byte three and
 byte four. Even if the value in the byte is smaller than what a full byte can use
it still have to take up a full byte for it to not be confusing for the machine reading it.
Each byte is - as said - 8 bits, so:
00000000 equals 0, all bits are off.
00000001 equals 1, all but one bit is off.
If we want the value 192, we get the bit value 11000000, and the full value 11111111 is naturally 255.
Putting the whole thing together, we got 4 byte units which for our IP-Address would look like this:
... or 192.168.0.1
An ip range still utilizes the bit that we use in the IP-Addresses, but we basically add on some values at the end of the 32 bit construct.
Depending on the size (in actual bits) of the range suffix, we make the prefix (the available ip-address) smaller or larger.
If we add 0 bit’s to the range, we have the whole net in an integer, it can range from 0.0.0.0 to 255.255.255.255, quite a large range.
If we add 1 bit (which is 1), we have halved the full range of the network 0.0.0.0 to 127.255.255.255.
Each new bit we add (say /4, 0100), will remove a chunk of the available addresses in the prefix, making it smaller and smaller, until we hit the bare minimum of a /32 which only allows for a single IP-Address in the range.
Writing 192.168.0.1/32 is essentially the same as writing 192.168.0.1 but in CIDR notation.
So the sizes in a CIDR notated range is “easily” calculated as a backwards pow2:
|32||1||2 ⁽³² ⁻ ³²⁾|
|31||2||2 ⁽³² ⁻ ³¹⁾|
|30||4||2 ⁽³² ⁻ ²⁹⁾|
|29||8||2 ⁽³² ⁻ ³¹⁾|
|28||16||2 ⁽³² ⁻ ³⁰⁾|
Now, you might think, but I can basically write 192.168.255.255/16 and that should just create some odd crazyness!
Well no. The /16 shifts away the first two bytes (8 + 8) making it basically say 192.168.0.0/16.
So when you overflow too far, say 192.168.0.0/4, you will lose the last 3 bytes, go lower than 2 and you will loose even more!
So, the CIDR notation keeps being a 32 bit value.
For ip 192.168.0.0
|32||1||192.168.0.0 - 192.168.0.0|
|31||2||192.168.0.0 - 192.168.0.1|
|30||4||192.168.0.0 - 192.168.0.3|
|29||8||192.168.0.0 - 192.168.0.7|
|28||16||192.168.0.0 - 192.168.0.15|
|16||65536||192.168.0.0 - 192.168.255.255|
|8||16777216||192.0.0.0 - 18.104.22.168|
|4||268435456||192.0.0.0 - 22.214.171.124|
|1||2147483646||126.96.36.199 - 255.255.255.255|
|0||4294967296||0.0.0.0 - 255.255.255.255|
So, why would we care? When will we ever use CIDR?
Well, I can’t really speak for everyone, but if you are interested in stuff like kubernetes, or wish to set up a VPN or even a few VPS’es on your favorite provider, it might actually be quite good to know the basics!
When you set up a kubernetes pod-network (with one of the network plugins that exists), it’s often possible (if not even needed!) to define your own pod and/or service network. It’s quite good to make sure that the network does not match up with the network that the machines communicate over!
Even your own home router might be a place where this could be needed. I personally have multiple sub-networks on my router, 192.168.0.0/20 is my main network, 192.168.16.0/20 could for example be a network space allocated for my guests, while I use 192.168.32.0/20 for my infrastructure through a VPN tunnel!
So, I wrote this blog post mainly during research of VPN for one of my customers, it’s quite fun and also quite advanced stuff on a first
glance, while after reading a bit, it makes a lot more sense.
If you read this and find any obvious errors or think that I misinterpreted anything, let me know! I’m not that awesome with bitstuff so it’s for sure not impossible that I missed something!