malware: avoid partial packets, sending to ClamAV
authorJeremy Harris <jgh146exb@wizmail.org>
Fri, 1 Jan 2021 14:31:14 +0000 (14:31 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Fri, 1 Jan 2021 14:31:14 +0000 (14:31 +0000)
src/src/malware.c

index dfa8e2b4b79b30e55c242a4e46e46bb6ebbfd605..a42e39a57e0bc92a4a1b4261fbdaf54c9497c40e 100644 (file)
@@ -132,6 +132,11 @@ static const uschar * malware_regex_default = US ".+";
 static const pcre * malware_default_re = NULL;
 
 
+#ifdef TCP_CORK
+# define EXIM_TCP_CORK TCP_CORK
+#elif defined(TCP_NOPUSH)
+# define EXIM_TCP_CORK TCP_NOPUSH
+#endif
 
 #ifndef DISABLE_MAL_CLAM
 /* The maximum number of clamd servers that are supported in the configuration */
@@ -1570,8 +1575,8 @@ badseek:  err = errno;
       if (num_servers)
        {
        /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
-        * only supports AF_INET, but we should probably be looking to the
-        * future and rewriting this to be protocol-independent anyway. */
+       only supports AF_INET, but we should probably be looking to the
+       future and rewriting this to be protocol-independent anyway. */
 
        while (num_servers > 0)
          {
@@ -1582,7 +1587,7 @@ badseek:  err = errno;
                         cd->hostspec, cd->tcp_port);
 
          /* Lookup the host. This is to ensure that we connect to the same IP
-          * on both connections (as one host could resolve to multiple ips) */
+         on both connections (as one host could resolve to multiple ips) */
          for (;;)
            {
            /*XXX we trust that the cmd_str is ideempotent */
@@ -1625,9 +1630,9 @@ badseek:  err = errno;
          }
 
       /* have socket in variable "sock"; command to use is semi-independent of
-       * the socket protocol.  We use SCAN if is local (either Unix/local
-       * domain socket, or explicitly told local) else we stream the data.
-       * How we stream the data depends upon how we were built.  */
+      the socket protocol.  We use SCAN if is local (either Unix/local
+      domain socket, or explicitly told local) else we stream the data.
+      How we stream the data depends upon how we were built.  */
 
       if (!use_scan_command)
        {
@@ -1674,13 +1679,17 @@ badseek:  err = errno;
            malware_daemon_ctx.sock);
          }
 
-       /* send file body to socket */
+       /* send file size */
+#ifdef EXIM_TCP_CORK
+       (void) setsockopt(clam_fd, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
+#endif
        send_size = htonl(fsize_uint);
        if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
          return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to send file size to socket (%s)", hostname),
            malware_daemon_ctx.sock);
 
+       /* send file body */
        while (fsize_uint)
          {
          unsigned n = MIN(fsize_uint, big_buffer_size);
@@ -1701,6 +1710,9 @@ badseek:  err = errno;
          return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to send file terminator to socket (%s)", hostname),
            malware_daemon_ctx.sock);
+#ifdef EXIM_TCP_CORK
+       (void) setsockopt(clam_fd, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
+#endif
        }
       else
        { /* use scan command */
@@ -1730,10 +1742,10 @@ badseek:  err = errno;
              malware_daemon_ctx.sock);
 
        /* Do not shut down the socket for writing; a user report noted that
-        * clamd 0.70 does not react well to this. */
+       clamd 0.70 does not react well to this. */
        }
       /* Commands have been sent, no matter which scan method or connection
-       * type we're using; now just read the result, independent of method. */
+      type we're using; now just read the result, independent of method. */
 
       /* Read the result */
       memset(av_buffer, 0, sizeof(av_buffer));
@@ -1779,6 +1791,7 @@ badseek:  err = errno;
       /* strip newline at the end (won't be present for zINSTREAM)
       (also any trailing whitespace, which shouldn't exist, but we depend upon
       this below, so double-check) */
+
       p = av_buffer + Ustrlen(av_buffer) - 1;
       if (*p == '\n') *p = '\0';