【问题标题】:How to compare IP address range in C#?如何比较 C# 中的 IP 地址范围?
【发布时间】:2012-05-18 12:36:56
【问题描述】:

如果我有一个 IP 地址范围(CIDR 表示法)并且我需要知道某个任意 IP 地址是否在该范围内 - 都以字符串形式呈现 - 使用 C# 执行此操作的最简单方法是什么?

例子:

  • IPv4 范围:192.168.168.100/24,要检查的 IP:192.168.168.200
  • IPv6 范围:fe80::202:b3ff:fe1e:8329/24,要检查的 IP:2001:db8::

【问题讨论】:

  • 您是否有兴趣查看仅 IPv4 的解决方案?
  • 没有。 ipv4 很简单。使其具有挑战性的是 ipv6,或者当这两种格式混合时。从这里没有回应来看,似乎没有多少人关心它……

标签: c# ipv6 ipv4 cidr


【解决方案1】:

这是一个简单的类:

public class IPSubnet
{
    private readonly byte[] _address;
    private readonly int _prefixLength;

    public IPSubnet(string value)
    {
        if (value == null)
            throw new ArgumentNullException("value");

        string[] parts = value.Split('/');
        if (parts.Length != 2)
            throw new ArgumentException("Invalid CIDR notation.", "value");

        _address = IPAddress.Parse(parts[0]).GetAddressBytes();
        _prefixLength = Convert.ToInt32(parts[1], 10);
    }

    public bool Contains(string address)
    {
        return this.Contains(IPAddress.Parse(address).GetAddressBytes());
    }

    public bool Contains(byte[] address)
    {
        if (address == null)
            throw new ArgumentNullException("address");

        if (address.Length != _address.Length)
            return false; // IPv4/IPv6 mismatch

        int index = 0;
        int bits = _prefixLength;

        for (; bits >= 8; bits -= 8)
        {
            if (address[index] != _address[index])
                return false;
            ++index;
        }

        if (bits > 0)
        {
            int mask = (byte)~(255 >> bits);
            if ((address[index] & mask) != (_address[index] & mask))
                return false;
        }

        return true;
    }
}

示例用法:

Console.WriteLine(new IPSubnet("192.168.168.100/24").Contains("192.168.168.200")); // True
Console.WriteLine(new IPSubnet("fe80::202:b3ff:fe1e:8329/24").Contains("2001:db8::")); // False

此类将所有 IPv4 地址与所有 IPv6 地址区别对待,不尝试在 IPv4 和 IPv6 之间进行转换。

【讨论】:

  • 谢谢。例如,虽然 IPv4 应转换为 IPv6,但可以使用“::192.168.168.100”,您的代码会将其视为 IPv6。
  • 您确定将 IPv4 地址转换为 IPv6 只需在其前面加上“::”前缀是正确的吗? IPv6 address Wikipedia 文章并未将此列为 IPv4 转换机制之一。
  • 抱歉耽搁了。我在网上找到的,如果你搜索“将 IPv4 转换为 IPv6”。所以我不知道...
【解决方案2】:

【讨论】:

  • 好吧,太糟糕了,因为不太清楚如何进行这种比较。例如,如果范围是 ipv6 表示法但地址是 ipv4,反之亦然怎么办?同样,仅将子网掩码应用于 ipv6 地址也不清楚。而且网上也没有太多的例子……
  • 我不确定你的意思? IPv4 和 IPv6 是两个完全不同的东西。没有 IPv4 将采用 IPv6 表示法。我不会将 ::192.168.1.1 与其他 IPv6 地址相同。
【解决方案3】:

我建议使用 IPNetwork 库https://github.com/lduchosal/ipnetwork。 从版本 2 开始,它也支持 IPv4 和 IPv6。

IPv6

  IPNetwork ipnetwork = IPNetwork.Parse("fe80::202:b3ff:fe1e:8329/24");

  IPAddress ipaddress = IPAddress.Parse("2001:db8::");
  IPAddress ipaddress2 = IPAddress.Parse("fe80::202:b3ff:fe1e:1");

  bool contains1 = IPNetwork.Contains(ipnetwork, ipaddress);
  bool contains2 = IPNetwork.Contains(ipnetwork, ipaddress2);

  Console.WriteLine("{0} contains {1} : {2}", ipnetwork, ipaddress,     contains1);
  Console.WriteLine("{0} contains {1} : {2}", ipnetwork, ipaddress2,     contains2);

输出

   fe80::/24 contains 2001:db8:: : False
   fe80::/24 contains fe80::202:b3ff:fe1e:1 : True

IPv4

  IPNetwork ipnetwork = IPNetwork.Parse("192.168.168.100/24");

  IPAddress ipaddress = IPAddress.Parse("192.168.168.200");
  IPAddress ipaddress2 = IPAddress.Parse("192.168.0.200");

  bool contains1 = IPNetwork.Contains(ipnetwork, ipaddress);
  bool contains2 = IPNetwork.Contains(ipnetwork, ipaddress2);

  Console.WriteLine("{0} contains {1} : {2}", ipnetwork, ipaddress, contains1);
  Console.WriteLine("{0} contains {1} : {2}", ipnetwork, ipaddress2, contains2);

输出

  192.168.168.0/24 contains 192.168.168.200 : True
  192.168.168.0/24 contains 192.168.0.200 : False

玩得开心!

【讨论】:

    猜你喜欢
    • 2014-03-06
    • 1970-01-01
    • 2014-04-06
    • 2010-11-04
    • 1970-01-01
    • 2010-09-14
    • 2013-11-23
    • 1970-01-01
    • 2012-08-26
    相关资源
    最近更新 更多