2010-06-03 22 views
9

¿Quería saber cómo puedo analizar una dirección IPv6 en 'C' y convertirla a un valor de 128 bits? Entonces una dirección hexadecimal como 1: 22: 333: aaaa: b: c: d: e necesita convertirse a su binario equivalente de 128 bits. El problema es que la dirección IP podría ser del tipo :: 2 y su variante, ya que son direcciones IPv6 válidas.Análisis de IPv6 en C

La entrada es desde el teclado y, por lo tanto, está en formato ASCII.

Cualquier sugerencia o sugerencia será apreciada. ¡Gracias!

+2

Parece que hay una dirección IP de 144 bits que tienes allí. – Thanatos

+0

Vaya ... Gracias por señalarlo. En realidad me refería a 1: 22: 333: aaaa: b: c: d: e –

Respuesta

11

Puede usar POSIX inet_pton para convertir una cadena en struct in6_addr.

#include <arpa/inet.h> 

    ... 

const char *ip6str = "::2"; 
struct in6_addr result; 

if (inet_pton(AF_INET6, ip6str, &result) == 1) // success! 
{ 
    //successfully parsed string into "result" 
} 
else 
{ 
    //failed, perhaps not a valid representation of IPv6? 
} 
+0

Puede pasar cualquier cosa lo suficientemente grande como para contener el resultado; por ejemplo, una matriz de 8 'short' también lo hará; siempre que el búfer tenga al menos 128 bits de longitud. – dreamlax

+1

A mí personalmente me gusta un poco más que 'getaddrinfo()', que sugerí a continuación.Lamentablemente, parece que Windows solo tiene 'inet_pton()' comenzando con Vista. (Y casi apostaría a que no analiza de acuerdo con RFC 2373, y solo lo hace con su dirección IPv6 típica ... ¿Alguien sabe?) – Thanatos

+0

@Thanatos: [Este enlace] (http://msdn.microsoft.com /en-us/library/cc805844\(VS.85\).aspx) hace referencia a [RFC 2553] (http://www.ietf.org/rfc/rfc2553) que declara la función 'inet_pton' como una función que convierte representaciones textuales de IPv4 e IPv6 en forma binaria, y dice que debe aceptar direcciones IPv6 en las representaciones descritas en la sección 2.2 de [RFC 2373] (http://www.ietf.org/rfc/rfc2373). – dreamlax

8

getaddrinfo() pueden entender las direcciones IPv6. Pase AF_INET6 a él en las sugerencias, así como AI_NUMERICHOST (para evitar una búsqueda DNS). Linux lo tiene, Windows lo tiene a partir de Windows XP.

+1

No olvides utilizar 'freeaddrinfo' si la función tiene éxito. – dreamlax

2

Para analizar IPv6 en C, es necesario elaborar una función de utilidad, que tokenized cuerdas (dos puntos para los bloques hexagonales, y la barra inclinada de bits de subred).

  1. Tokenizar cadena de IPv6 sin procesar en una subcadena más pequeña.
  2. Convierte la subcadena no vacía en bloques hexadecimales. (ASCII a conversión decimal)
  3. Expande el bloque hexadecimal en 2 bytes rellenando cero al frente. (solo los ceros a la izquierda se recortan)
  4. El IPv6 completo debe tener 8 bloques hexadecimales, calcule los bloques hexagonales faltantes. (la agrupación de ceros solo puede ocurrir una vez)
  5. Reinserte el bloque hexagonal faltante. (Índice de utilización de la subcadena vacío)
+1

Buena descripción si alguien quiere aprender el análisis de IPv6. Aunque solo quiere analizar las direcciones, las otras respuestas son mucho más simples. – bortzmeyer

+0

Gracias YeenFei por la descripción. Podría terminar escribiendo la función ... –

0

si se puede usar impulso , algo como esto debería funcionar:

#include<boost/asio.hpp> 

using boost::asio::ip; 

bool parseIpv6String(std::string ipv6_string, char* dest){ 
    try{ 
     address_v6 addr = address_v6::from_string(ipv6_string); 
     memcpy(dest,addr.to_bytes().data(), 16); 
    }catch(...){ 
     return false; 
    } 
    return true; 
} 

Es un poco más portátil que, por ejemplo, las funciones específicas de POSIX.

+0

¿Desde cuándo 'memcpy()' arroja excepciones ?! –

+0

tiene razón, from_string() hace. gracias por el aviso. – Patryk

1

Puede usar la función POSIX getaddrinfo(). Es más flexible que inet_pton(), por ejemplo, detecta automáticamente los formatos de direcciones IPv4 e IPv6, puede resolver incluso los nombres de host (utilizando la resolución DNS) y los nombres de puerto/servicio (usando /etc/services).

#include <sys/types.h> 
#include <netdb.h> 
#include <netdb.h> 

.... 

const char *ip6str = "::2"; 

struct sockaddr_storage result; 
socklen_t result_len; 

struct addrinfo *res = NULL; 
struct addrinfo hints; 
memset(&hints, 0, sizeof(struct addrinfo)); 
hints.ai_family = PF_UNSPEC; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_flags = AI_DEFAULT | AI_NUMERICHOST | AI_NUMERICSERV; 

rc = getaddrinfo(ip6str, NULL, &hints, &res); 
if (rc != 0) 
{ 
    fprintf(stderr, "Failure to parse host '%s': %s (%d)", ip6str, gai_strerror(rc), rc); 
    return -1; 
} 

if (res == NULL) 
{ 
    // Failure to resolve 'ip6str' 
    fprintf(stderr, "No host found for '%s'", ip6str); 
    return -1; 
} 

// We use the first returned entry 
result_len = res->ai_addrlen; 
memcpy(&result, res->ai_addr, res->ai_addrlen); 

freeaddrinfo(res); 

La dirección IPv6 se almacena en la variable struct sockaddr_storage result.

if (result.ss_family == AF_INET6) // Ensure that we deal with IPv6 
{ 
    struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *) &result; 
    struct in6_addr * in6 = &sa6->sin6_addr; 
    in6->s6_addr[0]; // This is a first byte of the IPv6 
    in6->s6_addr[15]; // This is a last byte of the IPv6 
}