2011-08-23 18 views
9

Chcę zapytać o obliczenie sieci ipv6 i strony hosta. Na przykład mam adres IPv6 2001:470:1f15:1bcd:34::41 i prefiks 96.czy istnieje kod bitowy i adres IPv6 oraz maska ​​sieci (prefiks)?

Czy znasz prosty sposób na zrobienie bitowego and między adresem IPv6 a prefiksem?

Według IPv4:

192.168.1.2 255.255.255.0 network : 192.168.1.0 

takie proste.

Chcę zrobić to samo z adresem IPv6. Ale adres IPv6 ma 16 bajtów, więc nie można do tego użyć unsigned int.

Czy jest jakieś API do tego? Czy powinienem użyć tablic?

+1

Jeśli piszesz jako 255.255.255.0/24 to nieco małostkowy jest niemal identyczny. – Flexo

+6

Zauważ, że nie powinieneś także używać 'unsigned int' dla IPv4; powinieneś używać 'uint32_t' (lub typedef tego). –

Odpowiedz

1

faceci i rozwiązać mój problem kod źródłowy jest poniżej niego korzystać i przejść kodowania: D:. Ostrzeżenie funkcja zakładać adres IPv6 jest ważna, mój typ to:

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

Wymaga wcięcia! –

+0

ok.! myślę, że lepiej – iyasar

+0

Wiele! : D Niezły. –

1

Możesz przekonwertować adres na binarny w kolejności bajtów sieciowych z inet_pton. Następnie ustaw/usuń bity jeden bajt na raz.

0

Zagrożenie IP lik tablicy 16 bajtów, pomiń masked/8 bajtów następnego bajtu maskować wyższe masked%8 bity ustaw pozostałe, do 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++; 
} 

napisał kod tutaj, więc hasn” T zostały przetestowane, ale myślę można użyć coś jak ten

2

Oblicz długości maski z przedrostkiem:

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

Zastosuj maskę sieci do adresu, otrzymałem to od 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

Alarm uszkodzenia pamięci! Podpowiedź: Ile razy twoja pętla iteruje, jeśli prefiksLength wynosi, powiedzmy, 3? – JdeBP

+0

@JdeBP Testowane tylko w wielokrotnościach 8 (tm) :-) –

1

OK Zrobiłem to w C zamiast w C++, ale powinno działać. Ponadto używa bswap_64, który jest rozszerzeniem AFAIK a GNU, więc może nie działać na wszystko.

Wydaje się być bardzo szybki na amd64, i szybciej niż obecne rozwiązania Yasar ma pochodzić z:

#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

Po prostu wypróbowałem to na wirtualnej skrzynce i686 i jest to znacznie szybsze. – benofbrown

Powiązane problemy