From 370fdfce00b1582af42d8716ccf56fbef1b4bec4 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sun, 27 Dec 2015 00:00:00 -0500 Subject: [PATCH] postfix-3.1-20151227 --- postfix/.indent.pro | 1 + postfix/HISTORY | 29 +++++ postfix/RELEASE_NOTES | 17 +++ postfix/WISHLIST | 22 ++-- postfix/conf/post-install | 2 + postfix/html/oqmgr.8.html | 18 ++- postfix/html/postconf.5.html | 17 +++ postfix/html/postlog.1.html | 8 +- postfix/html/qmgr.8.html | 18 ++- postfix/man/man1/postlog.1 | 9 +- postfix/man/man5/postconf.5 | 11 ++ postfix/man/man8/oqmgr.8 | 5 + postfix/man/man8/qmgr.8 | 5 + postfix/mantools/postlink | 1 + postfix/postfix-install | 15 +-- postfix/proto/postconf.proto | 13 +++ postfix/src/cleanup/Makefile.in | 4 + postfix/src/cleanup/cleanup.h | 1 + postfix/src/cleanup/cleanup_envelope.c | 11 ++ postfix/src/cleanup/cleanup_out_recipient.c | 32 ++++++ postfix/src/cleanup/cleanup_state.c | 1 + postfix/src/global/mail_params.c | 15 +++ postfix/src/global/mail_params.h | 4 + postfix/src/global/mail_version.h | 2 +- postfix/src/global/post_mail.c | 118 ++++++++++++++++++++ postfix/src/global/post_mail.h | 4 +- postfix/src/global/verify.c | 3 +- postfix/src/oqmgr/qmgr.c | 7 ++ postfix/src/oqmgr/qmgr.h | 1 + postfix/src/oqmgr/qmgr_message.c | 33 +++++- postfix/src/postlog/postlog.c | 15 ++- postfix/src/qmgr/qmgr.c | 7 ++ postfix/src/qmgr/qmgr.h | 1 + postfix/src/qmgr/qmgr_message.c | 33 +++++- postfix/src/verify/verify.c | 16 ++- 35 files changed, 442 insertions(+), 57 deletions(-) diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 0e9462f19..5502f64db 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -249,6 +249,7 @@ -TPLMYSQL -TPLPGSQL -TPOSTMAP_KEY_STATE +-TPOST_MAIL_FCLOSE_STATE -TPOST_MAIL_STATE -TPRIVATE_STR_TABLE -TPSC_CALL_BACK_ENTRY diff --git a/postfix/HISTORY b/postfix/HISTORY index 975fbec70..47bb88bfc 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -22030,3 +22030,32 @@ Apologies for any names omitted. Bugfix (introduced: 20151128) bogus queue file parsing error. File: showq/showq.c. + +20151226 + + Cleanup: postlog(1) now pauses for 1s after reporting a + fatal or panic error. This makes behavior of scripts such + as postfix-script consistent with built-in error messages. + File: postlog/postlog.c. + +20151227 + + Robustness: don't allow for whitespace in command-line + arguments. Files; postfix-install, conf/post-install. + + Robustness: added a comment to discourage people who keep + adding code that calls gethostbyname() to determine the + default myhostname setting. This is a mistake: all Postfix + programs will hang when the DNS is unavailable. File: + global/mail_params.c. + + Safety: a limit on the number of address verification probes + in the active queue (address_verify_pending_request_limit), + by default 1/4 of the active queue maximum size. The queue + manager tempfails probe messages that exceed the limit. + Files: mantools/postlink, proto/postconf.proto, cleanup/cleanup.h, + cleanup/cleanup_envelope.c, cleanup/cleanup_out_recipient.c, + cleanup/cleanup_state.c, global/mail_params.h, global/post_mail.c, + global/post_mail.h, global/verify.c, oqmgr/qmgr.c, oqmgr/qmgr.h, + oqmgr/qmgr_message.c, qmgr/qmgr.c, qmgr/qmgr.h, + qmgr/qmgr_message.c, verify/verify.c. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 0b51dee8d..08f899c4b 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -16,6 +16,23 @@ specifies the release date of a stable release or snapshot release. If you upgrade from Postfix 2.11 or earlier, read RELEASE_NOTES-3.0 before proceeding. + +Major changes with snaphot 20151227 +=================================== + +This introduces a safety limit on the number of address verification +probes in the active queue (address_verify_pending_request_limit), +by default 1/4 of the active queue maximum size. The queue manager +enforces the limit by tempfailing probe messages that exceed the +limit. The design avoids dependency on global counters that may get +out of sync after a process crashes. + +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. The address_verify_pending_request_limit +affects only unknown addresses and inactive addresses that have +expired (by default, after 31 days). + Incompatible change with Postfix snapshot 20150721 -------------------------------------------------- diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 4f2ec862f..f85ae3197 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -2,6 +2,12 @@ Wish list: Things to do before the stable release: + Viktor's bitrot patches. + + Not: SMTPUTF8 auto-conversion of lookups/matches. + + ---------------------end of Postfix 3.1.0 todo list + Spell-check, double-word check, and HTML validator check. Disable -DSNAPSHOT and -DNONPROD in makedefs. @@ -17,7 +23,8 @@ Wish list: smtp_reply_footer() undoable. Type-checking wrappers for htable(3), ctable(3) and other - modules that take and return a void* pointer. + modules that take and return a void* pointer. This is + the next best thing to C++ style HTABLE. TLS certificate provenance: indicate whether a subject name/issuer are verified or not (for example, change the @@ -76,9 +83,8 @@ Wish list: Log command=good/bad statistics in postscreen? - Implement smtpd_client_auth_rate limit? - - Make the access map BCC action consistent with header_checks. + Remember multiple access map BCC actions, for consistency + with header_checks. smtpd_checks tests either must use a DNS dummy resolver (override the res_search API) or all names must be under @@ -93,11 +99,6 @@ Wish list: along with other header-extracted information, and forward the Message-ID in the bounce server notification request. - Find a way to show non-default OPT, DEBUG etc. settings at - the top of the makedefs.out file. - - Update smtputf8_enable in postconf(5) - Clobber ORCPT when sender is owner-mumble? Add milter_mumble_macros to the list of per-macro features. @@ -114,9 +115,6 @@ Wish list: can return error descriptions instead of terminating with a fatal error. - Make sure that proxy: can handle random:, pipe:, and other - multimaps. - Add a switch to consider postscreen deep protocol tests as "completed" when receiving "RSET" after "RCPT TO" and the session has passed all tests up to that point. RSET becomes diff --git a/postfix/conf/post-install b/postfix/conf/post-install index d5db2600e..904cefa58 100644 --- a/postfix/conf/post-install +++ b/postfix/conf/post-install @@ -234,6 +234,8 @@ obsolete=; keep_list=; for arg do case $arg in + *[" "]*) echo $0: "Error: argument contains whitespace: '$arg'" + exit 1;; *=*) IFS= eval $arg; IFS="$BACKUP_IFS";; create-missing) create=1;; set-perm*) create=1; set_perms=1;; diff --git a/postfix/html/oqmgr.8.html b/postfix/html/oqmgr.8.html index d97ffc8d2..d952c0c7c 100644 --- a/postfix/html/oqmgr.8.html +++ b/postfix/html/oqmgr.8.html @@ -314,9 +314,15 @@ OQMGR(8) OQMGR(8) The time limit for the queue manager to send or receive informa- tion over an internal communication channel. + Available in Postfix version 3.1 and later: + + address_verify_pending_request_limit (see 'postconf -d' output) + A safety limit that prevents address verification requests from + overwhelming the Postfix queue. + MISCELLANEOUS CONTROLS config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and master.cf con- + The default location of the Postfix main.cf and master.cf con- figuration files. defer_transports (empty) @@ -324,11 +330,11 @@ OQMGR(8) OQMGR(8) mail unless someone issues "sendmail -q" or equivalent. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal point when log- + The maximal number of digits after the decimal point when log- ging sub-second delay values. helpful_warnings (yes) - Log warnings about problematic configuration settings, and pro- + Log warnings about problematic configuration settings, and pro- vide helpful suggestions. process_id (read-only) @@ -344,14 +350,14 @@ OQMGR(8) OQMGR(8) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - The mail system name that is prepended to the process name in - syslog records, so that "smtpd" becomes, for example, "post- + The mail system name that is prepended to the process name in + syslog records, so that "smtpd" becomes, for example, "post- fix/smtpd". Available in Postfix version 3.0 and later: confirm_delay_cleared (no) - After sending a "your message is delayed" notification, inform + After sending a "your message is delayed" notification, inform the sender when the delay clears up. FILES diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 67edf42b6..0cab4cfd1 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -294,6 +294,23 @@ This feature is available in Postfix 2.1 and later.

