2011-08-23 88 views
9

我想问一下关于ipv6网络和主机端的计算。是否有任何代码为bitwise和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来做到这一点?或者我应该使用数组?

+1

如果你写为255.255.255.0/24则比特摆弄几乎是相同的。 – Flexo

+6

请注意,您不应该对IPv4使用'unsigned int';你应该使用'uint32_t'(或者它的typedef)。 –

回答

1

家伙我解决我的问题的源代码如下使用它,并继续编码: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; 
} 
+0

需求缺口只有8个(TM)的整数倍! –

+0

好的!我认为更好 – iyasar

+0

很多! :D很好的一个。 –

1

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

0

威胁的IP LIK一个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++; 
} 

写的代码在这里,因此它不是招”牛逼过测试,但我想你可以使用类似这样

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

内存损坏警报!提示:如果prefixLength是3,你的循环会迭代多少次? – JdeBP

+0

@JdeBP测试中:-) –

1

OK ,我是用C而不是C++来做的,但它应该可以工作。此外,它使用bswap_64这是一个GNU扩展AFAIK,所以可能无法处理所有事情。

这似乎是在AMD64非常快,而且比目前的解决方案亚萨尔想出了更快:

#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; 
} 
+0

刚刚在i686 virtualbox上试过了,它的速度也更快。 – benofbrown