# # LOCAL SPAMASSASSIN RECEIVED HEADER TESTS # v1.2, Aug 10, 2007 # Eric A. Hall # # these rules look at the message and transfer data and make judgement # calls based on non-compliance problems # # # WARNING: THESE RULES WILL MISFIRE AGAINST LOCAL CLIENT CONNECTIONS # VERY EAGERLY, SINCE MANY SMTP CLIENTS BREAK MANY OF THE WELL-KNOWN # SMTP PROTOCOL RULES. AS SUCH, THESE RULES SHOULD NOT BE APPLIED TO # MAIL WHICH HAS BEEN GENERATED BY AUTHORIZED LOCAL CLIENTS, AND # SHOULD ONLY BE USED WITH PUBLIC-FACING MTAs THAT ONLY ACCEPT MAIL # FROM EXTERNAL SOURCES. # # # NOTE TO CORPUS TESTERS: These rules will only be accurately tested # if the Received headers in the corpora store all of the relevant # information (specifically including the reverse-DNS information for # the connecting client). If the reverse-DNS data is not stored, the # mass-check utility will (by default) show the 'rdns' field of the # X-Spam-Relays-Untrusted psuedo-header as empty, producing many # false-positives. This can be partly overcome by providing the # "--net" switch to mass-check, which will cause it to resolve # reverse-lookup data. However, given that networks change somewhat # frequently, this can also produce numerous false-positives due to # domain names having been changed, or netblocks having been moved, # and so forth. In order to further limit the number of errors, you # should also limit mass-check to recent messages, using the # "--since" command-line switch (eg, "--since='6 months'"). # # # Meta rules that look for excessive compliance errors. Some of the # explicit rules are defined further ahead in this ruleset, while # others are defined in SpamAssassin. # describe L_SOME_STD_PROBS At least two standards-compliance problems meta L_SOME_STD_PROBS (( __L_RCVD_HELO_NO_FQDN + __L_RCVD_HELO_LITERAL + __L_RCVD_HELO_NUMERIC + __L_RCVD_ADDR_WRONG + __L_RCVD_HOST_WRONG + __L_RCVD_HOST_NO_FQDN + __L_RCVD_HOST_NO_RDNS + __L_MSG_NO_FROM + __L_MSG_NO_DATE + __L_MSG_NO_MSGID + __L_CID_NO_FQDN ) == 2) score L_SOME_STD_PROBS 2.0 describe L_MANY_STD_PROBS Three or more standards-compliance problems meta L_MANY_STD_PROBS (( __L_RCVD_HELO_NO_FQDN + __L_RCVD_HELO_LITERAL + __L_RCVD_HELO_NUMERIC + __L_RCVD_ADDR_WRONG + __L_RCVD_HOST_WRONG + __L_RCVD_HOST_NO_FQDN + __L_RCVD_HOST_NO_RDNS + __L_MSG_NO_FROM + __L_MSG_NO_DATE + __L_MSG_NO_MSGID + __L_CID_NO_FQDN ) > 2) && (( __L_RCVD_HELO_NO_FQDN + __L_RCVD_HELO_LITERAL + __L_RCVD_HELO_NUMERIC + __L_RCVD_ADDR_WRONG + __L_RCVD_HOST_WRONG + __L_RCVD_HOST_NO_FQDN + __L_RCVD_HOST_NO_RDNS + __L_MSG_NO_FROM + __L_MSG_NO_DATE + __L_MSG_NO_MSGID + __L_CID_NO_FQDN ) < 5) score L_MANY_STD_PROBS 3.0 describe L_EXCESS_STD_PROBS Five or more standards-compliance problems meta L_EXCESS_STD_PROBS (( __L_RCVD_HELO_NO_FQDN + __L_RCVD_HELO_LITERAL + __L_RCVD_HELO_NUMERIC + __L_RCVD_ADDR_WRONG + __L_RCVD_HOST_WRONG + __L_RCVD_HOST_NO_FQDN + __L_RCVD_HOST_NO_RDNS + __L_MSG_NO_FROM + __L_MSG_NO_DATE + __L_MSG_NO_MSGID + __L_CID_NO_FQDN ) > 4) score L_EXCESS_STD_PROBS 5.0 # # This rule looks for an unqualified hostname in the first 'helo' field # of the X-Spam-Relays-Untrusted psuedo-header, and adds a score if a # match is found. Note that this rule technically looks for a lack of # dots in the HELO identifer, so it doesn't fire if an IP address is # used instead of a domain name. # describe __L_RCVD_HELO_NO_FQDN Unqualified hostname in the HELO greeting header __L_RCVD_HELO_NO_FQDN X-Spam-Relays-Untrusted =~ /^[^\]]+ helo=((.(?!\.))*)\s/ # # This rule checks for the presence of a domain-literal in the top-most # 'helo' field of the first X-Spam-Relays-Untrusted psuedo-header. # Although these are valid in SMTP, they are generally only used with # very low-end systems or messaging clients, and are therefore suspect # when found in a public-facing MTA. # # NOTE TO SELF: Should also add a rule checking for IPv6 literals # describe __L_RCVD_HELO_LITERAL HELO used a domain literal header __L_RCVD_HELO_LITERAL X-Spam-Relays-Untrusted =~ /^[^\]]+ helo=\!([\d\.])+\!\s/ # # This rule looks for an all-numeric hostname that is not enclosed in # square brackets. RFC1123 prohibits all-numeric hostnames, so these # hostnames are outright illegal. Note that SpamAssassin 3.0.2 also # catches some of these instances, but not all of them. If this # changes in the future, this rule will be removed. # describe __L_RCVD_HELO_NUMERIC HELO used non-literal all-numerics header __L_RCVD_HELO_NUMERIC X-Spam-Relays-Untrusted =~ /^[^\]]+ helo=([\d\.])+\s/ # # This rule looks for a match between the IP address of the sending # system and an IP address in the HELO identifier (literal or not). # Note that SA 3.0.2 already catches some of these instances, but not # all of them. If this changes, this rule will be removed. # describe __L_RCVD_ADDR_WRONG HELO and connection address mis-match header __L_RCVD_ADDR_WRONG X-Spam-Relays-Untrusted =~ /^[^\]]+ ip=(\S*) \S* helo=(?=\!?[\d\.]+)(?!\!?\1)/ # # This rule looks at the reverse DNS hostname and HELO identifiers, and # checks to see if the same hostname was used. If they are different, # score appropriately. Note that this happens *A LOT* with legitimate # email from poorly-configured networks so be very cautious with this # rule. Note that this rule will not fire if the 'rdns' field is empty, # or if the 'helo' field appears to contain an IP address or a domain # literal, or is also empty. # # NOTE: See below for tests that score extra for mismatched AOL, etc. # describe __L_RCVD_HOST_WRONG HELO name and reverse DNS mis-match header __L_RCVD_HOST_WRONG X-Spam-Relays-Untrusted =~ /^[^\]]+ rdns=(\S+) helo=(?!\d)(?!\!)(?!\1)(?!\s)/i # # This rule looks for an unqualified hostname in the first 'rdns' field # of the X-Spam-Relays-Untrusted psuedo-header, and adds a score if a # match is found. This matches those cases where the reverse domain # is just an unqualified hostname (eg, "my-pc"). Note that this will # match against "localhost" and other local unqualified domain names # if you are not cautious with deployment. # describe __L_RCVD_HOST_NO_FQDN Unqualified hostname in the reverse DNS header __L_RCVD_HOST_NO_FQDN X-Spam-Relays-Untrusted =~ /^[^\]]+ rdns=((.(?!\.))+)\s/ # # This rule looks at the top 'rdns' field of the X-Spam-Relays-Untrusted # psuedo-header, and if the field value is null, it assumes that the # server was unable to resolve the reverse-DNS lookup. Note that this # can happen due to resolver difficulties with the server, delegation # errors at the provider, or any number of other reasons, and should # only be enabled judiciously. Also note that this rule will not fire # if the HELO identifier is an IP address or domain-literal, or if the # 'helo' field is empty. # describe __L_RCVD_HOST_NO_RDNS No hostname whatsoever in the reverse DNS header __L_RCVD_HOST_NO_RDNS X-Spam-Relays-Untrusted =~ /^[^\]]+ rdns= helo=(?!\d)(?!\!)(?!\s)/i # # RFC 2821 says that the Date: and From: header fields are mandatory. # If they don't exist, the message is in violation of the Internet mail # standards. Note that these headers may have been aded by the last-hop # mail server, and these rules will not fire in that scenario. # header __L_MSG_HAS_FROM exists:From describe __L_MSG_HAS_FROM From: header field exists meta __L_MSG_NO_FROM !__L_MSG_HAS_FROM describe __L_MSG_NO_FROM From: header field does not exist header __L_MSG_HAS_DATE exists:Date describe __L_MSG_HAS_DATE Date: header field exists meta __L_MSG_NO_DATE !__L_MSG_HAS_DATE describe __L_MSG_NO_DATE Date: header field does not exist # # Although the RFCs do not strictly require a Message-ID header field # to be present, they strongly suggest that well-heeled senders should # add one. Thus, the absence of a Message-ID header field indicates # that the sender is not well-behaved. Note that this header may have # been added by the last-hop mail server, and these rules will not # fire in that scenario. # header __L_MSG_HAS_MSGID exists:Message-ID describe __L_MSG_HAS_MSGID Message-ID: header field exists meta __L_MSG_NO_MSGID !__L_MSG_HAS_MSGID describe __L_MSG_NO_MSGID Message-ID: header field does not exist # # Content-ID headers use the email address syntax for their value. # As such, any Content-ID headers that do not contain an "@" character # are treated as illegal. # mimeheader __L_CID_NO_FQDN Content-ID =~ /^\<((.(?!\@))*)\>$/ describe __L_CID_NO_FQDN Content-ID: header does not have domain part # # CHANGELOG # # v0.1 -- initial release # # v0.2 -- fixed typos and other clean-up # # v0.3 -- fixed parsing bug in the L_RCVD_FAKE_* rules # # v0.4 -- fixed parsing bug in L_RCVD_HELO_WRONG (same as L_RCVD_FAKE_*); # changed the L_RCVD_HELO_WRONG rule to be case-insensitive; # changed the L_RCVD_FAKE_* rules to be case-insensitive; # removed some left-over comment cruft from previous edits # # v0.5 -- added WARNING text discouraging use with local client session; # clarified some other comments; # renamed L_RCVD_NO_FQDN_HELO to L_RCVD_HELO_NO_FQDN for clarity; # added a check to L_RCVD_HOST_NO_RDNS to see if HELO was address # # v0.6 -- added L_RCVD_HOST_NO_FQDN to find RDNS with unqualified names; # added L_RCVD_LITERAL_WRONG to find mis-matched domain literals; # tweaked L_RCVD_HOST_WRONG to not match IP addresses in HELO; # fixed a bug with L_RCVD_HOST_NO_RDNS and domain literals # # v0.7 -- tweaked the L_RCVD_FAKE_* rules not to fire on empty RDNS # # v0.8 -- converted most of the rules to scoreless sub-tests; # created L_SMTP_SOME_PROBS that hit exactly two sub-rules; # created L_SMTP_MANY_PROBS that hit three or more sub-rules; # created __L_RCVD_HELO_NUMERIC to match non-literal addresses; # extended __L_RCVD_ADDR_WRONG to match non-literals; # re-wrote L_RCVD_FAKE_* to match empty RDNS again; # added NOTE text to describe limitations of corpus testing; # clarified or re-wrote many of the comment blocks # # v0.9 -- moved the L_RCVD_FAKE_ rules to their own cf file; # added __L_RCVD_NO_MSG_FROM to look for missing From; # added __L_RCVD_NO_MSG_DATE to look for missing Date; # added __L_RCVD_NO_MSG_MID to look for missing Message-ID; # # v1.0 -- renamed L_SMTP_* rules to *L_STD_* to reflect breadth # of tests being performed # renamed RCVD_MSG_FROM tests # renamed RCVD_MSG_DATE tests # renamed RCVD_MSG_MID tests # created new L_EXCESS_STD_PROBS for 5 or more hits # # v1.1 -- __L_RCVD_TOO_FEW|MANY_HOPS made separate rules; # added __L_CID_NO_FQDN for unqualified Content-ID headers # # v1.2 -- __L_MSG_NO_DATE test fixed #