735*_*sla 4 c network-programming ip-address 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];
};
Run Code Online (Sandbox Code Playgroud)
然后我可以定义ip_iterator_init ip_iterator_next, 和ip_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;
}
Run Code Online (Sandbox Code Playgroud)
接下来,获取第一个 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;
Run Code Online (Sandbox Code Playgroud)
首先,我假设 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 地址。简单的!
由于您的标题问题讨论了整个列表,您可以通过将掩码的补码与基数进行 ORing 来获得最终地址:
uint32_t finalIP = first_ip | ~mask;
Run Code Online (Sandbox Code Playgroud)
这也应该等于广播地址。然后,您可以按顺序从 firstIP 迭代到 finalIP,包括或排除 finalIP 取决于您是否需要广播地址(如果您需要网络地址,则包括或排除 firstIP)。
| 归档时间: |
|
| 查看次数: |
2450 次 |
| 最近记录: |