2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

postfix-2.3-20050726

This commit is contained in:
Wietse Venema 2005-07-26 00:00:00 -05:00 committed by Viktor Dukhovni
parent 01c5f58c4b
commit 3fb1ad8ad5
14 changed files with 210 additions and 126 deletions

View File

@ -11050,6 +11050,18 @@ Apologies for any names omitted.
client IP address). Files: global/mail_params.h, client IP address). Files: global/mail_params.h,
smtpd/smtpd_peer.c, smtpd/smtpd.c, smtpd/smtpd_check.c. smtpd/smtpd_peer.c, smtpd/smtpd.c, smtpd/smtpd_check.c.
20050726
Horror: total rewrite of DNS client error handling because
some misguided proposal attempts to give special meaning
to some syntactically invalid MX hostname lookup result.
Not only that, people expect sensible results with
reject_unknown_sender_domain etc. Files: dns/dns_lookup.c,
smtp/smtp_addr.c smtpd/smtpd_check.c, lmtp/lmtp_addr.c.
Cleanup: HOLD action executes only once, to reduce noise
in the logfile. Files: cleanup/cleanup_message.c, smtpd/smtpd.c.
Open problems: Open problems:
Med: when the cleanup server bounces local mail that should Med: when the cleanup server bounces local mail that should

View File

@ -17,7 +17,32 @@ Incompatibility with Postfix 2.1 and earlier
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2 If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
before proceeding. before proceeding.
Incompatibility with snapshot 20050715 Incompatibility with snapshot 20050726
======================================
Name server replies that contain a malformed hostname are now flagged
as permanent errors instead of transient errors. This change works
around a questionable proposal to use syntactically invalid hostnames
in MX records.
Major changes with snapshot 20050724
====================================
SMTPD Access control based on the existence of an address->name
mapping, with reject_unknown_reverse_client_hostname. There is
no corresponding access table lookup feature, because the name
is not validated in any way (except that it has proper syntax).
Several confusing SMTPD access restrictions were renamed:
reject_unknown_client -> reject_unknown_client_hostname,
reject_unknown_hostname -> reject_unknown_helo_hostname,
reject_invalid_hostname -> reject_invalid_helo_hostname,
reject_non_fqdn_hostname -> reject_non_fqdn_helo_hostname.
The old names are still recognized and documented.
Incompatibility with snapshot 20050716
====================================== ======================================
Internal interfaces have changed; this may break third-party patches Internal interfaces have changed; this may break third-party patches
@ -40,7 +65,7 @@ report "(unsigned) int" versus "(s)size_t" format string argument
mis-matches on 32-bit systems; they can be found only on 64-bit mis-matches on 32-bit systems; they can be found only on 64-bit
systems. systems.
Major changes with snapshot 20050715 Major changes with snapshot 20050716
==================================== ====================================
Improved portability to LP64 systems, by converting the type of Improved portability to LP64 systems, by converting the type of

View File

@ -8132,11 +8132,13 @@ code for rejected requests (default: 554). </dd>
<dt><b><a name="reject_unknown_recipient_domain">reject_unknown_recipient_domain</a></b></dt> <dt><b><a name="reject_unknown_recipient_domain">reject_unknown_recipient_domain</a></b></dt>
<dd>Reject the request when the RCPT TO address has no DNS A or MX <dd>Reject the request when Postfix is not final destination for
record and Postfix is not final destination for the recipient the recipient address, and the RCPT TO address has no DNS A or MX
address. <br> The <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies record, or when it has a malformed MX record such as a record with
the response code for rejected requests (default: 450). The response a zero-length MX hostname (Postfix 2.3 and later). <br> The
is always 450 in case of a temporary DNS error.</dd> <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies the response code
for rejected requests (default: 450). The response is always 450
in case of a temporary DNS error.</dd>
<dt><b><a name="reject_unlisted_recipient">reject_unlisted_recipient</a></b> (with Postfix 2.0: check_recipient_maps)</dt> <dt><b><a name="reject_unlisted_recipient">reject_unlisted_recipient</a></b> (with Postfix 2.0: check_recipient_maps)</dt>
@ -8602,11 +8604,13 @@ Postfix version 2.1 and later. </dd>
<dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt> <dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt>
<dd>Reject the request when the MAIL FROM address has no DNS A or <dd>Reject the request when Postfix is not final destination for
MX record and Postfix is not final destination for the sender the sender address, and the MAIL FROM address has no DNS A or MX
address. <br> The <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies record, or when it has a malformed MX record such as a record with
the response code for rejected requests (default: 450). The response a zero-length MX hostname (Postfix 2.3 and later). <br> The
is always 450 in case of a temporary DNS error. </dd> <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies the response code
for rejected requests (default: 450). The response is always 450
in case of a temporary DNS error. </dd>
<dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt> <dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt>

