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 [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]