I have a struct sockaddr
structure containing an IPv4-mapped-IPv6 address like ::ffff:10.0.0.1
. I want to obtain only the IPv4 version of it in a string (in this case, 10.0.0.1
) in C programming language. How do I go about achieving it?
3 Answers
As your structure contains an IPV6 address, I'll assume your have a struct sockaddr *
pointer (let's name it addrPtr
) pointing to a struct sockaddr_in6
structure.
You can get the address bytes easily.
const uint8_t *bytes = ((const struct sockaddr_in6 *)addrPtr)->sin6_addr.s6_addr;
Then add 12 to the pointer because the 12 first bytes are not interesting (10 0x00
, then 2 0xff
). Only the 4 last ones mater.
bytes += 12;
Now, we can use those four bytes to do whatever we want. For example, we might store them into a IPv4 struct in_addr
address.
struct in_addr addr = { *(const in_addr_t *)bytes };
Then we can get a string using inet_ntop
(declared in <arpa/inet.h>
).
char buffer[16]; // 16 characters at max: "xxx.xxx.xxx.xxx" + NULL terminator
const char *string = inet_ntop(AF_INET, &addr, buffer, sizeof(buffer));

- 6,475
- 2
- 26
- 36
-
1Or use `inet_ntoa()` instead of `sprintf()` – Remy Lebeau Jun 27 '12 at 22:57
-
2Good point. I edited my answer to use `inet_ntop`, which is recommended over `inet_ntoa` because it uses a local buffer (and is therefore thread-safe) instead of a static one. – Nicolas Bachschmidt Jun 27 '12 at 23:46
-
AFAIK, the static buffer used by `inet_ntoa()` is declared in TLS storage so it is thread-safe. But if your platform has `inet_ntop()`, so much the better. – Remy Lebeau Jun 28 '12 at 00:54
-
@NicolasBachschmidt: It's not `sin6->addr.__u6_addr.__u6_addr8`. It's `sin6_addr.s6_addr`. Reference: [link](http://uw714doc.sco.com/en/SDK_netapi/sockC.TheIPv6sockaddrstructure.html) – Muhammad Waqar Jun 28 '12 at 05:47
-
Thanks you. I read my local headers instead of reading the reference. That's fixed. – Nicolas Bachschmidt Jun 28 '12 at 08:26
-
2"Then add 12 to the pointer because the 12 first bytes are not interesting (10 0x00, then 2 0xff)." I would test these bytes before... – glglgl Jul 10 '12 at 10:19
If you want to be compatible with other types of addresses, use getnameinfo.
char hostbuf[NI_MAXHOST];
char *host;
if (getnameinfo(addr, addrlen, hostbuf, sizeof(hostbuf), NULL, 0, NI_NUMERICHOST))
;//error
if (strncmp(hostbuf, "::ffff:", sizeof("::ffff:") - 1) == 0)
host = hostbuf + sizeof("::ffff:") - 1;
else
host = hostbuf;

- 6,697
- 27
- 34
-
1You need to use `strlen("::ffff:")` instead of `sizeof("::ffff:")`. – Remy Lebeau Jun 27 '12 at 22:55
-
@RemyLebeau no, this works. It does include the NUL byte though, hence the `- 1`. – Per Johansson Jun 27 '12 at 23:04
-
2You are assuming `sizeof("::ffff:")` is being interpretted the same as `sizeof(char[8])` on all compilers, which is not a guarantee. It could be interpretted as `sizeof(char*)` instead, which would return 4 on 32-bit systems and 8 on 64-bit systems. The correct value needed by this code is 7, which is what `strlen("::ffff:")` returns without needing the `-1`. – Remy Lebeau Jun 28 '12 at 00:52
-
1I don't know if there are such compilers, but they'd be buggy if there are. The standard is pretty clear that "::ffff:" is a char[8] in all circumstances. It might then degenerate into a char* if appropriate, following the normal decay rules. – Per Johansson Jun 28 '12 at 08:37
-
1I still would not rely on the `sizeof()` behavior even if it does work. The code is logically comparing string values and operating on character counts instead of byte counts, so it makes more sense to use `strlen()` anyway. – Remy Lebeau Jun 28 '12 at 20:51
Once you have recognised an IPv4 mapped address, the IPv4 portion is simply the least significant four bytes of the address. I believe that this can be done as follows:
struct sockaddr *address; // this is the address
struct sockaddr_in6 *addrv6 = (struct sockaddr_in6 *)address;
unsigned long address;
memcpy(&address, addrv6->sin6_addr.s6_addr + 11, 4);
The documentation states that the address appears in network order (most significant byte first). If this differs from you machine architecture, you need to call htonl() in order to reverse byte order.

- 4,453
- 6
- 39
- 69