We are using the GeoLite2 database in order to implement an IP -> country lookup. For performance reasons, we want to import the CSV and convert it to our own format.
The CSV is represented like this:
5.39.40.96/27,3017382,3017382,,0,0
5.39.40.128/28,3017382,3017382,,0,0
5.39.40.144/28,2635167,3017382,,0,0
5.39.40.160/27,3017382,3017382,,0,0
5.39.40.192/26,3017382,3017382,,0,0
5.39.41.0/25,3017382,3017382,,0,0
5.39.41.128/26,3017382,3017382,,0,0
5.39.41.192/26,2635167,3017382,,0,0
5.39.42.0/24,3017382,3017382,,0,0
5.39.43.0/25,3017382,3017382,,0,0
So we need to convert the CIDR notation (example: 5.39.40.96/27
) into an IP address range. (From IP - To IP)
How can this be done in C#?
Note: This is not a duplicate of this question, since I'm asking about a C# implementation and not Java.
The formula to calculate the number of assignable IP address to CIDR networks is similar to classful networking. Subtract the number of network bits from 32. Raise 2 to that power and subtract 2 for the network and broadcast addresses. For example, a /24 network has 232-24 - 2 addresses available for host assignment.
How many addresses does a CIDR block represent? You calculate 2 32-prefix , where prefix is the number after the slash. For example, /29 contains 232-29=23=8 addresses.
Class B IP addresses range from 128.0.0.0 to 191.255.255.255 , with a default subnet mask of 255.255.0.0 (or /16 in CIDR). Class B addressing can have 16,384 (214) network addresses and 65,534 (216) usable addresses per network.
Here is one way to handle it, without using any library functions to make it clear what's happening and to help if someone needs to implement it in other languages later on.
The code first converts the CIDR into a 32bit number, then creates the mask to determine the start address, uses the inverse of the mask to determine the end address and then converts back to CIDR format.
Note that there is no error detection so the input must be in the a.b.c.d/m format.
The conversion of the IP address is just a simple concatenation of the four octets in big endian form (AABBCCDD) using bit shifts.
The mask tells how many bits from the most significant bit are fixed, meaning 32 is a single IP range and 0 would be the whole IP range. Thus we can take a mask with all bits set and shift it left with 32-maskbits
to determine the actual mask.
If we set the maskbits
bits to zero, we get the beginning of the range, so we AND the IP with maskbits. If we set the bits to one, we get the end of the range, so we will OR with the negated bits of mask.
Printing the IP address in CIDR format is again simple: just split the 32bit value into octets and write them separated with dots.
using System;
namespace CSTests
{
class Program
{
static string toip(uint ip)
{
return String.Format("{0}.{1}.{2}.{3}", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
}
static void Main(string[] args)
{
string IP = "5.39.40.96/27";
string[] parts = IP.Split('.', '/');
uint ipnum = (Convert.ToUInt32(parts[0]) << 24) |
(Convert.ToUInt32(parts[1]) << 16) |
(Convert.ToUInt32(parts[2]) << 8) |
Convert.ToUInt32(parts[3]);
int maskbits = Convert.ToInt32(parts[4]);
uint mask = 0xffffffff;
mask <<= (32 - maskbits);
uint ipstart = ipnum & mask;
uint ipend = ipnum | (mask ^ 0xffffffff);
Console.WriteLine(toip(ipstart) + " - " + toip(ipend));
}
}
}
Output:
5.39.40.96 - 5.39.40.127
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With