c++ 是否有按位和ipv6地址和网络掩码(前缀)代码?

hyrbngr7  于 2023-02-01  发布在  其他
关注(0)|答案(8)|浏览(192)

我想问一下ipv6网络和主机端的计算。
例如,我的IPv6地址为2001:470:1f15:1bcd:34::41,前缀为96
您知道在IPv6地址和前缀之间执行按位and的简单方法吗?
根据IPv4:

192.168.1.2  255.255.255.0  network : 192.168.1.0

如此简单。
我想对IPv6地址做同样的事情,但是IPv6地址是16字节的,所以你不能用unsigned int
有什么API可以做到这一点吗?或者我应该使用数组吗?

bvjxkvbb

bvjxkvbb1#

好的,我是用C而不是C++做的,但是它应该能用。而且,它使用bswap_64,这是一个GNU扩展,所以可能不是对所有东西都能用。
在amd64上看起来非常快,而且比Yasar想出的当前解决方案更快:

#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;
}
gpnt7bae

gpnt7bae2#

根据前缀长度计算掩码:

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 );

将网络掩码应用于地址,我从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;
}
zqdjd7g9

zqdjd7g93#

您可以使用inet_pton将地址转换为网络字节顺序的二进制。然后一次设置/清除一个字节。

qyyhg6bp

qyyhg6bp4#

请参见in6calc.c中的函数in6_addr_maskin6_addr_start
示例用法:

struct in6_addr addr, mask, start;
char addr_buffer[INET6_ADDRSTRLEN] = "2001:470:1f15:1bcd:34::41";
uint8_t bits = 96; 

inet_pton(AF_INET6, addr_buffer, &addr);

in6_addr_mask(&mask, bits); // Mask
in6_addr_start(&start, &addr, &mask); // Bitwise &

inet_ntop(AF_INET6, &start, addr_buffer, INET6_ADDRSTRLEN);
printf("Network:    %s\n", addr_buffer);

产量:

Network:    2001:470:1f15:1bcd:34::
z9zf31ra

z9zf31ra5#

威胁IP,如16字节数组,跳过下一个字节掩码中的masked/8字节,较高的masked%8位,将其他位设置为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++;
}

写的代码就在这里,所以它还没有经过测试,但我认为你可以使用这样的东西

vhipe2zx

vhipe2zx6#

下面是一个简单的计时器:

bool timer_check()
{
    static int count = 0;
    time_t seconds1;

    if(val)
    {
        time(&seconds);
        val = false;
        printf("In the first if loop\n");
    }

    time(&seconds1);

    if( (seconds1 - seconds) <= 10 && count < 10 )
    {
       count ++;
    }
    if ((seconds1 - seconds) >= 10)
    {
        count = 0;
        seconds = seconds1;
    }

    if (count < 10)
       return true;
    return false;
}
polkgigr

polkgigr7#

我搜索这个函数,但上面似乎很复杂,所以我写了自己的;

// Clear all bits above the prefix
void mask_ipv6(struct in6_addr* a, unsigned prefix)
{
    assert(prefix <= 128);
    unsigned bits_to_clear = 128 - prefix;
    unsigned i = 3;
    while (bits_to_clear >= 32) {
        a->s6_addr32[i] = 0;
        bits_to_clear -= 32;
        i--;
    }
    if (bits_to_clear == 0)
        return;
    uint32_t mask = htonl(~((1 << bits_to_clear) - 1));
    a->s6_addr32[i] &= mask;
}

当然,您可以使用自己更喜欢的函数名。

kninwzqo

kninwzqo8#

这是快速和肮脏的解决方案,源代码如下,如果你想,使用它。2警告!3该函数假设IPv6地址是有效的。

typedef uint16_t ip6_addr[8];

void ipv6_apply_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 residue = mask % 16;

     if(residue == 0 && index == 8)
      return;

     switch(residue){
        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;
}

相关问题