如何使用CIDR表示法查看IP地址是否属于一系列IP?

这里我有一个静态参考我需要检查的范围:

private static List Ip_Range = new List() { "12.144.86.0/23", "31.201.1.176/30", "46.36.198.101/32", "46.36.198.102/31", "46.36.198.104/31", "46.136.172.0/24", "63.65.11.0/24", "63.65.12.0/25", "63.65.12.128/26", "63.65.12.192/27", "63.65.12.224/28", "63.65.12.240/29", "63.65.12.248/30", "63.65.12.252/31", "63.65.12.254/32", "65.173.56.0/21", "67.23.241.179/32", "67.23.241.180/30", "67.23.241.184/29", "67.23.241.192/30", "67.23.241.196/31", "67.23.241.198/32", "72.32.164.56/29", "72.46.244.32/28", "74.91.16.48/29", "74.91.16.208/29", "74.91.20.48/28", "74.91.20.64/29", "74.112.134.120/29", "74.112.135.104/29", "74.205.37.16/29", "78.24.205.32/28", "98.129.27.88/29", "98.129.91.40/29", "166.114.0.0/16", "167.157.0.0/16", "174.143.165.80/29", "186.0.156.0/22", "186.2.0.0/17", "186.27.0.0/17", "190.0.248.0/21", "190.3.184.0/21" }; 

这是我看到它如何工作的一些伪代码:

 public static bool IpIsWithinRange(string ip) //Something like 127.0.0.1 or 184.56.26.35 { IPAddress incomingIp = IPAddress.Parse(ip); foreach (var subnet in Ip_Range) { IPAddress sub = IPAddress.Parse(subnet); ????? if (incomingIp "is in" sub) ? return true; } return false; } 

有关如何编写此function的任何建议?

如果您不想/不能将另一个库(作为IPnetwork)添加到您的项目中,只需要处理IPv4 CIDR范围,这里就是您的问题的快速解决方案

 // true if ipAddress falls inside the CIDR range, example // bool result = IsInRange("10.50.30.7", "10.0.0.0/8"); private bool IsInRange(string ipAddress, string CIDRmask) { string[] parts = CIDRmask.Split('/'); int IP_addr = BitConverter.ToInt32(IPAddress.Parse(parts[0]).GetAddressBytes(), 0); int CIDR_addr = BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0); int CIDR_mask = IPAddress.HostToNetworkOrder(-1 << (32 - int.Parse(parts[1]))); return ((IP_addr & CIDR_mask) == (CIDR_addr & CIDR_mask)); } 

以上将允许您快速检查给定的IPv4地址是否属于给定的CIDR范围; 注意上面的代码是准系统的,你可以在将它们提供给函数之前检查给定的IP(字符串)和CIDR范围是否正确(你可以使用tryparse或其他......)

决定回答我自己的问题,这样人们就可以受益。 如果可以改进,请做!

我使用了IPNetwork库 ,它运行得非常好! 以下是我使用的代码:

 using System.Net; public static class RedirectHelpers { public static bool IpIsWithinBoliviaRange(string ip) { IPAddress incomingIp = IPAddress.Parse(ip); foreach (var subnet in Bolivia_Ip_Range) { IPNetwork network = IPNetwork.Parse(subnet); if (IPNetwork.Contains(network, incomingIp)) return true; } return false; } private static List Bolivia_Ip_Range = new List() { "12.144.86.0/23", "31.201.1.176/30", "46.36.198.101/32", "46.36.198.102/31", "46.36.198.104/31", "46.136.172.0/24", "63.65.11.0/24", "63.65.12.0/25", "63.65.12.128/26", "63.65.12.192/27", "63.65.12.224/28", "63.65.12.240/29", "63.65.12.248/30", "63.65.12.252/31", "63.65.12.254/32", "65.173.56.0/21", "67.23.241.179/32", "67.23.241.180/30", "67.23.241.184/29", "67.23.241.192/30", "67.23.241.196/31", "67.23.241.198/32", "72.32.164.56/29", "72.46.244.32/28", "74.91.16.48/29", "74.91.16.208/29", "74.91.20.48/28", "74.91.20.64/29", "74.112.134.120/29", "74.112.135.104/29", "74.205.37.16/29", "78.24.205.32/28", "98.129.27.88/29", "98.129.91.40/29", "166.114.0.0/16", "167.157.0.0/16", "174.143.165.80/29", "186.0.156.0/22", "186.2.0.0/17", "186.27.0.0/17", "190.0.248.0/21", "190.3.184.0/21", "166.114.0.0/16", "167.157.0.0/16", "186.2.0.0/18", "190.11.64.0/20", "190.11.80.0/20", "190.103.64.0/20", "190.104.0.0/19", "190.107.32.0/20", "190.129.0.0/17", "190.181.0.0/18", "190.186.0.0/18", "190.186.64.0/18", "190.186.128.0/18", "200.7.160.0/20", "200.58.64.0/20", "200.58.80.0/20", "200.58.160.0/20", "200.58.176.0/20", "200.75.160.0/20", "200.85.128.0/20", "200.87.0.0/17", "200.87.128.0/17", "200.105.128.0/19", "200.105.160.0/19", "200.105.192.0/19", "200.112.192.0/20", "200.119.192.0/20", "200.119.208.0/20", "201.222.64.0/19", "201.222.96.0/19" }; } 

