New Map Type

Last Update 1997-05-19
Newsgroups: comp.mail.sendmail
From: (Kim)
Subject: Filtering mail by IP address in check_rcpt redux
Message-ID: <>
Date: Tue, 13 May 1997 13:07:46 GMT

The original hack I did to do email filtering by source and destination
IP address was called in the checkcompat function in conf.c of the sendmail
distribution.  After dealing with all the error messages after the mail
was received and processed when an attempt at spam email relaying happened
(Some folks trying to send junk email to some 50,000 AOL addresses managed
to generate some 70 MB of email bounced because of insufficient permissions.)
I decided from some suggestions to rewrite the code into a general map type
that could be applied to check_rcpt to stop the mail at the ingress point.

Here's a brief summary of the code I was beating on last week - it seems 
to have been working okay so far in testing:

I've created a new class of map called 'ip'.
In the file:
     KLocalIP ip FDM /etc/mail/localnetworks

This creates a named map LocalIP of type ip with options 'FDM' from
the file '/etc/mail/localnetworks', which is a list of networks and
netmasks.  The options are mostly implemented as follows:
  F  -  return a failure if the key passed to the map matches a network
  P  -  return a match if the key passed to the map matches a network
  N  -  Set the MF_NODEFER flag on the map - what is this used for, anyways?
  D  -  Set the map to look up all MX records for the key as well.
  H  -  If set, make a failed DNS lookup return success as opposed to
  T  -  If no match is made, return a temporary failure instead of not found.

(The flag to look up all MX records may go away.  I like Mitchell Blank's
MX code and set up better and may be using that instead to handle the
lookups of MX records separately.)

I've used this to implement a revamped check_rcpt that handles the IP 
address checking that I was looking for in there.  It also offers a lot
of new possibilities in blocking.  For instance, if you want to block
any mail that goes to or from, say, Cyberpromotions, or AGIS, but do not want 
to have to fiddle with your routers, you could create a list of their network
blocks (as opposed to a list of individual class C's) and put in filters
to catch mail to or from those networks, regardless of the domain name of
the day.  

If I put in a null route in my routers to the banned networks, my sendmail 
server will still retry to send the email, I think.  By adding this, 
sendmail can return a "571 Recepient in banned network" error or such.  
(Note that this could be used to catch any domain that had any MX records
in the banned networks.  Instead of tracking the domain of the day and
the MX record in the network of the day, I can check to see if the email
in anyway deposits itself on the banned network.)

Here is the current I'm kicking around for testing.

#check_ip called from check_rcpt
#R$*<@$+>$*	$:$(BannedIP $1 $: BANNED $) $| $2
#R$*<@$*BANNED> $| $*	$#error $@ 5.7.1 $: 571 The recipient is banned from this server.
# Match against first <@ > and see if it is local.
R$*<@$+>$*	1<@$(LocalIP $2 $: LOCALOK $)> $| $3
# If local, the first address is okay - remove it and continue processing.
R$*<@$*LOCALOK> $| $*	1 $3
# Otherwise, the first thing isn't local - no relaying!
R$*<@$+> $| $*	error $@ 5.7.1 $: 471 You are not allowed to send to that addr
ess from here
# If the first <@ > block was okay, check to see if there is another
# <@ > - the $+ at the end sees if we should be invoked recursively against
# the possibility of there being a secon <@ > block in the line.
R$*<@$+>$+	check_ip $1 <@ $2 > $3
#R$*<@$+>	$:$(BannedIP $1 $: BANNED $) 
#R$*<@$*BANNED>	$#error $@ 5.7.1 $: 571 The recipient is banned from this server.
# There is only <@ > block, and it's the last thing in the line.  Check to
# see if it is local.
R$*<@$+>	$:$1<@$(LocalIP $2 $: LOCALOK $)>
# At this point, there should be only one <@ > left.  If there was a
# previous <@ > block with a local address, the second rule would have
# removed it - if it was not local, it would have raised the error in
# the third rule.
# Is the last <@ > local?
R$*<@$*LOCALOK>	$@ Ok
# No, no relaying!
R$*<@$+>	$#error $@ 5.7.1 $: 471 You are not allowed to send to that address from here

# first: get client address
R$+	$: $(dequote "" $&{client_addr} $) $| $1
R0 $| $*	$@ ok       client_addr is 0 for sendmail -bs
#r$={localip}$* $| $*   $@ ok       from here
#R$* $| $*	$:$(BannedIP $1 $: BANNED $) $| $2
#RBANNED $| $*	$#error $@ 5.7.1 $: 571 You are banned from using this email
R$* $| $*	$:$(LocalIP $1 $: LOCALOK $) $| $2
RLOCALOK $| $*	$@ ok       client_addr is LOCALOK if in LocalIP map
# 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
# If something left, check to see if the remaining address(es) are
# in the local address space, maybe repeatedly.
R$*	$:$>check_ip $1

Any comments on concept so far?  I know my coding is probably
horrid.  :)


[(links)] [Hints] [Avoiding Spam] [New]
Claus Aßmann Please send comments to: <>