inet_ntop and getaddrinfo - Unix

This is a discussion on inet_ntop and getaddrinfo - Unix ; Hello folks, I came across a really weird "bug" in my code. Here is the code, without the header files (assume the correct header files are included) -- snip.c -- int main(int argc, char **argv) { char buf[INET6_ADDRSTRLEN]; struct addrinfo ...

+ Reply to Thread
Results 1 to 5 of 5

Thread: inet_ntop and getaddrinfo

  1. inet_ntop and getaddrinfo

    Hello folks,
    I came across a really weird "bug" in my code.
    Here is the code, without the header files (assume the correct header
    files are included)

    -- snip.c --
    int main(int argc, char **argv) {

    char buf[INET6_ADDRSTRLEN];
    struct addrinfo *ptr;
    int ret;

    /* ./a.out google.com 80 */
    if(argc != 3)
    return -1;

    if((ret = getaddrinfo(argv[1], argv[2], NULL, &ptr)) != 0) {
    gai_strerror(ret);
    return -1;
    }

    while(ptr != NULL) {
    ret = socket(ptr->ai_family, ptr->ai_socktype, ptr-
    >ai_protocol);

    if(ret == -1)
    perror("socket");
    else {
    if(connect(ret, ptr->ai_addr, ptr->ai_addrlen) == -1)
    perror("connect");
    else {
    /* doesnt work, prints nonsense */
    printf("connected to %s\n", inet_ntop(ptr->ai_family,
    ptr->ai_addr, buf, sizeof buf));

    /* works, notice the & in ptr->ai_addr */
    printf("connected to %s\n", inet_ntop(ptr->ai_family,
    &ptr->ai_addr, buf, sizeof buf));
    }
    close(ret);
    }
    ptr = ptr->ai_next;
    }


    return 0;
    }
    -- snip.c --

    I have completely no idea why this happends.
    inet_ntop() requires a pointer to a structure.
    the ai_addr member of the addrinfo struct is 'struct sockaddr *',
    which means &ai_addr is 'struct sockaddr **'
    It only makes sense to pass ptr->ai_addr. The expression ptr->ai_addr
    evaluates to a pointer to a structure, which is what inet_ntop wants.

    Please help me with this matter..

  2. Re: inet_ntop and getaddrinfo

    vippstar@gmail.com writes:

    [please see original for code]

    > -- snip.c --
    >
    > I have completely no idea why this happends.
    > inet_ntop() requires a pointer to a structure.
    > the ai_addr member of the addrinfo struct is 'struct sockaddr *',


    inet_ntop requires a pointer to an actual address, not a pointer to
    a struct sockaddr. Assuming the address would be an IPv4-address, the
    'actual type' of the returned address structure would be struct
    sockaddr_in, defined as

    struct sockaddr_in {
    sa_family_t sin_family;
    u_int16_t sin_port;
    struct in_addr sin_addr;
    };

    and the correct argument to inet_ntop would be the address of the
    sin_addr member of this structure. An equivalent way to pass the
    same argument would be to use

    ptr->ai_addr->sa_data + 2

    sa_data is the (protocol specific) address data area of a struct
    sockaddr, ie exluding metainformation like the address family, and
    the increment skips over the two bytes representing the port.


  3. Re: inet_ntop and getaddrinfo

    On Mar 16, 5:03 pm, Rainer Weikusat wrote:
    > vipps...@gmail.com writes:
    >
    > [please see original for code]
    >
    > > -- snip.c --

    >
    > > I have completely no idea why this happends.
    > > inet_ntop() requires a pointer to a structure.
    > > the ai_addr member of the addrinfo struct is 'struct sockaddr *',

    >
    > inet_ntop requires a pointer to an actual address, not a pointer to
    > a struct sockaddr. Assuming the address would be an IPv4-address, the
    > 'actual type' of the returned address structure would be struct
    > sockaddr_in, defined as
    >
    > struct sockaddr_in {
    > sa_family_t sin_family;
    > u_int16_t sin_port;
    > struct in_addr sin_addr;
    > };
    >
    > and the correct argument to inet_ntop would be the address of the
    > sin_addr member of this structure. An equivalent way to pass the
    > same argument would be to use
    >
    > ptr->ai_addr->sa_data + 2
    >
    > sa_data is the (protocol specific) address data area of a struct
    > sockaddr, ie exluding metainformation like the address family, and
    > the increment skips over the two bytes representing the port.


    Thanks a lot, so what's the correct way to pass what's returned from
    getaddrinfo() to inet_ntop()?
    &ptr->ai_addr? or ptr->ai_addr->sa_data + 2?
    Or both are OK?

  4. Re: inet_ntop and getaddrinfo

    vippstar@gmail.com writes:
    > On Mar 16, 5:03 pm, Rainer Weikusat wrote:
    >> vipps...@gmail.com writes:
    >>
    >> [please see original for code]
    >>
    >> > -- snip.c --

    >>
    >> > I have completely no idea why this happends.
    >> > inet_ntop() requires a pointer to a structure.
    >> > the ai_addr member of the addrinfo struct is 'struct sockaddr *',

    >>
    >> inet_ntop requires a pointer to an actual address, not a pointer to
    >> a struct sockaddr. Assuming the address would be an IPv4-address, the
    >> 'actual type' of the returned address structure would be struct
    >> sockaddr_in, defined as
    >>
    >> struct sockaddr_in {
    >> sa_family_t sin_family;
    >> u_int16_t sin_port;
    >> struct in_addr sin_addr;
    >> };
    >>
    >> and the correct argument to inet_ntop would be the address of the
    >> sin_addr member of this structure. An equivalent way to pass the
    >> same argument would be to use
    >>
    >> ptr->ai_addr->sa_data + 2
    >>
    >> sa_data is the (protocol specific) address data area of a struct
    >> sockaddr, ie exluding metainformation like the address family, and
    >> the increment skips over the two bytes representing the port.

    >
    > Thanks a lot, so what's the correct way to pass what's returned from
    > getaddrinfo() to inet_ntop()?
    > &ptr->ai_addr? or ptr->ai_addr->sa_data + 2?


    ,----
    | inet_ntop requires a pointer to an actual address, not a pointer to
    | a struct sockaddr.
    |
    | [struct sockaddr_in]
    |
    | the correct argument to inet_ntop would be the address of the
    | sin_addr member of this structure.
    `----

    This means one option would be to convert the struct sockaddr *
    to a struct sockaddr_in * and use the address of the sin_addr member
    of that, eg

    struct sockaddr_in const *sin;

    sin = (void *)ptr->ai_addr;

    ... inet_ntop(..., &sin->sin_addr)

    A struct sockaddr consists of

    - a 'common' metadata field (aka 'address family')
    - a char array holding per-protocol address information

    The name of the later is sa_data. The per-protocol address information
    of a struct sockaddr_in consists of a 16-bit port number, followed by
    the (32 bit) IPv4 address. This means, assuming the definitions etc
    above, that

    ptr->ai_addr->sa_data + 2 == (char *)&sin->sin_addr

    Your program actually prints nonsense when passing &ptr->ai_addr,
    too. Just more reasonably appearing nonsense. The correct output would
    be (one set of it):

    [rw@fever]/tmp $./a.out www.google.de 80
    connected to 209.85.129.99
    connected to 209.85.129.99
    connected to 209.85.129.104
    connected to 209.85.129.104
    connected to 209.85.129.147
    connected to 209.85.129.147

    (2nd output statement deleted). The code generating this:

    struct sockaddr_in const *sin;

    [...]

    sin = (struct sockaddr_in *)ptr->ai_addr;
    printf("connected to %s\n", inet_ntop(ptr->ai_family, &sin->sin_addr, buf, sizeof buf));

  5. Re: inet_ntop and getaddrinfo

    On Mar 16, 6:17 pm, Rainer Weikusat wrote:
    > | inet_ntop requires a pointer to an actual address, not a pointer to
    > | a struct sockaddr.

    I know you said this before but it's now that I understood it; thanks
    for being patient..
    It's weird I ignored that EVEN after reading the manual of inet_ntop
    or your post.
    I certainly need some sleep. ;-)
    >
    > Your program actually prints nonsense when passing &ptr->ai_addr,
    > too. Just more reasonably appearing nonsense. The correct output would
    > be (one set of it):

    Oh, that's an embarrassing mistake..
    This settles it. My whole confusion was based on the false assumption
    that &ptr->ai_addr works.
    > [rw@fever]/tmp $./a.outwww.google.de80

    The google interface appears to be buggy, it eats the whitespace
    here.. I wonder why.
    >
    > (2nd output statement deleted). The code generating this:
    >
    > struct sockaddr_in const *sin;
    >
    > [...]
    >
    > sin = (struct sockaddr_in *)ptr->ai_addr;
    > printf("connected to %s\n", inet_ntop(ptr->ai_family, &sin->sin_addr, buf, sizeof buf));

    Yep. thanks .

+ Reply to Thread