【问题标题】:is there any code for bitwise and ipv6 address and network mask (prefix)?是否有按位和 ipv6 地址和网络掩码(前缀)的代码?
【发布时间】:2011-08-23 09:01:39
【问题描述】:

我想问一下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 可以做到这一点?还是应该使用数组?

【问题讨论】:

  • 如果你把 255.255.255.0 写成 /24 那么位摆弄几乎是一样的。
  • 请注意,您也不应该将unsigned int 用于 IPv4;你应该使用uint32_t(或它的typedef)。

标签: c++ c networking ipv6


【解决方案1】:

好的,我是用 C 而不是 C++ 做的,但它应该可以工作。此外,它使用bswap_64,这是 AFAIK 的一个 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;
}

【讨论】:

  • 刚刚在 i686 virtualbox 上试了一下,速度也快了很多。
【解决方案2】:

根据前缀长度计算掩码:

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

【讨论】:

  • 内存损坏警报!提示:如果 prefixLength 是 3,你的循环迭代多少次?
  • @JdeBP 仅以 8 的倍数进行测试 (tm) :-)
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    像 16 字节数组一样威胁 IP,跳过下一个字节掩码中较高的 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++;
    }
    

    在此处编写代码,因此尚未经过测试,但我认为您可以使用类似的代码

    【讨论】:

      【解决方案5】:

      伙计们,我解决了我的问题,下面的源代码使用它并继续编码:D:警告该函数假定 IPv6 地址是有效的。, 我的类型是:

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

      【讨论】:

      • 哇,与“面具”这个词的模棱两可的用法令人费解。
      【解决方案6】:

      这是一个简单的计时器:

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

      【讨论】:

        【解决方案7】:

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

        // 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;
        }
        

        您当然可以使用更喜欢的函数名称。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-28
          • 2015-02-24
          • 1970-01-01
          • 2016-03-08
          • 1970-01-01
          • 2015-02-11
          相关资源
          最近更新 更多