【问题标题】:Convert CIDR notation into IP range将 CIDR 表示法转换为 IP 范围
【发布时间】:2024-01-21 10:04:01
【问题描述】:

我们正在使用 GeoLite2 数据库来实现 IP -> 国家 查找。出于性能原因,我们希望导入 CSV 并将其转换为我们自己的格式。

CSV 表示如下:

5.39.40.96/27,3017382,3017382,,0,0
5.39.40.128/28,3017382,3017382,,0,0
5.39.40.144/28,2635167,3017382,,0,0
5.39.40.160/27,3017382,3017382,,0,0
5.39.40.192/26,3017382,3017382,,0,0
5.39.41.0/25,3017382,3017382,,0,0
5.39.41.128/26,3017382,3017382,,0,0
5.39.41.192/26,2635167,3017382,,0,0
5.39.42.0/24,3017382,3017382,,0,0
5.39.43.0/25,3017382,3017382,,0,0

因此我们需要将 CIDR 表示法(示例:5.39.40.96/27)转换为 IP 地址范围。 (从 IP - 到 IP)

如何在 C# 中做到这一点?

注意:这不是 this question 的重复,因为我问的是 C# 实现而不是 Java。

【问题讨论】:

    标签: c# .net ip-address cidr


    【解决方案1】:

    这是处理它的一种方法,无需使用任何库函数来明确正在发生的事情,并在以后有人需要用其他语言实现它时提供帮助。

    代码首先将 CIDR 转换为 32 位数字,然后创建掩码以确定起始地址,使用掩码的反转来确定结束地址,然后再转换回 CIDR 格式。

    请注意,没有错误检测,因此输入必须为 a.b.c.d/m 格式。

    IP 地址的转换只是使用位移位以大端形式 (AABBCCDD) 的四个八位字节的简单串联。

    掩码表示从最高有效位开始有多少位是固定的,这意味着 32 是单个 IP 范围,而 0 是整个 IP 范围。因此,我们可以取一个所有位都设置的掩码,并用32-maskbits 将其左移以确定实际的掩码。

    如果我们将maskbits 位设置为零,我们将获得范围的开头,因此我们将 IP 与 maskbits 进行与运算。如果我们将位设置为 1,我们将得到范围的结尾,因此我们将与掩码的否定位进行 OR。

    以 CIDR 格式打印 IP 地址也很简单:只需将 32 位值拆分为八位字节并用点分隔写入。

    using System;
    
    namespace CSTests
    {
        class Program
        {
            static string toip(uint ip)
            {
                return String.Format("{0}.{1}.{2}.{3}", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
            }
    
            static void Main(string[] args)
            {
                string IP = "5.39.40.96/27";
                string[] parts = IP.Split('.', '/');
    
                uint ipnum = (Convert.ToUInt32(parts[0]) << 24) |
                    (Convert.ToUInt32(parts[1]) << 16) |
                    (Convert.ToUInt32(parts[2]) << 8) |
                    Convert.ToUInt32(parts[3]);
    
                int maskbits = Convert.ToInt32(parts[4]);
                uint mask = 0xffffffff;
                mask <<= (32 - maskbits);
    
                uint ipstart = ipnum & mask;
                uint ipend = ipnum | (mask ^ 0xffffffff);
    
                Console.WriteLine(toip(ipstart) + " - " + toip(ipend));
            }
        }
    }
    

    输出:

    5.39.40.96 - 5.39.40.127

    【讨论】:

    • 哇,这是一个非常好的答案!您的代码是如此简短和重点。 +1!
    • 你可以使用~mask代替(mask ^ 0xffffffff)来做同样的事情。
    【解决方案2】:

    Sami Kuhmonen,这是非常不错的代码,并且经过了极大的简化。我注意到它返回了网络 ID 和广播。但是,对于那些希望它返回可用地址空间的人。只需在起始 IP 上加一,从结束 IP 中减一即可。

    toip(ipstart + 1) + " - " + toip(ipend -1);
    

    【讨论】: