This is the first of several patches to limit the number of address
verification requests in the Postfix mail queue.

The second patch will introduce the primary, before-queue, enforcement
mechanism that considers the domain in an email address. This
involves more code and requires more time for quality testing.

The first patch introduces the secondary, post-queue, enforcement
mechanism that limits the number of probes in the active queue to
1/4 of the active queue capacity, without any regard of the domain
in an email address.

Tempfailing requests in this manner is not as bad as one might
think.  The Postfix verify cache proactively updates active addresses
well before they expire. Thus, non-selective tempfailing affects
only inactive addresses that have expired (31 days) or unknown
addresses.

This patch is as simple as possible. It involves one configuration
parameter (address_verify_pending_request_limit) for the pending
request limit, and one counter (qmgr_vrfy_pend_count) for the current
number of verification requests in the active queue. It tempfails
all verification requests that exceed the limit.

        Wietse

diff --exclude=man --exclude=html --exclude=README_FILES --exclude=.indent.pro 
--exclude=Makefile.in -cr --exclude=util --exclude=mantools --exclude=proto 
--exclude=oqmgr /var/tmp/postfix-2.12-20140406/src/global/mail_params.h 
./src/global/mail_params.h
*** /var/tmp/postfix-2.12-20140406/src/global/mail_params.h     Sun Apr  6 
19:00:17 2014
--- ./src/global/mail_params.h  Thu Apr 24 09:04:32 2014
***************
*** 2733,2738 ****
--- 2733,2742 ----
  #define DEF_VRFY_XPORT_MAPS           "$" VAR_TRANSPORT_MAPS
  extern char *var_vrfy_xport_maps;
  
