I wanted to know how I can parse an IPv6 address in C and convert it to a 128 bit value?
So a hex address like 1:22:333:aaaa:b:c:d:e
needs to be converted to its 128 bit equivalent binary. The problem is the IP address could be of the type ::2
and its variant since they are valid IPv6 address.
The input is from the keyboard and hence is in ASCII format.
An Ipv6 address uses 128 bits as opposed to 32 bits in IPv4.
Hexadecimal (the Base16 numbering system), rather than decimal (the Base10 numbering system), is used for IPv6 because it is easier to convert between hexadecimal and binary than it is to convert between decimal and binary. Each hexadecimal digit represents four binary digits.
In contrast, IPv6 addresses are 128 bits divided along 16-bit boundaries. Each 16-bit block is converted to a 4-digit hexadecimal number and separated by colons. The resulting representation is called colon-hexadecimal.
You can use POSIX inet_pton
to convert a string to a 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?
}
getaddrinfo()
can understand IPv6 addresses. Pass AF_INET6 to it in the hints, as well as AI_NUMERICHOST (to prevent a DNS lookup). Linux has it, Windows has it as of Windows XP.
You can use getaddrinfo()
POSIX function. It is more flexible than inet_pton()
, for example it automatically detects IPv4 and IPv6 address formats, it can resolve even hostnames (using DNS resolving) and port/service names (using /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);
The IPv6 address is stored in the struct sockaddr_storage result
variable.
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
}
To parse IPv6 in C, you need to build yourself a utility function, which tokenized string (colon for hex blocks, and forward-slash for subnet bits).
In Windows, you can use WSAStringToAddress
, which is available since Windows 2000.
Rosetta has samples in several languages: https://rosettacode.org/wiki/Parse_an_IP_Address
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With