Email relay rejection in SMTP NOTE: The following instructions were written in early 1998 and are for configuring Sendmail v8.8 to reject third party relaying. (Sendmail v8.9 comes pre-configured to reject relaying and these steps are not necessary). If you are running a vendor supplied version of sendmail, or have not upgraded your sendmail in several years, it is likely not v8.8 or higher. You would then need to compile and install v8.8 sendmail to use these instructions, or to v8.9 (where these instructions are not necessary). For source code, see: http://www.sendmail.org/ The changes are easy and based closely on information found on the web in anti-spam sites, for example: http://www.sendmail.org/antispam.html http://spam.abuse.net/spam/tools/mailblock.html#sendmail http://www.informatik.uni-kiel.de/%7Eca/email/english.html At this point, we are only trying to prevent C&C mail exchangers from being used as an outside-to-outside relay site, not trying to cut off all mail from certain junk email sites. That is equally easy, though. The relay rejection we have implemented is accomplished by the additions, found below, to the sendmail.cf file on your sendmail mail exchange server. The rejection works like this. When an SMTP connection comes in, the IP address of the sending site is known (supplied in the "client_addr" macro). There is also the macro "client_name", which is the domain name that "client_addr" maps to. A check is made to see whether either the incoming IP address is in the class "LocalIP" or the incoming name is in the class "LocalNames". Actually, the check is whether "LocalIP" matches a prefix of the IP address or "LocalNames" matches a suffix of the "client_name". If a match is made, the mail is considered local and allowed to go through. If it isn't local then the SMTP connection is coming from off-site. A check is then made of the argument to the SMTP "RCPT" command to see if it ends in one of the members of "RelayTo". Actually, this check is a bit more complicated than that so that it can catch addresses of the form, user%someplace.else@u.washington.edu ... so those can be rejected as well. Since the check is made on the "RCPT" argument, this comes before forwarding or aliasing. This means that people can still set their forwarding to redirect their email to someplace else (e.g., if they have left the University or wish to get all their email at another site). This forwarding will work and their email will make it there as expected. We're currently running a version 8 sendmail with parseaddr.c's function rscheck() modified to log the rejections instead of actually rejecting. Below is a copy of the m4 files as used by C&C to add all these to the sendmail config files. See the sites listed earlier for original source (they came from the informatik.uni-kiel.de site) and more detailed information on modifying sendmail behaviour to deal with junk mail. ---------------------- additions to sendmail.cf rules -------------------- # Class LocalNames contains names of domains which may use us as a relay. C{LocalNames} washington.edu # Class LocalIP contains prefixes of nets which may use us as a relay. C{LocalIP} 140.142. C{LocalIP} 128.95. C{LocalIP} 128.208. # Class RelayTo contains names of domains we're willing to relay mail # (that was originated outside of LocalIP and LocalNames) to. C{RelayTo} washington.edu C{RelayTo} uwash.com # Client_addr and client_name are macros equal to the ip addr and the # name from that ip addr of the client connecting to us. This rule is # passed the argument to the RCPT command. If this resolves to # anything but the error mailer we are accepting the mail. We are # trying to not be used as a relay mailer. Scheck_rcpt # first: get client address R$+ $: $(dequote "" $&{client_addr} $) $| $1 R0 $| $* $@ ok client_addr is 0 for sendmail -bs R$={LocalIP}$* $| $* $@ ok from here # next: get client name R$* $| $+ $: $(dequote "" $&{client_name} $) $| $2 R $| $* $@ ok no client name: directly invoked R$*$=w $| $* $@ ok from here R$*$={LocalNames} $| $* $@ ok from allowed system # now check other side R$* $| $* $: $>3 $2 # remove RelayTo part (maybe repeatedly) R$*<@$*$={RelayTo}.>$* $>3 $1 $4 # remove local part (maybe repeatedly) R$*<@$=w.>$* $>3 $1 $3 # still something left? R$*<@$+>$* $#error $@ 5.7.1 $: 571 we do not relay ---------------------------- check_rcpt.m4 ------------------------------- divert(-1) # # Copyright (c) 1997 Claus Assmann # # In short: you can do whatever you want with this, but don't blame me! # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # divert(0) VERSIONID(`$Id: check_rcpt.m4,v 1.3 1997/04/25 23:07:29 hubert Exp $') divert(2) define(`_USE_NAMES_RULES',`R $`'| $`'* $`'@ ok no client name: directly invoked R$`'*$`'=w $`'| $`'* $`'@ ok from here R$`'*$`'={LocalNames} $`'| $`'* $`'@ ok from allowed system') LOCAL_RULESETS # Client_addr and client_name are macros equal to the ip addr and the name from # that ip addr of the client connecting to us. This rule is passed the argument # to the RCPT command. If this resolves to anything but the error mailer we # are accepting the mail. We are trying to not be used as a relay mailer. Scheck_rcpt ifdef(`_USE_RCPT_', `', `errprint(`HACK "check_rcpt" requires use_ip or use_names')')dnl ifdef(`_USE_IP_', # first: get client address R$+ $: $(dequote "" $&{client_addr} $) $| $1 R0 $| $* $@ ok client_addr is 0 for sendmail -bs R$={LocalIP}$* $| $* $@ ok from here ifdef(`_USE_NAMES_', # next: get client name R$* $| $+ $: $(dequote "" $&{client_name} $) $| $2 _USE_NAMES_RULES ), # first: get client name R$+ $: $(dequote "" $&{client_name} $) $| $1 _USE_NAMES_RULES )dnl # now check other side R$* $| $* $: $>3 $2 ifdef(`_USE_RELAYTO_', # remove RelayTo part (maybe repeatedly) R$*<@$*$={RelayTo}.>$* $>3 $1 $4 )dnl # remove local part (maybe repeatedly) R$*<@$=w.>$* $>3 $1 $3 # still something left? R$*<@$+>$* $#error $@ 5.7.1 $: 571 we do not relay --------------------------------- use_ip.m4 ------------------------------- divert(-1) # # Copyright (c) 1996 Claus Assmann # # In short: you can do whatever you want with this, but don't blame me! # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # divert(0) VERSIONID(`$Id: use_ip.m4,v 1.2 1997/04/25 22:55:50 hubert Exp $') divert(-1) define(`_USE_IP_',1) define(`LOCAL_IP', `PUSHDIVERT(6)C{LocalIP} $1 POPDIVERT`'dnl')dnl define(`_USE_RCPT_',1) PUSHDIVERT(6) # Class LocalIP contains prefixes of nets which may use us as a relay. POPDIVERT ------------------------------ use_names.m4 ------------------------------- divert(-1) # # Copyright (c) 1996 Claus Assmann # # In short: you can do whatever you want with this, but don't blame me! # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # divert(0) VERSIONID(`$Id: use_names.m4,v 1.2 1997/04/25 22:58:29 hubert Exp $') divert(-1) define(`_USE_NAMES_',1) define(`LOCAL_NAME', `PUSHDIVERT(6)C{LocalNames} $1 POPDIVERT`'dnl')dnl define(`_USE_RCPT_',1) PUSHDIVERT(6) # Class LocalNames contains names of domains which may use us as a relay. POPDIVERT ---------------------------- use_relayto.m4 ------------------------------- divert(-1) # # Copyright (c) 1996 Claus Assmann # # In short: you can do whatever you want with this, but don't blame me! # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # divert(0) VERSIONID(`$Id: use_relayto.m4,v 1.2 1997/04/25 23:01:15 hubert Exp $') divert(-1) define(`_USE_RELAYTO_',1) define(`RELAY_TO', `PUSHDIVERT(6)C{RelayTo} $1 POPDIVERT`'dnl')dnl PUSHDIVERT(6) # Class RelayTo contains names of domains we're willing to relay mail # (that was originated outside of LocalIP and LocalNames) to. POPDIVERT ---------------------------------- end -----------------------------------