我有理由做类似的事情,所以我想我会在 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;
}