幸运的是,大部分工作已经完成(所以我们没有)。 查看IPNetwork项目。 您将使用IPNetwork.Parse解析所有CIDR地址。 然后,查看特定IPAddress是否在范围内,只需使用IPNetwork.Contains方法。


我觉得无聊,所以这里有一个方法可以用来测试IP地址是否在范围内:

 private Dictionary netCache = null; public bool IsInRange(string ipAddress) { if (netCache == null) netCache = Ip_Range.ToDictionary((keyItem) => keyItem, (valueItem) => IPNetwork.Parse(valueItem)); return netCache.Values.Any(net => IPNetwork.Contains(net, IPAddress.Parse(ipAddress))); } 

这取决于您问题中的Ip_Range列表,但IPNetwork它们转换为IPNetwork实例(为简洁起见,缺少完整性检查)。

用法:

 List addrList = new List { "12.144.86.1", "10.254.6.172" }; addrList.ForEach(addr => Console.WriteLine("{0}: {1}", addr, IsInRange(addr))); 

测试输出:

 12.144.86.1: True 10.254.6.172: False 

当然,仍然有很多可以(也可能应该)用它完成,但这certificate了这个概念。

如果您了解CIDR表示法,则可以轻松地在解析方法中进行数学运算。

您基本上知道IPv4地址长度为32位,CIDR表示法意味着“/”后面的位数是网络地址位(即屏蔽输出位),因此剩余位代表的是主机数量。子网。

来自维基百科文章 :

掩码或前缀定义的子网地址数可以计算为2地址大小 – 前缀大小,其中IPv6的地址大小为128,IPv4的地址大小为32。 例如,在IPv4中,前缀大小为/ 29给出:232-29 = 23 = 8个地址。

所以你可以(不,我不打算为你详细说明)将你的地址转换为二进制文件并使用给定的掩码(也是二进制forms)进行二进制AND ,然后你有IP地址的网络地址部分left,它应与您要检查的任何地址匹配,以查看它是否在特定子网中。

首先,您应该使用:

 IPNetwork ipnetwork = IPNetwork.Parse("192.168.168.100/29"); Console.WriteLine("CIDR: {0}", ipnetwork.Cidr); 

产量

 CIDR: 29 
  public static bool IpIsInRange(string subnet, string ip) { var splitSubnet = subnet.Split('/'); var maskBits = 32 - int.Parse(splitSubnet[1]); if (maskBits == 32) { return true; } var subnetIp = BitConverter.ToInt32(IPAddress.Parse(splitSubnet[0]).GetAddressBytes().Reverse().ToArray(), 0) >> maskBits << maskBits; var clientIp = BitConverter.ToInt32(IPAddress.Parse(ip).GetAddressBytes().Reverse().ToArray(), 0) >> maskBits << maskBits; return subnetIp == clientIp; } 

我使用以下方法来确定给定的IP地址是公共IP地址还是私有/内部地址:

 private bool IsInternalIpAddress(string ipAddress) { // notes: http://whatismyipaddress.com/private-ip var internalIpRanges = Enumerable .Range(16, 31) .Select(i => "172.{0}.".FormatWith(i)) .Concat(new[] {"192.168.", "10.", "127."}) .ToArray(); return ipAddress.StartsWith(internalIpRanges); }