You can use access control mappings to prevent people from relaying SMTP mail through your Messaging Server system. For example, you can prevent people from using your mail system to relay junk mail to hundreds or thousands of Internet mailboxes.
By default, Messaging Server prevents all SMTP relaying activity, including relaying by local POP and IMAP users.
Blocking unauthorized relaying while allowing it for legitimate local users requires configuring Messaging Server to know how to distinguish between the two classes of users. For example, local users using POP or IMAP depend upon Messaging Server to act as an SMTP relay.
To prevent SMTP relay, you must be able to:
Differentiate Between Internal and External Mail
To enable SMTP relay by internal hosts and clients, you must add your “internal” IP addresses or subnets to the INTERNAL_IP mapping table.
In order to block mail relaying activities, the MTA must first be able to differentiate between internal mail originated at your site and external mail originated out on the Internet and passing through your system back out to the Internet. The former class of mail you want to permit; the latter class you want to block. This differentiation is achieved using the switchchannel keyword on your inbound SMTP channel, usually the tcp_local channel, and is set by default.
The switchchannel keyword works by causing the SMTP server to look at the actual IP address associated with the incoming SMTP connection. Messaging Server uses that IP address, in conjunction with your rewrite rules, to differentiate between an SMTP connection originated within your domain and a connection from outside of your domain. This information can then be used to segregate the message traffic between internal and external traffic.
The MTA configuration described below is setup by default so that the server can differentiate between your internal and external message traffic.
In the configuration file, immediately before the local channel, is a defaults channel with the noswitchchannel keyword:
! final rewrite rules defaults noswitchchannel ! Local store ims-ms ...
The incoming TCP/IP channel specifies the switchchannel and remotehost keywords; for example:
tcp_local smtp single_sys mx switchchannel remotehost TCP-DAEMON
After the incoming TCP/IP channel definition, is a similar channel with a different name; for example:
tcp_intranet smtp single_sys mx allowswitchchannel routelocal tcp_intranet-daemon
The routelocal channel keyword causes the MTA, when rewriting an address to the channel, to attempt to “short circuit” any explicit routing in the address through this channel, thereby blocking possible attempts to relay by means of looping through internal SMTP hosts via explicitly source routed addresses.
With the above configuration settings, SMTP mail generated within your domain will come in via the tcp_intranet channel. All other SMTP mail will come in via the tcp_local channel. Mail is distinguished between internal and external based upon which channel it comes in on.
How does this work? The key is the switchchannel keyword. The keyword is applied to the tcp_local channel. When a message comes in your SMTP server, that keyword causes the server to look at the source IP address associated with the incoming connection. The server attempts a reverse-pointing envelope rewrite of the literal IP address of the incoming connection, looking for an associated channel. If the source IP address matches an IP address or subnet in your INTERNAL_IP mapping table, the rewrite rule which calls out to that mapping table causes the address to rewrite to the tcp_intranet channel.
Since the tcp_intranet channel is marked with the allowswitchchannel keyword, the message is switched to the tcp_intranet channel and comes in on that channel. If the message comes in from a system whose IP address is not in the INTERNAL_IP mapping table, the reverse-pointing envelope rewrite will either rewrite to the tcp_local or, perhaps to some other channel. However, it will not rewrite to the tcp_intranet channel and since all other channels are marked noswitchchannel by default, the message will not switch to another channel and will remain with the tcp_local channel.
Note that any mapping table or conversion file entries which use the string “tcp_local” may need to be changed to either “tcp_*” or “tcp_intranet” depending upon the usage.
Your site might have “local” client users who are not part of your physical network. When these users submit mail, the message submissions come in from an external IP address—for instance, arbitrary Internet Service Providers. If your users use mail clients that can perform SASL authentication, then their authenticated connections can be distinguished from arbitrary other external connections. The authenticated submissions you can then permit, while denying non-authenticated relay submission attempts. Differentiating between authenticated and non-authenticated connections is achieved using the saslswitchchannel keyword on your inbound SMTP channel, usually the tcp_local channel.
The saslswitchchannel keyword takes an argument specifying the channel to switch to; if an SMTP sender succeeds in authenticating, then their submitted messages are considered to come in the specified switched to channel.
In your configuration file, add a new TCP/IP channel definition with a distinct name; for example:
tcp_auth smtp single_sys mx mustsaslserver noswitchchannel TCP-INTERNAL
This channel should not allow regular channel switching (that is, it should have noswitchchannel on it either explicitly or implied by a prior defaults line). This channel should have mustsaslserver on it.
Modify your tcp_local channel by adding maysaslserver and saslswitchchannel tcp_auth, as shown in the following example:
tcp_local smtp mx single_sys maysaslserver saslswitchchannel \ tcp_auth switchchannel |TCP-DAEMON
With this configuration, SMTP mail sent by users who can authenticate with a local password will now come in the tcp_auth channel. Unauthenticated SMTP mail sent from internal hosts will still come in tcp_internal. All other SMTP mail will come in tcp_local.
Now to the point of this example: preventing unauthorized people from relaying SMTP mail through your system. First, keep in mind that you want to allow local users to relay SMTP mail. For instance, POP and IMAP users rely upon using Messaging Server to send their mail. Note that local users may either be physically local, in which case their messages come in from an internal IP address, or may be physically remote but able to authenticate themselves as local users.
You want to prevent random people out on the Internet from using your server as a relay. With the configuration described in the following sections, you can differentiate between these classes of users and block the correct class. Specifically, you want to block mail from coming in your tcp_local channel and going back out that same channel. To that end, an ORIG_SEND_ACCESS mapping table is used.
An ORIG_SEND_ACCESS mapping table may be used to block traffic based upon the source and destination channel. In this case, traffic from and back to the tcp_local channel is to be blocked. This is realized with the following ORIG_SEND_ACCESS mapping table:
ORIG_SEND_ACCESS tcp_local|*|tcp_local|* $NRelaying$ not$ permitted
In this example, the entry states that messages cannot come in the tcp_local channel and go right back out it. That is, this entry disallows external mail from coming in your SMTP server and being relayed right back out to the Internet.
An ORIG_SEND_ACCESS mapping table is used rather than a SEND_ACCESS mapping table so that the blocking will not apply to addresses that originally match the ims-ms channel (but which may expand via an alias or mailing list definition back to an external address). With a SEND_ACCESS mapping table one would have to go to extra lengths to allow outsiders to send to mailing lists that expand back out to external users, or to send to users who forward their messages back out to external addresses.
In the Messaging Server, there are a number of different ways to ensure that all mail accepted for delivery or forwarding comes from an address with a valid DNS name. The simplest way is to put the mailfromdnsverify channel keyword on the tcp_local channel.
Messaging Server also provides the dns_verify program which allows you to ensure that all mail accepted for delivery or forwarding comes from an address with a valid DNS name using the following rule in ORIG_MAIL_ACCESS:
ORIG_MAIL_ACCESS TCP|*|*|*|*|SMTP*|MAIL|*|*@*|*|* \ $[msg-svr-base/lib/dns_verify.so,\ dns_verify,$7|$$y|$$NInvalid$ host:$ $$7$ -$ %e]
The line breaks in the above example are syntactically significant in such mapping entries. The backslash character is a way of legally continuing on to the next line.
The dns_verify image can also be used to check incoming connections against things like the RBL (Realtime Blackhole List), MAPS (Mail Abuse Prevention System, DUL (Dial-up User List), or ORBS (Open Relay Behavior-modification System) lists as another attempt to protect against UBE. As with the new mailfromdnsverify keyword, there’s also a separate “simpler to configure” approach one can use for such checks rather than doing the dns_verify callout. The simpler approach is to use the DNS_VERIFY_DOMAIN option in the dispatcher.cnf file. For example, in the [SERVICE=SMTP] section, set instances of the option to the various lists you want to check against:
[SERVICE=SMTP] PORT=25 ! ...rest of normal options... DNS_VERIFY_DOMAIN=sbl-xbl.spamhaus.org. DNS_VERIFY_DOMAIN=list.dsbl.org. ...etc...
In this case, messages are rejected at the SMTP level, that is, the messages are rejected during the SMTP dialogue and thus never sent to the MTA. The disadvantage of this simpler approach is that it does the checks for all normal incoming SMTP messages including those from internal users. This is less efficient and potentially problematic if your Internet connectivity goes down. An alternative is to call out to dns_verify from a PORT_ACCESS mapping table or ORIG_MAIL_ACCESS mapping table. In the PORT_ACCESS mapping table, you can have an initial entry or entries that don’t check for local internal IP addresses or message submitters and a later entry that does the desired check for everyone else. Or, in an ORIG_MAIL_ACCESS mapping table, if you only apply the check on messages coming in the tcp_local channel then you’re skipping it for messages coming from your internal systems/clients. Examples using the entry points to dns_verify are shown below.
PORT_ACCESS ! Allow internal connections in unconditionally *|*|*|*|* $C$|INTERNAL_IP;$3|$Y$E ! Check other connections against RBL list TCP|*|25|*|* \ $C$[<msg-svr-base/lib/dns_verify.so,dns_verify_domain_port,$1,\ dnsblock.siroe.com,Your$ host$ ($1)$ found$ on$ dnsblock$ list]$E * $YEXTERNAL ORIG_MAIL_ACCESS TCP|*|25|*|*|SMTP*|*|tcp_local|*@*|*|* \ $C$[msg-svr-base/lib/dns_verify.so,\ dns_verify_domain,$1,sbl-xbl.spamhaus.org.]$E
For more information see: Performance Tuning Realtime BlockLists (RBL) Lookups.
The PORT_ACCESS table is probed both by the dispatcher, when accepting connections, and by the tcp_smtp_server process under certain circumstances.
tcp_smtp_server processes always check the PORT_ACCESS table for channels marked maysaslserver or mustsaslserver, and they will do it for all channels if bit 4 (value 16) of the LOG_CONNECTION in option.dat is set.
So if either of those are true, the customer needs to be aware that his PORT_ACCESS table is being processed twice for every connection. This may be a trivial overhead except that callouts to things like DNS RBLs or LDAP lookups can be relatively expensive in terms of their impact on SMTP server response time. For this reason, you want to avoid doing them any more than necessary. That is one reason the callout in the example above is coded after the INTERNAL_IP lookup. If the SMTP client is in your INTERNAL_IP table, then you allow the connection without doing the RBL lookup. Reversing that order would mean your local clients would be delayed by RBL lookups. To prevent doing this twice, add a check for one the flags set by dispatcher or tcp_smtp_server so that you only process that table entry when one of those is set or not. For example, add $:Ato the entry:
TCP|*|25|*|* \ $C$:A$[<msg-svr-base/lib/dns_verify.so,dns_verify_domain_port,$1,\ dnsblock.siroe.com,Your$ host$ ($1)$ found$ on$ dnsblock$ list]$E * $YEXTERNAL
We added the $:A after the $C so the table processing will continue down the table if this does not match. The $:A specifies that this entry be processed only if it is being done by the dispatcher, that is, not when done by tcp_smtp_server. Alternatively, if you wanted to cause it to be done only in tcp_smtp_server, check for S instead:
TCP|*|25|*|* \ $C$:S$[<msg-svr-base/lib/dns_verify.so,dns_verify_domain_port,$1,\ dnsblock.siroe.com,Your$ host$ ($1)$ found$ on$ dnsblock$ list]$E * $YEXTERNAL
The negative check would be $;A to check that A is not set, or $;S to check that S is not set.
The dns_verify program supports DNS-based databases used to determine incoming SMTP connections that might send unsolicited bulk mail. Some of the publicly available DNS databases do not contain TXT records that are typically used for this purpose. Instead, they only contain A records.
In a typical setup, the TXT record found in the DNS for a particular IP address contains an error message suitable to return to the SMTP client when refusing a message. But, if a TXT record is not found and an A record is found, then versions of dns_verify prior to Messaging Server 5.2 returned the message “No error text available.”
dns_verify now supports an option that specifies a default text that is used in the event that no TXT record is available. For example, the following PORT_ACCESS mapping table shows how to enable this option:
PORT_ACCESS *|*|*|*|* $C$|INTERNAL_IP;$3|$Y$E \ TCP|*|25|*|* \ $C$[<msg-svr-base/lib/dns_verify.so \ ,dns_verify_domain_port,$1,dnsblock.siroe.com,Your$ host$ ($1)$ \ found$ on$ dnsblock$ list]$E * $YEXTERNAL
In this example, if the remote system is found in a query in the domain dnsblock.siroe.com, but no TXT record is available, then the following message is returned, “Your host a.b.c.d found on dnsblock list.”