~ubuntu-branches/ubuntu/utopic/spamassassin/utopic-proposed

« back to all changes in this revision

Viewing changes to lib/Mail/SpamAssassin/Plugin/DNSEval.pm

  • Committer: Bazaar Package Importer
  • Author(s): Noah Meyerhans
  • Date: 2010-01-26 22:53:12 UTC
  • mfrom: (1.1.13 upstream) (5.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100126225312-wkftb10idc1kz2aq
Tags: 3.3.0-1
* New upstream version.
* Switch to dpkg-source 3.0 (quilt) format

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
use strict;
25
25
use warnings;
26
26
use bytes;
 
27
use re 'taint';
27
28
 
28
29
use vars qw(@ISA);
29
30
@ISA = qw(Mail::SpamAssassin::Plugin);
70
71
 
71
72
sub ip_list_uniq_and_strip_private {
72
73
  my ($self, @origips) = @_;
73
 
  my @ips = ();
74
 
  my %seen = ();
 
74
  my @ips;
 
75
  my %seen;
75
76
  my $IP_PRIVATE = IP_PRIVATE;
76
77
  foreach my $ip (@origips) {
77
78
    next unless $ip;
119
120
    (my $tag = $1) =~ tr/A-Z/a-z/;
120
121
    $acctags{$tag} = -1;
121
122
  }
122
 
  my $accreditor_field = $pms->get('Accreditor');
123
 
  if (defined($accreditor_field)) {
 
123
  my $accreditor_field = $pms->get('Accreditor',undef);
 
124
  if (defined $accreditor_field) {
124
125
    my @accreditors = split(/,/, $accreditor_field);
125
126
    foreach my $accreditor (@accreditors) {
126
127
      my @terms = split(' ', $accreditor);
155
156
  my @fullips = map { $_->{ip} } @{$pms->{relays_untrusted}};
156
157
 
157
158
  # now, make a list of all the IPs in the external set, for use in
158
 
  # notfirsthop testing.  this will often be more IPs than found
 
159
  # notfirsthop testing.  This will often be more IPs than found
159
160
  # in @fullips.  It includes the IPs that are trusted, but
160
161
  # not in internal_networks.
161
162
  my @fullexternal = map {
167
168
  # X-Sender-Ip: could be worth using (very low occurance for me)
168
169
  # X-Sender: has a very low bang-for-buck for me
169
170
  my $IP_ADDRESS = IP_ADDRESS;
170
 
  my @originating = ();
171
 
  for my $header ('X-Yahoo-Post-IP', 'X-Originating-IP', 'X-Apparently-From', 'X-SenderIP') {
172
 
    my $str = $pms->get($header);
173
 
    next unless $str;
 
171
  my @originating;
 
172
  for my $header (@{$pms->{conf}->{originating_ip_headers}}) {
 
173
    my $str = $pms->get($header,undef);
 
174
    next unless defined $str && $str ne '';
174
175
    push (@originating, ($str =~ m/($IP_ADDRESS)/g));
175
176
  }
176
177
 
188
189
 
189
190
  my $trusted = $self->{main}->{conf}->{trusted_networks};
190
191
 
191
 
  if (scalar @ips + scalar @originating > 0) {
192
 
    # If name is foo-notfirsthop, check all addresses except for
193
 
    # the originating one.  Suitable for use with dialup lists, like the PDL.
194
 
    # note that if there's only 1 IP in the untrusted set, do NOT pop the
195
 
    # list, since it'd remove that one, and a legit user is supposed to
196
 
    # use their SMTP server (ie. have at least 1 more hop)!
197
 
    # If name is foo-lastexternal, check only the Received header just before
198
 
    # it enters our internal networks; we can trust it and it's the one that
199
 
    # passed mail between networks
200
 
    if ($set =~ /-(notfirsthop|lastexternal)$/)
201
 
    {
202
 
      # use the external IP set, instead of the trusted set; the user may have
203
 
      # specified some third-party relays as trusted.  Also, don't use
204
 
      # @originating; those headers are added by a phase of relaying through
205
 
      # a server like Hotmail, which is not going to be in dialup lists anyway.
206
 
      @ips = $self->ip_list_uniq_and_strip_private(@fullexternal);
207
 
      if ($1 eq "lastexternal") {
208
 
        @ips = (defined $ips[0]) ? ($ips[0]) : ();
209
 
      } else {
 
192
  # If name is foo-notfirsthop, check all addresses except for
 
193
  # the originating one.  Suitable for use with dialup lists, like the PDL.
 
194
  # note that if there's only 1 IP in the untrusted set, do NOT pop the
 
195
  # list, since it'd remove that one, and a legit user is supposed to
 
196
  # use their SMTP server (ie. have at least 1 more hop)!
 
197
  # If name is foo-lastexternal, check only the Received header just before
 
198
  # it enters our internal networks; we can trust it and it's the one that
 
199
  # passed mail between networks
 
200
  if ($set =~ /-(notfirsthop|lastexternal)$/)
 
201
  {
 
202
    # use the external IP set, instead of the trusted set; the user may have
 
203
    # specified some third-party relays as trusted.  Also, don't use
 
204
    # @originating; those headers are added by a phase of relaying through
 
205
    # a server like Hotmail, which is not going to be in dialup lists anyway.
 
206
    @ips = $self->ip_list_uniq_and_strip_private(@fullexternal);
 
207
    if ($1 eq "lastexternal") {
 
208
      @ips = (defined $ips[0]) ? ($ips[0]) : ();
 
209
    } else {
210
210
        pop @ips if (scalar @ips > 1);
211
 
      }
212
 
    }
213
 
    # If name is foo-firsttrusted, check only the Received header just
214
 
    # after it enters our trusted networks; that's the only one we can
215
 
    # trust the IP address from (since our relay added that header).
216
 
    # And if name is foo-untrusted, check any untrusted IP address.
217
 
    elsif ($set =~ /-(first|un)trusted$/)
218
 
    {
219
 
      my @tips = ();
220
 
      foreach my $ip (@originating) {
221
 
        if ($ip && !$trusted->contains_ip($ip)) {
222
 
          push(@tips, $ip);
223
 
        }
224
 
      }
225
 
      @ips = $self->ip_list_uniq_and_strip_private (@ips, @tips);
226
 
      if ($1 eq "first") {
227
 
        @ips = (defined $ips[0]) ? ($ips[0]) : ();
228
 
      } else {
229
 
        shift @ips;
230
 
      }
231
 
    }
232
 
    else
233
 
    {
234
 
      my @tips = ();
235
 
      foreach my $ip (@originating) {
236
 
        if ($ip && !$trusted->contains_ip($ip)) {
237
 
          push(@tips, $ip);
238
 
        }
239
 
      }
240
 
      # add originating IPs as untrusted IPs (if they are untrusted)
241
 
      @ips = reverse $self->ip_list_uniq_and_strip_private (@ips, @tips);
242
 
 
243
 
      # How many IPs max you check in the received lines
244
 
      my $checklast=$self->{main}->{conf}->{num_check_received};
245
 
 
246
 
      if (scalar @ips > $checklast) {
247
 
        splice (@ips, $checklast);      # remove all others
248
 
      }
249
 
    }
250
 
  }
 
211
    }
 
212
  }
 
213
  # If name is foo-firsttrusted, check only the Received header just
 
214
  # after it enters our trusted networks; that's the only one we can
 
215
  # trust the IP address from (since our relay added that header).
 
216
  # And if name is foo-untrusted, check any untrusted IP address.
 
217
  elsif ($set =~ /-(first|un)trusted$/)
 
218
  {
 
219
    my @tips;
 
220
    foreach my $ip (@originating) {
 
221
      if ($ip && !$trusted->contains_ip($ip)) {
 
222
        push(@tips, $ip);
 
223
      }
 
224
    }
 
225
    @ips = $self->ip_list_uniq_and_strip_private (@ips, @tips);
 
226
    if ($1 eq "first") {
 
227
      @ips = (defined $ips[0]) ? ($ips[0]) : ();
 
228
    } else {
 
229
      shift @ips;
 
230
    }
 
231
  }
 
232
  else
 
233
  {
 
234
    my @tips;
 
235
    foreach my $ip (@originating) {
 
236
      if ($ip && !$trusted->contains_ip($ip)) {
 
237
        push(@tips, $ip);
 
238
      }
 
239
    }
 
240
 
 
241
    # add originating IPs as untrusted IPs (if they are untrusted)
 
242
    @ips = reverse $self->ip_list_uniq_and_strip_private (@ips, @tips);
 
243
  }
 
244
 
 
245
  # How many IPs max you check in the received lines
 
246
  my $checklast=$self->{main}->{conf}->{num_check_received};
 
247
 
 
248
  if (scalar @ips > $checklast) {
 
249
    splice (@ips, $checklast);  # remove all others
 
250
  }
 
251
 
 
252
  my $tflags = $pms->{conf}->{tflags}->{$rule};
 
253
 
 
254
  # Trusted relays should only be checked against nice rules (dnswls)
 
255
  if (defined $tflags && $tflags !~ /\bnice\b/) {
 
256
    foreach my $ip (@ips) {
 
257
      last if !$trusted->contains_ip($ip);
 
258
      shift @ips;  # remove trusted hosts from beginning
 
259
    }
 
260
  }
 
261
 
 
262
  unless (scalar @ips > 0) {
 
263
    dbg("dns: no untrusted IPs to check");
 
264
    return 0;
 
265
  }
 
266
 
251
267
  dbg("dns: only inspecting the following IPs: ".join(", ", @ips));
252
268
 
253
269
  eval {
298
314
# this only checks the address host name and not the domain name because
299
315
# using the domain name had much worse results for dsn.rfc-ignorant.org
300
316
sub check_rbl_envfrom {
301
 
  _check_rbl_addresses(@_, $_[1]->get('EnvelopeFrom:addr'));
 
317
  _check_rbl_addresses(@_, $_[1]->get('EnvelopeFrom:addr',undef));
302
318
}
303
319
 
304
320
sub _check_rbl_addresses {
309
325
 
310
326
  my %hosts;
311
327
  for my $address (@addresses) {
312
 
    if ($address =~ m/\@(\S+\.\S+)/) {
 
328
    if (defined $address && $address =~ m/ \@ ( [^\@\s]+ \. [^\@\s]+ )/x) {
313
329
      $hosts{lc($1)} = 1;
314
330
    }
315
331
  }
333
349
  my ($self, $pms, $rule) = @_;
334
350
 
335
351
  my $host;
336
 
  for my $from ($pms->get('EnvelopeFrom:addr')) {
 
352
  for my $from ($pms->get('EnvelopeFrom:addr',undef)) {
337
353
    next unless defined $from;
338
354
 
339
355
    $from =~ tr/././s;          # bug 3366
340
 
    if ($from =~ /\@(\S+\.\S+)/) {
 
356
    if ($from =~ m/ \@ ( [^\@\s]+ \. [^\@\s]+ )/x ) {
341
357
      $host = lc($1);
342
358
      last;
343
359
    }