C# 如何使用 CIDR 表示法查看 IP 地址是否属于 IP 范围内?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9622967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 08:14:16  来源:igfitidea点击:

How to see if an IP address belongs inside of a range of IPs using CIDR notation?

c#ipcidr

提问by Only Bolivian Here

Here I have a static reference the ranges I need to check:

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

private static List<string> Ip_Range = new List<string>()
{
    "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"
};

Here's some pseudo code on how I see it working:

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

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

Any suggestions on how to code up this functionality?

关于如何编写此功能的任何建议?

采纳答案by Only Bolivian Here

Decided to answer my own question so people can benefit. If it can be improved, please do!

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

I used the IPNetwork libraryand it worked out fantastically! Below is the code I used:

我使用了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<string> Bolivia_Ip_Range = new List<string>()
    {
        "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"
    };
}

回答by Tony The Lion

If you understand the CIDR notation, you can easily do the math in your parse method.

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

You basically know that an IPv4 address is 32bits long and that the CIDR notation means that the number of bits behind the "/" are the network address bits (ie the masked out bits), therefore the leftover bits are represent the number of hosts in the subnet.

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

From wikipedia article:

来自维基百科文章

The number of addresses of a subnet defined by the mask or prefix can be calculated as 2address size - prefix size, in which the address size for IPv6 is 128 and 32 for IPv4. For example, in IPv4, a prefix size of /29 gives: 232-29 = 23 = 8 addresses.

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

So you could (no I'm not going to work out the details for you) convert your addresses into binary and do the binary ANDwith the given mask (also in binary form), then you have the network address part of the IP address left, which should match with whatever address you're checking against to see if it's in a particular subnet.

所以你可以(不,我不会为你计算细节)将你的地址转换成二进制并使用给定的掩码(也是二进制形式)执行二进制 AND,然后你就有了 IP 地址的网络地址部分左边,它应该与您检查的任何地址相匹配,以查看它是否在特定子网中。

回答by M.Babcock

Luckily most of the work has already been done for you (so we don't have to). Check out the IPNetworkproject. You'll parse all of your CIDR addresses with IPNetwork.Parse. Then to see if a specific IPAddressis in range just use IPNetwork.Containsmethod.

幸运的是,大部分工作已经为您完成(所以我们不必这样做)。查看IPNetwork项目。您将使用IPNetwork.Parse. 然后查看特定对象IPAddress是否在范围内,只需使用IPNetwork.Contains方法。



I got bored so here's a method you can use to test whether an IP address is in range or not:

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

private Dictionary<string, IPNetwork> 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)));
}

This is dependent on the Ip_Rangelist from your question but translates them to IPNetworkinstances (missing sanity checks for brevity).

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

Usage:

用法:

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

Test Output:

测试输出:

12.144.86.1: True
10.254.6.172: False

Of course there is still a lot that could (and probably should) be done with it, but this proves the concept.

当然,还有很多事情可以(并且可能应该)用它来完成,但这证明了这个概念。

回答by RePRO

For start, you should use that:

首先,您应该使用它:

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

Output

输出

CIDR: 29

回答by ObiWan

If you don't want/can't add another library (as the IPnetwork one) to your project and just need to deal with IPv4 CIDR ranges, here's a quick solution to your problem

如果您不想/不能向您的项目添加另一个库(如 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));
}

the above will allow you to quickly check if a given IPv4 address falls inside a given CIDR range; notice that the above code is barebone, it's up to you to check if a given IP (string) and CIDR range are correct before feeding them to the function (you may just use the tryparse or whatever...)

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

回答by Dynamic

I use the below method to determine whether a given IP Address is a public one or private/internal:

我使用以下方法来确定给定的 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);
    }

回答by Алексей Сидоров

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