LOGFILE="${HOME}/PROCMAIL.LOG" VERBOSE="on" LOGABSTRACT="all" # ############################################################################### # # RFC 821, (paragraph 4.1.2) compliant, (with sendmail(1) RDNS # compatible extensions,) forged local domain detection. # # From RFC 821, a "Received:", (i.e., a header,) # record is of the format: # # "Received:" "FROM" "BY" \ # # # Unfortunately, the "FROM " section can be forged in the SMTP # EHLO dialog. If a sendmail(1) compatible RDNS is used on an MX # Internet gateway, the RDNS section, "(RDNS [ip address])", will be # inserted immediately after the "FROM ", and will contain the # FQDN of the IP address of sending machine, (other MTAs may have # different RDNS semantics.) # # If the RDNS FQDN is not in the local domain, then the message came # from another domain, and if the message is declared to be from the # local domain, (i.e., in the "From ", "From: ", etc., records,) it is # a forgery. # # Unfortunately, finding "Received: " records that are not from the # local domain can be problematical with regular expressions. A # solution is to parse each with regular # expressions, looking backwards for the local domain name, character # by character, in the sendmail(1) RDNS extension. If any character # position does not contain the correct character from the local # domain, then the message is not from the local domain-and if it # declares that it is, then it is a forgery. # # Using dummy.com as an example of the local domain: # # Folded whitespace, (the characters between the block braces are a # tab character, hex 09, followed by a space character, hex 20,) since # "Received: " records typically span multiples lines: # ws='[ ]*($[ ]+)*' # :0: * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*\.[-0-9a-z_+=][-0-9a-z_+=][^m]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*\.[-0-9a-z_+=][^o][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*\.[^c][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^y]\.[-0-9a-z_+=][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^m][-0-9a-z._+=]\.[-0-9a-z_+=][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^m][-0-9a-z._+=][-0-9a-z._+=]\.[-0-9a-z_+=][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^u][-0-9a-z._+=][-0-9a-z._+=][-0-9a-z._+=]\.[-0-9a-z_+=][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^d][-0-9a-z._+=][-0-9a-z._+=][-0-9a-z._+=][-0-9a-z._+=]\.[-0-9a-z_+=][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^.][-0-9a-z._+=][-0-9a-z._+=][-0-9a-z._+=][-0-9a-z._+=][-0-9a-z._+=]\.[-0-9a-z_+=][-0-9a-z_+=][-0-9a-z_+=]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(unknown${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com xxx # :0: yyy # # Where the first conditional checks the last character of the RDNS' # FQDN, against the last character of the local domain, the second # conditional checks the next to the last character, and so on. # # Many local machines in the domain do not have a FQDN in the RDNS; # only the machine name. If the RDNS has only a local name, it will be # regarded as local to the domain; with the exception of an RDNS # failure, where the FQDN is "unknown", (thus the last conditional.) # # The next to the last conditional asserts that the local domain in # the FQDN of the RDNS must be preceded by nothing, or a period, '.' # to preclude the suffix of an external domain being interpreted as # the local domain, (i.e., wxyzdummy.com would be confused with # dummy.com, the local domain.) # # Note that the construct can be further reduced: # # :0: # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*\.[-0-9a-z_+=][-0-9a-z_+=][^m]${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*\.[-0-9a-z_+=][^o]m${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*\.[^c]om${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^y]\.com${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^m]l\.com${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^m]ul\.com${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^u]hul\.com${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^d]ahul\.com${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(([-0-9a-z_+=]+\.)*[-0-9a-z_+=]*[^.]dummy\.com${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # * 1^0 $ ^received:${ws}from${ws}\/[-0-9a-z._+=]+${ws}\(unknown${ws}\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]\)${ws}by${ws}([-0-9a-z_+=]+\.)*dummy\.com # xxx # # # :0: # yyy # # Note that the '\/' character sequence, (which will print "match" # information in the log file, "PROCMAIL.LOG",) should be removed from # any production version. # ###################################################################### # # A license is hereby granted to reproduce this software for personal, # non-commercial use. # # THIS PROGRAM IS PROVIDED "AS IS". THE AUTHOR PROVIDES NO WARRANTIES # WHATSOEVER, EXPRESSED OR IMPLIED, INCLUDING WARRANTIES OF # MERCHANTABILITY, TITLE, OR FITNESS FOR ANY PARTICULAR PURPOSE. THE # AUTHOR DOES NOT WARRANT THAT USE OF THIS PROGRAM DOES NOT INFRINGE THE # INTELLECTUAL PROPERTY RIGHTS OF ANY THIRD PARTY IN ANY COUNTRY. # # So there. # # Copyright (c) 1992-2005, John Conover, , All # Rights Reserved. # # $Revision: 1.0 $ # $Date: 2005/03/11 08:33:13 $ # $Id: howto-forgery.txt,v 1.0 2005/03/11 08:33:13 conover Exp $ # $Log: howto-forgery.txt,v $ # Revision 1.0 2005/03/11 08:33:13 conover # Initial revision #