Thread: Can't get the whole IP address with getaddrinfo

  1. #1
    Registered User
    Join Date
    Apr 2010
    Posts
    50

    Can't get the whole IP address with getaddrinfo

    Hi.

    I have this code above:

    Code:
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
      struct addrinfo hints, *res;
      int errcode;
      char addrstr[100];
    
      memset (&hints, 0, sizeof (hints));
      hints.ai_family = PF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;
    
      errcode = getaddrinfo ("www.google.com", NULL, &hints, &res);
      if (errcode != 0)
      {
          perror ("getaddrinfo failed");
          return 1;
      }
    
    
      switch (res->ai_family)
      {
        case AF_INET:
          printf("IPV4\n");
          inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
          printf("%s\n",addrstr);
          break;
        case AF_INET6:
          printf("IPV6\n");
          inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
          printf("%s\n",addrstr);
          break;
      }
      
      
    
        
        return 0;
    }
    but when i run it it returns me as a google's ip this :

    0.0.74.125
    Any idea ?

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    You call inet_ntop() with incorrect parameters. The second parameter should be &(((struct sockaddr_in *)curr->ai_addr)->sin_addr) for IPv4, and &(((struct sockaddr_in6 *)curr->ai_addr)->sin6_addr) for IPv6. The pointer you use happens to point to the port number for IPv4 (which is zero as no service was specified), and that's why you get that particular string as output. Also, the last parameter should be just sizeof addrstr.

    There are several other issues in your code. For example, you only output the first result, not all of them. Consider the following program, which takes the host name(s) as command-line parameters, and prints the usage if no parameters are specified:
    Code:
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdio.h>
    #include <errno.h>
    
    int main(int argc, char *argv[])
    {
        struct addrinfo hints, *list, *curr;
        int arg, errcode;
    
        if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
            fprintf(stderr, "\n");
            fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
            fprintf(stderr, "       %s HOSTNAME ...\n", argv[0]);
            fprintf(stderr, "\n");
            return EXIT_FAILURE;
        }
    
        for (arg = 1; arg < argc; arg++) {
    
            memset(&hints, 0, sizeof (hints));
            hints.ai_family = PF_UNSPEC;
            hints.ai_socktype = SOCK_STREAM;
    
            errcode = getaddrinfo(argv[arg], NULL, &hints, &list);
            if (errcode) {
                fprintf(stderr, "%s: %s.\n", argv[arg], gai_strerror(errcode));
                return EXIT_FAILURE;
            }
    
            for (curr = list; curr != NULL; curr = curr->ai_next) {
                if (curr->ai_family == AF_INET) {
                    char addrbuf[INET_ADDRSTRLEN + 1];
                    const char *addr;
    
                    addr = inet_ntop(AF_INET, &(((struct sockaddr_in *)curr->ai_addr)->sin_addr), addrbuf, sizeof addrbuf);
                    if (addr == NULL) {
                        fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
                        return EXIT_FAILURE;
                    }
                    printf("%s: IPv4 = %s\n", argv[arg], addr);
    
                } else
                if (curr->ai_family == AF_INET6) {
                    char addrbuf[INET6_ADDRSTRLEN + 1];
                    const char *addr;
    
                    addr = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)curr->ai_addr)->sin6_addr), addrbuf, sizeof addrbuf);
                    if (addr == NULL) {
                        fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
                        return EXIT_FAILURE;
                    }
                    printf("%s: IPv6 = %s\n", argv[arg], addr);
    
                }
            }
    
            freeaddrinfo(list);
    
        }
    
        return EXIT_SUCCESS;
    }
    Please compare the above code to yours, to see how you're supposed to use e.g. the getaddrinfo() and inet_ntop() interfaces. It should not be too long or complicated to understand, I hope.

    I recommend compiling this using gcc -Wall -Wextra -O2 example.c -o example (i.e. enabling all warnings). When I run ./example www.google.com, the output is
    www.google.com: IPv4 = 74.125.133.106
    www.google.com: IPv4 = 74.125.133.105
    www.google.com: IPv4 = 74.125.133.103
    www.google.com: IPv4 = 74.125.133.147
    www.google.com: IPv4 = 74.125.133.99
    www.google.com: IPv4 = 74.125.133.104
    www.google.com: IPv6 = 2a00:1450:400c:c07::93
    which shows all the addresses matching the name. (A good application should try them in order, not just fail if the first one fails. That's what the client example in the getaddrinfo(3) man page does.)

    Questions?

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    First, #include <arpa/inet.h>, which is needed for inet_ntop().

    You need to treat the struct sockaddr as the proper type, by casting it. Example:
    Code:
    inet_ntop(res->ai_family, &((struct sockaddr_in *)res->ai_addr)->sin_addr, addrstr, 100);
    res->ai_addr->sa_data doesn't contain anything useful, as far as you're concerned. It's just an opaque bunch of data that is used by the “subtypes” of struct sockaddr to store address data. How that address data is stored is up to the subtype.

  4. #4
    Registered User
    Join Date
    Apr 2010
    Posts
    50
    Thank you very much for your answer, but can you explain what that line of code does ?

    Code:
    &((struct sockaddr_in *)res->ai_addr)->sin_addr
    Does it cast addrinfo struct into sockaddr_in struct ?

  5. #5
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    can you explain what that line of code does
    res->ai_addr has type struct sockaddr * (i.e. pointer to struct sockaddr).

    You know that it is really pointing to a struct sockaddr_in *, because res->ai_family tells you so.

    So you're not casting the struct (which is not possible), but rather, a pointer to the struct. This is a very crude sort of polymorphism: struct sockaddr is a generic “superclass”, and struct sockaddr_in is a “subclass” of it. By doing this, you don't need separate socket functions for each socket type (e.g. you don't need connect_afinet() and connect_afinet6()). One single function can connect any socket type. The drawback is that you have to manually, via casting, convert between the base socket type and your target socket type.

    Breaking down the code above:

    Code:
    struct sockaddr_in *in = (struct sockaddr_in *)res->ai_addr; /* converts the struct sockaddr * to a struct sockaddr_in * */
    &in->sin_addr; /* takes the address of the struct sockaddr_in's sin_addr field */

  6. #6
    Registered User
    Join Date
    Apr 2010
    Posts
    50
    Thank you very much for your explanation. Very helpful.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. getaddrinfo : who is right?
    By icegood in forum C Programming
    Replies: 2
    Last Post: 12-12-2012, 06:27 PM
  2. ip address using getaddrinfo()
    By ueg1990 in forum C Programming
    Replies: 4
    Last Post: 07-07-2012, 06:54 PM
  3. is getaddrinfo really necessary?
    By sunjayc99 in forum Networking/Device Communication
    Replies: 3
    Last Post: 06-28-2008, 03:14 PM
  4. Why create a wrapper fo getaddrinfo()
    By Overworked_PhD in forum Linux Programming
    Replies: 2
    Last Post: 11-10-2007, 01:37 AM
  5. getaddrinfo()
    By Cactus_Hugger in forum Windows Programming
    Replies: 1
    Last Post: 07-24-2006, 02:41 AM