View File

@ -4648,13 +4648,15 @@ no sender-specified routing (user@elsewhere@domain).
The relay_domains_reject_code parameter specifies the response The relay_domains_reject_code parameter specifies the response
code for rejected requests (default: 554). code for rejected requests (default: 554).
.IP "\fBreject_unknown_recipient_domain\fR" .IP "\fBreject_unknown_recipient_domain\fR"
Reject the request when the RCPT TO address has no DNS A or MX Reject the request when Postfix is not final destination for
record and Postfix is not final destination for the recipient the recipient address, and the RCPT TO address has no DNS A or MX
address. record, or when it has a malformed MX record such as a record with
a zero-length MX hostname (Postfix 2.3 and later).
.br .br
The unknown_address_reject_code parameter specifies The
the response code for rejected requests (default: 450). The response unknown_address_reject_code parameter specifies the response code
is always 450 in case of a temporary DNS error. for rejected requests (default: 450). The response is always 450
in case of a temporary DNS error.
.IP "\fBreject_unlisted_recipient\fR (with Postfix 2.0: check_recipient_maps)" .IP "\fBreject_unlisted_recipient\fR (with Postfix 2.0: check_recipient_maps)"
Reject the request when the RCPT TO address is not listed in Reject the request when the RCPT TO address is not listed in
the list of valid recipients for its domain class. See the the list of valid recipients for its domain class. See the
@ -4953,13 +4955,15 @@ Enforces the reject_sender_login_mismatch restriction for
unauthenticated clients only. This feature is available in unauthenticated clients only. This feature is available in
Postfix version 2.1 and later. Postfix version 2.1 and later.
.IP "\fBreject_unknown_sender_domain\fR" .IP "\fBreject_unknown_sender_domain\fR"
Reject the request when the MAIL FROM address has no DNS A or Reject the request when Postfix is not final destination for
MX record and Postfix is not final destination for the sender the sender address, and the MAIL FROM address has no DNS A or MX
address. record, or when it has a malformed MX record such as a record with
a zero-length MX hostname (Postfix 2.3 and later).
.br .br
The unknown_address_reject_code parameter specifies The
the response code for rejected requests (default: 450). The response unknown_address_reject_code parameter specifies the response code
is always 450 in case of a temporary DNS error. for rejected requests (default: 450). The response is always 450
in case of a temporary DNS error.
.IP "\fBreject_unlisted_sender\fR" .IP "\fBreject_unlisted_sender\fR"
Reject the request when the MAIL FROM address is not listed in Reject the request when the MAIL FROM address is not listed in
the list of valid recipients for its domain class. See the the list of valid recipients for its domain class. See the

View File

@ -5150,11 +5150,13 @@ code for rejected requests (default: 554). </dd>
<dt><b><a name="reject_unknown_recipient_domain">reject_unknown_recipient_domain</a></b></dt> <dt><b><a name="reject_unknown_recipient_domain">reject_unknown_recipient_domain</a></b></dt>
<dd>Reject the request when the RCPT TO address has no DNS A or MX <dd>Reject the request when Postfix is not final destination for
record and Postfix is not final destination for the recipient the recipient address, and the RCPT TO address has no DNS A or MX
address. <br> The unknown_address_reject_code parameter specifies record, or when it has a malformed MX record such as a record with
the response code for rejected requests (default: 450). The response a zero-length MX hostname (Postfix 2.3 and later). <br> The
is always 450 in case of a temporary DNS error.</dd> unknown_address_reject_code parameter specifies the response code
for rejected requests (default: 450). The response is always 450
in case of a temporary DNS error.</dd>
<dt><b><a name="reject_unlisted_recipient">reject_unlisted_recipient</a></b> (with Postfix 2.0: check_recipient_maps)</dt> <dt><b><a name="reject_unlisted_recipient">reject_unlisted_recipient</a></b> (with Postfix 2.0: check_recipient_maps)</dt>
@ -5488,11 +5490,13 @@ Postfix version 2.1 and later. </dd>
<dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt> <dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt>
<dd>Reject the request when the MAIL FROM address has no DNS A or <dd>Reject the request when Postfix is not final destination for
MX record and Postfix is not final destination for the sender the sender address, and the MAIL FROM address has no DNS A or MX
address. <br> The unknown_address_reject_code parameter specifies record, or when it has a malformed MX record such as a record with
the response code for rejected requests (default: 450). The response a zero-length MX hostname (Postfix 2.3 and later). <br> The
is always 450 in case of a temporary DNS error. </dd> unknown_address_reject_code parameter specifies the response code
for rejected requests (default: 450). The response is always 450
in case of a temporary DNS error. </dd>
<dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt> <dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt>

