Список IP-адресов С# для возможной нотации CIDR?

Существует преобразование нотаций CIDR в диапазоны IP-адресов, связанное с публикацией. Мне нужна инверсия этого. Мне нужно сжать множество IP-адресов в нотацию CIDR, если это возможно.

Пример ввода:

192.168.0.0
192.168.0.1 
.. 
..
192.168.0.255
192.168.2.4
192.168.3.8

Пример вывода:

192.168.0/24
192.168.2.4
192.168.3.8

Поскольку 192.168.2.4 и 192.168.3.8 не могут быть представлены в нотации CIDR, их можно перечислить как есть.

Я знаю, что это трудно для этого. Поскольку нотация CIDR имеет разный размер блоков. Но, по крайней мере, как я могу сжать свой список с блоком C (256 IP-адресов)?

Я попытаюсь сделать это с помощью С# linq.


person akdora    schedule 08.12.2015    source источник


Ответы (2)


Я думаю, что без кодирования трудно обойтись. Вот моя попытка написать CidrCompressor. Вызовите Add() для каждого IP-адреса, а затем получите сжатый список, используя свойство IpList.

public class CidrCompressor
{    
    private readonly Regex _subnetRegex = new Regex(@"^(?<net>\d+\.\d+\.\d+)\.0$", RegexOptions.Compiled); 
    private Regex _currentNetRegex;
    private string _currentNet;
    private int _lastSubIp;

    private List<string> _ipList = new List<string>();

    private void AddReceivedInSubnet()
    {
        for (var i = 0; i < _lastSubIp; ++i)
        {
            _ipList.Add(string.Format("{0}.{1}", _currentNet, i));
        }
        _currentNetRegex = null;
    }

    public void Add(string ip)
    {
        var m = _subnetRegex.Match(ip);
        if (m.Success)
        {
            // Matches *.0
            // Start matching subnet
            _currentNet = m.Groups["net"].Value;
            _currentNetRegex = new Regex(string.Format(@"^{0}\.(?<subIp>\d+)$", _currentNet));          
            _lastSubIp = 0;
        }
        else if (_currentNetRegex != null)
        {
            // Currently matching a subnet
            m = _currentNetRegex.Match(ip);

            if (m.Success)
            {
                var subIp = int.Parse(m.Groups["subIp"].Value);

                if (subIp == _lastSubIp + 1)
                {
                    // See if we have received a full subnet
                    if (subIp == 255)
                    {
                        _ipList.Add(_currentNet + "/24");
                        _currentNetRegex = null;                    
                    }
                    else
                    {
                        _lastSubIp = subIp;
                    }
                }
                else
                {
                    // Not continuous so add indivudial IPs
                    AddReceivedInSubnet();
                    Add(ip);
                }
            }
            else
            {
                // Received IP in different net before .255
                // Add all IPs received
                AddReceivedInSubnet();

                // Process ip we received
                Add(ip);
            }
        }
        else
        {
            _ipList.Add(ip);
        }
    }

    public IEnumerable<string> IpList 
    {
        get
        {
            return _ipList;
        }
    }
}
person Krister Renaud    schedule 08.12.2015
comment
Спасибо, Кристер, но ваше решение кажется сложным. Я напишу свое решение ниже. - person akdora; 08.12.2015

Я нашел решение для нотации CIDR блока C, но оно предназначено для ТОЛЬКО блока C. не для всех блоков.

    public static List<string> IpListToCIDR(List<string> ipList)
    {
        //Suanda sadece C blok icin yazilmistir. Ileride gelistirilebilir
        //result list
        List<string> compressedList = new List<string>();

        //group ip addresses
        var cidrList = ipList.GroupBy(o => new
                            {
                               GrpKey = o.Substring(0, o.LastIndexOf('.'))
                            })
                            .Select(g => new
                            {
                                IpSubnet = g.Key.GrpKey,
                                Count = g.Count()
                            })
                            .Where(m => m.Count >= 255)
                            .ToList();
        //exclude grouped list
        var excludeList = (from a in ipList
                           join c in cidrList on a.Substring(0, a.LastIndexOf('.')) equals c.IpSubnet
                           select a).ToList();

        //add C block CIDR list
        compressedList.AddRange(cidrList.Select(m => m.IpSubnet + ".0/24").ToList());
        //add rest of them
        compressedList.AddRange(ipList.Where(m=> !excludeList.Contains(m)).ToList());

        return compressedList;
    }
person akdora    schedule 08.12.2015