During the next interview I was asked a small test task, write a network open port scanner on Go. The task is not difficult in principle, but one of the conditions was that, as a parameter, both the IP address and the range of network addresses in the form of a network mask can be transferred: 192.168.8.0/21.
The topic is likely to be very trivial for network engineers and administrators, and probably even boring. My goal is simply to state here the algorithm for converting an IP range to a network mask (hereinafter referred to as CIDR) and back from CIDR to an address range.
A bit of theory, but those who are already familiar with the terms can be skipped and go directly to the algorithm.
')
And so, what is IP, I think everyone understands and does not need to explain. Now what is CIDR (or network mask). Imagine that we have an IP: "192.168.11.10." In fact, these are 8-bit values ββseparated by dots, and each individual part is a so-called
octet . It is clear that IP can be represented as a 32-bit number.

It is this number that is transmitted in the IP packet. Now let's imagine that we have a subnet consisting of 8 hosts - 192.168.11.0 to 192.168.11.7 (Note: 192.168.11.0 cannot be used as the address of any network interface, since this address is used as a subnet identifier, therefore, in fact will be 7, but for our example it does not matter yet.)
It is clear that there can be several subnets within one large network and you need to send a packet inside your subnet directly, but let's say if a packet needs to be sent to another subnet allowed on IP: 192.168.11.22, then it needs to be sent to the network router, which will forward this packet to another subnet. It is expensive and pointless to store all the addresses of your subnet on the sender's host, so we just store the network mask and for the above designated network of 8 hosts it will be equal to - 255.255.255.248. Now, if we decompose the network mask into bits, we get 29 ones and 3 zeros.

The subnet mask can never mix β1β and β0β; therefore, the sequence β1β always goes first, and then the sequence β0β. Now the range above the designated addresses 192.168.11.0 to 192.168.11.7, can be represented as <IP address of the subnet> / <Subnet mask>, i.e. 192.168.11.0/29. This is Classless Addressing or Classless Inter-Domain Routing (CIDR) and any range of IP addresses can be represented in this compact form. Regarding proper subnetting and routing, it makes sense to refer to specialized literature and is not the purpose of this article - I hope network administrators will forgive me.
And so the algorithm itself with comments is given below. At once I will say that for the range 216.58.192.12 - 216.58.192.206, there is no possibility to split it into one subnet and the algorithm will immediately divide the range into several subnets:
{
"216.58.192.12/30",
"216.58.192.16/28",
"216.58.192.32/27",
"216.58.192.64/26",
"216.58.192.128/26",
"216.58.192.192/29",
"216.58.192.200/30",
"216.58.192.204/31",
"216.58.192.206/32"
}
Convert IPv4 range into CIDR Now for the reverse algorithm, when you need to transfer the same classless addressing range back to IP. Personally, in my test task, this algorithm was not needed and perhaps one of the network administrators will comment on how much it is needed in real life, but I decided to write both of them at once. Algorithm to elementary is simple, you must add its dimension in the initial IP subnet.
Convert CIDR to IPv4 range Note: only for Go developers: the algorithm can be made even more productive if you return data in the format - (IP, * IPNet, error), but for universality I return the data as a string.
The network scanner code is here:
GitHub . If you put a star, I will be grateful, but only if I deserve it :))
References: