Michał Ziobro
Michał Ziobro

Reputation: 11812

C socket programming: binding with getaddrinfo() and get device IP server is available

I am creating passive server socket using (as I read 'modern' approach) getaddrinfo(). Using this approach and specifying in hints: AI_PASSIVE, AF_UNSPEC, sock_type I loop through results like this:

 for(ai_ptr = addrinfo_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)

and then create socket and bind to address found in first addrinfo_res.

 bind(ps_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen)

How I can know on which address (not 0.0.0.0) my server is available in local area network?

I have tried this code below to find all interfaces and IP address on them:

 // linked list of structures describing
    // the network interfaces of the local system
    struct ifaddrs *ifaddr, *ifa;
    int n, gai_err;

    if(getifaddrs(&ifaddr) == FAILURE) {
        fprintf(stderr, "getifaddrs: %s\n", strerror(errno));
        return FAILURE;
    }

    // walk through linked list
    for(ifa = ifaddr, n=0; ifa != NULL; ifa = ifa->ifa_next, n++) {

        if(ifa->ifa_addr == NULL)
            continue;

        int family = ifa->ifa_addr->sa_family;

        // display interface name, family
        printf("%-8s %s (%d)\n", ifa->ifa_name,
               (family == AF_INET) ? "AF_INET" :
               (family == AF_INET6) ? "AF_INET6" : "???",
               family);

        // for an AF_INET* interface addresses, display the address
        if(family == AF_INET || family == AF_INET6) {

            char host[NI_MAXHOST];

            if( (gai_err = getnameinfo(ifa->ifa_addr,
                        (family == AF_INET) ? sizeof(struct sockaddr_in) :
                                              sizeof(struct sockaddr_in6),
                        host, NI_MAXHOST,
                        NULL, 0, NI_NUMERICHOST)) != 0) {
                fprintf(stderr, "getnameinfo: %s\n", gai_strerror(gai_err));
            }

            printf("\t\t address: <%s>\n", host);
        }
    }

    freeifaddrs(ifaddr);
    return SUCCESS;

But how I can be sure I will return (print) suitable IP address to which client can connect to?

I have such results:

lo0      ??? (18)
lo0      AF_INET (2)
         address: <127.0.0.1>
lo0      AF_INET6 (30)
         address: <::1>
lo0      AF_INET6 (30)
         address: <fe80::1%lo0>
gif0     ??? (18)
stf0     ??? (18)
en0      ??? (18)
en0      AF_INET6 (30)
         address: <fe80::1088:e458:89a7:7ee9%en0>
en0      AF_INET (2)
         address: <192.168.8.102>
en1      ??? (18)
bridge0  ??? (18)
p2p0     ??? (18)
awdl0    ??? (18)
awdl0    AF_INET6 (30)
         address: <fe80::dce1:4eff:fef8:f3bd%awdl0>
utun0    ??? (18)
utun0    AF_INET6 (30)
         address: <fe80::695f:8478:f380:9efb%utun0>

When I tested server is available only on 192.168.8.102 or IPv6 ::ffff:192.168.102. But on the second en0 AF_INET6 IP address fe80::1088:e458:89a7:7ee9. How to ensure that when someone else takes this program on another computer with different IP addresses and interfaces (like not en0 but eth0?) I will be possible to return correct IP address my server is available, in order he/she know on which IP it could connect from client side program? enter image description here

Upvotes: 0

Views: 1021

Answers (1)

Cheatah
Cheatah

Reputation: 1835

You can not be sure, as any system can have multiple interfaces with different networks and addresses. Even the route back does not has to be the same as the route to your system.

Furthermore, a client may have to connect to a different address and port because of NAT anywhere between the client and the server.

You could get the addresses from recvmsg using the IP_PKTINFO socket option to see which address a message was destined to, but again, this could have been translated on network level.

Upvotes: 0

Related Questions