View File

@ -316,8 +316,8 @@ static const char *cleanup_act(CLEANUP_STATE *state, char *context,
if (*optional_text) { if (*optional_text) {
state->reason = dsn_prepend("5.7.1", optional_text); state->reason = dsn_prepend("5.7.1", optional_text);
if (*state->reason != '4' && *state->reason != '5') { if (*state->reason != '4' && *state->reason != '5') {
msg_warn("bad DSN action in %s -- need 4.x.x or 5.x.x", msg_warn("bad DSN action in %s -- need 4.x.x or 5.x.x",
optional_text); optional_text);
*state->reason = '4'; *state->reason = '4';
} }
} else { } else {
@ -356,8 +356,10 @@ static const char *cleanup_act(CLEANUP_STATE *state, char *context,
return (buf); return (buf);
} }
if (STREQUAL(value, "HOLD", command_len)) { if (STREQUAL(value, "HOLD", command_len)) {
cleanup_act_log(state, "hold", context, buf, optional_text); if ((state->flags & CLEANUP_FLAG_HOLD) == 0) {
state->flags |= CLEANUP_FLAG_HOLD; cleanup_act_log(state, "hold", context, buf, optional_text);
state->flags |= CLEANUP_FLAG_HOLD;
}
return (buf); return (buf);
} }
if (STREQUAL(value, "PREPEND", command_len)) { if (STREQUAL(value, "PREPEND", command_len)) {

View File

@ -157,13 +157,15 @@ extern int dns_lookup_v(const char *, unsigned, DNS_RR **, VSTRING *,
/* /*
* Request flags. * Request flags.
*/ */
#define DNS_REQ_FLAG_ANY (1<<0) #define DNS_REQ_FLAG_STOP_OK (1<<0)
#define DNS_REQ_FLAG_ALL (1<<1) #define DNS_REQ_FLAG_STOP_INVAL (1<<1)
#define DNS_REQ_FLAG_NONE (0)
/* /*
* Status codes. Failures must have negative codes so they will not collide * Status codes. Failures must have negative codes so they will not collide
* with valid counts of answer records etc. * with valid counts of answer records etc.
*/ */
#define DNS_INVAL (-5) /* query ok, malformed reply */
#define DNS_FAIL (-4) /* query failed, don't retry */ #define DNS_FAIL (-4) /* query failed, don't retry */
#define DNS_NOTFOUND (-3) /* query ok, data not found */ #define DNS_NOTFOUND (-3) /* query ok, data not found */
#define DNS_RETRY (-2) /* query failed, try again */ #define DNS_RETRY (-2) /* query failed, try again */

View File

@ -37,7 +37,8 @@
/* number of CNAME indirections. All result names (including /* number of CNAME indirections. All result names (including
/* null terminator) will fit a buffer of size DNS_NAME_LEN. /* null terminator) will fit a buffer of size DNS_NAME_LEN.
/* All name results are validated by \fIvalid_hostname\fR(); /* All name results are validated by \fIvalid_hostname\fR();
/* an invalid name is reported as a transient error. /* an invalid name is reported as a DNS_INVAL result, while
/* malformed replies are reported as transient errors.
/* /*
/* dns_lookup_l() and dns_lookup_v() allow the user to specify /* dns_lookup_l() and dns_lookup_v() allow the user to specify
/* a list of resource types. /* a list of resource types.
@ -46,6 +47,8 @@
/* .fi /* .fi
/* .IP name /* .IP name
/* The name to be looked up in the domain name system. /* The name to be looked up in the domain name system.
/* This name must pass the valid_hostname() test; it
/* must not be an IP address.
/* .IP type /* .IP type
/* The resource record type to be looked up (T_A, T_MX etc.). /* The resource record type to be looked up (T_A, T_MX etc.).
/* .IP rflags /* .IP rflags
@ -59,16 +62,18 @@
/* Append local domain to unqualified names. /* Append local domain to unqualified names.
/* .RE /* .RE
/* .IP lflags /* .IP lflags
/* Multi-type request control for dns_lookup_l() and /* Multi-type request control for dns_lookup_l() and dns_lookup_v().
/* dns_lookup_v(). This is one of the following: /* For convenience, DNS_REQ_FLAG_NONE requests no special
/* processing. Invoke dns_lookup() for all specified resource
/* record types in the specified order, and merge their results.
/* Otherwise, specify one or more of the following:
/* .RS /* .RS
/* .IP DNS_REQ_FLAG_ANY /* .IP DNS_REQ_FLAG_STOP_INVAL
/* Call dns_lookup() for each specified resource record type /* Invoke dns_lookup() for the resource types in the order as
/* in the specified order, until the list is exhausted or /* specified, and return when dns_lookup() returns DNS_INVAL.
/* until some result is DNS_OK. /* .IP DNS_REQ_FLAG_STOP_OK
/* .IP DNS_REQ_FLAG_ALL /* Invoke dns_lookup() for the resource types in the order as
/* Call dns_lookup() for all specified resource record types /* specified, and return when dns_lookup() returns DNS_OK.
/* in the specified order, and merge their results.
/* .RE /* .RE
/* .IP ltype /* .IP ltype
/* The resource record types to be looked up. In the case of /* The resource record types to be looked up. In the case of
@ -93,8 +98,11 @@
/* The DNS query succeeded. /* The DNS query succeeded.
/* .IP DNS_NOTFOUND /* .IP DNS_NOTFOUND
/* The DNS query succeeded; the requested information was not found. /* The DNS query succeeded; the requested information was not found.
/* .IP DNS_INVAL
/* The DNS query succeeded; the result failed the valid_hostname() test.
/* .IP DNS_RETRY /* .IP DNS_RETRY
/* The query failed; the problem is transient. /* The query failed, or the reply was malformed.
/* The problem is considered transient.
/* .IP DNS_FAIL /* .IP DNS_FAIL
/* The query failed. /* The query failed.
/* BUGS /* BUGS
@ -142,8 +150,8 @@
/* /*
* Structure to keep track of things while decoding a name server reply. * Structure to keep track of things while decoding a name server reply.
*/ */
#define DEF_DNS_REPLY_SIZE 4096 /* in case we're using TCP */ #define DEF_DNS_REPLY_SIZE 4096 /* in case we're using TCP */
#define MAX_DNS_REPLY_SIZE 32768 /* in case we're using TCP */ #define MAX_DNS_REPLY_SIZE 32768 /* in case we're using TCP */
typedef struct DNS_REPLY { typedef struct DNS_REPLY {
unsigned char *buf; /* raw reply data */ unsigned char *buf; /* raw reply data */
@ -341,8 +349,8 @@ static int valid_rr_name(const char *name, const char *location,
/* dns_get_rr - extract resource record from name server reply */ /* dns_get_rr - extract resource record from name server reply */
static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos, static int dns_get_rr(DNS_RR **list, DNS_REPLY *reply, unsigned char *pos,
char *rr_name, DNS_FIXED *fixed) char *rr_name, DNS_FIXED *fixed)
{ {
char temp[DNS_NAME_LEN]; char temp[DNS_NAME_LEN];
ssize_t data_len; ssize_t data_len;
@ -353,8 +361,9 @@ static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
#define MIN2(a, b) ((unsigned)(a) < (unsigned)(b) ? (a) : (b)) #define MIN2(a, b) ((unsigned)(a) < (unsigned)(b) ? (a) : (b))
*list = 0;
if (pos + fixed->length > reply->end) if (pos + fixed->length > reply->end)
return (0); return (DNS_RETRY);
switch (fixed->type) { switch (fixed->type) {
default: default:
@ -367,23 +376,23 @@ static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
case T_NS: case T_NS:
case T_PTR: case T_PTR:
if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0) if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
return (0); return (DNS_RETRY);
if (!valid_rr_name(temp, "resource data", fixed->type, reply)) if (!valid_rr_name(temp, "resource data", fixed->type, reply))
return (0); return (DNS_INVAL);
data_len = strlen(temp) + 1; data_len = strlen(temp) + 1;
break; break;
case T_MX: case T_MX:
GETSHORT(pref, pos); GETSHORT(pref, pos);
if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0) if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
return (0); return (DNS_RETRY);
if (!valid_rr_name(temp, "resource data", fixed->type, reply)) if (!valid_rr_name(temp, "resource data", fixed->type, reply))
return (0); return (DNS_INVAL);
data_len = strlen(temp) + 1; data_len = strlen(temp) + 1;
break; break;
case T_A: case T_A:
if (fixed->length != INET_ADDR_LEN) { if (fixed->length != INET_ADDR_LEN) {
msg_warn("extract_answer: bad address length: %d", fixed->length); msg_warn("extract_answer: bad address length: %d", fixed->length);
return (0); return (DNS_RETRY);
} }
if (fixed->length > sizeof(temp)) if (fixed->length > sizeof(temp))
msg_panic("dns_get_rr: length %d > DNS_NAME_LEN", msg_panic("dns_get_rr: length %d > DNS_NAME_LEN",
@ -395,7 +404,7 @@ static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
case T_AAAA: case T_AAAA:
if (fixed->length != INET6_ADDR_LEN) { if (fixed->length != INET6_ADDR_LEN) {
msg_warn("extract_answer: bad address length: %d", fixed->length); msg_warn("extract_answer: bad address length: %d", fixed->length);
return (0); return (DNS_RETRY);
} }
if (fixed->length > sizeof(temp)) if (fixed->length > sizeof(temp))
msg_panic("dns_get_rr: length %d > DNS_NAME_LEN", msg_panic("dns_get_rr: length %d > DNS_NAME_LEN",
@ -414,8 +423,9 @@ static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
*dst = 0; *dst = 0;
break; break;
} }
return (dns_rr_create(rr_name, fixed->type, fixed->class, fixed->ttl, *list = dns_rr_create(rr_name, fixed->type, fixed->class, fixed->ttl,
pref, temp, data_len)); pref, temp, data_len);
return (DNS_OK);
} }
/* dns_get_alias - extract CNAME from name server reply */ /* dns_get_alias - extract CNAME from name server reply */
@ -428,7 +438,7 @@ static int dns_get_alias(DNS_REPLY *reply, unsigned char *pos,
if (dn_expand(reply->buf, reply->end, pos, cname, c_len) < 0) if (dn_expand(reply->buf, reply->end, pos, cname, c_len) < 0)
return (DNS_RETRY); return (DNS_RETRY);
if (!valid_rr_name(cname, "resource data", fixed->type, reply)) if (!valid_rr_name(cname, "resource data", fixed->type, reply))
return (DNS_RETRY); return (DNS_INVAL);
return (DNS_OK); return (DNS_OK);
} }
@ -445,14 +455,15 @@ static int dns_get_answer(DNS_REPLY *reply, int type,
DNS_RR *rr; DNS_RR *rr;
int resource_found = 0; int resource_found = 0;
int cname_found = 0; int cname_found = 0;
int not_found_status = DNS_NOTFOUND; int not_found_status = DNS_RETRY; /* can't happen */
int status;
/* /*
* Initialize. Skip over the name server query if we haven't yet. * Initialize. Skip over the name server query if we haven't yet.
*/ */
if (reply->answer_start == 0) if (reply->answer_start == 0)
if (dns_skip_query(reply) < 0) if ((status = dns_skip_query(reply)) < 0)
return (DNS_RETRY); return (status);
pos = reply->answer_start; pos = reply->answer_start;
if (rrlist) if (rrlist)
*rrlist = 0; *rrlist = 0;
@ -461,12 +472,12 @@ static int dns_get_answer(DNS_REPLY *reply, int type,
* Either this, or use a GOTO for emergency exits. The purpose is to * Either this, or use a GOTO for emergency exits. The purpose is to
* prevent incomplete answers from being passed back to the caller. * prevent incomplete answers from being passed back to the caller.
*/ */
#define CORRUPT { \ #define CORRUPT(status) { \
if (rrlist && *rrlist) { \ if (rrlist && *rrlist) { \
dns_rr_free(*rrlist); \ dns_rr_free(*rrlist); \
*rrlist = 0; \ *rrlist = 0; \
} \ } \
return (DNS_RETRY); \ return (status); \
} }
/* /*
@ -478,21 +489,21 @@ static int dns_get_answer(DNS_REPLY *reply, int type,
* Optionally extract the fully-qualified domain name. * Optionally extract the fully-qualified domain name.
*/ */
if (pos >= reply->end) if (pos >= reply->end)
CORRUPT; CORRUPT(DNS_RETRY);
len = dn_expand(reply->buf, reply->end, pos, rr_name, DNS_NAME_LEN); len = dn_expand(reply->buf, reply->end, pos, rr_name, DNS_NAME_LEN);
if (len < 0) if (len < 0)
CORRUPT; CORRUPT(DNS_RETRY);
pos += len; pos += len;
/* /*
* Extract the fixed reply data: type, class, ttl, length. * Extract the fixed reply data: type, class, ttl, length.
*/ */
if (pos + RRFIXEDSZ > reply->end) if (pos + RRFIXEDSZ > reply->end)
CORRUPT; CORRUPT(DNS_RETRY);
if (dns_get_fixed(pos, &fixed) != DNS_OK) if ((status = dns_get_fixed(pos, &fixed)) != DNS_OK)
CORRUPT; CORRUPT(status);
if (!valid_rr_name(rr_name, "resource name", fixed.type, reply)) if (!valid_rr_name(rr_name, "resource name", fixed.type, reply))
CORRUPT; CORRUPT(DNS_INVAL);
if (fqdn) if (fqdn)
vstring_strcpy(fqdn, rr_name); vstring_strcpy(fqdn, rr_name);
if (msg_verbose) if (msg_verbose)
@ -504,21 +515,21 @@ static int dns_get_answer(DNS_REPLY *reply, int type,
* Optionally extract the requested resource or CNAME data. * Optionally extract the requested resource or CNAME data.
*/ */
if (pos + fixed.length > reply->end) if (pos + fixed.length > reply->end)
CORRUPT; CORRUPT(DNS_RETRY);
if (type == fixed.type || type == T_ANY) { /* requested type */ if (type == fixed.type || type == T_ANY) { /* requested type */
if (rrlist) { if (rrlist) {
if ((rr = dns_get_rr(reply, pos, rr_name, &fixed)) != 0) { if ((status = dns_get_rr(&rr, reply, pos, rr_name, &fixed)) == DNS_OK) {
resource_found++; resource_found++;
*rrlist = dns_rr_append(*rrlist, rr); *rrlist = dns_rr_append(*rrlist, rr);
} else } else if (not_found_status != DNS_RETRY)
not_found_status = DNS_RETRY; not_found_status = status;
} else } else
resource_found++; resource_found++;
} else if (fixed.type == T_CNAME) { /* cname resource */ } else if (fixed.type == T_CNAME) { /* cname resource */
cname_found++; cname_found++;
if (cname && c_len > 0) if (cname && c_len > 0)
if (dns_get_alias(reply, pos, &fixed, cname, c_len) != DNS_OK) if ((status = dns_get_alias(reply, pos, &fixed, cname, c_len)) != DNS_OK)
CORRUPT; CORRUPT(status);
} }
pos += fixed.length; pos += fixed.length;
} }
@ -591,10 +602,9 @@ int dns_lookup(const char *name, unsigned type, unsigned flags,
default: default:
if (why) if (why)
vstring_sprintf(why, "Name service error for name=%s type=%s: " vstring_sprintf(why, "Name service error for name=%s type=%s: "
"Malformed name server reply", "Malformed or unexpected name server reply",
name, dns_strtype(type)); name, dns_strtype(type));
case DNS_OK: case DNS_OK:
case DNS_NOTFOUND:
return (status); return (status);
case DNS_RECURSE: case DNS_RECURSE:
if (msg_verbose) if (msg_verbose)
@ -633,7 +643,10 @@ int dns_lookup_l(const char *name, unsigned flags, DNS_RR **rrlist,
non_err = 1; non_err = 1;
if (rrlist) if (rrlist)
*rrlist = dns_rr_append(*rrlist, rr); *rrlist = dns_rr_append(*rrlist, rr);
if (lflags == DNS_REQ_FLAG_ANY) if (lflags & DNS_REQ_FLAG_STOP_OK)
break;
} else if (status == DNS_INVAL) {
if (lflags & DNS_REQ_FLAG_STOP_INVAL)
break; break;
} else if (status == DNS_RETRY) { } else if (status == DNS_RETRY) {
soft_err = 1; soft_err = 1;
@ -667,7 +680,10 @@ int dns_lookup_v(const char *name, unsigned flags, DNS_RR **rrlist,
non_err = 1; non_err = 1;
if (rrlist) if (rrlist)
*rrlist = dns_rr_append(*rrlist, rr); *rrlist = dns_rr_append(*rrlist, rr);
if (lflags == DNS_REQ_FLAG_ANY) if (lflags & DNS_REQ_FLAG_STOP_OK)
break;
} else if (status == DNS_INVAL) {
if (lflags & DNS_REQ_FLAG_STOP_INVAL)
break; break;
} else if (status == DNS_RETRY) { } else if (status == DNS_RETRY) {
soft_err = 1; soft_err = 1;

View File

@ -100,7 +100,7 @@ int main(int argc, char **argv)
name = argv[2]; name = argv[2];
msg_verbose = 1; msg_verbose = 1;
switch (dns_lookup_v(name, RES_DEFNAMES | RES_DEBUG, &rr, fqdn, why, switch (dns_lookup_v(name, RES_DEFNAMES | RES_DEBUG, &rr, fqdn, why,
DNS_REQ_FLAG_ALL, types)) { DNS_REQ_FLAG_NONE, types)) {
default: default:
msg_fatal("%s", vstring_str(why)); msg_fatal("%s", vstring_str(why));
case DNS_OK: case DNS_OK:

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20050724" #define MAIL_RELEASE_DATE "20050726"
#define MAIL_VERSION_NUMBER "2.3" #define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -191,7 +191,7 @@ static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
* Append the addresses for this host to the address list. * Append the addresses for this host to the address list.
*/ */
switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why->reason, switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why->reason,
DNS_REQ_FLAG_ALL, proto_info->dns_atype_list)) { DNS_REQ_FLAG_NONE, proto_info->dns_atype_list)) {
case DNS_OK: case DNS_OK:
for (rr = addr; rr; rr = rr->next) for (rr = addr; rr; rr = rr->next)
rr->pref = pref; rr->pref = pref;
@ -207,6 +207,7 @@ static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
"5.4.3", 550, "550 Name server failure"); "5.4.3", 550, "550 Name server failure");
lmtp_errno = LMTP_FAIL; lmtp_errno = LMTP_FAIL;
break; break;
case DNS_INVAL:
case DNS_NOTFOUND: case DNS_NOTFOUND:
lmtp_dsn_formal(why, DSN_BY_LOCAL_MTA, lmtp_dsn_formal(why, DSN_BY_LOCAL_MTA,
"5.4.4", 550, "550 Host not found"); "5.4.4", 550, "550 Host not found");

View File

@ -162,7 +162,7 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
*/ */
if (smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS) { if (smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS) {
switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0,
why->reason, DNS_REQ_FLAG_ALL, why->reason, DNS_REQ_FLAG_NONE,
proto_info->dns_atype_list)) { proto_info->dns_atype_list)) {
case DNS_OK: case DNS_OK:
for (rr = addr; rr; rr = rr->next) for (rr = addr; rr; rr = rr->next)
@ -180,6 +180,7 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
if (smtp_errno != SMTP_ERR_RETRY) if (smtp_errno != SMTP_ERR_RETRY)
smtp_errno = SMTP_ERR_FAIL; smtp_errno = SMTP_ERR_FAIL;
return (addr_list); return (addr_list);
case DNS_INVAL:
case DNS_NOTFOUND: case DNS_NOTFOUND:
smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, smtp_dsn_formal(why, DSN_BY_LOCAL_MTA,
"5.4.4", 550, "550 Host not found"); "5.4.4", 550, "550 Host not found");
@ -474,6 +475,11 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why,
addr_list = dns_rr_sort(addr_list, smtp_compare_pref); addr_list = dns_rr_sort(addr_list, smtp_compare_pref);
} }
break; break;
case DNS_INVAL:
smtp_dsn_formal(why, DSN_BY_LOCAL_MTA,
"5.4.4", 550, "550 Host not found");
smtp_errno = SMTP_ERR_FAIL;
break;
case DNS_NOTFOUND: case DNS_NOTFOUND:
addr_list = smtp_host_addr(name, misc_flags, why); addr_list = smtp_host_addr(name, misc_flags, why);
break; break;

View File

@ -86,7 +86,7 @@ const char *smtp_unalias_name(const char *name)
if ((result = htable_find(cache, name)) == 0) { if ((result = htable_find(cache, name)) == 0) {
fqdn = vstring_alloc(10); fqdn = vstring_alloc(10);
if (dns_lookup_l(name, smtp_unalias_flags, (DNS_RR **) 0, fqdn, if (dns_lookup_l(name, smtp_unalias_flags, (DNS_RR **) 0, fqdn,
(VSTRING *) 0, DNS_REQ_FLAG_ANY, T_MX, T_A, (VSTRING *) 0, DNS_REQ_FLAG_NONE, T_MX, T_A,
#ifdef HAS_IPV6 #ifdef HAS_IPV6
T_AAAA, T_AAAA,
#endif #endif

View File

@ -966,7 +966,7 @@ static int reject_unknown_client(SMTPD_STATE *state)
if (state->name_status != SMTPD_PEER_CODE_OK) if (state->name_status != SMTPD_PEER_CODE_OK)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
state->name_status == SMTPD_PEER_CODE_PERM ? state->name_status == SMTPD_PEER_CODE_PERM ?
var_unk_client_code : 450, "4.7.1", var_unk_client_code : 450, "4.7.1",
"Client host rejected: cannot find your hostname, [%s]", "Client host rejected: cannot find your hostname, [%s]",
state->addr)); state->addr));
@ -1155,18 +1155,20 @@ static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
#endif #endif
dns_status = dns_lookup_l(name, 0, (DNS_RR **) 0, (VSTRING *) 0, dns_status = dns_lookup_l(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
(VSTRING *) 0, DNS_REQ_FLAG_ANY, (VSTRING *) 0, DNS_REQ_FLAG_STOP_OK,
RR_ADDR_TYPES, T_MX, 0); RR_ADDR_TYPES, T_MX, 0);
if (dns_status == DNS_NOTFOUND) if (dns_status != DNS_OK) { /* incl. DNS_INVAL */
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, if (dns_status != DNS_RETRY)
var_unk_name_code, "4.7.1", return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"<%s>: %s rejected: Host not found", var_unk_name_code, "4.7.1",
reply_name, reply_class)); "<%s>: %s rejected: Host not found",
else if (dns_status != DNS_OK) reply_name, reply_class));
DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY, else
450, "4.7.1", DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
"<%s>: %s rejected: Host not found", 450, "4.7.1",
reply_name, reply_class); "<%s>: %s rejected: Host not found",
reply_name, reply_class);
}
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
@ -1181,22 +1183,26 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s", myname, name); msg_info("%s: %s", myname, name);
#define MAILHOST_LOOKUP_FLAGS (DNS_REQ_FLAG_STOP_OK | DNS_REQ_FLAG_STOP_INVAL)
dns_status = dns_lookup_l(name, 0, (DNS_RR **) 0, (VSTRING *) 0, dns_status = dns_lookup_l(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
(VSTRING *) 0, DNS_REQ_FLAG_ANY, (VSTRING *) 0, MAILHOST_LOOKUP_FLAGS,
RR_ADDR_TYPES, T_MX, 0); T_MX, RR_ADDR_TYPES, 0);
if (dns_status == DNS_NOTFOUND) if (dns_status != DNS_OK) { /* incl. DNS_INVAL */
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, if (dns_status != DNS_RETRY)
var_unk_addr_code, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
var_unk_addr_code,
strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ? strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
"4.1.8" : "4.1.2", "4.1.8" : "4.1.2",
"<%s>: %s rejected: Domain not found", "<%s>: %s rejected: Domain not found",
reply_name, reply_class)); reply_name, reply_class));
else if (dns_status != DNS_OK) else
DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY, DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ? 450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
"4.1.8" : "4.1.2", "4.1.8" : "4.1.2",
"<%s>: %s rejected: Domain not found", "<%s>: %s rejected: Domain not found",
reply_name, reply_class); reply_name, reply_class);
}
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
@ -1395,8 +1401,8 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
* Verify that all host addresses are within permit_mx_backup_networks. * Verify that all host addresses are within permit_mx_backup_networks.
*/ */
dns_status = dns_lookup_v(host, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0, dns_status = dns_lookup_v(host, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0,
DNS_REQ_FLAG_ALL, inet_proto_info()->dns_atype_list); DNS_REQ_FLAG_NONE, inet_proto_info()->dns_atype_list);
if (dns_status != DNS_OK) { if (dns_status != DNS_OK) { /* incl. DNS_INVAL */
DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY, DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
450, "4.4.4", 450, "4.4.4",
"<%s>: %s rejected: Unable to look up host %s as mail exchanger", "<%s>: %s rejected: Unable to look up host %s as mail exchanger",
@ -1622,11 +1628,12 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient,
if (dns_status == DNS_NOTFOUND) if (dns_status == DNS_NOTFOUND)
return (has_my_addr(state, domain, reply_name, reply_class) ? return (has_my_addr(state, domain, reply_name, reply_class) ?
SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO); SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO);
if (dns_status != DNS_OK) { if (dns_status != DNS_OK) { /* incl. DNS_INVAL */
DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY, if (dns_status == DNS_RETRY)
450, "4.4.4", DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
"<%s>: %s rejected: Unable to look up mail exchanger information", 450, "4.4.4",
reply_name, reply_class); "<%s>: %s rejected: Unable to look up mail exchanger information",
reply_name, reply_class);
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
@ -1961,7 +1968,8 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
*/ */
if (STREQUAL(value, "HOLD", cmd_len)) { if (STREQUAL(value, "HOLD", cmd_len)) {
#ifndef TEST #ifndef TEST
if (can_delegate_action(state, table, "HOLD", reply_class) == 0) if (can_delegate_action(state, table, "HOLD", reply_class) == 0
|| (state->saved_flags & CLEANUP_FLAG_HOLD))
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
#endif #endif
vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class, vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
@ -3502,7 +3510,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
forbid_whitelist(state, name, status, state->helo_name); forbid_whitelist(state, name, status, state->helo_name);
} }
} else if (strcasecmp(name, REJECT_NON_FQDN_HELO_HOSTNAME) == 0 } else if (strcasecmp(name, REJECT_NON_FQDN_HELO_HOSTNAME) == 0
||strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) { || strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
if (state->helo_name) { if (state->helo_name) {
if (*state->helo_name != '[') if (*state->helo_name != '[')
status = reject_non_fqdn_hostname(state, state->helo_name, status = reject_non_fqdn_hostname(state, state->helo_name,