RaspberMan
RaspberMan

Reputation: 51

C - getaddrinfo()

Can someone help me to get the IPs of google.com?

I can't find any good resource on this.
Most tutorials on C network programming create a client socket and a server socket on the same computer. (I don't know in which situation that would make sense)
And none of the codes on beej.us worked for me.

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>

int main(void)
{
    struct addrinfo* res = NULL;
    getaddrinfo("google.com", "443", 0, &res);

    struct addrinfo* i;

    for(i=res; i!=0; res=res->ai_next)
    {
        printf("%s\n", res->ai_addr->sa_data);
    }
}

Output:

�
�
�
���$u
���$u
���$u
���"u
���"u
���"u
��� u
��� u
��� u
���&u
���&u
���&u
Segmentation fault

Upvotes: 4

Views: 20277

Answers (2)

dbush
dbush

Reputation: 223719

First, you never modify i inside of the loop so you end up with an infinite loop. You need to change to loop statement to:

for(i=res; i!=NULL; i=i->ai_next)

Regarding the output, the ai_addr field is of type struct sockaddr *, which is a pointer to a generic socket address struct, and its sa_data field is just a binary blob of the data for that address, not a printable string.

To print these values correctly, you need to inet_ntop function. First, you need to inspect ai_addr->sa_family to see if it is an IPv4 address or an IPv6 address. Then you'll need to cast ai_addr to either a struct sockaddr_in * for IPv4 or struct sockaddr_in6 * for IPv6, then pass the sin_addr or sin6_addr field respectively to inet_ntop along with the address family to convert it to a string.

for(i=res; i!=NULL; i=i->ai_next)
{
    char str[INET6_ADDRSTRLEN];
    if (i->ai_addr->sa_family == AF_INET) {
        struct sockaddr_in *p = (struct sockaddr_in *)i->ai_addr;
        printf("%s\n", inet_ntop(AF_INET, &p->sin_addr, str, sizeof(str)));
    } else if (i->ai_addr->sa_family == AF_INET6) {
        struct sockaddr_in6 *p = (struct sockaddr_in6 *)i->ai_addr;
        printf("%s\n", inet_ntop(AF_INET6, &p->sin6_addr, str, sizeof(str)));
    }
}

Output:

172.217.10.238
172.217.10.238
172.217.10.238
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e

Upvotes: 10

ryyker
ryyker

Reputation: 23208

In This statement i is never being modified in loop body, and because it is not initialized, it never even enters the loop:

for(i=res; i!=0; res=res->ai_next)
{
    printf("%s\n", res->ai_addr->sa_data);
}

Additionally, you are missing a few other parts. The following steps are part of a full example linked below:

Create the following instances of struct addrinfo:

struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;

Then initialize Winsock

   // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

Setup the hints address info structure

ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

Call getaddrinfo

dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
if ( dwRetval != 0 ){//handle error}

Now, for example based on above, your loop would look like:

   for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {//

Entering "www.google.com" 0 on the command line for the complete example (linked below) will look similar to this:
enter image description here

This full Windows example is here. Note: Bug in code, i.e. ptr->ai_cannonname can be null with "www.google.com" so change this line to test before calling:

if(ptr->ai_canonname) printf("\tCanonical name: %s\n", ptr->ai_canonname);

A full Linux example is here.

Upvotes: 3

Related Questions