From e0991a9be56d3f19eff06a357674de9cf7338061 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sat, 8 Nov 2008 12:28:28 -0500 Subject: [PATCH] IPv6 support. Should be able to handle either IPv4 or IPv6 transparently. It's untested though. --- src/pwmd.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/src/pwmd.c b/src/pwmd.c index 24d7a793..d66237e1 100644 --- a/src/pwmd.c +++ b/src/pwmd.c @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef HAVE_SETRLIMIT #include @@ -1476,12 +1477,21 @@ static void init_new_connection(gint fd, gchar *addr) } #ifdef WITH_GNUTLS +/* From Beej's Guide to Network Programming. It's a good tutorial. */ +static void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) + return &(((struct sockaddr_in*)sa)->sin_addr); + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + static void *tcp_accept_thread(void *arg) { gint sockfd = (gint)arg; for (;;) { - struct sockaddr_in raddr; + struct sockaddr_storage raddr; socklen_t slen = sizeof(raddr); gint fd = -1; @@ -1497,8 +1507,13 @@ static void *tcp_accept_thread(void *arg) if (quit) break; - if (fd >= 0) - init_new_connection(fd, inet_ntoa(raddr.sin_addr)); + if (fd >= 0) { + gchar s[INET6_ADDRSTRLEN]; + + inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr), + s, sizeof s); + init_new_connection(fd, s); + } } /* Just in case pth_accept() failed for some reason other than EBADF */ @@ -1852,7 +1867,6 @@ int main(int argc, char *argv[]) #ifdef WITH_GNUTLS struct assuan_io_hooks io_hooks = {read_hook, write_hook}; gint ret; - struct sockaddr_in my_addr; #endif #if 0 #ifndef DEBUG @@ -2173,39 +2187,64 @@ int main(int argc, char *argv[]) #ifdef WITH_GNUTLS if (get_key_file_boolean("global", "enable_tcp")) { gchar *tmp, *tmp2; - - if ((sockfd_r = socket(PF_INET, SOCK_STREAM, 0)) == -1) { - warn("socket()"); + struct addrinfo hints, *servinfo, *p; + gint port = get_key_file_integer("global", "tcp_port"); + char buf[7]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port), + &hints, &servinfo)) == -1) { + warnx("getaddrinfo(): %s", gai_strerror(opt)); goto do_exit; } - my_addr.sin_family = PF_INET; - my_addr.sin_port = htons(get_key_file_integer("global", "tcp_port")); - my_addr.sin_addr.s_addr = INADDR_ANY; - memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero)); + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd_r = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + warn("socket()"); + continue; + } - if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &iter, sizeof(int)) == -1) { - warn("setsockopt"); + if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(int)) == -1) { + warn("setsockopt()"); + goto do_exit; + } + + if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd_r); + warn("bind()"); + continue; + } + + opt++; + break; + } + + freeaddrinfo(servinfo); + + if (!p) { + warnx("%s", N_("could not bind")); goto do_exit; } if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) { gchar *tmp = get_key_file_string("global", "tcp_interface"); - if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1) == -1) { + if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1) + == -1) { warn("setsockopt"); + g_free(tmp); goto do_exit; } g_free(tmp); } - if (bind(sockfd_r, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1) { - warn("bind()"); - do_unlink = 1; - goto do_exit; - } - ret = gnutls_certificate_allocate_credentials(&x509_cred); if (ret != GNUTLS_E_SUCCESS) { -- 2.11.4.GIT