mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +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,
|
||||
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:
|
||||
|
||||
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
|
||||
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
|
||||
=========================================================
|
||||
|
||||
|
@@ -164,8 +164,17 @@
|
||||
# about content filters is in the Postfix FIL-
|
||||
# TER_README file.
|
||||
#
|
||||
# Note: this action currently affects all recipients
|
||||
# of the message.
|
||||
# Note: this action overrides the main.cf con-
|
||||
# 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...
|
||||
# Apply the named UCE restriction(s) (permit, reject,
|
||||
|
@@ -38,6 +38,9 @@
|
||||
# off in the second cleanup server. More info about content
|
||||
# filtering 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.
|
||||
#
|
||||
# By default, these patterns apply the primary message headers, to
|
||||
# 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
|
||||
# filtering 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.
|
||||
#
|
||||
# By default, the same patterns are applied as for header_checks.
|
||||
#
|
||||
|
@@ -51,7 +51,12 @@
|
||||
# and after the filter, with header/body
|
||||
# checks turned off in the second cleanup
|
||||
# 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
|
||||
# possible using the conventional perl syntax. The macros in the
|
||||
|
@@ -52,7 +52,12 @@
|
||||
# and after the filter, with header/body
|
||||
# checks turned off in the second cleanup
|
||||
# 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
|
||||
# possible using the conventional perl syntax. The macros in the
|
||||
|
@@ -43,7 +43,11 @@
|
||||
# After the message is queued, send the entire message through
|
||||
# a content filter. This requires different cleanup servers
|
||||
# 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.
|
||||
# Expressions by Liviu Daia. Amended by Victor Duchovni.
|
||||
|
@@ -43,7 +43,11 @@
|
||||
# After the message is queued, send the entire message through
|
||||
# a content filter. This requires different cleanup servers
|
||||
# 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
|
||||
/^To: friend@public.com/ REJECT
|
||||
|
@@ -266,6 +266,8 @@ mynetworks_style = subnet
|
||||
# Discard the message if the result is DISCARD text...
|
||||
# Hold the message in the queue if the result is HOLD text...
|
||||
# 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.
|
||||
# reject_rbl_client domain.tld: reject if the reversed client IP address
|
||||
# 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...
|
||||
# Hold the message in the queue if the result is HOLD text...
|
||||
# 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.
|
||||
# reject: reject 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...
|
||||
# Hold the message in the queue if the result is HOLD text...
|
||||
# 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.
|
||||
# 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
|
||||
@@ -423,6 +429,8 @@ smtpd_sender_restrictions =
|
||||
# Discard the message if the result is DISCARD text...
|
||||
# Hold the message in the queue if the result is HOLD text...
|
||||
# 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.
|
||||
# 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.
|
||||
|
@@ -165,8 +165,17 @@ ACCESS(5) ACCESS(5)
|
||||
about content filters is in the Postfix FIL-
|
||||
TER_README file.
|
||||
|
||||
Note: this action currently affects all recipients
|
||||
of the message.
|
||||
Note: this action overrides the <b>main.cf</b> <b>con-</b>
|
||||
<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>
|
||||
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
|
||||
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>
|
||||
|
||||
<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
|
||||
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>
|
||||
|
||||
<p>
|
||||
|
@@ -152,7 +152,14 @@ After the message is queued, send the entire message through
|
||||
a content filter. More information about content filters
|
||||
is in the Postfix FILTER_README file.
|
||||
.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
|
||||
Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
|
||||
\fBreject_unauth_destination\fR, and so on).
|
||||
|
@@ -63,7 +63,7 @@
|
||||
# Note: lookup of the null sender address is not possible with
|
||||
# some types of lookup table. By default, Postfix uses \fB<>\fR
|
||||
# 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.
|
||||
# ADDRESS EXTENSION
|
||||
# .fi
|
||||
@@ -100,8 +100,8 @@
|
||||
# the numerical code and text.
|
||||
# .IP \fBREJECT\fR
|
||||
# .IP "\fBREJECT \fIoptional text...\fR
|
||||
# Reject the address etc. that matches the pattern. Reply with
|
||||
# \fI$reject_code optional text...\fR when the optional text is
|
||||
# Reject the address etc. that matches the pattern. Reply with
|
||||
# \fI$reject_code optional text...\fR when the optional text is
|
||||
# specified, otherwise reply with a generic error response message.
|
||||
# .IP \fBOK\fR
|
||||
# Accept the address etc. that matches the pattern.
|
||||
@@ -136,7 +136,14 @@
|
||||
# a content filter. More information about content filters
|
||||
# is in the Postfix FILTER_README file.
|
||||
# .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
|
||||
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
|
||||
# \fBreject_unauth_destination\fR, and so on).
|
||||
|
@@ -67,6 +67,7 @@ typedef struct CLEANUP_STATE {
|
||||
MIME_STATE *mime_state; /* MIME state engine */
|
||||
int mime_errs; /* MIME error flags */
|
||||
char *filter; /* from header/body patterns */
|
||||
char *redirect; /* from header/body patterns */
|
||||
} CLEANUP_STATE;
|
||||
|
||||
/*
|
||||
|
@@ -89,6 +89,14 @@ void cleanup_extracted(CLEANUP_STATE *state, int type, char *buf, int len)
|
||||
if (state->filter != 0)
|
||||
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
|
||||
* 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 {
|
||||
if (state->filter)
|
||||
myfree(state->filter);
|
||||
/* XXX should log something? */
|
||||
state->filter = mystrdup(optional_text);
|
||||
cleanup_act_log(state, "filter", context, buf, optional_text);
|
||||
}
|
||||
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;
|
||||
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)
|
||||
msg_warn("unexpected text after command in %s map: %s",
|
||||
map_class, value);
|
||||
|
@@ -92,6 +92,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
|
||||
state->mime_state = 0;
|
||||
state->mime_errs = 0;
|
||||
state->filter = 0;
|
||||
state->redirect = 0;
|
||||
return (state);
|
||||
}
|
||||
|
||||
@@ -131,5 +132,7 @@ void cleanup_state_free(CLEANUP_STATE *state)
|
||||
mime_state_free(state->mime_state);
|
||||
if (state->filter)
|
||||
myfree(state->filter);
|
||||
if (state->redirect)
|
||||
myfree(state->redirect);
|
||||
myfree((char *) state);
|
||||
}
|
||||
|
@@ -1157,6 +1157,12 @@ resolve_local.o: mail_params.h
|
||||
resolve_local.o: own_inet_addr.h
|
||||
resolve_local.o: resolve_local.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: ../../include/sys_defs.h
|
||||
rewrite_clnt.o: ../../include/msg.h
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* Patches change the patchlevel and the release date. Snapshots change the
|
||||
* 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 DEF_MAIL_VERSION "2.0.3-" MAIL_RELEASE_DATE
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#define REC_TYPE_WARN 'W' /* warning message time */
|
||||
#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_MESG 'M' /* start message records */
|
||||
@@ -64,9 +65,9 @@
|
||||
* 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'.
|
||||
*/
|
||||
#define REC_TYPE_ENVELOPE "MCTFILSDROWVA"
|
||||
#define REC_TYPE_ENVELOPE "MCTFILSDROWVA>"
|
||||
#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
|
||||
|
@@ -199,6 +199,7 @@ qmgr_message.o: ../../include/verp_sender.h
|
||||
qmgr_message.o: ../../include/mail_proto.h
|
||||
qmgr_message.o: ../../include/iostuff.h
|
||||
qmgr_message.o: ../../include/attr.h
|
||||
qmgr_message.o: ../../include/rewrite_clnt.h
|
||||
qmgr_message.o: ../../include/resolve_clnt.h
|
||||
qmgr_message.o: qmgr.h
|
||||
qmgr_message.o: ../../include/scan_dir.h
|
||||
|
@@ -176,7 +176,8 @@ struct QMGR_ENTRY_LIST {
|
||||
};
|
||||
|
||||
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 busy_refcount; /* queue entries (busy list) */
|
||||
int window; /* slow open algorithm */
|
||||
@@ -194,7 +195,7 @@ struct QMGR_QUEUE {
|
||||
|
||||
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_throttle(QMGR_QUEUE *, const char *);
|
||||
extern void qmgr_queue_unthrottle(QMGR_QUEUE *);
|
||||
@@ -271,6 +272,7 @@ struct QMGR_MESSAGE {
|
||||
char *return_receipt; /* confirm receipt address */
|
||||
char *filter_xport; /* filtering transport */
|
||||
char *inspect_xport; /* inspecting transport */
|
||||
char *redirect_addr; /* info@spammer.tld */
|
||||
long data_size; /* message content size */
|
||||
long rcpt_offset; /* more 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 *recipient;
|
||||
QMGR_MESSAGE *message = entry->message;
|
||||
char *cp;
|
||||
VSTRING *sender_buf = 0;
|
||||
char *sender;
|
||||
int flags;
|
||||
char *nexthop;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
| (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_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
|
||||
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
|
||||
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_SENDER, sender,
|
||||
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) {
|
||||
active_share = queue_length / (double) qmgr_message_count;
|
||||
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)
|
||||
msg_warn("this may slow down other mail deliveries");
|
||||
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);
|
||||
else if (queue->peers.next != queue->peers.prev)
|
||||
msg_warn("you may need a separate master.cf transport for %s",
|
||||
queue->name);
|
||||
queue->nexthop);
|
||||
else {
|
||||
msg_warn("you may need to reduce %s connect and helo timeouts",
|
||||
transport->name);
|
||||
|
@@ -124,6 +124,7 @@
|
||||
|
||||
/* Client stubs. */
|
||||
|
||||
#include <rewrite_clnt.h>
|
||||
#include <resolve_clnt.h>
|
||||
|
||||
/* Application-specific. */
|
||||
@@ -159,6 +160,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
|
||||
message->return_receipt = 0;
|
||||
message->filter_xport = 0;
|
||||
message->inspect_xport = 0;
|
||||
message->redirect_addr = 0;
|
||||
message->data_size = 0;
|
||||
message->warn_offset = 0;
|
||||
message->warn_time = 0;
|
||||
@@ -385,6 +387,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
if (message->inspect_xport != 0)
|
||||
myfree(message->inspect_xport);
|
||||
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) {
|
||||
if (message->sender == 0) {
|
||||
message->sender = mystrdup(start);
|
||||
@@ -577,7 +583,7 @@ static int qmgr_message_sort_compare(const void *p1, const void *p2)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Compare (already lowercased) next-hop hostname.
|
||||
* Compare queue name (nexthop or recipient@nexthop).
|
||||
*/
|
||||
if ((result = strcmp(queue1->name, queue2->name)) != 0)
|
||||
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 */
|
||||
|
||||
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_QUEUE *queue = 0;
|
||||
RESOLVE_REPLY reply;
|
||||
VSTRING *queue_name;
|
||||
char *at;
|
||||
char **cpp;
|
||||
char *nexthop;
|
||||
@@ -641,63 +666,75 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
|
||||
|
||||
resolve_clnt_init(&reply);
|
||||
queue_name = vstring_alloc(1);
|
||||
for (recipient = list.info; recipient < list.info + list.len; recipient++) {
|
||||
|
||||
/*
|
||||
* Resolve the destination to (transport, nexthop, address). The
|
||||
* result address may differ from the one specified by the sender.
|
||||
* Redirect overrides all else. But only once (per batch of
|
||||
* recipients). For consistency with the remainder of Postfix,
|
||||
* rewrite the address to canonical form before resolving it.
|
||||
*/
|
||||
if (var_sender_routing == 0) {
|
||||
resolve_clnt_query(recipient->address, &reply);
|
||||
if (reply.flags & RESOLVE_FLAG_FAIL) {
|
||||
qmgr_defer_recipient(message, recipient,
|
||||
"address resolver failure");
|
||||
if (message->redirect_addr) {
|
||||
if (recipient > list.info) {
|
||||
recipient->queue = 0;
|
||||
continue;
|
||||
}
|
||||
if (reply.flags & RESOLVE_FLAG_ERROR) {
|
||||
qmgr_bounce_recipient(message, recipient,
|
||||
"bad address syntax: \"%s\"",
|
||||
recipient->address);
|
||||
rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
|
||||
reply.recipient);
|
||||
UPDATE(recipient->address, STR(reply.recipient));
|
||||
if (qmgr_resolve_one(message, recipient,
|
||||
recipient->address, &reply) < 0)
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
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 (!STREQ(recipient->address, STR(reply.recipient)))
|
||||
UPDATE(recipient->address, STR(reply.recipient));
|
||||
}
|
||||
if (message->filter_xport) {
|
||||
|
||||
/*
|
||||
* Content filtering overrides the address resolver.
|
||||
*/
|
||||
else if (message->filter_xport) {
|
||||
vstring_strcpy(reply.transport, message->filter_xport);
|
||||
if ((nexthop = split_at(STR(reply.transport), ':')) == 0
|
||||
|| *nexthop == 0)
|
||||
nexthop = var_myhostname;
|
||||
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)))
|
||||
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) {
|
||||
qmgr_bounce_recipient(message, recipient,
|
||||
"null recipient address");
|
||||
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
|
||||
* may misinterpret such addresses as command-line options.
|
||||
@@ -716,46 +753,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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,
|
||||
len) == 0
|
||||
&& !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.
|
||||
*/
|
||||
@@ -816,7 +806,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
transport = qmgr_transport_create(STR(reply.transport));
|
||||
queue = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This transport is dead. Defer delivery to this recipient.
|
||||
@@ -826,13 +815,50 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
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
|
||||
* recipient.
|
||||
*/
|
||||
if (queue == 0 || !STREQ(queue->name, STR(reply.nexthop))) {
|
||||
if ((queue = qmgr_queue_find(transport, STR(reply.nexthop))) == 0)
|
||||
queue = qmgr_queue_create(transport, STR(reply.nexthop));
|
||||
if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
|
||||
if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
|
||||
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;
|
||||
}
|
||||
resolve_clnt_free(&reply);
|
||||
vstring_free(queue_name);
|
||||
}
|
||||
|
||||
/* qmgr_message_assign - assign recipients to specific delivery requests */
|
||||
@@ -973,6 +1000,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
||||
myfree(message->filter_xport);
|
||||
if (message->inspect_xport)
|
||||
myfree(message->inspect_xport);
|
||||
if (message->redirect_addr)
|
||||
myfree(message->redirect_addr);
|
||||
qmgr_rcpt_list_free(&message->rcpt_list);
|
||||
qmgr_message_count--;
|
||||
myfree((char *) message);
|
||||
|
@@ -8,16 +8,17 @@
|
||||
/*
|
||||
/* int qmgr_queue_count;
|
||||
/*
|
||||
/* QMGR_QUEUE *qmgr_queue_create(transport, site)
|
||||
/* QMGR_QUEUE *qmgr_queue_create(transport, name, nexthop)
|
||||
/* QMGR_TRANSPORT *transport;
|
||||
/* const char *site;
|
||||
/* const char *name;
|
||||
/* const char *nexthop;
|
||||
/*
|
||||
/* void qmgr_queue_done(queue)
|
||||
/* QMGR_QUEUE *queue;
|
||||
/*
|
||||
/* QMGR_QUEUE *qmgr_queue_find(transport, site)
|
||||
/* QMGR_QUEUE *qmgr_queue_find(transport, name)
|
||||
/* QMGR_TRANSPORT *transport;
|
||||
/* const char *site;
|
||||
/* const char *name;
|
||||
/*
|
||||
/* void qmgr_queue_throttle(queue, reason)
|
||||
/* QMGR_QUEUE *queue;
|
||||
@@ -34,7 +35,7 @@
|
||||
/* qmgr_queue_count is a global counter for the total number
|
||||
/* 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
|
||||
/* concurrency limit as specified with the
|
||||
/* \fIinitial_destination_concurrency\fR configuration parameter,
|
||||
@@ -45,9 +46,8 @@
|
||||
/* its entries have been taken care of. It is an error to dispose
|
||||
/* of a dead queue.
|
||||
/*
|
||||
/* qmgr_queue_find() looks up the queue for the named destination
|
||||
/* for the named transport. A null result means that the queue
|
||||
/* was not found.
|
||||
/* qmgr_queue_find() looks up the named queue for the named
|
||||
/* transport. A null result means that the queue was not found.
|
||||
/*
|
||||
/* qmgr_queue_throttle() handles a delivery error, and decrements the
|
||||
/* 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);
|
||||
htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
|
||||
myfree(queue->name);
|
||||
myfree(queue->nexthop);
|
||||
qmgr_queue_count--;
|
||||
myfree((char *) queue);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -229,7 +231,8 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
||||
|
||||
queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
|
||||
qmgr_queue_count++;
|
||||
queue->name = mystrdup(site);
|
||||
queue->name = mystrdup(name);
|
||||
queue->nexthop = mystrdup(nexthop);
|
||||
queue->todo_refcount = 0;
|
||||
queue->busy_refcount = 0;
|
||||
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->blocker_tag = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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/vstring.h
|
||||
proxymap.o: ../../include/vbuf.h
|
||||
proxymap.o: ../../include/htable.h
|
||||
proxymap.o: ../../include/stringops.h
|
||||
proxymap.o: ../../include/dict.h
|
||||
proxymap.o: ../../include/vstream.h
|
||||
proxymap.o: ../../include/argv.h
|
||||
|
@@ -149,14 +149,14 @@
|
||||
char *var_local_rcpt_maps;
|
||||
char *var_virt_alias_maps;
|
||||
char *var_virt_alias_doms;
|
||||
char *var_virt_mbox_maps;
|
||||
char *var_virt_mbox_doms;
|
||||
char *var_virt_mailbox_maps;
|
||||
char *var_virt_mailbox_doms;
|
||||
char *var_relay_rcpt_maps;
|
||||
char *var_relay_domains;
|
||||
char *var_canonical_maps;
|
||||
char *var_send_canon_maps;
|
||||
char *var_rcpt_canon_maps;
|
||||
char *var_relocatedmaps;
|
||||
char *var_relocated_maps;
|
||||
char *var_transport_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_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_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mbox_maps, 0, 0,
|
||||
VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mbox_doms, 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_mailbox_doms, 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_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_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_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 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/iostuff.h
|
||||
qmgr_message.o: ../../include/attr.h
|
||||
qmgr_message.o: ../../include/rewrite_clnt.h
|
||||
qmgr_message.o: ../../include/resolve_clnt.h
|
||||
qmgr_message.o: qmgr.h
|
||||
qmgr_message.o: ../../include/scan_dir.h
|
||||
|
@@ -140,7 +140,8 @@ struct QMGR_ENTRY_LIST {
|
||||
};
|
||||
|
||||
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 busy_refcount; /* queue entries (busy list) */
|
||||
int window; /* slow open algorithm */
|
||||
@@ -157,7 +158,7 @@ struct QMGR_QUEUE {
|
||||
|
||||
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 void qmgr_queue_done(QMGR_QUEUE *);
|
||||
extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *);
|
||||
@@ -231,6 +232,7 @@ struct QMGR_MESSAGE {
|
||||
char *return_receipt; /* confirm receipt address */
|
||||
char *filter_xport; /* filtering transport */
|
||||
char *inspect_xport; /* inspecting transport */
|
||||
char *redirect_addr; /* info@spammer.tld */
|
||||
long data_size; /* message content size */
|
||||
long rcpt_offset; /* more recipients here */
|
||||
QMGR_RCPT_LIST rcpt_list; /* complete addresses */
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/* NAME
|
||||
/* qmgr_deliver 3
|
||||
/* SUMMARY
|
||||
/* deliver one pe-site queue entry to that site
|
||||
/* deliver one per-site queue entry to that site
|
||||
/* SYNOPSIS
|
||||
/* #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 *recipient;
|
||||
QMGR_MESSAGE *message = entry->message;
|
||||
char *cp;
|
||||
VSTRING *sender_buf = 0;
|
||||
char *sender;
|
||||
int flags;
|
||||
char *nexthop;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
| (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_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
|
||||
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
|
||||
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_SENDER, sender,
|
||||
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) {
|
||||
active_share = queue_length / (double) qmgr_message_count;
|
||||
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)
|
||||
msg_warn("this may slow down other mail deliveries");
|
||||
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);
|
||||
else if (queue->peers.next != queue->peers.prev)
|
||||
msg_warn("you may need a separate master.cf transport for %s",
|
||||
queue->name);
|
||||
queue->nexthop);
|
||||
else {
|
||||
msg_warn("you may need to reduce %s connect and helo timeouts",
|
||||
transport->name);
|
||||
|
@@ -115,6 +115,7 @@
|
||||
|
||||
/* Client stubs. */
|
||||
|
||||
#include <rewrite_clnt.h>
|
||||
#include <resolve_clnt.h>
|
||||
|
||||
/* Application-specific. */
|
||||
@@ -149,6 +150,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
|
||||
message->return_receipt = 0;
|
||||
message->filter_xport = 0;
|
||||
message->inspect_xport = 0;
|
||||
message->redirect_addr = 0;
|
||||
message->data_size = 0;
|
||||
message->warn_offset = 0;
|
||||
message->warn_time = 0;
|
||||
@@ -266,6 +268,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
if (message->inspect_xport != 0)
|
||||
myfree(message->inspect_xport);
|
||||
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) {
|
||||
if (message->sender == 0) {
|
||||
message->sender = mystrdup(start);
|
||||
@@ -452,14 +458,14 @@ static int qmgr_message_sort_compare(const void *p1, const void *p2)
|
||||
/*
|
||||
* Compare message transport.
|
||||
*/
|
||||
if ((result = strcasecmp(queue1->transport->name,
|
||||
queue2->transport->name)) != 0)
|
||||
if ((result = strcmp(queue1->transport->name,
|
||||
queue2->transport->name)) != 0)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
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_QUEUE *queue = 0;
|
||||
RESOLVE_REPLY reply;
|
||||
VSTRING *queue_name;
|
||||
char *at;
|
||||
char **cpp;
|
||||
char *nexthop;
|
||||
@@ -521,63 +546,75 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
|
||||
|
||||
resolve_clnt_init(&reply);
|
||||
queue_name = vstring_alloc(1);
|
||||
for (recipient = list.info; recipient < list.info + list.len; recipient++) {
|
||||
|
||||
/*
|
||||
* Resolve the destination to (transport, nexthop, address). The
|
||||
* result address may differ from the one specified by the sender.
|
||||
* Redirect overrides all else. But only once (per batch of
|
||||
* recipients). For consistency with the remainder of Postfix,
|
||||
* rewrite the address to canonical form before resolving it.
|
||||
*/
|
||||
if (var_sender_routing == 0) {
|
||||
resolve_clnt_query(recipient->address, &reply);
|
||||
if (reply.flags & RESOLVE_FLAG_FAIL) {
|
||||
qmgr_defer_recipient(message, recipient,
|
||||
"address resolver failure");
|
||||
if (message->redirect_addr) {
|
||||
if (recipient > list.info) {
|
||||
recipient->queue = 0;
|
||||
continue;
|
||||
}
|
||||
if (reply.flags & RESOLVE_FLAG_ERROR) {
|
||||
qmgr_bounce_recipient(message, recipient,
|
||||
"bad address syntax: \"%s\"",
|
||||
recipient->address);
|
||||
rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
|
||||
reply.recipient);
|
||||
UPDATE(recipient->address, STR(reply.recipient));
|
||||
if (qmgr_resolve_one(message, recipient,
|
||||
recipient->address, &reply) < 0)
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
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 (!STREQ(recipient->address, STR(reply.recipient)))
|
||||
UPDATE(recipient->address, STR(reply.recipient));
|
||||
}
|
||||
if (message->filter_xport) {
|
||||
|
||||
/*
|
||||
* Content filtering overrides the address resolver.
|
||||
*/
|
||||
else if (message->filter_xport) {
|
||||
vstring_strcpy(reply.transport, message->filter_xport);
|
||||
if ((nexthop = split_at(STR(reply.transport), ':')) == 0
|
||||
|| *nexthop == 0)
|
||||
nexthop = var_myhostname;
|
||||
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)))
|
||||
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) {
|
||||
qmgr_bounce_recipient(message, recipient,
|
||||
"null recipient address");
|
||||
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
|
||||
* may misinterpret such addresses as command-line options.
|
||||
@@ -596,46 +633,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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,
|
||||
len) == 0
|
||||
&& !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.
|
||||
*/
|
||||
@@ -696,7 +686,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
transport = qmgr_transport_create(STR(reply.transport));
|
||||
queue = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This transport is dead. Defer delivery to this recipient.
|
||||
@@ -706,13 +695,50 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
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
|
||||
* recipient.
|
||||
*/
|
||||
if (queue == 0 || !STREQ(queue->name, STR(reply.nexthop))) {
|
||||
if ((queue = qmgr_queue_find(transport, STR(reply.nexthop))) == 0)
|
||||
queue = qmgr_queue_create(transport, STR(reply.nexthop));
|
||||
if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
|
||||
if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
|
||||
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;
|
||||
}
|
||||
resolve_clnt_free(&reply);
|
||||
vstring_free(queue_name);
|
||||
}
|
||||
|
||||
/* qmgr_message_assign - assign recipients to specific delivery requests */
|
||||
@@ -791,6 +818,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
||||
myfree(message->filter_xport);
|
||||
if (message->inspect_xport)
|
||||
myfree(message->inspect_xport);
|
||||
if (message->redirect_addr)
|
||||
myfree(message->redirect_addr);
|
||||
qmgr_rcpt_list_free(&message->rcpt_list);
|
||||
qmgr_message_count--;
|
||||
myfree((char *) message);
|
||||
|
@@ -8,16 +8,17 @@
|
||||
/*
|
||||
/* int qmgr_queue_count;
|
||||
/*
|
||||
/* QMGR_QUEUE *qmgr_queue_create(transport, site)
|
||||
/* QMGR_QUEUE *qmgr_queue_create(transport, name, nexthop)
|
||||
/* QMGR_TRANSPORT *transport;
|
||||
/* const char *site;
|
||||
/* const char *name;
|
||||
/* const char *nexthop;
|
||||
/*
|
||||
/* void qmgr_queue_done(queue)
|
||||
/* QMGR_QUEUE *queue;
|
||||
/*
|
||||
/* QMGR_QUEUE *qmgr_queue_find(transport, site)
|
||||
/* QMGR_QUEUE *qmgr_queue_find(transport, name)
|
||||
/* QMGR_TRANSPORT *transport;
|
||||
/* const char *site;
|
||||
/* const char *name;
|
||||
/*
|
||||
/* QMGR_QUEUE *qmgr_queue_select(transport)
|
||||
/* QMGR_TRANSPORT *transport;
|
||||
@@ -37,7 +38,7 @@
|
||||
/* qmgr_queue_count is a global counter for the total number
|
||||
/* 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
|
||||
/* concurrency limit as specified with the
|
||||
/* \fIinitial_destination_concurrency\fR configuration parameter,
|
||||
@@ -48,9 +49,8 @@
|
||||
/* its entries have been taken care of. It is an error to dispose
|
||||
/* of a dead queue.
|
||||
/*
|
||||
/* qmgr_queue_find() looks up the queue for the named destination
|
||||
/* for the named transport. A null result means that the queue
|
||||
/* was not found.
|
||||
/* qmgr_queue_find() looks up the named queue for the named
|
||||
/* transport. A null result means that the queue was not found.
|
||||
/*
|
||||
/* qmgr_queue_select() uses a round-robin strategy to select
|
||||
/* 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);
|
||||
htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
|
||||
myfree(queue->name);
|
||||
myfree(queue->nexthop);
|
||||
qmgr_queue_count--;
|
||||
myfree((char *) queue);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -252,7 +254,8 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
||||
|
||||
queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
|
||||
qmgr_queue_count++;
|
||||
queue->name = mystrdup(site);
|
||||
queue->name = mystrdup(name);
|
||||
queue->nexthop = mystrdup(nexthop);
|
||||
queue->todo_refcount = 0;
|
||||
queue->busy_refcount = 0;
|
||||
queue->transport = transport;
|
||||
@@ -262,13 +265,13 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
|
||||
queue->reason = 0;
|
||||
queue->clog_time_to_warn = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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/iostuff.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/deliver_request.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 (*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);
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
} 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);
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
} else {
|
||||
@@ -1802,6 +1802,26 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
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
|
||||
* 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)
|
||||
&& *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),
|
||||
strlen(var_double_bounce_sender))
|
||||
/* Absorbed by qmgr. */
|
||||
/* Absorbed by qmgr. */
|
||||
&& !MATCH_LEFT(MAIL_ADDR_POSTMASTER, CONST_STR(reply->recipient),
|
||||
strlen(MAIL_ADDR_POSTMASTER))
|
||||
/* Generated by bounce. */
|
||||
/* Generated by bounce. */
|
||||
&& !MATCH_LEFT(MAIL_ADDR_MAIL_DAEMON, CONST_STR(reply->recipient),
|
||||
strlen(MAIL_ADDR_MAIL_DAEMON))
|
||||
&& NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient)))
|
||||
|
@@ -624,6 +624,18 @@ dict_open.o: split_at.h
|
||||
dict_open.o: htable.h
|
||||
dict_pcre.o: dict_pcre.c
|
||||
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: sys_defs.h
|
||||
dict_regexp.o: mymalloc.h
|
||||
|
Reference in New Issue
Block a user