--- /dev/null
+diff -Nur inn-2.3.2.orig/authprogs/auth_pass.c inn-2.3.2/authprogs/auth_pass.c
+--- inn-2.3.2.orig/authprogs/auth_pass.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/authprogs/auth_pass.c Tue Jun 19 16:06:41 2001
+@@ -70,8 +70,11 @@
+ int length;
+ char password[256];
+ char peername[1024];
++#ifdef INET6
++ char tmpname[1048];
++#endif /* INET6 */
+ struct passwd * pwd;
+- struct sockaddr_in sin;
++ struct sockaddr_storage ss;
+ char username[32];
+
+ /*
+@@ -105,22 +108,43 @@
+ /*
+ * Get the hostname of the peer.
+ */
+- length = sizeof(sin);
+- if (getpeername(0, (struct sockaddr *)&sin, &length) < 0) {
++ length = sizeof(ss);
++ if (getpeername(0, (struct sockaddr *)&ss, &length) < 0) {
+ if (!isatty(0)) {
+ fprintf(stderr, "cant getpeername()::%s:+:!*\n", username);
+ exit(1);
+ }
+ (void)strcpy(peername, "stdin");
+- } else if (sin.sin_family != AF_INET) {
++#ifdef INET6
++ } else if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
++#else
++ } else if (ss.ss_family != AF_INET) {
++#endif
+ fprintf(stderr, "Bad address family %ld::%s:+:!*\n",
+- (long)sin.sin_family, username);
++ (long)ss.ss_family, username);
+ exit(1);
+- } else if ((hp = gethostbyaddr((char *)&sin.sin_addr, sizeof(sin.sin_addr), AF_INET)) == NULL) {
+- strcpy(peername, inet_ntoa(sin.sin_addr));
++#ifdef INET6
++ } else {
++#ifdef HAVE_SOCKADDR_LEN
++ getnameinfo((struct sockaddr *)&ss, ss.ss_len, peername,
++ sizeof(peername), NULL, 0, 0);
++#else
++ getnameifno((struct sockaddr *)&ss, SA_LEN((struct sockaddr *)&ss),
++ peername, sizeof(peername), NULL, 0, 0);
++#endif /* HAVE_SOCKADDR_LEN */
++ if (strchr(peername, ':') != NULL) {
++ sprintf(tmpname, "[%s]", peername);
++ if (strlen(tmpname) < sizeof(peername))
++ strcpy(peername, tmpname);
++ }
++ }
++#else /* INET6 */
++ } else if ((hp = gethostbyaddr((char *)&((struct sockaddr_in *)&ss)-sin_addr, sizeof(struct in_addr), AF_INET)) == NULL) {
++ strcpy(peername, inet_ntoa(((struct sockaddr *)&ss)->sin_addr));
+ } else {
+ strncpy(peername, hp->h_name, sizeof(peername));
+ }
++#endif /* INET6 */
+
+ /*
+ * Get the user name in the passwd file.
+diff -Nur inn-2.3.2.orig/configure.in inn-2.3.2/configure.in
+--- inn-2.3.2.orig/configure.in Thu May 3 22:27:32 2001
++++ inn-2.3.2/configure.in Tue Jun 19 16:06:41 2001
+@@ -380,6 +380,199 @@
+ fi
+ esac
+
++dnl === part for IPv6 support ===
++AC_MSG_CHECKING([whether to enable ipv6])
++AC_ARG_ENABLE(ipv6,
++[ --enable-ipv6 Enable ipv6 (with ipv4) support
++ --disable-ipv6 Disable ipv6 support],
++[ case "$enableval" in
++ no)
++ AC_MSG_RESULT(no)
++ ipv6=no
++ ;;
++ *) AC_MSG_RESULT(yes)
++ AC_DEFINE(ENABLE_IPV6)
++ ipv6=yes
++ ;;
++ esac ],
++
++ AC_TRY_RUN([ /* AF_INET6 avalable check */
++#include <sys/types.h>
++#include <sys/socket.h>
++main()
++{
++ if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
++ exit(1);
++ else
++ exit(0);
++}
++],
++ AC_MSG_RESULT(yes)
++ AC_DEFINE(ENABLE_IPV6)
++ ipv6=yes,
++ AC_MSG_RESULT(no)
++ ipv6=no,
++ AC_MSG_RESULT(no)
++ ipv6=no
++))
++
++ipv6type=unknown
++ipv6lib=none
++
++if test "$ipv6" = "yes"; then
++ AC_MSG_CHECKING([IPv6 stack type])
++ for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
++ case $i in
++ inria)
++ dnl http://www.kame.net/
++ AC_EGREP_CPP(%%%yes%%%, [dnl
++#include <netinet/in.h>
++#ifdef IPV6_INRIA_VERSION
++%%%yes%%%
++#endif],
++ [ipv6type=$i;
++ CFLAGS="-DINET6 $CFLAGS"])
++ ;;
++ kame)
++ dnl http://www.kame.net/
++ AC_EGREP_CPP(%%%yes%%%, [dnl
++#include <netinet/in.h>
++#ifdef __KAME__
++%%%yes%%%
++#endif],
++ [ipv6type=$i;
++ CFLAGS="-DINET6 $CFLAGS"])
++ ;;
++ linux-glibc)
++ dnl http://www.v6.linux.or.jp/
++ AC_EGREP_CPP(%%%yes%%%, [dnl
++#include <features.h>
++#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
++%%%yes%%%
++#endif],
++ [ipv6type=$i;
++ CFLAGS="-DINET6 $CFLAGS"])
++ ;;
++ linux-inet6)
++ dnl http://www.v6.linux.or.jp/
++ if test -d /usr/inet6; then
++ ipv6type=$i
++ ipv6lib=inet6
++ ipv6libdir=/usr/inet6/lib
++ CFLAGS="-DINET6 -I/usr/inet6/include $CFLAGS"
++ fi
++ ;;
++ toshiba)
++ AC_EGREP_CPP(%%%yes%%%, [dnl
++#include <sys/param.h>
++#ifdef _TOSHIBA_INET6
++%%%yes%%%
++#endif],
++ [ipv6type=$i;
++ ipv6lib=inet6;
++ ipv6libdir=/usr/local/v6/lib;
++ CFLAGS="-DINET6 $CFLAGS"])
++ ;;
++ v6d)
++ AC_EGREP_CPP(%%%yes%%%, [dnl
++#include </usr/local/v6/include/sys/v6config.h>
++#ifdef __V6D__
++%%%yes%%%
++#endif],
++ [ipv6type=$i;
++ ipv6lib=v6;
++ ipv6libdir=/usr/local/v6/lib;
++ CFLAGS="-I/usr/local/v6/include $CFLAGS"])
++ ;;
++ zeta)
++ AC_EGREP_CPP(%%%yes%%%, [dnl
++#include <sys/param.h>
++#ifdef _ZETA_MINAMI_INET6
++yes
++#endif],
++ [ipv6type=$i;
++ ipv6lib=inet6;
++ ipv6libdir=/usr/local/v6/lib;
++ CFLAGS="-DINET6 $CFLAGS"])
++ ;;
++ esac
++ if test "$ipv6type" != "unknown"; then
++ break
++ fi
++ done
++ AC_MSG_RESULT($ipv6type)
++fi
++
++if test "$ipv6" = "yes"; then
++ if test -d /usr/local/v6/lib; then
++ ac_inet6_LDFLAGS="inet6"
++ ipv6libdir=/usr/local/v6/lib
++ LDFLAGS="$LDFLAGS -L/usr/local/v6/lib"
++ AC_CHECK_LIB(inet6, getaddrinfo, , ipv6lib="$ac_inet6_LDFLAGS")
++ else
++ AC_CHECK_FUNCS(getaddrinfo)
++ fi
++fi
++
++if test "$ipv6" = "yes" -a "$ipv6lib" != "none"; then
++ if test -d $ipv6libdir -a -f $ipv6libdir/lib$ipv6lib.a; then
++ LIBS="-L$ipv6libdir -l$ipv6lib $LIBS"
++ fi
++fi
++AC_SUBST(ipv6)
++
++dnl checking for sa_len;
++dnl the following check says 'yes' if your system has __libc_sa_len
++dnl AC_EGREP_HEADER(sa_len, sys/socket.h,
++dnl [ AC_DEFINE(HAVE_SOCKADDR_LEN) AC_MSG_RESULT(yes)], AC_MSG_RESULT(no))
++AC_MSG_CHECKING([whether struct sockaddr has sa_len])
++AC_TRY_COMPILE([
++#include <sys/types.h>
++#include <sys/socket.h>
++],[
++struct sockaddr sa;
++int i = sa.sa_len;
++],
++[AC_MSG_RESULT(yes)
++ AC_DEFINE(HAVE_SOCKADDR_LEN)],
++AC_MSG_RESULT(no))
++
++AC_MSG_CHECKING([whether sys/socket.h has SA_LEN])
++AC_TRY_RUN([
++#include <sys/types.h>
++#include <sys/socket.h>
++struct sockaddr sa;
++int main(){ int i = SA_LEN((struct sockaddr*)&sa); return 0;}
++],
++[AC_MSG_RESULT(yes)
++ AC_DEFINE(HAVE_SA_LEN)],
++AC_MSG_RESULT(no),AC_MSG_RESULT(no))
++
++AC_MSG_CHECKING([whether sys/socket.h has struct sockaddr_storage])
++AC_TRY_COMPILE([
++#include <sys/types.h>
++#include <sys/socket.h>
++],[
++struct sockaddr_storage ss;
++],
++[AC_MSG_RESULT(yes)
++ AC_DEFINE(HAVE_SOCKADDR_STORAGE)],
++AC_MSG_RESULT(no))
++
++AC_MSG_CHECKING([whether struct sockaddr_storage has __ss_family])
++AC_TRY_COMPILE([
++#include <sys/types.h>
++#include <sys/socket.h>
++],[
++struct sockaddr_storage ss;
++int i = ss.__ss_family;
++],
++[AC_MSG_RESULT(yes)
++ AC_DEFINE(HAVE_2553_STYLE_SS_FAMILY)],
++AC_MSG_RESULT(no), AC_MSG_RESULT(no))
++
++dnl === end of part for IPv6 support ===
++
+ dnl Checks for pathnames.
+
+ dnl See if we have ctags; if so, set CTAGS to its full path plus the -t -w
+@@ -1061,7 +1254,7 @@
+ AC_CHECK_FUNCS(atexit fchmod fcntl gethostname getpagesize getrusage \
+ getspnam gettimeofday mkfifo setbuffer sigaction setsid \
+ socketpair statvfs strcspn strncasecmp strstr strtoul \
+- symlink waitpid)
++ symlink waitpid inet_ntoa)
+
+ dnl We only care if we have setreuid() if we don't have seteuid().
+ AC_CHECK_FUNCS(seteuid setreuid, break)
+@@ -1095,7 +1288,7 @@
+ fi
+
+ dnl If we can't find any of the following, we have replacements for them.
+-AC_REPLACE_FUNCS(fseeko ftello getopt inet_aton inet_ntoa pread pwrite \
++AC_REPLACE_FUNCS(fseeko ftello getopt inet_aton pread pwrite \
+ strcasecmp strdup strerror strspn setenv hstrerror)
+
+ dnl If replacing fseeko or ftello, see if we can use fsetpos/fgetpos.
+diff -Nur inn-2.3.2.orig/doc/man/inn.conf.5 inn-2.3.2/doc/man/inn.conf.5
+--- inn-2.3.2.orig/doc/man/inn.conf.5 Thu May 3 22:27:32 2001
++++ inn-2.3.2/doc/man/inn.conf.5 Tue Jun 19 16:06:41 2001
+@@ -1055,6 +1055,25 @@
+ directory). It must be on the same partition as \fIpathincoming\fR for
+ \&\fIrnews\fR\|(1) to work correctly. The default value is set at configure time
+ and defaults to \fIpathnews\fR/tmp.
++.Sh "IPv6 Configurations"
++.IX Subsection "IPv6 Configurations"
++If your system can use IPv6, the following parameters are available.
++.Ip "\fIlistenonipv6\fR" 4
++.IX Item "listenonipv6"
++If set to true, \fIinnd\fR\|(8) creates an IPv6 socket for waiting connections
++from IPv6 clients.
++.Ip "\fIbindipv6address\fR" 4
++.IX Item "bindipv6address"
++Which IPv6 address \fIinnd\fR\|(8) should bind itself to. This must be in
++numeric IPv6 address format. If set to \f(CW\*(C`all\*(C'\fR or not set, innd
++defaults to listening on all interfaces. The default value is unset.
++.Ip "\fIsourceipv6address\fR" 4
++.IX Item "sourceipv6address"
++Which local IPv6 address to bind to outgoing NNTP sockets (used by
++\fIinnxmit\fR\|(8) among other programs). This must be in numeric IPv6
++address format. If set to \f(CW\*(C`all\*(C'\fR or not set,
++the operating system will choose the source IPv6 address for outgoing
++connections. The default value is unset.
+ .SH "EXAMPLE"
+ .IX Header "EXAMPLE"
+ Here is a very minimalist example that only sets those parameters that are
+diff -Nur inn-2.3.2.orig/include/clibrary.h inn-2.3.2/include/clibrary.h
+--- inn-2.3.2.orig/include/clibrary.h Thu May 3 22:27:32 2001
++++ inn-2.3.2/include/clibrary.h Tue Jun 19 16:06:41 2001
+@@ -102,9 +102,7 @@
+ #ifndef HAVE_PWRITE
+ extern ssize_t pwrite(int fd, void *buf, size_t nbyte, OFFSET_T offset);
+ #endif
+-#ifndef HAVE_INET_NTOA
+-extern char *inet_ntoa();
+-#endif
++extern char *Inet_NtoA();
+ #ifndef HAVE_STRDUP
+ extern char *strdup();
+ #endif
+diff -Nur inn-2.3.2.orig/include/config.h.in inn-2.3.2/include/config.h.in
+--- inn-2.3.2.orig/include/config.h.in Thu May 3 22:27:32 2001
++++ inn-2.3.2/include/config.h.in Tue Jun 19 16:06:41 2001
+@@ -732,4 +732,26 @@
+ /* All incoming control commands (ctlinnd, etc). */
+ #define L_CC_CMD LOG_INFO
+
++/* IPv6 support */
++
++/* sockaddr.sa_len */
++#undef HAVE_SOCKADDR_LEN
++
++/* SA_LEN() */
++#undef HAVE_SA_LEN
++
++/* struct sockaddr_storage */
++#undef HAVE_SOCKADDR_STORAGE
++
++/* getaddrinfo() */
++#undef HAVE_GETADDRINFO
++
++/* sockaddr_storage.__ss_family */
++#undef HAVE_2553_STYLE_SS_FAMILY
++
++#ifdef HAVE_2553_STYLE_SS_FAMILY
++# define ss_family __ss_family
++# define ss_len __ss_len
++#endif
++
+ #endif /* !__CONFIG_H__ */
+diff -Nur inn-2.3.2.orig/include/innconf.h inn-2.3.2/include/innconf.h
+--- inn-2.3.2.orig/include/innconf.h Thu May 3 22:27:32 2001
++++ inn-2.3.2/include/innconf.h Tue Jun 19 16:06:41 2001
+@@ -329,7 +329,16 @@
+ { _CONF_WIPCHECK, "", 2, 1 },
+ #define _CONF_NNRPPYTHONAUTH "nnrppythonauth"
+ #define CONF_VAR_NNRPPYTHONAUTH 103
+- { _CONF_NNRPPYTHONAUTH, "", 2, 1 }
++ { _CONF_NNRPPYTHONAUTH, "", 2, 1 },
++#define _CONF_LISTENONIPV6 "listenonipv6"
++#define CONF_VAR_LISTENONIPV6 104
++ { _CONF_LISTENONIPV6, "", 2, 0 },
++#define _CONF_BINDIPV6ADDRESS "bindipv6address"
++#define CONF_VAR_BINDIPV6ADDRESS 105
++ { _CONF_BINDIPV6ADDRESS, "", 1, 0 },
++#define _CONF_SOURCEIPV6ADDRESS "sourceipv6address"
++#define CONF_VAR_SOURCEIPV6ADDRESS 106
++ { _CONF_SOURCEIPV6ADDRESS, "", 1, 0 }
+ };
+-#define MAX_CONF_VAR 104
++#define MAX_CONF_VAR 106
+
+diff -Nur inn-2.3.2.orig/include/libinn.h inn-2.3.2/include/libinn.h
+--- inn-2.3.2.orig/include/libinn.h Thu May 3 22:27:32 2001
++++ inn-2.3.2/include/libinn.h Tue Jun 19 16:06:41 2001
+@@ -101,6 +101,7 @@
+ /* Feed Configuration */
+ int artcutoff; /* Max accepted article age */
+ char *bindaddress; /* Which interface IP to bind to */
++ char *bindipv6address; /* Which interface IP to bind to */
+ int hiscachesize; /* Size of the history cache in kB */
+ int ignorenewsgroups; /* Propagate cmsgs by affected group? */
+ int immediatecancel; /* Immediately cancel timecaf messages? */
+@@ -112,11 +113,13 @@
+ int refusecybercancels; /* Reject message IDs with "<cancel."? */
+ int remembertrash; /* Put unwanted article IDs into history */
+ char *sourceaddress; /* Source IP for outgoing NNTP connections */
++ char *sourceipv6address; /* Source IP for outgoing NNTP connections */
+ int usecontrolchan; /* Use a channel feed for control messages? */
+ int verifycancels; /* Verify cancels against article author */
+ int wanttrash; /* Put unwanted articles in junk */
+ int wipcheck; /* How long to defer other copies of article */
+ int wipexpire; /* How long to keep pending article record */
++ int listenonipv6; /* Listen on IPv6 socket */
+
+ /* Article Storage */
+ long cnfscheckfudgesize; /* Additional CNFS integrity checking */
+diff -Nur inn-2.3.2.orig/include/sa_len.h inn-2.3.2/include/sa_len.h
+--- inn-2.3.2.orig/include/sa_len.h Thu Jan 1 01:00:00 1970
++++ inn-2.3.2/include/sa_len.h Tue Jun 19 16:06:41 2001
+@@ -0,0 +1,46 @@
++/*
++ * sa_len.h : tiny version of SA_LEN
++ * (original written by <yoshfuji@ecei.tohoku.ac.jp>)
++ */
++
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <sys/un.h>
++
++#ifndef SIN6_LEN
++#ifndef SA_LEN
++#define SA_LEN(s_) ap_sa_len((s_)->sa_family)
++
++static int ap_sa_len (int af)
++{
++ switch (af) {
++#if defined(AF_INET)
++ case AF_INET:
++ return (sizeof(struct sockaddr_in));
++#endif /* AF_INET */
++#if defined(INET6)
++ case AF_INET6:
++ return (sizeof(struct sockaddr_in6));
++#endif /* AF_INET6 */
++#if defined(AF_LOCAL)
++ case AF_LOCAL:
++#endif /* AF_LOCAL */
++#if defined(AF_UNIX) && !(AF_UNIX == AF_LOCAL)
++ case AF_UNIX:
++#endif /* AF_UNIX */
++#if defined(AF_FILE) && !(AF_FILE == AF_LOCAL)
++ case AF_FILE:
++#endif /* AF_FILE */
++#if defined(AF_LOCAL) || defined(AF_UNIX) || defined(AF_FILE)
++ return (sizeof(struct sockaddr_un));
++#endif /* fdefined(AF_LOCAL) || defined(AF_UNIX) || defined(AF_FILE) */
++ default:
++ return 0;
++ }
++ return 0;
++}
++
++#endif /* SA_LEN */
++#endif /* SIN6_LEN */
++
+diff -Nur inn-2.3.2.orig/include/sockaddr_storage.h inn-2.3.2/include/sockaddr_storage.h
+--- inn-2.3.2.orig/include/sockaddr_storage.h Thu Jan 1 01:00:00 1970
++++ inn-2.3.2/include/sockaddr_storage.h Tue Jun 19 16:06:41 2001
+@@ -0,0 +1,53 @@
++/*
++struct sockaddr_storage
++
++ RFC2553 proposes struct sockaddr_storage.
++ This is a placeholder for all sockaddr-variant structures. This is
++ implemented like follows:
++
++ You should use this structure to hold any of sockaddr-variant
++ structures.
++*/
++#ifndef HAVE_SOCKADDR_STORAGE
++
++struct sockaddr_storage {
++#ifdef HAVE_SOCKADDR_LEN
++ u_char ss_len;
++ u_char ss_family;
++#else
++ u_short ss_family;
++#endif
++ u_char __padding[128 - 2];
++};
++
++/*
++union sockunion
++
++ Alternatively, you may want to implement sockunion.h, with the
++ following content:
++
++ NOTE: For better portability, struct sockaddr_storage should be used.
++ union sockunion is okay, but is not really portable enough.
++*/
++union sockunion {
++ struct sockinet {
++#ifdef HAVE_SOCKADDR_LEN
++ u_char si_len;
++ u_char si_family;
++#else
++ u_short si_family;
++#endif
++ u_short si_port;
++ } su_si;
++ struct sockaddr_in su_sin;
++#ifdef INET6
++ struct sockaddr_in6 su_sin6;
++#endif
++};
++#ifdef HAVE_SOCKADDR_LEN
++#define su_len su_si.si_len
++#endif
++#define su_family su_si.si_family
++#define su_port su_si.si_port
++
++#endif /* HAVE_SOCKADDR_STORAGE */
+diff -Nur inn-2.3.2.orig/innd/chan.c inn-2.3.2/innd/chan.c
+--- inn-2.3.2.orig/innd/chan.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/chan.c Tue Jun 19 16:06:41 2001
+@@ -36,8 +36,8 @@
+
+ #define PRIORITISE_REMCONN
+ #ifdef PRIORITISE_REMCONN
+-STATIC int CHANrcfd;
+-STATIC CHANNEL *CHANrc;
++STATIC int CHANrcfd[2];
++STATIC CHANNEL *CHANrc[2];
+ #endif /* PRIORITISE_REMCONN */
+
+ /*
+@@ -147,7 +147,7 @@
+ (void)memset((POINTER)CHANtable, 0,
+ (SIZE_T)(CHANtablesize * sizeof *CHANtable));
+ CHANnull.NextLog = innconf->chaninacttime;
+- CHANnull.Address.s_addr = MyAddress.s_addr;
++ memcpy((POINTER)&CHANnull.Address, (POINTER)&MyAddress, sizeof MyAddress);
+ for (cp = CHANtable; --i >= 0; cp++)
+ *cp = CHANnull;
+ }
+@@ -239,8 +239,13 @@
+ #ifdef PRIORITISE_REMCONN
+ /* Note remconn channel, for efficiency */
+ if (Type == CTremconn) {
+- CHANrc = cp;
+- CHANrcfd = fd;
++ if (CHANrc[0] == NULL) {
++ CHANrc[0] = cp;
++ CHANrcfd[0] = fd;
++ } else {
++ CHANrc[1] = cp;
++ CHANrcfd[1] = fd;
++ }
+ }
+ #endif /* PRIORITISE_REMCONN */
+ return cp;
+@@ -261,7 +266,7 @@
+ syslog(L_NOTICE, "%s trace badwrites %d blockwrites %d badreads %d",
+ p, cp->BadWrites, cp->BlockedWrites, cp->BadReads);
+ syslog(L_NOTICE, "%s trace address %s lastactive %ld nextlog %ld",
+- p, inet_ntoa(cp->Address), cp->LastActive, cp->NextLog);
++ p, Inet_NtoA(&cp->Address), cp->LastActive, cp->NextLog);
+ if (FD_ISSET(cp->fd, &SCHANmask))
+ syslog(L_NOTICE, "%s trace sleeping %ld 0x%x",
+ p, (long)cp->Waketime, cp->Waker);
+@@ -383,7 +388,7 @@
+ break;
+ case CTnntp:
+ (void)sprintf(buff, "%s:%d",
+- cp->Address.s_addr == 0 ? "localhost" : RChostname(cp),
++ cp->Address.ss_family == 0 ? "localhost" : RChostname(cp),
+ cp->fd);
+ break;
+ case CTlocalconn:
+@@ -922,11 +927,14 @@
+
+ #ifdef PRIORITISE_REMCONN
+ /* Try the remconn channel next. */
+- if (FD_ISSET(CHANrcfd, &RCHANmask) && FD_ISSET(CHANrcfd, &MyRead)) {
+- count--;
+- if (count > 3) count = 3; /* might be more requests */
+- (*CHANrc->Reader)(CHANrc);
+- FD_CLR(CHANrcfd, &MyRead);
++ for (i = 0; i < 2; i++) {
++ if (FD_ISSET(CHANrcfd[i], &RCHANmask) &&
++ FD_ISSET(CHANrcfd[i], &MyRead)) {
++ count--;
++ if (count > 3) count = 3; /* might be more requests */
++ (*CHANrc[i]->Reader)(CHANrc[i]);
++ FD_CLR(CHANrcfd[i], &MyRead);
++ }
+ }
+ #endif /* PRIORITISE_REMCONN */
+
+diff -Nur inn-2.3.2.orig/innd/innd.c inn-2.3.2/innd/innd.c
+--- inn-2.3.2.orig/innd/innd.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/innd.c Tue Jun 19 16:06:41 2001
+@@ -558,7 +558,7 @@
+ {
+ static char WHEN[] = "PID file";
+ int i;
+- int fd;
++ int fd[2];
+ int logflags;
+ char buff[SMBUF];
+ char *p;
+@@ -599,7 +599,7 @@
+ ShouldRenumber = FALSE;
+ ShouldSyntaxCheck = FALSE;
+ logflags = L_OPENLOG_FLAGS | LOG_NOWAIT;
+- fd = -1;
++ fd[0] = fd[1] = -1;
+
+ #if defined(DO_FAST_RESOLV)
+ /* We only use FQDN's in the hosts.nntp file. */
+@@ -680,10 +680,12 @@
+ case 'p':
+ /* Silently ignore multiple -p flags, in case ctlinnd xexec
+ * called inndstart. */
+- if (fd == -1) {
+- fd = atoi(optarg);
++ if (fd[0] == -1) {
++ fd[0] = atoi(optarg);
+ AmRoot = FALSE;
+- }
++ } else if (fd[1] == -1) {
++ fd[1] = atoi(optarg);
++ }
+ break;
+ case 'P':
+ innconf->port = atoi(optarg);
+@@ -774,7 +776,7 @@
+ syslog(L_FATAL, "%s internal cant stat control directory %m", LogName);
+ exit(1);
+ }
+- if (fd != -1 && setgid(NewsGID) < 0)
++ if (fd[0] != -1 && setgid(NewsGID) < 0)
+ syslog(L_ERROR, "%s cant setgid running as %d not %d %m",
+ LogName, (int)getgid(), (int)NewsGID);
+
+@@ -884,7 +886,11 @@
+ HISsetup();
+ CCsetup();
+ LCsetup();
+- RCsetup(fd);
++ RCsetup(fd[0]);
++#ifdef INET6
++ if (innconf->listenonipv6 && fd[1] != -1)
++ RCsetup(fd[1]);
++#endif
+ WIPsetup();
+ NCsetup(i);
+ ARTsetup();
+diff -Nur inn-2.3.2.orig/innd/innd.h inn-2.3.2/innd/innd.h
+--- inn-2.3.2.orig/innd/innd.h Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/innd.h Tue Jun 19 16:06:41 2001
+@@ -51,6 +51,7 @@
+ #include "nntp.h"
+ #include "paths.h"
+ #include "storage.h"
++#include "sockaddr_storage.h"
+
+ #if defined(DO_TCL)
+ #include <tcl.h>
+@@ -66,7 +67,7 @@
+ /*
+ ** Some convenient shorthands.
+ */
+-typedef struct in_addr INADDR;
++typedef struct sockaddr_storage INADDR;
+
+ #ifndef u_long
+ #define u_long unsigned long
+diff -Nur inn-2.3.2.orig/innd/inndstart.c inn-2.3.2/innd/inndstart.c
+--- inn-2.3.2.orig/innd/inndstart.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/inndstart.c Tue Jun 19 16:06:41 2001
+@@ -145,6 +145,12 @@
+ unsigned long address;
+ int s;
+ struct sockaddr_in server;
++#ifdef INET6
++ int s6;
++ struct sockaddr_in6 server6;
++ char p6flag[SMBUF];
++ int in6any;
++#endif
+ int i;
+ int j;
+ char * p;
+@@ -299,6 +305,64 @@
+
+ /* Create a socket and name it. innconf->bindaddress controls what
+ address we bind as, defaulting to INADDR_ANY. */
++#ifdef INET6
++ in6any = 1;
++ s6 = -1;
++ if (innconf->listenonipv6) {
++ s6 = socket(AF_INET6, SOCK_STREAM, 0);
++ if (s6 < 0) {
++ syslog(L_FATAL, "can't open inet6 socket: %m");
++ exit(1);
++ }
++#ifdef SO_REUSEADDR
++ i = 1;
++ if (setsockopt(s6, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof i) < 0)
++ syslog(L_ERROR, "can't setsockopt: %m");
++#endif
++ memset(&server6, 0, sizeof server6);
++ server6.sin6_port = htons(port);
++ server6.sin6_family = AF_INET6;
++ server6.sin6_addr = in6addr_any;
++ p = innconf->bindipv6address;
++ if (p && !EQ(p, "all") && !EQ(p, "any")) {
++ if (inet_pton(AF_INET6, p, &server6.sin6_addr) < 1) {
++ syslog(L_FATAL, "invalid bindipv6address in inn.conf (%s)", p);
++ exit(1);
++ }
++ in6any = 0;
++ }
++#ifdef HAVE_SOCKADDR_LEN
++ server6.sin6_len = sizeof server6;
++#endif
++ for (i = 1; i < argc; i++) {
++ if (EQn("-6", argv[i], 2)) {
++ if (strlen(argv[i]) > 2) {
++ p = argv[i] + 2;
++ } else {
++ i++;
++ if (argv[i] == NULL) {
++ syslog(L_FATAL, "missing address after -6");
++ fprintf(stderr, "Missing address after -6\n");
++ exit(1);
++ }
++ p = argv[i];
++ }
++ if (inet_pton(AF_INET6, p, &server6) < 1) {
++ syslog(L_FATAL, "invalid ipv6 address %s", p);
++ fprintf(stderr, "Invalid ipv6 address %s\n", p);
++ exit(1);
++ }
++ in6any = 0;
++ }
++ }
++ if (bind(s6, (struct sockaddr *)&server6, sizeof server6) < 0) {
++ syslog(L_FATAL, "can't bind: %m");
++ exit(1);
++ }
++ }
++ if (!innconf->listenonipv6 || !in6any)
++#endif /* INET6 */
++ {
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ syslog(L_FATAL, "can't open socket: %m");
+@@ -317,6 +381,8 @@
+ syslog(L_FATAL, "can't bind: %m");
+ exit(1);
+ }
++ }
++
+
+ /* Now, permanently drop privileges. */
+ if (setgid(news_gid) < 0 || getgid() != news_gid) {
+@@ -330,24 +396,47 @@
+
+ /* Build the argument vector for innd. Pass -p<port> to innd to tell it
+ what port we just created and bound to for it. */
+- innd_argv = NEW(char *, 1 + argc + 1);
++#ifdef INET6
++ if (innconf->listenonipv6 && !in6any)
++ innd_argv = NEW(char *, 1 + argc + 2);
++ else
++#endif
++ innd_argv = NEW(char *, 1 + argc + 1);
+ i = 0;
+ #ifdef DEBUGGER
+ innd_argv[i++] = DEBUGGER;
+ innd_argv[i++] = cpcatpath(innconf->pathbin, "innd");
+ innd_argv[i] = 0;
++#ifdef INET6
++ if (innconf->listenonipv6)
++ printf("When starting innd, use -d -p%d [-p%d]\n", s6, s);
++ else
++#endif /* INET6 */
+ printf("When starting innd, use -dp%d\n", s);
+ #else /* DEBUGGER */
+- sprintf(pflag, "-p%d", s);
+ innd_argv[i++] = cpcatpath(innconf->pathbin, "innd");
+- innd_argv[i++] = pflag;
++#ifdef INET6
++ if (innconf->listenonipv6) {
++ sprintf(p6flag, "-p%d", s6);
++ innd_argv[i++] = p6flag;
++ }
++ if (innconf->listenonipv6 && in6any)
++ {
++ sprintf(pflag, "-p-1");
++ innd_argv[i++] = pflag;
++ } else
++#endif
++ {
++ sprintf(pflag, "-p%d", s);
++ innd_argv[i++] = pflag;
++ }
+
+- /* Don't pass along -p, -P, or -I. Check the length of the argument
++ /* Don't pass along -p, -P, -6, or -I. Check the length of the argument
+ string, and if it's == 2 (meaning there's nothing after the -p or -P
+- or -I), skip the next argument too, to support leaving a space
++ or -6 or -I), skip the next argument too, to support leaving a space
+ between the argument and the value. */
+ for (j = 1; j < argc; j++) {
+- if (argv[j][0] == '-' && strchr("pPI", argv[j][1])) {
++ if (argv[j][0] == '-' && strchr("6pPI", argv[j][1])) {
+ if (strlen(argv[j]) == 2) j++;
+ continue;
+ } else {
+diff -Nur inn-2.3.2.orig/innd/lc.c inn-2.3.2/innd/lc.c
+--- inn-2.3.2.orig/innd/lc.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/lc.c Tue Jun 19 16:06:41 2001
+@@ -39,7 +39,7 @@
+ return;
+ }
+ if ((new = NCcreate(fd, FALSE, TRUE)) != NULL) {
+- new->Address.s_addr = MyAddress.s_addr;
++ memcpy(&new->Address, &MyAddress, sizeof(MyAddress));
+ syslog(L_NOTICE, "%s connected %d", "localhost", new->fd);
+ NCwritereply(new, (char *)NCgreeting);
+ }
+diff -Nur inn-2.3.2.orig/innd/rc.c inn-2.3.2/innd/rc.c
+--- inn-2.3.2.orig/innd/rc.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/rc.c Tue Jun 19 16:06:41 2001
+@@ -19,9 +19,6 @@
+ # define INADDR_NONE 0xffffffff
+ #endif
+
+-#define COPYADDR(dest, src) \
+- (void)memcpy((POINTER)dest, (POINTER)src, (SIZE_T)sizeof (INADDR))
+-
+ #define TEST_CONFIG(a, b) \
+ { \
+ b = ((peer_params.Keysetbit & (1 << a)) != 0) ? TRUE : FALSE; \
+@@ -66,7 +63,7 @@
+ STATIC char *RCslaveflag;
+ STATIC char *RCnnrpd = NULL;
+ STATIC char *RCnntpd = NULL;
+-STATIC CHANNEL *RCchan;
++STATIC CHANNEL *RCchan[2];
+ STATIC REMOTEHOST_DATA *RCpeerlistfile;
+ STATIC REMOTEHOST *RCpeerlist;
+ STATIC int RCnpeerlist;
+@@ -112,6 +109,68 @@
+ STATIC int remotecount;
+ STATIC int remotefirst;
+
++void
++COPYADDR(INADDR *dst, char *src)
++{
++ struct sockaddr_in sin;
++
++ memset(&sin, 0, sizeof(sin));
++ sin.sin_family = AF_INET;
++#if defined(HAVE_SOCKADDR_LEN)
++ sin.sin_len = sizeof(sin);
++#endif /* defined(HAVE_SOCKADDR_LEN) */
++ (void)memcpy((POINTER)&sin.sin_addr, src, sizeof(sin.sin_addr));
++
++ (void)memcpy((POINTER)dst, (POINTER)&sin, sizeof(sin));
++}
++
++BOOL
++RCaddressmatch(INADDR *cp, INADDR *rp)
++{
++#ifdef INET6
++ struct sockaddr_in *sin_cp, *sin_rp;
++ struct sockaddr_in6 *sin6_cp, *sin6_rp;
++
++ if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET) {
++ sin6_cp = (struct sockaddr_in6 *)cp;
++ sin_rp = (struct sockaddr_in *)rp;
++ if (IN6_IS_ADDR_V4MAPPED(&sin6_cp->sin6_addr) &&
++ memcmp(&sin6_cp->sin6_addr.s6_addr[12], &sin_rp->sin_addr.s_addr,
++ sizeof(struct in_addr)) == 0)
++ return TRUE;
++ else
++ return FALSE;
++ } else if (cp->ss_family == AF_INET && rp->ss_family == AF_INET6) {
++ sin_cp = (struct sockaddr_in *)cp;
++ sin6_rp = (struct sockaddr_in6 *)rp;
++ if (IN6_IS_ADDR_V4MAPPED(&sin6_rp->sin6_addr) &&
++ memcmp(&sin6_rp->sin6_addr.s6_addr[12], &sin_cp->sin_addr.s_addr,
++ sizeof(struct in_addr)) == 0)
++ return TRUE;
++ else
++ return FALSE;
++ }
++#endif /* INET6 */
++ if (cp->ss_family != rp->ss_family)
++ return FALSE;
++
++ switch (cp->ss_family) {
++ case AF_INET:
++ if (((struct sockaddr_in *)cp)->sin_addr.s_addr ==
++ ((struct sockaddr_in *)rp)->sin_addr.s_addr)
++ return TRUE;
++ return FALSE;
++#ifdef INET6
++ case AF_INET6:
++ if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)cp)->sin6_addr,
++ &((struct sockaddr_in6 *)rp)->sin6_addr))
++ return TRUE;
++ return FALSE;
++#endif /* INET6 */
++ }
++
++ return FALSE;
++}
+
+ /*
+ * Split text into comma-separated fields. Return an allocated
+@@ -168,7 +227,7 @@
+ #endif
+
+ int
+-RCfix_options(int fd, struct sockaddr_in *remote)
++RCfix_options(int fd, INADDR *remote)
+ {
+ #if IP_OPTIONS
+ unsigned char optbuf[BUFSIZ / 3], *cp;
+@@ -177,10 +236,22 @@
+ int ipproto;
+ struct protoent *ip;
+
+- if ((ip = getprotobyname("ip")) != 0)
+- ipproto = ip->p_proto;
+- else
+- ipproto = IPPROTO_IP;
++ switch (remote->ss_family) {
++ case AF_INET:
++ if ((ip = getprotobyname("ip")) != 0)
++ ipproto = ip->p_proto;
++ else
++ ipproto = IPPROTO_IP;
++ break;
++#if defined(INET6)
++ case AF_INET6:
++ if ((ip = getprotobyname("ipv6")) != 0)
++ ipproto = ip->p_proto;
++ else
++ ipproto = IPPROTO_IPV6;
++ break;
++#endif /* defined(INET6) */
++ }
+
+ if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) optbuf, &optsize) == 0
+ && optsize != 0) {
+@@ -189,7 +260,7 @@
+ sprintf(lp, " %2.2x", *cp);
+ syslog(LOG_NOTICE,
+ "connect from %s with IP options (ignored):%s",
+- inet_ntoa(remote->sin_addr), lbuf);
++ Inet_NtoA(remote), lbuf);
+ if (setsockopt(fd, ipproto, IP_OPTIONS, (char *) 0, optsize) != 0) {
+ syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
+ return -1;
+@@ -210,17 +281,17 @@
+ register int i;
+
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
+- if (cp->Address.s_addr == rp->Address.s_addr) {
++ if (RCaddressmatch(&cp->Address, &rp->Address)) {
+ if (rp->Password[0] == '\0' || EQ(pass, rp->Password))
+ return TRUE;
+ syslog(L_ERROR, "%s (%s) bad_auth", rp->Label,
+- inet_ntoa(cp->Address));
++ Inet_NtoA(&cp->Address));
+ return FALSE;
+ }
+
+ if (!AnyIncoming)
+ /* Not found in our table; this can't happen. */
+- syslog(L_ERROR, "%s not_found", inet_ntoa(cp->Address));
++ syslog(L_ERROR, "%s not_found", Inet_NtoA(&cp->Address));
+
+ /* Anonymous hosts should not authenticate. */
+ return FALSE;
+@@ -237,7 +308,7 @@
+ register int i;
+
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
+- if (cp->Address.s_addr == rp->Address.s_addr)
++ if (RCaddressmatch(&cp->Address, &rp->Address))
+ if (rp->MaxCnx)
+ return FALSE;
+ else
+@@ -256,7 +327,7 @@
+ register int i;
+
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
+- if (cp->Address.s_addr == rp->Address.s_addr)
++ if (RCaddressmatch(&cp->Address, &rp->Address))
+ return (rp->MaxCnx);
+ /* Not found in our table; this can't happen. */
+ return RemoteLimit;
+@@ -270,7 +341,7 @@
+ RCrejectreader(CHANNEL *cp)
+ {
+ syslog(L_ERROR, "%s internal RCrejectreader (%s)", LogName,
+- inet_ntoa(cp->Address));
++ Inet_NtoA(&cp->Address));
+ }
+
+
+@@ -348,7 +419,7 @@
+ RCreader(CHANNEL *cp)
+ {
+ int fd;
+- struct sockaddr_in remote;
++ INADDR remote;
+ ARGTYPE size;
+ register int i;
+ register REMOTEHOST *rp;
+@@ -362,9 +433,9 @@
+ CHANNEL tempchan;
+ char buff[SMBUF];
+
+- if (cp != RCchan) {
+- syslog(L_ERROR, "%s internal RCreader wrong channel 0x%x not 0x%x",
+- LogName, cp, RCchan);
++ if (cp != RCchan[0] && cp != RCchan[1]) {
++ syslog(L_ERROR, "%s internal RCreader wrong channel 0x%x",
++ LogName, cp);
+ return;
+ }
+
+@@ -425,7 +496,7 @@
+ ** Finally, if neither rejection happened, add the entry to the
+ ** table, and continue on as a normal connect.
+ */
+- tempchan.Address.s_addr = remote.sin_addr.s_addr;
++ memcpy(&tempchan.Address, &remote, sizeof(remote));
+ reject_message = NULL;
+ if (RemoteTimer != 0) {
+ now = time(NULL);
+@@ -439,7 +510,7 @@
+ i = (i + 1) & (REMOTETABLESIZE - 1);
+ continue;
+ }
+- if (remotetable[i].Address.s_addr == remote.sin_addr.s_addr)
++ if (RCaddressmatch(&remotetable[i].Address, &remote))
+ found++;
+ i = (i + 1) & (REMOTETABLESIZE - 1);
+ }
+@@ -453,7 +524,7 @@
+ }
+ else {
+ i = (remotefirst + remotecount) & (REMOTETABLESIZE - 1);
+- remotetable[i].Address = remote.sin_addr;
++ memcpy(&remotetable[i].Address, &remote, sizeof(remote));
+ remotetable[i].Expires = now + RemoteTimer;
+ remotecount++;
+ }
+@@ -466,7 +537,7 @@
+ if (reject_message) {
+ new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
+ RCrejectwritedone);
+- new->Address.s_addr = remote.sin_addr.s_addr;
++ memcpy(&new->Address, &remote, sizeof(remote));
+ new->Rejected = reject_val;
+ RCHANremove(new);
+ WCHANset(new, reject_message, (int)strlen(reject_message));
+@@ -477,7 +548,7 @@
+
+ /* See if it's one of our servers. */
+ for (name = NULL, rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
+- if (rp->Address.s_addr == remote.sin_addr.s_addr) {
++ if (RCaddressmatch(&rp->Address, &remote)) {
+ name = rp->Name;
+ break;
+ }
+@@ -491,7 +562,7 @@
+ new->NoResendId = rp->NoResendId;
+ new->MaxCnx = rp->MaxCnx;
+ new->HoldTime = rp->HoldTime;
+- new->Address.s_addr = remote.sin_addr.s_addr;
++ memcpy(&new->Address, &remote, sizeof(remote));
+ if (new->MaxCnx > 0 && new->HoldTime == 0) {
+ CHANsetActiveCnx(new);
+ if((new->ActiveCnx > new->MaxCnx) && (new->fd > 0)) {
+@@ -519,7 +590,7 @@
+ reject_message = NNTP_ACCESS;
+ new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
+ RCrejectwritedone);
+- new->Address.s_addr = remote.sin_addr.s_addr;
++ memcpy(&new->Address, &remote, sizeof(remote));
+ new->Rejected = reject_val;
+ RCHANremove(new);
+ WCHANset(new, reject_message, (int)strlen(reject_message));
+@@ -529,9 +600,9 @@
+ }
+
+ if (new != NULL) {
+- new->Address.s_addr = remote.sin_addr.s_addr;
++ memcpy(&new->Address, &remote, sizeof(remote));
+ syslog(L_NOTICE, "%s connected %d streaming %s",
+- name ? name : inet_ntoa(new->Address), new->fd,
++ name ? name : Inet_NtoA(&new->Address), new->fd,
+ (!StreamingOff && new->Streaming) ? "allowed" : "not allowed");
+ }
+ }
+@@ -681,7 +752,9 @@
+ register REMOTEHOST peer_params;
+ register REMOTEHOST default_params;
+ BOOL flag, bit, toolong;
+-
++#if defined(HAVE_GETADDRINFO)
++ struct addrinfo hints, *res, *res0;
++#endif /* defined(HAVE_GETADDRINFO) */
+
+ *RCbuff = '\0';
+ if (*list) {
+@@ -880,9 +953,51 @@
+ RENEW (*list, REMOTEHOST, *count);
+ rp = *list + j;
+
++#if defined(HAVE_GETADDRINFO)
++ (void)memset((POINTER)&hints, 0, sizeof hints);
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++ if (getaddrinfo(*q, NULL, &hints, &res0) != 0) {
++ syslog(L_ERROR, "%s cant getaddrinfo %s %m", LogName, *q);
++ /* decrement *count, since we never got to add this record. */
++ (*count)--;
++ continue;
++ }
++ /* Count the addresses and see if we have to grow the list */
++ i = 0;
++ for (res = res0; res != NULL; res = res->ai_next)
++ i++;
++ /* Grow the array */
++ j = rp - *list;
++ *count += i - 1;
++ RENEW(*list, REMOTEHOST, *count);
++ rp = *list + j;
++
++ /* Add all hosts */
++ for (res = res0; res != NULL; res = res->ai_next) {
++ (void)memcpy(&rp->Address, res->ai_addr, res->ai_addrlen);
++ rp->Name = COPY (*q);
++ rp->Label = COPY (peer_params.Label);
++ rp->Email = COPY(peer_params.Email);
++ rp->Comment = COPY(peer_params.Comment);
++ rp->Streaming = peer_params.Streaming;
++ rp->Skip = peer_params.Skip;
++ rp->NoResendId = peer_params.NoResendId;
++ rp->Password = COPY(peer_params.Password);
++ rp->Patterns = peer_params.Pattern != NULL ?
++ RCCommaSplit(COPY(peer_params.Pattern)) : NULL;
++ rp->MaxCnx = peer_params.MaxCnx;
++ rp->HoldTime = peer_params.HoldTime;
++ rp++;
++ }
++ freeaddrinfo(res0);
++#else /* defined(HAVE_GETADDRINFO) */
+ /* Was host specified as a dotted quad ? */
+- if ((rp->Address.s_addr = inet_addr(*q)) != INADDR_NONE) {
++ if (inet_addr(*q) != INADDR_NONE) {
++ u_long addr;
+ /* syslog(LOG_NOTICE, "think it's a dotquad: %s", *q); */
++ addr = inet_addr(*q);
++ COPYADDR(&rp->Address, (char *)&addr);
+ rp->Name = COPY (*q);
+ rp->Label = COPY (peer_params.Label);
+ rp->Password = COPY(peer_params.Password);
+@@ -920,7 +1035,9 @@
+ int t = 0;
+ /* Strange DNS ? try this.. */
+ for (r = hp->h_aliases; *r != 0; r++) {
+- if (inet_addr(*r) == INADDR_NONE) /* IP address ? */
++ u_long addr;
++ addr = inet_addr(*r);
++ if (addr == INADDR_NONE) /* IP address ? */
+ continue;
+ (*count)++;
+ /* Grow the array */
+@@ -928,7 +1045,7 @@
+ RENEW (*list, REMOTEHOST, *count);
+ rp = *list + j;
+
+- rp->Address.s_addr = inet_addr(*r);
++ COPYADDR(&rp->Address, (char *)&addr);
+ rp->Name = COPY (*q);
+ rp->Label = COPY (peer_params.Label);
+ rp->Email = COPY(peer_params.Email);
+@@ -1003,6 +1120,7 @@
+ rp->HoldTime = peer_params.HoldTime;
+ rp++;
+ #endif /* defined(h_addr) */
++#endif /* defined(HAVE_GETADDRINFO) */
+ }
+ DISPOSE(r[0]);
+ DISPOSE(r);
+@@ -1496,9 +1614,9 @@
+ register int i;
+
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
+- if (cp->Address.s_addr == rp->Address.s_addr)
++ if (RCaddressmatch(&cp->Address, &rp->Address))
+ return rp->Name;
+- (void)strcpy(buff, inet_ntoa(cp->Address));
++ (void)strcpy(buff, Inet_NtoA(&cp->Address));
+ return buff;
+ }
+
+@@ -1511,7 +1629,7 @@
+ int i;
+
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
+- if (cp->Address.s_addr == rp->Address.s_addr)
++ if (RCaddressmatch(&cp->Address, &rp->Address))
+ return rp->Label;
+ }
+ return NULL;
+@@ -1530,7 +1648,7 @@
+ int i;
+
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
+- if (cp->Address.s_addr != rp->Address.s_addr)
++ if (RCaddressmatch(&cp->Address, &rp->Address))
+ continue;
+ if (rp->Patterns == NULL)
+ break;
+@@ -1559,12 +1677,53 @@
+ register int i;
+ {
+ struct sockaddr_in server;
++#if defined(INET6)
++ struct sockaddr_in6 server6;
++#endif /* defined(INET6) */
+ #if defined(SO_REUSEADDR)
+ int on;
+ #endif /* defined(SO_REUSEADDR) */
++ int idx;
+
+ if (i < 0) {
+ /* Create a socket and name it. */
++#if defined(INET6)
++ if (RCchan[0] != NULL && innconf->listenonipv6) {
++ if ((i = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
++ syslog(L_FATAL, "%s cant ipv6 socket RCreader %m", LogName);
++ exit(1);
++ }
++#if defined(SO_REUSEADDR)
++ on = 1;
++ if (setsockopt(i, SOL_SOCKET, SO_REUSEADDR, (caddr_t)&on,
++ sizeof on) < 0)
++ syslog(L_ERROR, "%s cant setsockopt RCreader %m", LogName);
++#endif /* defined(SO_REUSEADDR) */
++ (void)memset((POINTER)&server6, 0, sizeof server6);
++ server6.sin6_port = htons(innconf->port);
++ server6.sin6_family = AF_INET6;
++ server6.sin6_addr = in6addr_any;
++#if defined(HAVE_SOCKADDR_LEN)
++ server6.sin6_len = sizeof server6;
++#endif /* defined(HAVE_SOCKADDR_LEN) */
++ if (innconf->bindipv6address) {
++ if (inet_pton(AF_INET6, innconf->bindipv6address,
++ &server6.sin6_addr) < 1) {
++ syslog(L_FATAL, "unable to determine bind ipv6 (%s) %m",
++ innconf->bindipv6address);
++ exit(1);
++ }
++ }
++ if (bind(i, (struct sockaddr *)&server6, sizeof server6) < 0) {
++ syslog(L_FATAL, "%s cant bind RCreader %m", LogName);
++ exit(1);
++ }
++ } else if (RCchan[0] != NULL) {
++ /* If "listenonipv6" not set, and one socket has already been
++ created, no need to create more socket */
++ return;
++ }
++#endif /* defined(INET6) */
+ if ((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(L_FATAL, "%s cant socket RCreader %m", LogName);
+ exit(1);
+@@ -1599,9 +1758,15 @@
+ syslog(L_FATAL, "%s cant listen RCreader %m", LogName);
+ exit(1);
+ }
+- RCchan = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
+- syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(RCchan));
+- RCHANadd(RCchan);
++
++ if (RCchan[0] == NULL)
++ idx = 0;
++ else
++ idx = 1;
++ RCchan[idx] = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
++
++ syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(RCchan[idx]));
++ RCHANadd(RCchan[idx]);
+
+ /* Get the list of hosts we handle. */
+ RCreadlist();
+@@ -1617,8 +1782,11 @@
+ register REMOTEHOST *rp;
+ register int i;
+
+- CHANclose(RCchan, CHANname(RCchan));
+- RCchan = NULL;
++ for (i = 0; i < 2; i++)
++ if (RCchan[i] != NULL) {
++ CHANclose(RCchan[i], CHANname(RCchan[i]));
++ RCchan[i] = NULL;
++ }
+ if (RCpeerlist) {
+ for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
+ DISPOSE(rp->Name);
+diff -Nur inn-2.3.2.orig/innd/status.c inn-2.3.2/innd/status.c
+--- inn-2.3.2.orig/innd/status.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innd/status.c Tue Jun 19 16:06:41 2001
+@@ -16,7 +16,7 @@
+
+ typedef struct _STATUS {
+ char name[SMBUF];
+- char ip_addr[15];
++ char ip_addr[64];
+ BOOL can_stream;
+ unsigned short activeCxn;
+ unsigned short sleepingCxns;
+@@ -134,7 +134,8 @@
+ tmp = head = NULL;
+ for (i = 0; (cp = CHANiter(&i, CTnntp)) != NULL; ) {
+ j = 0;
+- strcpy(TempString, cp->Address.s_addr == 0 ? "localhost" : RChostname(cp));
++ strcpy(TempString, cp->Address.ss_family == 0 ? "localhost" :
++ RChostname(cp));
+ for (status = head ; status != NULL ; status = status->next) {
+ if (strcmp(TempString, status->name) == 0)
+ break;
+@@ -143,7 +144,7 @@
+ status = NEW(STATUS, 1);
+ peers++; /* a new peer */
+ strcpy (status->name, TempString); /* name */
+- strcpy (status->ip_addr, inet_ntoa(cp->Address)); /* ip address */
++ strcpy (status->ip_addr, Inet_NtoA(&cp->Address)); /* ip address */
+ status->can_stream = cp->Streaming;
+ status->seconds = status->Size = status->DuplicateSize = 0;
+ status->Ihave = status->Ihave_Duplicate =
+diff -Nur inn-2.3.2.orig/innfeed/connection.c inn-2.3.2/innfeed/connection.c
+--- inn-2.3.2.orig/innfeed/connection.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innfeed/connection.c Tue Jun 19 16:06:41 2001
+@@ -131,6 +131,12 @@
+ #include "host.h"
+ #include "msgs.h"
+
++#ifndef HAVE_SOCKADDR_STORAGE
++#include "sockaddr_storage.h"
++#endif
++
++#include "sa_len.h"
++
+ #if defined (NDEBUG)
+ #define VALIDATE_CONNECTION(x) ((void) 0)
+ #else
+@@ -263,7 +269,8 @@
+ static u_int gCxnCount = 0 ;
+ static u_int max_reconnect_period = MAX_RECON_PER ;
+ static u_int init_reconnect_period = INIT_RECON_PER ;
+-static u_long bind_addr = INADDR_ANY;
++static struct sockaddr_storage bind_addr;
++static int bind_addr_flag = 0;
+ #if 0
+ static bool inited = false ;
+ #endif
+@@ -406,17 +413,33 @@
+ iv = INIT_RECON_PER ;
+ init_reconnect_period = (u_int) iv ;
+
++ memset (&bind_addr, 0, sizeof(bind_addr));
+ if (getString (topScope,"bindaddress",&sv,NO_INHERIT))
+ {
+- bind_addr = inet_addr(sv);
+- if (bind_addr == INADDR_NONE)
+- {
++ if (inet_addr(sv) != INADDR_NONE) {
++ bind_addr.ss_family = AF_INET;
++ ((struct sockaddr_in *)&bind_addr)->sin_addr.s_addr = inet_addr(sv);
++#ifdef HAVE_SOCKADDR_LEN
++ bind_addr.ss_len = sizeof(struct sockaddr_in);
++#endif
++ bind_addr_flag = 1;
++ }
++#ifdef INET6
++ else if (inet_pton(AF_INET6, sv,
++ &((struct sockaddr_in6 *)&bind_addr)->sin6_addr) == 1) {
++ bind_addr.ss_family = AF_INET6;
++#ifdef HAVE_SOCKADDR_LEN
++ bind_addr.ss_len = sizeof(struct sockaddr_in6);
++#endif
++ bind_addr_flag = 1;
++ }
++#endif /* INET6 */
++ else {
+ logOrPrint (LOG_ERR,fp,"innfeed unable to determine bind ip") ;
+- bind_addr = INADDR_ANY;
++ bind_addr_flag = 0;
+ }
+- }
+- else
+- bind_addr = INADDR_ANY;
++ } else
++ bind_addr_flag = 0;
+
+ return rval ;
+ }
+@@ -533,9 +556,9 @@
+ */
+ bool cxnConnect (Connection cxn)
+ {
+- struct sockaddr_in cxnAddr, cxnSelf ;
++ struct sockaddr_storage cxnAddr, cxnSelf ;
+ int fd, rval ;
+- struct in_addr *addr = NULL;
++ struct sockaddr_storage *addr = NULL;
+ const char *peerName = hostPeerName (cxn->myHost) ;
+
+ ASSERT (cxn->myEp == NULL) ;
+@@ -566,12 +589,15 @@
+ return false ;
+ }
+
+- memset (&cxnAddr, 0, sizeof (cxnAddr)) ;
+- cxnAddr.sin_family = AF_INET ;
+- cxnAddr.sin_port = htons(cxn->port) ;
+- cxnAddr.sin_addr.s_addr = addr->s_addr ;
++ memcpy (&cxnAddr, addr, sizeof(cxnAddr));
++ if (cxnAddr.ss_family == AF_INET)
++ ((struct sockaddr_in *)&cxnAddr)->sin_port = htons(cxn->port);
++#ifdef INET6
++ else if (cxnAddr.ss_family == AF_INET6)
++ ((struct sockaddr_in6 *)&cxnAddr)->sin6_port = htons(cxn->port);
++#endif
+
+- if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
++ if ((fd = socket (cxnAddr.ss_family, SOCK_STREAM, 0)) < 0)
+ {
+ syslog (LOG_ERR, SOCKET_CREATE_ERROR, peerName, cxn->ident) ;
+ d_printf (1,"Can't get a socket: %m\n") ;
+@@ -582,13 +608,15 @@
+ }
+
+ /* bind to a specified virtual host */
+- if (bind_addr != INADDR_ANY)
++ if (bind_addr_flag == 1)
+ {
+- memset (&cxnSelf, 0, sizeof (cxnSelf)) ;
+- cxnSelf.sin_family = AF_INET ;
+- cxnSelf.sin_port = 0 ;
+- cxnSelf.sin_addr.s_addr = bind_addr;
+- if (bind (fd, (struct sockaddr *) &cxnSelf,sizeof (cxnSelf)) < 0)
++ (void)memcpy (&cxnSelf, &bind_addr, sizeof(cxnSelf));
++#ifdef HAVE_SOCKADDR_LEN
++ if (bind (fd, (struct sockaddr *) &cxnSelf, cxnSelf.ss_len) < 0)
++#else
++ if (bind (fd, (struct sockaddr *) &cxnSelf,
++ SA_LEN((struct sockaddr *) &cxnSelf)) < 0)
++#endif
+ {
+ syslog (LOG_ERR,"bind: %m") ;
+
+@@ -620,7 +648,12 @@
+ return false ;
+ }
+
+- rval = connect (fd, (struct sockaddr *) &cxnAddr, sizeof (cxnAddr)) ;
++#ifdef HAVE_SOCKADDR_LEN
++ rval = connect (fd, (struct sockaddr *) &cxnAddr, cxnAddr.ss_len);
++#else
++ rval = connect (fd, (struct sockaddr *) &cxnAddr,
++ SA_LEN((struct sockaddr *) &cxnAddr));
++#endif
+ if (rval < 0 && errno != EINPROGRESS)
+ {
+ syslog (LOG_ERR, CONNECT_ERROR, peerName, cxn->ident) ;
+diff -Nur inn-2.3.2.orig/innfeed/endpoint.c inn-2.3.2/innfeed/endpoint.c
+--- inn-2.3.2.orig/innfeed/endpoint.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innfeed/endpoint.c Tue Jun 19 16:06:41 2001
+@@ -1628,6 +1628,11 @@
+ EndPoint accConn ;
+ struct sockaddr_in accNet ;
+ int accFd = socket (AF_INET,SOCK_STREAM,0) ;
++#ifdef INET6
++ EndPoint accConn6;
++ struct sockaddr_in6 accNet6;
++ int accFd6 = socket (AF_INET6,SOCK_STREAM,0);
++#endif
+ u_short port = atoi (argc > 1 ? argv[1] : "10000") ;
+ time_t t = theTime() ;
+
+@@ -1663,6 +1668,26 @@
+ accConn = newEndPoint (accFd) ;
+
+ prepareRead (accConn,NULL,newConn,NULL,0) ;
++
++#ifdef INET6
++ ASSERT(accFd6 >= 0);
++ memset (&accNet6,0,sizeof (accNet6));
++ accNet6.sin6_family = AF_INET6;
++ accNet6.sin6_addr = in6addr_any;
++ accNet6.sin6_port = htons (port);
++
++ if (bind (accFd6, (struct sockaddr_in6 *) &accNet6, sizeof (accNet6)) < 0)
++ {
++ perror ("bind: %m") ;
++ exit (1) ;
++ }
++
++ listen (accFd6,5);
++
++ accCon6 = newEndPoint (accFd6);
++
++ prepareRead (accCon6,NULL,newConn,NULL,0) ;
++#endif
+
+ prepareSleep (Timeout,5,(void *) 0x10) ;
+
+diff -Nur inn-2.3.2.orig/innfeed/host.c inn-2.3.2/innfeed/host.c
+--- inn-2.3.2.orig/innfeed/host.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/innfeed/host.c Tue Jun 19 16:06:41 2001
+@@ -40,6 +40,8 @@
+ #include "config.h"
+ #include "clibrary.h"
+
++#include <sys/types.h>
++#include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <assert.h>
+@@ -67,6 +69,10 @@
+ #include "msgs.h"
+ #include "tape.h"
+
++#ifndef HAVE_SOCKADDR_STORAGE
++#include "sockaddr_storage.h"
++#endif
++
+ #define REQ 1
+ #define NOTREQ 0
+ #define NOTREQNOADD 2
+@@ -1128,22 +1134,63 @@
+ return nh ;
+ }
+
+-struct in_addr *hostIpAddr (Host host)
++struct sockaddr_storage *hostIpAddr (Host host)
+ {
+ int i ;
+ char *p ;
+ char **newIpAddrs = NULL;
+- struct in_addr ipAddr, *returnAddr ;
++ struct sockaddr_storage ipAddr, *returnAddr;
+ struct hostent *hostEnt ;
++#ifdef HAVE_GETADDRINFO
++ struct addrinfo hints, *res, *pr;
++#endif
+ char *msgstr[SMBUF] ;
+
+ ASSERT(host->params != NULL);
++ returnAddr = NULL;
+
+ /* check to see if need to look up the host name */
+ if (host->nextIpLookup <= theTime())
+ {
++#ifdef HAVE_GETADDRINFO
++ memset(&hints, 0, sizeof(hints));
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++ i = getaddrinfo(host->params->ipName, NULL, &hints, &res);
++ if (i != 0)
++ {
++ syslog (LOG_ERR, HOST_RESOLV_ERROR, host->params->peerName,
++ host->params->ipName, gai_strerror(i));
++ }
++ else
++ {
++ /* figure number of pointers that need space */
++ i = 0;
++ for (pr = res; pr != NULL; pr = pr->ai_next, i++)
++ ;
++ i++;
++
++ newIpAddrs =
++ (char **) MALLOC ( (i * sizeof(char *)) +
++ ( (i - 1) * sizeof(struct sockaddr_storage)) ) ;
++ ASSERT (newIpAddrs != NULL) ;
++
++ p = (char *)&newIpAddrs [ i ] ;
++ i = 0;
++ for (pr = res; pr != NULL; pr = pr->ai_next)
++ {
++ newIpAddrs[i] = p;
++ memcpy (p, pr->ai_addr, pr->ai_addrlen);
++ p += sizeof(struct sockaddr_storage);
++ i++;
++ }
++ newIpAddrs[i] = NULL;
++ freeaddrinfo(res);
++ }
++#else
+ /* see if the ipName we're given is a dotted quad */
+- if ( !inet_aton (host->params->ipName,&ipAddr) )
++ if ( !inet_aton (host->params->ipName,
++ &((struct sockaddr_in *)&ipAddr)->sin_addr) )
+ {
+ if ((hostEnt = gethostbyname (host->params->ipName)) == NULL)
+ {
+@@ -1159,7 +1206,8 @@
+
+ newIpAddrs =
+ (char **) MALLOC ( (i * sizeof(char *)) +
+- ( (i - 1) * hostEnt->h_length) ) ;
++ ( (i - 1) *
++ sizeof(struct sockaddr_storage) ) );
+ ASSERT (newIpAddrs != NULL) ;
+
+ /* copy the addresses from gethostbyname() static space */
+@@ -1168,7 +1216,13 @@
+ for (i = 0 ; hostEnt->h_addr_list[i] ; i++)
+ {
+ newIpAddrs[i] = p;
+- memcpy (p, hostEnt->h_addr_list[i], hostEnt->h_length) ;
++ memcpy (&((struct sockaddr_in *)p)->sin_addr,
++ hostEnt->h_addr_list[i], hostEnt->h_length) ;
++ ((struct sockaddr_in *)p)->sin_family = AF_INET;
++#ifdef HAVE_SOCKADDR_LEN
++ ((struct sockaddr_in *)p)->sin_len =
++ sizeof(struct sockaddr_in);
++#endif
+ p += hostEnt->h_length ;
+ }
+ newIpAddrs[i] = NULL ;
+@@ -1181,9 +1235,13 @@
+ p = (char *)&newIpAddrs [ 2 ];
+ newIpAddrs[0] = p;
+ memcpy (p, (char *)&ipAddr, sizeof(ipAddr)) ;
++ ((struct sockaddr_in *)p)->sin_family = AF_INET;
++#ifdef HAVE_SOCKADDR_LEN
++ ((struct sockaddr_in *)p)->sin_len = sizeof(struct sockaddr_in);
++#endif
+ newIpAddrs[1] = NULL;
+ }
+-
++#endif /* HAVE_GETADDRINFO */
+ if (newIpAddrs)
+ {
+ if (host->ipAddrs)
+@@ -1201,7 +1259,7 @@
+
+ if (host->ipAddrs)
+ {
+- returnAddr = (struct in_addr *)(host->nextIpAddr[0]) ;
++ returnAddr = (struct sockaddr_storage *)(host->nextIpAddr[0]) ;
+ if (*(++host->nextIpAddr) == NULL)
+ host->nextIpAddr = host->ipAddrs ;
+ }
+diff -Nur inn-2.3.2.orig/innfeed/host.h inn-2.3.2/innfeed/host.h
+--- inn-2.3.2.orig/innfeed/host.h Thu May 3 22:27:32 2001
++++ inn-2.3.2/innfeed/host.h Tue Jun 19 16:06:41 2001
+@@ -105,7 +105,7 @@
+ void hostSendArticle (Host host, Article article) ;
+
+ /* return an IP address for the host */
+-struct in_addr *hostIpAddr (Host host) ;
++struct sockaddr_storage *hostIpAddr (Host host) ;
+
+ /*
+ * Functions used by the Connection to indicate Connection state.
+diff -Nur inn-2.3.2.orig/lib/Makefile inn-2.3.2/lib/Makefile
+--- inn-2.3.2.orig/lib/Makefile Thu May 3 22:27:32 2001
++++ inn-2.3.2/lib/Makefile Tue Jun 19 16:06:41 2001
+@@ -16,7 +16,7 @@
+ md5.c nonblocking.c parsedate.c perl.c qio.c radix32.c readin.c \
+ remopen.c reservedfd.c resource.c rwlock.c sendarticle.c \
+ sendpass.c tempname.c waitnb.c wildmat.c version.c xfopena.c \
+- xmalloc.c xsignal.c xwrite.c xwritev.c
++ xmalloc.c xsignal.c xwrite.c xwritev.c inet_ntoa.c
+
+ OBJECTS = $(MISSING_OBJ) \
+ argparse.o checkart.o cleanfrom.o clientactive.o clientlib.o \
+@@ -26,7 +26,7 @@
+ md5.o nonblocking.o parsedate.o qio.o radix32.o readin.o \
+ remopen.o reservedfd.o resource.o rwlock.o sendarticle.o \
+ sendpass.o tempname.o waitnb.o wildmat.o version.o xfopena.o \
+- xmalloc.o xsignal.o xwrite.o xwritev.o
++ xmalloc.o xsignal.o xwrite.o xwritev.o inet_ntoa.o
+
+ LOBJECTS= $(OBJECTS:.o=.lo)
+
+diff -Nur inn-2.3.2.orig/lib/getconfig.c inn-2.3.2/lib/getconfig.c
+--- inn-2.3.2.orig/lib/getconfig.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/lib/getconfig.c Tue Jun 19 16:06:41 2001
+@@ -267,6 +267,9 @@
+ innconf->groupbaseexpiry = TRUE;
+ innconf->wipcheck = 5;
+ innconf->wipexpire = 10;
++ innconf->listenonipv6 = FALSE;
++ innconf->bindipv6address = NULL;
++ innconf->sourceipv6address = NULL;
+ }
+
+ void ClearInnConf()
+@@ -304,6 +307,9 @@
+ if (innconf->backoff_db != NULL) DISPOSE(innconf->backoff_db);
+ if (innconf->ovmethod != NULL) DISPOSE(innconf->ovmethod);
+ if (innconf->ovgrouppat != NULL) DISPOSE(innconf->ovgrouppat);
++ if (innconf->bindipv6address != NULL) DISPOSE(innconf->bindipv6address);
++ if (innconf->sourceipv6address != NULL) DISPOSE(innconf->sourceipv6address);
++
+ memset(ConfigBit, '\0', ConfigBitsize);
+ }
+
+@@ -981,6 +987,21 @@
+ TEST_CONFIG(CONF_VAR_WIPEXPIRE, bit);
+ if (!bit) innconf->wipexpire = atoi(p);
+ SET_CONFIG(CONF_VAR_WIPEXPIRE);
++ } else
++ if (EQ(ConfigBuff, _CONF_LISTENONIPV6)) {
++ TEST_CONFIG(CONF_VAR_LISTENONIPV6, bit);
++ if (!bit && boolval != -1) innconf->listenonipv6 = boolval;
++ SET_CONFIG(CONF_VAR_LISTENONIPV6);
++ } else
++ if (EQ(ConfigBuff, _CONF_BINDIPV6ADDRESS)) {
++ TEST_CONFIG(CONF_VAR_BINDIPV6ADDRESS, bit);
++ if (!bit) innconf->bindipv6address = COPY(p);
++ SET_CONFIG(CONF_VAR_BINDIPV6ADDRESS);
++ } else
++ if (EQ(ConfigBuff, _CONF_SOURCEIPV6ADDRESS)) {
++ TEST_CONFIG(CONF_VAR_SOURCEIPV6ADDRESS, bit);
++ if (!bit) innconf->sourceipv6address = COPY(p);
++ SET_CONFIG(CONF_VAR_SOURCEIPV6ADDRESS);
+ }
+ }
+ (void)Fclose(F);
+diff -Nur inn-2.3.2.orig/lib/inet_ntoa.c inn-2.3.2/lib/inet_ntoa.c
+--- inn-2.3.2.orig/lib/inet_ntoa.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/lib/inet_ntoa.c Tue Jun 19 16:06:41 2001
+@@ -5,9 +5,17 @@
+ */
+ #include <stdio.h>
+ #include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <netdb.h>
+ #include "configdata.h"
+ #include "clibrary.h"
++#include "sockaddr_storage.h"
+
++#if !defined(HAVE_SOCKADDR_LEN)
++#include "sa_len.h"
++#endif
+
+ /*
+ * Copyright (c) 1983 Regents of the University of California.
+@@ -40,7 +48,7 @@
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+- */
++ /
+
+ #if defined(LIBC_SCCS) && !defined(lint)
+ static char sccsid[] = "@(#)inet_ntoa.c 5.6 (Berkeley) 2/24/91";
+@@ -50,16 +58,45 @@
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+-#include <netinet/in.h>
+
+ #define UC(c) (((int)c) & 0xFF)
+
+-char *inet_ntoa(struct in_addr in)
++char *Inet_NtoA(struct sockaddr_storage *ss)
+ {
++#if !defined(INET6)
++#if defined(HAVE_INET_NTOA)
++ return inet_ntoa(((struct sockaddr_in *)ss)->sin_addr);
++#else
+ static char buff[18];
+ char *p;
+
+ p = (char *)∈
+ (void)sprintf(buff, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
+ return buff;
++#endif /* HAVE_INET_NTOA */
++#else /* INET6 */
++ static char buff[256];
++ struct sockaddr_in sin;
++ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
++
++ if (ss->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ) {
++ memcpy(&sin.sin_addr, sin6->sin6_addr.s6_addr+12,
++ sizeof(sin.sin_addr));
++ sin.sin_port = ((struct sockaddr_in6 *)ss)->sin6_port;
++ sin.sin_family = AF_INET;
++#if defined(HAVE_SOCKADDR_LEN)
++ sin.sin_len = sizeof(struct sockaddr_in);
++#endif
++ return inet_ntoa(sin.sin_addr);
++ }
++#if defined(HAVE_SOCKADDR_LEN)
++ getnameinfo((struct sockaddr *)ss, ss->ss_len, buff, sizeof(buff), NULL, 0,
++ NI_NUMERICHOST);
++#else
++ getnameinfo((struct sockaddr *)ss, SA_LEN((struct sockaddr *)ss), buff,
++ sizeof(buff), NULL, 0, NI_NUMERICHOST);
++#endif /* HAVE_SOCKADDR_IN */
++
++ return buff;
++#endif /* INET6 */
+ }
+diff -Nur inn-2.3.2.orig/lib/remopen.c inn-2.3.2/lib/remopen.c
+--- inn-2.3.2.orig/lib/remopen.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/lib/remopen.c Tue Jun 19 16:06:41 2001
+@@ -40,13 +40,69 @@
+ int j;
+ int oerrno;
+ FILE *F;
++#if defined(HAVE_GETADDRINFO)
++ struct addrinfo hints, *res, *addr;
++ char portbuf[16];
++ struct sockaddr_storage client;
++#else
+ struct hostent *hp;
+ struct hostent fakehp;
+ struct in_addr quadaddr;
+ struct sockaddr_in server, client;
++#endif /* defined(HAVE_GETADDRINFO) */
+
+ buff = errbuff ? errbuff : mybuff;
+ *buff = '\0';
++
++#if defined(HAVE_GETADDRINFO)
++ (void)memset((POINTER)&hints, 0, sizeof hints);
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++ sprintf(portbuf, "%d", port);
++ if (getaddrinfo(host, portbuf, &hints, &res) != 0)
++ return -1;
++
++ for (addr = res; addr; addr = addr->ai_next) {
++ /* Make a socket and try to connect */
++ if ((i = socket(addr->ai_family, SOCK_STREAM, 0)) < 0)
++ break;
++ (void)memset((POINTER)&client, 0, sizeof client);
++ if (addr->ai_family == AF_INET) {
++ if (innconf->sourceaddress &&
++ inet_pton(AF_INET, innconf->sourceaddress,
++ &((struct sockaddr_in *)&client)->sin_addr) < 1) {
++ freeaddrinfo(addr);
++ return -1;
++ }
++ ((struct sockaddr_in *)&client)->sin_family = AF_INET;
++ }
++#if defined(INET6)
++ if (addr->ai_family == AF_INET6) {
++ if (innconf->sourceipv6address &&
++ inet_pton(AF_INET6, innconf->sourceipv6address,
++ &((struct sockaddr_in6 *)&client)->sin6_addr) < 1) {
++ freeaddrinfo(addr);
++ return -1;
++ }
++ ((struct sockaddr_in6 *)&client)->sin6_family = AF_INET6;
++ }
++#endif /* defined(INET6) */
++ /* Bind to the source address we want. */
++ if (bind(i, (struct sockaddr *)&client, addr->ai_addrlen) < 0) {
++ oerrno = errno;
++ (void)close(i);
++ errno = oerrno;
++ continue;
++ }
++ if (connect(i, addr->ai_addr, addr->ai_addrlen) < 0) {
++ oerrno = errno;
++ (void)close(i);
++ errno = oerrno;
++ continue;
++ }
++
++#else /* HAVE_GETADDRINFO */
++
+ quadaddr.s_addr = inet_addr(host);
+ if (quadaddr.s_addr != (unsigned int) -1) {
+ /* Host was specified as a dotted-quad internet address. Fill in
+@@ -111,6 +167,7 @@
+ errno = oerrno;
+ continue;
+ }
++#endif /* defined(HAVE_GETADDRINFO) */
+
+ /* Connected -- now make sure we can post. */
+ if ((F = fdopen(i, "r")) == NULL) {
+diff -Nur inn-2.3.2.orig/nnrpd/commands.c inn-2.3.2/nnrpd/commands.c
+--- inn-2.3.2.orig/nnrpd/commands.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/nnrpd/commands.c Tue Jun 19 16:06:41 2001
+@@ -184,7 +184,22 @@
+
+ /*syslog(L_NOTICE, "%s (%ld) returned: %d %s %d\n", av[0], (long) pid, i, path, status);*/
+ /* Split "host:permissions:user:pass:groups" into fields. */
+- for (fields[0] = path, i = 0, p = path; *p; p++)
++ /* "host" field for IPv6 address must be enclosed with "[" and "]" */
++ if (path[0] == '[') {
++ fields[0] = path + 1;
++ i = 0;
++ p = path + 1;
++ while (*p && *p != ']')
++ p++;
++ *p = '\0';
++ p += 2; /* Skip next ':' */
++ fields[++i] = p;
++ } else {
++ fields[0] = path;
++ i = 0;
++ p = path;
++ }
++ for (; *p; p++)
+ if (*p == ':') {
+ *p = '\0';
+ fields[++i] = p + 1;
+@@ -753,7 +768,7 @@
+ /* Acquire lock (this could be in RateLimit but that would
+ * invoke the spaghetti factor).
+ */
+- if ((path = (char *) PostRecFilename(ClientIP,PERMuser)) == NULL) {
++ if ((path = (char *) PostRecFilename(&ClientIP,PERMuser)) == NULL) {
+ Reply("%s\r\n", NNTP_CANTPOST);
+ return;
+ }
+diff -Nur inn-2.3.2.orig/nnrpd/misc.c inn-2.3.2/nnrpd/misc.c
+--- inn-2.3.2.orig/nnrpd/misc.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/nnrpd/misc.c Tue Jun 19 16:06:41 2001
+@@ -664,12 +664,12 @@
+ */
+ char
+ *PostRecFilename(ip,user)
+- unsigned long ip;
++ INADDR *ip;
+ char *user;
+ {
+ static char buff[SPOOLNAMEBUFF];
+ char dirbuff[SPOOLNAMEBUFF];
+- unsigned char addr[4];
++ unsigned char addr[16];
+ unsigned int i;
+
+ if (PERMaccessconf->backoff_auth) {
+@@ -677,11 +677,27 @@
+ return(buff);
+ }
+
+- for (i=0; i<4; i++) {
+- addr[i] = (unsigned char) (0x000000ff & (ip>>(i*8)));
++ switch (ip->ss_family) {
++ case AF_INET:
++ for (i=0; i<4; i++) {
++ addr[i] = (unsigned char)
++ (0x000000ff & (((struct sockaddr_in *)ip)->sin_addr.s_addr >>
++ (i*8)));
++ }
++ sprintf(dirbuff,"%s/%03d%03d/%03d",postrec_dir,addr[3],addr[2],addr[1]);
++ break;
++#ifdef INET6
++ case AF_INET6:
++ for (i=0;i<15;i++)
++ addr[i] = ((struct sockaddr_in6 *)ip)->sin6_addr.s6_addr[i];
++ sprintf(dirbuff,"%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x/%02x%02x",
++ postrec_dir,addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
++ addr[6],addr[7],addr[8],addr[9],addr[10],addr[11],
++ addr[12],addr[13]);
++ break;
++#endif
+ }
+
+- sprintf(dirbuff,"%s/%03d%03d/%03d",postrec_dir,addr[3],addr[2],addr[1]);
+ if (!MakeDirectory(dirbuff,TRUE)) {
+ syslog(L_ERROR,"%s Unable to create postrec directories '%s': %s",
+ ClientHost,dirbuff,strerror(errno));
+diff -Nur inn-2.3.2.orig/nnrpd/nnrpd.c inn-2.3.2/nnrpd/nnrpd.c
+--- inn-2.3.2.orig/nnrpd/nnrpd.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/nnrpd/nnrpd.c Tue Jun 19 16:12:24 2001
+@@ -34,6 +34,8 @@
+ int nnrpd_starttls_done = 0;
+ #endif
+
++#include "sa_len.h"
++
+ #if defined(hpux) || defined(__hpux) || defined(_SCO_DS)
+ extern int h_errno;
+ #endif
+@@ -362,11 +364,82 @@
+ Address2Name(INADDR *ap, char *hostname, int i)
+ {
+ char *p;
++#if defined(INET6)
++ struct addrinfo hints, *res, *res0;
++ int len, ret;
++ struct sockaddr_in sin;
++ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ap;
++#else
+ struct hostent *hp;
+ #if defined(h_addr)
+ char **pp;
+ #endif
++#endif /* defined (INET6) */
++
++#if defined(INET6)
++ /* Get the official hostname, store it away. (with new API) */
++ if (ap->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ) {
++ memcpy(&sin.sin_addr, sin6->sin6_addr.s6_addr+12,
++ sizeof(sin.sin_addr));
++ sin.sin_port = ((struct sockaddr_in6 *)ap)->sin6_port;
++ sin.sin_family = AF_INET;
++#if defined(HAVE_SOCKADDR_LEN)
++ sin.sin_len = sizeof(struct sockaddr_in);
++#endif /* defined(HAVE_SOCKADDR_LEN) */
++ ap = &sin;
++ }
+
++#if defined(HAVE_SOCKADDR_LEN)
++ len = ap->ss_len;
++#else
++ len = SA_LEN((struct sockaddr *)ap);
++#endif /* defined(HAVE_SOCKADDR_LEN) */
++ ret = getnameinfo((struct sockaddr *)ap, len, hostname, i, NULL, 0,
++ NI_NAMEREQD);
++ if (ret != 0) {
++ HostErrorStr = gai_strerror(ret);
++ return FALSE;
++ }
++
++ /* Get the address for this host */
++ (void)memset(&hints, 0, sizeof(hints));
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_flags = AI_CANONNAME;
++ hints.ai_socktype = SOCK_STREAM;
++ ret = getaddrinfo(hostname, NULL, &hints, &res0);
++ if (ret != 0) {
++ HostErrorStr = gai_strerror(ret);
++ return FALSE;
++ }
++
++ /* Make sure one of those addresses is the address we got. */
++ for (res = res0; res != NULL; res = res->ai_next) {
++ if (res->ai_addr->sa_family == ap->ss_family) {
++ if (ap->ss_family == AF_INET &&
++ memcmp(&((struct sockaddr_in *)ap)->sin_addr,
++ &((struct sockaddr_in *)res->ai_addr)->sin_addr,
++ sizeof(struct in_addr)) == 0)
++ break;
++ else if (ap->ss_family == AF_INET6 &&
++ memcmp(&((struct sockaddr_in6 *)ap)->sin6_addr,
++ &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
++ sizeof(struct in6_addr)) == 0)
++ break;
++ }
++ }
++ if (res == NULL) {
++ freeaddrinfo(res0);
++ return FALSE;
++ }
++ if (res->ai_canonname == NULL) { /* XXX */
++ freeaddrinfo(res0);
++ return FALSE;
++ }
++ (void)strncpy(hostname, res->ai_canonname, i);
++ freeaddrinfo(res0);
++
++#else /* defined(INET6) */
++
+ /* Get the official hostname, store it away. */
+ if ((hp = gethostbyaddr((char *)ap, sizeof *ap, AF_INET)) == NULL) {
+ HostErrorStr = (char *)hstrerror(h_errno);
+@@ -385,25 +458,27 @@
+ #if defined(h_addr)
+ /* We have many addresses */
+ for (pp = hp->h_addr_list; *pp; pp++)
+- if (memcmp((POINTER)&ap->s_addr, (POINTER)*pp,
+- (SIZE_T)hp->h_length) == 0)
++ if (memcmp((POINTER)&(((struct sockaddr_in *)ap)->sin_addr.s_addr),
++ (POINTER)*pp, (SIZE_T)hp->h_length) == 0)
+ break;
+ if (*pp == NULL)
+ return FALSE;
+ #else
+ /* We have one address. */
+- if (memcmp((POINTER)&ap->s_addr, (POINTER)hp->h_addr,
+- (SIZE_T)hp->h_length) != 0)
++ if (memcmp((POINTER)&(((struct sockaddr_in *)ap)->sin_addr.s_addr),
++ (POINTER)hp->h_addr, (SIZE_T)hp->h_length) != 0)
+ return FALSE;
+ #endif
+
+ /* Only needed for misconfigured YP/NIS systems. */
+- if (ap->s_addr != INADDR_LOOPBACK && strchr(hostname, '.') == NULL
+- && (p = innconf->domain) != NULL) {
++ if (((struct sockaddr_in *)ap)->sin_addr.s_addr != INADDR_LOOPBACK &&
++ strchr(hostname, '.') == NULL && (p = innconf->domain) != NULL) {
+ (void)strcat(hostname, ".");
+ (void)strcat(hostname, p);
+ }
+
++#endif /* defined(INET6) */
++
+ /* Make all lowercase, for wildmat. */
+ for (p = hostname; *p; p++)
+ if (CTYPE(isupper, (int)*p))
+@@ -418,7 +493,7 @@
+ */
+ STATIC void StartConnection()
+ {
+- struct sockaddr_in sin;
++ struct sockaddr_storage ss;
+ ARGTYPE length;
+ char buff[SMBUF];
+ char *ClientAddr;
+@@ -427,9 +502,9 @@
+ static ACCESSGROUP *authconf;
+
+ /* Get the peer's name. */
+- length = sizeof sin;
++ length = sizeof ss;
+ ClientAddr = NULL;
+- if (getpeername(STDIN, (struct sockaddr *)&sin, &length) < 0) {
++ if (getpeername(STDIN, (struct sockaddr *)&ss, &length) < 0) {
+ if (!isatty(STDIN)) {
+ syslog(L_TRACE, "%s cant getpeername %m", "?");
+ (void)strcpy(ClientHost, "?"); /* so stats generation looks correct. */
+@@ -437,14 +512,18 @@
+ ExitWithStats(1, TRUE);
+ }
+ (void)strcpy(ClientHost, "stdin");
+- ClientIP = 0L;
++ memset(&ClientIP, 0, sizeof(ClientIP));
+ ServerHost[0] = '\0';
+ }
+
+ else {
+- if (sin.sin_family != AF_INET) {
++#if defined(INET6)
++ if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
++#else
++ if (ss.ss_family != AF_INET) {
++#endif /* defined(INET6) */
+ syslog(L_ERROR, "%s bad_address_family %ld",
+- "?", (long)sin.sin_family);
++ "?", (long)ss.ss_family);
+ Printf("%d Bad address family. Goodbye.\r\n", NNTP_ACCESS_VAL);
+ ExitWithStats(1, TRUE);
+ }
+@@ -452,8 +531,8 @@
+ /* Get client's name. */
+ #if defined(DO_NNRP_GETHOSTBYADDR)
+ HostErrorStr = NULL;
+- if (!Address2Name(&sin.sin_addr, ClientHost, (int)sizeof ClientHost)) {
+- (void)strcpy(ClientHost, inet_ntoa(sin.sin_addr));
++ if (!Address2Name(&ss, ClientHost, (int)sizeof ClientHost)) {
++ (void)strcpy(ClientHost, Inet_NtoA(&ss));
+ if (HostErrorStr == NULL) {
+ syslog(L_NOTICE,
+ "? cant gethostbyaddr %s %m -- using IP address for access",
+@@ -464,32 +543,32 @@
+ ClientHost, HostErrorStr);
+ }
+ ClientAddr = ClientHost;
+- ClientIP = inet_addr(ClientHost);
++ (void)memcpy(&ClientIP, &ss, sizeof(ss));
+ }
+ else {
+ ClientAddr = buff;
+- (void)strcpy(buff, inet_ntoa(sin.sin_addr));
+- ClientIP = inet_addr(buff);
++ (void)strcpy(buff, Inet_NtoA(&ss));
++ (void)memcpy(&ClientIP, &ss, sizeof(ss));
+ }
+ #else
+- (void)strcpy(ClientHost, inet_ntoa(sin.sin_addr));
+- ClientIP = inet_addr(ClientHost);
++ (void)strcpy(ClientHost, Inet_NtoA(&ss));
++ (void)memcpy(&ClientIP, &ss, sizeof(ss));
+ #endif /* defined(DO_NNRP_GETHOSTBYADDR) */
+- (void)strncpy(ClientIp, inet_ntoa(sin.sin_addr), sizeof(ClientIp));
+- length = sizeof sin;
+- if (getsockname(STDIN, (struct sockaddr *)&sin, &length) < 0) {
++ (void)strncpy(ClientIp, Inet_NtoA(&ss), sizeof(ClientIp));
++ length = sizeof ss;
++ if (getsockname(STDIN, (struct sockaddr *)&ss, &length) < 0) {
+ syslog(L_NOTICE, "%s can't getsockname %m", ClientHost);
+ Printf("%d Can't figure out where you connected to. Goodbye\r\n", NNTP_ACCESS_VAL);
+ ExitWithStats(1, TRUE);
+ }
+ #ifdef DO_NNRP_GETHOSTBYADDR
+ HostErrorStr = NULL;
+- if (!Address2Name(&sin.sin_addr, ServerHost, sizeof(ServerHost))) {
+- strcpy(ServerHost, inet_ntoa(sin.sin_addr));
++ if (!Address2Name(&ss, ServerHost, sizeof(ServerHost))) {
++ strcpy(ServerHost, Inet_NtoA(&ss));
+ /* suppress error reason */
+ }
+ #else
+- strcpy(ServerHost, inet_ntoa(sin.sin_addr));
++ strcpy(ServerHost, Inet_NtoA(&ss));
+ #endif /* DO_NNRP_GETHOSTBYADDR */
+ }
+
+@@ -741,9 +820,14 @@
+ struct timeval tv;
+ unsigned short ListenPort = NNTP_PORT;
+ unsigned long ListenAddr = htonl(INADDR_ANY);
+- int lfd, fd;
++ int lfd[2], fd, maxfd, tmpfd;
++ fd_set fds;
++#ifdef INET6
++ struct sockaddr_in6 ListenAddr6;
++#endif
+ ARGTYPE clen;
+- struct sockaddr_in ssa, csa;
++ struct sockaddr_in ssa;
++ struct sockaddr_storage csa;
+ struct stat Sb;
+ PID_T pid = -1;
+ GID_T NewsGID;
+@@ -777,17 +861,27 @@
+
+ openlog("nnrpd", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
+
++#ifdef INET6
++ memset(&ListenAddr6, '\0', sizeof(ListenAddr6));
++#endif
++
+ if (ReadInnConf() < 0) exit(1);
+
+ #ifdef HAVE_SSL
+- while ((i = getopt(argc, argv, "b:Di:g:op:Rr:s:tS")) != EOF)
++ while ((i = getopt(argc, argv, "6:b:Di:g:op:Rr:s:tS")) != EOF)
+ #else
+- while ((i = getopt(argc, argv, "b:Di:g:op:Rr:s:t")) != EOF)
++ while ((i = getopt(argc, argv, "6:b:Di:g:op:Rr:s:t")) != EOF)
+ #endif /* HAVE_SSL */
+ switch (i) {
+ default:
+ Usage();
+ /* NOTREACHED */
++ case '6': /* bind to a certain ipv6 address in
++ daemon mode */
++#ifdef INET6
++ inet_pton(AF_INET6, optarg, &ListenAddr6.sin6_addr);
++#endif
++ break;
+ case 'b': /* bind to a certain address in
+ daemon mode */
+ ListenAddr = inet_addr(optarg);
+@@ -849,12 +943,12 @@
+ SPOOLlen = strlen(innconf->patharticles);
+
+ if (DaemonMode) {
+- if ((lfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
++ if ((lfd[0] = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(L_FATAL, "can't open socket (%m)");
+ exit(1);
+ }
+
+- if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
++ if (setsockopt(lfd[0], SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
+ syslog(L_FATAL, "can't setsockopt(SO_REUSEADDR) (%m)");
+ exit(1);
+ }
+@@ -864,11 +958,38 @@
+ ssa.sin_addr.s_addr = ListenAddr;
+ ssa.sin_port = htons(ListenPort);
+
+- if (bind(lfd, (struct sockaddr *) &ssa, sizeof(ssa)) < 0) {
++ if (bind(lfd[0], (struct sockaddr *) &ssa, sizeof(ssa)) < 0) {
+ fprintf(stderr, "%s: can't bind (%s)\n", argv[0], strerror(errno));
+ syslog(L_FATAL, "can't bind local address (%m)");
+ exit(1);
+ }
++
++ lfd[1] = -1;
++#ifdef INET6
++ if (innconf->bindipv6address) {
++ if ((lfd[1] = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
++ syslog(L_FATAL, "can't open socket(%m)");
++ exit(1);
++ }
++ if (setsockopt(lfd[1], SOL_SOCKET, SO_REUSEADDR, (char *)&one,
++ sizeof(one)) < 0) {
++ syslog(L_FATAL, "can't setsockopt(SO_REUSEADDR) (%m)");
++ exit(1);
++ }
++ ListenAddr6.sin6_family = AF_INET6;
++ ListenAddr6.sin6_port = htons(ListenPort);
++#ifdef HAVE_SOCKADDR_LEN
++ ListenAddr6.sin6_len = sizeof(ListenAddr6);
++#endif
++ if (bind(lfd[1], (struct sockaddr *)&ListenAddr6,
++ sizeof(ListenAddr6)) < 0) {
++ fprintf(stderr, "%s: can't bind (%s)\n", argv[0],
++ strerror(errno));
++ syslog(L_FATAL, "can't bind local address (%m)");
++ exit(1);
++ }
++ }
++#endif /* INET6 */
+
+ /* If started as root, switch to news uid */
+ if (getuid() == 0) {
+@@ -953,11 +1074,33 @@
+
+ TITLEset("nnrpd: accepting connections");
+
+- listen(lfd, 128);
++ listen(lfd[0], 128);
++ maxfd = lfd[0];
++ if (lfd[1] != -1) {
++ if (maxfd < lfd[1])
++ lfd[1] = maxfd;
++ listen(lfd[1], 128);
++ }
++ maxfd++;
+
+ do {
++ FD_ZERO(&fds);
++ FD_SET(lfd[0], &fds);
++ if (lfd[1] != -1)
++ FD_SET(lfd[1], &fds);
++
++ if (select(maxfd, &fds, NULL, NULL, NULL) < 0) {
++ syslog(L_FATAL, "%s: select cause error (%m)");
++ exit(1);
++ }
++
+ clen = sizeof(csa);
+- fd = accept(lfd, (struct sockaddr *) &csa, &clen);
++ if (FD_ISSET(lfd[0], &fds))
++ tmpfd = lfd[0];
++ else if (lfd[1] != -1 && FD_ISSET(lfd[1], &fds))
++ tmpfd = lfd[1];
++ fd = accept(tmpfd, (struct sockaddr *) &csa, &clen);
++
+ if (fd < 0)
+ continue;
+
+@@ -980,7 +1123,9 @@
+
+ /* child process starts here */
+ TITLEset("nnrpd: connected");
+- close(lfd);
++ close(lfd[0]);
++ if (lfd[1] != -1)
++ close(lfd[1]);
+ dup2(fd, 0);
+ close(fd);
+ dup2(0, 1);
+diff -Nur inn-2.3.2.orig/nnrpd/nnrpd.h inn-2.3.2/nnrpd/nnrpd.h
+--- inn-2.3.2.orig/nnrpd/nnrpd.h Thu May 3 22:27:32 2001
++++ inn-2.3.2/nnrpd/nnrpd.h Tue Jun 19 16:06:41 2001
+@@ -31,6 +31,9 @@
+ #include "paths.h"
+ #include "qio.h"
+
++#ifndef HAVE_SOCKADDR_STORAGE
++#include "sockaddr_storage.h"
++#endif
+
+ /*
+ ** Maximum input line length, sigh.
+@@ -43,7 +46,7 @@
+ /*
+ ** Some convenient shorthands.
+ */
+-typedef struct in_addr INADDR;
++typedef struct sockaddr_storage INADDR;
+
+
+ /*
+@@ -138,7 +141,7 @@
+ EXTERN char ClientHost[SMBUF];
+ EXTERN char ServerHost[SMBUF];
+ EXTERN char Username[SMBUF];
+-EXTERN char ClientIp[20];
++EXTERN char ClientIp[64];
+ EXTERN char LogName[256] ;
+ extern char *ACTIVETIMES;
+ extern char *HISTORY;
+@@ -176,7 +179,7 @@
+ EXTERN long POSTrejected;
+
+ EXTERN BOOL BACKOFFenabled;
+-EXTERN long ClientIP;
++EXTERN INADDR ClientIP;
+ EXTERN char *VirtualPath;
+ EXTERN int VirtualPathlen;
+
+diff -Nur inn-2.3.2.orig/nnrpd/perm.c inn-2.3.2/nnrpd/perm.c
+--- inn-2.3.2.orig/nnrpd/perm.c Thu May 3 22:27:32 2001
++++ inn-2.3.2/nnrpd/perm.c Tue Jun 19 16:06:41 2001
+@@ -1488,6 +1488,10 @@
+ if (!ret && (p = strchr(pat, '/')) != (char *)NULL) {
+ int bits, c;
+ struct in_addr ia, net;
++#ifdef INET6
++ int n;
++ struct in6_addr ia6, net6;
++#endif
+ unsigned int mask;
+
+ *p = '\0';
+@@ -1505,6 +1509,23 @@
+ if ((ia.s_addr & mask) == (net.s_addr & mask))
+ ret = 1;
+ }
++#ifdef INET6
++ if (inet_pton(AF_INET6, ClientIp, &ia6) == 1 &&
++ inet_pton(AF_INET6, pat, &net6) == 1) {
++ if (strchr(p+1, '.') == (char *)NULL) {
++ mask = atoi(p+1);
++ n = mask / 8;
++ bits = mask % 8;
++ for (c = 0; c < n; c++)
++ if (ia6.s6_addr[c] != net6.s6_addr[c])
++ break;
++ if (c == n &&
++ (ia6.s6_addr[c] & (0x00ff << (8 - bits))) ==
++ (net6.s6_addr[c] & (0x00ff << (8 - bits))))
++ ret = 1;
++ }
++ }
++#endif /* INET6 */
+ }
+ }
+ if (ret)
+diff -Nur inn-2.3.2.orig/samples/inn.conf.in inn-2.3.2/samples/inn.conf.in
+--- inn-2.3.2.orig/samples/inn.conf.in Thu May 3 22:27:32 2001
++++ inn-2.3.2/samples/inn.conf.in Tue Jun 19 16:06:41 2001
+@@ -170,3 +170,7 @@
+ pathrun: @RUNDIR@
+ pathspool: @SPOOLDIR@
+ pathtmp: @TMPPATH@
++
++# for IPv6 support
++
++listenonipv6: @ipv6@