按定义的限制减少 cidrs 列表

Reduce list of cidrs by a defined limit

我得到了以下实现来将一堆 ip 解析为多个 cidr 范围。我最多只能喝 50 杯苹果酒。我需要以某种方式添加该限制。我正在考虑计算每个 cidr 之间的距离以将它们分组,直到我在某种递归算法中达到 50 个限制。

有什么建议吗?

    public static IEnumerable<string> Parse(IEnumerable<string> ipCollection)
    {
        var ips = ipCollection as IList<string> ?? ipCollection.ToList();

        if (!ips.Any()) return Enumerable.Empty<string>();

        var parsedIps = new List<IPNetwork>();

        foreach (var ip in ips)
        {
            IPNetwork ipNetwork;
            if (IPNetwork.TryParse(ip, out ipNetwork)) parsedIps.Add(ipNetwork);
        }

        // unable to parse any ips
        if (!parsedIps.Any()) return Enumerable.Empty<string>();

        return parsedIps.Count == 1
            ? ips.Select(ip => $"{ip}/32")
            : IPNetwork.Supernet(parsedIps.ToArray()).Select(x => x.ToString());
    }

响应即:

新的希望

我找到了生成 cidr 的更好方法。我使用的方法是按提供的 ips 的前两个八位字节分组,因为提供商总是有这些 ips 的范围。

    public static IEnumerable<string> Parse(IEnumerable<string> ipCollection)
    {
        var parsedIpAddresses = new List<IPAddress>();

        ipCollection.ForEach(ip =>
        {
            IPAddress validIp;
            if (IPAddress.TryParse(ip, out validIp)) parsedIpAddresses.Add(validIp);
        });

        return SplitCidrs(parsedIpAddresses);
    }

    private static IEnumerable<string> SplitCidrs(List<IPAddress> ips)
    {
        var cidrs = new List<IPNetwork>();

        foreach (var mask in GetOrderedMasks(ips))
        {
            var filterIps = ips.Where(
                    x => x.ToString().StartsWith(mask)
                )
                .OrderBy(x => x.Address)
                .Select(x => x.ToString())
                .ToList();

            var newCidr = IPNetwork.WideSubnet(filterIps.First(), filterIps.Last());

            if (!cidrs.Contains(newCidr))
            {
                cidrs.Add(newCidr);
            }

            if (cidrs.Count >= AwsSgLimit - 1)
            {
                throw new AmazonSgLimitReached();
            }
        }

        return cidrs.Select(x => x.ToString());
    }

    private static IEnumerable<string> GetOrderedMasks(IEnumerable<IPAddress> ips)
    {
        return ips
            .Where(x => !x.ToString().StartsWith("10."))
            .GroupBy(
                x => string.Join(".", x.GetAddressBytes().Take(2))
            )
            .OrderByDescending(x => x.Count())
            .Select(group => group.Key.ToString() + ".");
    }

测试

在下面的算法中,我使用了一种完全不同的方法,我已经对不同的 IP 群体进行了测试。在其中一项测试中,我将 55 个不一致的 ip(记住我的限制是 50 个 cidr)传递给函数,使用上面的原始代码最终返回非常宽的 cidr(/8、/16)。使用新算法,我只得到 /32,这是 100% 优化更新。我知道有 5 个被浪费了,但这种情况在 Internet 提供商子网环境下并不真实。

第二次测试,我又通过了真实的生产数据。结果非常好,因为 我摆脱了 所有的“/7”和九个“/8”(1.61 亿个 ips现在我只有一个“/16”(65k ips)作为最差的cidr。考虑到这是真实数据,这也是一个巨大的改进,我基本上得到了相同的结果。

其余的是真实范围,但仍然很小(21、24、28)和孤立的 ips (32)。仍有改进的空间,因为我们没有达到 50 x 28 个免费插槽的 AWS 限制。

结果

结论

我绝对推荐此算法根据特定提供商分配的 ip 生成 cidr,因为这些提供商通常在特定范围内移动。