summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2015-05-19 20:28:42 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2015-05-19 22:36:35 +0100
commit1705dd20918634cfce236049e47d0fe43753dbc8 (patch)
treeca9ef683885cf9993ad1abae356ff67cb4965955 /src
parent1f155f8e69b44ee7678dd1009ae0348e5c8d768e (diff)
Change HELO-verify forward case from byname to bydns and add DNSSEC tracking
Diffstat (limited to 'src')
-rw-r--r--src/src/dns.c285
-rw-r--r--src/src/expand.c1
-rw-r--r--src/src/globals.c1
-rw-r--r--src/src/globals.h1
-rw-r--r--src/src/host.c9
-rw-r--r--src/src/smtp_in.c57
6 files changed, 176 insertions, 178 deletions
diff --git a/src/src/dns.c b/src/src/dns.c
index ad98a9d4e..79c4ed3fc 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -796,7 +796,7 @@ for (i = 0; i < 10; i++)
cname_rr.data = type_rr.data = NULL;
for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
{
if (rr->type == type)
@@ -895,25 +895,25 @@ switch (type)
{
/* The "mx hosts only" type doesn't require any special action here */
case T_MXH:
- return dns_lookup(dnsa, name, T_MX, fully_qualified_name);
+ return dns_lookup(dnsa, name, T_MX, fully_qualified_name);
/* Find nameservers for the domain or the nearest enclosing zone, excluding
the root servers. */
case T_ZNS:
- type = T_NS;
- /* FALLTHROUGH */
+ type = T_NS;
+ /* FALLTHROUGH */
case T_SOA:
- {
- const uschar *d = name;
- while (d != 0)
- {
- int rc = dns_lookup(dnsa, d, type, fully_qualified_name);
- if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc;
- while (*d != 0 && *d != '.') d++;
- if (*d++ == 0) break;
- }
- return DNS_NOMATCH;
- }
+ {
+ const uschar *d = name;
+ while (d != 0)
+ {
+ int rc = dns_lookup(dnsa, d, type, fully_qualified_name);
+ if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc;
+ while (*d != 0 && *d != '.') d++;
+ if (*d++ == 0) break;
+ }
+ return DNS_NOMATCH;
+ }
/* Try to look up the Client SMTP Authorization SRV record for the name. If
there isn't one, search from the top downwards for a CSA record in a parent
@@ -922,148 +922,147 @@ switch (type)
can tell whether to look at the explicit authorization field or the subdomain
assertion field. */
case T_CSA:
- {
- uschar *srvname, *namesuff, *tld, *p;
- int priority, weight, port;
- int limit, rc, i;
- BOOL ipv6;
- dns_record *rr;
- dns_scan dnss;
-
- DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name);
-
- srvname = string_sprintf("_client._smtp.%s", name);
- rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
- if (rc == DNS_SUCCEED || rc == DNS_AGAIN)
- {
- if (rc == DNS_SUCCEED) *fully_qualified_name = string_copy(name);
- return rc;
- }
+ {
+ uschar *srvname, *namesuff, *tld, *p;
+ int priority, weight, port;
+ int limit, rc, i;
+ BOOL ipv6;
+ dns_record *rr;
+ dns_scan dnss;
+
+ DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name);
+
+ srvname = string_sprintf("_client._smtp.%s", name);
+ rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
+ if (rc == DNS_SUCCEED || rc == DNS_AGAIN)
+ {
+ if (rc == DNS_SUCCEED) *fully_qualified_name = string_copy(name);
+ return rc;
+ }
- /* Search for CSA subdomain assertion SRV records from the top downwards,
- starting with the 2nd level domain. This order maximizes cache-friendliness.
- We skip the top level domains to avoid loading their nameservers and because
- we know they'll never have CSA SRV records. */
+ /* Search for CSA subdomain assertion SRV records from the top downwards,
+ starting with the 2nd level domain. This order maximizes cache-friendliness.
+ We skip the top level domains to avoid loading their nameservers and because
+ we know they'll never have CSA SRV records. */
- namesuff = Ustrrchr(name, '.');
- if (namesuff == NULL) return DNS_NOMATCH;
+ namesuff = Ustrrchr(name, '.');
+ if (namesuff == NULL) return DNS_NOMATCH;
+ tld = namesuff + 1;
+ ipv6 = FALSE;
+ limit = dns_csa_search_limit;
+
+ /* Use more appropriate search parameters if we are in the reverse DNS. */
+
+ if (strcmpic(namesuff, US".arpa") == 0)
+ if (namesuff - 8 > name && strcmpic(namesuff - 8, US".in-addr.arpa") == 0)
+ {
+ namesuff -= 8;
tld = namesuff + 1;
- ipv6 = FALSE;
- limit = dns_csa_search_limit;
+ limit = 3;
+ }
+ else if (namesuff - 4 > name && strcmpic(namesuff - 4, US".ip6.arpa") == 0)
+ {
+ namesuff -= 4;
+ tld = namesuff + 1;
+ ipv6 = TRUE;
+ limit = 3;
+ }
- /* Use more appropriate search parameters if we are in the reverse DNS. */
+ DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld);
- if (strcmpic(namesuff, US".arpa") == 0)
- {
- if (namesuff - 8 > name && strcmpic(namesuff - 8, US".in-addr.arpa") == 0)
- {
- namesuff -= 8;
- tld = namesuff + 1;
- limit = 3;
- }
- else if (namesuff - 4 > name && strcmpic(namesuff - 4, US".ip6.arpa") == 0)
- {
- namesuff -= 4;
- tld = namesuff + 1;
- ipv6 = TRUE;
- limit = 3;
- }
- }
+ /* Do not perform the search if the top level or 2nd level domains do not
+ exist. This is quite common, and when it occurs all the search queries would
+ go to the root or TLD name servers, which is not friendly. So we check the
+ AUTHORITY section; if it contains the root's SOA record or the TLD's SOA then
+ the TLD or the 2LD (respectively) doesn't exist and we can skip the search.
+ If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
+ the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
+
+ if (rc == DNS_NOMATCH)
+ {
+ /* This is really gross. The successful return value from res_search() is
+ the packet length, which is stored in dnsa->answerlen. If we get a
+ negative DNS reply then res_search() returns -1, which causes the bounds
+ checks for name decompression to fail when it is treated as a packet
+ length, which in turn causes the authority search to fail. The correct
+ packet length has been lost inside libresolv, so we have to guess a
+ replacement value. (The only way to fix this properly would be to
+ re-implement res_search() and res_query() so that they don't muddle their
+ success and packet length return values.) For added safety we only reset
+ the packet length if the packet header looks plausible. */
+
+ HEADER *h = (HEADER *)dnsa->answer;
+ if (h->qr == 1 && h->opcode == QUERY && h->tc == 0
+ && (h->rcode == NOERROR || h->rcode == NXDOMAIN)
+ && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0
+ && ntohs(h->nscount) >= 1)
+ dnsa->answerlen = MAXPACKET;
+
+ for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
+ rr;
+ rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
+ )
+ if (rr->type != T_SOA) continue;
+ else if (strcmpic(rr->name, US"") == 0 ||
+ strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
+ else break;
+ }
- DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld);
+ for (i = 0; i < limit; i++)
+ {
+ if (ipv6)
+ {
+ /* Scan through the IPv6 reverse DNS in chunks of 16 bits worth of IP
+ address, i.e. 4 hex chars and 4 dots, i.e. 8 chars. */
+ namesuff -= 8;
+ if (namesuff <= name) return DNS_NOMATCH;
+ }
+ else
+ /* Find the start of the preceding domain name label. */
+ do
+ if (--namesuff <= name) return DNS_NOMATCH;
+ while (*namesuff != '.');
+
+ DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1);
+
+ srvname = string_sprintf("_client._smtp.%s", namesuff + 1);
+ rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
+ if (rc == DNS_AGAIN) return rc;
+ if (rc != DNS_SUCCEED) continue;
+
+ /* Check that the SRV record we have found is worth returning. We don't
+ just return the first one we find, because some lower level SRV record
+ might make stricter assertions than its parent domain. */
+
+ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
+ rr;
+ rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
+ {
+ if (rr->type != T_SRV) continue;
- /* Do not perform the search if the top level or 2nd level domains do not
- exist. This is quite common, and when it occurs all the search queries would
- go to the root or TLD name servers, which is not friendly. So we check the
- AUTHORITY section; if it contains the root's SOA record or the TLD's SOA then
- the TLD or the 2LD (respectively) doesn't exist and we can skip the search.
- If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
- the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
+ /* Extract the numerical SRV fields (p is incremented) */
+ p = rr->data;
+ GETSHORT(priority, p);
+ GETSHORT(weight, p); weight = weight; /* compiler quietening */
+ GETSHORT(port, p);
- if (rc == DNS_NOMATCH)
- {
- /* This is really gross. The successful return value from res_search() is
- the packet length, which is stored in dnsa->answerlen. If we get a
- negative DNS reply then res_search() returns -1, which causes the bounds
- checks for name decompression to fail when it is treated as a packet
- length, which in turn causes the authority search to fail. The correct
- packet length has been lost inside libresolv, so we have to guess a
- replacement value. (The only way to fix this properly would be to
- re-implement res_search() and res_query() so that they don't muddle their
- success and packet length return values.) For added safety we only reset
- the packet length if the packet header looks plausible. */
-
- HEADER *h = (HEADER *)dnsa->answer;
- if (h->qr == 1 && h->opcode == QUERY && h->tc == 0
- && (h->rcode == NOERROR || h->rcode == NXDOMAIN)
- && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0
- && ntohs(h->nscount) >= 1)
- dnsa->answerlen = MAXPACKET;
-
- for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
- rr != NULL;
- rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
- if (rr->type != T_SOA) continue;
- else if (strcmpic(rr->name, US"") == 0 ||
- strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
- else break;
- }
+ /* Check the CSA version number */
+ if (priority != 1) continue;
- for (i = 0; i < limit; i++)
+ /* If it's making an interesting assertion, return this response. */
+ if (port & 1)
{
- if (ipv6)
- {
- /* Scan through the IPv6 reverse DNS in chunks of 16 bits worth of IP
- address, i.e. 4 hex chars and 4 dots, i.e. 8 chars. */
- namesuff -= 8;
- if (namesuff <= name) return DNS_NOMATCH;
- }
- else
- /* Find the start of the preceding domain name label. */
- do
- if (--namesuff <= name) return DNS_NOMATCH;
- while (*namesuff != '.');
-
- DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1);
-
- srvname = string_sprintf("_client._smtp.%s", namesuff + 1);
- rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
- if (rc == DNS_AGAIN) return rc;
- if (rc != DNS_SUCCEED) continue;
-
- /* Check that the SRV record we have found is worth returning. We don't
- just return the first one we find, because some lower level SRV record
- might make stricter assertions than its parent domain. */
-
- for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
- rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
- {
- if (rr->type != T_SRV) continue;
-
- /* Extract the numerical SRV fields (p is incremented) */
- p = rr->data;
- GETSHORT(priority, p);
- GETSHORT(weight, p); weight = weight; /* compiler quietening */
- GETSHORT(port, p);
-
- /* Check the CSA version number */
- if (priority != 1) continue;
-
- /* If it's making an interesting assertion, return this response. */
- if (port & 1)
- {
- *fully_qualified_name = namesuff + 1;
- return DNS_SUCCEED;
- }
- }
+ *fully_qualified_name = namesuff + 1;
+ return DNS_SUCCEED;
}
- return DNS_NOMATCH;
}
+ }
+ return DNS_NOMATCH;
+ }
default:
- if (type >= 0)
- return dns_lookup(dnsa, name, type, fully_qualified_name);
+ if (type >= 0)
+ return dns_lookup(dnsa, name, type, fully_qualified_name);
}
/* Control should never reach here */
diff --git a/src/src/expand.c b/src/src/expand.c
index 209270163..7e10ee553 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -648,6 +648,7 @@ static var_entry var_table[] = {
{ "sender_address_local_part", vtype_localpart, &sender_address },
{ "sender_data", vtype_stringptr, &sender_data },
{ "sender_fullhost", vtype_stringptr, &sender_fullhost },
+ { "sender_helo_dnssec", vtype_bool, &sender_helo_dnssec },
{ "sender_helo_name", vtype_stringptr, &sender_helo_name },
{ "sender_host_address", vtype_stringptr, &sender_host_address },
{ "sender_host_authenticated",vtype_stringptr, &sender_host_authenticated },
diff --git a/src/src/globals.c b/src/src/globals.c
index 3cbbbd311..c0d03daaa 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1202,6 +1202,7 @@ uschar *sender_address_unrewritten = NULL;
uschar *sender_data = NULL;
unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32];
uschar *sender_fullhost = NULL;
+BOOL sender_helo_dnssec = FALSE;
uschar *sender_helo_name = NULL;
uschar **sender_host_aliases = &no_aliases;
uschar *sender_host_address = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index d90854cbe..1aca0714f 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -755,6 +755,7 @@ extern uschar *sender_address_unrewritten; /* Set if rewritten by verify */
extern uschar *sender_data; /* lookup result for senders */
extern unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for sender domain */
extern uschar *sender_fullhost; /* Sender host name + address */
+extern BOOL sender_helo_dnssec; /* True if HELO verify used DNS and was DNSSEC */
extern uschar *sender_helo_name; /* Host name from HELO/EHLO */
extern uschar **sender_host_aliases; /* Points to list of alias names */
extern unsigned int sender_host_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for incoming host */
diff --git a/src/src/host.c b/src/src/host.c
index 4772a7c6c..5629d7db2 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -1668,11 +1668,10 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
store_pool = POOL_PERM; /* Save names in permanent storage */
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
- {
- if (rr->type == T_PTR) count++;
- }
+ if (rr->type == T_PTR)
+ count++;
/* Get store for the list of aliases. For compatibility with
gethostbyaddr, we make an empty list if there are none. */
@@ -1682,7 +1681,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
/* Re-scan and extract the names */
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
{
uschar *s = NULL;
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index b2f8b0fc8..aa3936288 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -3003,31 +3003,25 @@ else
/* If a host name is known, check it and all its aliases. */
- if (sender_host_name != NULL)
- {
- helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0;
-
- if (helo_verified)
+ if (sender_host_name)
+ if ((helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0))
{
- /*XXX have sender_host_dnssec */
+ sender_helo_dnssec = sender_host_dnssec;
HDEBUG(D_receive) debug_printf("matched host name\n");
}
else
{
uschar **aliases = sender_host_aliases;
- while (*aliases != NULL)
- {
- helo_verified = strcmpic(*aliases++, sender_helo_name) == 0;
- if (helo_verified) break;
- /*XXX have sender_host_dnssec */
- }
- HDEBUG(D_receive)
- {
- if (helo_verified)
+ while (*aliases)
+ if ((helo_verified = strcmpic(*aliases++, sender_helo_name) == 0))
+ {
+ sender_helo_dnssec = sender_host_dnssec;
+ break;
+ }
+
+ HDEBUG(D_receive) if (helo_verified)
debug_printf("matched alias %s\n", *(--aliases));
- }
}
- }
/* Final attempt: try a forward lookup of the helo name */
@@ -3035,31 +3029,34 @@ else
{
int rc;
host_item h;
+ dnssec_domains d;
+ host_item *hh;
+
h.name = sender_helo_name;
h.address = NULL;
h.mx = MX_NONE;
h.next = NULL;
+ d.request = US"*";
+ d.require = US"";
+
HDEBUG(D_receive) debug_printf("getting IP address for %s\n",
sender_helo_name);
-/*XXX would like to determine dnssec status here */
-/* need to change to bydns */
- rc = host_find_byname(&h, NULL, 0, NULL, TRUE);
+ rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A,
+ NULL, NULL, NULL, &d, NULL, NULL);
if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL)
- {
- host_item *hh = &h;
- while (hh != NULL)
- {
+ for (hh = &h; hh; hh = hh->next)
if (Ustrcmp(hh->address, sender_host_address) == 0)
{
helo_verified = TRUE;
+ if (h.dnssec == DS_YES) sender_helo_dnssec = TRUE;
HDEBUG(D_receive)
- debug_printf("IP address for %s matches calling address\n",
- sender_helo_name);
+ {
+ debug_printf("IP address for %s matches calling address\n"
+ "Forward DNS security status: %sverified\n",
+ sender_helo_name, sender_helo_dnssec ? "" : "un");
+ }
break;
}
- hh = hh->next;
- }
- }
}
}
@@ -3473,7 +3470,7 @@ while (done <= 0)
now obsolescent, since the verification can now be requested selectively
at ACL time. */
- helo_verified = helo_verify_failed = FALSE;
+ helo_verified = helo_verify_failed = sender_helo_dnssec = FALSE;
if (helo_required || helo_verify)
{
BOOL tempfail = !smtp_verify_helo();