问题
I want to ask about calculation of ipv6 network and host side.
For example, I have the IPv6 address 2001:470:1f15:1bcd:34::41
and prefix 96
.
Do you know a easy way to do bitwise and
between IPv6 address and prefix?
According to IPv4:
192.168.1.2 255.255.255.0 network : 192.168.1.0
So simple.
I want to do the same thing to IPv6 address. But IPv6 address is 16 bytes, so you can't use unsigned int
for that.
Is there any API to do this? Or should I use arrays?
回答1:
Calculate mask from prefix length:
struct sockaddr_in6 netmask;
for (long i = prefixLength, j = 0; i > 0; i -= 8, ++j)
netmask.sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff
: (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU );
Apply netmask to address, I derived this from inet_lnaof.
bool
inet6_lnaof (
struct in6_addr* restrict dst,
const struct in6_addr* restrict src,
const struct in6_addr* restrict netmask
)
{
bool has_lna = FALSE;
assert (NULL != dst);
assert (NULL != src);
assert (NULL != netmask);
for (unsigned i = 0; i < 16; i++) {
dst->s6_addr[i] = src->s6_addr[i] & netmask->s6_addr[i];
has_lna |= (0 != (src->s6_addr[i] & !netmask->s6_addr[i]));
}
return has_lna;
}
回答2:
You can convert the address to binary in network byte order with inet_pton. Then set/clear the bits one byte at a time.
回答3:
OK, I did this in C rather than C++, but it should work. Also, it uses bswap_64 which is AFAIK a GNU extension so may not work on everything.
It seems to be very quick on amd64, and faster than the current solution Yasar has come up with:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <arpa/inet.h>
#if defined __GNUC__ && __GNUC__ >= 2
#include <byteswap.h>
#else
#error "Sorry, you need GNU for this"
#endif
struct split
{
uint64_t start;
uint64_t end;
};
void ipv6_prefix (unsigned char *masked, unsigned char *packed, int prefix)
{
struct split parts;
uint64_t mask = 0;
unsigned char *p = masked;
memset(masked, 0, sizeof(struct in6_addr));
memcpy(&parts, packed, sizeof(parts));
if (prefix <= 64)
{
mask = bswap_64(bswap_64(parts.start) & ((uint64_t) (~0) << (64 - prefix)));
memcpy(masked, &mask, sizeof(uint64_t));
return;
}
prefix -= 64;
memcpy(masked, &(parts.start), sizeof(uint64_t));
p += sizeof(uint64_t);
mask = bswap_64(bswap_64(parts.end) & (uint64_t) (~0) << (64 - prefix));
memcpy(p, &mask, sizeof(uint64_t));
}
int main (int argc, char **argv)
{
unsigned char packed[sizeof(struct in6_addr)];
unsigned char masked[sizeof(struct in6_addr)];
char buf[INET6_ADDRSTRLEN], *p;
int prefix = 56;
if (argc < 2)
return 1;
if ((p = strchr(argv[1], '/')))
{
*p++ = '\0';
prefix = atoi(p);
}
inet_pton(AF_INET6, argv[1], packed);
ipv6_prefix(masked, packed, prefix);
inet_ntop(AF_INET6, masked, buf, INET6_ADDRSTRLEN);
printf("prefix = %s/%d\n", buf, prefix);
return 0;
}
回答4:
Threat the IP lik a 16 bytes array, skip the masked/8
bytes in the next byte mask the higher masked%8
bits, set the other ones to 0
int offset=masked/8;
char remmask=0;
int rem = masked%8;
while(rem)
{
rem--;
remmask|= 0x80>>rem; //0x80 is the highest bit in a byte set
}
offset++;
(((char*)ipv6)+offset) &= remmask;
while(offset<16)
{
(((char*)ipv6)+offset=0;
offset++;
}
Wrote the code right here, so it hasn't been tested but I am thinking you could use something like this
回答5:
guys i solved my problem the source code is below use it and go on coding :D : Warning the function assume the IPv6 address is valid., my type is:
typedef uint16_t ip6_addr[8];
void ipv6_app_mask(const char *ip6addr, unsigned int mask, ip6_addr ip6){
ip6_addr in_ip6;
inet_pton(PF_INET6, ip6addr, ip6);
for(int i = 0; i < 8; i++){
in_ip6[i] = ntohs(ip6[i]);
}
int index = (int) (mask / 16);
int remain_mask = mask % 16;
if(remain_mask == 0 && index == 8)
return;
switch(remain_mask){
case 0:in_ip6[index++] = 0; break;
case 1:in_ip6[index++]&=0x8000; break;
case 2:in_ip6[index++]&=0xc000; break;
case 3:in_ip6[index++]&=0xe000; break;
case 4:in_ip6[index++]&=0xf000; break;
case 5:in_ip6[index++]&=0xf800; break;
case 6:in_ip6[index++]&=0xfc00; break;
case 7:in_ip6[index++]&=0xfe00; break;
case 8:in_ip6[index++]&=0xff00; break;
case 9:in_ip6[index++]&=0xff80; break;
case 10:in_ip6[index++]&=0xffc0; break;
case 11:in_ip6[index++]&=0xffe0; break;
case 12:in_ip6[index++]&=0xfff0; break;
case 13:in_ip6[index++]&=0xfff8; break;
case 14:in_ip6[index++]&=0xfffc; break;
case 15:in_ip6[index++]&=0xfffe; break;
}
for (int i = index; i < 8; i++){
in_ip6[i] = 0;
}
for(int i = 0; i < 8; i++){
ip6[i] = htons(in_ip6[i]);
}
return;
}
来源:https://stackoverflow.com/questions/7158528/is-there-any-code-for-bitwise-and-ipv6-address-and-network-mask-prefix