C CIDR到地址列表



我正在编写一个程序,其中我需要迭代从用户给定的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的问题上。我不久前学过网络数学,但自从我获得证书以来,我一直在使用在线计算器。

假设您在字符串中有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位值应该是直接的。我将我的文字标记为无符号长,以确保如果我们在一个小的位宽机器上,在赋值之前不会截断结果。

设置mask的表达式背后的思想是,CIDR中的位计数指定了指示网络的最高有效位的数量,所以如果我们从32中减去它,这就是我们需要向上移动一整组位才能获得该掩码的数量(在截断后)。例如,32的掩码将是所有比特,并且32-32=0,所以我们根本不会移位,给出所有32比特。比特计数为24(如您的示例)将给出32-24=8,并且0xFFFFFFFF<lt;8是截断后的0xFFFFFF00(或十进制记数法中的255.255.0)

最后,为了获得初始IP,我只需使用逐位AND将掩码应用于IP地址。易于理解的

由于你的标题问题讨论了整个列表,你可以通过对掩码的补码进行OR运算来获得最终地址:

uint32_t finalIP = first_ip | ~mask;

这也应该等于广播地址。然后,您可以按顺序从firstIP迭代到finalIP,包括或排除finalIP取决于您是否需要广播地址(如果您是否需要网络地址,则包括或排除firstIP)。

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

最新更新