Преобразование нотации CIDR в диапазон IP-адресов

Мы используем базу данных GeoLite2, чтобы реализовать поиск IP -> страна. По соображениям производительности мы хотим импортировать CSV и преобразовать его в наш собственный формат.

CSV представлен следующим образом:

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

Поэтому нам нужно преобразовать нотацию CIDR (пример: 5.39.40.96/27) в диапазон IP-адресов. (С IP-адреса на IP-адрес)

Как это можно сделать на C #?

Примечание. Это не дубликат этот вопрос, поскольку я спрашиваю о реализации на C #, а не о Java.


person bytecode77    schedule 15.08.2015    source источник


Ответы (2)


Вот один из способов справиться с этим, без использования каких-либо библиотечных функций, чтобы прояснить, что происходит, и помочь, если кому-то позже понадобится реализовать это на других языках.

Код сначала преобразует CIDR в 32-битное число, затем создает маску для определения начального адреса, использует инверсию маски для определения конечного адреса и затем преобразует обратно в формат CIDR.

Обратите внимание, что здесь нет обнаружения ошибок, поэтому ввод должен быть в формате a.b.c.d / m.

Преобразование IP-адреса представляет собой простое соединение четырех октетов в форме прямого байта (AABBCCDD) с использованием битовых сдвигов.

Маска сообщает, сколько битов из самого старшего бита зафиксировано, то есть 32 - это один диапазон IP, а 0 - весь диапазон IP. Таким образом, мы можем взять маску со всеми установленными битами и сдвинуть ее влево с помощью 32-maskbits, чтобы определить фактическую маску.

Если мы установим бит maskbits в ноль, мы получим начало диапазона, поэтому мы И IP с битами маски. Если мы установим биты в единицу, мы получим конец диапазона, поэтому мы выполним операцию ИЛИ с инвертированными битами маски.

Распечатать IP-адрес в формате CIDR снова просто: просто разделите 32-битное значение на октеты и запишите их, разделив их точками.

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));
        }
    }
}

Вывод:

5.39.40.96 - 5.39.40.127

person Sami Kuhmonen    schedule 15.08.2015
comment
Вау, это действительно хороший ответ! Ваш код такой короткий и по существу. +1! - person bytecode77; 15.08.2015
comment
Вместо (mask ^ 0xffffffff) вы можете использовать ~mask, чтобы сделать то же самое. - person Scott Chamberlain; 12.04.2017

Сами Кухмонен, это очень красивый код и серьезно упрощен. Я заметил, что он возвращает идентификатор сети и трансляцию. Однако для тех, кто хочет, чтобы он вернул пригодное для использования адресное пространство. Просто добавьте единицу к начальному IP-адресу и вычтите единицу из конечного IP-адреса.

toip(ipstart + 1) + " - " + toip(ipend -1);
person DemarcPoint    schedule 28.02.2020