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 +#include +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 +#ifdef IPV6_INRIA_VERSION +%%%yes%%% +#endif], + [ipv6type=$i; + CFLAGS="-DINET6 $CFLAGS"]) + ;; + kame) + dnl http://www.kame.net/ + AC_EGREP_CPP(%%%yes%%%, [dnl +#include +#ifdef __KAME__ +%%%yes%%% +#endif], + [ipv6type=$i; + CFLAGS="-DINET6 $CFLAGS"]) + ;; + linux-glibc) + dnl http://www.v6.linux.or.jp/ + AC_EGREP_CPP(%%%yes%%%, [dnl +#include +#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 +#ifdef _TOSHIBA_INET6 +%%%yes%%% +#endif], + [ipv6type=$i; + ipv6lib=inet6; + ipv6libdir=/usr/local/v6/lib; + CFLAGS="-DINET6 $CFLAGS"]) + ;; + v6d) + AC_EGREP_CPP(%%%yes%%%, [dnl +#include +#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 +#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 +#include +],[ +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 +#include +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 +#include +],[ +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 +#include +],[ +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 ") + */ + +#include +#include +#include +#include + +#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 @@ -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,42 @@ /* Build the argument vector for innd. Pass -p to innd to tell it what port we just created and bound to for it. */ - innd_argv = NEW(char *, 1 + argc + 1); + innd_argv = NEW(char *, 1 + argc + 2); 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 +#include #include #include #include @@ -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.3.orig/lib/Makefile inn-2.3.3/lib/Makefile --- inn-2.3.3.orig/lib/Makefile Thu May 3 22:27:32 2001 +++ inn-2.3.3/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 + xmalloc.c xsignal.c xwrite.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 + xmalloc.o xsignal.o xwrite.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 #include +#include +#include +#include +#include #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 #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@