问题
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