--- Begin Message ---
Package: imapproxy
Version: 1.2.4-4
Severity: wishlist
Justification: "Pervasive IPv6 support" release goal
(http://lists.debian.org/debian-devel-announce/2006/05/msg00015.html)
Perhaps not the most important application to make IPv6 capable, but since the
proxy and the target IMAP server can run on a different machines, IPv6 can be
useful (at least in the future, when nobody uses IPv4 anymore).
I think I've fixed this already with my attached patch, but I'm wondering:
I assume all changes should be in #ifdef HAVE_IPV6 blocks, leaving the code
unchanged if HAVE_IPV6 is undefined.
What the heck is ISD.host used for? The result from gethostbyname() is copied
there (shallowly), but then it's never used, right? And whatever is the
servent structure good for? Shouldn't just a port number be enough?
Does the addrlen argument to connect(2) have to equal sizeof struct
sockaddr_in or sizeof struct sockaddr_in6 depending on the socket type and
the s?_family field of the sockaddr structure? It seems that a larger value
is OK too.
So what my patch does is this (when HAVE_IPV6 is defined):
* Replaces statically allocated sockaddr_in structs with sockaddr_storage.
* Uses getaddrinfo() instead of gethostbyname() to resolve server_hostname.
* Tries all addresses returned by getaddrinfo().
* Uses inet_pton() instead of inet_addr() to parse listen_addr.
* Changes the server_port configuration option to be a string, since
getaddrinfo() wants a string (which can then be a service name
from /etc/services) to fill out the port fields of the sockaddr structures of
the returned addrinfo structures.
* Gets rid of the superflous fields from struct IMAPServerDescriptor and adds
an addrinfo pointer instead, to carry the getaddrinfo() result from
ServerInit() to SetBannerAndCapability().
* Add a --enable-ipv6 parameter to ./configure, or rather configure.in.
However, autoconf and autoheaders aren't run by debian/rules, so that needs
to be done and the changes included in the diff.
I also discovered a couple of other oddities such as no default value for
server_port, and the loop in SetBannerAndCapability() always breaks
(commented with "Success"), even if connect() fails.
--
Magnus Holmgren [EMAIL PROTECTED]
(No Cc of list mail needed, thanks)
diff -bwu up-imapproxy-1.2.4/src/imapcommon.c up-imapproxy-1.2.4/src/imapcommon.c
--- up-imapproxy-1.2.4/src/imapcommon.c
+++ up-imapproxy-1.2.4/src/imapcommon.c
@@ -498,7 +498,11 @@
*/
Server.conn = ( ICD_Struct * ) malloc( sizeof ( ICD_Struct ) );
memset( Server.conn, 0, sizeof ( ICD_Struct ) );
+#ifdef HAVE_IPV6
+ Server.conn->sd = socket( ISD.srv.ss_family, SOCK_STREAM, IPPROTO_TCP );
+#else
Server.conn->sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
+#endif
if ( Server.conn->sd == -1 )
{
syslog(LOG_INFO, "LOGIN: '%s' (%s:%d) failed: Unable to open server socket: %s", Username, ClientAddr, sin_port, strerror( errno ) );
diff -bwu up-imapproxy-1.2.4/src/main.c up-imapproxy-1.2.4/src/main.c
--- up-imapproxy-1.2.4/src/main.c
+++ up-imapproxy-1.2.4/src/main.c
@@ -253,8 +253,13 @@
int listensd; /* socket descriptor we'll bind to */
int clientsd; /* incoming socket descriptor */
int addrlen;
+#ifdef HAVE_IPV6
+ struct sockaddr_storage srvaddr;
+ struct sockaddr_storage cliaddr;
+#else
struct sockaddr_in srvaddr;
struct sockaddr_in cliaddr;
+#endif
pthread_t ThreadId; /* thread id of each incoming conn */
pthread_t RecycleThread; /* used just for the recycle thread */
pthread_attr_t attr; /* generic thread attribute struct */
@@ -494,6 +499,37 @@
}
memset( (char *) &srvaddr, 0, sizeof srvaddr );
+#ifdef HAVE_IPV6
+ if ( !PC_Struct.listen_addr ) {
+ srvaddr.ss_family = PF_INET;
+ ((struct sockaddr_in*)&srvaddr)->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else if (inet_pton(AF_INET6, PC_Struct.listen_addr,
+ &((struct sockaddr_in6*)&srvaddr)->sin6_addr) > 0) {
+ srvaddr.ss_family = PF_INET6;
+ }
+ else if (inet_pton(AF_INET, PC_Struct.listen_addr,
+ &((struct sockaddr_in*)&srvaddr)->sin_addr) > 0) {
+ srvaddr.ss_family = PF_INET;
+ }
+ else {
+ syslog( LOG_ERR, "%s: bad bind address: '%s' specified in config file. Exiting.", fn, PC_Struct.listen_addr );
+ exit( 1 );
+ }
+
+ syslog(LOG_INFO, "%s: Binding to tcp %s:%d", fn, PC_Struct.listen_addr ?
+ PC_Struct.listen_addr : "*", PC_Struct.listen_port );
+
+ if (srvaddr.ss_family == PF_INET6) {
+ ((struct sockaddr_in6*)&srvaddr)->sin6_port = htons(PC_Struct.listen_port);
+ listensd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ }
+ else {
+ ((struct sockaddr_in*)&srvaddr)->sin_port = htons(PC_Struct.listen_port);
+ listensd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ }
+
+#else
srvaddr.sin_family = PF_INET;
if ( !PC_Struct.listen_addr )
{
@@ -515,6 +551,8 @@
srvaddr.sin_port = htons(PC_Struct.listen_port);
listensd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+#endif
+
if ( listensd == -1 )
{
syslog(LOG_ERR, "%s: socket() failed: %s", fn, strerror(errno));
@@ -710,7 +748,11 @@
static void ServerInit( void )
{
char *fn = "ServerInit()";
+#ifdef HAVE_IPV6
+ struct addrinfo hints, *ai;
+#else
struct hostent *hp;
+#endif
struct rlimit rl;
int rc;
struct passwd *pw;
@@ -765,6 +807,34 @@
/* grab a host entry for the imap server. */
syslog( LOG_INFO, "%s: proxying to IMAP server '%s'.", fn,
PC_Struct.server_hostname );
+#ifdef HAVE_IPV6
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+
+ for( ;; )
+ {
+ rc = getaddrinfo( PC_Struct.server_hostname, PC_Struct.server_port, &hints, &ai );
+
+ if ( rc )
+ {
+ syslog(LOG_ERR, "%s: gethostbyname() failed to resolve hostname of remote IMAP server: %s -- retrying", fn, strerror(errno) );
+ sleep( 15 );
+ }
+ else
+ {
+ break;
+ }
+ }
+ syslog(LOG_INFO, "%s: Proxying to IMAP port %s",
+ fn, PC_Struct.server_port );
+
+ /*
+ * we fill in our global socket address structure in SetBannerAndCapability,
+ * the possibly several addresses belonging to the hostname can be tried.
+ */
+ ISD.ai = ai;
+#else
for( ;; )
{
@@ -794,6 +864,7 @@
ISD.srv.sin_family = PF_INET;
memcpy( &ISD.srv.sin_addr.s_addr, ISD.host.h_addr, ISD.host.h_length );
ISD.srv.sin_port = ISD.serv.s_port;
+#endif
}
@@ -955,10 +1026,43 @@
int BytesRead;
char *fn = "SetBannerAndCapability()";
int NumRef = 0;
+#ifdef HAVE_IPV6
+ struct addrinfo *ai;
+ int addrlen;
+#endif
/* initialize some stuff */
memset( &itd, 0, sizeof itd );
+#ifdef HAVE_IPV6
+
+ for ( ai = ISD.ai; ; ai = ai->ai_next ) {
+ addrlen = ai->ai_family == PF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
+
+ sd = socket( ai->ai_family, SOCK_STREAM, IPPROTO_TCP );
+ if ( sd == -1 )
+ {
+ syslog(LOG_ERR, "%s: socket() failed: %s -- exiting", fn, strerror(errno));
+ exit( 1 );
+ }
+
+ if ( connect( sd, ai->ai_addr, addrlen ) == -1 ) {
+
+ syslog(LOG_WARNING, "%s: connect() to imap server on socket [%d] failed: %s", fn, sd, strerror(errno));
+ close( sd );
+ }
+ else
+ break; /* Success */
+
+ if (!ai) {
+ syslog(LOG_ERR, "%s: connect() failed to all addresses.", fn);
+ sleep( 15 ); /* IMAP server may not be started yet. */
+ ai = ISD.ai;
+ }
+ }
+ memcpy( &ISD.srv, ai->ai_addr, addrlen );
+
+#else
for ( ;; )
{
sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
@@ -977,9 +1081,10 @@
sleep( 15 ); /* IMAP server may not be started yet. */
}
+ else
break; /* Success */
}
-
+#endif
memset( &conn, 0, sizeof ( ICD_Struct ) );
itd.conn = &conn;
only in patch2:
--- up-imapproxy-1.2.4.orig/include/imapproxy.h
+++ up-imapproxy-1.2.4/include/imapproxy.h
@@ -190,2 +190,6 @@
{
+#ifdef HAVE_IPV6
+ struct addrinfo *ai;
+ struct sockaddr_storage srv; /* IMAP socket address */
+#else
struct hostent host; /* IMAP host entry */
@@ -193,2 +197,3 @@
struct sockaddr_in srv; /* IMAP socket address */
+#endif
};
@@ -264,3 +269,7 @@
char *server_hostname; /* server we proxy to */
+#ifdef HAVE_IPV6
+ char *server_port; /* getaddrinfo() wants a string and then we can use service names */
+#else
unsigned int server_port; /* port we proxy to */
+#endif
unsigned int cache_size; /* number of cache slots */
only in patch2:
--- up-imapproxy-1.2.4.orig/src/config.c
+++ up-imapproxy-1.2.4/src/config.c
@@ -368,4 +368,9 @@
+#ifdef HAVE_IPV6
+ ADD_TO_TABLE( "server_port", SetStringValue,
+ &PC_Struct.server_port, index );
+#else
ADD_TO_TABLE( "server_port", SetNumericValue,
&PC_Struct.server_port, index );
+#endif
only in patch2:
--- up-imapproxy-1.2.4.orig/configure.in
+++ up-imapproxy-1.2.4/configure.in
@@ -34,2 +34,9 @@
+AC_ARG_ENABLE(ipv6, [ --enable-ipv6 enable IPv6 support (default)],
+ if test x$enableval = xno; then
+ want_ipv6=no
+ else
+ want_ipv6=yes
+ fi,
+ want_ipv6=yes)
@@ -131,2 +138,20 @@
+if test "x$want_ipv6" = "xyes"; then
+ AC_MSG_CHECKING([for IPv6])
+ AC_CACHE_VAL(i_cv_type_in6_addr,
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <netdb.h>
+ #include <arpa/inet.h>]],
+ [[struct in6_addr i;]])],
+ [i_cv_type_in6_addr=yes],
+ [i_cv_type_in6_addr=no])])
+ if test $i_cv_type_in6_addr = yes; then
+ AC_DEFINE(HAVE_IPV6,, Build with IPv6 support)
+ fi
+ AC_MSG_RESULT($i_cv_type_in6_addr)
+fi
+
pgpagXn4f83Vr.pgp
Description: PGP signature
--- End Message ---