diff --git a/p910nd.c b/p910nd.c index e32cca5..4395128 100644 --- a/p910nd.c +++ b/p910nd.c @@ -16,6 +16,9 @@ * Port 9100+n will then be passively opened * n defaults to 0 * + * Version 0.94 + * Support IPv6 + * * Version 0.93 * Fix open call to include mode, required for O_CREAT * @@ -141,6 +144,40 @@ static char *device = 0; static int bidir = 0; static char *bindaddr = 0; + +/* Helper function: convert a struct sockaddr address (IPv4 and IPv6) to a string */ +char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) +{ + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen); + break; + default: + strncpy(s, "Unknown AF", maxlen); + return NULL; + } + return s; +} + +uint16_t get_port(const struct sockaddr *sa) +{ + uint16_t port; + switch(sa->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + break; + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + break; + default: + return 0; + } + return port; +} + void usage(void) { fprintf(stderr, "%s %s %s\n", progname, version, copyright); @@ -399,11 +436,13 @@ int copy_stream(int fd, int lp) void one_job(int lpnumber) { int lp; - struct sockaddr_in client; + struct sockaddr_storage client; socklen_t clientlen = sizeof(client); - if (getpeername(0, (struct sockaddr *)&client, &clientlen) >= 0) - syslog(LOG_NOTICE, "Connection from %s port %hu\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); + if (getpeername(0, (struct sockaddr *)&client, &clientlen) >= 0) { + char host[INET6_ADDRSTRLEN]; + syslog(LOG_NOTICE, "Connection from %s port %hu\n", get_ip_str((struct sockaddr *)&client, host, sizeof(host)), get_port((struct sockaddr *)&client)); + } if (get_lock(lpnumber) == 0) return; /* Make sure lp device is open... */ @@ -423,10 +462,11 @@ void server(int lpnumber) #endif int netfd, fd, lp, one = 1; socklen_t clientlen; - struct sockaddr_in netaddr, client; + struct sockaddr_storage client; + struct addrinfo hints, *res, *ressave; char pidfilename[sizeof(PIDFILE)]; + char service[sizeof(BASEPORT+lpnumber-'0')+1]; FILE *f; - int ipret; #ifndef TESTING switch (fork()) { @@ -465,47 +505,55 @@ void server(int lpnumber) if (get_lock(lpnumber) == 0) exit(1); #endif -#ifdef USE_GETPROTOBYNAME - if ((proto = getprotobyname("tcp")) == NULL) { - syslog(LOGOPTS, "Cannot find protocol for TCP!\n"); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + (void)snprintf(service, sizeof(service), "%hu", (BASEPORT + lpnumber - '0')); + if (getaddrinfo(bindaddr, service, &hints, &res) != 0) { + syslog(LOGOPTS, "getaddr: %m\n"); exit(1); } - if ((netfd = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) + ressave = res; + while (res) { +#ifdef USE_GETPROTOBYNAME + if ((proto = getprotobyname("tcp6")) == NULL) { + if ((proto = getprotobyname("tcp")) == NULL) { + syslog(LOGOPTS, "Cannot find protocol for TCP!\n"); + exit(1); + } + } + if ((netfd = socket(res->ai_family, res->ai_socktype, proto->p_proto)) < 0) #else - if ((netfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) + if ((netfd = socket(res->ai_family, res->ai_socktype, IPPROTO_IP)) < 0) #endif - { - syslog(LOGOPTS, "socket: %m\n"); - exit(1); - } - if (setsockopt(netfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) - < 0) { - syslog(LOGOPTS, "setsocketopt: %m\n"); - exit(1); - } - netaddr.sin_family = AF_INET; - netaddr.sin_port = htons(BASEPORT + lpnumber - '0'); - if (bindaddr == 0) { - netaddr.sin_addr.s_addr = htonl(INADDR_ANY); - } else { - ipret = inet_pton(AF_INET, bindaddr, &netaddr.sin_addr.s_addr); - if (ipret < 0) { - syslog(LOGOPTS, "inet_pton: %m\n"); - exit(1); - } else if (ipret == 0) { - syslog(LOGOPTS, "inet_pton: invalid bind IP address\n"); - exit(1); + { + syslog(LOGOPTS, "socket: %m\n"); + close(netfd); + res = res->ai_next; + continue; } + if (setsockopt(netfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { + syslog(LOGOPTS, "setsocketopt: %m\n"); + close(netfd); + res = res->ai_next; + continue; + } + if (bind(netfd, res->ai_addr, res->ai_addrlen) < 0) { + syslog(LOGOPTS, "bind: %m\n"); + close(netfd); + res = res->ai_next; + continue; + } + if (listen(netfd, 5) < 0) { + syslog(LOGOPTS, "listen: %m\n"); + close(netfd); + res = res->ai_next; + continue; + } + break; } - memset(netaddr.sin_zero, 0, sizeof(netaddr.sin_zero)); - if (bind(netfd, (struct sockaddr *)&netaddr, sizeof(netaddr)) < 0) { - syslog(LOGOPTS, "bind: %m\n"); - exit(1); - } - if (listen(netfd, 5) < 0) { - syslog(LOGOPTS, "listen: %m\n"); - exit(1); - } + freeaddrinfo(ressave); clientlen = sizeof(client); memset(&client, 0, sizeof(client)); while ((fd = accept(netfd, (struct sockaddr *)&client, &clientlen)) >= 0) { @@ -517,7 +565,8 @@ void server(int lpnumber) continue; } #endif - syslog(LOG_NOTICE, "Connection from %s port %hu accepted\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); + char host[INET6_ADDRSTRLEN]; + syslog(LOG_NOTICE, "Connection from %s port %hu accepted\n", get_ip_str((struct sockaddr *)&client, host, sizeof(host)), get_port((struct sockaddr *)&client)); /*write(fd, "Printing", 8); */ /* Make sure lp device is open... */ @@ -536,7 +585,7 @@ void server(int lpnumber) int is_standalone(void) { - struct sockaddr_in bind_addr; + struct sockaddr_storage bind_addr; socklen_t ba_len; /*