Dns_verify callouts

From Messaging Server Technical Reference Wiki
Jump to: navigation, search


The dns_verify.so library provides a collection of mapping callouts that can be used to validate and/or resolve domains names or IP addresses via the DNS or local host tables. (Exactly what sources are used, and in what order, is controlled at the operating system level, usually by settings in /etc/resolv.conf.) Three basic types of operations are provided:

  • DNS A/AAAA record and host table lookups for domain names.
  • DNS PTR record and host table lookups for IP addresses.
  • TXT record lookups for checking IP addresses against blacklists.

For example, dns_verify.so can be used to verify that an entry in DNS or host tables exists for the domain used in the SMTP MAIL FROM: command, or to look up an IP address in a blacklist supplied by such services as MAPS and ORBS. The message can be rejected or accepted based on the presence or absence of a corresponding DNS record.

IMPORTANT NOTE: Performing DNS existence checks may result in the rejection of some valid messages. For instance, this could include mail from legitimate sites that simply have not yet registered their domain name, or during periods of bad information in DNS.

The dns_verify.so library has several routines that can be called:

  • dns_verify
  • dns_verify_ptr (new in 7.0.5.34)
  • dns_verify_domain
  • dns_verify_domain_port
  • dns_verify_domain_warn
  • dns_verify_ipv4 (new in 8.0.1.2)
  • dns_verify_ipv6 (new in 8.0.1.2)
  • dns_get_first_mx (new in 8.0.2.2)

These routines are each described in the sections below.

Note that your mapping tables with dns_verify.so callouts can be tested by using the imsimta test -mapping utility.

The dns_verify routine

The dns_verify routine does a name lookup in the local host tables and an A/AAAA lookup in the DNS. One possible use for this is to check to make sure the domain from the SMTP MAIL FROM: command actually exists. Any mapping table action can be taken if the lookup succeeds, fails, or returns an error.

The dns_verify routine's argument is four strings separated by "|", as follows:

domainname[|success[|failure[|unknown]]] 

domainname
The name to look up in the DNS and local host tables.
success (optional)
If specified, it is the mapping table string to return if domainname is found. If not specified, the default is "$Y".
failure (optional)
If specified, it is the mapping table string to return if domainname is not found. If not specified, the default is "$N".
unknown (optional)
If specified, it is the mapping table string to return if there was a temporary DNS failure during the lookup operation. If not specified, and the success string was specified, that string is used. If neither are specified, the default is "$Y".

Note that in the mapping table any $'s you wish to return need to be doubled. For example, to specify "$Y", you need to put in "$$Y".

An alternate separator can be used instead of "|". To specify an alternate separator, insert it as the first character of the routine's argument. For example, to specify "+" as the separator, use the following syntax:


+domainname+success+failure+unknown

The success, failure, and unknown strings can contain the following format characters:

dns_verify callout substitutions
String Value
%a If successful, the %a substitutes the IP address returned by the lookup operation. An empty string is returned if the domain name exists but doesn't have an associated IP address.
%e If the lookup is not successful, %e substitutes the error message associated with the lookup.
 %n If successful, %n substitutes the primary name for domainname. An empty string is returned if the domain name exists but doesn't have an associated IP address.

The following example shows a simple SEND_ACCESS mapping table entry to verify that the sender's hostname exists in the DNS or local host tables:


SEND_ACCESS 
 
  *tcp_*|*@*|*|*         \
$C$[IMTA_LIB:dns_verify,dns_verify,$3|$$Y|$$NInvalid$ host:$ $$3$-$ %e]$E 

The following example shows a PORT_ACCESS mapping table entry that performs a check against a hypothetical DNS blacklist dnsbl.example.net


PORT_ACCESS 
 
  TCP|*|25|*.*.*.*|*     \
