1# <@LICENSE> 2# Licensed to the Apache Software Foundation (ASF) under one or more 3# contributor license agreements. See the NOTICE file distributed with 4# this work for additional information regarding copyright ownership. 5# The ASF licenses this file to you under the Apache License, Version 2.0 6# (the "License"); you may not use this file except in compliance with 7# the License. You may obtain a copy of the License at: 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# </@LICENSE> 17 18# --------------------------------------------------------------------------- 19 20# So, what's the difference between a trusted and untrusted Received header? 21# Basically, relays we *know* are trustworthy are 'trusted', all others after 22# the last one of those are 'untrusted'. 23# 24# We determine trust by detecting if they are inside the network ranges 25# specified in 'trusted_networks'. There is also an inference algorithm 26# which determines other trusted relays without user configuration. 27# 28# There's another type of Received header: the semi-trusted one. This is the 29# header added by *our* MX, at the boundary of trust; we can trust the IP 30# address (and possibly rDNS) in this header, but that's about it; HELO name is 31# untrustworthy. We just use this internally for now. 32# 33# Finally, there's also 'internal_networks'. These are the networks that you 34# control; your MXes should be included. This way, if you specify a wide range 35# of trusted hosts, a mail that is relayed from a dynamic IP address via a 36# 'trusted' host will not hit RCVD_IN_DYNABLOCK. 37 38# --------------------------------------------------------------------------- 39 40use strict; # make Test::Perl::Critic happy 41package Mail::SpamAssassin::Message::Metadata::Received; 1; 42 43package Mail::SpamAssassin::Message::Metadata; 44use strict; 45use warnings; 46# use bytes; 47use re 'taint'; 48 49use Mail::SpamAssassin::Dns; 50use Mail::SpamAssassin::PerMsgStatus; 51use Mail::SpamAssassin::Constants qw(:ip); 52 53# --------------------------------------------------------------------------- 54 55sub parse_received_headers { 56 my ($self, $pms, $msg) = @_; 57 58 # a caller may assert that a message is coming from inside or from an 59 # authenticated roaming users; this info may not be available in mail 60 # header section, e.g. in case of nonstandard authentication mechanisms 61 my $originating; # boolean 62 if (exists $msg->{suppl_attrib}->{originating}) { 63 $originating = $msg->{suppl_attrib}->{originating} || 0; 64 dbg("metadata: set originating from suppl_attrib: %s", $originating); 65 } 66 67 $self->{relays_trusted} = [ ]; 68 $self->{num_relays_trusted} = 0; 69 $self->{relays_trusted_str} = ''; 70 71 $self->{relays_untrusted} = [ ]; 72 $self->{num_relays_untrusted} = 0; 73 $self->{relays_untrusted_str} = ''; 74 75 $self->{relays_internal} = [ ]; 76 $self->{num_relays_internal} = 0; 77 $self->{relays_internal_str} = ''; 78 79 $self->{relays_external} = [ ]; 80 $self->{num_relays_external} = 0; 81 $self->{relays_external_str} = ''; 82 83 $self->{num_relays_unparseable} = 0; 84 85 $self->{last_trusted_relay_index} = -1; # last counting from the top, 86 $self->{last_internal_relay_index} = -1; # first in time 87 88 $self->{allow_mailfetch_markers} = 1; # This needs to be set for the 89 # first Received: header 90 # now figure out what relays are trusted... 91 my $trusted = $pms->{main}->{conf}->{trusted_networks}; 92 my $internal = $pms->{main}->{conf}->{internal_networks}; 93 my $msa = $pms->{main}->{conf}->{msa_networks}; 94 my $did_user_specify_trust = $pms->{main}->{conf}->{trusted_networks_configured}; 95 my $did_user_specify_internal = $pms->{main}->{conf}->{internal_networks_configured}; 96 my $in_trusted = 1; 97 my $in_internal = 1; 98 my $found_msa = 0; 99 100 unless ($did_user_specify_trust && $did_user_specify_internal) { 101 if (!$did_user_specify_trust && !$did_user_specify_internal) { 102 dbg('config: trusted_networks are not configured; it is recommended '. 103 'that you configure trusted_networks manually'); 104 } elsif (!$did_user_specify_internal) { 105 # use 'trusted' for 'internal'; compatibility with SpamAssassin 2.60 106 $internal = $trusted; 107 dbg('config: internal_networks not configured, using trusted_networks '. 108 'configuration for internal_networks; if you really want '. 109 'internal_networks to only contain the required 127/8 add '. 110 "'internal_networks !0/0' to your configuration"); 111 } else { 112 # use 'internal' for 'trusted'; I don't know why we let people define 113 # internal without trusted, but we do... and we rely on trusted being set 114 $trusted = $internal; 115 dbg('config: trusted_networks not configured, using internal_networks '. 116 'configuration for trusted_networks'); 117 } 118 } 119 120 my $IP_ADDRESS = IP_ADDRESS; 121 my $IP_PRIVATE = IP_PRIVATE; 122 my $LOCALHOST = LOCALHOST; 123 124 my @hdrs = $msg->get_header('Received'); 125 126 # Now add the single line headers like X-Originating-IP. (bug 5680) 127 # we convert them into synthetic "Received" headers so we can share 128 # code below. 129 foreach my $header (@{$pms->{main}->{conf}->{originating_ip_headers}}) { 130 my $str = $msg->get_header($header); 131 next unless ($str && $str =~ m/($IP_ADDRESS)/); 132 push @hdrs, "from X-Originating-IP: $1\n"; 133 } 134 135 foreach my $line ( @hdrs ) { 136 137 # qmail-scanner support hack: we may have had one of these set from the 138 # previous (read: more recent) Received header. if so, add it on to this 139 # header's set, since that's the handover it was describing. 140 141 my $qms_env_from; 142 if ($self->{qmail_scanner_env_from}) { 143 $qms_env_from = $self->{qmail_scanner_env_from}; 144 delete $self->{qmail_scanner_env_from}; 145 } 146 147 $line =~ s/\n[ \t]+/ /gs; 148 149 my $relay = $self->parse_received_line ($line); 150 if (!defined $relay) { 151 dbg("received-header: unparseable: $line"); 152 $self->{num_relays_unparseable}++; 153 } 154 155 # undefined or 0 means there's no result, so goto the next header 156 unless ($relay) { 157 $self->{last_trusted_relay_index}++ if $in_trusted; 158 $self->{last_internal_relay_index}++ if $in_internal; 159 next; 160 } 161 162 # hack for qmail-scanner, as described above; add in the saved 163 # metadata 164 if ($qms_env_from) { 165 $relay->{envfrom} = $qms_env_from; 166 $self->make_relay_as_string($relay); 167 } 168 169 # relay status only changes when we're still in the trusted portion of the 170 # relays and we haven't yet found an MSA 171 if ($in_trusted && !$found_msa) { 172 unless ($did_user_specify_trust || $did_user_specify_internal) { 173 # OK, infer the trusted/untrusted handover, we don't have real info 174 my $inferred_as_trusted = 0; 175 176 # if the 'from' IP addr is in a reserved net range, it's not on 177 # the public internet. 178 if ($relay->{ip_private}) { 179 dbg("received-header: 'from' ".$relay->{ip}." has private IP"); 180 $inferred_as_trusted = 1; 181 } 182 183 # if we find authentication tokens in the received header we can extend 184 # the trust boundary to that host 185 if ($relay->{auth}) { 186 dbg("received-header: authentication method ".$relay->{auth}); 187 $inferred_as_trusted = 1; 188 } 189 190 # if the user didn't specify any trusted/internal config, everything 191 # we assume as trusted is also internal, just like we'd do if they 192 # specified trusted but not any internal networks or vice versa 193 if (!$inferred_as_trusted) { 194 dbg("received-header: do not trust any hosts from here on"); 195 $in_trusted = 0; 196 $in_internal = 0; 197 } 198 199 } else { 200 # trusted_networks matches? 201 if (!$relay->{auth} && !$trusted->contains_ip($relay->{ip})) { 202 if (!$originating) { 203 $in_trusted = 0; # break the trust chain 204 } else { # caller asserts a msg was submitted from inside or auth'd 205 $found_msa = 1; # let's assume the previous hop was actually 206 # an MSA, and propagate trust from here on 207 dbg('received-header: originating, '. 208 '%s and remaining relays will be considered trusted%s', 209 $relay->{ip}, !$in_internal ? '' : ', but no longer internal'); 210 } 211 $in_internal = 0; # if it's not trusted it's not internal 212 } else { 213 # internal_networks matches? 214 if ($in_internal && !$relay->{auth} && !$internal->contains_ip($relay->{ip})) { 215 $in_internal = 0; 216 } 217 # msa_networks matches? 218 if ($msa->contains_ip($relay->{ip})) { 219 dbg('received-header: found MSA relay, remaining relays will be'. 220 ' considered trusted: '.($in_trusted ? 'yes' : 'no'). 221 ' internal: '.($in_internal ? 'yes' : 'no')); 222 $found_msa = 1; 223 $relay->{msa} = 1; 224 } 225 } 226 } 227 } 228 229 dbg("received-header: relay ".$relay->{ip}. 230 " trusted? ".($in_trusted ? "yes" : "no"). 231 " internal? ".($in_internal ? "yes" : "no"). 232 " msa? ".($relay->{msa} ? "yes" : "no")); 233 234 $relay->{internal} = $in_internal; 235 $relay->{msa} ||= 0; 236 237 # be sure to mark up the as_string version for users too 238 $relay->{as_string} =~ s/ intl=\d / intl=$relay->{internal} /; 239 $relay->{as_string} =~ s/ msa=\d / msa=$relay->{msa} /; 240 241 if ($in_trusted) { 242 push (@{$self->{relays_trusted}}, $relay); 243 $self->{allow_mailfetch_markers} = 1; 244 $self->{last_trusted_relay_index}++; 245 } else { 246 push (@{$self->{relays_untrusted}}, $relay); 247 $self->{allow_mailfetch_markers} = 0; 248 } 249 250 if ($in_internal) { 251 push (@{$self->{relays_internal}}, $relay); 252 $self->{last_internal_relay_index}++; 253 } else { 254 push (@{$self->{relays_external}}, $relay); 255 } 256 } 257 258 $self->{relays_trusted_str} = join(' ', map { $_->{as_string} } 259 @{$self->{relays_trusted}}); 260 $self->{relays_untrusted_str} = join(' ', map { $_->{as_string} } 261 @{$self->{relays_untrusted}}); 262 $self->{relays_internal_str} = join(' ', map { $_->{as_string} } 263 @{$self->{relays_internal}}); 264 $self->{relays_external_str} = join(' ', map { $_->{as_string} } 265 @{$self->{relays_external}}); 266 267 # OK, we've now split the relay list into trusted and untrusted. 268 269 # add the stringified representation to the message object, so Bayes 270 # and rules can use it. Note that rule_tests.t does not impl put_metadata, 271 # so protect against that here. These will not appear in the final 272 # message; they're just used internally. 273 274 if ($self->{msg}->can ("delete_header")) { 275 $self->{msg}->delete_header ("X-Spam-Relays-Trusted"); 276 $self->{msg}->delete_header ("X-Spam-Relays-Untrusted"); 277 $self->{msg}->delete_header ("X-Spam-Relays-Internal"); 278 $self->{msg}->delete_header ("X-Spam-Relays-External"); 279 280 if ($self->{msg}->can ("put_metadata")) { 281 $self->{msg}->put_metadata ("X-Spam-Relays-Trusted", 282 $self->{relays_trusted_str}); 283 $self->{msg}->put_metadata ("X-Spam-Relays-Untrusted", 284 $self->{relays_untrusted_str}); 285 $self->{msg}->put_metadata ("X-Spam-Relays-Internal", 286 $self->{relays_internal_str}); 287 $self->{msg}->put_metadata ("X-Spam-Relays-External", 288 $self->{relays_external_str}); 289 } 290 } 291 292 # be helpful; save some cumbersome typing 293 $self->{num_relays_trusted} = scalar (@{$self->{relays_trusted}}); 294 $self->{num_relays_untrusted} = scalar (@{$self->{relays_untrusted}}); 295 $self->{num_relays_internal} = scalar (@{$self->{relays_internal}}); 296 $self->{num_relays_external} = scalar (@{$self->{relays_external}}); 297 298 dbg("metadata: X-Spam-Relays-Trusted: ".$self->{relays_trusted_str}); 299 dbg("metadata: X-Spam-Relays-Untrusted: ".$self->{relays_untrusted_str}); 300 dbg("metadata: X-Spam-Relays-Internal: ".$self->{relays_internal_str}); 301 dbg("metadata: X-Spam-Relays-External: ".$self->{relays_external_str}); 302} 303 304# --------------------------------------------------------------------------- 305 306# returns undef if the header just couldn't be parsed 307# returns 0 if the header was specifically skipped 308# returns a hash of information if the header is parsed, including: 309# ip => $ip, 310# by => $by, 311# helo => $helo, 312# id => $id, 313# ident => $ident, 314# envfrom => $envfrom, 315# lc_by => (lc $by), 316# lc_helo => (lc $helo), 317# auth => $auth 318# 319sub parse_received_line { 320 my ($self) = shift; 321 local ($_) = shift; 322 local ($1,$2,$3,$4,$5,$6); 323 324 s/\s+/ /g; 325 s/^ //; 326 s/ $//; 327 328 # get rid of invalid semicolon at the end of the header 329 1 while s/\s?;$//; 330 331 my $ip = ''; 332 my $helo = ''; 333 my $rdns = ''; 334 my $by = ''; 335 my $id = ''; 336 my $ident = ''; 337 my $envfrom = undef; 338 my $mta_looked_up_dns = 0; 339 my $IP_ADDRESS = IP_ADDRESS; 340 my $IP_PRIVATE = IP_PRIVATE; 341 my $LOCALHOST = LOCALHOST; 342 my $auth = ''; 343 344# --------------------------------------------------------------------------- 345 346 # We care about lines starting with from. all of the others are ignorable: 347 # Bug 4943: give /^(from/ a chance to be parsed 348 # 349 # (qmail 27981 invoked by uid 225); 14 Mar 2003 07:24:34 -0000 350 # (qmail 84907 invoked from network); 13 Feb 2003 20:59:28 -0000 351 # (ofmipd 208.31.42.38); 17 Mar 2003 04:09:01 -0000 352 # by faerber.muc.de (OpenXP/32 v3.9.4 (Win32) alpha @ 2003-03-07-1751d); 07 Mar 2003 22:10:29 +0000 353 # by x.x.org (bulk_mailer v1.13); Wed, 26 Mar 2003 20:44:41 -0600 354 # by SPIDERMAN with Internet Mail Service (5.5.2653.19) id <19AF8VY2>; Tue, 25 Mar 2003 11:58:27 -0500 355 # by oak.ein.cz (Postfix, from userid 1002) id DABBD1BED3; Thu, 13 Feb 2003 14:02:21 +0100 (CET) 356 # OTM-MIX(otm-mix00) id k5N1aDtp040896; Fri, 23 Jun 2006 10:36:14 +0900 (JST) 357 # at Infodrom Oldenburg (/\##/\ Smail-3.2.0.102 1998-Aug-2 #2) from infodrom.org by finlandia.Infodrom.North.DE via smail from stdin id <m1FglM8-000okjC@finlandia.Infodrom.North.DE> for debian-security-announce@lists.debian.org; Thu, 18 May 2006 18:28:08 +0200 (CEST) 358 # with ECARTIS (v1.0.0; list bind-announce); Fri, 18 Aug 2006 07:19:58 +0000 (UTC) 359 # Received: Message by Barricade wilhelm.eyp.ee with ESMTP id h1I7hGU06122 for <spamassassin-talk@lists.sourceforge.net>; Tue, 18 Feb 2003 09:43:16 +0200 360 return 0 if (!/^\(?from /i); 361 362 # from www-data by wwwmail.documenta.de (Exim 4.50) with local for <example@vandinter.org> id 1GFbZc-0006QV-L8; Tue, 22 Aug 2006 21:06:04 +0200 363 # from server.yourhostingaccount.com with local for example@vandinter.org id 1GDtdl-0002GU-QE (8710); Thu, 17 Aug 2006 21:59:17 -0400 364 return 0 if /\bwith local for\b/; 365 366 # Received: from virtual-access.org by bolero.conactive.com ; Thu, 20 Feb 2003 23:32:58 +0100 367 # Received: FROM ca-ex-bridge1.nai.com BY scwsout1.nai.com ; Fri Feb 07 10:18:12 2003 -0800 368 # but not: Received: from [86.122.158.69] by mta2.iomartmail.com; Thu, 2 Aug 2007 21:50:04 -0200 369 if (/^from (\S+) by [^\s;]+ ?;/i && $1 !~ /^\[[\d.]+\]$/) { return 0; } 370 371# --------------------------------------------------------------------------- 372 373 # Let's get rid of the date at the end 374 # ; Tue, 23 May 2006 13:06:35 -0400 375 s/[\s;]+(?:(?:Mon|T(?:ue|hu)|Wed|Fri|S(?:at|un)), )?\d+ (?:J(?:an|u[nl])|Feb|Ma[ry]|A(?:pr|ug)|Sep|Oct|Nov|Dec) \d+ \d+:\d+(?::\d+)? \S+$//; 376 377 # from av0001.technodiva.com (localhost [127.0.0.1])by localhost.technodiva.com (Postfix) with ESMTP id 846CF2117for <proftp-user@lists.sourceforge.net>; Mon, 7 Aug 2006 17:48:07 +0200 (MEST) 378 s/\)by /) by /; 379 380# --------------------------------------------------------------------------- 381 382 # OK -- given knowledge of most Received header formats, 383 # break them down. We have to do something like this, because 384 # some MTAs will swap position of rdns and helo -- so we can't 385 # simply use simplistic regexps. 386 387 # try to catch unique message identifier 388 if (/ id <?([^\s<>;]{3,})/) { 389 $id = $1; 390 } 391 392 if (/\bhelo=([-A-Za-z0-9\.\^+_&:=?!@%*\$\\\/]+)(?:[^-A-Za-z0-9\.\^+_&:=?!@%*\$\\\/]|$)/) { 393 $helo = $1; 394 } 395 elsif (/\b(?:HELO|EHLO) ([-A-Za-z0-9\.\^+_&:=?!@%*\$\\\/]+)(?:[^-A-Za-z0-9\.\^+_&:=?!@%*\$\\\/]|$)/) { 396 $helo = $1; 397 } 398 if (/ by (\S+)(?:[^-A-Za-z0-9\;\.]|$)/) { $by = $1; } 399 400# --------------------------------------------------------------------------- 401 402 # try to catch authenticated message identifier 403 # 404 # with ESMTPA, ESMTPSA, LMTPA, LMTPSA should cover RFC 3848 compliant MTAs, 405 # UTF8SMTPA and UTF8LMTPA are covered by RFC 4954 and RFC 6531, 406 # with ASMTP (Authenticated SMTP) is used by Earthlink, Exim 4.34, and others 407 # with HTTP should only be authenticated webmail sessions 408 # with HTTPU is used by Communigate Pro with Pronto! webmail interface 409 # with HTTPS is used by Horde adjusts the Received header to say "HTTPS" when 410 # a connection is made over HTTPS 411 # IANA registry: https://www.iana.org/assignments/mail-parameters/mail-parameters.xhtml 412 if (/ by / && / with ((?:ES|L|UTF8S|UTF8L)MTPS?A|ASMTP|HTTP[SU]?)(?: |;|$)/i) { 413 $auth = $1; 414 } 415 # GMail should use ESMTPSA to indicate that it is in fact authenticated, 416 # but doesn't. 417 elsif (/ by mx\.google\.com with ESMTPS id [a-z0-9]{1,4}sm[0-9]{2,9}[a-z]{3}\.[0-9]{1,3}\.[0-9]{4}\.(?:[0-6][0-9]\.){4}[0-6][0-9]/ && /\(version=([^ ]+) cipher=([^\)]+)\)/ ) { 418 $auth = 'GMail - transport=' . $1 . ' cipher=' . $2; 419 } 420 # Courier v0.47 and possibly others 421 elsif (/^from .*?(?:\]\)|\)\]) \(AUTH: (LOGIN|PLAIN|DIGEST-MD5|CRAM-MD5) \S+(?:, .*?)?\) by /) { 422 $auth = $1; 423 } 424 # Sendmail, MDaemon, some webmail servers, and others 425 elsif (/authenticated/ && /^from .*?(?:\](?: \([^)]*\))?\)|\)\]) .*?\(.*?authenticated.*?\).*? by/) { 426 $auth = 'Sendmail'; 427 } 428 # workaround for GMX, which authenticates users but does not indicate it properly - # SMTP version 429 elsif (/from \S* \((?:HELO|EHLO) (\S*)\) \[(${IP_ADDRESS})\] by (mail\.gmx\.(?:net|com)) \([^\)]+\) with ((?:ESMTP|SMTP))/) { 430 $auth = "GMX ($4 / $3)"; 431 } 432 # Critical Path Messaging Server 433 elsif (/ \(authenticated as /&&/\) by .+ \(\d{1,2}\.\d\.\d{3}(?:\.\d{1,3})?\) \(authenticated as .+\) id /) { 434 $auth = 'CriticalPath'; 435 } 436 # Postfix 2.3 and later with "smtpd_sasl_authenticated_header yes" 437 # Normally $1 is "Postfix", but could be changed with mail_name (Bug 5646) 438 elsif (/\) \(Authenticated sender: \S+\) by \S+ \(([^\)]+)\) with /) { 439 $auth = $1 eq 'Postfix' ? $1 : "Postfix ($1)"; 440 } 441 # Communigate Pro - Bug 6495 adds HTTP as possible transmission method 442 # Bug 7277: XIMSS used by Pronto and other custom apps, IMAP supports XMIT extension 443 elsif (/CommuniGate Pro (HTTP|SMTP|XIMSS|IMAP)/ && / \(account /) { 444 $auth = 'Communigate'; 445 } 446 # Microsoft Exchange (complete with syntax error) 447 elsif (/ with Microsoft Exchange Server HTTP-DAV\b/) { 448 $auth = 'HTTP-DAV'; 449 } 450 # froufrou mailers like United Internet use a '(via HTTP)' comment, Bug 7101 451 elsif (/ by / && / \(via (HTTP.?)\)(?: |;|$)/i) { 452 $auth = $1; 453 } 454 455# --------------------------------------------------------------------------- 456 457 if (s/^from //) { 458 # try to catch enveloper senders 459 if (/(?:return-path:? |envelope-(?:sender|from)[ =])(\S+)\b/i) { 460 $envfrom = $1; 461 } 462 463 # from 142.169.110.122 (SquirrelMail authenticated user synapse) by 464 # mail.nomis80.org with HTTP; Sat, 3 Apr 2004 10:33:43 -0500 (EST) 465 # Expanded to NaSMail Bug 6783 466 if (/ \((?:SquirrelMail|NaSMail) authenticated user /) { 467 #REVERTING bug 3236 and implementing re: bug 6549 468 if (/(${IP_ADDRESS})\b(?![.-]).{10,80}by (\S+) with HTTP/) { 469 $ip = $1; $by = $2; goto enough; 470 } 471 } 472 473 # AOL WebMail headers 474 if (/aol\.com/ && /with HTTP \(WebMailUI\)/) { 475 # Received: from 82.135.198.129 by FWM-M18.sysops.aol.com (64.12.168.82) with HTTP (WebMailUI); Tue, 19 Jun 2007 11:16:54 -0400 476 if(/(${IP_ADDRESS}) by (\S+) \(${IP_ADDRESS}\) with HTTP \(WebMailUI\)/) { 477 $ip = $1; $by = $2; goto enough; 478 } 479 } 480 481 # catch MS-ish headers here 482 if (/ SMTPSVC/) { 483 # MS servers using this fmt do not lookup the rDNS. 484 # Received: from inet-vrs-05.redmond.corp.microsoft.com ([157.54.6.157]) 485 # by INET-IMC-05.redmond.corp.microsoft.com with Microsoft 486 # SMTPSVC(5.0.2195.6624); Thu, 6 Mar 2003 12:02:35 -0800 487 # Received: from 0 ([61.31.135.91]) by bass.bass.com.eg with Microsoft 488 # SMTPSVC(5.0.2195.6713); Tue, 21 Sep 2004 08:59:06 +0300 489 # Received: from 0 ([61.31.138.57] RDNS failed) by nccdi.com with 490 # Microsoft SMTPSVC(6.0.3790.0); Thu, 23 Sep 2004 08:51:06 -0700 491 # Received: from tthompson ([217.35.105.172] unverified) by 492 # mail.neosinteractive.com with Microsoft SMTPSVC(5.0.2195.5329); 493 # Tue, 11 Mar 2003 13:23:01 +0000 494 # Received: from ([172.16.1.78]) by email2.codeworksonline.com with Microsoft SMTPSVC(5.0.2195.6713); Wed, 6 Sep 2006 21:14:29 -0400 495 if (/^(\S*) \(\[(${IP_ADDRESS})\][^\)]{0,40}\) by (\S+) with Microsoft SMTPSVC/) { 496 $helo = $1; $ip = $2; $by = $3; goto enough; 497 } 498 499 # Received: from mail pickup service by mail1.insuranceiq.com with 500 # Microsoft SMTPSVC; Thu, 13 Feb 2003 19:05:39 -0500 501 if (/^mail pickup service by (\S+) with Microsoft SMTPSVC$/) { 502 return 0; 503 } 504 } 505 506 # Microsoft SMTP Server 507 elsif (/ with (?:Microsoft SMTP Server|mapi id) (?:\([^\)]+\) )?\d+\.\d+\.\d+\.\d+(?:$| )/) { 508 # Received: from EXC-DAG-02.global.net (10.45.252.152) by EXC-DAG-02.global.net 509 # (10.45.252.152) with Microsoft SMTP Server (version=TLS1_2, 510 # cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1261.35; 511 # Mon, 29 Oct 2018 11:17:19 +0100 512 # Received: from AM5PR0402MB2836.eurprd04.prod.outlook.com 513 # ([fe80::19bd:c588:dd17:5226]) by AM5PR0402MB2836.eurprd04.prod.outlook.com 514 # ([fe80::19bd:c588:dd17:5226%6]) with mapi id 15.20.1943.023; 515 # Wed, 5 Jun 2019 10:17:08 +0000 516 if (/^(\S+) \(\[?(${IP_ADDRESS})(?:%[A-Z0-9._~-]*)?\]?\) by (\S+) /) { 517 $helo = $1; $ip = $2; $by = $3; $id = ''; goto enough; 518 } 519 } 520 521 elsif (/\[XMail /) { # bug 3791, bug 4053 522 # Received: from list.brainbuzz.com (63.146.189.86:23198) by mx1.yourtech.net with [XMail 1.20 ESMTP Server] id <S72E> for <jason@ellingson.org.spamassassin.org> from <bounce-cscommunity-11965901@list.cramsession.com.spamassassin.org>; Sat, 18 Sep 2004 23:17:54 -0500 523 # Received: from list.brainbuzz.com (63.146.189.86:23198) by mx1.yourtech.net (209.32.147.34:25) with [XMail 1.20 ESMTP Server] id <S72E> for <jason@ellingson.org.spamassassin.org> from <bounce-cscommunity-11965901@list.cramsession.com.spamassassin.org>; Sat, 18 Sep 2004 23:17:54 -0500 524 if (/^(\S+) \((\[?${IP_ADDRESS}\]?)(?::\d+)\) by (\S+)(?: \(\S+\))? with \[XMail/) 525 { 526 $helo = $1; $ip = $2; $by = $3; 527 / id <(\S+)>/ and $id = $1; 528 / from <(\S+)>/ and $envfrom = $1; 529 goto enough; 530 } 531 } 532 533 # from ([10.225.209.19:33672]) by ecelerity-va-1 (ecelerity HEAD) with SMTP id EE/20-30863-33CE1054; Fri, 08 Sep 2006 18:18:27 -0400 534 # from ([127.0.0.1:32923]) by bm1-21.ed10.com (ecelerity 2.1.1ea r(11031M)) with ECSTREAM id 8B/57-16227-3764EB44 for <example@vandinter.org>; Wed, 19 Jul 2006 10:49:23 -0400 535 # from ([192.168.1.151:49601] helo=dev1.democracyinaction.org) by m12.prod.democracyinaction.com (ecelerity 2.1.1.3 r(11743)) with ESMTP id 52/92-02454-89FBA054 for <example@vandinter.org>; Fri, 15 Sep 2006 10:58:32 -0400 536 elsif (/\(ecelerity\b/) { 537 if (/^\(\[(${IP_ADDRESS}):\d+\] helo=(\S+)\) by (\S+) /) { 538 $ip = $1; $helo = $2; $by = $3; 539 goto enough; 540 } 541 542 if (/^\S+ \(\[(${IP_ADDRESS}):\d+\]\) by (\S+) /) { 543 $ip = $1; $by = $2; 544 goto enough; 545 } 546 } 547 548 elsif (/Exim/) { 549 # one of the HUGE number of Exim formats :( 550 # This must be scriptable. (update: it is. cf bug 3950, 3582) 551 # mss 2004-09-27: See <http://www.exim.org/exim-html-4.40/doc/html/spec_14.html#IX1315> 552 553 # from root (helo=candygram.thunk.org) by thunker.thunk.org with local-esmtps (tls_cipher TLS-1.0:RSA_AES_256_CBC_SHA:32) (Exim 4.50 #1 (Debian)) id 1FwHqR-0008Bw-OG; Fri, 30 Jun 2006 08:11:35 -0400 554 # from root (helo=localhost) by broadcast.iac.iafrica.com with local-bsmtp (Exim 4.30; FreeBSD) id 1GN22d-0000xp-2K for example@vandinter.org; Tue, 12 Sep 2006 08:46:43 +0200 555 # from smarter (helo=localhost) by mx1-out.lists.smarterliving.com with local-bsmtp (Exim 4.24) id 1GIRA2-0007IZ-4n for example@vandinter.org; Wed, 30 Aug 2006 10:35:22 -0400 556 # Received: from andrew by trinity.supernews.net with local (Exim 4.12) id 18xeL6-000Dn1-00; Tue, 25 Mar 2003 02:39:00 +0000 557 if (/\bwith local(?:-\S+)? /) { return 0; } 558 559 # Received: from [61.174.163.26] (helo=host) by sc8-sf-list1.sourceforge.net with smtp (Exim 3.31-VA-mm2 #1 (Debian)) id 18t2z0-0001NX-00 for <razor-users@lists.sourceforge.net>; Wed, 12 Mar 2003 01:57:10 -0800 560 # Received: from [218.19.142.229] (helo=hotmail.com ident=yiuhyotp) by yzordderrex with smtp (Exim 3.35 #1 (Debian)) id 194BE5-0005Zh-00; Sat, 12 Apr 2003 03:58:53 +0100 561 if (/^\[(${IP_ADDRESS})\] \((.*?)\) by (\S+) /) { 562 $ip = $1; my $sub = $2; $by = $3; 563 $sub =~ s/helo=(\S+)// and $helo = $1; 564 $sub =~ s/ident=(\S*)// and $ident = $1; 565 goto enough; 566 } 567 568 # Received: from sc8-sf-list1-b.sourceforge.net ([10.3.1.13] helo=sc8-sf-list1.sourceforge.net) by sc8-sf-list2.sourceforge.net with esmtp (Exim 3.31-VA-mm2 #1 (Debian)) id 18t301-0007Bh-00; Wed, 12 Mar 2003 01:58:13 -0800 569 # Received: from dsl092-072-213.bos1.dsl.speakeasy.net ([66.92.72.213] helo=blazing.arsecandle.org) by sc8-sf-list1.sourceforge.net with esmtp (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) id 18lyuU-0007TI-00 for <SpamAssassin-talk@lists.sourceforge.net>; Thu, 20 Feb 2003 14:11:18 -0800 570 # Received: from eclectic.kluge.net ([66.92.69.221] ident=[W9VcNxE2vKxgWHD05PJbLzIHSxcmZQ/O]) by sc8-sf-list1.sourceforge.net with esmtp (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) id 18m0hT-00031I-00 for <spamassassin-talk@lists.sourceforge.net>; Thu, 20 Feb 2003 16:06:00 -0800 571 # Received: from mail.ssccbelen.edu.pe ([216.244.149.154]) by yzordderrex 572 # with esmtp (Exim 3.35 #1 (Debian)) id 18tqiz-000702-00 for 573 # <jm@example.com>; Fri, 14 Mar 2003 15:03:57 +0000 574 # Received: from server040.webpack.hosteurope.de ([80.237.130.48]:52313) 575 # by vps832469583.serverpool.info with esmtps 576 # (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.50) id 1GzVLs-0002Oz-7b... 577 if (/^(\S+) \(\[(${IP_ADDRESS})\](.*?)\) by (\S+) /) { 578 $rdns=$1; $ip = $2; my $sub = $3; $by = $4; 579 $helo=$rdns; # default, apparently: bug 5112 580 $sub =~ s/helo=(\S+)// and $helo = $1; 581 $sub =~ s/ident=(\S*)// and $ident = $1; 582 goto enough; 583 } 584 585 # Received: from boggle.ihug.co.nz [203.109.252.209] by grunt6.ihug.co.nz 586 # with esmtp (Exim 3.35 #1 (Debian)) id 18SWRe-0006X6-00; Sun, 29 Dec 587 # 2002 18:57:06 +1300 588 if (/^(\S+) \[(${IP_ADDRESS})\](:\d+)? by (\S+) /) { 589 $rdns= $1; $ip = $2; $helo = $1; $by = $4; goto enough; 590 } 591 592 # attempt to deal with other odd Exim formats; just match little bits 593 # of the header. 594 # Received: from helene8.i.pinwand.net (helene.cats.ms) [10.0.8.6.13219] 595 # (mail) by lisbeth.i.pinwand.net with esmtp (Exim 3.35 #1 (Debian)) id 596 # 1CO5y7-0001vC-00; Sun, 31 Oct 2004 04:01:23 +0100 597 if (/^(\S+) /) { 598 $rdns= $1; # assume this is the rDNS, not HELO. is this appropriate? 599 } 600 if (/ \((\S+)\) /) { 601 $helo = $1; 602 } 603 if (/ \[(${IP_ADDRESS})(?:\.\d+)?\] /) { 604 $ip = $1; 605 } 606 if (/by (\S+) /) { 607 $by = $1; 608 # now, if we have a "by" and an IP, that's enough for most uses; 609 # we have to make do with that. 610 if ($ip) { goto enough; } 611 } 612 613 # else it's probably forged. fall through 614 } 615 616 elsif (/ \(Postfix\) with/) { 617 # Received: from localhost (unknown [127.0.0.1]) 618 # by cabbage.jmason.org (Postfix) with ESMTP id A96E18BD97 619 # for <jm@localhost>; Thu, 13 Mar 2003 15:23:15 -0500 (EST) 620 if ( /^(\S+) \((\S+) \[(${IP_ADDRESS})\]\) by (\S+) / ) { 621 $mta_looked_up_dns = 1; 622 $helo = $1; $rdns = $2; $ip = $3; $by = $4; 623 if ($rdns eq 'unknown') { $rdns = ''; } 624 goto enough; 625 } 626 627 # Received: from 207.8.214.3 (unknown[211.94.164.65]) 628 # by puzzle.pobox.com (Postfix) with SMTP id 9029AFB732; 629 # Sat, 8 Nov 2003 17:57:46 -0500 (EST) 630 # (Pobox.com version: reported in bug 2745) 631 if ( /^(\S+) \((\S+)\[(${IP_ADDRESS})\]\) by (\S+) / ) { 632 $mta_looked_up_dns = 1; 633 $helo = $1; $rdns = $2; $ip = $3; $by = $4; 634 if ($rdns eq 'unknown') { $rdns = ''; } 635 goto enough; 636 } 637 } 638 639 elsif (/\(Scalix SMTP Relay/) { 640 # from DPLAPTOP ( 72.242.176.162) by mail.puryear-it.com (Scalix SMTP Relay 10.0.1.3) via ESMTP; Fri, 23 Jun 2006 16:39:47 -0500 (CDT) 641 if (/^(\S+) \( ?(${IP_ADDRESS})\) by (\S+)/) { 642 $helo = $1; $ip = $2; $by = $3; goto enough; 643 } 644 } 645 646 elsif (/ \(Lotus Domino /) { 647 # it seems Domino never records the rDNS: bug 5926 648 if (/^(\S+) \(\[(${IP_ADDRESS})\]\) by (\S+) \(Lotus/) { 649 $mta_looked_up_dns = 0; 650 $helo = $1; $ip = $2; $by = $3; goto enough; 651 } 652 } 653 654 # Received: from 217.137.58.28 ([217.137.58.28]) 655 # by webmail.ukonline.net (IMP) with HTTP 656 # for <anarchyintheuk@localhost>; Sun, 11 Apr 2004 00:31:07 +0100 657 if (/\bwith HTTP\b/ && # more efficient split up this way 658 /^(${IP_ADDRESS}) \(\[${IP_ADDRESS}\]\) by (\S+)/) 659 { 660 # some smarty-pants decided to fake a numeric HELO for HTTP 661 # no rDNS for this format? 662 $ip = $1; $by = $2; goto enough; 663 } 664 665 # MiB: 2003/11/29 Some qmail-ldap headers may be misinterpreted as sendmail-headers 666 # resulting in a messed-up interpretation. We have to skip sendmail tests 667 # if we find evidence that this is a qmail-ldap header. 668 # 669 unless (/ by \S+ \(qmail-\S+\) with /) { 670 # 671 # sendmail: 672 # Received: from mail1.insuranceiq.com (host66.insuranceiq.com [65.217.159.66] (may be forged)) by dogma.slashnull.org (8.11.6/8.11.6) with ESMTP id h2F0c2x31856 for <jm@jmason.org>; Sat, 15 Mar 2003 00:38:03 GMT 673 # Received: from BAY0-HMR08.adinternal.hotmail.com (bay0-hmr08.bay0.hotmail.com [65.54.241.207]) by dogma.slashnull.org (8.11.6/8.11.6) with ESMTP id h2DBpvs24047 for <webmaster@efi.ie>; Thu, 13 Mar 2003 11:51:57 GMT 674 # Received: from ran-out.mx.develooper.com (IDENT:qmailr@one.develooper.com [64.81.84.115]) by dogma.slashnull.org (8.11.6/8.11.6) with SMTP id h381Vvf19860 for <jm-cpan@jmason.org>; Tue, 8 Apr 2003 02:31:57 +0100 675 # from rev.net (natpool62.rev.net [63.148.93.62] (may be forged)) (authenticated) by mail.rev.net (8.11.4/8.11.4) with ESMTP id h0KKa7d32306 for <spamassassin-talk@lists.sourceforge.net> 676 # 677 if (/^(\S+) \((\S+) \[(${IP_ADDRESS})\].*\) by (\S+) \(/) { 678 $mta_looked_up_dns = 1; 679 $helo = $1; $rdns = $2; $ip = $3; $by = $4; 680 $rdns =~ s/^IDENT:([^\@]*)\@// and $ident = $1; # remove IDENT lookups 681 $rdns =~ s/^([^\@]*)\@// and $ident = $1; # remove IDENT lookups 682 goto enough; 683 } 684 } 685 686# --------------------------------------------------------------------------- 687 688 ## OK, AT THIS POINT FORMATS GET A BIT NON-STANDARD 689 690 # Received: from ns.elcanto.co.kr (66.161.246.58 [66.161.246.58]) by 691 # mail.ssccbelen.edu.pe with SMTP (Microsoft Exchange Internet Mail Service 692 # Version 5.5.1960.3) id G69TW478; Thu, 13 Mar 2003 14:01:10 -0500 693 if (/^(\S+) \((\S+) \[(${IP_ADDRESS})\]\) by (\S+) with \S+ \(/) { 694 $mta_looked_up_dns = 1; 695 $rdns = $2; $ip = $3; $helo = $1; $by = $4; goto enough; 696 } 697 698 # from mail2.detr.gsi.gov.uk ([51.64.35.18] helo=ahvfw.dtlr.gsi.gov.uk) by mail4.gsi.gov.uk with smtp id 190K1R-0000me-00 for spamassassin-talk-admin@lists.sourceforge.net; Tue, 01 Apr 2003 12:33:46 +0100 699 if (/^(\S+) \(\[(${IP_ADDRESS})\] helo=(\S+)\) by (\S+) with /) { 700 $rdns = $1; $ip = $2; $helo = $3; $by = $4; 701 goto enough; 702 } 703 704 # from 12-211-5-69.client.attbi.com (<unknown.domain>[12.211.5.69]) by rwcrmhc53.attbi.com (rwcrmhc53) with SMTP id <2002112823351305300akl1ue>; Thu, 28 Nov 2002 23:35:13 +0000 705 if (/^(\S+) \(<unknown\S*>\[(${IP_ADDRESS})\]\) by (\S+) /) { 706 $helo = $1; $ip = $2; $by = $3; 707 goto enough; 708 } 709 710 # from attbi.com (h000502e08144.ne.client2.attbi.com[24.128.27.103]) by rwcrmhc53.attbi.com (rwcrmhc53) with SMTP id <20030222193438053008f7tee>; Sat, 22 Feb 2003 19:34:39 +0000 711 if (/^(\S+) \((\S+\.\S+)\[(${IP_ADDRESS})\]\) by (\S+) /) { 712 $mta_looked_up_dns = 1; 713 $helo = $1; $rdns = $2; $ip = $3; $by = $4; 714 goto enough; 715 } 716 717 718 # Received: from 4wtgRl (kgbxn@[211.244.147.115]) by dogma.slashnull.org (8.11.6/8.11.6) with SMTP id h8BBsUJ18848; Thu, 11 Sep 2003 12:54:31 +0100 719 if (/^(\S+) \((\S*)\@\[(${IP_ADDRESS})\].*\) by (\S+) \(/) { 720 $mta_looked_up_dns = 1; # this one does. there just wasn't one 721 $helo = $1; $ip = $3; $by = $4; 722 $ident = $2; 723 goto enough; 724 } 725 726 # Received: from 213.123.174.21 by lw11fd.law11.hotmail.msn.com with HTTP; 727 # Wed, 24 Jul 2002 16:36:44 GMT 728 if (/by (\S+\.hotmail\.msn\.com) /) { 729 $by = $1; 730 /^(${IP_ADDRESS}) / and $ip = $1; 731 goto enough; 732 } 733 734 # Received: from x71-x56-x24-5.webspeed.dk (HELO niels) (69.96.3.15) by la.mx.develooper.com (qpsmtpd/0.27-dev) with SMTP; Fri, 02 Jan 2004 19:26:52 -0800 735 # Received: from sc8-sf-sshgate.sourceforge.net (HELO sc8-sf-netmisc.sourceforge.net) (66.35.250.220) by la.mx.develooper.com (qpsmtpd/0.27-dev) with ESMTP; Fri, 02 Jan 2004 14:44:41 -0800 736 # Received: from mx10.topofferz.net (HELO ) (69.6.60.10) by blazing.arsecandle.org with SMTP; 3 Mar 2004 20:34:38 -0000 737 if (/^(\S+) \((?:HELO|EHLO) (\S*)\) \((${IP_ADDRESS})\) by (\S+) \(qpsmtpd\/\S+\) with (?:ESMTP|SMTP)/) { 738 $rdns = $1; $helo = $2; $ip = $3; $by = $4; goto enough; 739 } 740 741 # Received: from mail-backend.DDDD.com (LHLO mail-backend.DDDD.com) (10.2.2.20) by mail-backend.DDDD.com with LMTP; Thu, 18 Jun 2015 16:50:56 -0700 (PDT) 742 if (/^(\S+) \(LHLO (\S*)\) \((${IP_ADDRESS})\) by (\S+) with LMTP/) { 743 $rdns = $1; $helo = $2; $ip = $3; $by = $4; goto enough; 744 } 745 746 # from dslb-082-083-045-064.pools.arcor-ip.net (EHLO homepc) [82.83.45.64] by mail.gmx.net (mp010) with SMTP; 03 Feb 2007 13:13:47 +0100 747 if (/^(\S+) \((?:HELO|EHLO) (\S*)\) \[(${IP_ADDRESS})\] by (\S+) \([^\)]+\) with (?:ESMTP|SMTP)/) { 748 $rdns = $1; $helo = $2; $ip = $3; $by = $4; goto enough; 749 } 750 751 # MiB (Michel Bouissou, 2003/11/16) 752 # Moved some tests up because they might match on qmail tests, where this 753 # is not qmail 754 # 755 # Received: from imo-m01.mx.aol.com ([64.12.136.4]) by eagle.glenraven.com 756 # via smtpd (for [198.85.87.98]) with SMTP; Wed, 08 Oct 2003 16:25:37 -0400 757 if (/^(\S+) \(\[(${IP_ADDRESS})\]\) by (\S+) via smtpd \(for \S+\) with SMTP\(/) { 758 $helo = $1; $ip = $2; $by = $3; goto enough; 759 } 760 761 # Try to match most of various qmail possibilities 762 # 763 # General format: 764 # Received: from postfix3-2.free.fr (HELO machine.domain.com) (foobar@213.228.0.169) by totor.bouissou.net with SMTP; 14 Nov 2003 08:05:50 -0000 765 # 766 # "from (remote.rDNS|unknown)" is always there 767 # "(HELO machine.domain.com)" is there only if HELO differs from remote rDNS. 768 # HELO may be "" -- ie no string. "HELO" may also be "EHLO". HELO string 769 # may be an IP in fmt [1.2.3.4] -- do not strip [ and ], they are important. 770 # "foobar@" is remote IDENT info, specified only if ident given by remote 771 # Remote IP always appears between (parentheses), with or without IDENT@ 772 # "by local.system.domain.com" always appears 773 # 774 # Protocol can be different from "SMTP", i.e. "RC4-SHA encrypted SMTP" or "QMQP" 775 # qmail's reported protocol shouldn't be "ESMTP", so by allowing only "with (.* )(SMTP|QMQP)" 776 # we should avoid matching on some sendmailish Received: lines that reports remote IP 777 # between ([218.0.185.24]) like qmail-ldap does, but use "with ESMTP". 778 # 779 # Normally, qmail-smtpd remote IP isn't between square brackets [], but some versions of 780 # qmail-ldap seem to add square brackets around remote IP. These versions of qmail-ldap 781 # use a longer format that also states the (envelope-sender <sender@domain>) and the 782 # qmail-ldap version. Example: 783 # Received: from unknown (HELO terpsichore.farfalle.com) (jdavid@[216.254.40.70]) (envelope-sender <jdavid@farfalle.com>) by mail13.speakeasy.net (qmail-ldap-1.03) with SMTP for <jm@jmason.org>; 12 Feb 2003 18:23:19 -0000 784 # 785 # Some others of the numerous qmail patches out there can also add variants of their own 786 # 787 # Received: from 211.245.85.228 (EHLO ) (211.245.85.228) by mta232.mail.scd.yahoo.com with SMTP; Sun, 25 Jan 2004 00:24:37 -0800 788 # 789 # bug 4813: make sure that the line doesn't have " id " after the 790 # protocol since that's a sendmail line and not qmail ... 791 if (/^\S+( \((?:HELO|EHLO) \S*\))? \((\S+\@)?\[?${IP_ADDRESS}\]?\)( \(envelope-sender <\S+>\))? by \S+( \(.+\))* with (.* )?(SMTP|QMQP)(?! id )/ ) { 792 if (/^(\S+) \((?:HELO|EHLO) ([^ \(\)]*)\) \((\S*)\@\[?(${IP_ADDRESS})\]?\)( \(envelope-sender <\S+>\))? by (\S+)/) { 793 $rdns = $1; $helo = $2; $ident = $3; $ip = $4; $by = $6; 794 } 795 elsif (/^(\S+) \((?:HELO|EHLO) ([^ \(\)]*)\) \(\[?(${IP_ADDRESS})\]?\)( \(envelope-sender <\S+>\))? by (\S+)/) { 796 $rdns = $1; $helo = $2; $ip = $3; $by = $5; 797 } 798 elsif (/^(\S+) \((\S*)\@\[?(${IP_ADDRESS})\]?\)( \(envelope-sender <\S+>\))? by (\S+)/) { 799 # note: absence of HELO means that it matched rDNS in qmail-land 800 $helo = $rdns = $1; $ident = $2; $ip = $3; $by = $5; 801 } 802 elsif (/^(\S+) \(\[?(${IP_ADDRESS})\]?\)( \(envelope-sender <\S+>\))? by (\S+)/) { 803 $helo = $rdns = $1; $ip = $2; $by = $4; 804 } 805 # qmail doesn't perform rDNS requests by itself, but is usually called 806 # by tcpserver or a similar daemon that passes rDNS information to qmail-smtpd. 807 # If qmail puts something else than "unknown" in the rDNS field, it means that 808 # it received this information from the daemon that called it. If qmail-smtpd 809 # writes "Received: from unknown", it means that either the remote has no 810 # rDNS, or qmail was called by a daemon that didn't gave the rDNS information. 811 if ($rdns ne "unknown") { 812 $mta_looked_up_dns = 1; 813 } else { 814 $rdns = ''; 815 } 816 goto enough; 817 818 } 819 # /MiB 820 821 # Received: from [193.220.176.134] by web40310.mail.yahoo.com via HTTP; 822 # Wed, 12 Feb 2003 14:22:21 PST 823 if (/ via HTTP$/&&/^\[(${IP_ADDRESS})\] by (\S+) via HTTP$/) { 824 $ip = $1; $by = $2; goto enough; 825 } 826 827 # Received: from 192.168.5.158 ( [192.168.5.158]) as user jason@localhost by mail.reusch.net with HTTP; Mon, 8 Jul 2002 23:24:56 -0400 828 if (/^(\S+) \( \[(${IP_ADDRESS})\]\).*? by (\S+) /) { 829 # TODO: is $1 helo? 830 $ip = $2; $by = $3; goto enough; 831 } 832 833 # Received: from (64.52.135.194 [64.52.135.194]) by mail.unearthed.com with ESMTP id BQB0hUH2 Thu, 20 Feb 2003 16:13:20 -0700 (PST) 834 if (/^\((\S+) \[(${IP_ADDRESS})\]\) by (\S+) /) { 835 $helo = $1; $ip = $2; $by = $3; goto enough; 836 } 837 838 # Received: from [65.167.180.251] by relent.cedata.com (MessageWall 1.1.0) with SMTP; 20 Feb 2003 23:57:15 -0000 839 if (/^\[(${IP_ADDRESS})\] by (\S+) /) { 840 $ip = $1; $by = $2; goto enough; 841 } 842 843 # from ([172.16.1.78]) by email2.codeworksonline.com with Microsoft SMTPSVC(5.0.2195.6713); Wed, 6 Sep 2006 21:14:29 -0400 844 # from (130.215.36.186) by mcafee.wpi.edu via smtp id 021b_7e19a55a_ea7e_11da_83a9_00304811e63a; Tue, 23 May 2006 13:06:35 -0400 845 # from ([172.21.2.10]) by out-relay4.mtahq.org with ESMTP id 4420961.8281; Tue, 22 Aug 2006 17:53:08 -0400 846 if (/^\(\[?(${IP_ADDRESS})\]?\) by (\S+) /) { 847 $ip = $1; $by = $2; goto enough; 848 } 849 850 # Received: from acecomms [202.83.84.95] by mailscan.acenet.net.au [202.83.84.27] with SMTP (MDaemon.PRO.v5.0.6.R) for <spamassassin-talk@lists.sourceforge.net>; Fri, 21 Feb 2003 09:32:27 +1000 851 if (/^(\S+) \[(${IP_ADDRESS})\] by (\S+) \[${IP_ADDRESS}\] with /) { 852 $mta_looked_up_dns = 1; 853 $helo = $1; $ip = $2; $by = $3; 854 goto enough; 855 } 856 857 # Received: smtp510.aspkunden.de [(134.97.4.21)] by mail.aspemail.de (134.97.4.24) (MDaemon PRO v19.0.2) with ESMTP id md50018233933.msg; Tue, 16 Jul 2019 11:39:22 +0200 858 if (/^(\S+) \[\((${IP_ADDRESS})\)\] by (\S+) \(${IP_ADDRESS}\) /) { 859 $helo = $1; $ip = $2; $by = $3; 860 goto enough; 861 } 862 863 # Received: from mail.sxptt.zj.cn ([218.0.185.24]) by dogma.slashnull.org 864 # (8.11.6/8.11.6) with ESMTP id h2FH0Zx11330 for <webmaster@efi.ie>; 865 # Sat, 15 Mar 2003 17:00:41 GMT 866 if (/^(\S+) \(\[(${IP_ADDRESS})\]\) by (\S+) \(/) { # sendmail 867 $mta_looked_up_dns = 1; 868 $helo = $1; $ip = $2; $by = $3; goto enough; 869 } 870 871 # Received: from umr-mail7.umr.edu (umr-mail7.umr.edu [131.151.1.64]) via ESMTP by mrelay1.cc.umr.edu (8.12.1/) id h06GHYLZ022481; Mon, 6 Jan 2003 10:17:34 -0600 872 # Received: from Agni (localhost [::ffff:127.0.0.1]) (TLS: TLSv1/SSLv3, 168bits,DES-CBC3-SHA) by agni.forevermore.net with esmtp; Mon, 28 Oct 2002 14:48:52 -0800 873 # Received: from gandalf ([4.37.75.131]) (authenticated bits=0) by herald.cc.purdue.edu (8.12.5/8.12.5/herald) with ESMTP id g9JLefrm028228 for <spamassassin-talk@lists.sourceforge.net>; Sat, 19 Oct 2002 16:40:41 -0500 (EST) 874 # Received: from bushinternet.com (softdnserr [::ffff:61.99.99.67]) by mail.cs.helsinki.fi with esmtp; Fri, 22 Aug 2003 12:25:41 +0300 875 if (/^(\S+) \((\S+) \[(${IP_ADDRESS})\]\).*? by (\S+)\b/) { # sendmail 876 if ($2 eq 'softdnserr') { 877 $mta_looked_up_dns = 0; # bug 2326: couriertcpd 878 } else { 879 $mta_looked_up_dns = 1; $rdns = $2; 880 } 881 $helo = $1; $ip = $3; $by = $4; goto enough; 882 } 883 884 # from jsoliday.acs.internap.com ([63.251.66.24.63559]) by 885 # mailhost.acs.internap.com with esmtp (v3.35.1) id 1GNrLz-000295-00; 886 # Thu, 14 Sep 2006 09:34:07 -0400 887 if (/^(\S+) \(\[(${IP_ADDRESS})(?:[.:]\d+)?\]\).*? by (\S+) /) { 888 $mta_looked_up_dns = 1; 889 $helo = $1; $ip = $2; $by = $3; goto enough; 890 } 891 892 # Received: from roissy (p573.as1.exs.dublin.eircom.net [159.134.226.61]) 893 # (authenticated bits=0) by slate.dublin.wbtsystems.com (8.12.6/8.12.6) 894 # with ESMTP id g9MFWcvb068860 for <jm@jmason.org>; 895 # Tue, 22 Oct 2002 16:32:39 +0100 (IST) 896 if (/^(\S+) \((\S+) \[(${IP_ADDRESS})\]\)(?: \(authenticated bits=\d+\))? by (\S+) \(/) { # sendmail 897 $mta_looked_up_dns = 1; 898 $helo = $1; $rdns = $2; $ip = $3; $by = $4; goto enough; 899 } 900 901 # Identify fetch-from-server incidents: 902 # Fetchmail: 903 # Received: from cabbage.jmason.org [127.0.0.1] 904 # by localhost with IMAP (fetchmail-5.9.0) 905 # for jm@localhost (single-drop); Thu, 13 Mar 2003 20:39:56 -0800 (PST) 906 # 907 # Getmail: 908 # Received: from pop3.mail.dk (195.41.46.251) by loki.valhalla with POP3; 909 # 14 Apr 2010 11:14:29 -0000 910 # 911 if (/with (?:POP3|IMAP)/) { 912 $self->found_pop_fetcher_sig(); 913 return 0; # skip mail fetcher handovers 914 } 915 916 # Let's try to support a few qmailish formats in one; 917 # http://issues.apache.org/SpamAssassin/show_bug.cgi?id=2744#c14 : 918 # Received: from unknown (HELO feux01a-isp) (213.199.4.210) by totor.bouissou.net with SMTP; 1 Nov 2003 07:05:19 -0000 919 # Received: from adsl-207-213-27-129.dsl.lsan03.pacbell.net (HELO merlin.net.au) (Owner50@207.213.27.129) by totor.bouissou.net with SMTP; 10 Nov 2003 06:30:34 -0000 920 if (/^(\S+) \((?:HELO|EHLO) ([^\)]*)\) \((\S*@)?\[?(${IP_ADDRESS})\]?\).* by (\S+) /) 921 { 922 $mta_looked_up_dns = 1; 923 $rdns = $1; 924 $helo = $2; 925 $ident = (defined $3) ? $3 : ''; 926 $ip = $4; 927 $by = $5; 928 if ($ident) { 929 $ident =~ s/\@$//; 930 } 931 goto enough; 932 } 933 934 # Received: from x1-6-00-04-bd-d2-e0-a3.k317.webspeed.dk (benelli@80.167.158.170) by totor.bouissou.net with SMTP; 5 Nov 2003 23:18:42 -0000 935 if (/^(\S+) \((\S*@)?\[?(${IP_ADDRESS})\]?\).* by (\S+) /) 936 { 937 $mta_looked_up_dns = 1; 938 # bug 2744 notes that if HELO == rDNS, qmail drops it. 939 $rdns = $1; $helo = $rdns; $ident = (defined $2) ? $2 : ''; 940 $ip = $3; $by = $4; 941 if ($ident) { $ident =~ s/\@$//; } 942 goto enough; 943 } 944 945 # Received: from [129.24.215.125] by ws1-7.us4.outblaze.com with http for 946 # _bushisevil_@mail.com; Thu, 13 Feb 2003 15:59:28 -0500 947 if (/ with http for /&&/^\[(${IP_ADDRESS})\] by (\S+) with http for /) { 948 $ip = $1; $by = $2; goto enough; 949 } 950 951 # Received: from snake.corp.yahoo.com(216.145.52.229) by x.x.org via smap (V1.3) 952 # id xma093673; Wed, 26 Mar 03 20:43:24 -0600 953 if (/ via smap /&&/^(\S+)\((${IP_ADDRESS})\) by (\S+) via smap /) { 954 $mta_looked_up_dns = 1; 955 $rdns = $1; $ip = $2; $by = $3; goto enough; 956 } 957 958 # Received: from smtp.greyware.com(208.14.208.51, HELO smtp.sff.net) by x.x.org via smap (V1.3) 959 # id xma002908; Fri, 27 Feb 04 14:16:56 -0800 960 if (/^(\S+)\((${IP_ADDRESS}), (?:HELO|EHLO) (\S*)\) by (\S+) via smap /) { 961 $mta_looked_up_dns = 1; 962 $rdns = $1; $ip = $2; $helo = $3; $by = $4; goto enough; 963 } 964 965 # Received: from [192.168.0.71] by web01-nyc.clicvu.com (Post.Office MTA 966 # v3.5.3 release 223 ID# 0-64039U1000L100S0V35) with SMTP id com for 967 # <x@x.org>; Tue, 25 Mar 2003 11:42:04 -0500 968 if (/ \(Post/&&/^\[(${IP_ADDRESS})\] by (\S+) \(Post/) { 969 $ip = $1; $by = $2; goto enough; 970 } 971 972 # Received: from [127.0.0.1] by euphoria (ArGoSoft Mail Server 973 # Freeware, Version 1.8 (1.8.2.5)); Sat, 8 Feb 2003 09:45:32 +0200 974 if (/ \(ArGoSoft/&&/^\[(${IP_ADDRESS})\] by (\S+) \(ArGoSoft/) { 975 $ip = $1; $by = $2; goto enough; 976 } 977 978 # Received: from 157.54.8.23 by inet-vrs-05.redmond.corp.microsoft.com 979 # (InterScan E-Mail VirusWall NT); Thu, 06 Mar 2003 12:02:35 -0800 980 # Received: from 10.165.130.62 by CNNIMAIL12.CNN.COM (SMTPL release 1.0d) with TCP; Fri, 1 Sep 2006 20:28:14 -0400 981 if (/^(${IP_ADDRESS}) by (\S+) \((?:SMTPL|InterScan)\b/) { 982 $ip = $1; $by = $2; goto enough; 983 } 984 985 # Received: from faerber.muc.de by slarti.muc.de with BSMTP (rsmtp-qm-ot 0.4) 986 # for asrg@ietf.org; 7 Mar 2003 21:10:38 -0000 987 if (/ with BSMTP/&&/^\S+ by \S+ with BSMTP/) { 988 return 0; # BSMTP != a TCP/IP handover, ignore it 989 } 990 991 # Received: from spike (spike.ig.co.uk [193.32.60.32]) by mail.ig.co.uk with 992 # SMTP id h27CrCD03362 for <asrg@ietf.org>; Fri, 7 Mar 2003 12:53:12 GMT 993 if (/^(\S+) \((\S+) \[(${IP_ADDRESS})\]\) by (\S+) with /) { 994 $mta_looked_up_dns = 1; 995 $helo = $1; $rdns = $2; $ip = $3; $by = $4; goto enough; 996 } 997 998 # Received: from customer254-217.iplannetworks.net (HELO AGAMENON) 999 # (baldusi@200.69.254.217 with plain) by smtp.mail.vip.sc5.yahoo.com with 1000 # SMTP; 11 Mar 2003 21:03:28 -0000 1001 if (/^(\S+) \((?:HELO|EHLO) (\S*)\) \((?:(\S+)\@)?(${IP_ADDRESS}).*?\) by (\S+) with /) { 1002 $mta_looked_up_dns = 1; 1003 $rdns = $1; $helo = $2; $ip = $4; $by = $5; 1004 $ident = $3 if defined $3; 1005 goto enough; 1006 } 1007 1008 # Received: from [192.168.1.104] (account nazgul HELO [192.168.1.104]) 1009 # by somewhere.com (CommuniGate Pro SMTP 3.5.7) with ESMTP-TLS id 2088434; 1010 # Fri, 07 Mar 2003 13:05:06 -0500 1011 if (/^\[(${IP_ADDRESS})\] \((?:account \S+ )?(?:HELO|EHLO) (\S*)\) by (\S+) \(/) { 1012 $ip = $1; $helo = $2; $by = $3; goto enough; 1013 } 1014 1015 # Received: from host.example.com ([192.0.2.1] verified) 1016 # by mail.example.net (CommuniGate Pro SMTP 5.1.13) 1017 # with ESMTP id 9786656 for user@example.net; Thu, 27 Mar 2008 15:08:17 +0600 1018 if (/ \(CommuniGate Pro/ && /^(\S+) \(\[(${IP_ADDRESS})\] verified\) by (\S+) \(/) { 1019 $mta_looked_up_dns = 1; 1020 $rdns = $1; $helo = $1; $ip = $2; $by = $3; goto enough; 1021 } 1022 1023 # Received: from ([10.0.0.6]) by mail0.ciphertrust.com with ESMTP ; Thu, 1024 # 13 Mar 2003 06:26:21 -0500 (EST) 1025 if (/^\(\[(${IP_ADDRESS})\]\) by (\S+) with /) { 1026 $ip = $1; $by = $2; goto enough; 1027 } 1028 1029 # Received: from ironport.com (10.1.1.5) by a50.ironport.com with ESMTP; 01 Apr 2003 12:00:51 -0800 1030 # Received: from dyn-81-166-39-132.ppp.tiscali.fr (81.166.39.132) by cpmail.dk.tiscali.com (6.7.018) 1031 if (/^([^\d]\S+) \((${IP_ADDRESS})\) by (\S+) /) { 1032 $helo = $1; $ip = $2; $by = $3; goto enough; 1033 } 1034 1035 # Received: from scv3.apple.com (scv3.apple.com) by mailgate2.apple.com (Content Technologies SMTPRS 4.2.1) with ESMTP id <T61095998e1118164e13f8@mailgate2.apple.com>; Mon, 17 Mar 2003 17:04:54 -0800 1036 # bug 4704: Only let this match Content Technologies so it stops breaking things that come after it by matching first 1037 if (/^\S+ \(\S+\) by \S+ \(Content Technologies /) { 1038 return 0; # useless without the $ip anyway! 1039 } 1040 1041 # Received: from 01al10015010057.ad.bls.com ([90.152.5.141] [90.152.5.141]) 1042 # by aismtp3g.bls.com with ESMTP; Mon, 10 Mar 2003 11:10:41 -0500 1043 if (/^(\S+) \(\[(${IP_ADDRESS})\] \[(\S+)\]\) by (\S+) with /) { 1044 # not sure what $3 is ;) 1045 $helo = $1; $ip = $2; $by = $4; 1046 goto enough; 1047 } 1048 1049 # Received: from 206.47.0.153 by dm3cn8.bell.ca with ESMTP (Tumbleweed MMS 1050 # SMTP Relay (MMS v5.0)); Mon, 24 Mar 2003 19:49:48 -0500 1051 if (/^(${IP_ADDRESS}) by (\S+) with /) { 1052 $ip = $1; $by = $2; 1053 goto enough; 1054 } 1055 1056 # Received: from pobox.com (h005018086b3b.ne.client2.attbi.com[66.31.45.164]) 1057 # by rwcrmhc53.attbi.com (rwcrmhc53) with SMTP id <2003031302165605300suph7e>; 1058 # Thu, 13 Mar 2003 02:16:56 +0000 1059 if (/^(\S+) \((\S+)\[(${IP_ADDRESS})\]\) by (\S+) /) { 1060 $mta_looked_up_dns = 1; 1061 $helo = $1; $rdns = $2; $ip = $3; $by = $4; goto enough; 1062 } 1063 1064 # Received: from [10.128.128.81]:50999 (HELO dfintra.f-secure.com) by fsav4im2 ([10.128.128.74]:25) (F-Secure Anti-Virus for Internet Mail 6.0.34 Release) with SMTP; Tue, 5 Mar 2002 14:11:53 -0000 1065 if (/^\[(${IP_ADDRESS})\]\S+ \((?:HELO|EHLO) (\S*)\) by (\S+) /) { 1066 $ip = $1; $helo = $2; $by = $3; goto enough; 1067 } 1068 1069 # Received: from 62.180.7.250 (HELO daisy) by smtp.altavista.de (209.228.22.152) with SMTP; 19 Sep 2002 17:03:17 +0000 1070 if (/^(${IP_ADDRESS}) \((?:HELO|EHLO) (\S*)\) by (\S+) /) { 1071 $ip = $1; $helo = $2; $by = $3; goto enough; 1072 } 1073 1074 # Received: from oemcomputer [63.232.189.195] by highstream.net (SMTPD32-7.07) id A4CE7F2A0028; Sat, 01 Feb 2003 21:39:10 -0500 1075 if (/^(\S+) \[(${IP_ADDRESS})\] by (\S+) /) { 1076 $helo = $1; $ip = $2; $by = $3; goto enough; 1077 } 1078 1079 # from nodnsquery(192.100.64.12) by herbivore.monmouth.edu via csmap (V4.1) id srcAAAyHaywy 1080 if (/^(\S+)\((${IP_ADDRESS})\) by (\S+) /) { 1081 $rdns = $1; $ip = $2; $by = $3; goto enough; 1082 } 1083 1084 # Received: from [192.168.0.13] by <server> (MailGate 3.5.172) with SMTP; 1085 # Tue, 1 Apr 2003 15:04:55 +0100 1086 if (/^\[(${IP_ADDRESS})\] by (\S+) \(MailGate /) { 1087 $ip = $1; $by = $2; goto enough; 1088 } 1089 1090 # Received: from jmason.org (unverified [195.218.107.131]) by ni-mail1.dna.utvinternet.net <B0014212518@ni-mail1.dna.utvinternet.net>; Tue, 11 Feb 2003 12:18:12 +0000 1091 if (/^(\S+) \(unverified \[(${IP_ADDRESS})\]\) by (\S+) /) { 1092 $helo = $1; $ip = $2; $by = $3; goto enough; 1093 } 1094 1095 # # from 165.228.131.11 (proxying for 139.130.20.189) (SquirrelMail authenticated user jmmail) by jmason.org with HTTP 1096 # if (/^from (\S+) \(proxying for (${IP_ADDRESS})\) \([A-Za-z][^\)]+\) by (\S+) with /) { 1097 # $ip = $2; $by = $3; goto enough; 1098 # } 1099 if (/^(${IP_ADDRESS}) \([A-Za-z][^\)]+\) by (\S+) with /) { 1100 $ip = $1; $by = $2; goto enough; 1101 } 1102 1103 # Received: from [212.87.144.30] (account seiz [212.87.144.30] verified) by x.imd.net (CommuniGate Pro SMTP 4.0.3) with ESMTP-TLS id 5026665 for spamassassin-talk@lists.sourceforge.net; Wed, 15 Jan 2003 16:27:05 +0100 1104 # bug 4704 This pattern was checked as just an Exim format, but it does exist elsewhere 1105 # Received: from [206.51.230.145] (helo=t-online.de) 1106 # by mxeu2.kundenserver.de with ESMTP (Nemesis), 1107 # id 0MKpdM-1CkRpr14PF-000608; Fri, 31 Dec 2004 19:49:15 +0100 1108 # Received: from [218.19.142.229] (helo=hotmail.com ident=yiuhyotp) 1109 # by yzordderrex with smtp (Exim 3.35 #1 (Debian)) id 194BE5-0005Zh-00; Sat, 12 Apr 2003 03:58:53 +0100 1110 if (/^\[(${IP_ADDRESS})\] \(([^\)]+)\) by (\S+) /) { 1111 $ip = $1; my $sub = $2; $by = $3; 1112 $sub =~ s/helo=(\S+)// and $helo = $1; 1113 $sub =~ s/ident=(\S*)// and $ident = $1; 1114 goto enough; 1115 } 1116 1117 # Received: from mtsbp606.email-info.net (?dXqpg3b0hiH9faI2OxLT94P/YKDD3rQ1?@64.253.199.166) by kde.informatik.uni-kl.de with SMTP; 30 Apr 2003 15:06:29 1118 if (/^(\S+) \((?:\S+\@)?(${IP_ADDRESS})\) by (\S+) with /) { 1119 $rdns = $1; $ip = $2; $by = $3; goto enough; 1120 } 1121 1122 # Obtuse smtpd: http://www.obtuse.com/ 1123 # Received: from TCE-E-7-182-54.bta.net.cn(202.106.182.54) via SMTP 1124 # by st.tahina.priv.at, id smtpdEDUB8h; Sun Nov 13 14:50:12 2005 1125 # Received: from pl027.nas934.d-osaka.nttpc.ne.jp(61.197.82.27), claiming to be "foo.woas.net" via SMTP 1126 # by st.tahina.priv.at, id smtpd1PBsZT; Sun Nov 13 15:38:52 2005 1127 if (/^(\S+)\((${IP_ADDRESS})\)(?:, claiming to be "(\S+)")? via \S+ by (\S+),/) { 1128 $rdns = $1; $ip = $2; $helo = (defined $3) ? $3 : ''; $by = $4; 1129 if ($1 ne 'UNKNOWN') { 1130 $mta_looked_up_dns = 1; 1131 $rdns = $1; 1132 } 1133 goto enough; 1134 } 1135 1136 # Yahoo Authenticated SMTP; Bug #6535 1137 # from itrqtnlnq (lucilleskinner@93.124.107.183 with login) by smtp111.mail.ne1.yahoo.com with SMTP; 17 Jan 2011 08:23:27 -0800 PST 1138 if (/^(\S+) \((\S+)@(${IP_ADDRESS}) with login\) by (\S+\.yahoo\.com) with SMTP/) { 1139 $helo = $1; $ip = $3; $by = $4; goto enough; 1140 } 1141 1142 # a synthetic header, generated internally: 1143 # Received: X-Originating-IP: 1.2.3.4 1144 if (/^X-Originating-IP: (${IP_ADDRESS})$/) { 1145 $ip = $1; $by = ''; goto enough; 1146 } 1147 1148 ## STUFF TO IGNORE ## 1149 1150 # Received: from raptor.research.att.com (bala@localhost) by 1151 # raptor.research.att.com (SGI-8.9.3/8.8.7) with ESMTP id KAA14788 1152 # for <asrg@example.com>; Fri, 7 Mar 2003 10:37:56 -0500 (EST) 1153 # make this localhost-specific, so we know it's safe to ignore 1154 if (/^\S+ \([^\s\@]+\@${LOCALHOST}\) by \S+ \(/) { return 0; } 1155 1156 # from paul (helo=felix) by felix.peema.org with local-esmtp (Exim 4.43) 1157 # id 1Ccq0j-0002k2-Lk; Fri, 10 Dec 2004 19:01:01 +0000 1158 # Exim doco says this is local submission, cf switch -oMr 1159 if (/^\S+ \S+ by \S+ with local-e?smtp /) { return 0; } 1160 1161 # from 127.0.0.1 (AVG SMTP 7.0.299 [265.6.8]); Wed, 05 Jan 2005 15:06:48 -0800 1162 if (/^127\.0\.0\.1 \(AVG SMTP \S+ \[\S+\]\)/) { return 0; } 1163 1164 # from qmail-scanner-general-admin@lists.sourceforge.net by alpha by uid 7791 with qmail-scanner-1.14 (spamassassin: 2.41. Clear:SA:0(-4.1/5.0):. Processed in 0.209512 secs) 1165 if (/^\S+\@\S+ by \S+ by uid \S+ /) { return 0; } 1166 1167 # Received: from DSmith1204@aol.com by imo-m09.mx.aol.com (mail_out_v34.13.) id 7.53.208064a0 (4394); Sat, 11 Jan 2003 23:24:31 -0500 (EST) 1168 if (/^\S+\@\S+ by \S+ /) { return 0; } 1169 1170 # Received: from Unknown/Local ([?.?.?.?]) by mailcity.com; Fri, 17 Jan 2003 15:23:29 -0000 1171 if (/^Unknown\/Local \(/) { return 0; } 1172 1173 # Received: from localhost (mailnull@localhost) by x.org (8.12.6/8.9.3) 1174 # with SMTP id h2R2iivG093740; Wed, 26 Mar 2003 20:44:44 -0600 1175 # (CST) (envelope-from x@x.org) 1176 # Received: from localhost (localhost [127.0.0.1]) (uid 500) by mail with local; Tue, 07 Jan 2003 11:40:47 -0600 1177 if (/^${LOCALHOST} \((?:\S+\@)?${LOCALHOST}[\)\[]/) { return 0; } 1178 1179 # Received: from olgisoft.com (127.0.0.1) by 127.0.0.1 (EzMTS MTSSmtp 1180 # 1.55d5) ; Thu, 20 Mar 03 10:06:43 +0100 for <asrg@ietf.org> 1181 if (/^\S+ \((?:\S+\@)?${LOCALHOST}\) /) { return 0; } 1182 1183 # Received: from casper.ghostscript.com (raph@casper [127.0.0.1]) h148aux8016336verify=FAIL); Tue, 4 Feb 2003 00:36:56 -0800 1184 if (/^\S+ \(\S+\@\S+ \[${LOCALHOST}\]\) /) { return 0; } 1185 1186 # Received: from (AUTH: e40a9cea) by vqx.net with esmtp (courier-0.40) for <asrg@ietf.org>; Mon, 03 Mar 2003 14:49:28 +0000 1187 if (/^\(AUTH: \S+\) by \S+ with /) { return 0; } 1188 1189 # from localhost (localhost [[UNIX: localhost]]) by home.barryodonovan.com 1190 # (8.12.11/8.12.11/Submit) id iBADHRP6011034; Fri, 10 Dec 2004 13:17:27 GMT 1191 if (/^localhost \(localhost \[\[UNIX: localhost\]\]\) by /) { return 0; } 1192 1193 # Internal Amazon traffic 1194 # Received: from dc-mail-3102.iad3.amazon.com by mail-store-2001.amazon.com with ESMTP (peer crosscheck: dc-mail-3102.iad3.amazon.com) 1195 if (/^\S+\.amazon\.com by \S+\.amazon\.com with ESMTP \(peer crosscheck: /) { return 0; } 1196 1197 # Received: from GWGC6-MTA by gc6.jefferson.co.us with Novell_GroupWise; Tue, 30 Nov 2004 10:09:15 -0700 1198 if (/^[^\.]+ by \S+ with Novell_GroupWise/) { return 0; } 1199 1200 # Received: from no.name.available by [165.224.43.143] via smtpd (for [165.224.216.89]) with ESMTP; Fri, 28 Jan 2005 13:06:39 -0500 1201 # Received: from no.name.available by [165.224.216.88] via smtpd (for lists.sourceforge.net [66.35.250.206]) with ESMTP; Fri, 28 Jan 2005 15:42:30 -0500 1202 # These are from an internal host protected by a Raptor firewall, to hosts 1203 # outside the firewall. We can only ignore the handover since we don't have 1204 # enough info in those headers; however, from googling, it appears that 1205 # all samples are cases where the handover is safely ignored. 1206 if (/^no\.name\.available by \S+ via smtpd \(for /) { return 0; } 1207 1208 # from 156.56.111.196 by blazing.arsecandle.org (envelope-from <gentoo-announce-return-530-rod=arsecandle.org@lists.gentoo.org>, uid 502) with qmail-scanner-1.24 (clamdscan: 0.80/594. f-prot: 4.4.2/3.14.11. Clear:RC:0(156.56.111.196):. Processed in 0.288806 secs); 06 Feb 2005 21:11:38 -0000 1209 # these are safe to ignore. the previous handover line has the full 1210 # details of the handover described here, it's just qmail-scanner 1211 # logging a little more. 1212 if (/^\S+ by \S+ \(.{0,100}\) with qmail-scanner/) { 1213 if (defined $envfrom) { 1214 $envfrom =~ s/^\s*<*//gs; 1215 $envfrom =~ s/>*\s*$//gs; 1216 $envfrom =~ s/[\s\000\#\[\]\(\)\<\>\|]/!/gs; 1217 } 1218 $self->{qmail_scanner_env_from} = $envfrom; # hack! 1219 return 0; 1220 } 1221 1222 # Received: from mmail by argon.connect.org.uk with local (connectmail/exim) 1223 # id 18tOsg-0008FX-00; Thu, 13 Mar 2003 09:20:06 +0000 1224 if (/^\S+ by \S+ with local/) { return 0; } 1225 1226 # Local unix socket handover from Cyrus, tested with v2.3.14 1227 # Received: from testintranator.net.vm ([unix socket])_ by testintranator.net.vm (Cyrus v2.3.14) with LMTPA;_ Tue, 21 Jul 2009 14:34:14 +0200 1228 # Attention: Actually the received header is parsed as "testintranator.net.vm ([unix socket]) by testintranator.net.vm (Cyrus v2.3.14) with LMTPA", "from" is omitted. 1229 if (/^\S+ \(\[unix socket\]\) by \S+ \(Cyrus v[0-9]*?\.[0-9]*?\.[0-9]*?\) with LMTPA/) { return 0; } 1230 1231 # HANDOVERS WE KNOW WE CAN'T DEAL WITH: TCP transmission, but to MTAs that 1232 # just don't log enough info for us to use (ie. no IP address present). 1233 # Note: "return 0" is strongly recommended here, unless you're sure 1234 # the regexp won't match something in the field; otherwise ALL_TRUSTED may 1235 # fire even in the presence of an unparseable Received header. 1236 1237 # Received: from CATHY.IJS.SI by CATHY.IJS.SI (PMDF V4.3-10 #8779) id <01KTSSR50NSW001MXN@CATHY.IJS.SI>; Fri, 21 Mar 2003 20:50:56 +0100 1238 # Received: from MATT_LINUX by hippo.star.co.uk via smtpd (for mail.webnote.net [193.120.211.219]) with SMTP; 3 Jul 2002 15:43:50 UT 1239 # Received: from cp-its-ieg01.mail.saic.com by cpmx.mail.saic.com for me@jmason.org; Tue, 23 Jul 2002 14:09:10 -0700 1240 if (/^\S+ by \S+ (?:with|via|for|\()/) { return 0; } 1241 1242 # from senmail2.senate.gov with LMTP by senmail2 (3.0.2/sieved-3-0-build-942) for <example@vandinter.org>; Fri, 30 Jun 2006 10:58:41 -0400 1243 # from zimbramail.artsit.org.uk (unverified) by MAILSWEEP.birminghamartsit.org.uk (Clearswift SMTPRS 5.1.7) with ESMTP id <T78926b35f2c0a80003da8@MAILSWEEP.birminghamartsit.org.uk> for <discuss@lists.surbl.org>; Tue, 30 May 2006 15:56:15 +0100 1244 if (/^\S+ (?:(?:with|via|for) \S+|\(unverified\)) by\b/) { return 0; } 1245 1246 # from MjA3NDc4Mg (unknown) by ismtpd0001p1lon1.sendgrid.net (SG) with HTTP id aqHKNX2kSp-HiqspAa-uvw for <email@e.example.com>; Thu, 02 Apr 2020 07:53:55.516 +0000 (UTC) 1247 if (/^\S+ \(unknown\) by \S+ \(SG\) with \b/) { return 0; } 1248 1249 # from localhost (example.com [local]) by example.com (OpenSMTPD) with ESMTPA id 5db34e0d for <email@example.com>; Tue, 7 Apr 2020 01:38:29 -0600 (MDT) 1250 if (/^\S+ \(\S+ \[local\]\) by \S+ \(OpenSMTPD\) with \b/) { return 0; } 1251 1252 # from DL1GSPMX02 (dl1gspmx02.gamestop.com) by email.ebgames.com (LSMTP for Windows NT v1.1b) with SMTP id <21.000575A0@email.ebgames.com>; Tue, 12 Sep 2006 21:06:43 -0500 1253 if (/\(LSMTP for/) { return 0; } 1254 1255 # from ([127.0.0.1]) with MailEnable ESMTP; Wed, 10 Jul 2019 10:29:59 +0300 1256 if (/^\(\[${LOCALHOST}\]\) with MailEnable /) { return 0; } 1257 1258 # from facebook.com (RrlQsUbrndsQ6/zbJaSzSPcmy3GwqE5h6IukkE5GGBIJgonAFnoQE3L+9tv2TU3e 2401:db00:1110:50e8:face:0000:002f:0000) 1259 # by facebook.com with Thrift id 423753524b5011e9a83e248a0796a3b2-169bd530; Wed, 20 Mar 2019 13:39:29 -0700 1260 if (/^facebook\.com \([^\)]+\) by facebook\.com with Thrift id \S+$/) { return 0; } 1261 1262 # from 384836569573 named unknown by gmailapi.google.com with HTTPREST; Wed, 6 Mar 2019 03:39:24 -0500 1263 if (/^\S+ named \S+ by gmailapi\.google\.com with HTTPREST$/) { return 0; } 1264 1265 # from mail.payex.com id <B5b8f11e30004>; Wed, 05 Sep 2018 01:14:43 +0200 1266 if (/^\S+ id \S+$/) { return 0; } 1267 1268 # from [<4124973-137966-3089@be2.maropost.com>] ([<4124973-137966-3089@be2.maropost.com>] helo=maropost.com) by 643852-mailer2 (envelope-from 4124973-137966-3089@be2.maropost.com) 1269 # (Jetsend MTA 0.0.1 with ESMTP; Fri Sep 14 14:36:56 EDT 2018 1270 if (/^\[<.*? \(Jetsend/) { return 0; } 1271 1272 # if at this point we still haven't figured out the HELO string, see if we 1273 # can't just guess 1274 if (!$helo && /^(\S+)[^-A-Za-z0-9\.]/) { $helo = $1; } 1275 } 1276 1277# --------------------------------------------------------------------------- 1278 1279 elsif (s/^FROM //) { 1280 # simta: http://rsug.itd.umich.edu/software/simta/ 1281 # Note the ugly uppercase FROM/BY/ID 1282 # Received: FROM hackers.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.81]) 1283 # BY madman.mr.itd.umich.edu ID 434B508E.174A6.13932 ; 11 Oct 2005 01:41:34 -0400 1284 # Received: FROM [192.168.1.24] (s233-64-90-216.try.wideopenwest.com [64.233.216.90]) 1285 # BY hackers.mr.itd.umich.edu ID 434B5051.8CDE5.15436 ; 11 Oct 2005 01:40:33 -0400 1286 # Received: FROM helo (1.2.3.4 [1.2.3.4]) BY xxx.com (Rockliffe SMTPRA 10.3.0) 1287 # WITH SMTP ID <B0065361981@xxx.com> FOR <foo@bar.net>; Tue, 6 Nov 2018 07:41:26 +0200 1288 1289 if (/^(\S+) \((\S+) \[(${IP_ADDRESS})\]\) BY (\S+) (?:\([^\)]+\) WITH SMTP )?ID <?(\S+?)>?(?: FOR <[^>]+>)?$/ ) { 1290 $mta_looked_up_dns = 1; 1291 $helo = $1; $rdns = $2; $ip = $3; $by = $4; $id = $5; 1292 $rdns = '' if $rdns eq 'unverified'; 1293 goto enough; 1294 } 1295 } 1296 1297# --------------------------------------------------------------------------- 1298 1299 elsif (s/^\(from //) { 1300 # Norton AntiVirus Gateway 1301 # Received: (from localhost [24.180.47.240]) 1302 # by host.name (NAVGW 2.5.2.12) with SMTP id M2006060503484615455 1303 # for <user@domain.co.uk>; Mon, 05 Jun 2006 03:48:47 +0100 1304 if (/^(\S*) \[(${IP_ADDRESS})\]\) by (\S+) \(NAVGW .*?\) with /) { 1305 $helo = $1; $ip = $2; $by = $3; 1306 goto enough; 1307 } 1308 1309 # header produced by command line /usr/bin/sendmail -t -f username@example.com 1310 # Received: (from username@localhost) by home.example.com 1311 # (8.12.11/8.12.11/Submit) id iBADHRP6011034; Fri, 10 Dec 2004 13:17:27 GMT 1312 if (/^\S+\@localhost\) by \S+ /) { return 0; } 1313 1314 # Received: (from vashugins@juno.com) by m06.lax.untd.com (jqueuemail) id LRVB3JAJ; Fri, 02 Jun 2006 08:15:21 PDT 1315 if (/^[^\s\@]+\@[^)]+\) by \S+\(jqueuemail\) id [^\s;]+/) { return 0; } 1316 } 1317 1318# --------------------------------------------------------------------------- 1319 1320 # FALL-THROUGH: OK, at this point let's try some general patterns for things 1321 # we may not have already parsed out. 1322 if (!$ip && /\[(${IP_ADDRESS})\]/) { $ip = $1; } 1323 1324# --------------------------------------------------------------------------- 1325 1326 # We need to have a minimal amount of information to have a useful parse. 1327 # If we have the IP and the "by" name, move forward. If we don't, we'll 1328 # drop into the unparseable area. 1329 if ($ip && $by) { goto enough; } 1330 1331 # Ok, we can't handle this header, go ahead and return that. 1332 return; 1333 1334# --------------------------------------------------------------------------- 1335 1336enough: 1337 1338 # OK, line parsed (at least partially); now deal with the contents 1339 1340 # flag handovers we couldn't get an IP address from at all 1341 if ($ip eq '') { 1342 dbg("received-header: could not parse IP address from: $_"); 1343 } 1344 1345 # DISABLED: if we cut out localhost-to-localhost SMTP handovers, 1346 # we will give FPs on SPF checks -- since the SMTP "MAIL FROM" addr 1347 # will be recorded, but we won't have the relays handover recorded 1348 # for that SMTP transaction, so we wind up checking the wrong IP 1349 # for the addr. 1350 if (0) { 1351 if ($ip eq '127.0.0.1') { 1352 dbg("received-header: ignoring localhost handover"); 1353 return 0; # ignore localhost handovers 1354 } 1355 } 1356 1357 # Strip ending dot, Bug 7810 1358 $rdns =~ s/\.+\z//; 1359 1360 if ($rdns =~ /^unknown$/i || $rdns =~ /^\[/) { 1361 $rdns = ''; # some MTAs seem to do this 1362 } 1363 1364 $ip =~ s/^ipv6://i; # remove "IPv6:" prefix 1365 $ip =~ s/^\[//; $ip =~ s/\]\z//; 1366 1367 # IPv6 Scoped Address (RFC 4007, RFC 6874, RFC 3986 "unreserved" charset) 1368 $ip =~ s/%[A-Z0-9._~-]*\z//si; # scoped address? remove <zone_id> 1369 1370 # remove "::ffff:" prefix from IPv4-mapped-in-IPv6 addresses, 1371 # so we can treat them simply as IPv4 addresses 1372 # (only handles 'alternative form', not 'preferred form' - to be improved) 1373 $ip =~ s/^0*:0*:(?:0*:)*ffff:(\d+\.\d+\.\d+\.\d+)$/$1/i; 1374 1375 $by =~ s/\;$//; 1376 1377 # ensure invalid chars are stripped. Replace with '!' to flag their 1378 # presence, though. NOTE: this means "[1.2.3.4]" IP addr HELO 1379 # strings, which are legit by RFC-2821, look like "!1.2.3.4!". 1380 # still useful though. 1381 my $strip_chars = qr/[\s\000\#\[\]\(\)\<\>\|]/; 1382 $ip =~ s/$strip_chars/!/gs; 1383 $rdns =~ s/$strip_chars/!/gs; 1384 $helo =~ s/$strip_chars/!/gs; 1385 $by =~ s/$strip_chars/!/gs; 1386 $ident =~ s/$strip_chars/!/gs; 1387 if (defined $envfrom) { 1388 $envfrom =~ s/^\s*<*//gs; 1389 $envfrom =~ s/>*\s*$//gs; 1390 $envfrom =~ s/$strip_chars/!/gs; 1391 } 1392 1393 my $relay = { 1394 ip => $ip, 1395 by => $by, 1396 helo => $helo, 1397 id => $id, 1398 ident => $ident, 1399 envfrom => $envfrom, 1400 lc_by => (lc $by), 1401 lc_helo => (lc $helo), 1402 auth => $auth 1403 }; 1404 1405 if ($rdns eq '') { 1406 if ($mta_looked_up_dns) { 1407 # we know the MTA always does lookups, so this means the host 1408 # really has no rDNS (rather than that the MTA didn't bother 1409 # looking it up for us). 1410 $relay->{no_reverse_dns} = 1; 1411 $rdns = ''; 1412 } else { 1413 $relay->{rdns_not_in_headers} = 1; 1414 } 1415 } 1416 1417 $relay->{rdns} = $rdns; 1418 $relay->{lc_rdns} = lc $rdns; 1419 1420 $self->make_relay_as_string($relay); 1421 1422 my $is_private = ($ip =~ /${IP_PRIVATE}/o); 1423 $relay->{ip_private} = $is_private; 1424 1425 # add it to an internal array so Eval tests can use it 1426 return $relay; 1427} 1428 1429sub make_relay_as_string { 1430 my ($self, $relay) = @_; 1431 1432 # as-string rep. use spaces so things like Bayes can tokenize them easily. 1433 # NOTE: when tokenizing or matching, be sure to note that new 1434 # entries may be added to this string later. However, the *order* 1435 # of entries must be preserved, so that regexps that assume that 1436 # e.g. "ip" comes before "helo" will still work. 1437 # 1438 1439 # we could mark envfrom as "undef" if missing? dunno if needed? 1440 my $envfrom = $relay->{envfrom} || ''; 1441 my $asstr = "[ ip=$relay->{ip} rdns=$relay->{rdns} helo=$relay->{helo} by=$relay->{by} ident=$relay->{ident} envfrom=$envfrom intl=0 id=$relay->{id} auth=$relay->{auth} msa=0 ]"; 1442 dbg("received-header: parsed as $asstr"); 1443 $relay->{as_string} = $asstr; 1444} 1445 1446# restart the parse if we find a fetchmail marker or similar. 1447# spamcop does this, and it's a great idea ;) 1448sub found_pop_fetcher_sig { 1449 my ($self) = @_; 1450 if ($self->{allow_mailfetch_markers}) { 1451 dbg("received-header: found mail fetcher marker, restarting parse"); 1452 $self->{relays_trusted} = [ ]; 1453 $self->{relays_internal} = [ ]; 1454 $self->{relays_external} = [ ]; 1455 } else { 1456 dbg("received-header: found mail fetcher marker outside trusted area, ignored"); 1457 } 1458} 1459 1460# --------------------------------------------------------------------------- 1461 14621; 1463