in the makedefs script, to make future updates easier. File:
makedefs.
- Cleanup: don't log multiple Milter "hold" actions for
- the same message. File: cleanup/cleanup_milter.c.
+ Cleanup: don't log multiple Milter "hold" actions for the
+ same email message. File: cleanup/cleanup_milter.c.
+
+20080826
+
+ Cleanup: moving test programs from makedefs into a makedefs.d
+ directory brought more pain than gain.
+
+ Cleanup: untangled the Linux version dependent sections in
+ the makedefs script, to make future updates easier. File:
+ makedefs.
+
+ Documentation: MacOS process limit configuration by Quanah
+ Gibson-Mount. File: proto/TUNING_README.html.
+
+ Feature: smtp-sink -M option to terminate after receiving
+ a specified number of messages. Laurent Gentil. File:
+ smtpstone/smtp-sink.c.
+
+ Bugfix (introduced Postfix 2.4): epoll file descriptor leak.
+ With Postfix >= 2.4 on Linux >= 2.6, Postfix has an epoll
+ file descriptor leak when it executes non-Postfix commands
+ in, for example, user-controlled $HOME/.forward files. A
+ local user can access a leaked epoll file descriptor to
+ implement a denial of service attack on Postfix. Data
+ confidentiality and integrity are not affected. File:
+ util/events.c.
Other Postfix performance tuning topics:
* Tuning the number of Postfix processes
+ * Tuning the number of processes on the system
* Tuning the number of open files or sockets
The following tools can be used to measure mail system performance under
smtp inet n - - - 10 smtpd
. . .
+T\bTu\bun\bni\bin\bng\bg t\bth\bhe\be n\bnu\bum\bmb\bbe\ber\br o\bof\bf p\bpr\bro\boc\bce\bes\bss\bse\bes\bs o\bon\bn t\bth\bhe\be s\bsy\bys\bst\bte\bem\bm
+
+ * MacOS X will run out of process slots when you increase Postfix process
+ limits. The following works with OSX 10.4 and OSX 10.5.
+
+ MacOS X kernel parameters can be specified in /etc/sysctl.conf.
+
+ /etc/sysctl.conf:
+ kern.maxproc=2048
+ kern.maxprocperuid=2048
+
+ Unfortunately these can't simply be set on the fly with "sysctl -w". You
+ also have to set the following in /etc/launchd.conf so that the root user
+ after boot will have the right process limit (2048). Otherwise you have to
+ always run ulimit -u 2048 as root, then start a user shell, and then start
+ processes for things to take effect.
+
+ /etc/launchd.conf:
+ limit maxproc 2048
+
+ Once these are in place, reboot the system. After that, the limits will
+ stay in place.
+
T\bTu\bun\bni\bin\bng\bg t\bth\bhe\be n\bnu\bum\bmb\bbe\ber\br o\bof\bf o\bop\bpe\ben\bn f\bfi\bil\ble\bes\bs o\bor\br s\bso\boc\bck\bke\bet\bts\bs
When Postfix opens too many files or sockets, processes will abort with fatal
Wish list:
-
+
Force a panic when the VDA patch reduces the file size limit
under the message size. They break the code that marks a
recipient as "done", when that recipient was added late
<li> <a href="#proc_limit">Tuning the number of Postfix processes</a>
+<li> <a href="#proc_sys">Tuning the number of processes on the system</a>
+
<li> <a href="#file_limit">Tuning the number of open files or
sockets</a>
</pre>
</blockquote>
+<h2><a name="proc_sys">Tuning the number of processes on the system</a></h2>
+
+<ul>
+
+<li> <p> MacOS X will run out of process slots when you increase
+Postfix process limits. The following works with OSX 10.4 and OSX
+10.5. </p>
+
+<p> MacOS X kernel parameters can be specified in /etc/sysctl.conf.
+</p>
+
+<pre>
+/etc/sysctl.conf:
+ kern.maxproc=2048
+ kern.maxprocperuid=2048
+</pre>
+
+<p> Unfortunately these can't simply be set on the fly with "sysctl
+-w". You also have to set the following in /etc/launchd.conf so
+that the root user after boot will have the right process limit
+(2048). Otherwise you have to always run ulimit -u 2048 as root,
+then start a user shell, and then start processes for things to
+take effect. </p>
+
+<pre>
+/etc/launchd.conf:
+ limit maxproc 2048
+</pre>
+
+<p> Once these are in place, reboot the system. After that, the limits will
+stay in place. </p>
+
+</ul>
+
<h2><a name="file_limit">Tuning the number of open files or sockets</a></h2>
<p> When Postfix opens too many files or sockets, processes will
destinations via <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a>. </dd>
<dt><b>may</b></dt>
-<dd> Opportunistic TLS. TLS will be used if supported by the server. Since
+<dd> Opportunistic TLS. Use TLS if this is supported by the remote
+SMTP server, otherwise use plaintext. Since
sending in the clear is acceptable, demanding stronger than default TLS
security parameters merely reduces inter-operability. Postfix 2.3 and
later ignore the <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> and
implementations. </dd>
<dt><b>encrypt</b></dt> <dd>Mandatory TLS encryption. Since a minimum
-level of security is intended, it reasonable to be specific about
+level of security is intended, it is reasonable to be specific about
sufficiently secure protocol versions and ciphers. At this security level
and higher, the <a href="postconf.5.html">main.cf</a> parameters <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> and
<a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> specify the TLS protocols and minimum
# Do not build with IPv6 support.
# By default, IPv6 support is compiled in on platforms that
# are known to have IPv6 support.
+#
+# Note: this directive is for debugging and testing only. It
+# is not guaranteed to work on all platforms.
# .IP \fB-DNO_KQUEUE\fR
# Do not build with FreeBSD/NetBSD/OpenBSD/MacOSX KQUEUE support.
# By default, KQUEUE support is compiled in on platforms that
exit 1
}
-SYSTEM=`(uname -s) 2>/dev/null`
-RELEASE=`(uname -r) 2>/dev/null`
-VERSION=`(uname -v) 2>/dev/null`
-
-case "$VERSION" in
- dcosx*) SYSTEM=$VERSION;;
+case $# in
+ # Officially supported usage.
+ 0) SYSTEM=`(uname -s) 2>/dev/null`
+ RELEASE=`(uname -r) 2>/dev/null`
+ VERSION=`(uname -v) 2>/dev/null`
+ case "$VERSION" in
+ dcosx*) SYSTEM=$VERSION;;
+ esac;;
+ # Unsupported debug-only mode. Not suitable for cross-platform tests.
+ 2) SYSTEM="$1"; RELEASE="$2";;
+ *) echo usage: $0 [system release] 1>&2; exit 1;;
esac
case "$SYSTEM.$RELEASE" in
# Work around broken str*casecmp(). Do it all here instead
# of having half the solution in the sys_defs.h file.
CCARGS="$CCARGS -Dstrcasecmp=fix_strcasecmp \
- -Dstrncasecmp=fix_strncasecmp"
+ -Dstrncasecmp=fix_strncasecmp"
STRCASE="strcasecmp.o"
# Avoid common types of braindamage
case "$LD_LIBRARY_PATH" in
case "$RELEASE" in
2.[0-5].*) CCARGS="$CCARGS -DNO_EPOLL";;
# Workaround for retarded libc
- 2.6.*) trap 'rm -f linux_epoll linux_epoll.o' 1 2 3 15
- ${CC-gcc} -o linux_epoll makedefs.d/linux_epoll.c || exit 1
- ./linux_epoll 2>/dev/null ||
+ 2.6.*) trap 'rm -f makedefs.test makedefs.test.[co]' 1 2 3 15
+ cat >makedefs.test.c <<'EOF'
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ int epoll_handle;
+
+ if ((epoll_handle = epoll_create(1)) < 0) {
+ perror("epoll_create");
+ exit(1);
+ }
+ exit(0);
+}
+EOF
+ ${CC-gcc} -o makedefs.test makedefs.test.c || exit 1
+ ./makedefs.test 2>/dev/null ||
CCARGS="$CCARGS -DNO_EPOLL"
- rm -f linux_epoll linux_epoll.o;;
+ rm -f makedefs.test makedefs.test.[co];;
esac
;;
GNU.0*|GNU/kFreeBSD.[567]*)
: ${CC=cc}
# Darwin > 1.3 uses awk and flat_namespace
case $RELEASE in
- 1.[0-3]) AWK=gawk
- ;;
+ 1.[0-3]) AWK=gawk;;
*) AWK=awk
- SYSLIBS=-flat_namespace
- ;;
+ SYSLIBS=-flat_namespace;;
esac
# Darwin 7 adds IPv6 support, BIND_8_COMPAT, NO_NETINFO
case $RELEASE in
- [1-6].*) CCARGS="$CCARGS -DNO_IPV6"
- ;;
- *) CCARGS="$CCARGS -DBIND_8_COMPAT -DNO_NETINFO"
- ;;
+ [1-6].*) CCARGS="$CCARGS -DNO_IPV6";;
+ *) CCARGS="$CCARGS -DBIND_8_COMPAT -DNO_NETINFO";;
esac
# Darwin 8.11.1 has kqueue support, but let's play safe
case $RELEASE in
- [1-8].*) CCARGS="$CCARGS -DNO_KQUEUE"
- ;;
- *) trap 'rm -f macosx_kqueue macosx_kqueue.o' 1 2 3 15
- ${CC-gcc} -o macosx_kqueue makedefs.d/macosx_kqueue.c || exit 1
- ./macosx_kqueue 2>/dev/null ||
+ [1-8].*) CCARGS="$CCARGS -DNO_KQUEUE";;
+ *) trap 'rm -f makedefs.test makedefs.test.[co]' 1 2 3 15
+ cat >makedefs.test.c <<'EOF'
+/* Adapted from libevent. */
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef EV_SET
+#define EV_SET(kp, id, fi, fl, ffl, da, ud) do { \
+ struct kevent *__kp = (kp); \
+ __kp->ident = (id); \
+ __kp->filter = (fi); \
+ __kp->flags = (fl); \
+ __kp->fflags = (ffl); \
+ __kp->data = (da); \
+ __kp->udata = (ud); \
+ } while(0)
+#endif
+
+int main(int argc, char **argv)
+{
+ int kq;
+ struct kevent test_change;
+ struct kevent test_result;
+
+ if ((kq = kqueue()) < 0) {
+ perror("kqueue");
+ exit(1);
+ }
+#define TEST_FD (-1)
+
+ EV_SET(&test_change, TEST_FD, EVFILT_READ, EV_ADD, 0, 0, 0);
+ if (kevent(kq,
+ &test_change, sizeof(test_change) / sizeof(struct kevent),
+ &test_result, sizeof(test_result) / sizeof(struct kevent),
+ (struct timespec *) 0) != 1 ||
+ test_result.ident != TEST_FD ||
+ test_result.flags != EV_ERROR) {
+ fprintf(stderr, "Error: kevent reports errors incorrectly\n");
+ exit(1);
+ }
+ exit(0);
+}
+EOF
+ $CC -o makedefs.test makedefs.test.c || exit 1
+ ./makedefs.test 2>/dev/null ||
CCARGS="$CCARGS -DNO_KQUEUE"
- rm -f macosx_kqueue macosx_kqueue.o
- ;;
+ rm -f makedefs.test makedefs.test.[co];;
esac
;;
Rhapsody.5*|"Mac OS".10*)
#
case "$CCARGS" in
*-DNO_SIGSETJMP*) ;;
- *) trap 'rm -f sigsetjmp sigsetjmp.o' 1 2 3 15
- ${CC-gcc} -o sigsetjmp makedefs.d/sigsetjmp.c || exit 1
- ./sigsetjmp 2>/dev/null || CCARGS="$CCARGS -DNO_SIGSETJMP"
- rm -f sigsetjmp sigsetjmp.o;;
+ *) trap 'rm -f makedefs.test makedefs.test.[co]' 1 2 3 15
+ cat >makedefs.test.c <<'EOF'
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int count = 0;
+
+int main(int argc, char **argv)
+{
+ sigjmp_buf env;
+ int retval;
+
+ switch (retval = sigsetjmp(env, 1)) {
+ case 0:
+ siglongjmp(env, 12345);
+ case 12345:
+ break;
+ default:
+ fprintf(stderr, "Error: siglongjmp ignores second argument\n");
+ exit(1);
+ }
+
+ switch (retval = sigsetjmp(env, 1)) {
+ case 0:
+ if (count++ > 0) {
+ fprintf(stderr, "Error: not overriding siglongjmp(env, 0)\n");
+ exit(1);
+ }
+ siglongjmp(env, 0);
+ case 1:
+ break;
+ default:
+ fprintf(stderr, "Error: overriding siglongjmp(env, 0) with %d\n",
+ retval);
+ exit(1);
+ }
+ exit(0);
+}
+EOF
+ ${CC-gcc} -o makedefs.test makedefs.test.c || exit 1
+ ./makedefs.test 2>/dev/null ||
+ CCARGS="$CCARGS -DNO_SIGSETJMP"
+ rm -f makedefs.test makedefs.test.[co]
esac
#
+++ /dev/null
-#include <sys/types.h>
-#include <sys/epoll.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv)
-{
- int epoll_handle;
-
- if ((epoll_handle = epoll_create(1)) < 0) {
- perror("epoll_create");
- exit(1);
- }
- exit(0);
-}
+++ /dev/null
-/* Adapted from libevent. */
-
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifndef EV_SET
-#define EV_SET(kp, id, fi, fl, ffl, da, ud) do { \
- struct kevent *__kp = (kp); \
- __kp->ident = (id); \
- __kp->filter = (fi); \
- __kp->flags = (fl); \
- __kp->fflags = (ffl); \
- __kp->data = (da); \
- __kp->udata = (ud); \
- } while(0)
-#endif
-
-int main(int argc, char **argv)
-{
- int kq;
- struct kevent test_change;
- struct kevent test_result;
-
- if ((kq = kqueue()) < 0) {
- perror("kqueue");
- exit(1);
- }
-#define TEST_FD (-1)
-
- EV_SET(&test_change, TEST_FD, EVFILT_READ, EV_ADD, 0, 0, 0);
- if (kevent(kq,
- &test_change, sizeof(test_change) / sizeof(struct kevent),
- &test_result, sizeof(test_result) / sizeof(struct kevent),
- (struct timespec *) 0) != 1 ||
- test_result.ident != TEST_FD ||
- test_result.flags != EV_ERROR) {
- fprintf(stderr, "kqueue is broken\n");
- exit(1);
- }
- exit(0);
-}
+++ /dev/null
-#include <setjmp.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-static int count = 0;
-
-int main(int argc, char **argv)
-{
- sigjmp_buf env;
- int retval;
-
- switch (retval = sigsetjmp(env, 1)) {
- case 0:
- siglongjmp(env, 12345);
- case 12345:
- break;
- default:
- fprintf(stderr, "Error: siglongjmp ignores second argument\n");
- exit(1);
- }
-
- switch (retval = sigsetjmp(env, 1)) {
- case 0:
- if (count++ > 0) {
- fprintf(stderr, "Error: not overriding siglongjmp(env, 0)\n");
- exit(1);
- }
- siglongjmp(env, 0);
- case 1:
- break;
- default:
- fprintf(stderr, "Error: overriding siglongjmp(env, 0) with %d\n",
- retval);
- exit(1);
- }
- exit(0);
-}
TLS will not be used unless enabled for specific
destinations via smtp_tls_policy_maps.
.IP "\fBmay\fR"
-Opportunistic TLS. TLS will be used if supported by the server. Since
+Opportunistic TLS. Use TLS if this is supported by the remote
+SMTP server, otherwise use plaintext. Since
sending in the clear is acceptable, demanding stronger than default TLS
security parameters merely reduces inter-operability. Postfix 2.3 and
later ignore the smtp_tls_mandatory_ciphers and
implementations.
.IP "\fBencrypt\fR"
Mandatory TLS encryption. Since a minimum
-level of security is intended, it reasonable to be specific about
+level of security is intended, it is reasonable to be specific about
sufficiently secure protocol versions and ciphers. At this security level
and higher, the main.cf parameters smtp_tls_mandatory_protocols and
smtp_tls_mandatory_ciphers specify the TLS protocols and minimum
<li> <a href="#proc_limit">Tuning the number of Postfix processes</a>
+<li> <a href="#proc_sys">Tuning the number of processes on the system</a>
+
<li> <a href="#file_limit">Tuning the number of open files or
sockets</a>
</pre>
</blockquote>
+<h2><a name="proc_sys">Tuning the number of processes on the system</a></h2>
+
+<ul>
+
+<li> <p> MacOS X will run out of process slots when you increase
+Postfix process limits. The following works with OSX 10.4 and OSX
+10.5. </p>
+
+<p> MacOS X kernel parameters can be specified in /etc/sysctl.conf.
+</p>
+
+<pre>
+/etc/sysctl.conf:
+ kern.maxproc=2048
+ kern.maxprocperuid=2048
+</pre>
+
+<p> Unfortunately these can't simply be set on the fly with "sysctl
+-w". You also have to set the following in /etc/launchd.conf so
+that the root user after boot will have the right process limit
+(2048). Otherwise you have to always run ulimit -u 2048 as root,
+then start a user shell, and then start processes for things to
+take effect. </p>
+
+<pre>
+/etc/launchd.conf:
+ limit maxproc 2048
+</pre>
+
+<p> Once these are in place, reboot the system. After that, the limits will
+stay in place. </p>
+
+</ul>
+
<h2><a name="file_limit">Tuning the number of open files or sockets</a></h2>
<p> When Postfix opens too many files or sockets, processes will
destinations via smtp_tls_policy_maps. </dd>
<dt><b>may</b></dt>
-<dd> Opportunistic TLS. TLS will be used if supported by the server. Since
+<dd> Opportunistic TLS. Use TLS if this is supported by the remote
+SMTP server, otherwise use plaintext. Since
sending in the clear is acceptable, demanding stronger than default TLS
security parameters merely reduces inter-operability. Postfix 2.3 and
later ignore the smtp_tls_mandatory_ciphers and
implementations. </dd>
<dt><b>encrypt</b></dt> <dd>Mandatory TLS encryption. Since a minimum
-level of security is intended, it reasonable to be specific about
+level of security is intended, it is reasonable to be specific about
sufficiently secure protocol versions and ciphers. At this security level
and higher, the main.cf parameters smtp_tls_mandatory_protocols and
smtp_tls_mandatory_ciphers specify the TLS protocols and minimum
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20080824"
+#define MAIL_RELEASE_DATE "20080902"
#define MAIL_VERSION_NUMBER "2.6"
#ifdef SNAPSHOT
/*
/* The functions that inspect content or envelope commands
/* return either an SMTP reply ([45]XX followed by enhanced
-/* status code and text), "D" (discard), "H" (quarantine), or
-/* a null pointer, which means "no news is good news".
+/* status code and text), "D" (discard), "H" (quarantine),
+/* "S" (shutdown connection), or a null pointer, which means
+/* "no news is good news".
/*
/* milter_create() instantiates the milter clients specified
/* with the milter_names argument. The conn_macros etc.
* AAAA record makes no sense here. Just like with IPv4 we use the lookup
* result as a bit mask, not as an IP address.
*/
-#ifdef PF_INET6
+#ifdef HAS_IPV6
if (valid_ipv6_hostaddr(addr, DONT_GRIPE)) {
if (hostaddr_to_sockaddr(addr, (char *) 0, 0, &res) != 0
|| res->ai_family != PF_INET6)
/* connections that \fBsmtp-sink\fR will handle. This prevents
/* the process from running out of file descriptors. Excess
/* connections will stay queued in the TCP/IP stack.
+/* .IP "\fB-M \fIcount\fR"
+/* Terminate after receiving \fIcount\fR messages.
/* .IP "\fB-n \fIcount\fR"
-/* Terminate after \fIcount\fR sessions. This is for testing purposes.
+/* Terminate after \fIcount\fR sessions.
/* .IP \fB-p\fR
/* Do not announce support for ESMTP command pipelining.
/* .IP \fB-P\fR
static int quit_count;
static int mesg_count;
static int max_quit_count;
+static int max_msg_quit_count;
static int disable_pipelining;
static int disable_8bitmime;
static int disable_esmtp;
if (state->dump_file)
mail_file_finish(state);
mail_cmd_reset(state);
- if (count) {
+ if (count || max_msg_quit_count > 0) {
mesg_count++;
- do_stats();
+ if (count)
+ do_stats();
+ if (max_msg_quit_count > 0 && mesg_count >= max_msg_quit_count)
+ exit(0);
}
break;
}
static void usage(char *myname)
{
- msg_fatal("usage: %s [-468acCeEFLpPv] [-A abort_delay] [-f commands] [-h hostname] [-m max_concurrency] [-n quit_count] [-q commands] [-r commands] [-s commands] [-w delay] [-d dump-template] [-D dump-template] [-R root-dir] [-S start-string] [-u user_privs] [host]:port backlog", myname);
+ msg_fatal("usage: %s [-468acCeEFLpPv] [-A abort_delay] [-d dump-template] [-D dump-template] [-f commands] [-h hostname] [-m max_concurrency] [M message_quit_count] [-n quit_count] [-q commands] [-r commands] [-R root-dir] [-s commands] [-S start-string] [-u user_privs] [-w delay] [host]:port backlog", myname);
}
MAIL_VERSION_STAMP_DECLARE;
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "468aA:cCd:D:eEf:Fh:Ln:m:pPq:Q:r:R:s:S:t:u:vw:W:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "468aA:cCd:D:eEf:Fh:Ln:m:M:pPq:Q:r:R:s:S:t:u:vw:W:")) > 0) {
switch (ch) {
case '4':
protocols = INET_PROTO_NAME_IPV4;
if ((max_client_count = atoi(optarg)) <= 0)
msg_fatal("bad concurrency limit: %s", optarg);
break;
+ case 'M':
+ if ((max_msg_quit_count = atoi(optarg)) <= 0)
+ msg_fatal("bad message quit count: %s", optarg);
+ break;
case 'n':
if ((max_quit_count = atoi(optarg)) <= 0)
msg_fatal("bad quit count: %s", optarg);
#define EVENT_REG_INIT_HANDLE(er, n) do { \
er = event_pollfd = open("/dev/poll", O_RDWR); \
+ if (event_pollfd >= 0) close_on_exec(event_pollfd, CLOSE_ON_EXEC); \
} while (0)
#define EVENT_REG_INIT_TEXT "open /dev/poll"
#define EVENT_REG_INIT_HANDLE(er, n) do { \
er = event_epollfd = epoll_create(n); \
+ if (event_epollfd >= 0) close_on_exec(event_epollfd, CLOSE_ON_EXEC); \
} while (0)
#define EVENT_REG_INIT_TEXT "epoll_create"