mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 06:05:37 +00:00
postfix-2.0.3-20030125
This commit is contained in:
committed by
Viktor Dukhovni
parent
0bf8270bb1
commit
17e07be3f4
@@ -7796,6 +7796,22 @@ Apologies for any names omitted.
|
|||||||
Postfix now uses TIME.DEVICE_INODE.HOST. Files: local/maildir.c,
|
Postfix now uses TIME.DEVICE_INODE.HOST. Files: local/maildir.c,
|
||||||
virtual/maildir.c.
|
virtual/maildir.c.
|
||||||
|
|
||||||
|
20030124
|
||||||
|
|
||||||
|
Cleanup: queue structures no longer overload queue name
|
||||||
|
and nexthop destination. Files: *qmgr/qmgr_message.c,
|
||||||
|
*qmgr/qmgr_queue.c, *qmgr/qmgr_deliver.c.
|
||||||
|
|
||||||
|
20030125
|
||||||
|
|
||||||
|
Feature: "REDIRECT user@domain" action in access maps or
|
||||||
|
in header/body_checks causes mail to be sent to the specified
|
||||||
|
address instead of the intended recipient(s). I would never
|
||||||
|
recommend that people use this to redirect (bounced) SPAM
|
||||||
|
to the beneficiaries of an advertisement campaign. Files:
|
||||||
|
smtpd/smtpd_check.c, cleanup/cleanup_message.c,
|
||||||
|
*qmgr/qmgr_message.c.
|
||||||
|
|
||||||
Open problems:
|
Open problems:
|
||||||
|
|
||||||
Med: make qmgr recipient bounce/defer activity asynchronous
|
Med: make qmgr recipient bounce/defer activity asynchronous
|
||||||
|
@@ -22,6 +22,27 @@ snapshot release). Patches change the patchlevel and the release
|
|||||||
date. Snapshots change only the release date, unless they include
|
date. Snapshots change only the release date, unless they include
|
||||||
the same bugfixes as a patch release.
|
the same bugfixes as a patch release.
|
||||||
|
|
||||||
|
Incompatible changes with Postfix snapshot 2.0.3-20030125
|
||||||
|
=========================================================
|
||||||
|
|
||||||
|
This release adds a new queue file record type for the address
|
||||||
|
specified in "REDIRECT user@domain" actions in access maps or
|
||||||
|
header/body_checks.
|
||||||
|
|
||||||
|
Major changes with Postfix snapshot 2.0.3-20030125
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
Code cleanup up of queue manager internals. Queue names are no
|
||||||
|
longer mixed up with the next-hop destination, and the address
|
||||||
|
resolver loop is now easier to understand.
|
||||||
|
|
||||||
|
New "REDIRECT user@domain" action for access maps and header/body_checks
|
||||||
|
that overrides all the originally specified recipients of a message.
|
||||||
|
I would never recommend that people use this to redirect (bounced)
|
||||||
|
SPAM to the beneficiaries of an advertisement campaign. It would
|
||||||
|
have helped when someone began spamming the network with sender
|
||||||
|
addresses in one of my domains, and I got all the bounces.
|
||||||
|
|
||||||
Incompatible changes with Postfix snapshot 2.0.1-20030112
|
Incompatible changes with Postfix snapshot 2.0.1-20030112
|
||||||
=========================================================
|
=========================================================
|
||||||
|
|
||||||
|
@@ -164,8 +164,17 @@
|
|||||||
# about content filters is in the Postfix FIL-
|
# about content filters is in the Postfix FIL-
|
||||||
# TER_README file.
|
# TER_README file.
|
||||||
#
|
#
|
||||||
# Note: this action currently affects all recipients
|
# Note: this action overrides the main.cf con-
|
||||||
# of the message.
|
# tent_filter setting, and currently affects all
|
||||||
|
# recipients of the message.
|
||||||
|
#
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# After the message is queued, send the message to
|
||||||
|
# the specified address instead of the intended
|
||||||
|
# recipient(s).
|
||||||
|
#
|
||||||
|
# Note: this action overrides the FILTER action, and
|
||||||
|
# currently affects all recipients of the message.
|
||||||
#
|
#
|
||||||
# restriction...
|
# restriction...
|
||||||
# Apply the named UCE restriction(s) (permit, reject,
|
# Apply the named UCE restriction(s) (permit, reject,
|
||||||
|
@@ -38,6 +38,9 @@
|
|||||||
# off in the second cleanup server. More info about content
|
# off in the second cleanup server. More info about content
|
||||||
# filtering is in the Postfix FILTER_README file. This feature
|
# filtering is in the Postfix FILTER_README file. This feature
|
||||||
# overrides the main.cf content_filter setting.
|
# overrides the main.cf content_filter setting.
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# Send the message to the specified address instead of the
|
||||||
|
# intended recipient(s). This feature overrides the FILTER action.
|
||||||
#
|
#
|
||||||
# By default, these patterns apply the primary message headers, to
|
# By default, these patterns apply the primary message headers, to
|
||||||
# MIME headers, and to the headers of attached messages. With older
|
# MIME headers, and to the headers of attached messages. With older
|
||||||
@@ -82,6 +85,9 @@ header_checks = regexp:/etc/postfix/header_checks
|
|||||||
# off in the second cleanup server. More info about content
|
# off in the second cleanup server. More info about content
|
||||||
# filtering is in the Postfix FILTER_README file. This feature
|
# filtering is in the Postfix FILTER_README file. This feature
|
||||||
# overrides the main.cf content_filter setting.
|
# overrides the main.cf content_filter setting.
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# Send the message to the specified address instead of the
|
||||||
|
# intended recipient(s). This feature overrides the FILTER action.
|
||||||
#
|
#
|
||||||
# By default, the same patterns are applied as for header_checks.
|
# By default, the same patterns are applied as for header_checks.
|
||||||
#
|
#
|
||||||
|
@@ -51,7 +51,12 @@
|
|||||||
# and after the filter, with header/body
|
# and after the filter, with header/body
|
||||||
# checks turned off in the second cleanup
|
# checks turned off in the second cleanup
|
||||||
# server. More information about content filters
|
# server. More information about content filters
|
||||||
# is in the Postfix FILTER_README file.
|
# is in the Postfix FILTER_README file. This feature
|
||||||
|
# overrides the main.cf content_filter setting.
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# Send the message to the specified address instead
|
||||||
|
# of the intended recipient(s). This feature overrides
|
||||||
|
# the FILTER action.
|
||||||
#
|
#
|
||||||
# Substitution of sub-strings from the matched expression is
|
# Substitution of sub-strings from the matched expression is
|
||||||
# possible using the conventional perl syntax. The macros in the
|
# possible using the conventional perl syntax. The macros in the
|
||||||
|
@@ -52,7 +52,12 @@
|
|||||||
# and after the filter, with header/body
|
# and after the filter, with header/body
|
||||||
# checks turned off in the second cleanup
|
# checks turned off in the second cleanup
|
||||||
# server. More information about content filters
|
# server. More information about content filters
|
||||||
# is in the Postfix FILTER_README file.
|
# is in the Postfix FILTER_README file. This feature
|
||||||
|
# overrides the main.cf content_filter setting.
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# Send the message to the specified address instead
|
||||||
|
# of the intended recipient(s). This feature overrides
|
||||||
|
# the FILTER action.
|
||||||
#
|
#
|
||||||
# Substitution of sub-strings from the matched expression is
|
# Substitution of sub-strings from the matched expression is
|
||||||
# possible using the conventional perl syntax. The macros in the
|
# possible using the conventional perl syntax. The macros in the
|
||||||
|
@@ -43,7 +43,11 @@
|
|||||||
# After the message is queued, send the entire message through
|
# After the message is queued, send the entire message through
|
||||||
# a content filter. This requires different cleanup servers
|
# a content filter. This requires different cleanup servers
|
||||||
# before and after the filter, with header/body checks turned
|
# before and after the filter, with header/body checks turned
|
||||||
# off in the second cleanup server.
|
# off in the second cleanup server. This overrides the main.cf
|
||||||
|
# content filter setting.
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# Send the message to the specified address instead of the
|
||||||
|
# intended recipient(s). This overrides the FILTER action.
|
||||||
|
|
||||||
# Skip over base 64 encoded blocks. This saves lots of CPU cycles.
|
# Skip over base 64 encoded blocks. This saves lots of CPU cycles.
|
||||||
# Expressions by Liviu Daia. Amended by Victor Duchovni.
|
# Expressions by Liviu Daia. Amended by Victor Duchovni.
|
||||||
|
@@ -43,7 +43,11 @@
|
|||||||
# After the message is queued, send the entire message through
|
# After the message is queued, send the entire message through
|
||||||
# a content filter. This requires different cleanup servers
|
# a content filter. This requires different cleanup servers
|
||||||
# before and after the filter, with header/body checks turned
|
# before and after the filter, with header/body checks turned
|
||||||
# off in the second cleanup server.
|
# off in the second cleanup server. This overrides the main.cf
|
||||||
|
# content filter setting.
|
||||||
|
# REDIRECT user@domain
|
||||||
|
# Send the message to the specified address instead of the
|
||||||
|
# intended recipient(s). This overrides the FILTER action.
|
||||||
|
|
||||||
/^Subject: Make Money Fast/ REJECT
|
/^Subject: Make Money Fast/ REJECT
|
||||||
/^To: friend@public.com/ REJECT
|
/^To: friend@public.com/ REJECT
|
||||||
|
@@ -266,6 +266,8 @@ mynetworks_style = subnet
|
|||||||
# Discard the message if the result is DISCARD text...
|
# Discard the message if the result is DISCARD text...
|
||||||
# Hold the message in the queue if the result is HOLD text...
|
# Hold the message in the queue if the result is HOLD text...
|
||||||
# Release mail "on hold" with the postsuper(1) command.
|
# Release mail "on hold" with the postsuper(1) command.
|
||||||
|
# Filter the message if the result is FILTER transport:nexthop.
|
||||||
|
# Redirect the message if the result is REDIRECT user@domain.
|
||||||
# Permit the SMTP client if the result is OK or all numerical.
|
# Permit the SMTP client if the result is OK or all numerical.
|
||||||
# reject_rbl_client domain.tld: reject if the reversed client IP address
|
# reject_rbl_client domain.tld: reject if the reversed client IP address
|
||||||
# is listed in an A record under domain.tld.
|
# is listed in an A record under domain.tld.
|
||||||
@@ -312,6 +314,8 @@ smtpd_helo_required = no
|
|||||||
# Discard the message if the result is DISCARD text...
|
# Discard the message if the result is DISCARD text...
|
||||||
# Hold the message in the queue if the result is HOLD text...
|
# Hold the message in the queue if the result is HOLD text...
|
||||||
# Release mail "on hold" with the postsuper(1) command.
|
# Release mail "on hold" with the postsuper(1) command.
|
||||||
|
# Filter the message if the result is FILTER transport:nexthop.
|
||||||
|
# Redirect the message if the result is REDIRECT user@domain.
|
||||||
# Permit the HELO command if the result is OK or all numerical.
|
# Permit the HELO command if the result is OK or all numerical.
|
||||||
# reject: reject the request. Place this at the end of a restriction.
|
# reject: reject the request. Place this at the end of a restriction.
|
||||||
# permit: permit the request. Place this at the end of a restriction.
|
# permit: permit the request. Place this at the end of a restriction.
|
||||||
@@ -349,6 +353,8 @@ smtpd_helo_restrictions =
|
|||||||
# Discard the message if the result is DISCARD text...
|
# Discard the message if the result is DISCARD text...
|
||||||
# Hold the message in the queue if the result is HOLD text...
|
# Hold the message in the queue if the result is HOLD text...
|
||||||
# Release mail "on hold" with the postsuper(1) command.
|
# Release mail "on hold" with the postsuper(1) command.
|
||||||
|
# Filter the message if the result is FILTER transport:nexthop.
|
||||||
|
# Redirect the message if the result is REDIRECT user@domain.
|
||||||
# Permit the sender if the result is OK or all numerical.
|
# Permit the sender if the result is OK or all numerical.
|
||||||
# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies
|
# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies
|
||||||
# a MAIL FROM address owner, but the client is not (SASL) logged in as
|
# a MAIL FROM address owner, but the client is not (SASL) logged in as
|
||||||
@@ -423,6 +429,8 @@ smtpd_sender_restrictions =
|
|||||||
# Discard the message if the result is DISCARD text...
|
# Discard the message if the result is DISCARD text...
|
||||||
# Hold the message in the queue if the result is HOLD text...
|
# Hold the message in the queue if the result is HOLD text...
|
||||||
# Release mail "on hold" with the postsuper(1) command.
|
# Release mail "on hold" with the postsuper(1) command.
|
||||||
|
# Filter the message if the result is FILTER transport:nexthop.
|
||||||
|
# Redirect the message if the result is REDIRECT user@domain.
|
||||||
# Permit the recipient if the result is OK or all numerical.
|
# Permit the recipient if the result is OK or all numerical.
|
||||||
# reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
|
# reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
|
||||||
# reject: reject the request. Place this at the end of a restriction.
|
# reject: reject the request. Place this at the end of a restriction.
|
||||||
|
@@ -165,8 +165,17 @@ ACCESS(5) ACCESS(5)
|
|||||||
about content filters is in the Postfix FIL-
|
about content filters is in the Postfix FIL-
|
||||||
TER_README file.
|
TER_README file.
|
||||||
|
|
||||||
Note: this action currently affects all recipients
|
Note: this action overrides the <b>main.cf</b> <b>con-</b>
|
||||||
of the message.
|
<b>tent</b><i>_</i><b>filter</b> setting, and currently affects all
|
||||||
|
recipients of the message.
|
||||||
|
|
||||||
|
<b>REDIRECT</b> <i>user@domain</i>
|
||||||
|
After the message is queued, send the message to
|
||||||
|
the specified address instead of the intended
|
||||||
|
recipient(s).
|
||||||
|
|
||||||
|
Note: this action overrides the FILTER action, and
|
||||||
|
currently affects all recipients of the message.
|
||||||
|
|
||||||
<i>restriction...</i>
|
<i>restriction...</i>
|
||||||
Apply the named UCE restriction(s) (<b>permit</b>, <b>reject</b>,
|
Apply the named UCE restriction(s) (<b>permit</b>, <b>reject</b>,
|
||||||
|
@@ -168,6 +168,11 @@ off in the second cleanup server. More details about content
|
|||||||
filtering are in the Postfix FILTER_README file. This feature
|
filtering are in the Postfix FILTER_README file. This feature
|
||||||
overrides the main.cf <b>content_filter</b> setting.
|
overrides the main.cf <b>content_filter</b> setting.
|
||||||
|
|
||||||
|
<dt>REDIRECT <i>user</i>@<i>domain</i> <dd>
|
||||||
|
After the message is queued, send the message to the
|
||||||
|
specified address instead of the intended recipients.
|
||||||
|
overrides the FILTER action.
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -267,6 +272,11 @@ off in the second cleanup server. More details about content
|
|||||||
filtering are in the Postfix FILTER_README file. This feature
|
filtering are in the Postfix FILTER_README file. This feature
|
||||||
overrides the main.cf <b>content_filter</b> setting.
|
overrides the main.cf <b>content_filter</b> setting.
|
||||||
|
|
||||||
|
<dt>REDIRECT <i>user</i>@<i>domain</i> <dd>
|
||||||
|
After the message is queued, send the message to the
|
||||||
|
specified address instead of the intended recipients.
|
||||||
|
overrides the FILTER action.
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@@ -152,7 +152,14 @@ After the message is queued, send the entire message through
|
|||||||
a content filter. More information about content filters
|
a content filter. More information about content filters
|
||||||
is in the Postfix FILTER_README file.
|
is in the Postfix FILTER_README file.
|
||||||
.sp
|
.sp
|
||||||
Note: this action currently affects all recipients of the message.
|
Note: this action overrides the \fBmain.cf content_filter\fR setting,
|
||||||
|
and currently affects all recipients of the message.
|
||||||
|
.IP "\fBREDIRECT \fIuser@domain\fR"
|
||||||
|
After the message is queued, send the message to the specified
|
||||||
|
address instead of the intended recipient(s).
|
||||||
|
.sp
|
||||||
|
Note: this action overrides the FILTER action, and currently affects
|
||||||
|
all recipients of the message.
|
||||||
.IP \fIrestriction...\fR
|
.IP \fIrestriction...\fR
|
||||||
Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
|
Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
|
||||||
\fBreject_unauth_destination\fR, and so on).
|
\fBreject_unauth_destination\fR, and so on).
|
||||||
|
@@ -63,7 +63,7 @@
|
|||||||
# Note: lookup of the null sender address is not possible with
|
# Note: lookup of the null sender address is not possible with
|
||||||
# some types of lookup table. By default, Postfix uses \fB<>\fR
|
# some types of lookup table. By default, Postfix uses \fB<>\fR
|
||||||
# as the lookup key for such addresses. The value is specified with
|
# as the lookup key for such addresses. The value is specified with
|
||||||
# the \fBsmtpd_null_access_lookup_key\fR parameter in the Postfix
|
# the \fBsmtpd_null_access_lookup_key\fR parameter in the Postfix
|
||||||
# \fBmain.cf\fR file.
|
# \fBmain.cf\fR file.
|
||||||
# ADDRESS EXTENSION
|
# ADDRESS EXTENSION
|
||||||
# .fi
|
# .fi
|
||||||
@@ -100,8 +100,8 @@
|
|||||||
# the numerical code and text.
|
# the numerical code and text.
|
||||||
# .IP \fBREJECT\fR
|
# .IP \fBREJECT\fR
|
||||||
# .IP "\fBREJECT \fIoptional text...\fR
|
# .IP "\fBREJECT \fIoptional text...\fR
|
||||||
# Reject the address etc. that matches the pattern. Reply with
|
# Reject the address etc. that matches the pattern. Reply with
|
||||||
# \fI$reject_code optional text...\fR when the optional text is
|
# \fI$reject_code optional text...\fR when the optional text is
|
||||||
# specified, otherwise reply with a generic error response message.
|
# specified, otherwise reply with a generic error response message.
|
||||||
# .IP \fBOK\fR
|
# .IP \fBOK\fR
|
||||||
# Accept the address etc. that matches the pattern.
|
# Accept the address etc. that matches the pattern.
|
||||||
@@ -136,7 +136,14 @@
|
|||||||
# a content filter. More information about content filters
|
# a content filter. More information about content filters
|
||||||
# is in the Postfix FILTER_README file.
|
# is in the Postfix FILTER_README file.
|
||||||
# .sp
|
# .sp
|
||||||
# Note: this action currently affects all recipients of the message.
|
# Note: this action overrides the \fBmain.cf content_filter\fR setting,
|
||||||
|
# and currently affects all recipients of the message.
|
||||||
|
# .IP "\fBREDIRECT \fIuser@domain\fR"
|
||||||
|
# After the message is queued, send the message to the specified
|
||||||
|
# address instead of the intended recipient(s).
|
||||||
|
# .sp
|
||||||
|
# Note: this action overrides the FILTER action, and currently affects
|
||||||
|
# all recipients of the message.
|
||||||
# .IP \fIrestriction...\fR
|
# .IP \fIrestriction...\fR
|
||||||
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
|
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
|
||||||
# \fBreject_unauth_destination\fR, and so on).
|
# \fBreject_unauth_destination\fR, and so on).
|
||||||
|
@@ -67,6 +67,7 @@ typedef struct CLEANUP_STATE {
|
|||||||
MIME_STATE *mime_state; /* MIME state engine */
|
MIME_STATE *mime_state; /* MIME state engine */
|
||||||
int mime_errs; /* MIME error flags */
|
int mime_errs; /* MIME error flags */
|
||||||
char *filter; /* from header/body patterns */
|
char *filter; /* from header/body patterns */
|
||||||
|
char *redirect; /* from header/body patterns */
|
||||||
} CLEANUP_STATE;
|
} CLEANUP_STATE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -89,6 +89,14 @@ void cleanup_extracted(CLEANUP_STATE *state, int type, char *buf, int len)
|
|||||||
if (state->filter != 0)
|
if (state->filter != 0)
|
||||||
cleanup_out_string(state, REC_TYPE_FILT, state->filter);
|
cleanup_out_string(state, REC_TYPE_FILT, state->filter);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output the optional redirect target address before the mandatory
|
||||||
|
* Return-Receipt-To and Errors-To queue file records so that the queue
|
||||||
|
* manager will pick up the address before starting deliveries.
|
||||||
|
*/
|
||||||
|
if (state->redirect != 0)
|
||||||
|
cleanup_out_string(state, REC_TYPE_RDR, state->redirect);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Older Postfix versions didn't emit encoding information, so this
|
* Older Postfix versions didn't emit encoding information, so this
|
||||||
* record can only be optional. Putting this before the mandatory
|
* record can only be optional. Putting this before the mandatory
|
||||||
|
@@ -322,8 +322,8 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf,
|
|||||||
} else {
|
} else {
|
||||||
if (state->filter)
|
if (state->filter)
|
||||||
myfree(state->filter);
|
myfree(state->filter);
|
||||||
/* XXX should log something? */
|
|
||||||
state->filter = mystrdup(optional_text);
|
state->filter = mystrdup(optional_text);
|
||||||
|
cleanup_act_log(state, "filter", context, buf, optional_text);
|
||||||
}
|
}
|
||||||
return (CLEANUP_ACT_KEEP);
|
return (CLEANUP_ACT_KEEP);
|
||||||
}
|
}
|
||||||
@@ -338,6 +338,19 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf,
|
|||||||
state->flags |= CLEANUP_FLAG_HOLD;
|
state->flags |= CLEANUP_FLAG_HOLD;
|
||||||
return (CLEANUP_ACT_KEEP);
|
return (CLEANUP_ACT_KEEP);
|
||||||
}
|
}
|
||||||
|
if (STREQUAL(value, "REDIRECT", command_len)) {
|
||||||
|
if (strchr(optional_text, '@') == 0) {
|
||||||
|
msg_warn("bad REDIRECT target \"%s\" in %s map, need user@domain",
|
||||||
|
optional_text, map_class);
|
||||||
|
} else {
|
||||||
|
if (state->redirect)
|
||||||
|
myfree(state->redirect);
|
||||||
|
state->redirect = mystrdup(optional_text);
|
||||||
|
cleanup_act_log(state, "redirect", context, buf, optional_text);
|
||||||
|
state->flags &= ~CLEANUP_FLAG_FILTER;
|
||||||
|
}
|
||||||
|
return (CLEANUP_ACT_KEEP);
|
||||||
|
}
|
||||||
if (*optional_text)
|
if (*optional_text)
|
||||||
msg_warn("unexpected text after command in %s map: %s",
|
msg_warn("unexpected text after command in %s map: %s",
|
||||||
map_class, value);
|
map_class, value);
|
||||||
|
@@ -92,6 +92,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
|
|||||||
state->mime_state = 0;
|
state->mime_state = 0;
|
||||||
state->mime_errs = 0;
|
state->mime_errs = 0;
|
||||||
state->filter = 0;
|
state->filter = 0;
|
||||||
|
state->redirect = 0;
|
||||||
return (state);
|
return (state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,5 +132,7 @@ void cleanup_state_free(CLEANUP_STATE *state)
|
|||||||
mime_state_free(state->mime_state);
|
mime_state_free(state->mime_state);
|
||||||
if (state->filter)
|
if (state->filter)
|
||||||
myfree(state->filter);
|
myfree(state->filter);
|
||||||
|
if (state->redirect)
|
||||||
|
myfree(state->redirect);
|
||||||
myfree((char *) state);
|
myfree((char *) state);
|
||||||
}
|
}
|
||||||
|
@@ -1157,6 +1157,12 @@ resolve_local.o: mail_params.h
|
|||||||
resolve_local.o: own_inet_addr.h
|
resolve_local.o: own_inet_addr.h
|
||||||
resolve_local.o: resolve_local.h
|
resolve_local.o: resolve_local.h
|
||||||
resolve_local.o: match_parent_style.h
|
resolve_local.o: match_parent_style.h
|
||||||
|
resover.o: resover.c
|
||||||
|
resover.o: ../../include/sys_defs.h
|
||||||
|
resover.o: ../../include/msg.h
|
||||||
|
resover.o: ../../include/vstring.h
|
||||||
|
resover.o: ../../include/vbuf.h
|
||||||
|
resover.o: ../../include/split_at.h
|
||||||
rewrite_clnt.o: rewrite_clnt.c
|
rewrite_clnt.o: rewrite_clnt.c
|
||||||
rewrite_clnt.o: ../../include/sys_defs.h
|
rewrite_clnt.o: ../../include/sys_defs.h
|
||||||
rewrite_clnt.o: ../../include/msg.h
|
rewrite_clnt.o: ../../include/msg.h
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* Patches change the patchlevel and the release date. Snapshots change the
|
* Patches change the patchlevel and the release date. Snapshots change the
|
||||||
* release date only, unless they include the same bugfix as a patch release.
|
* release date only, unless they include the same bugfix as a patch release.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20030124"
|
#define MAIL_RELEASE_DATE "20030125"
|
||||||
|
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "2.0.3-" MAIL_RELEASE_DATE
|
#define DEF_MAIL_VERSION "2.0.3-" MAIL_RELEASE_DATE
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#define REC_TYPE_WARN 'W' /* warning message time */
|
#define REC_TYPE_WARN 'W' /* warning message time */
|
||||||
#define REC_TYPE_ATTR 'A' /* named attribute for extensions */
|
#define REC_TYPE_ATTR 'A' /* named attribute for extensions */
|
||||||
|
|
||||||
|
#define REC_TYPE_RDR '>' /* redirect target */
|
||||||
#define REC_TYPE_FLGS 'f' /* cleanup processing flags */
|
#define REC_TYPE_FLGS 'f' /* cleanup processing flags */
|
||||||
|
|
||||||
#define REC_TYPE_MESG 'M' /* start message records */
|
#define REC_TYPE_MESG 'M' /* start message records */
|
||||||
@@ -64,9 +65,9 @@
|
|||||||
* allow for the presence of A records in the extracted segment, because it
|
* allow for the presence of A records in the extracted segment, because it
|
||||||
* can be requested to re-process already queued mail with `postsuper -r'.
|
* can be requested to re-process already queued mail with `postsuper -r'.
|
||||||
*/
|
*/
|
||||||
#define REC_TYPE_ENVELOPE "MCTFILSDROWVA"
|
#define REC_TYPE_ENVELOPE "MCTFILSDROWVA>"
|
||||||
#define REC_TYPE_CONTENT "XLN"
|
#define REC_TYPE_CONTENT "XLN"
|
||||||
#define REC_TYPE_EXTRACT "EDROPreAFI"
|
#define REC_TYPE_EXTRACT "EDROPreAFI>"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The record at the beginning of the envelope segment specifies the message
|
* The record at the beginning of the envelope segment specifies the message
|
||||||
|
@@ -199,6 +199,7 @@ qmgr_message.o: ../../include/verp_sender.h
|
|||||||
qmgr_message.o: ../../include/mail_proto.h
|
qmgr_message.o: ../../include/mail_proto.h
|
||||||
qmgr_message.o: ../../include/iostuff.h
|
qmgr_message.o: ../../include/iostuff.h
|
||||||
qmgr_message.o: ../../include/attr.h
|
qmgr_message.o: ../../include/attr.h
|
||||||
|
qmgr_message.o: ../../include/rewrite_clnt.h
|
||||||
qmgr_message.o: ../../include/resolve_clnt.h
|
qmgr_message.o: ../../include/resolve_clnt.h
|
||||||
qmgr_message.o: qmgr.h
|
qmgr_message.o: qmgr.h
|
||||||
qmgr_message.o: ../../include/scan_dir.h
|
qmgr_message.o: ../../include/scan_dir.h
|
||||||
|
@@ -176,7 +176,8 @@ struct QMGR_ENTRY_LIST {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct QMGR_QUEUE {
|
struct QMGR_QUEUE {
|
||||||
char *name; /* domain name */
|
char *name; /* domain name or address */
|
||||||
|
char *nexthop; /* domain name */
|
||||||
int todo_refcount; /* queue entries (todo list) */
|
int todo_refcount; /* queue entries (todo list) */
|
||||||
int busy_refcount; /* queue entries (busy list) */
|
int busy_refcount; /* queue entries (busy list) */
|
||||||
int window; /* slow open algorithm */
|
int window; /* slow open algorithm */
|
||||||
@@ -194,7 +195,7 @@ struct QMGR_QUEUE {
|
|||||||
|
|
||||||
extern int qmgr_queue_count;
|
extern int qmgr_queue_count;
|
||||||
|
|
||||||
extern QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *, const char *);
|
extern QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *, const char *, const char *);
|
||||||
extern void qmgr_queue_done(QMGR_QUEUE *);
|
extern void qmgr_queue_done(QMGR_QUEUE *);
|
||||||
extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *);
|
extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *);
|
||||||
extern void qmgr_queue_unthrottle(QMGR_QUEUE *);
|
extern void qmgr_queue_unthrottle(QMGR_QUEUE *);
|
||||||
@@ -271,6 +272,7 @@ struct QMGR_MESSAGE {
|
|||||||
char *return_receipt; /* confirm receipt address */
|
char *return_receipt; /* confirm receipt address */
|
||||||
char *filter_xport; /* filtering transport */
|
char *filter_xport; /* filtering transport */
|
||||||
char *inspect_xport; /* inspecting transport */
|
char *inspect_xport; /* inspecting transport */
|
||||||
|
char *redirect_addr; /* info@spammer.tld */
|
||||||
long data_size; /* message content size */
|
long data_size; /* message content size */
|
||||||
long rcpt_offset; /* more recipients here */
|
long rcpt_offset; /* more recipients here */
|
||||||
long unread_offset; /* more unread recipients here */
|
long unread_offset; /* more unread recipients here */
|
||||||
|
@@ -129,11 +129,9 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
|||||||
QMGR_RCPT_LIST list = entry->rcpt_list;
|
QMGR_RCPT_LIST list = entry->rcpt_list;
|
||||||
QMGR_RCPT *recipient;
|
QMGR_RCPT *recipient;
|
||||||
QMGR_MESSAGE *message = entry->message;
|
QMGR_MESSAGE *message = entry->message;
|
||||||
char *cp;
|
|
||||||
VSTRING *sender_buf = 0;
|
VSTRING *sender_buf = 0;
|
||||||
char *sender;
|
char *sender;
|
||||||
int flags;
|
int flags;
|
||||||
char *nexthop;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If variable envelope return path is requested, change prefix+@origin
|
* If variable envelope return path is requested, change prefix+@origin
|
||||||
@@ -149,28 +147,15 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
|||||||
sender = vstring_str(sender_buf);
|
sender = vstring_str(sender_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* With mail transports that accept only one recipient per delivery, the
|
|
||||||
* queue name is user@nexthop, so that we can implement per-recipient
|
|
||||||
* concurrency limits. However, the delivery agent protocol expects
|
|
||||||
* nexthop only, so we must strip off the recipient local part.
|
|
||||||
*
|
|
||||||
* XXX Should have separate fields for queue name and for destination, so
|
|
||||||
* that we don't have to make a special case for the error delivery agent
|
|
||||||
* (where nexthop is arbitrary text). See also: qmgr_message.c.
|
|
||||||
*/
|
|
||||||
flags = message->tflags
|
flags = message->tflags
|
||||||
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
|
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
|
||||||
nexthop = strcmp(entry->queue->transport->name, MAIL_SERVICE_ERROR) != 0
|
|
||||||
&& (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
|
|
||||||
cp + 1 : entry->queue->name;
|
|
||||||
attr_print(stream, ATTR_FLAG_MORE,
|
attr_print(stream, ATTR_FLAG_MORE,
|
||||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
|
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
|
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
|
||||||
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
|
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
|
||||||
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
|
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
|
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
|
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
|
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
|
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
|
||||||
|
@@ -300,7 +300,7 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
|
|||||||
&& (now = event_time()) >= queue->clog_time_to_warn) {
|
&& (now = event_time()) >= queue->clog_time_to_warn) {
|
||||||
active_share = queue_length / (double) qmgr_message_count;
|
active_share = queue_length / (double) qmgr_message_count;
|
||||||
msg_warn("mail for %s is using up %d of %d active queue entries",
|
msg_warn("mail for %s is using up %d of %d active queue entries",
|
||||||
queue->name, queue_length, qmgr_message_count);
|
queue->nexthop, queue_length, qmgr_message_count);
|
||||||
if (active_share < 0.9)
|
if (active_share < 0.9)
|
||||||
msg_warn("this may slow down other mail deliveries");
|
msg_warn("this may slow down other mail deliveries");
|
||||||
transport = queue->transport;
|
transport = queue->transport;
|
||||||
@@ -314,7 +314,7 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
|
|||||||
VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
|
VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
|
||||||
else if (queue->peers.next != queue->peers.prev)
|
else if (queue->peers.next != queue->peers.prev)
|
||||||
msg_warn("you may need a separate master.cf transport for %s",
|
msg_warn("you may need a separate master.cf transport for %s",
|
||||||
queue->name);
|
queue->nexthop);
|
||||||
else {
|
else {
|
||||||
msg_warn("you may need to reduce %s connect and helo timeouts",
|
msg_warn("you may need to reduce %s connect and helo timeouts",
|
||||||
transport->name);
|
transport->name);
|
||||||
|
@@ -124,6 +124,7 @@
|
|||||||
|
|
||||||
/* Client stubs. */
|
/* Client stubs. */
|
||||||
|
|
||||||
|
#include <rewrite_clnt.h>
|
||||||
#include <resolve_clnt.h>
|
#include <resolve_clnt.h>
|
||||||
|
|
||||||
/* Application-specific. */
|
/* Application-specific. */
|
||||||
@@ -159,6 +160,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
|
|||||||
message->return_receipt = 0;
|
message->return_receipt = 0;
|
||||||
message->filter_xport = 0;
|
message->filter_xport = 0;
|
||||||
message->inspect_xport = 0;
|
message->inspect_xport = 0;
|
||||||
|
message->redirect_addr = 0;
|
||||||
message->data_size = 0;
|
message->data_size = 0;
|
||||||
message->warn_offset = 0;
|
message->warn_offset = 0;
|
||||||
message->warn_time = 0;
|
message->warn_time = 0;
|
||||||
@@ -385,6 +387,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
if (message->inspect_xport != 0)
|
if (message->inspect_xport != 0)
|
||||||
myfree(message->inspect_xport);
|
myfree(message->inspect_xport);
|
||||||
message->inspect_xport = mystrdup(start);
|
message->inspect_xport = mystrdup(start);
|
||||||
|
} else if (rec_type == REC_TYPE_RDR) {
|
||||||
|
if (message->redirect_addr != 0)
|
||||||
|
myfree(message->redirect_addr);
|
||||||
|
message->redirect_addr = mystrdup(start);
|
||||||
} else if (rec_type == REC_TYPE_FROM) {
|
} else if (rec_type == REC_TYPE_FROM) {
|
||||||
if (message->sender == 0) {
|
if (message->sender == 0) {
|
||||||
message->sender = mystrdup(start);
|
message->sender = mystrdup(start);
|
||||||
@@ -577,7 +583,7 @@ static int qmgr_message_sort_compare(const void *p1, const void *p2)
|
|||||||
return (result);
|
return (result);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare (already lowercased) next-hop hostname.
|
* Compare queue name (nexthop or recipient@nexthop).
|
||||||
*/
|
*/
|
||||||
if ((result = strcmp(queue1->name, queue2->name)) != 0)
|
if ((result = strcmp(queue1->name, queue2->name)) != 0)
|
||||||
return (result);
|
return (result);
|
||||||
@@ -619,6 +625,24 @@ static void qmgr_message_sort(QMGR_MESSAGE *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* qmgr_resolve_one - resolve or skip one recipient */
|
||||||
|
|
||||||
|
static int qmgr_resolve_one(QMGR_MESSAGE *message, QMGR_RCPT *recipient,
|
||||||
|
const char *addr, RESOLVE_REPLY *reply)
|
||||||
|
{
|
||||||
|
resolve_clnt_query(addr, reply);
|
||||||
|
if (reply->flags & RESOLVE_FLAG_FAIL) {
|
||||||
|
qmgr_defer_recipient(message, recipient, "address resolver failure");
|
||||||
|
return (-1);
|
||||||
|
} else if (reply->flags & RESOLVE_FLAG_ERROR) {
|
||||||
|
qmgr_bounce_recipient(message, recipient,
|
||||||
|
"bad address syntax: \"%s\"", addr);
|
||||||
|
return (-1);
|
||||||
|
} else {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* qmgr_message_resolve - resolve recipients */
|
/* qmgr_message_resolve - resolve recipients */
|
||||||
|
|
||||||
static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||||
@@ -629,6 +653,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
QMGR_TRANSPORT *transport = 0;
|
QMGR_TRANSPORT *transport = 0;
|
||||||
QMGR_QUEUE *queue = 0;
|
QMGR_QUEUE *queue = 0;
|
||||||
RESOLVE_REPLY reply;
|
RESOLVE_REPLY reply;
|
||||||
|
VSTRING *queue_name;
|
||||||
char *at;
|
char *at;
|
||||||
char **cpp;
|
char **cpp;
|
||||||
char *nexthop;
|
char *nexthop;
|
||||||
@@ -641,63 +666,75 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
|
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
|
||||||
|
|
||||||
resolve_clnt_init(&reply);
|
resolve_clnt_init(&reply);
|
||||||
|
queue_name = vstring_alloc(1);
|
||||||
for (recipient = list.info; recipient < list.info + list.len; recipient++) {
|
for (recipient = list.info; recipient < list.info + list.len; recipient++) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resolve the destination to (transport, nexthop, address). The
|
* Redirect overrides all else. But only once (per batch of
|
||||||
* result address may differ from the one specified by the sender.
|
* recipients). For consistency with the remainder of Postfix,
|
||||||
|
* rewrite the address to canonical form before resolving it.
|
||||||
*/
|
*/
|
||||||
if (var_sender_routing == 0) {
|
if (message->redirect_addr) {
|
||||||
resolve_clnt_query(recipient->address, &reply);
|
if (recipient > list.info) {
|
||||||
if (reply.flags & RESOLVE_FLAG_FAIL) {
|
recipient->queue = 0;
|
||||||
qmgr_defer_recipient(message, recipient,
|
|
||||||
"address resolver failure");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (reply.flags & RESOLVE_FLAG_ERROR) {
|
rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
|
||||||
qmgr_bounce_recipient(message, recipient,
|
reply.recipient);
|
||||||
"bad address syntax: \"%s\"",
|
UPDATE(recipient->address, STR(reply.recipient));
|
||||||
recipient->address);
|
if (qmgr_resolve_one(message, recipient,
|
||||||
|
recipient->address, &reply) < 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
if (!STREQ(recipient->address, STR(reply.recipient)))
|
||||||
} else {
|
UPDATE(recipient->address, STR(reply.recipient));
|
||||||
resolve_clnt_query(message->sender, &reply);
|
|
||||||
if (reply.flags & RESOLVE_FLAG_FAIL) {
|
|
||||||
qmgr_defer_recipient(message, recipient,
|
|
||||||
"address resolver failure");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (reply.flags & RESOLVE_FLAG_ERROR) {
|
|
||||||
qmgr_bounce_recipient(message, recipient,
|
|
||||||
"bad address syntax: \"%s\"",
|
|
||||||
message->sender);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vstring_strcpy(reply.recipient, recipient->address);
|
|
||||||
}
|
}
|
||||||
if (message->filter_xport) {
|
|
||||||
|
/*
|
||||||
|
* Content filtering overrides the address resolver.
|
||||||
|
*/
|
||||||
|
else if (message->filter_xport) {
|
||||||
vstring_strcpy(reply.transport, message->filter_xport);
|
vstring_strcpy(reply.transport, message->filter_xport);
|
||||||
if ((nexthop = split_at(STR(reply.transport), ':')) == 0
|
if ((nexthop = split_at(STR(reply.transport), ':')) == 0
|
||||||
|| *nexthop == 0)
|
|| *nexthop == 0)
|
||||||
nexthop = var_myhostname;
|
nexthop = var_myhostname;
|
||||||
vstring_strcpy(reply.nexthop, nexthop);
|
vstring_strcpy(reply.nexthop, nexthop);
|
||||||
} else {
|
vstring_strcpy(reply.recipient, recipient->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve the destination to (transport, nexthop, address). The
|
||||||
|
* result address may differ from the one specified by the sender.
|
||||||
|
*/
|
||||||
|
else if (var_sender_routing == 0) {
|
||||||
|
if (qmgr_resolve_one(message, recipient,
|
||||||
|
recipient->address, &reply) < 0)
|
||||||
|
continue;
|
||||||
if (!STREQ(recipient->address, STR(reply.recipient)))
|
if (!STREQ(recipient->address, STR(reply.recipient)))
|
||||||
UPDATE(recipient->address, STR(reply.recipient));
|
UPDATE(recipient->address, STR(reply.recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Sender-based routing does not work very well, because it has
|
||||||
|
* problems with sending bounces.
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
if (qmgr_resolve_one(message, recipient,
|
||||||
|
message->sender, &reply) < 0)
|
||||||
|
continue;
|
||||||
|
vstring_strcpy(reply.recipient, recipient->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bounce null recipients. This should never happen, but is most
|
||||||
|
* likely the result of a fault in a different program, so aborting
|
||||||
|
* the queue manager process does not help.
|
||||||
|
*/
|
||||||
if (recipient->address[0] == 0) {
|
if (recipient->address[0] == 0) {
|
||||||
qmgr_bounce_recipient(message, recipient,
|
qmgr_bounce_recipient(message, recipient,
|
||||||
"null recipient address");
|
"null recipient address");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX The nexthop destination is also used as lookup key for the
|
|
||||||
* per-destination queue. Fold the nexthop to lower case so that we
|
|
||||||
* don't have multiple queues for the same site.
|
|
||||||
*/
|
|
||||||
lowercase(STR(reply.nexthop));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bounce recipient addresses that start with `-'. External commands
|
* Bounce recipient addresses that start with `-'. External commands
|
||||||
* may misinterpret such addresses as command-line options.
|
* may misinterpret such addresses as command-line options.
|
||||||
@@ -716,46 +753,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Queues are identified by the transport name and by the next-hop
|
|
||||||
* hostname. When the delivery agent accepts only one recipient per
|
|
||||||
* delivery, give each recipient its own queue, so that deliveries to
|
|
||||||
* different recipients of the same message can happen in parallel.
|
|
||||||
* This also has the benefit that one bad recipient cannot interfere
|
|
||||||
* with deliveries to other recipients. XXX Should split the address
|
|
||||||
* on the recipient delimiter if one is defined, but doing a proper
|
|
||||||
* job requires knowledge of local aliases. Yuck! I don't want to
|
|
||||||
* duplicate delivery-agent specific knowledge in the queue manager.
|
|
||||||
*
|
|
||||||
* XXX The nexthop field is overloaded to serve as destination and as
|
|
||||||
* queue name. Should have separate fields for queue name and for
|
|
||||||
* destination, so that we don't have to make a special case for the
|
|
||||||
* error delivery agent (where nexthop is arbitrary text). See also:
|
|
||||||
* qmgr_deliver.c.
|
|
||||||
*/
|
|
||||||
at = strrchr(STR(reply.recipient), '@');
|
|
||||||
len = (at ? (at - STR(reply.recipient)) : strlen(STR(reply.recipient)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up or instantiate the proper transport. We're working a
|
|
||||||
* little ahead, doing queue management stuff that used to be done
|
|
||||||
* way down.
|
|
||||||
*/
|
|
||||||
if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
|
|
||||||
if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
|
|
||||||
transport = qmgr_transport_create(STR(reply.transport));
|
|
||||||
queue = 0;
|
|
||||||
}
|
|
||||||
if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
|
|
||||||
&& transport->recipient_limit == 1) {
|
|
||||||
VSTRING_SPACE(reply.nexthop, len + 2);
|
|
||||||
memmove(STR(reply.nexthop) + len + 1, STR(reply.nexthop),
|
|
||||||
LEN(reply.nexthop) + 1);
|
|
||||||
memcpy(STR(reply.nexthop), STR(reply.recipient), len);
|
|
||||||
STR(reply.nexthop)[len] = '@';
|
|
||||||
lowercase(STR(reply.nexthop));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Discard mail to the local double bounce address here, so this
|
* Discard mail to the local double bounce address here, so this
|
||||||
* system can run without a local delivery agent. They'd still have
|
* system can run without a local delivery agent. They'd still have
|
||||||
@@ -766,6 +763,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
* be directed to a general-purpose null delivery agent.
|
* be directed to a general-purpose null delivery agent.
|
||||||
*/
|
*/
|
||||||
if (reply.flags & RESOLVE_CLASS_LOCAL) {
|
if (reply.flags & RESOLVE_CLASS_LOCAL) {
|
||||||
|
at = strrchr(STR(reply.recipient), '@');
|
||||||
|
len = (at ? (at - STR(reply.recipient))
|
||||||
|
: strlen(STR(reply.recipient)));
|
||||||
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
|
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
|
||||||
len) == 0
|
len) == 0
|
||||||
&& !var_double_bounce_sender[len]) {
|
&& !var_double_bounce_sender[len]) {
|
||||||
@@ -798,16 +798,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX Gross hack alert. We want to group recipients by transport and
|
|
||||||
* by next-hop hostname, in order to minimize the number of network
|
|
||||||
* transactions. However, it would be wasteful to have an in-memory
|
|
||||||
* resolver reply structure for each in-core recipient. Instead, we
|
|
||||||
* bind each recipient to an in-core queue instance which is needed
|
|
||||||
* anyway. That gives all information needed for recipient grouping.
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up or instantiate the proper transport.
|
* Look up or instantiate the proper transport.
|
||||||
*/
|
*/
|
||||||
@@ -816,7 +806,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
transport = qmgr_transport_create(STR(reply.transport));
|
transport = qmgr_transport_create(STR(reply.transport));
|
||||||
queue = 0;
|
queue = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This transport is dead. Defer delivery to this recipient.
|
* This transport is dead. Defer delivery to this recipient.
|
||||||
@@ -826,13 +815,50 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The nexthop destination provides the default name for the
|
||||||
|
* per-destination queue. When the delivery agent accepts only one
|
||||||
|
* recipient per delivery, give each recipient its own queue, so that
|
||||||
|
* deliveries to different recipients of the same message can happen
|
||||||
|
* in parallel, and so that we can enforce per-recipient concurrency
|
||||||
|
* limits and prevent one recipient from tying up all the delivery
|
||||||
|
* agent resources. We use recipient@nexthop as queue name rather
|
||||||
|
* than the actual recipient domain name, so that one recipient in
|
||||||
|
* multiple equivalent domains cannot evade the per-recipient
|
||||||
|
* concurrency limit. XXX Should split the address on the recipient
|
||||||
|
* delimiter if one is defined, but doing a proper job requires
|
||||||
|
* knowledge of local aliases. Yuck! I don't want to duplicate
|
||||||
|
* delivery-agent specific knowledge in the queue manager.
|
||||||
|
*
|
||||||
|
* Fold the result to lower case so that we don't have multiple queues
|
||||||
|
* for the same name.
|
||||||
|
*
|
||||||
|
* Important! All recipients in a queue must have the same nexthop
|
||||||
|
* value. It is OK to have multiple queues with the same nexthop
|
||||||
|
* value, but only when those queues are named after recipients.
|
||||||
|
*/
|
||||||
|
vstring_strcpy(queue_name, STR(reply.nexthop));
|
||||||
|
if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
|
||||||
|
&& transport->recipient_limit == 1) {
|
||||||
|
at = strrchr(STR(reply.recipient), '@');
|
||||||
|
len = (at ? (at - STR(reply.recipient))
|
||||||
|
: strlen(STR(reply.recipient)));
|
||||||
|
VSTRING_SPACE(queue_name, len + 2);
|
||||||
|
memmove(STR(queue_name) + len + 1, STR(queue_name),
|
||||||
|
LEN(queue_name) + 1);
|
||||||
|
memcpy(STR(queue_name), STR(reply.recipient), len);
|
||||||
|
STR(queue_name)[len] = '@';
|
||||||
|
}
|
||||||
|
lowercase(STR(queue_name));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This transport is alive. Find or instantiate a queue for this
|
* This transport is alive. Find or instantiate a queue for this
|
||||||
* recipient.
|
* recipient.
|
||||||
*/
|
*/
|
||||||
if (queue == 0 || !STREQ(queue->name, STR(reply.nexthop))) {
|
if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
|
||||||
if ((queue = qmgr_queue_find(transport, STR(reply.nexthop))) == 0)
|
if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
|
||||||
queue = qmgr_queue_create(transport, STR(reply.nexthop));
|
queue = qmgr_queue_create(transport, STR(queue_name),
|
||||||
|
STR(reply.nexthop));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -849,6 +875,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
recipient->queue = queue;
|
recipient->queue = queue;
|
||||||
}
|
}
|
||||||
resolve_clnt_free(&reply);
|
resolve_clnt_free(&reply);
|
||||||
|
vstring_free(queue_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qmgr_message_assign - assign recipients to specific delivery requests */
|
/* qmgr_message_assign - assign recipients to specific delivery requests */
|
||||||
@@ -973,6 +1000,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
|||||||
myfree(message->filter_xport);
|
myfree(message->filter_xport);
|
||||||
if (message->inspect_xport)
|
if (message->inspect_xport)
|
||||||
myfree(message->inspect_xport);
|
myfree(message->inspect_xport);
|
||||||
|
if (message->redirect_addr)
|
||||||
|
myfree(message->redirect_addr);
|
||||||
qmgr_rcpt_list_free(&message->rcpt_list);
|
qmgr_rcpt_list_free(&message->rcpt_list);
|
||||||
qmgr_message_count--;
|
qmgr_message_count--;
|
||||||
myfree((char *) message);
|
myfree((char *) message);
|
||||||
|
@@ -8,16 +8,17 @@
|
|||||||
/*
|
/*
|
||||||
/* int qmgr_queue_count;
|
/* int qmgr_queue_count;
|
||||||
/*
|
/*
|
||||||
/* QMGR_QUEUE *qmgr_queue_create(transport, site)
|
/* QMGR_QUEUE *qmgr_queue_create(transport, name, nexthop)
|
||||||
/* QMGR_TRANSPORT *transport;
|
/* QMGR_TRANSPORT *transport;
|
||||||
/* const char *site;
|
/* const char *name;
|
||||||
|
/* const char *nexthop;
|
||||||
/*
|
/*
|
||||||
/* void qmgr_queue_done(queue)
|
/* void qmgr_queue_done(queue)
|
||||||
/* QMGR_QUEUE *queue;
|
/* QMGR_QUEUE *queue;
|
||||||
/*
|
/*
|
||||||
/* QMGR_QUEUE *qmgr_queue_find(transport, site)
|
/* QMGR_QUEUE *qmgr_queue_find(transport, name)
|
||||||
/* QMGR_TRANSPORT *transport;
|
/* QMGR_TRANSPORT *transport;
|
||||||
/* const char *site;
|
/* const char *name;
|
||||||
/*
|
/*
|
||||||
/* void qmgr_queue_throttle(queue, reason)
|
/* void qmgr_queue_throttle(queue, reason)
|
||||||
/* QMGR_QUEUE *queue;
|
/* QMGR_QUEUE *queue;
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
/* qmgr_queue_count is a global counter for the total number
|
/* qmgr_queue_count is a global counter for the total number
|
||||||
/* of in-core queue structures.
|
/* of in-core queue structures.
|
||||||
/*
|
/*
|
||||||
/* qmgr_queue_create() creates an empty queue for the named
|
/* qmgr_queue_create() creates an empty named queue for the named
|
||||||
/* transport and destination. The queue is given an initial
|
/* transport and destination. The queue is given an initial
|
||||||
/* concurrency limit as specified with the
|
/* concurrency limit as specified with the
|
||||||
/* \fIinitial_destination_concurrency\fR configuration parameter,
|
/* \fIinitial_destination_concurrency\fR configuration parameter,
|
||||||
@@ -45,9 +46,8 @@
|
|||||||
/* its entries have been taken care of. It is an error to dispose
|
/* its entries have been taken care of. It is an error to dispose
|
||||||
/* of a dead queue.
|
/* of a dead queue.
|
||||||
/*
|
/*
|
||||||
/* qmgr_queue_find() looks up the queue for the named destination
|
/* qmgr_queue_find() looks up the named queue for the named
|
||||||
/* for the named transport. A null result means that the queue
|
/* transport. A null result means that the queue was not found.
|
||||||
/* was not found.
|
|
||||||
/*
|
/*
|
||||||
/* qmgr_queue_throttle() handles a delivery error, and decrements the
|
/* qmgr_queue_throttle() handles a delivery error, and decrements the
|
||||||
/* concurrency limit for the destination. When the concurrency limit
|
/* concurrency limit for the destination. When the concurrency limit
|
||||||
@@ -212,13 +212,15 @@ void qmgr_queue_done(QMGR_QUEUE *queue)
|
|||||||
QMGR_LIST_UNLINK(transport->queue_list, QMGR_QUEUE *, queue, peers);
|
QMGR_LIST_UNLINK(transport->queue_list, QMGR_QUEUE *, queue, peers);
|
||||||
htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
|
htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
|
||||||
myfree(queue->name);
|
myfree(queue->name);
|
||||||
|
myfree(queue->nexthop);
|
||||||
qmgr_queue_count--;
|
qmgr_queue_count--;
|
||||||
myfree((char *) queue);
|
myfree((char *) queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qmgr_queue_create - create in-core queue for site */
|
/* qmgr_queue_create - create in-core queue for site */
|
||||||
|
|
||||||
QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *name,
|
||||||
|
const char *nexthop)
|
||||||
{
|
{
|
||||||
QMGR_QUEUE *queue;
|
QMGR_QUEUE *queue;
|
||||||
|
|
||||||
@@ -229,7 +231,8 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
|||||||
|
|
||||||
queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
|
queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
|
||||||
qmgr_queue_count++;
|
qmgr_queue_count++;
|
||||||
queue->name = mystrdup(site);
|
queue->name = mystrdup(name);
|
||||||
|
queue->nexthop = mystrdup(nexthop);
|
||||||
queue->todo_refcount = 0;
|
queue->todo_refcount = 0;
|
||||||
queue->busy_refcount = 0;
|
queue->busy_refcount = 0;
|
||||||
queue->transport = transport;
|
queue->transport = transport;
|
||||||
@@ -240,13 +243,13 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
|||||||
queue->clog_time_to_warn = 0;
|
queue->clog_time_to_warn = 0;
|
||||||
queue->blocker_tag = 0;
|
queue->blocker_tag = 0;
|
||||||
QMGR_LIST_APPEND(transport->queue_list, queue, peers);
|
QMGR_LIST_APPEND(transport->queue_list, queue, peers);
|
||||||
htable_enter(transport->queue_byname, site, (char *) queue);
|
htable_enter(transport->queue_byname, name, (char *) queue);
|
||||||
return (queue);
|
return (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qmgr_queue_find - find in-core queue for site */
|
/* qmgr_queue_find - find in-core named queue */
|
||||||
|
|
||||||
QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *transport, const char *site)
|
QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *transport, const char *name)
|
||||||
{
|
{
|
||||||
return ((QMGR_QUEUE *) htable_find(transport->queue_byname, site));
|
return ((QMGR_QUEUE *) htable_find(transport->queue_byname, name));
|
||||||
}
|
}
|
||||||
|
@@ -61,6 +61,8 @@ proxymap.o: ../../include/msg.h
|
|||||||
proxymap.o: ../../include/mymalloc.h
|
proxymap.o: ../../include/mymalloc.h
|
||||||
proxymap.o: ../../include/vstring.h
|
proxymap.o: ../../include/vstring.h
|
||||||
proxymap.o: ../../include/vbuf.h
|
proxymap.o: ../../include/vbuf.h
|
||||||
|
proxymap.o: ../../include/htable.h
|
||||||
|
proxymap.o: ../../include/stringops.h
|
||||||
proxymap.o: ../../include/dict.h
|
proxymap.o: ../../include/dict.h
|
||||||
proxymap.o: ../../include/vstream.h
|
proxymap.o: ../../include/vstream.h
|
||||||
proxymap.o: ../../include/argv.h
|
proxymap.o: ../../include/argv.h
|
||||||
|
@@ -149,14 +149,14 @@
|
|||||||
char *var_local_rcpt_maps;
|
char *var_local_rcpt_maps;
|
||||||
char *var_virt_alias_maps;
|
char *var_virt_alias_maps;
|
||||||
char *var_virt_alias_doms;
|
char *var_virt_alias_doms;
|
||||||
char *var_virt_mbox_maps;
|
char *var_virt_mailbox_maps;
|
||||||
char *var_virt_mbox_doms;
|
char *var_virt_mailbox_doms;
|
||||||
char *var_relay_rcpt_maps;
|
char *var_relay_rcpt_maps;
|
||||||
char *var_relay_domains;
|
char *var_relay_domains;
|
||||||
char *var_canonical_maps;
|
char *var_canonical_maps;
|
||||||
char *var_send_canon_maps;
|
char *var_send_canon_maps;
|
||||||
char *var_rcpt_canon_maps;
|
char *var_rcpt_canon_maps;
|
||||||
char *var_relocatedmaps;
|
char *var_relocated_maps;
|
||||||
char *var_transport_maps;
|
char *var_transport_maps;
|
||||||
char *var_proxy_read_maps;
|
char *var_proxy_read_maps;
|
||||||
|
|
||||||
@@ -385,14 +385,14 @@ int main(int argc, char **argv)
|
|||||||
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
|
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
|
||||||
VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
|
VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
|
||||||
VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
|
VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
|
||||||
VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mbox_maps, 0, 0,
|
VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
|
||||||
VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mbox_doms, 0, 0,
|
VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms, 0, 0,
|
||||||
VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
|
VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
|
||||||
VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
|
VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
|
||||||
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
|
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
|
||||||
VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
|
VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
|
||||||
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
|
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
|
||||||
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocatedmaps, 0, 0,
|
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
|
||||||
VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
|
VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
|
||||||
VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
|
VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
|
||||||
0,
|
0,
|
||||||
|
@@ -186,6 +186,7 @@ qmgr_message.o: ../../include/verp_sender.h
|
|||||||
qmgr_message.o: ../../include/mail_proto.h
|
qmgr_message.o: ../../include/mail_proto.h
|
||||||
qmgr_message.o: ../../include/iostuff.h
|
qmgr_message.o: ../../include/iostuff.h
|
||||||
qmgr_message.o: ../../include/attr.h
|
qmgr_message.o: ../../include/attr.h
|
||||||
|
qmgr_message.o: ../../include/rewrite_clnt.h
|
||||||
qmgr_message.o: ../../include/resolve_clnt.h
|
qmgr_message.o: ../../include/resolve_clnt.h
|
||||||
qmgr_message.o: qmgr.h
|
qmgr_message.o: qmgr.h
|
||||||
qmgr_message.o: ../../include/scan_dir.h
|
qmgr_message.o: ../../include/scan_dir.h
|
||||||
|
@@ -140,7 +140,8 @@ struct QMGR_ENTRY_LIST {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct QMGR_QUEUE {
|
struct QMGR_QUEUE {
|
||||||
char *name; /* domain name */
|
char *name; /* domain name or address */
|
||||||
|
char *nexthop; /* domain name */
|
||||||
int todo_refcount; /* queue entries (todo list) */
|
int todo_refcount; /* queue entries (todo list) */
|
||||||
int busy_refcount; /* queue entries (busy list) */
|
int busy_refcount; /* queue entries (busy list) */
|
||||||
int window; /* slow open algorithm */
|
int window; /* slow open algorithm */
|
||||||
@@ -157,7 +158,7 @@ struct QMGR_QUEUE {
|
|||||||
|
|
||||||
extern int qmgr_queue_count;
|
extern int qmgr_queue_count;
|
||||||
|
|
||||||
extern QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *, const char *);
|
extern QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *, const char *, const char *);
|
||||||
extern QMGR_QUEUE *qmgr_queue_select(QMGR_TRANSPORT *);
|
extern QMGR_QUEUE *qmgr_queue_select(QMGR_TRANSPORT *);
|
||||||
extern void qmgr_queue_done(QMGR_QUEUE *);
|
extern void qmgr_queue_done(QMGR_QUEUE *);
|
||||||
extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *);
|
extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *);
|
||||||
@@ -231,6 +232,7 @@ struct QMGR_MESSAGE {
|
|||||||
char *return_receipt; /* confirm receipt address */
|
char *return_receipt; /* confirm receipt address */
|
||||||
char *filter_xport; /* filtering transport */
|
char *filter_xport; /* filtering transport */
|
||||||
char *inspect_xport; /* inspecting transport */
|
char *inspect_xport; /* inspecting transport */
|
||||||
|
char *redirect_addr; /* info@spammer.tld */
|
||||||
long data_size; /* message content size */
|
long data_size; /* message content size */
|
||||||
long rcpt_offset; /* more recipients here */
|
long rcpt_offset; /* more recipients here */
|
||||||
QMGR_RCPT_LIST rcpt_list; /* complete addresses */
|
QMGR_RCPT_LIST rcpt_list; /* complete addresses */
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
/* NAME
|
/* NAME
|
||||||
/* qmgr_deliver 3
|
/* qmgr_deliver 3
|
||||||
/* SUMMARY
|
/* SUMMARY
|
||||||
/* deliver one pe-site queue entry to that site
|
/* deliver one per-site queue entry to that site
|
||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* #include "qmgr.h"
|
/* #include "qmgr.h"
|
||||||
/*
|
/*
|
||||||
@@ -124,11 +124,9 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
|||||||
QMGR_RCPT_LIST list = entry->rcpt_list;
|
QMGR_RCPT_LIST list = entry->rcpt_list;
|
||||||
QMGR_RCPT *recipient;
|
QMGR_RCPT *recipient;
|
||||||
QMGR_MESSAGE *message = entry->message;
|
QMGR_MESSAGE *message = entry->message;
|
||||||
char *cp;
|
|
||||||
VSTRING *sender_buf = 0;
|
VSTRING *sender_buf = 0;
|
||||||
char *sender;
|
char *sender;
|
||||||
int flags;
|
int flags;
|
||||||
char *nexthop;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If variable envelope return path is requested, change prefix+@origin
|
* If variable envelope return path is requested, change prefix+@origin
|
||||||
@@ -144,28 +142,15 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
|||||||
sender = vstring_str(sender_buf);
|
sender = vstring_str(sender_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* With mail transports that accept only one recipient per delivery, the
|
|
||||||
* queue name is user@nexthop, so that we can implement per-recipient
|
|
||||||
* concurrency limits. However, the delivery agent protocol expects
|
|
||||||
* nexthop only, so we must strip off the recipient local part.
|
|
||||||
*
|
|
||||||
* XXX Should have separate fields for queue name and for destination, so
|
|
||||||
* that we don't have to make a special case for the error delivery agent
|
|
||||||
* (where nexthop is arbitrary text). See also: qmgr_message.c.
|
|
||||||
*/
|
|
||||||
flags = message->tflags
|
flags = message->tflags
|
||||||
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
|
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
|
||||||
nexthop = strcmp(entry->queue->transport->name, MAIL_SERVICE_ERROR) != 0
|
|
||||||
&& (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
|
|
||||||
cp + 1 : entry->queue->name;
|
|
||||||
attr_print(stream, ATTR_FLAG_MORE,
|
attr_print(stream, ATTR_FLAG_MORE,
|
||||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
|
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
|
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
|
||||||
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
|
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
|
||||||
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
|
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
|
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
|
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
|
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
|
||||||
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
|
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
|
||||||
|
@@ -239,7 +239,7 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_QUEUE *queue, QMGR_MESSAGE *message)
|
|||||||
&& (now = event_time()) >= queue->clog_time_to_warn) {
|
&& (now = event_time()) >= queue->clog_time_to_warn) {
|
||||||
active_share = queue_length / (double) qmgr_message_count;
|
active_share = queue_length / (double) qmgr_message_count;
|
||||||
msg_warn("mail for %s is using up %d of %d active queue entries",
|
msg_warn("mail for %s is using up %d of %d active queue entries",
|
||||||
queue->name, queue_length, qmgr_message_count);
|
queue->nexthop, queue_length, qmgr_message_count);
|
||||||
if (active_share < 0.9)
|
if (active_share < 0.9)
|
||||||
msg_warn("this may slow down other mail deliveries");
|
msg_warn("this may slow down other mail deliveries");
|
||||||
transport = queue->transport;
|
transport = queue->transport;
|
||||||
@@ -253,7 +253,7 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_QUEUE *queue, QMGR_MESSAGE *message)
|
|||||||
VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
|
VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
|
||||||
else if (queue->peers.next != queue->peers.prev)
|
else if (queue->peers.next != queue->peers.prev)
|
||||||
msg_warn("you may need a separate master.cf transport for %s",
|
msg_warn("you may need a separate master.cf transport for %s",
|
||||||
queue->name);
|
queue->nexthop);
|
||||||
else {
|
else {
|
||||||
msg_warn("you may need to reduce %s connect and helo timeouts",
|
msg_warn("you may need to reduce %s connect and helo timeouts",
|
||||||
transport->name);
|
transport->name);
|
||||||
|
@@ -115,6 +115,7 @@
|
|||||||
|
|
||||||
/* Client stubs. */
|
/* Client stubs. */
|
||||||
|
|
||||||
|
#include <rewrite_clnt.h>
|
||||||
#include <resolve_clnt.h>
|
#include <resolve_clnt.h>
|
||||||
|
|
||||||
/* Application-specific. */
|
/* Application-specific. */
|
||||||
@@ -149,6 +150,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
|
|||||||
message->return_receipt = 0;
|
message->return_receipt = 0;
|
||||||
message->filter_xport = 0;
|
message->filter_xport = 0;
|
||||||
message->inspect_xport = 0;
|
message->inspect_xport = 0;
|
||||||
|
message->redirect_addr = 0;
|
||||||
message->data_size = 0;
|
message->data_size = 0;
|
||||||
message->warn_offset = 0;
|
message->warn_offset = 0;
|
||||||
message->warn_time = 0;
|
message->warn_time = 0;
|
||||||
@@ -266,6 +268,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
if (message->inspect_xport != 0)
|
if (message->inspect_xport != 0)
|
||||||
myfree(message->inspect_xport);
|
myfree(message->inspect_xport);
|
||||||
message->inspect_xport = mystrdup(start);
|
message->inspect_xport = mystrdup(start);
|
||||||
|
} else if (rec_type == REC_TYPE_RDR) {
|
||||||
|
if (message->redirect_addr != 0)
|
||||||
|
myfree(message->redirect_addr);
|
||||||
|
message->redirect_addr = mystrdup(start);
|
||||||
} else if (rec_type == REC_TYPE_FROM) {
|
} else if (rec_type == REC_TYPE_FROM) {
|
||||||
if (message->sender == 0) {
|
if (message->sender == 0) {
|
||||||
message->sender = mystrdup(start);
|
message->sender = mystrdup(start);
|
||||||
@@ -452,14 +458,14 @@ static int qmgr_message_sort_compare(const void *p1, const void *p2)
|
|||||||
/*
|
/*
|
||||||
* Compare message transport.
|
* Compare message transport.
|
||||||
*/
|
*/
|
||||||
if ((result = strcasecmp(queue1->transport->name,
|
if ((result = strcmp(queue1->transport->name,
|
||||||
queue2->transport->name)) != 0)
|
queue2->transport->name)) != 0)
|
||||||
return (result);
|
return (result);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare next-hop hostname.
|
* Compare queue name (nexthop or recipient@nexthop).
|
||||||
*/
|
*/
|
||||||
if ((result = strcasecmp(queue1->name, queue2->name)) != 0)
|
if ((result = strcmp(queue1->name, queue2->name)) != 0)
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,6 +505,24 @@ static void qmgr_message_sort(QMGR_MESSAGE *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* qmgr_resolve_one - resolve or skip one recipient */
|
||||||
|
|
||||||
|
static int qmgr_resolve_one(QMGR_MESSAGE *message, QMGR_RCPT *recipient,
|
||||||
|
const char *addr, RESOLVE_REPLY *reply)
|
||||||
|
{
|
||||||
|
resolve_clnt_query(addr, reply);
|
||||||
|
if (reply->flags & RESOLVE_FLAG_FAIL) {
|
||||||
|
qmgr_defer_recipient(message, recipient, "address resolver failure");
|
||||||
|
return (-1);
|
||||||
|
} else if (reply->flags & RESOLVE_FLAG_ERROR) {
|
||||||
|
qmgr_bounce_recipient(message, recipient,
|
||||||
|
"bad address syntax: \"%s\"", addr);
|
||||||
|
return (-1);
|
||||||
|
} else {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* qmgr_message_resolve - resolve recipients */
|
/* qmgr_message_resolve - resolve recipients */
|
||||||
|
|
||||||
static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||||
@@ -509,6 +533,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
QMGR_TRANSPORT *transport = 0;
|
QMGR_TRANSPORT *transport = 0;
|
||||||
QMGR_QUEUE *queue = 0;
|
QMGR_QUEUE *queue = 0;
|
||||||
RESOLVE_REPLY reply;
|
RESOLVE_REPLY reply;
|
||||||
|
VSTRING *queue_name;
|
||||||
char *at;
|
char *at;
|
||||||
char **cpp;
|
char **cpp;
|
||||||
char *nexthop;
|
char *nexthop;
|
||||||
@@ -521,63 +546,75 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
|
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
|
||||||
|
|
||||||
resolve_clnt_init(&reply);
|
resolve_clnt_init(&reply);
|
||||||
|
queue_name = vstring_alloc(1);
|
||||||
for (recipient = list.info; recipient < list.info + list.len; recipient++) {
|
for (recipient = list.info; recipient < list.info + list.len; recipient++) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resolve the destination to (transport, nexthop, address). The
|
* Redirect overrides all else. But only once (per batch of
|
||||||
* result address may differ from the one specified by the sender.
|
* recipients). For consistency with the remainder of Postfix,
|
||||||
|
* rewrite the address to canonical form before resolving it.
|
||||||
*/
|
*/
|
||||||
if (var_sender_routing == 0) {
|
if (message->redirect_addr) {
|
||||||
resolve_clnt_query(recipient->address, &reply);
|
if (recipient > list.info) {
|
||||||
if (reply.flags & RESOLVE_FLAG_FAIL) {
|
recipient->queue = 0;
|
||||||
qmgr_defer_recipient(message, recipient,
|
|
||||||
"address resolver failure");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (reply.flags & RESOLVE_FLAG_ERROR) {
|
rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
|
||||||
qmgr_bounce_recipient(message, recipient,
|
reply.recipient);
|
||||||
"bad address syntax: \"%s\"",
|
UPDATE(recipient->address, STR(reply.recipient));
|
||||||
recipient->address);
|
if (qmgr_resolve_one(message, recipient,
|
||||||
|
recipient->address, &reply) < 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
if (!STREQ(recipient->address, STR(reply.recipient)))
|
||||||
} else {
|
UPDATE(recipient->address, STR(reply.recipient));
|
||||||
resolve_clnt_query(message->sender, &reply);
|
|
||||||
if (reply.flags & RESOLVE_FLAG_FAIL) {
|
|
||||||
qmgr_defer_recipient(message, recipient,
|
|
||||||
"address resolver failure");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (reply.flags & RESOLVE_FLAG_ERROR) {
|
|
||||||
qmgr_bounce_recipient(message, recipient,
|
|
||||||
"bad address syntax: \"%s\"",
|
|
||||||
message->sender);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vstring_strcpy(reply.recipient, recipient->address);
|
|
||||||
}
|
}
|
||||||
if (message->filter_xport) {
|
|
||||||
|
/*
|
||||||
|
* Content filtering overrides the address resolver.
|
||||||
|
*/
|
||||||
|
else if (message->filter_xport) {
|
||||||
vstring_strcpy(reply.transport, message->filter_xport);
|
vstring_strcpy(reply.transport, message->filter_xport);
|
||||||
if ((nexthop = split_at(STR(reply.transport), ':')) == 0
|
if ((nexthop = split_at(STR(reply.transport), ':')) == 0
|
||||||
|| *nexthop == 0)
|
|| *nexthop == 0)
|
||||||
nexthop = var_myhostname;
|
nexthop = var_myhostname;
|
||||||
vstring_strcpy(reply.nexthop, nexthop);
|
vstring_strcpy(reply.nexthop, nexthop);
|
||||||
} else {
|
vstring_strcpy(reply.recipient, recipient->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve the destination to (transport, nexthop, address). The
|
||||||
|
* result address may differ from the one specified by the sender.
|
||||||
|
*/
|
||||||
|
else if (var_sender_routing == 0) {
|
||||||
|
if (qmgr_resolve_one(message, recipient,
|
||||||
|
recipient->address, &reply) < 0)
|
||||||
|
continue;
|
||||||
if (!STREQ(recipient->address, STR(reply.recipient)))
|
if (!STREQ(recipient->address, STR(reply.recipient)))
|
||||||
UPDATE(recipient->address, STR(reply.recipient));
|
UPDATE(recipient->address, STR(reply.recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Sender-based routing does not work very well, because it has
|
||||||
|
* problems with sending bounces.
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
if (qmgr_resolve_one(message, recipient,
|
||||||
|
message->sender, &reply) < 0)
|
||||||
|
continue;
|
||||||
|
vstring_strcpy(reply.recipient, recipient->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bounce null recipients. This should never happen, but is most
|
||||||
|
* likely the result of a fault in a different program, so aborting
|
||||||
|
* the queue manager process does not help.
|
||||||
|
*/
|
||||||
if (recipient->address[0] == 0) {
|
if (recipient->address[0] == 0) {
|
||||||
qmgr_bounce_recipient(message, recipient,
|
qmgr_bounce_recipient(message, recipient,
|
||||||
"null recipient address");
|
"null recipient address");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX The nexthop destination is also used as lookup key for the
|
|
||||||
* per-destination queue. Fold the nexthop to lower case so that we
|
|
||||||
* don't have multiple queues for the same site.
|
|
||||||
*/
|
|
||||||
lowercase(STR(reply.nexthop));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bounce recipient addresses that start with `-'. External commands
|
* Bounce recipient addresses that start with `-'. External commands
|
||||||
* may misinterpret such addresses as command-line options.
|
* may misinterpret such addresses as command-line options.
|
||||||
@@ -596,46 +633,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Queues are identified by the transport name and by the next-hop
|
|
||||||
* hostname. When the delivery agent accepts only one recipient per
|
|
||||||
* delivery, give each recipient its own queue, so that deliveries to
|
|
||||||
* different recipients of the same message can happen in parallel.
|
|
||||||
* This also has the benefit that one bad recipient cannot interfere
|
|
||||||
* with deliveries to other recipients. XXX Should split the address
|
|
||||||
* on the recipient delimiter if one is defined, but doing a proper
|
|
||||||
* job requires knowledge of local aliases. Yuck! I don't want to
|
|
||||||
* duplicate delivery-agent specific knowledge in the queue manager.
|
|
||||||
*
|
|
||||||
* XXX The nexthop field is overloaded to serve as destination and as
|
|
||||||
* queue name. Should have separate fields for queue name and for
|
|
||||||
* destination, so that we don't have to make a special case for the
|
|
||||||
* error delivery agent (where nexthop is arbitrary text). See also:
|
|
||||||
* qmgr_deliver.c.
|
|
||||||
*/
|
|
||||||
at = strrchr(STR(reply.recipient), '@');
|
|
||||||
len = (at ? (at - STR(reply.recipient)) : strlen(STR(reply.recipient)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up or instantiate the proper transport. We're working a
|
|
||||||
* little ahead, doing queue management stuff that used to be done
|
|
||||||
* way down.
|
|
||||||
*/
|
|
||||||
if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
|
|
||||||
if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
|
|
||||||
transport = qmgr_transport_create(STR(reply.transport));
|
|
||||||
queue = 0;
|
|
||||||
}
|
|
||||||
if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
|
|
||||||
&& transport->recipient_limit == 1) {
|
|
||||||
VSTRING_SPACE(reply.nexthop, len + 2);
|
|
||||||
memmove(STR(reply.nexthop) + len + 1, STR(reply.nexthop),
|
|
||||||
LEN(reply.nexthop) + 1);
|
|
||||||
memcpy(STR(reply.nexthop), STR(reply.recipient), len);
|
|
||||||
STR(reply.nexthop)[len] = '@';
|
|
||||||
lowercase(STR(reply.nexthop));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Discard mail to the local double bounce address here, so this
|
* Discard mail to the local double bounce address here, so this
|
||||||
* system can run without a local delivery agent. They'd still have
|
* system can run without a local delivery agent. They'd still have
|
||||||
@@ -646,6 +643,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
* be directed to a general-purpose null delivery agent.
|
* be directed to a general-purpose null delivery agent.
|
||||||
*/
|
*/
|
||||||
if (reply.flags & RESOLVE_CLASS_LOCAL) {
|
if (reply.flags & RESOLVE_CLASS_LOCAL) {
|
||||||
|
at = strrchr(STR(reply.recipient), '@');
|
||||||
|
len = (at ? (at - STR(reply.recipient))
|
||||||
|
: strlen(STR(reply.recipient)));
|
||||||
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
|
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
|
||||||
len) == 0
|
len) == 0
|
||||||
&& !var_double_bounce_sender[len]) {
|
&& !var_double_bounce_sender[len]) {
|
||||||
@@ -678,16 +678,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX Gross hack alert. We want to group recipients by transport and
|
|
||||||
* by next-hop hostname, in order to minimize the number of network
|
|
||||||
* transactions. However, it would be wasteful to have an in-memory
|
|
||||||
* resolver reply structure for each in-core recipient. Instead, we
|
|
||||||
* bind each recipient to an in-core queue instance which is needed
|
|
||||||
* anyway. That gives all information needed for recipient grouping.
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up or instantiate the proper transport.
|
* Look up or instantiate the proper transport.
|
||||||
*/
|
*/
|
||||||
@@ -696,7 +686,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
transport = qmgr_transport_create(STR(reply.transport));
|
transport = qmgr_transport_create(STR(reply.transport));
|
||||||
queue = 0;
|
queue = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This transport is dead. Defer delivery to this recipient.
|
* This transport is dead. Defer delivery to this recipient.
|
||||||
@@ -706,13 +695,50 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The nexthop destination provides the default name for the
|
||||||
|
* per-destination queue. When the delivery agent accepts only one
|
||||||
|
* recipient per delivery, give each recipient its own queue, so that
|
||||||
|
* deliveries to different recipients of the same message can happen
|
||||||
|
* in parallel, and so that we can enforce per-recipient concurrency
|
||||||
|
* limits and prevent one recipient from tying up all the delivery
|
||||||
|
* agent resources. We use recipient@nexthop as queue name rather
|
||||||
|
* than the actual recipient domain name, so that one recipient in
|
||||||
|
* multiple equivalent domains cannot evade the per-recipient
|
||||||
|
* concurrency limit. XXX Should split the address on the recipient
|
||||||
|
* delimiter if one is defined, but doing a proper job requires
|
||||||
|
* knowledge of local aliases. Yuck! I don't want to duplicate
|
||||||
|
* delivery-agent specific knowledge in the queue manager.
|
||||||
|
*
|
||||||
|
* Fold the result to lower case so that we don't have multiple queues
|
||||||
|
* for the same name.
|
||||||
|
*
|
||||||
|
* Important! All recipients in a queue must have the same nexthop
|
||||||
|
* value. It is OK to have multiple queues with the same nexthop
|
||||||
|
* value, but only when those queues are named after recipients.
|
||||||
|
*/
|
||||||
|
vstring_strcpy(queue_name, STR(reply.nexthop));
|
||||||
|
if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
|
||||||
|
&& transport->recipient_limit == 1) {
|
||||||
|
at = strrchr(STR(reply.recipient), '@');
|
||||||
|
len = (at ? (at - STR(reply.recipient))
|
||||||
|
: strlen(STR(reply.recipient)));
|
||||||
|
VSTRING_SPACE(queue_name, len + 2);
|
||||||
|
memmove(STR(queue_name) + len + 1, STR(queue_name),
|
||||||
|
LEN(queue_name) + 1);
|
||||||
|
memcpy(STR(queue_name), STR(reply.recipient), len);
|
||||||
|
STR(queue_name)[len] = '@';
|
||||||
|
}
|
||||||
|
lowercase(STR(queue_name));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This transport is alive. Find or instantiate a queue for this
|
* This transport is alive. Find or instantiate a queue for this
|
||||||
* recipient.
|
* recipient.
|
||||||
*/
|
*/
|
||||||
if (queue == 0 || !STREQ(queue->name, STR(reply.nexthop))) {
|
if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
|
||||||
if ((queue = qmgr_queue_find(transport, STR(reply.nexthop))) == 0)
|
if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
|
||||||
queue = qmgr_queue_create(transport, STR(reply.nexthop));
|
queue = qmgr_queue_create(transport, STR(queue_name),
|
||||||
|
STR(reply.nexthop));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -729,6 +755,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
recipient->queue = queue;
|
recipient->queue = queue;
|
||||||
}
|
}
|
||||||
resolve_clnt_free(&reply);
|
resolve_clnt_free(&reply);
|
||||||
|
vstring_free(queue_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qmgr_message_assign - assign recipients to specific delivery requests */
|
/* qmgr_message_assign - assign recipients to specific delivery requests */
|
||||||
@@ -791,6 +818,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
|||||||
myfree(message->filter_xport);
|
myfree(message->filter_xport);
|
||||||
if (message->inspect_xport)
|
if (message->inspect_xport)
|
||||||
myfree(message->inspect_xport);
|
myfree(message->inspect_xport);
|
||||||
|
if (message->redirect_addr)
|
||||||
|
myfree(message->redirect_addr);
|
||||||
qmgr_rcpt_list_free(&message->rcpt_list);
|
qmgr_rcpt_list_free(&message->rcpt_list);
|
||||||
qmgr_message_count--;
|
qmgr_message_count--;
|
||||||
myfree((char *) message);
|
myfree((char *) message);
|
||||||
|
@@ -8,16 +8,17 @@
|
|||||||
/*
|
/*
|
||||||
/* int qmgr_queue_count;
|
/* int qmgr_queue_count;
|
||||||
/*
|
/*
|
||||||
/* QMGR_QUEUE *qmgr_queue_create(transport, site)
|
/* QMGR_QUEUE *qmgr_queue_create(transport, name, nexthop)
|
||||||
/* QMGR_TRANSPORT *transport;
|
/* QMGR_TRANSPORT *transport;
|
||||||
/* const char *site;
|
/* const char *name;
|
||||||
|
/* const char *nexthop;
|
||||||
/*
|
/*
|
||||||
/* void qmgr_queue_done(queue)
|
/* void qmgr_queue_done(queue)
|
||||||
/* QMGR_QUEUE *queue;
|
/* QMGR_QUEUE *queue;
|
||||||
/*
|
/*
|
||||||
/* QMGR_QUEUE *qmgr_queue_find(transport, site)
|
/* QMGR_QUEUE *qmgr_queue_find(transport, name)
|
||||||
/* QMGR_TRANSPORT *transport;
|
/* QMGR_TRANSPORT *transport;
|
||||||
/* const char *site;
|
/* const char *name;
|
||||||
/*
|
/*
|
||||||
/* QMGR_QUEUE *qmgr_queue_select(transport)
|
/* QMGR_QUEUE *qmgr_queue_select(transport)
|
||||||
/* QMGR_TRANSPORT *transport;
|
/* QMGR_TRANSPORT *transport;
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
/* qmgr_queue_count is a global counter for the total number
|
/* qmgr_queue_count is a global counter for the total number
|
||||||
/* of in-core queue structures.
|
/* of in-core queue structures.
|
||||||
/*
|
/*
|
||||||
/* qmgr_queue_create() creates an empty queue for the named
|
/* qmgr_queue_create() creates an empty named queue for the named
|
||||||
/* transport and destination. The queue is given an initial
|
/* transport and destination. The queue is given an initial
|
||||||
/* concurrency limit as specified with the
|
/* concurrency limit as specified with the
|
||||||
/* \fIinitial_destination_concurrency\fR configuration parameter,
|
/* \fIinitial_destination_concurrency\fR configuration parameter,
|
||||||
@@ -48,9 +49,8 @@
|
|||||||
/* its entries have been taken care of. It is an error to dispose
|
/* its entries have been taken care of. It is an error to dispose
|
||||||
/* of a dead queue.
|
/* of a dead queue.
|
||||||
/*
|
/*
|
||||||
/* qmgr_queue_find() looks up the queue for the named destination
|
/* qmgr_queue_find() looks up the named queue for the named
|
||||||
/* for the named transport. A null result means that the queue
|
/* transport. A null result means that the queue was not found.
|
||||||
/* was not found.
|
|
||||||
/*
|
/*
|
||||||
/* qmgr_queue_select() uses a round-robin strategy to select
|
/* qmgr_queue_select() uses a round-robin strategy to select
|
||||||
/* from the named transport one per-destination queue with a
|
/* from the named transport one per-destination queue with a
|
||||||
@@ -235,13 +235,15 @@ void qmgr_queue_done(QMGR_QUEUE *queue)
|
|||||||
QMGR_LIST_UNLINK(transport->queue_list, QMGR_QUEUE *, queue);
|
QMGR_LIST_UNLINK(transport->queue_list, QMGR_QUEUE *, queue);
|
||||||
htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
|
htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
|
||||||
myfree(queue->name);
|
myfree(queue->name);
|
||||||
|
myfree(queue->nexthop);
|
||||||
qmgr_queue_count--;
|
qmgr_queue_count--;
|
||||||
myfree((char *) queue);
|
myfree((char *) queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qmgr_queue_create - create in-core queue for site */
|
/* qmgr_queue_create - create in-core queue for site */
|
||||||
|
|
||||||
QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *name,
|
||||||
|
const char *nexthop)
|
||||||
{
|
{
|
||||||
QMGR_QUEUE *queue;
|
QMGR_QUEUE *queue;
|
||||||
|
|
||||||
@@ -252,7 +254,8 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
|||||||
|
|
||||||
queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
|
queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
|
||||||
qmgr_queue_count++;
|
qmgr_queue_count++;
|
||||||
queue->name = mystrdup(site);
|
queue->name = mystrdup(name);
|
||||||
|
queue->nexthop = mystrdup(nexthop);
|
||||||
queue->todo_refcount = 0;
|
queue->todo_refcount = 0;
|
||||||
queue->busy_refcount = 0;
|
queue->busy_refcount = 0;
|
||||||
queue->transport = transport;
|
queue->transport = transport;
|
||||||
@@ -262,13 +265,13 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
|||||||
queue->reason = 0;
|
queue->reason = 0;
|
||||||
queue->clog_time_to_warn = 0;
|
queue->clog_time_to_warn = 0;
|
||||||
QMGR_LIST_PREPEND(transport->queue_list, queue);
|
QMGR_LIST_PREPEND(transport->queue_list, queue);
|
||||||
htable_enter(transport->queue_byname, site, (char *) queue);
|
htable_enter(transport->queue_byname, name, (char *) queue);
|
||||||
return (queue);
|
return (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qmgr_queue_find - find in-core queue for site */
|
/* qmgr_queue_find - find in-core named queue */
|
||||||
|
|
||||||
QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *transport, const char *site)
|
QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *transport, const char *name)
|
||||||
{
|
{
|
||||||
return ((QMGR_QUEUE *) htable_find(transport->queue_byname, site));
|
return ((QMGR_QUEUE *) htable_find(transport->queue_byname, name));
|
||||||
}
|
}
|
||||||
|
@@ -221,6 +221,7 @@ smtpd_check.o: ../../include/rec_type.h
|
|||||||
smtpd_check.o: ../../include/mail_proto.h
|
smtpd_check.o: ../../include/mail_proto.h
|
||||||
smtpd_check.o: ../../include/iostuff.h
|
smtpd_check.o: ../../include/iostuff.h
|
||||||
smtpd_check.o: ../../include/attr.h
|
smtpd_check.o: ../../include/attr.h
|
||||||
|
smtpd_check.o: ../../include/mail_addr.h
|
||||||
smtpd_check.o: ../../include/verify_clnt.h
|
smtpd_check.o: ../../include/verify_clnt.h
|
||||||
smtpd_check.o: ../../include/deliver_request.h
|
smtpd_check.o: ../../include/deliver_request.h
|
||||||
smtpd_check.o: ../../include/recipient_list.h
|
smtpd_check.o: ../../include/recipient_list.h
|
||||||
|
@@ -1752,11 +1752,11 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
|||||||
*/
|
*/
|
||||||
if (STREQUAL(value, "FILTER", cmd_len)) {
|
if (STREQUAL(value, "FILTER", cmd_len)) {
|
||||||
if (*cmd_text == 0) {
|
if (*cmd_text == 0) {
|
||||||
msg_warn("access map %s entry %s has FILTER entry without value",
|
msg_warn("access map %s entry \"%s\" has FILTER entry without value",
|
||||||
table, datum);
|
table, datum);
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
} else if (strchr(cmd_text, ':') == 0) {
|
} else if (strchr(cmd_text, ':') == 0) {
|
||||||
msg_warn("access map %s entry %s requires transport:destination",
|
msg_warn("access map %s entry \"%s\" requires transport:destination",
|
||||||
table, datum);
|
table, datum);
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
} else {
|
} else {
|
||||||
@@ -1802,6 +1802,26 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
|||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REDIRECT means deliver to designated recipient. But we may still
|
||||||
|
* change our mind, and reject/discard the message for other reasons.
|
||||||
|
*/
|
||||||
|
if (STREQUAL(value, "REDIRECT", cmd_len)) {
|
||||||
|
if (strchr(cmd_text, '@') == 0) {
|
||||||
|
msg_warn("access map %s entry \"%s\" requires user@domain target",
|
||||||
|
table, datum);
|
||||||
|
return (SMTPD_CHECK_DUNNO);
|
||||||
|
} else {
|
||||||
|
vstring_sprintf(error_text, "<%s>: %s triggers REDIRECT %s",
|
||||||
|
reply_name, reply_class, cmd_text);
|
||||||
|
log_whatsup(state, "redirect", STR(error_text));
|
||||||
|
#ifndef TEST
|
||||||
|
rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", cmd_text);
|
||||||
|
#endif
|
||||||
|
return (SMTPD_CHECK_DUNNO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All-numeric result probably means OK - some out-of-band authentication
|
* All-numeric result probably means OK - some out-of-band authentication
|
||||||
* mechanism uses this as time stamp.
|
* mechanism uses this as time stamp.
|
||||||
@@ -3309,13 +3329,13 @@ static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient)
|
|||||||
|
|
||||||
if ((reply->flags & RESOLVE_CLASS_LOCAL)
|
if ((reply->flags & RESOLVE_CLASS_LOCAL)
|
||||||
&& *var_local_rcpt_maps
|
&& *var_local_rcpt_maps
|
||||||
/* Generated by bounce, absorbed by qmgr. */
|
/* Generated by bounce, absorbed by qmgr. */
|
||||||
&& !MATCH_LEFT(var_double_bounce_sender, CONST_STR(reply->recipient),
|
&& !MATCH_LEFT(var_double_bounce_sender, CONST_STR(reply->recipient),
|
||||||
strlen(var_double_bounce_sender))
|
strlen(var_double_bounce_sender))
|
||||||
/* Absorbed by qmgr. */
|
/* Absorbed by qmgr. */
|
||||||
&& !MATCH_LEFT(MAIL_ADDR_POSTMASTER, CONST_STR(reply->recipient),
|
&& !MATCH_LEFT(MAIL_ADDR_POSTMASTER, CONST_STR(reply->recipient),
|
||||||
strlen(MAIL_ADDR_POSTMASTER))
|
strlen(MAIL_ADDR_POSTMASTER))
|
||||||
/* Generated by bounce. */
|
/* Generated by bounce. */
|
||||||
&& !MATCH_LEFT(MAIL_ADDR_MAIL_DAEMON, CONST_STR(reply->recipient),
|
&& !MATCH_LEFT(MAIL_ADDR_MAIL_DAEMON, CONST_STR(reply->recipient),
|
||||||
strlen(MAIL_ADDR_MAIL_DAEMON))
|
strlen(MAIL_ADDR_MAIL_DAEMON))
|
||||||
&& NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient)))
|
&& NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient)))
|
||||||
|
@@ -624,6 +624,18 @@ dict_open.o: split_at.h
|
|||||||
dict_open.o: htable.h
|
dict_open.o: htable.h
|
||||||
dict_pcre.o: dict_pcre.c
|
dict_pcre.o: dict_pcre.c
|
||||||
dict_pcre.o: sys_defs.h
|
dict_pcre.o: sys_defs.h
|
||||||
|
dict_pcre.o: mymalloc.h
|
||||||
|
dict_pcre.o: msg.h
|
||||||
|
dict_pcre.o: safe.h
|
||||||
|
dict_pcre.o: vstream.h
|
||||||
|
dict_pcre.o: vbuf.h
|
||||||
|
dict_pcre.o: vstring.h
|
||||||
|
dict_pcre.o: stringops.h
|
||||||
|
dict_pcre.o: readlline.h
|
||||||
|
dict_pcre.o: dict.h
|
||||||
|
dict_pcre.o: argv.h
|
||||||
|
dict_pcre.o: dict_pcre.h
|
||||||
|
dict_pcre.o: mac_parse.h
|
||||||
dict_regexp.o: dict_regexp.c
|
dict_regexp.o: dict_regexp.c
|
||||||
dict_regexp.o: sys_defs.h
|
dict_regexp.o: sys_defs.h
|
||||||
dict_regexp.o: mymalloc.h
|
dict_regexp.o: mymalloc.h
|
||||||
|
Reference in New Issue
Block a user