Bug#644794: [PATCH] Fix buffer lengths for IPv6 adresses logging

"Thomas Preud'homme" <[email protected]> Tue, 11 Oct 2011 20:07:33 +0200
Newsgroups gmane.linux.debian.devel.bugs.general,gmane.mail.spam.dspam.devel
Message-ID <[email protected]>
Le lundi 10 octobre 2011 00:15:15, Thomas Preud'homme a écrit :
> Le dimanche 9 octobre 2011 19:16:58, Thomas Preud'homme a écrit :
> > Le dimanche 9 octobre 2011 15:11:10, Julien Valroff a écrit :
> > > Hi,
> > > 
> > > Here is an attempt to fix Debian bug #644794 [0] stating the logged
> > > IPv6 addresses are truncated.
> > > 
> > > Cheers,
> > > Julien
> > 
> > I would like to propose a patch myself too. Size of ip array should be
> > 128 but I'm thinking about replacing this array by a more appropriate
> > structure (like union of struct in_addr or struct in6_addr). but I want
> > to check it's adequate first.
> > 
> > Congrats for your quick reaction Julien.
> 
> Ok, it will take more time than expected because there is also some other
> place in the code which I believe assume IPv4.
> 
> egrep -In "\[32\]" **/*.c | wc -l gives 11
> 
> One exemple is in src/daemon.c around line 250. I transformed local_addr
> and remote_addr in an union of sockaddr_in and sockaddr_in6 but then the
> code needs to be adapted. I will try to finish the patch tomorrow.

The patch is not completely finished but I'm going in holidays for a week so I 
prefer to post it. I didn't changed the handling of remote_addr in THREAD_CTX 
structure. Also I didn't try to compile so there is probably lots of mistake 
left.

I discovered while writing the last part in daemon.c that IPv4 can be handled 
transparently through IPv6 API so probably some simplification can be done in 
dspam.c

Anyway, it's better than nothing.

Best regards.
dspam_add_ipv6_support.patch (text/x-patch, 7.2 KB)
diff --git a/src/daemon.c b/src/daemon.c
index 1464a0c..f559b97 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -88,7 +88,7 @@
  */
 
 int daemon_listen(DRIVER_CTX *DTX) {
-  struct sockaddr_in local_addr, remote_addr;
+  struct sockaddr_in6 local_addr, remote_addr;
   THREAD_CTX *TTX = NULL;
   fd_set master, read_fds;
   pthread_attr_t attr;
@@ -146,13 +146,13 @@ int daemon_listen(DRIVER_CTX *DTX) {
     len = sizeof(saun.sun_family) + strlen(saun.sun_path) + 1;
 
     LOGDEBUG(INFO_DAEMON_DOMAINSOCK, address);
-  
+
     if (bind(listener, (struct sockaddr *) &saun, len)<0) {
       close(listener);
       LOG(LOG_CRIT, INFO_DAEMON_DOMAINSOCK, address, strerror(errno));
       umask (mask);
       return EFAILURE;
-    }    
+    }
 
     umask (mask);
 
@@ -171,20 +171,23 @@ int daemon_listen(DRIVER_CTX *DTX) {
       return(EFAILURE);
     }
 
-    memset(&local_addr, 0, sizeof(struct sockaddr_in));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_port = htons(port);
+    memset(&local_addr, 0, sizeof(local_addr));
+    local_addr.sin6_family = AF_INET6;
+    local_addr.sin6_port = htons(port);
     if (_ds_read_attribute(agent_config, "ServerHost")) {
       char *host = _ds_read_attribute(agent_config, "ServerHost");
-      local_addr.sin_addr.s_addr = inet_addr(host);
+      if (!inet_pton(AF_INET6, host, &local_addr.sin6_addr.s_addr)) {
+        LOG(LOG_CRIT, ERR_DAEMON_PTON, host);
+        return(EFAILURE);
+      }
       LOGDEBUG(INFO_DAEMON_BIND, host, port);
     } else {
-      local_addr.sin_addr.s_addr = INADDR_ANY;
+      local_addr.sin6_addr.s_addr = IN6ADDR_ANY_INIT;
       LOGDEBUG(INFO_DAEMON_BIND, "*", port);
     }
 
-    if (bind(listener, (struct sockaddr *)&local_addr, 
-             sizeof(struct sockaddr)) == -1) 
+    if (bind(listener, (struct sockaddr *)&local_addr,
+             sizeof(local_addr)) == -1)
     {
       close(listener);
       LOG(LOG_CRIT, ERR_DAEMON_BIND, port, strerror(errno));
@@ -232,22 +235,21 @@ int daemon_listen(DRIVER_CTX *DTX) {
             int newfd;
             int addrlen = sizeof(remote_addr);
 
-            if ((newfd = accept(listener, 
-                                (struct sockaddr *)&remote_addr, 
+            if ((newfd = accept(listener,
+                                (struct sockaddr *)&remote_addr,
                                 (socklen_t *) &addrlen)) == -1)
             {
               LOG(LOG_WARNING, ERR_DAEMON_ACCEPT, strerror(errno));
               continue;
 #ifdef DEBUG
             } else if (!domain) {
-              char buff[32];
-              LOGDEBUG("connection id %d from %s.", newfd, 
-#ifdef HAVE_INET_NTOA_R_2
-                       inet_ntoa_r(remote_addr.sin_addr, buff)
-#else
-                       inet_ntoa_r(remote_addr.sin_addr, buff, sizeof(buff))
-#endif
-                      );
+              char buff[INET6_ADDRSTRLEN];
+              inet_ntop(AF_INET6, (struct sockaddr_in6) remote_addr.sin6_addr,
+                        buff, sizeof(buff));
+              if (!strncmp(buff, "::ffff:", 7))
+                LOGDEBUG("connection id %d from %s.", newfd, buf + 7);
+              else
+                LOGDEBUG("connection id %d from %s.", newfd, buf);
 #endif
             }
             fcntl(newfd, F_SETFL, O_RDWR);
diff --git a/src/daemon.h b/src/daemon.h
index fa045af..d3cd83c 100644
--- a/src/daemon.h
+++ b/src/daemon.h
@@ -51,7 +51,7 @@ typedef struct {
   int sockfd;
   char authenticated;
   pthread_t thread;
-  struct sockaddr_in remote_addr;
+  struct sockaddr_in6 remote_addr;
   buffer *packet_buffer;
   DRIVER_CTX *DTX;
 } THREAD_CTX;
diff --git a/src/dspam.c b/src/dspam.c
index 26266c9..0ddadce 100644
--- a/src/dspam.c
+++ b/src/dspam.c
@@ -409,7 +409,7 @@ process_message (
       strcmp(_ds_pref_val(ATX->PTX, "optOutClamAV"), "on"))
   {
     if (has_virus(message)) {
-      char ip[32];
+      char ip[INET6_ADDRSTRLEN];
       CTX->result = DSR_ISSPAM;
       CTX->probability = 1.0;
       CTX->confidence = 1.0;
@@ -3814,7 +3814,7 @@ MEM_ALLOC:
  */
 
 int tracksource(DSPAM_CTX *CTX) {
-  char ip[32];
+  char ip[INET6_ADDRSTRLEN];
 
   if (!dspam_getsource (CTX, ip, sizeof (ip)))
   {
@@ -4001,53 +4001,50 @@ int is_blacklisted(DSPAM_CTX *CTX, AGENT_CTX *ATX) {
   /* No cygwin support for IP Blacklisting */
   return 0;
 #else
-  char ip[32];
+  char ip[INET6_ADDRSTRLEN];
   int bad = 0;
   struct attribute *attrib;
   struct addrinfo *res = NULL;
-  struct sockaddr_in saddr;
-  char host[32];
+  char host[INET6_ADDRSTRLEN];
   char lookup[256];
-  char *ptr;
-  char *octet[4];
-  int i = 3;
-  octet[0] = octet[1] = octet[2] = octet[3] = NULL;
 
   if (!dspam_getsource (CTX, ip, sizeof (ip))) {
-    host[0] = 0;
-    ptr = strtok(ip, ".");
-    while(ptr != NULL && i>=0 && i<4) {
-      octet[i] = ptr;
-      ptr = strtok(NULL, ".");
-      if (ptr == NULL && i!=0)
-        return 0;
-      i--;
+    struct addrinfo *unused_addr, hint = {
+      .ai_flags = AI_NUMERICHOST;
+      .ai_family = AF_UNSPEC;
+      .ai_socktype = .ai_protocol = 0;
     }
 
-    if (octet[0] == NULL || octet[1] == NULL || octet[2] == NULL || octet[3] == NULL)
+    host[0] = 0;
+    if (getaddrinfo(ip, NULL, &hint, &unused_addr))
       return 0;
 
-    snprintf(host, sizeof(host), "%s.%s.%s.%s.", octet[0], octet[1], octet[2], octet[3]);
+    free(unused_addr);
+    snprintf(host, sizeof(host), "%s", ip);
 
     attrib = _ds_find_attribute(agent_config, "Lookup");
     while(attrib != NULL) {
       int error;
-      snprintf(lookup, sizeof(lookup), "%s%s", host, attrib->value);
+      snprintf(lookup, sizeof(lookup), "%s.%s", host, attrib->value);
       error = getaddrinfo(lookup, NULL, NULL, &res);
       if (!error) {
-        char buff[128];
         if (!bad) {
-          memcpy(&saddr, res->ai_addr, sizeof(struct sockaddr));
-#ifdef HAVE_INET_NTOA_R_2
-          inet_ntoa_r(saddr.sin_addr, buff);
-#else
-          inet_ntoa_r(saddr.sin_addr, buff, sizeof(buff));
-#endif
-          if (strncmp(buff, "127.0.0.", 8) == 0) {
-            STATUS("Blacklisted (%s)", attrib->value);
-            bad = 1;
-            freeaddrinfo(res);
-            break;
+          if (res->ai_family == AF_INET) {
+            struct sockaddr_in *saddr = res->ai_addr;
+
+            if (saddr->sin_addr.s_addr & htonl(0xFF000000) == 127) {
+              STATUS("Blacklisted (%s)", attrib->value);
+              bad = 1;
+              freeaddrinfo(res);
+            }
+          } else {
+            struct sockaddr_in6 *saddr = res->ai_addr;
+
+            if (saddr->sin6_addr == in6addr_loopback) {
+              STATUS("Blacklisted (%s)", attrib->value);
+              bad = 1;
+              freeaddrinfo(res);
+            }
           }
         }
         freeaddrinfo(res);
diff --git a/src/language.h b/src/language.h
index ed33188..7edab53 100644
--- a/src/language.h
+++ b/src/language.h
@@ -122,6 +122,7 @@ user, e.g.. root or Trusted User [uid=%d(%s)]"
 
 #define ERR_DAEMON_NO_SUPPORT   "DSPAM was not compiled with daemon support"
 #define ERR_DAEMON_BIND         "Could not bind to :%d: %s"
+#define ERR_DAEMON_PTON         "Could not bind to :%s"
 #define ERR_DAEMON_DOMAINBIND	"Could not bind to %s: %s"
 #define ERR_DAEMON_SOCKET	"Could not create socket: %s"
 #define ERR_DAEMON_SOCKOPT	"Could not set sockopt %s: %s"
signature.asc (application/pgp-signature, 836 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iQIcBAABAgAGBQJOlIXlAAoJENADhS+9UlKenXwQALWFPBXpQ1CB291epmE5O38q
+quVpBry64f2sJU7KQ6LPMt23fIt1CbqRBb60JjhvFLnMxA0hHyWQ7DhlkfmrF0h
mkcWWg/ZdmJSyKZjPP+KpIe1sFXj2vySnci1E39JWF3x10hlRJnINTwH7nQOYhwd
hNVFOl3NQeep/DphDVA8lEfGnj+Kf2HrpxNpn9iXSxobiGpWJbip4FrTBcVuzCLE
x8/1O/KXJ/io5LBJTY1uUBINo6yj0Smu98uSZCXTphkADcxkW/LtlV7FwKWQ3Zgs
Id4OqwDt5tA1C2oI8u5HfaKbUs8P+KjYaHFFuHzvg9xr+Uhvu9WiXk0FLyO8lMrD
KrXrpNtWfTQmh3VIrLnPKkJ50LlENII9Ze/syG1A//zck5nFpjNWew5vePQ2vz9U
EeRMmWJ1Ie1H5BRCAPM8m9CIhgY9MwZUoLmjwSfk6lRxrcQqal+8K0dogvoILDzW
OlapbW2Wk+oLj7gvm16VeINu3+W56I/6/3iKowMnc98S1mQMy1wQK6ILdSzIaTT6
vCphOn9ZPE5neTs4NHvkkEkyNpbFhqxPkkic7jnvGAWiFSy4ExejncK7Y+iiS4lJ
dm2lnVMh0cTvk6rYksMahQA6WLMp/nHHMiBtYTnnN0Z82rrmuokKI1YGgtf5eR8I
8M1lnLXcDU4ApGuLXBQu
=kVJU
-----END PGP SIGNATURE-----