【问题标题】:How to check if a V6 ip belongs to a subnet using bitwise operation如何使用按位运算检查 V6 ip 是否属于子网
【发布时间】:2018-09-14 22:51:31
【问题描述】:

我有一个像 6000::8000:1/128 这样的 V6 ip。我需要检查这个 IP 是否位于 6000::8000:0/112 的子网内。

我想使用按位运算。有人可以帮我解释一下逻辑吗?

提前致谢!

【问题讨论】:

  • 哪种编程语言?
  • 他提到了按位运算,所以对编程语言的依赖应该不大。
  • C 或 c++ 位运算

标签: ipv6


【解决方案1】:

我有理由做类似的事情,所以我想我会在 3.5 年后加入。

我的解决方案相当脆弱,但基本上我只是使用inet_pton() 将地址和网络转换为字符数组,然后遍历地址和网络的每个字节(或其中的一部分,取决于网络掩码的长度)比较位是否不同。但是,此解决方案同时处理 IPv4 和 IPv6。

./a.out 2001::/64 2001::1234 调用,其中第一个参数是网络/网络掩码,第二个参数是确定网络是否包含的地址。

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef struct {
    char netaddr[INET6_ADDRSTRLEN];
    char * straddr;
    int netmask;
    int domain;
} network;

//Parses a address/netmask string
network * parseNetwork(char * str) {

    network * retnet;
    char * slashptr;

    retnet = (network *) malloc(sizeof(network));

    //Parse the netmask
    if ((slashptr = strchr(str, '/')) == NULL) {
        retnet->netmask = 0;
    } else {
        slashptr++;
        retnet->netmask = atoi(slashptr);
        --slashptr;
        *slashptr = '\0';
    }

    //Parse the network portion
    if (strchr(str, ':') != NULL)  {
        //this is v6
        retnet->domain = AF_INET6;
        if (inet_pton(AF_INET6, str, retnet->netaddr) <= 0) {
            fprintf(stderr, 
                    "Error converting IPv6 address to network format\n");
            exit(-1);
        }
        if (retnet->netmask > 128 || retnet->netmask < 0) {
            fprintf(stderr, "[-] IPv6 subnet mask must be 0 <= x <= 128\n");
            exit(-1);
        }
    } else if (strchr(str, '.') != NULL) {
        //this is v4
        retnet->domain = AF_INET;
        if (inet_pton(AF_INET, str, retnet->netaddr) <= 0) {
            fprintf(stderr, 
                    "Error converting IPv4 address to network format\n");
            exit(-1);
        }
        if (retnet->netmask > 32 || retnet->netmask < 0) {
            fprintf(stderr, "[-] IPv4 subnet mask must be 0 <= x <= 32\n");
            exit(-1);
        }
    }

    retnet->straddr = strdup(str);

    return retnet;

}

void printNetwork(network * net)
{
    printf("Netaddr: %s\n", net->straddr);
    printf("Netmask: %d\n", net->netmask);
    printf("Domain: %s\n", net->domain == AF_INET ? "IPv4" : "IPv6");
}

int networkContainsAddr(network * net, network * addr)
{

    int res = 0;
    int maskbits = net->netmask;
    int end;

    if (net->domain == AF_INET) {
        end = 4;
    } else {
        end = 16;
    }

    for (int i = 0; i < end && maskbits > 0 && res == 0; i++)
    {
        int bytebits, bytemask, netbits, addrbits;

        //# bits on in mask for this byte
        bytebits = (maskbits >= 8) ? 8 : maskbits;         
        //bitmask for this byte
        bytemask = pow((double) 2, (double) bytebits) - 1; 
        //mask out bits in network
        netbits = (net->netaddr[i] & (bytemask << (8 - bytebits)));         
        //mask out bits in ? address
        addrbits = (addr->netaddr[i] & (bytemask << (8 - bytebits)));    
        //result non-zero if bits differ
        res = netbits ^ addrbits; 
        maskbits -= bytebits;
    }

    return res;

}

int main(int argc, char * argv[])
{
    int result;
    network * net, * addr;

    if (argc < 3) {
        fprintf(stderr, "[-] Usage: %s network/netmask address\n", argv[0]);
        exit(-1);
    }

    net = parseNetwork(argv[1]);
    printNetwork(net);
    addr = parseNetwork(argv[2]);
    printNetwork(addr);

    result = networkContainsAddr(net, addr);

    printf("%s is%s in %s/%d\n", addr->straddr, result ? " not" : "", 
                                 net->straddr, net->netmask);

    free(net->straddr);
    free(net);
    free(addr->straddr);
    free(addr);
    

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    • 2015-09-23
    • 2012-08-03
    • 2012-04-17
    • 2023-01-26
    • 2021-06-20
    • 2014-02-20
    相关资源
    最近更新 更多