+ + +
address_verify_pending_request_limit +(default: see "postconf -d" output)
+ +

A safety limit that prevents address verification requests from +overwhelming the Postfix queue. By default, the number of pending +requests is limited to 1/4 of the active queue maximum size +(qmgr_message_active_limit). The queue manager enforces the limit +by tempfailing requests that exceed the limit. This affects only +unknown addresses and inactive addresses that have expired, because +the verify(8) daemon automatically refreshes an active address +before it expires.

+ +

This feature is available in Postfix 3.1 and later.

+ +
address_verify_poll_count diff --git a/postfix/html/postlog.1.html b/postfix/html/postlog.1.html index 3ecbcbc08..514e7f305 100644 --- a/postfix/html/postlog.1.html +++ b/postfix/html/postlog.1.html @@ -31,9 +31,11 @@ POSTLOG(1) POSTLOG(1) -i Include the process ID in the logging tag. - -p priority - Specifies the logging severity: info (default), warn, error, - fatal, or panic. + -p priority (default: info) + Specifies the logging severity: info, warn, error, fatal, or + panic. With Postfix 3.1 and later, the program will pause for 1 + second after reporting a fatal or panic condition, just like + other Postfix programs. -t tag Specifies the logging tag, that is, the identifying name that appears at the beginning of each logging record. A default tag diff --git a/postfix/html/qmgr.8.html b/postfix/html/qmgr.8.html index 7f2225d4c..a919a173d 100644 --- a/postfix/html/qmgr.8.html +++ b/postfix/html/qmgr.8.html @@ -376,9 +376,15 @@ QMGR(8) QMGR(8) The time limit for the queue manager to send or receive informa- tion over an internal communication channel. + Available in Postfix version 3.1 and later: + + address_verify_pending_request_limit (see 'postconf -d' output) + A safety limit that prevents address verification requests from + overwhelming the Postfix queue. + MISCELLANEOUS CONTROLS config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and master.cf con- + The default location of the Postfix main.cf and master.cf con- figuration files. defer_transports (empty) @@ -386,11 +392,11 @@ QMGR(8) QMGR(8) mail unless someone issues "sendmail -q" or equivalent. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal point when log- + The maximal number of digits after the decimal point when log- ging sub-second delay values. helpful_warnings (yes) - Log warnings about problematic configuration settings, and pro- + Log warnings about problematic configuration settings, and pro- vide helpful suggestions. process_id (read-only) @@ -406,14 +412,14 @@ QMGR(8) QMGR(8) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - The mail system name that is prepended to the process name in - syslog records, so that "smtpd" becomes, for example, "post- + The mail system name that is prepended to the process name in + syslog records, so that "smtpd" becomes, for example, "post- fix/smtpd". Available in Postfix version 3.0 and later: confirm_delay_cleared (no) - After sending a "your message is delayed" notification, inform + After sending a "your message is delayed" notification, inform the sender when the delay clears up. FILES diff --git a/postfix/man/man1/postlog.1 b/postfix/man/man1/postlog.1 index b1fc21822..8aa798b54 100644 --- a/postfix/man/man1/postlog.1 +++ b/postfix/man/man1/postlog.1 @@ -32,9 +32,12 @@ Read the \fBmain.cf\fR configuration file in the named directory instead of the default configuration directory. .IP \fB\-i\fR Include the process ID in the logging tag. -.IP "\fB\-p \fIpriority\fR" -Specifies the logging severity: \fBinfo\fR (default), \fBwarn\fR, -\fBerror\fR, \fBfatal\fR, or \fBpanic\fR. +.IP "\fB\-p \fIpriority\fR (default: \fBinfo\fR)" +Specifies the logging severity: \fBinfo\fR, \fBwarn\fR, +\fBerror\fR, \fBfatal\fR, or \fBpanic\fR. With Postfix 3.1 +and later, the program will pause for 1 second after reporting +a \fBfatal\fR or \fBpanic\fR condition, just like other +Postfix programs. .IP "\fB\-t \fItag\fR" Specifies the logging tag, that is, the identifying name that appears at the beginning of each logging record. A default tag diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 24cdf21e0..273a6164f 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -177,6 +177,17 @@ be refreshed. Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks). .PP This feature is available in Postfix 2.1 and later. +.SH address_verify_pending_request_limit (default: see "postconf \-d" output) +A safety limit that prevents address verification requests from +overwhelming the Postfix queue. By default, the number of pending +requests is limited to 1/4 of the active queue maximum size +(qmgr_message_active_limit). The queue manager enforces the limit +by tempfailing requests that exceed the limit. This affects only +unknown addresses and inactive addresses that have expired, because +the \fBverify\fR(8) daemon automatically refreshes an active address +before it expires. +.PP +This feature is available in Postfix 3.1 and later. .SH address_verify_poll_count (default: normal: 3, overload: 1) How many times to query the \fBverify\fR(8) service for the completion of an address verification request in progress. diff --git a/postfix/man/man8/oqmgr.8 b/postfix/man/man8/oqmgr.8 index 46514085a..54a01f060 100644 --- a/postfix/man/man8/oqmgr.8 +++ b/postfix/man/man8/oqmgr.8 @@ -308,6 +308,11 @@ a request before it is terminated by a built\-in watchdog timer. .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 3.1 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. .SH "MISCELLANEOUS CONTROLS" .na .nf diff --git a/postfix/man/man8/qmgr.8 b/postfix/man/man8/qmgr.8 index 400f789c5..de116a043 100644 --- a/postfix/man/man8/qmgr.8 +++ b/postfix/man/man8/qmgr.8 @@ -356,6 +356,11 @@ a request before it is terminated by a built\-in watchdog timer. .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 3.1 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. .SH "MISCELLANEOUS CONTROLS" .na .nf diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 82ec6bece..2d1ab0736 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -89,6 +89,7 @@ while (<>) { s;\baddress_verify_service_name\b;$&;g; s;\baddress_verify_transport_maps\b;$&;g; s;\baddress_verify_virtual_transport\b;$&;g; + s;\baddress_verify_pending_request_limit\b;$&;g; s;\bsmtp_address_verify_target\b;$&;g; s;\blmtp_address_verify_target\b;$&;g; s;\balias_database\b;$&;g; diff --git a/postfix/postfix-install b/postfix/postfix-install index 01d17b485..b80069093 100644 --- a/postfix/postfix-install +++ b/postfix/postfix-install @@ -216,10 +216,11 @@ USAGE="Usage: $0 [name=value] [option] for arg do case $arg in - *=*) IFS= eval $arg; IFS="$BACKUP_IFS";; --non-int*) non_interactive=1;; - -package) need_install_root=install_root;; - *) echo "$0: Error: $USAGE" 1>&2; exit 1;; +*[" "]*) echo "$0: Error: argument contains whitespace: '$arg'"; exit 1;; + *=*) IFS= eval $arg; IFS="$BACKUP_IFS";; + -non-int*) non_interactive=1;; + -package) need_install_root=install_root;; + *) echo "$0: Error: $USAGE" 1>&2; exit 1;; esac shift done @@ -597,14 +598,14 @@ do esac done -# Don't allow whitespace in parameter settings. +# Don't allow space or tab in parameter settings. for name in $CONFIG_PARAMS sample_directory do eval junk=\$$name case "$junk" in -*" "*|*" "*) echo $0: Error: $name value contains whitespace: "'$junk'" 1>&2 - exit 1;; +*"[ ]"*) echo "$0: Error: $name value contains whitespace: '$junk'" 1>&2 + exit 1;; esac done diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 7097015fd..33cf62923 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -16592,3 +16592,16 @@ clients).

