CIDR转地址列表

4
我正在编写一个程序,需要遍历由用户提供的CIDR(例如75.24.64.0/24)得出的地址列表。
我看了一些代码,例如这个,但那看起来有点复杂。
最后,我决定使用类似下面这样的结构体:
struct ip_iterator {
    unsigned int netmask;
    int bitcount;
    long long num_total;
    long long num_left;
    int current_ip[4];
};

我可以定义ip_iterator_initip_iterator_nextip_iterator_is_finished函数。然而,我卡在了如何从cidr到第一个IP的转换上。我以前学过网络数学,但自从获得证书后,我一直在使用在线计算器。

2个回答

6
假设您将 CIDR 存储在字符串中,类似下面的内容可能会对您有所帮助。
首先需要一个将 CIDR 转换成 IP 和掩码的函数:
int cidr_to_ip_and_mask(const char *cidr, uint32_t *ip, uint32_t *mask)
{
    uint8_t a, b, c, d, bits;
    if (sscanf(cidr, "%hhu.%hhu.%hhu.%hhu/%hhu", a, b, c, d, bits) < 5) {
        return -1; /* didn't convert enough of CIDR */
    }
    if (bits > 32) {
        return -1; /* Invalid bit count */
    }
    *ip =
        (a << 24UL) |
        (b << 16UL) |
        (c << 8UL) |
        (d);
    *mask = (0xFFFFFFFFUL << (32 - bits)) & 0xFFFFFFFFUL;
}

接下来是获取第一个IP的代码片段:
uint32_t ip;
uint32_t mask;
uint32_t first_ip;
if (cidr_to_ip_and_mask(cidr, &ip, &mask) < 0) {
    /* return some failure */
}
first_ip = ip & mask;

首先,我假设使用C99或可用stdint.h的环境,以便可以使用显式位宽数据类型(最大可移植性,因为您未指定架构)。我还假设这是IPv4,因为这是您的示例字符串。
接下来,我使用sscanf将字符串转换为地址组件。将字节组合成完整的32位值应该很简单。我正在将我的文字标记为unsigned long,以确保在小位宽机器上分配之前不会截断结果。
设置mask表达式背后的思想是CIDR中的比特数指定了多少最高有效位表示网络,因此如果我们从32中减去它,那么我们需要移动一组完整的位数来获取该掩码(在截断后)。例如,掩码为32将是所有位,而32-32 = 0,因此我们根本不会移位,给出所有32位。像您的示例一样的24位计数将给出32-24 = 8,0xFFFFFFFF << 8在截断后为0xFFFFFF00(或十进制表示为255.255.255.0)
最后,要获取初始IP,我只需使用按位AND将掩码应用于IP地址即可。 简单!
由于您的标题问题涉及整个列表,因此可以通过对补码进行OR运算来获得最终地址。
uint32_t finalIP = first_ip | ~mask;

这里的广播地址应该与这个相等。然后,您可以按顺序从第一个IP迭代到最终IP,包括或排除最终IP,这取决于您是否需要广播地址(以及是否包括或排除第一个IP,如果您想要网络地址或不需要)。

谢谢你的出色回答!不过你忘了一个分号 ;) - 735Tesla
1
那会出问题的。你需要放&a、&b、&c、&d和&bits。但除此之外还不错。 - hookenz

1
int cidr_to_ip_and_mask(const char *cidr, uint32_t *ip, uint32_t *mask)
{
    uint8_t a, b, c, d, bits;
    if (sscanf(cidr, "%hhu.%hhu.%hhu.%hhu/%hhu", &a, &b, &c, &d, &bits) < 5) {
        return -1; /* didn't convert enough of CIDR */
    }
    if (bits > 32) {
        return -1; /* Invalid bit count */
    }
    *ip =
        (a << 24UL) |
        (b << 16UL) |
        (c << 8UL) |
        (d);
    *mask = (0xFFFFFFFFUL << (32 - bits)) & 0xFFFFFFFFUL;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接