Search code examples
cposix

inet_ntop returning partically incorrect IPv6 address


I am aware of this similar question, but the answers do not make sense and are possibly for a different problem.

In my iOS app I connect to a server using CFSockets and wish to show the remote address of the server. When using IPv4 it works as expected, but there are weird results with IPv6 where the network prefix of the address are correct, but the host bits are completely different.

int sock_fd = <...> // Assume I already have the fd
struct sockaddr addr;
socklen_t addr_len = sizeof(addr);
getpeername(sock_fd, &addr, &addr_len);
char addressString[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, addressString, INET6_ADDRSTRLEN);

What I expected was 2607:f2f8:a4c8::2 but what I get is an address with the correct network prefix but different host bits each time, e.g:

               vvvvvvvvvvvvvvvvvvvv Random?
2607:f2f8:a4c8:0:c400:13b0:f6c5:afa
^^^^^^^^^^^^^^ Correct


Solution

  • The man page of getpeername(2) gives a hint as to why this is happening:

    The address_len parameter should be initialized to indicate the amount of space pointed to by address. On return it contains the actual size of the address returned (in bytes).

    The address is truncated if the buffer provided is too small.

    The size of struct sockaddr is too small for IPv6 addresses and will result in the address being truncated.

    You need to use struct sockaddr_storage with getpeername rather than just struct sockaddr

    struct sockaddr_storage addr;
    socklen_t addr_len = sizeof(addr);
    getpeername(socket, (struct sockaddr *)&addr, &addr_len)