$C$[IMTA_LIB:dns_verify,dns_verify,\
$4.$3.$2.$1.dnsbl.example.net|$$N500$ IP$ blacklisted|$$Y

The dns_verify_ipv4 routine

The dns_verify_ipv4 routine is identical to dns_verify, except that it restricts its results to IPv4 addresses.

The dns_verify_ipv6 routine

The dns_verify_ipv4 routine is identical to dns_verify, except that it restricts its results to IPv6 addresses.

The dns_verify_ptr routine

The dns_verify_ptr routine does an IPv4/IPv6 address lookup in the DNS and/or host tables. Any mapping table action can be taken if the lookup succeeds, fails, or returns an error.

The dns_verify routine's argument is four strings separated by "|", as follows:

ip-address[|success[|failure[|unknown]]] 

ip-address
The IPv4/IPv6 address to be looked up, without any enclosing brackets or prefixes.
success (optional)
If specified, it is the mapping table string to return if ip-address is found. If not specified, the default is "$Y".
failure (optional)
If specified, it is the mapping table string to return if ip-address is not found. If not specified, the default is "$N".
unknown (optional)
If specified, it is the mapping table string to return if there was a temporary DNS failure during the lookup operation. If not specified, and the success string was specified, that string is used. If neither are specified, the default is "$Y".

The dns_verify_ptr routine supports the same alternate delimiter and substitution strings as the dns_verify routine described above.

The dns_verify_domain and dns_verify_domain_port routines

The dns_verify_domain and dns_verify_domain_port routines are used to perform queries for DNS entries with well-defined blacklist semantics and return pre-defined success, failure, and unknown messages. The same operation can be performed using the dns_verify routine, but with more complicated setup.

The dns_verify_domain_port routine is designed for use in the PORT_ACCESS mapping table. The dns_verify_domain routine is used in the MAIL_ACCESS, SEND_ACCESS, and similar mapping tables.

The dns_verify_domain and dns_verify_domain_port routines perform the same type of action as the dns_verify_domain Dispatcher option. Using the routine allows you more control over which connections trigger the DNS lookups.

The dns_verify_domain and dns_verify_domain_port routines' argument is three strings separated by ",", as follows:

ip-address,domainname[,text-string] 

ip-address
The IP address that you want to check against the blackhole list
domainname
The name of the blackhole list to check against, e.g., blackholes.mail-abuse.org
text-string (optional)
If specified, it is the text to return if no TXT record is available. If not specified, the default is "No Error Text Available".

The dns_verify_domain and dns_verify_domain_port routines check the given list for the IP address. For example, if ip-address is 127.0.0.2, and domainname is bl.spamcop.net, either of dns_verify_domain or dns_verify_domain_port looks up the following name: 2.0.0.127.bl.spamcop.net. They first look up the TXT record for that name, and if it is not available, they look up the A record.

The following examples illustrate the use of these routines.


MAIL_ACCESS 
 
  TCP|*|25|*|*|*|*|tcp_local|*|*|* \
$C$[IMTA_LIB:dns_verify,dns_verify_domain,$1,bl.spamcop.net]$E 
 
PORT_ACCESS 
 
  TCP|*|25|*|*     \
$C$[IMTA_LIB:dns_verify,dns_verify_domain_port,$1,bl.spamcop.net]$E 

The approximate equivalent of the previous MAIL_ACCESS example using the dns_verify routine would be something like:


MAIL_ACCESS 
 
  TCP|*|25|*.*.*.*|*|*|*|tcp_local|*|*|*    \
$C$[IMTA_LIB:dns_verify,dns_verify,+$4.$3.$2.$1.bl.spamcop.net+\
$$N$$X5.7.1|Blocked$ -$ see$ http://spamcop.net/bl.shtml?$$1.$$2.$$3.$$4+$$Y%5D$E 

dns_verify_domain_warn

The dns_verify_domain_warn routine performs the same DNS lookup as the dns_verify_domain and dns_verify_domain_port routines, but instead of rejecting the message if the DNS entry exists, it adds a new header line to the message. The dns_verify_domain_warn routine can be used in any of the sender or recipient access mapping tables.

The dns_verify_domain_warn routine's argument is four strings separated by ",", as follows:

ip-address,domainname[,text-string[,header]] 

The ip-address, domainname, and text-string arguments are the same as for dns_verify_domain and dns_verify_domain_port. header is optional. If specified, it is a string containing the header name, and other optional text, to include before the TXT record string or text-string value. The header name must be one that the MTA recognizes. The default is "X-Dispatcher: ".

The following example shows an ORIG_MAIL_ACCESS mapping table entry to query spamcop.net:


ORIG_MAIL_ACCESS 
 
 TCP|*|25|*|*|*|*|*|*|*|* \
$C$[IMTA_LIB:dns_verify,dns_verify_domain_warn,$1,\
bl.spamcop.net,spamcop.net:$ entry$ found$ for$ $$1,\
X-Dispatcher:$ SPAMfilter$ (spamcop.net):$ ]$E 

For a source IP address of 127.0.0.2, this example would return


$Y$AX-Dispatcher: SPAMfilter (spamcop.net): Blocked - see http://spamcop.net/bl.shtml?127.0.0.2 

This is then added as a header to the message. One way to act on this is to create a system-wide, channel, or user  Sieve filter containing a Sieve action along the lines of:


if header :contains "X-Dispatcher" "SPAMfilter" { discard; } 

dns_get_first_mx

New in MS 8.0.2.2. The dns_get_first_mx routine performs an MX record lookup on the specified domain. Unlike the other DNS routines described in this section, the routine argument consists solely of the domain to look up. The routine succeeds if the lookup is successful and returns the "first" MX record using the same algorithm the MTA uses to determine record order. An empty string is returned if the lookup succeeds but no MX records are found.

The routine fails if the specified domain cannot be found in the DNS. A temporary failure condition is returned if the DNS operation fails with a temporary error.

One possible use of this routine is to determine if a given domain is serviced by a particular collection of servers - which can then be used to implement a limited form of MX rollup. For example, a mapping that will determine if a given domain is handled by Office 365 servers could (at preent) be coded as:


OUTLOOK_MX
 
  *                         $E$[IMTA_LIB:dns_verify,dns_get_first_mx,$0]$C
  *.protection.outlook.com  $Y

This mapping could in turn be called from either a rewrite rule or a FORWARD to route messages to a special channel configured to deliver to an appropriate set of MXes regardless of destination domain.


See also: