;; IPv6 patch for Ian Freislich's popd ;; Dec 6, 2000 by Hajimu UMEMOTO ;; ;; You can find popd from: ;; http://people.freebsd.org/~markm/popd.tar.gz ;; Index: popd/popd.c diff -u popd/popd.c.orig popd/popd.c --- popd/popd.c.orig Thu Sep 7 05:57:59 2000 +++ popd/popd.c Thu Dec 7 02:08:38 2000 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,8 @@ usage(void) { printf("Usage: \n"); + printf("\t-4\tlisten on IPv4\n"); + printf("\t-6\tlisten on IPv6\n"); printf("\t-A realm\tAdd realm to username if virtual mode and\n"); printf("\t\tno realm was supplied\n"); printf("\t-B dir\tBulletins to all users can be found in dir\n"); @@ -170,9 +173,10 @@ getconfig(int argc, char **argv) { extern char *optarg; - struct servent *servent; + struct addrinfo hints, *res; int ch; + int inet_flag = 0, inet6_flag = 0; config.socket_in = stdin; config.socket_out = stdout; @@ -182,7 +186,8 @@ config.secrets = NULL; config.dbfile = _DB_FILE; config.autodelete = FALSE; - config.bind_address.s_addr = htonl(INADDR_ANY); + config.family = PF_UNSPEC; + config.bind_address = NULL; config.bulletindir = NULL; config.defaultrealm = NULL; config.daemonise = TRUE; @@ -201,8 +206,16 @@ config.remove = FALSE; while ((ch = getopt(argc, argv, - "A:B:DE:FLMR:S:UVa:b:de:hm:n:p:r:t:u:x")) != -1) { + "46A:B:DE:FLMR:S:UVa:b:de:hm:n:p:r:t:u:x")) != -1) { switch (ch) { + case '4': + config.family = PF_INET; + inet_flag++; + break; + case '6': + config.family = PF_INET6; + inet6_flag++; + break; case 'A': config.defaultrealm = optarg; break; @@ -243,10 +256,16 @@ config.dbfile = optarg; break; case 'b': - if (!inet_aton(optarg, &config.bind_address)) { + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(optarg, NULL, &hints, &res)) { fprintf(stderr, "Inavalid address\n"); usage(); } + freeaddrinfo(res); + config.bind_address = optarg; break; case 'd': config.daemonise = FALSE; @@ -261,7 +280,17 @@ config.hashdepth = atoi(optarg); break; case 'p': - config.port = atoi(optarg); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(NULL, optarg, &hints, &res)) { + fprintf(stderr, + "Inavalid port number\n"); + usage(); + } + freeaddrinfo(res); + config.port = optarg; break; case 'r': insert_radius_server(optarg); @@ -281,17 +310,11 @@ usage(); } } + if (inet_flag && inet6_flag) + config.family = PF_UNSPEC; - if (!config.port) { - if ((servent = getservbyname("pop3", "tcp"))) { - config.port = ntohs(servent->s_port); - } - else { - fprintf(stderr, - "Couldn't get pop3 port from services\n"); - exit(EX_PROTOCOL); - } - } + if (!config.port) + config.port = "pop3"; } /* Determine if we've been handed a socket by a program such as @@ -302,12 +325,14 @@ main(int argc, char **argv) { struct user *user = NULL; - struct sockaddr_in addr; - struct protoent *prot; - struct pollfd pollfd; + struct sockaddr_storage addr; + struct pollfd *pollfd; + struct addrinfo hints, *res, *r; int serverfd, curfd, result, - facility; + facility, error, npollfd, i, + on = 1; socklen_t addrlen; + char ip[NI_MAXHOST]; addrlen = sizeof(addr); facility = LOG_NOTICE; @@ -327,23 +352,79 @@ * but we weren't given a connected socket, * so open up a socket. */ - prot = getprotobyname("TCP"); - serverfd = socket(AF_INET, SOCK_STREAM, prot->p_proto); - memset(&addr, '\0', addrlen); - addr.sin_family = AF_INET; - addr.sin_port = htons(config.port); - addr.sin_addr = config.bind_address; - setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &serverfd, - sizeof(serverfd)); - if (bind(serverfd, (struct sockaddr *)&addr, addrlen)) { - fprintf(stderr, "Can't bind port %d on %s\n", - config.port, inet_ntoa(config.bind_address)); - syslog(facility, "Can't bind port %d on %s\n", - config.port, inet_ntoa(config.bind_address)); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = config.family; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(config.bind_address, config.port, + &hints, &res); + if (error) { + fprintf(stderr, "%s\n", gai_strerror(error)); + syslog(facility, "%s\n", gai_strerror(error)); + exit(EX_OSFILE); + } + + /* Count max number of sockets we may open */ + for (npollfd = 0, r = res; r; r = r->ai_next, npollfd++) + ; + + pollfd = malloc(npollfd * sizeof(struct pollfd)); + if (!pollfd) { + fprintf(stderr, + "couldn't allocate memory for sockets"); + syslog(facility, + "couldn't allocate memory for sockets"); + exit(EX_OSFILE); + } + + npollfd = 0; /* num of sockets counter at start of array */ + for (r = res; r; r = r->ai_next) { + serverfd = socket(r->ai_family, r->ai_socktype, + r->ai_protocol); + if (serverfd < 0) + continue; + if (setsockopt(serverfd, SOL_SOCKET, + SO_REUSEADDR, &on, sizeof(on)) < 0) { + close(serverfd); + continue; + } +#if defined(IPV6_BINDV6ONLY) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) + if (r->ai_family == AF_INET6) { + if (setsockopt(serverfd, IPPROTO_IPV6, + IPV6_BINDV6ONLY, + &on, sizeof(on)) < 0) { + close(serverfd); + continue; + } + } +#endif + if (bind(serverfd, r->ai_addr, r->ai_addrlen) < 0) { + getnameinfo(r->ai_addr, r->ai_addrlen, + ip, sizeof(ip), NULL, 0, + NI_NUMERICHOST | NI_WITHSCOPEID); + fprintf(stderr, "Can't bind port %s on %s\n", + config.port, ip); + syslog(facility, "Can't bind port %s on %s\n", + config.port, ip); + close(serverfd); + continue; + } + pollfd[npollfd++].fd = serverfd; + } + + if (res) + freeaddrinfo(res); + + if (npollfd == 0) { + fprintf(stderr, "Couldn't bind to any socket"); + syslog(facility, "Couldn't bind to any socket"); + free(pollfd); exit(EX_OSFILE); } + if (config.debug) { - fprintf(stderr, "Got socket and listening on port %d\n", + fprintf(stderr, + "Got socket and listening on port %s\n", config.port); } if (config.daemonise && !config.debug) { @@ -370,37 +451,49 @@ } } - listen(serverfd, LISTEN_BACKLOG); - pollfd.fd = serverfd; - pollfd.events = POLLRDNORM; + for (i = 0; i < npollfd; i++) { + listen(pollfd[i].fd, LISTEN_BACKLOG); + pollfd[i].events = POLLRDNORM; + pollfd[i].revents = 0; + } curfd = -1; - while (poll(&pollfd, 1, INFTIM)) { + result = -1; + while (result != 0 && poll(pollfd, npollfd, INFTIM)) { if (errno == EINTR) { removesignal(); continue; } - curfd = accept(serverfd, (struct sockaddr*)&addr, - &addrlen); - if (curfd < 0) { - syslog(facility, - "Error accepting connection\n"); - continue; - } + for (i = 0; i < npollfd; ++i) { + if (!pollfd[i].revents) + continue; + pollfd[i].revents = 0; + curfd = accept(pollfd[i].fd, + (struct sockaddr*)&addr, + &addrlen); + if (curfd < 0) { + syslog(facility, + "Error accepting connection\n"); + continue; + } - result = fork(); - if (result < 0) { - syslog(facility, "Unable to fork, sleeping..."); - sleep(10); - continue; + result = fork(); + if (result < 0) { + syslog(facility, + "Unable to fork, sleeping..."); + sleep(10); + continue; + } + if (result == 0) + break; + close(curfd); + if (config.debug) + fprintf(stderr, + "Giving child %d fdes %d\n", + result, curfd); } - if (result == 0) - break; - close(curfd); - if (config.debug) - fprintf(stderr, "Giving child %d fdes %d\n", - result, curfd); } - close(serverfd); + for (i = 0; i < npollfd; ++i) + close(pollfd[i].fd); if (!(config.socket_in = fdopen(curfd, "r")) || !(config.socket_out = fdopen(curfd, "w"))) exit(EX_PROTOCOL); @@ -412,12 +505,14 @@ opensigpipe(); setsignals(); if (config.daemonise || config.debug) - syslog(facility, "Connection from %s", - inet_ntoa(addr.sin_addr)); + getnameinfo((struct sockaddr *)&addr, addr.ss_len, + ip, sizeof(ip), NULL, 0, + NI_NUMERICHOST | NI_WITHSCOPEID); + if (config.daemonise || config.debug) + syslog(facility, "Connection from %s", ip); if (config.debug) fprintf(stderr, "Handling connection from %s " - "on file descriptor %d\n", inet_ntoa(addr.sin_addr), - fileno(config.socket_in)); + "on file descriptor %d\n", ip, fileno(config.socket_in)); if (config.secrets) config.timestamp = make_timestamp(); Index: popd/popd.h diff -u popd/popd.h.orig popd/popd.h --- popd/popd.h.orig Tue Dec 5 23:55:40 2000 +++ popd/popd.h Wed Dec 6 03:21:11 2000 @@ -85,7 +85,7 @@ int falseuidl; int fascistlogging; int hashdepth; - int port; + char *port; int top; int uidl; int virtual; @@ -108,7 +108,8 @@ char *timestamp; char *user; - struct in_addr bind_address; + u_char family; + char *bind_address; FILE *socket_in; FILE *socket_out; struct radius_s *radius;