2011-08-23 2 views
9

Je veux poser des questions sur le calcul du réseau ipv6 et côté hôte. Par exemple, j'ai l'adresse IPv6 2001:470:1f15:1bcd:34::41 et le préfixe 96.existe-t-il du code pour les adresses bit à bit et ipv6 et le masque de réseau (préfixe)?

Connaissez-vous un moyen facile de faire bit à bit and entre l'adresse IPv6 et le préfixe?

Selon IPv4:

192.168.1.2 255.255.255.0 network : 192.168.1.0 

si simple.

Je veux faire la même chose avec l'adresse IPv6. Mais l'adresse IPv6 est de 16 octets, donc vous ne pouvez pas utiliser unsigned int pour cela.

Y a-t-il une API pour cela? Ou devrais-je utiliser des tableaux?

+1

Si vous écrivez 255.255.255.0 comme/24 alors le tripoter bit est presque identique. – Flexo

+6

Notez que vous ne devez pas non plus utiliser 'unsigned int' pour IPv4; vous devriez utiliser 'uint32_t' (ou un typedef de celui-ci). –

Répondre

1

les gars, je résolu mon problème, le code source est utiliser ci-dessous et aller sur le codage: D:. Avertissement la fonction suppose l'adresse IPv6 est valide, mon type est:

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

Besoins d'indentation! –

+0

ok.! Je pense mieux – iyasar

+0

Beaucoup! : D Un gentil. –

1

Vous pouvez convertir l'adresse en binaire dans l'ordre des octets réseau avec inet_pton. Puis définissez/effacez les bits un octet à la fois.

0

menace l'IP lik un 16 octets tableau, sauter les masked/8 octets dans l'octet suivant masquer les masked%8 plus de bits, définissez les autres à 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++; 
} 

A écrit le code ici, donc il n » t été testé, mais je pense que vous pouvez utiliser quelque chose comme ça

2

Calculer le masque de longueur du préfixe:

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

Appliquer le masque de réseau à l'adresse, je l'ai dérivé de 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

Alerte de corruption de mémoire! Astuce: Combien de fois votre boucle itère si prefixLength est, disons, 3? – JdeBP

+0

@JdeBP Testé en multiples de 8 seulement (tm) :-) –

1

OK , Je l'ai fait en C plutôt qu'en C++, mais ça devrait marcher. En outre, il utilise bswap_64 qui est AFAIK une extension GNU donc peut ne pas fonctionner sur tout.

Il semble être très rapide sur amd64, et plus rapide que la solution actuelle Yasar est venu avec:

#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

Je viens de l'essayer sur une virtualbox i686 et c'est aussi beaucoup plus rapide. – benofbrown