Question

getaddrinfo and IPv6

I'm trying to understand what the getaddrinfo function returns :

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>

int main (int argc, char *argv[])
{


struct addrinfo *res = 0 ;

  getaddrinfo("localhost", NULL ,NULL,&res);
  printf("ai_flags -> %i\n", res->ai_flags) ;
  printf("ai_family -> %i\n", res->ai_family) ;
  printf("ai_socktype -> %i\n", res->ai_socktype) ;
  printf("ai_protocol -> %i\n", res->ai_protocol) ;
  printf("ai_addrlen -> %i\n", res->ai_addrlen) ;
  struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
  printf("ai_addr hostname ->  %s\n", inet_ntoa(saddr->sin_addr));

  freeaddrinfo(res);

  return 0 ;
}

results :

ai_flags -> 40
ai_family -> 2
ai_socktype -> 1
ai_protocol -> 6
ai_addrlen -> 16
ai_addr hostname ->  127.0.0.1

In /etc/hosts, I 've got :

127.0.0.1 localhost    
::1     localhost

Getaddrinfo returns only 127.0.0.1 and not ::1 ? I don't understand why ?

The second question is where can I find the meaning of those ints (40,2,1,6 etc) ? I've read the man but there is nothing about that.

I also wanted to know if it's possible to give a IPv6 adress (for example ::1) and the function returns the name : localhost ?

Thanks a lot !!

 21  30213  21
1 Jan 1970

Solution

 11

@jwodder and @onteria_ covered the IPv6 portion well, so I'll just tackle the numbers portion:

ai_flags -> 40

Probably this is going to be the sum of the following two in /usr/include/netdb.h:

# define AI_V4MAPPED    0x0008  /* IPv4 mapped addresses are acceptable.  */
# define AI_ADDRCONFIG  0x0020  /* Use configuration of this host to choose

This is the protocol family, inet, inet6, apx, unix, etc.:

ai_family -> 2

bits/socket.h:78:#define    PF_INET     2   /* IP protocol family.  */
bits/socket.h:119:#define   AF_INET     PF_INET

This is the socket type, stream, dgram, packet, rdm, seqpacket:

ai_socktype -> 1

bits/socket.h:42:  SOCK_STREAM = 1,     /* Sequenced, reliable, connection-based

The higher-level protocol, TCP, UDP, TCP6, UDP6, UDPlite, ospf, icmp, etc:

ai_protocol -> 6

Funny enough, in /etc/protocols:

tcp 6   TCP     # transmission control protocol

The size of the struct sockaddr. (Differs based on the address family! Ugh.)

ai_addrlen -> 16

This is because you're getting back a struct sockaddr_in, see linux/in.h:

#define __SOCK_SIZE__   16      /* sizeof(struct sockaddr)  */
struct sockaddr_in {
  sa_family_t       sin_family; /* Address family       */
  __be16        sin_port;   /* Port number          */
  struct in_addr    sin_addr;   /* Internet address     */

  /* Pad to size of `struct sockaddr'. */
  unsigned char     __pad[__SOCK_SIZE__ - sizeof(short int) -
            sizeof(unsigned short int) - sizeof(struct in_addr)];
};

And the last one, from /etc/hosts :)

ai_addr hostname ->  127.0.0.1
2011-05-10

Solution

 10

res also contains a field struct addrinfo *ai_next;, which is a pointer to additional entries found by getaddrinfo, or NULL if there were no other entries. If you examine res->ai_next, you should find the IPv6 entry.

As for the integer fields in a struct addrinfo, they correspond to predefined constants with implementation-defined values, and the integer values themselves are not of general interest. If you want to know what a given field means, compare it against the constants that can be assigned to that field (SOCK_STREAM, SOCK_DGRAM, etc. for ai_socktype; IPPROTO_TCP, IPPROTO_UDP, etc. for ai_protocol; and so forth) or, for ai_flags, test each bit corresponding to a predefined constant (e.g., if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); }).

2011-05-10