develooper Front page | perl.cvs.qpsmtpd | Postings from April 2007

[svn:qpsmtpd] r732 - trunk/plugins/async

From:
msergeant
Date:
April 9, 2007 15:19
Subject:
[svn:qpsmtpd] r732 - trunk/plugins/async
Message ID:
20070409221940.0D418CB9B8@x12.develooper.com
Author: msergeant
Date: Mon Apr  9 15:19:40 2007
New Revision: 732

Added:
   trunk/plugins/async/require_resolvable_fromhost

Log:
Ported to async


Added: trunk/plugins/async/require_resolvable_fromhost
==============================================================================
--- (empty file)
+++ trunk/plugins/async/require_resolvable_fromhost	Mon Apr  9 15:19:40 2007
@@ -0,0 +1,135 @@
+#!/usr/bin/perl -w
+
+use Qpsmtpd::DSN;
+use ParaDNS;
+use Socket;
+
+my %invalid  = ();
+my $has_ipv6 = Qpsmtpd::Constants::has_ipv6;
+
+sub register {
+    my ( $self, $qp ) = @_;
+    
+    foreach my $i ( $self->qp->config("invalid_resolvable_fromhost") ) {
+        $i =~ s/^\s*//;
+        $i =~ s/\s*$//;
+        if ( $i =~ m#^((\d{1,3}\.){3}\d{1,3})/(\d\d?)# ) {
+            $invalid{$1} = $3;
+        }
+    }
+
+    $self->register_hook( mail => 'hook_mail_start' );
+    $self->register_hook( mail => 'hook_mail_done' );
+}
+
+sub hook_mail_start {
+    my ( $self, $transaction, $sender ) = @_;
+    
+    return DECLINED
+      if ( $self->qp->connection->notes('whitelistclient') );
+
+    if ( $sender ne "<>" ) {
+        
+        unless ( $sender->host ) {
+            # default of addr_bad_from_system is DENY, we use DENYSOFT here to
+            # get the same behaviour as without Qpsmtpd::DSN...
+            return Qpsmtpd::DSN->addr_bad_from_system( DENYSOFT,
+                "FQDN required in the envelope sender" );
+        }
+        
+        $self->check_dns( $sender->host );
+        return YIELD;
+    }
+    
+    return DECLINED;
+}
+
+sub hook_mail_done {
+    my ( $self, $transaction, $sender ) = @_;
+    
+    return DECLINED
+      if ( $self->qp->connection->notes('whitelistclient') );
+
+    if (!$transaction->notes('resolvable_fromhost')) {
+        # default of temp_resolver_failed is DENYSOFT
+        return Qpsmtpd::DSN->temp_resolver_failed(
+            "Could not resolve " . $sender->host );
+    }
+    return DECLINED;
+}
+
+sub check_dns {
+    my ( $self, $host ) = @_;
+    my @host_answers;
+
+    return if $host =~ m/^\[(\d{1,3}\.){3}\d{1,3}\]$/;
+
+    my $qp = $self->qp;
+    
+    my $a_records = [];
+    my $num_queries = $has_ipv6 ? 2 : 1;
+    ParaDNS->new(
+        callback  => sub {
+            my $mx = shift;
+            return if $mx =~ /^[A-Z]+$/; # error
+            my $addr = $mx->[0];
+            $num_queries++;
+            ParaDNS->new(
+                callback => sub { push @$a_records, $_[0] if $_[0] !~ /^[A-Z]+$/; },
+                finished => sub { $num_queries--; $self->finish_up($qp, $a_records) unless $num_queries; },
+                host     => $addr,
+                type     => 'A',
+            );
+            if ($has_ipv6) {
+                $num_queries++;
+                ParaDNS->new(
+                    callback => sub { push @$a_records, $_[0] if $_[0] !~ /^[A-Z]+$/; },
+                    finished => sub { $num_queries--; $self->finish_up($qp, $a_records) unless $num_queries; },
+                    host     => $addr,
+                    type     => 'AAAA',
+                );
+            }
+        },
+        host      => $host,
+        type      => 'MX',
+    );
+    ParaDNS->new(
+        callback  => sub { push @$a_records, $_[0] if $_[0] !~ /^[A-Z]+$/; },
+        finished  => sub { $num_queries--; $self->finish_up($qp, $a_records) unless $num_queries },
+        host      => $host,
+        type      => 'A',
+    );
+    ParaDNS->new(
+        callback  => sub { push @$a_records, $_[0] if $_[0] !~ /^[A-Z]+$/; },
+        finished  => sub { $num_queries--; $self->finish_up($qp, $a_records) unless $num_queries },
+        host      => $host,
+        type      => 'AAAA',
+    ) if $has_ipv6;
+}
+
+sub finish_up {
+    my ($self, $qp, $a_records) = @_;
+    
+    foreach my $addr (@$a_records) {
+        if (is_valid($addr)) {
+            $qp->transaction->notes('resolvable_fromhost', 1);
+            last;
+        }
+    }
+    
+    $qp->run_continuation;
+}
+
+sub is_valid {
+    my $ip = shift;
+    my ( $net, $mask );
+    foreach $net ( keys %invalid ) {
+        $mask = $invalid{$net};
+        $mask = pack "B32", "1" x ($mask) . "0" x ( 32 - $mask );
+        return 0
+          if join( ".", unpack( "C4", inet_aton($ip) & $mask ) ) eq $net;
+    }
+    return 1;
+}
+
+# vim: ts=4 sw=4 expandtab syn=perl



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About