token when it adds mail to the incoming queue. If no token
is available the cleanup server pauses for $in_flow_delay
seconds and proceeds anyway. The delay allows mail sending
- process to catch up and access the disk. Valid delays are
- 0..10 seconds.
+ process to catch up and access the disk while not blocking
+ inbound mail. Valid delays are 0..10 seconds.
20010727
Bugfix: updated LDAP client module from LaMont Jones, HP.
+ This also introduces new LDAP query filter patterns: %u
+ (address localpart) and %d (domain part). Files:
+ conf/sample-ldap.cf, util/dict_ldap.c.
20010729
- Bugfix: recursive restrictions could clobber non-reentrant
- address resolving results. Problem found by Victor Duchovni,
- morganstanley.com. In order to fix, introduced address
- resolving caching, which shouls speed up UCE processing.
+ Bugfix: recursive smtpd_whatever_restrictions clobbered
+ intermediate results when switching between sender and
+ recipient address restrictions. Problem found by Victor
+ Duchovni, morganstanley.com. In order to fix, introduced
+ address resolver result caching, which should also help to
+ speed up sender/recipient address restriction processing.
- Bugfix: the not yet published DUNNO table lookup result
- did not prevent further partial key lookups in the same
- table. Problem found by Victor Duchovni, morganstanley.com.
+ Bugfix: the not yet announced DUNNO access table lookup
+ result did not prevent lookups with substrings of the same
+ lookup key. Found by Victor Duchovni, morganstanley.com.
-20010729
+20010730
Robustness: trim trailing whitespace from regexp and pcre
right-hand sides, for consistency with DB/DBM tables.
Files: util/dict_pcre.c, util/dict_regexp.c.
+
+20010731
+
+ Robustness: eliminate duplicate IP addresses after expansion
+ of hostnames in $inet_interfaces, so that Postfix does not
+ suddenly refuse to start up after someone changes the DNS.
+ Files: util/inet_addr_list.c global/own_inet_addr.c.
+
+ Feature: specify "disable_verp_bounces = yes" to have
+ Postfix send one RFC-standard, non-VERP, bounce report for
+ multi-recipient mail, even when VERP style delivery is
+ requested.
+Incompatible changes with snapshot-20010731
+===========================================
+
+The protocol between Postfix master and child processes has changed.
+You must stop and start Postfix in order to switch between Snapshot
+20010731 and releases that implement the older protocol.
+
+Major changes with snapshot-20010731
+====================================
+
+Specify "disable_verp_bounces = yes" to have Postfix send one
+RFC-standard, non-VERP, bounce report for multi-recipient mail,
+even when VERP style delivery is requested.
+
+Variable coupling between message receiving rates and message
+delivery rates. When the message receiving rate exceeds the message
+delivery rate, an SMTP server will pause for $in_flow_delay seconds
+(default: 1) before accepting a message. This delay gives Postfix
+a chance catch up and access the disk, while still allowing new
+mail to arrive.
+
+The in_flow_delay feature has effect mainly when your system is
+being flooded port through a limited number of SMTP connections.
+This is also useful for mass-mailing applications, because it avoids
+the need to hand-tune the rate at which mail is sent into Postfix.
+
+The in_flow_delay feature has negligible effect when mail arrives
+via many different SMTP connections. With the default limit of 50
+SMTP server processes and with the default $in_flow_delay of 1
+second, total mail inflow is limited to 50 messages per second more
+than the number of messages that are delivered per second. Many
+systems saturate at values much smaller than 50 messages per second.
+
Incompatible changes with snapshot-20010714
===========================================
#
# The mail_owner parameter specifies the owner of the Postfix queue
# and of most Postfix daemon processes. Specify the name of a user
-# account THAT DOES NOT SHARE A GROUP WITH OTHER ACCOUNTS AND THAT
-# OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In particular,
-# don't specify nobody or daemon. PLEASE USE A DEDICATED USER.
+# account THAT DOES NOT SHARE ITS USER OR GROUP ID WITH OTHER ACCOUNTS
+# AND THAT OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In
+# particular, don't specify nobody or daemon. PLEASE USE A DEDICATED
+# USER.
#
mail_owner = postfix
#
#local_recipient_maps = $alias_maps unix:passwd.byname
+# INPUT RATE CONTROL
+#
+# The in_flow_delay configuration parameter implements mail input
+# flow control. By default, a Postfix process will pause for one
+# second before accepting a new message, when the message arrival
+# rate exceeds the message delivery rate. With the default 50 SMTP
+# server process limit, this limits the mail inflow to 50 messages
+# a second more than the number of messages delivered per second.
+#
+# Specify 0 to disable the feature. Valid delays are 0..10.
+#
+#in_flow_delay = 1
+
# ADDRESS REWRITING
#
# Insert text from sample-rewrite.cf if you need to do address
Limit the amount of memory in bytes used to process
a message header.
+ <b>in</b><i>_</i><b>flow</b><i>_</i><b>delay</b>
+ Amount of time to pause before accepting a message,
+ when the message arrival rate exceeds the message
+ delivery rate.
+
<b>extract</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
Limit the amount of recipients extracted from mes-
sage headers.
cess (including successful <b>postmap</b> <b>-q</b> lookup) and termi-
nates with non-zero exit status in case of failure.
-<b>BUGS</b>
- The "delete key" support is limited to one delete opera-
- tion per command invocation.
-
<b>ENVIRONMENT</b>
<b>MAIL</b><i>_</i><b>CONFIG</b>
Directory with Postfix configuration files.
Enable verbose logging for debugging purposes.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
details and for default values.
<b>database</b><i>_</i><b>type</b>
- Default alias database type. On many UNIX systems,
+ Default alias database type. On many UNIX systems,
the default type is either <b>dbm</b> or <b>hash</b>.
<b>STANDARDS</b>
<a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface.
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
cess (including successful <b>postmap</b> <b>-q</b> lookup) and termi-
nates with non-zero exit status in case of failure.
-<b>BUGS</b>
- The "delete key" support is limited to one delete opera-
- tion per command invocation.
-
<b>ENVIRONMENT</b>
<b>MAIL</b><i>_</i><b>CONFIG</b>
Directory with Postfix configuration files.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
<b>database</b><i>_</i><b>type</b>
- Default output database type. On many UNIX sys-
- tems, the default database type is either <b>hash</b> or
+ Default output database type. On many UNIX sys-
+ tems, the default database type is either <b>hash</b> or
<b>dbm</b>.
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
\fBpostalias\fR terminates with zero exit status in case of success
(including successful \fBpostmap -q\fR lookup) and terminates
with non-zero exit status in case of failure.
-.SH BUGS
-.ad
-.fi
-The "delete key" support is limited to one delete operation
-per command invocation.
.SH ENVIRONMENT
.na
.nf
\fBpostmap\fR terminates with zero exit status in case of success
(including successful \fBpostmap -q\fR lookup) and terminates
with non-zero exit status in case of failure.
-.SH BUGS
-.ad
-.fi
-The "delete key" support is limited to one delete operation
-per command invocation.
.SH ENVIRONMENT
.na
.nf
Limit the number of envelope recipients that are remembered.
.IP \fBheader_size_limit\fR
Limit the amount of memory in bytes used to process a message header.
+.IP \fBin_flow_delay\fR
+Amount of time to pause before accepting a message, when the
+message arrival rate exceeds the message delivery rate.
.IP \fBextract_recipient_limit\fR
Limit the amount of recipients extracted from message headers.
.SH SEE ALSO
/* Limit the number of envelope recipients that are remembered.
/* .IP \fBheader_size_limit\fR
/* Limit the amount of memory in bytes used to process a message header.
+/* .IP \fBin_flow_delay\fR
+/* Amount of time to pause before accepting a message, when the
+/* message arrival rate exceeds the message delivery rate.
/* .IP \fBextract_recipient_limit\fR
/* Limit the amount of recipients extracted from message headers.
/* SEE ALSO
#define DEF_VERP_FILTER "-=+"
extern char *var_verp_filter;
+#define VAR_VERP_BOUNCE_OFF "disable_verp_bounces"
+#define DEF_VERP_BOUNCE_OFF 0
+extern bool var_verp_bounce_off;
+
/*
* Inbound mail flow control. This allows for a stiffer coupling between
* receiving mail and sending mail. A sending process produces one token for
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20010730"
+#define DEF_MAIL_VERSION "Snapshot-20010731"
extern char *var_mail_version;
/* LICENSE
VAR_INET_INTERFACES, host);
myfree(hosts);
+ /*
+ * Weed out duplicate IP addresses. Duplicates happen when the same
+ * IP address is listed under multiple hostnames. If we don't weed
+ * out duplicates, Postfix can suddenly stop working after the DNS is
+ * changed.
+ */
+ inet_addr_list_uniq(addr_list);
+
inet_addr_list_init(&local_addrs);
inet_addr_list_init(&local_masks);
if (inet_addr_local(&local_addrs, &local_masks) == 0)
/*
* Write or discard N bytes.
*/
+ memset(buf, 0, len > BUFFER_SIZE ? BUFFER_SIZE : len);
+
for (count = len; count > 0; count -= n)
if ((n = write(MASTER_FLOW_WRITE, buf, count > BUFFER_SIZE ?
- BUFFER_SIZE : count)) < 0)
+ BUFFER_SIZE : count)) < 0)
return (-1);
if (msg_verbose)
msg_info("%s: %d %d", myname, len, len - count);
int var_local_con_lim;
int var_local_rcpt_lim;
int var_proc_limit;
+bool var_verp_bounce_off;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
qmgr_incoming = qmgr_scan_create(MAIL_QUEUE_INCOMING);
qmgr_deferred = qmgr_scan_create(MAIL_QUEUE_DEFERRED);
qmgr_scan_request(qmgr_incoming, QMGR_SCAN_START);
- qmgr_deferred_run_event(0, (char *)0);
+ qmgr_deferred_run_event(0, (char *) 0);
}
/* main - the main program */
};
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user,
+ VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off,
0,
};
} else {
if (msg_verbose)
msg_info("%s: bounce %s", myname, message->queue_id);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
if (event_time() > message->arrival_time + var_max_queue_time) {
msg_info("%s: from=<%s>, status=expired, returned to sender",
message->queue_id, message->sender);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
int var_local_rcpt_lim; /* XXX */
int var_local_con_lim; /* XXX */
int var_proc_limit;
+bool var_verp_bounce_off;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
};
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user,
+ VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off,
0,
};
} else {
if (msg_verbose)
msg_info("%s: bounce %s", myname, message->queue_id);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
if (event_time() > message->arrival_time + var_max_queue_time) {
msg_info("%s: from=<%s>, status=expired, returned to sender",
message->queue_id, message->sender);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
smtpd_check.o: ../../include/dict.h
smtpd_check.o: ../../include/vstream.h
smtpd_check.o: ../../include/htable.h
+smtpd_check.o: ../../include/ctable.h
smtpd_check.o: ../../include/dns.h
smtpd_check.o: ../../include/namadr_list.h
smtpd_check.o: ../../include/domain_list.h
int recursion;
off_t msg_size;
int junk_cmds;
- VSTRING *error_text;
#ifdef USE_SASL_AUTH
char *sasl_mechanism_list;
char *sasl_method;
state->recursion = 0;
state->msg_size = 0;
state->junk_cmds = 0;
- state->error_text = vstring_alloc(100);
#ifdef USE_SASL_AUTH
if (SMTPD_STAND_ALONE(state))
if (state->buffer)
vstring_free(state->buffer);
smtpd_peer_reset(state);
- vstring_free(state->error_text);
#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable)
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
mystrtok sigdelay translit valid_hostname vstream_popen \
vstring vstring_vstream doze select_bug stream_test mac_expand \
- watchdog unescape hex_quote name_mask rand_sleep sane_time ctable
+ watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
+ inet_addr_list
LIB_DIR = ../../lib
INC_DIR = ../../include
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+inet_addr_list: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
- hex_quote_test cache_test
+ hex_quote_test ctable_test inet_addr_list_test
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
diff ctable.ref ctable.tmp
rm -f ctable.tmp
+inet_addr_list_test: inet_addr_list
+ ./inet_addr_list `cat inet_addr_list.in` >inet_addr_list.tmp 2>&1
+ diff inet_addr_list.ref inet_addr_list.tmp
+ rm -f inet_addr_list.tmp
+
DB_TYPE = `../postconf/postconf -h default_database_type`
dict_test: dict_open testdb dict_test.in dict_test.ref
/* INET_ADDR_LIST *list;
/* struct in_addr *addr;
/*
+/* void inet_addr_list_uniq(list)
+/* INET_ADDR_LIST *list;
+/*
/* void inet_addr_list_free(list)
/* INET_ADDR_LIST *list;
/* DESCRIPTION
/* inet_addr_list_append() appends the specified address to
/* the specified list, extending the list on the fly.
/*
+/* inet_addr_list_uniq() sorts the specified address list and
+/* eliminates duplicates.
+/*
/* inet_addr_list_free() reclaims memory used for the
/* specified address list.
/* LICENSE
#include <sys_defs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <stdlib.h>
/* Utility library. */
list->addrs[list->used++] = *addr;
}
+/* inet_addr_list_comp - compare addresses */
+
+static int inet_addr_list_comp(const void *a, const void *b)
+{
+ const struct in_addr *a_addr = (const struct in_addr *) a;
+ const struct in_addr *b_addr = (const struct in_addr *) b;
+
+ return (a_addr->s_addr - b_addr->s_addr);
+}
+
+/* inet_addr_list_uniq - weed out duplicates */
+
+void inet_addr_list_uniq(INET_ADDR_LIST *list)
+{
+ int n;
+ int m;
+
+ /*
+ * Put the identical members right next to each other.
+ */
+ qsort((void *) list->addrs, list->used,
+ sizeof(list->addrs[0]), inet_addr_list_comp);
+
+ /*
+ * Nuke the duplicates. Postcondition after while loop: m is the largest
+ * index for which list->addrs[n] == list->addrs[m].
+ */
+ for (m = n = 0; m < list->used; m++, n++) {
+ if (m != n)
+ list->addrs[n] = list->addrs[m];
+ while (m + 1 < list->used
+ && inet_addr_list_comp((void *) &(list->addrs[n]),
+ (void *) &(list->addrs[m + 1])) == 0)
+ m += 1;
+ }
+ list->used = n;
+}
+
/* inet_addr_list_free - destroy internet address list */
void inet_addr_list_free(INET_ADDR_LIST *list)
{
myfree((char *) list->addrs);
}
+
+#ifdef TEST
+
+ /*
+ * Duplicate elimination needs to be tested.
+ */
+#include <inet_addr_host.h>
+
+static void inet_addr_list_print(INET_ADDR_LIST *list)
+{
+ int n;
+
+ for (n = 0; n < list->used; n++)
+ msg_info("%s", inet_ntoa(list->addrs[n]));
+}
+
+int main(int argc, char **argv)
+{
+ INET_ADDR_LIST list;
+
+ inet_addr_list_init(&list);
+ while (--argc && *++argv)
+ if (inet_addr_host(&list, *argv) == 0)
+ msg_fatal("host not found: %s", *argv);
+ msg_info("list before sort/uniq");
+ inet_addr_list_print(&list);
+ inet_addr_list_uniq(&list);
+ msg_info("list after sort/uniq");
+ inet_addr_list_print(&list);
+ inet_addr_list_free(&list);
+ return (0);
+}
+
+#endif
extern void inet_addr_list_init(INET_ADDR_LIST *);
extern void inet_addr_list_free(INET_ADDR_LIST *);
+extern void inet_addr_list_uniq(INET_ADDR_LIST *);
extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *);
/* LICENSE
--- /dev/null
+168.100.189.2
+168.100.189.2
+168.100.189.1
+168.100.189.3
+168.100.189.3
+168.100.189.3
+168.100.189.4
+168.100.189.1
+168.100.189.4
--- /dev/null
+unknown: list before sort/uniq
+unknown: 168.100.189.2
+unknown: 168.100.189.2
+unknown: 168.100.189.1
+unknown: 168.100.189.3
+unknown: 168.100.189.3
+unknown: 168.100.189.3
+unknown: 168.100.189.4
+unknown: 168.100.189.1
+unknown: 168.100.189.4
+unknown: list after sort/uniq
+unknown: 168.100.189.1
+unknown: 168.100.189.2
+unknown: 168.100.189.3
+unknown: 168.100.189.4