按定义的限制减少 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,因为这些提供商通常在特定范围内移动。
我得到了以下实现来将一堆 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,因为这些提供商通常在特定范围内移动。