This feature is available in Postfix 3.1 and later.

+ +%PARAM address_verify_pending_request_limit see "postconf -d" output + +

A safety limit that prevents address verification requests from +overwhelming the Postfix queue. By default, the number of pending +requests is limited to 1/4 of the active queue maximum size +(qmgr_message_active_limit). The queue manager enforces the limit +by tempfailing requests that exceed the limit. This affects only +unknown addresses and inactive addresses that have expired, because +the verify(8) daemon automatically refreshes an active address +before it expires.

+ +

This feature is available in Postfix 3.1 and later.

diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index ad479d09c..e44418862 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -760,7 +760,9 @@ cleanup_envelope.o: ../../include/attr.h cleanup_envelope.o: ../../include/been_here.h cleanup_envelope.o: ../../include/check_arg.h cleanup_envelope.o: ../../include/cleanup_user.h +cleanup_envelope.o: ../../include/deliver_request.h cleanup_envelope.o: ../../include/dict.h +cleanup_envelope.o: ../../include/dsn.h cleanup_envelope.o: ../../include/dsn_mask.h cleanup_envelope.o: ../../include/header_body_checks.h cleanup_envelope.o: ../../include/header_opts.h @@ -775,6 +777,7 @@ cleanup_envelope.o: ../../include/match_list.h cleanup_envelope.o: ../../include/milter.h cleanup_envelope.o: ../../include/mime_state.h cleanup_envelope.o: ../../include/msg.h +cleanup_envelope.o: ../../include/msg_stats.h cleanup_envelope.o: ../../include/myflock.h cleanup_envelope.o: ../../include/mymalloc.h cleanup_envelope.o: ../../include/nvtable.h @@ -1161,6 +1164,7 @@ cleanup_out_recipient.o: ../../include/sys_defs.h cleanup_out_recipient.o: ../../include/tok822.h cleanup_out_recipient.o: ../../include/trace.h cleanup_out_recipient.o: ../../include/vbuf.h +cleanup_out_recipient.o: ../../include/verify.h cleanup_out_recipient.o: ../../include/vstream.h cleanup_out_recipient.o: ../../include/vstring.h cleanup_out_recipient.o: cleanup.h diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h index 9bd7f1b87..a0dc9fbc9 100644 --- a/postfix/src/cleanup/cleanup.h +++ b/postfix/src/cleanup/cleanup.h @@ -64,6 +64,7 @@ typedef struct CLEANUP_STATE { ARGV *auto_hdrs; /* MTA's own header(s) */ ARGV *hbc_rcpt; /* header/body checks BCC addresses */ int flags; /* processing options, status flags */ + int tflags; /* User- or MTA-requested tracing */ int qmgr_opts; /* qmgr processing options */ int errs; /* any badness experienced */ int err_mask; /* allowed badness */ diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c index 261542ba8..abdc8f5d0 100644 --- a/postfix/src/cleanup/cleanup_envelope.c +++ b/postfix/src/cleanup/cleanup_envelope.c @@ -68,6 +68,7 @@ #include #include #include +#include /* Application-specific. */ @@ -488,6 +489,16 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, return; } } + if (strcmp(attr_name, MAIL_ATTR_TRACE_FLAGS) == 0) { + if (!alldig(attr_value)) { + msg_warn("%s: message rejected: bad TFLAG record <%.200s>", + state->queue_id, buf); + state->errs |= CLEANUP_STAT_BAD; + return; + } + if (state->tflags == 0) + state->tflags = DEL_REQ_TRACE_FLAGS(atoi(attr_value)); + } nvtable_update(state->attr, attr_name, attr_value); cleanup_out(state, type, buf, len); return; diff --git a/postfix/src/cleanup/cleanup_out_recipient.c b/postfix/src/cleanup/cleanup_out_recipient.c index 25ffb9052..bbe080365 100644 --- a/postfix/src/cleanup/cleanup_out_recipient.c +++ b/postfix/src/cleanup/cleanup_out_recipient.c @@ -76,6 +76,7 @@ #include #include #include +#include #include /* cleanup_trace_path */ #include #include @@ -104,6 +105,20 @@ static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt, } } +/* cleanup_verify_append - update verify daemon */ + +static void cleanup_verify_append(CLEANUP_STATE *state, RECIPIENT *rcpt, + DSN *dsn, int verify_status) +{ + MSG_STATS stats; + + if (verify_append(state->queue_id, CLEANUP_MSG_STATS(&stats, state), + rcpt, "none", dsn, verify_status) != 0) { + msg_warn("%s: verify service update error", state->queue_id); + state->errs |= CLEANUP_STAT_WRITE; + } +} + /* cleanup_out_recipient - envelope recipient output filter */ void cleanup_out_recipient(CLEANUP_STATE *state, @@ -193,6 +208,15 @@ void cleanup_out_recipient(CLEANUP_STATE *state, * recipient information, also ignore differences in DSN attributes. We * do, however, keep the DSN attributes of the recipient that survives * duplicate elimination. + * + * In the case of a verify(8) request for a one-to-many alias, declare the + * alias address as "deliverable". Do not verify the individual addresses + * in the expansion because that results in multiple verify(8) updates + * for one verify(8) request. + * + * Multiple verify(8) updates for one verify(8) request would overwrite + * each other's status, and if the last status update is "undeliverable", + * then the whole alias is flagged as undeliverable. */ else { RECIPIENT rcpt; @@ -200,6 +224,14 @@ void cleanup_out_recipient(CLEANUP_STATE *state, argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps, cleanup_ext_prop_mask & EXT_PROP_VIRTUAL); + if (argv->argc > 1 && (state->tflags & DEL_REQ_FLAG_MTA_VRFY)) { + (void) DSN_SIMPLE(&dsn, "2.0.0", "aliased to multiple recipients"); + dsn.action = "deliverable"; + RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip); + cleanup_verify_append(state, &rcpt, &dsn, DEL_RCPT_STAT_OK); + argv_free(argv); + return; + } if ((dsn_notify & DSN_NOTIFY_SUCCESS) && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) { (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded"); diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c index 0d71b44ab..17a46172b 100644 --- a/postfix/src/cleanup/cleanup_state.c +++ b/postfix/src/cleanup/cleanup_state.c @@ -81,6 +81,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src) state->auto_hdrs = argv_alloc(1); state->hbc_rcpt = 0; state->flags = 0; + state->tflags = 0; state->qmgr_opts = 0; state->errs = 0; state->err_mask = 0; diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index 85e1ecfdb..4842d572f 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -368,13 +368,21 @@ static const char *check_myhostname(void) /* * If the local machine name is not in FQDN form, try to append the * contents of $mydomain. Use a default domain as a final workaround. + * + * DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - IT MAKES EVERY POSTFIX + * PROGRAM HANG WHEN DNS SERVICE IS UNAVAILABLE. IF YOU DON'T LIKE THE + * DEFAULT, THEN EDIT MAIN.CF. */ name = get_hostname(); + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ if ((dot = strchr(name, '.')) == 0) { + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) domain = DEF_MYDOMAIN; + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ name = concatenate(name, ".", domain, (char *) 0); } + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ return (name); } @@ -386,9 +394,16 @@ static const char *check_mydomainname(void) /* * Use a default domain when the hostname is not a FQDN ("foo"). + * + * DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - IT MAKES EVERY POSTFIX + * PROGRAM HANG WHEN DNS SERVICE IS UNAVAILABLE. IF YOU DON'T LIKE THE + * DEFAULT, THEN EDIT MAIN.CF. */ + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ if ((dot = strchr(var_myhostname, '.')) == 0) + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ return (DEF_MYDOMAIN); + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ return (dot + 1); } diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 91c7f126e..81464b1e0 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -2706,6 +2706,10 @@ extern int var_scache_ttl_lim; #define DEF_SCACHE_STAT_TIME "600s" extern int var_scache_stat_time; +#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; + /* * Address verification service. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index e7538e5b7..3fa1ccd16 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20151218" +#define MAIL_RELEASE_DATE "20151227" #define MAIL_VERSION_NUMBER "3.1" #ifdef SNAPSHOT diff --git a/postfix/src/global/post_mail.c b/postfix/src/global/post_mail.c index 002b8d99d..fbb631d9b 100644 --- a/postfix/src/global/post_mail.c +++ b/postfix/src/global/post_mail.c @@ -54,6 +54,11 @@ /* /* int post_mail_fclose(stream) /* VSTREAM *STREAM; +/* +/* void post_mail_fclose_async(stream, notify, context) +/* VSTREAM *stream; +/* void (*notify)(int status, void *context); +/* void *context; /* DESCRIPTION /* This module provides a convenient interface for the most /* common case of sending one message to one recipient. It @@ -91,6 +96,11 @@ /* /* post_mail_fclose() completes the posting of a message. /* +/* post_mail_fclose_async() completes the posting of a message +/* and upon completion invokes the caller-specified notify +/* routine, with the cleanup status and caller-specified context +/* as arguments. +/* /* Arguments: /* .IP sender /* The sender envelope address. It is up to the application @@ -187,6 +197,16 @@ typedef struct { VSTRING *queue_id; } POST_MAIL_STATE; + /* + * Call-back state for asynchronous close requests. + */ +typedef struct { + int status; + VSTREAM *stream; + POST_MAIL_FCLOSE_NOTIFY notify; + void *context; +} POST_MAIL_FCLOSE_STATE; + /* post_mail_init - initial negotiations */ static void post_mail_init(VSTREAM *stream, const char *sender, @@ -205,6 +225,13 @@ static void post_mail_init(VSTREAM *stream, const char *sender, GETTIMEOFDAY(&now); date = mail_date(now.tv_sec); + /* + * XXX Don't flush buffers while sending the initial message records. + * That would cause deadlock between verify(8) and cleanup(8) servers. + */ + vstream_control(stream, VSTREAM_CTL_BUFSIZE, 2 * VSTREAM_BUFSIZE, + VSTREAM_CTL_END); + /* * Negotiate with the cleanup service. Give up if we can't agree. */ @@ -435,3 +462,94 @@ int post_mail_fclose(VSTREAM *cleanup) (void) vstream_fclose(cleanup); return (status); } + +/* post_mail_fclose_event - event handler */ + +static void post_mail_fclose_event(int event, void *context) +{ + POST_MAIL_FCLOSE_STATE *state = (POST_MAIL_FCLOSE_STATE *) context; + int status = state->status; + + switch (event) { + + /* + * Final server reply. Pick up the completion status. + */ + case EVENT_READ: + if (status == 0) { + if (vstream_ferror(state->stream) != 0 + || attr_scan(state->stream, ATTR_FLAG_MISSING, + ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) + status = CLEANUP_STAT_WRITE; + } + break; + + /* + * No response or error. + */ + default: + msg_warn("error talking to service: %s", var_cleanup_service); + status = CLEANUP_STAT_WRITE; + break; + } + + /* + * Stop the watchdog timer, and disable further read events that end up + * calling this function. + */ + event_cancel_timer(post_mail_fclose_event, context); + event_disable_readwrite(vstream_fileno(state->stream)); + + /* + * Notify the requestor and clean up. + */ + state->notify(status, state->context); + (void) vstream_fclose(state->stream); + myfree((void *) state); +} + +/* post_mail_fclose_async - finish posting of message */ + +void post_mail_fclose_async(VSTREAM *stream, + void (*notify) (int status, void *context), + void *context) +{ + POST_MAIL_FCLOSE_STATE *state; + int status = 0; + + + /* + * Send the message end marker only when there were no errors. + */ + if (vstream_ferror(stream) != 0) { + status = CLEANUP_STAT_WRITE; + } else { + rec_fputs(stream, REC_TYPE_XTRA, ""); + rec_fputs(stream, REC_TYPE_END, ""); + if (vstream_fflush(stream)) + status = CLEANUP_STAT_WRITE; + } + + /* + * Bundle up the suspended state. + */ + state = (POST_MAIL_FCLOSE_STATE *) mymalloc(sizeof(*state)); + state->status = status; + state->stream = stream; + state->notify = notify; + state->context = context; + + /* + * To keep interfaces as simple as possible we report all errors via the + * same interface as all successes. + */ + if (status == 0) { + event_enable_read(vstream_fileno(stream), post_mail_fclose_event, + (void *) state); + event_request_timer(post_mail_fclose_event, (void *) state, + var_daemon_timeout); + } else { + event_request_timer(post_mail_fclose_event, (void *) state, 0); + } +} diff --git a/postfix/src/global/post_mail.h b/postfix/src/global/post_mail.h index 70bb34f0d..eb7974a07 100644 --- a/postfix/src/global/post_mail.h +++ b/postfix/src/global/post_mail.h @@ -28,7 +28,7 @@ /* * External interface. */ -typedef void (*POST_MAIL_NOTIFY)(VSTREAM *, void *); +typedef void (*POST_MAIL_NOTIFY) (VSTREAM *, void *); extern VSTREAM *post_mail_fopen(const char *, const char *, int, int, int, VSTRING *); extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int, int, int, VSTRING *); extern void post_mail_fopen_async(const char *, const char *, int, int, int, VSTRING *, POST_MAIL_NOTIFY, void *); @@ -36,6 +36,8 @@ extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...); extern int post_mail_fputs(VSTREAM *, const char *); extern int post_mail_buffer(VSTREAM *, const char *, int); extern int post_mail_fclose(VSTREAM *); +typedef void (*POST_MAIL_FCLOSE_NOTIFY) (int, void *); +extern void post_mail_fclose_async(VSTREAM *, POST_MAIL_FCLOSE_NOTIFY, void *); #define POST_MAIL_BUFFER(v, b) \ post_mail_buffer((v), vstring_str(b), VSTRING_LEN(b)) diff --git a/postfix/src/global/verify.c b/postfix/src/global/verify.c index d6bf36f67..8b20ac710 100644 --- a/postfix/src/global/verify.c +++ b/postfix/src/global/verify.c @@ -102,8 +102,9 @@ int verify_append(const char *queue_id, MSG_STATS *stats, if (var_verify_neg_cache || vrfy_stat == DEL_RCPT_STAT_OK) { req_stat = verify_clnt_update(recipient->orig_addr, vrfy_stat, my_dsn.reason); + /* Two verify updates for one verify request! */ if (req_stat == VRFY_STAT_OK - && strcasecmp_utf8(recipient->address, recipient->orig_addr) != 0) + && strcasecmp_utf8(recipient->address, recipient->orig_addr) != 0) req_stat = verify_clnt_update(recipient->address, vrfy_stat, my_dsn.reason); } else { diff --git a/postfix/src/oqmgr/qmgr.c b/postfix/src/oqmgr/qmgr.c index cca95c773..4ea89e700 100644 --- a/postfix/src/oqmgr/qmgr.c +++ b/postfix/src/oqmgr/qmgr.c @@ -272,6 +272,11 @@ /* .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 3.1 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 @@ -405,6 +410,7 @@ char *var_def_filter_nexthop; int var_qmgr_daemon_timeout; int var_qmgr_ipc_timeout; int var_dsn_delay_cleared; +int var_vrfy_pend_limit; static QMGR_SCAN *qmgr_scans[2]; @@ -664,6 +670,7 @@ int main(int argc, char **argv) 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 --git a/postfix/src/oqmgr/qmgr.h b/postfix/src/oqmgr/qmgr.h index b8c8d0e48..db4b394eb 100644 --- a/postfix/src/oqmgr/qmgr.h +++ b/postfix/src/oqmgr/qmgr.h @@ -330,6 +330,7 @@ struct QMGR_MESSAGE { 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 --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index 5b8596b07..26d9bd37e 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -8,6 +8,7 @@ /* /* 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,6 +39,13 @@ /* 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 @@ -136,6 +144,7 @@ int qmgr_message_count; int qmgr_recipient_count; +int qmgr_vrfy_pend_count; /* qmgr_message_create - create in-core message structure */ @@ -705,11 +714,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message) * 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; + 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; } @@ -1107,6 +1120,14 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) } } + /* + * 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. */ @@ -1310,6 +1331,8 @@ void qmgr_message_free(QMGR_MESSAGE *message) 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((void *) message); } diff --git a/postfix/src/postlog/postlog.c b/postfix/src/postlog/postlog.c index 518f45a1a..7403b079c 100644 --- a/postfix/src/postlog/postlog.c +++ b/postfix/src/postlog/postlog.c @@ -26,9 +26,12 @@ /* instead of the default configuration directory. /* .IP \fB-i\fR /* Include the process ID in the logging tag. -/* .IP "\fB-p \fIpriority\fR" -/* Specifies the logging severity: \fBinfo\fR (default), \fBwarn\fR, -/* \fBerror\fR, \fBfatal\fR, or \fBpanic\fR. +/* .IP "\fB-p \fIpriority\fR (default: \fBinfo\fR)" +/* Specifies the logging severity: \fBinfo\fR, \fBwarn\fR, +/* \fBerror\fR, \fBfatal\fR, or \fBpanic\fR. With Postfix 3.1 +/* and later, the program will pause for 1 second after reporting +/* a \fBfatal\fR or \fBpanic\fR condition, just like other +/* Postfix programs. /* .IP "\fB-t \fItag\fR" /* Specifies the logging tag, that is, the identifying name that /* appears at the beginning of each logging record. A default tag @@ -261,5 +264,11 @@ int main(int argc, char **argv) } else { log_stream(level, VSTREAM_IN); } + + /* + * Consistency with msg(3) functions. + */ + if (level >= MSG_FATAL) + sleep(1); exit(0); } diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c index 137cd9308..657e44216 100644 --- a/postfix/src/qmgr/qmgr.c +++ b/postfix/src/qmgr/qmgr.c @@ -318,6 +318,11 @@ /* .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 3.1 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 @@ -465,6 +470,7 @@ char *var_def_filter_nexthop; int var_qmgr_daemon_timeout; int var_qmgr_ipc_timeout; int var_dsn_delay_cleared; +int var_vrfy_pend_limit; static QMGR_SCAN *qmgr_scans[2]; @@ -739,6 +745,7 @@ int main(int argc, char **argv) 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 --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index 88ce7920e..17919d183 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -380,6 +380,7 @@ struct QMGR_MESSAGE { 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 --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index a83e4a0aa..495d52d93 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -8,6 +8,7 @@ /* /* 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,6 +39,13 @@ /* 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 @@ -145,6 +153,7 @@ int qmgr_message_count; int qmgr_recipient_count; +int qmgr_vrfy_pend_count; /* qmgr_message_create - create in-core message structure */ @@ -746,11 +755,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message) * 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; + 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; } @@ -1166,6 +1179,14 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) } } + /* + * 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. */ @@ -1431,6 +1452,8 @@ void qmgr_message_free(QMGR_MESSAGE *message) 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((void *) message); } diff --git a/postfix/src/verify/verify.c b/postfix/src/verify/verify.c index 300bd9ea3..d9538a8b2 100644 --- a/postfix/src/verify/verify.c +++ b/postfix/src/verify/verify.c @@ -400,9 +400,17 @@ static void verify_update_service(VSTREAM *client_stream) vstring_free(text); } +/* verify_post_mail_fclose_action - callback */ + +static void verify_post_mail_fclose_action(int unused_status, + void *unused_context) +{ + /* no code here, we just need to avoid blocking in post_mail_fclose() */ +} + /* verify_post_mail_action - callback */ -static void verify_post_mail_action(VSTREAM *stream, void *unused_context) +static void verify_post_mail_action(VSTREAM *stream, void *context) { /* @@ -410,7 +418,7 @@ static void verify_post_mail_action(VSTREAM *stream, void *unused_context) * deferred, or bounced. */ if (stream != 0) - post_mail_fclose(stream); + post_mail_fclose_async(stream, verify_post_mail_fclose_action, context); } /* verify_query_service - query address status */ @@ -500,8 +508,8 @@ static void verify_query_service(VSTREAM *client_stream) (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now) if (now - probed > PROBE_TTL - && (POSITIVE_REFRESH_NEEDED(addr_status, updated) - || NEGATIVE_REFRESH_NEEDED(addr_status, updated))) { + && (POSITIVE_REFRESH_NEEDED(addr_status, updated) + || NEGATIVE_REFRESH_NEEDED(addr_status, updated))) { if (msg_verbose) msg_info("PROBE %s status=%d probed=%ld updated=%ld", STR(addr), addr_status, now, updated);