Hello again,

since you are not completely convinced, I undertook the labour
to develop a your original code into a domain agnostic version.

Remember in all your experiments, that any outcome is influenced
by many factors:

    mapping of IPv4 addresses to IPv6 addresses,

    the value of "net.ipv6.bindv6only",

    the fact that Xinetd prefers a dual stacked server, 

    a choice between

        nc6  from "netcat6",

        ncat from "nmap".

In particular these last two do not treat address mapping
in a fully identical way,

You will certainly recognise most of your original code
in the following rewrite. There is a particular passage
that tries to enforce a dual-stacked listener, but other-
wise the recipe is standard practice.



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

void write_client_addr(int fd) {

    struct sockaddr_storage addr;
    socklen_t addr_l;
    char addrbuff[256];
    char outputbuff[256];
    int outputsize;

    addr_l = sizeof(addr);
    getpeername(fd, (struct sockaddr *) &addr, &addr_l);

    getnameinfo((struct sockaddr *) &addr, addr_l,
                addrbuff, sizeof(addrbuff), NULL, 0, NI_NUMERICHOST);
    
    outputsize = snprintf(outputbuff, sizeof(outputbuff),
                          "Your address is %s\n", addrbuff);
    write(fd, outputbuff, outputsize);
}

int main(int argc, char *argv[]) {
    int client_fd = 0;

    if (argc == 1) {
        int status, val, s;
        const char *portstr = "1942";
        struct addrinfo hints, *res, *ai;
        struct sockaddr_storage farAddr;
        socklen_t farAddrL;

        s = -1;
        memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;

        if ( (status = getaddrinfo(NULL, portstr, &hints, &res)) == 0)
        {
            /* We want to get IPv6 if at all possible.  */
            for (ai = res; ai != NULL; ai = ai->ai_next)
                if (ai->ai_family == AF_INET6)
                    break;

            if (ai == NULL)
                ai = res; /* Failure: roll back.  */

            for ( ; ai != NULL; ai = ai->ai_next)
            {
                if ( (s = socket(ai->ai_family, ai->ai_socktype, 
ai->ai_protocol)) < 0)
                    continue;

                val = 1;
                if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) 
< 0)
                    fprintf(stderr, "setsockopt() failed.\n");

                val = 0;
                if ((ai->ai_family == AF_INET6)
                        && (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &val, 
sizeof(val)) < 0))
                    fprintf(stderr, "Failed in creating dual-stacked 
listener.\n");

                if ( bind(s, ai->ai_addr, ai->ai_addrlen) == 0 )
                    if ( listen(s, 10) >= 0 )
                        break;

                close(s); /* Try next candidate address.  */
                s = -1;
            }

            freeaddrinfo(res);
            if ( ai == NULL ) {
                fprintf(stderr, "Failed at establishing a listener.\n");
                return EXIT_FAILURE;
            }
        } else { /* Failed at obtaining even an address.  */
            fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(status));
            return EXIT_FAILURE;
        }

        farAddrL = sizeof(farAddr);
        client_fd = accept(s, (struct sockaddr *) &farAddr, &farAddrL);
    }

    write_client_addr(client_fd);

    return EXIT_SUCCESS;
}



-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to