All IP's in a subnet (C)

笑着哭i 提交于 2019-12-25 04:09:33

问题


Does someone have a good example of a way I could take a IP address with a CIDR such as 192.168.1.1/24 and return all the ip addresses inside of that range such as 192.168.1.1, 192.168.1.2, 192.168.1.3 ...

I'm fine with it being returned in a array of unsigned long, a char or just something like

/* Pseudocode */
while(currnetip <= finalip) { 
    print(currnetip); 
    currnetip++; 
}

As long as I can understand it its fine.

Feel free to comment a link to a post if you think it could help me.

Edit: Probably worth mentioning I've found lots of stuff that calculated the broadcast address ect I'm just not sure how to link all those functions together.


回答1:


First, pack your IPv4 address into an uint32_t (defined in <stdint.h>), putting the leftmost octet in dotted-decimal notation into the most significat bits. For example,

uint32_t ipv4_pack(const uint8_t octet1,
                   const uint8_t octet2,
                   const uint8_t octet3,
                   const uint8_t octet4)
{
    return (((uint32_t)octet1) << 24)
         | (((uint32_t)octet2) << 16)
         | (((uint32_t)octet3) <<  8)
         |  ((uint32_t)octet4);
}

and its inverse,

unsigned char *ipv4_unpack(unsigned char *addr, const uint32_t packed)
{
    addr[3] = (uint8_t)(packed);
    addr[2] = (uint8_t)(packed >> 8);
    addr[1] = (uint8_t)(packed >> 16);
    addr[0] = (uint8_t)(packed >> 24);
    return addr;
}

An address like 128.64.32.16 is packed into 0x80402010 (128 == 8016, 64 == 4016, 32 == 2016, and 16 == 1016).


You need to also convert the CIDR prefix size (1 to 32) into a binary mask of that many highest bits set:

uint32_t ipv4_mask(const int prefix_size)
{
    if (prefix_size > 31)
        return (uint32_t)0xFFFFFFFFU;
    else
    if (prefix_size > 0)
        return ((uint32_t)0xFFFFFFFFU) << (32 - prefix_size);
    else
        return (uint32_t)0U;
}

Prefix 24 corresponds to a mask of 11111111111111111111111100000000 in binary, and 0xFFFFFF00 in hexadecimal.

Prefix 28 corresponds to a mask of 11111111111111111111111111110000 in binary, and 0xFFFFFFF0 in hexadecimal.

For address addr1.addr2.addr3.addr4/prefix, the first address in a range (typically the gateway address for said range) is

uint32_t first = ipv4_pack(addr1, addr2, addr3, addr4) & ipv4_mask(prefix);

and the last address (typically the broadcast address for said range) is

uint32_t last = ipv4_pack(addr1, addr2, addr3, addr4) | (~ipv4_mask(prefix));

In all cases, first <= last, and iterating from first to last, inclusive, and calling ipv4_unpack() to unpack the value into dotted-decimal notation), yields all IPv4 addresses within the range.


The same would work for IPv6, but requires something like an uint128_t type. (It can be emulated with smaller unsigned integer types, of course, taking a few more instructions, but the logic stays the same.)



来源:https://stackoverflow.com/questions/40774074/all-ips-in-a-subnet-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!