问题
I need to find out, is ip belong to ip mask. For example:
ip = 192.168.0.1 mask = 192.168.0.1/24.
I found function that convert ip to mask:
inet_cidrtoaddr(int cidr, struct in_addr *addr)
{
int ocets;
if (cidr < 0 || cidr > 32) {
errno = EINVAL;
return -1;
}
ocets = (cidr + 7) / 8;
addr->s_addr = 0;
if (ocets > 0) {
memset(&addr->s_addr, 255, (size_t)ocets - 1);
memset((unsigned char *)&addr->s_addr + (ocets - 1),
(256 - (1 << (32 - cidr) % 8)), 1);
}
return 0;
}
How can i compare ip and cidr range ?
回答1:
If you have the IP address, the network address, and the netmask, then you can use a function like this:
bool
is_in_net (
const struct in_addr* addr, /* host byte order */
const struct in_addr* netaddr,
const struct in_addr* netmask
)
{
if ((addr->s_addr & netmask->s_addr) == (netaddr->s_addr & netmask->s_addr))
return true;
return false;
}
回答2:
So to put Olis answer in code:
// Check if 192.168.0.1 is inside 192.168.0.0/24
in_addr ip, net, netmask;
inet_aton("192.168.0.1", &ip);
inet_aton("192.168.0.0", &net);
He said:
inet_cidrtoaddr(24, &netmask);
bool is_inside = ((ip.s_addr & netmask.s_addr) == (net.s_addr & netmask.s_addr));
I prefer the addr4_match method though:
bool cidr_match(const in_addr &addr, const in_addr &net, uint8_t bits) {
if (bits == 0) {
// C99 6.5.7 (3): u32 << 32 is undefined behaviour
return true;
}
return !((addr.s_addr ^ net.s_addr) & htonl(0xFFFFFFFFu << (32 - bits)));
}
bool is_inside = cidr_match(ip, net, 24);
I experimented with a bunch of different input: https://gist.github.com/duedal/b83303b4988a4afb2a75
If somebody finding this is wanting an IPv6 solution too:
bool cidr6_match(const in6_addr &address, const in6_addr &network, uint8_t bits) {
#ifdef LINUX
const uint32_t *a = address.s6_addr32;
const uint32_t *n = network.s6_addr32;
#else
const uint32_t *a = address.__u6_addr.__u6_addr32;
const uint32_t *n = network.__u6_addr.__u6_addr32;
#endif
int bits_whole, bits_incomplete;
bits_whole = bits >> 5; // number of whole u32
bits_incomplete = bits & 0x1F; // number of bits in incomplete u32
if (bits_whole) {
if (memcmp(a, n, bits_whole << 2)) {
return false;
}
}
if (bits_incomplete) {
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
return false;
}
}
return true;
}
Check if 2001:db8::ff00:42:8329 is present in 2001:db8/32. Beware inet_net_pton is very picky, it's 2001:db8/32 not 2001:db8::/32. However 2001:db8::/48 is perfectly valid (also known as 2001:db8:0/48).
in6_addr ip6, net6, net6_48;
memset(&net6, 0, sizeof(net6));
memset(&net6_48, 0, sizeof(net6_48));
assert(inet_pton(AF_INET6, "2001:db8::ff00:42:8329", &ip6));
int bits = inet_net_pton(AF_INET6, "2001:db8/32", &net6, sizeof(net6));
assert((bits != -1)); // assert that inet_net_pton understood us
bool is_inside6 = cidr6_match(ip6, net6, bits);
int bits_48 = inet_net_pton(AF_INET6, "2001:db8::/48", &net6_48, sizeof(net6_48));
assert((bits_48 == 48));
bool is_inside6_48 = cidr6_match(ip6, net6_48, bits_48);
回答3:
This function computes a net-mask (e.g. something of the form 255.255.255.128). So to check whether a specified IP address falls within a specified sub-net, just apply the mask to the CIDR address, and to the IP address (you do this with bitwise AND). If the results are the same, then the IP address is valid.
回答4:
Try this:
const std::uint32_t CIDR_PREFIXES[33] = {
[0] = htonl(0),
[1] = htonl(0x80000000),
[2] = htonl(0xC0000000),
[3] = htonl(0xE0000000),
[4] = htonl(0xF0000000),
[5] = htonl(0xF8000000),
[6] = htonl(0xFC000000),
[7] = htonl(0xFE000000),
[8] = htonl(0xFF000000),
[9] = htonl(0xFF800000),
[10] = htonl(0xFFC00000),
[11] = htonl(0xFFE00000),
[12] = htonl(0xFFF00000),
[13] = htonl(0xFFF80000),
[14] = htonl(0xFFFC0000),
[15] = htonl(0xFFFE0000),
[16] = htonl(0xFFFF0000),
[17] = htonl(0xFFFF8000),
[18] = htonl(0xFFFFC000),
[19] = htonl(0xFFFFE000),
[20] = htonl(0xFFFFF000),
[21] = htonl(0xFFFFF800),
[22] = htonl(0xFFFFFC00),
[23] = htonl(0xFFFFFE00),
[24] = htonl(0xFFFFFF00),
[25] = htonl(0xFFFFFF80),
[26] = htonl(0xFFFFFFC0),
[27] = htonl(0xFFFFFFE0),
[28] = htonl(0xFFFFFFF0),
[29] = htonl(0xFFFFFFF8),
[30] = htonl(0xFFFFFFFC),
[31] = htonl(0xFFFFFFFE),
[32] = htonl(0xFFFFFFFF),
};
bool matchCIDR(const in_addr &network, const in_addr &addr, unsigned prefix)
{
if (prefix > 32)
return false;
std::uint32_t cidr = CIDR_PREFIXES[prefix];
std::uint32_t hNetwork = network.s_addr;
std::uint32_t hAddr = addr.s_addr;
return hNetwork == (hAddr & cidr);
}
In C++ though, should be quite easy to make it C
来源:https://stackoverflow.com/questions/7213995/ip-cidr-match-function