+ #define VAR_VRFY_PEND_LIMIT           "address_verify_pending_request_limit"
+ #define DEF_VRFY_PEND_LIMIT           (DEF_QMGR_ACT_LIMIT / 4)
+ extern int var_vrfy_pend_limit;
+ 
   /*
    * Message delivery trace service.
    */
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=.indent.pro 
--exclude=Makefile.in -cr --exclude=util --exclude=mantools --exclude=proto 
--exclude=oqmgr /var/tmp/postfix-2.12-20140406/src/qmgr/qmgr.c ./src/qmgr/qmgr.c
*** /var/tmp/postfix-2.12-20140406/src/qmgr/qmgr.c      Sat Sep 28 21:03:32 2013
--- ./src/qmgr/qmgr.c   Thu Apr 24 10:19:02 2014
***************
*** 310,315 ****
--- 310,320 ----
  /* .IP "\fBqmgr_ipc_timeout (60s)\fR"
  /*    The time limit for the queue manager to send or receive information
  /*    over an internal communication channel.
+ /* .PP
+ /*    Available in Postfix version 2.12 and later:
+ /* .IP "\fBaddress_verify_pending_request_limit (see 'postconf -d' output)\fR"
+ /*    A safety limit that prevents address verification requests
+ /*    from overwhelming the Postfix queue.
  /* MISCELLANEOUS CONTROLS
  /* .ad
  /* .fi
***************
*** 445,450 ****
--- 450,456 ----
  char   *var_def_filter_nexthop;
  int     var_qmgr_daemon_timeout;
  int     var_qmgr_ipc_timeout;
+ int     var_vrfy_pend_limit;
  
  static QMGR_SCAN *qmgr_scans[2];
  
***************
*** 718,723 ****
--- 724,730 ----
        VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0,
        VAR_LOCAL_CON_LIMIT, DEF_LOCAL_CON_LIMIT, &var_local_con_lim, 0, 0,
        VAR_CONC_COHORT_LIM, DEF_CONC_COHORT_LIM, &var_conc_cohort_limit, 0, 0,
+       VAR_VRFY_PEND_LIMIT, DEF_VRFY_PEND_LIMIT, &var_vrfy_pend_limit, 1, 0,
        0,
      };
      static const CONFIG_BOOL_TABLE bool_table[] = {
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=.indent.pro 
--exclude=Makefile.in -cr --exclude=util --exclude=mantools --exclude=proto 
--exclude=oqmgr /var/tmp/postfix-2.12-20140406/src/qmgr/qmgr.h ./src/qmgr/qmgr.h
*** /var/tmp/postfix-2.12-20140406/src/qmgr/qmgr.h      Sat Jul 24 13:28:00 2010
--- ./src/qmgr/qmgr.h   Thu Apr 24 10:17:33 2014
***************
*** 377,382 ****
--- 377,383 ----
  
  extern int qmgr_message_count;
  extern int qmgr_recipient_count;
+ extern int qmgr_vrfy_pend_count;
  
  extern void qmgr_message_free(QMGR_MESSAGE *);
  extern void qmgr_message_update_warn(QMGR_MESSAGE *);
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=.indent.pro 
--exclude=Makefile.in -cr --exclude=util --exclude=mantools --exclude=proto 
--exclude=oqmgr /var/tmp/postfix-2.12-20140406/src/qmgr/qmgr_message.c 
./src/qmgr/qmgr_message.c
*** /var/tmp/postfix-2.12-20140406/src/qmgr/qmgr_message.c      Fri Apr  5 
17:27:48 2013
--- ./src/qmgr/qmgr_message.c   Thu Apr 24 14:27:44 2014
***************
*** 8,13 ****
--- 8,14 ----
  /*
  /*    int     qmgr_message_count;
  /*    int     qmgr_recipient_count;
+ /*    int     qmgr_vrfy_pend_count;
  /*
  /*    QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode)
  /*    const char *class;
***************
*** 38,43 ****
--- 39,51 ----
  /*    of in-core recipient structures (i.e. the sum of all recipients
  /*    in all in-core message structures).
  /*
+ /*    qmgr_vrfy_pend_count is a global counter for the total
+ /*    number of in-core message structures that are associated
+ /*    with an address verification request. Requests that exceed
+ /*    the address_verify_pending_limit are deferred immediately.
+ /*    This is a backup mechanism for a more refined enforcement
+ /*    mechanism in the verify(8) daemon.
+ /*
  /*    qmgr_message_alloc() creates an in-core message structure
  /*    with sender and recipient information taken from the named queue
  /*    file. A null result means the queue file could not be read or
***************
*** 149,154 ****
--- 157,163 ----
  
  int     qmgr_message_count;
  int     qmgr_recipient_count;
+ int     qmgr_vrfy_pend_count;
  
  /* qmgr_message_create - create in-core message structure */
  
***************
*** 748,758 ****
             * after the logfile is deleted.
             */
            else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
!               message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
!               if (message->tflags == DEL_REQ_FLAG_RECORD)
!                   message->tflags_offset = curr_offset;
!               else
!                   message->tflags_offset = 0;
            }
            continue;
        }
--- 757,771 ----
             * after the logfile is deleted.
             */
            else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
!               if (message->tflags == 0) {
!                   message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
!                   if (message->tflags == DEL_REQ_FLAG_RECORD)
!                       message->tflags_offset = curr_offset;
!                   else
!                       message->tflags_offset = 0;
!                   if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) != 0)
!                       qmgr_vrfy_pend_count++;
!               }
            }
            continue;
        }
***************
*** 1159,1164 ****
--- 1172,1185 ----
        }
  
        /*
+        * Safety: defer excess address verification requests.
+        */
+       if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) != 0
+           && qmgr_vrfy_pend_count > var_vrfy_pend_limit)
+           QMGR_REDIRECT(&reply, MAIL_SERVICE_RETRY,
+                         "4.3.2 Too many address verification requests");
+ 
+       /*
         * Look up or instantiate the proper transport.
         */
        if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
***************
*** 1423,1428 ****
--- 1444,1451 ----
        myfree(message->rewrite_context);
      recipient_list_free(&message->rcpt_list);
      qmgr_message_count--;
+     if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) != 0)
+       qmgr_vrfy_pend_count--;
      myfree((char *) message);
  }
  

Reply via email to