【问题标题】:IP cidr match functionIP cidr 匹配功能
【发布时间】:2011-08-27 10:37:02
【问题描述】:

我需要弄清楚,ip是否属于ip mask。 例如:

ip = 192.168.0.1 掩码 = 192.168.0.1/24。

我找到了将 ip 转换为掩码的函数:

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

如何比较 ip 和 cidr 范围?

【问题讨论】:

  • 该函数的更简单形式:addr-&gt;s_addr = 0xffffffffU &lt;&lt; ( 32 - prefixLength )
  • @Steve-o:如果prefixLength 为 0,则会导致未定义的结果。

标签: c cidr


【解决方案1】:

所以将 Olis 的答案放入代码中:

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

他说:

inet_cidrtoaddr(24, &netmask);
bool is_inside = ((ip.s_addr & netmask.s_addr) == (net.s_addr & netmask.s_addr));

我更喜欢addr4_match 方法:

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

我尝试了一堆不同的输入:https://gist.github.com/duedal/b83303b4988a4afb2a75

如果有人发现这个也需要 IPv6 解决方案:

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

检查 2001:db8::ff00:42:8329 是否存在于 2001:db8/32 中。注意 inet_net_pton 非常挑剔,它是 2001:db8/32 而不是 2001:db8::/32。但是 2001:db8::/48 完全有效(也称为 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);

【讨论】:

【解决方案2】:

如果你有 IP 地址、网络地址和网络掩码,那么你可以使用这样的函数:

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

【讨论】:

    【解决方案3】:

    这个函数计算一个网络掩码(例如,255.255.255.128 形式的东西)。因此,要检查指定的 IP 地址是否属于指定的子网,只需将掩码应用于 CIDR 地址和 IP 地址(使用bitwise AND 执行此操作)。如果结果相同,则IP地址有效。

    【讨论】:

      【解决方案4】:

      试试这个:

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

      不过,在 C++ 中,应该很容易将其变为 C

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-12
        • 2022-12-07
        • 2010-10-10
        • 1970-01-01
        • 2021-11-16
        • 2016-04-26
        相关资源
        最近更新 更多