[svn:qpsmtpd] r657 - in branches/0.3x: . lib/Qpsmtpd plugins
[email protected] Sun, 27 Aug 2006 16:17:38 -0700 (PDT)
| Newsgroups | perl.cvs.qpsmtpd |
|---|---|
| Message-ID | <[email protected]> |
Author: ask
Date: Sun Aug 27 16:17:33 2006
New Revision: 657
Modified:
branches/0.3x/ (props changed)
branches/0.3x/Changes
branches/0.3x/lib/Qpsmtpd/Constants.pm
branches/0.3x/plugins/check_relay
branches/0.3x/plugins/require_resolvable_fromhost
branches/0.3x/qpsmtpd-forkserver
Log:
r4175@embla: ask | 2006-08-28 01:17:10 +0200
Experimental IPv6 support (forkserver only). (Mike Williams)
Modified: branches/0.3x/Changes
==============================================================================
--- branches/0.3x/Changes (original)
+++ branches/0.3x/Changes Sun Aug 27 16:17:33 2006
@@ -1,5 +1,7 @@
0.33
+ Experimental IPv6 support (forkserver only). (Mike Williams)
+
Support "module" plugins ("My::Plugin" in the config/plugins file)
Enhance the spamassassin plugin to support connecting to a remote
Modified: branches/0.3x/lib/Qpsmtpd/Constants.pm
==============================================================================
--- branches/0.3x/lib/Qpsmtpd/Constants.pm (original)
+++ branches/0.3x/lib/Qpsmtpd/Constants.pm Sun Aug 27 16:17:33 2006
@@ -27,6 +27,24 @@
DONE => 910,
);
+my $has_ipv6;
+
+if (
+ eval {require Socket6;} &&
+ # INET6 prior to 2.01 will not work; sorry.
+ eval {require IO::Socket::INET6; IO::Socket::INET6->VERSION("2.00");}
+ ) {
+ import Socket6;
+ $has_ipv6=1;
+}
+else {
+ $has_ipv6=0;
+}
+
+sub has_ipv6 {
+ return $has_ipv6;
+}
+
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = (keys(%return_codes), keys(%log_levels), "return_code", "log_level");
Modified: branches/0.3x/plugins/check_relay
==============================================================================
--- branches/0.3x/plugins/check_relay (original)
+++ branches/0.3x/plugins/check_relay Sun Aug 27 16:17:33 2006
@@ -19,7 +19,7 @@
$connection->relay_client(1);
last;
}
- $client_ip =~ s/\d+\.?$//; # strip off another 8 bits
+ $client_ip =~ s/(\d|\w|::)+(:|\.)?$//; # strip off another 8 bits
}
return (DECLINED);
Modified: branches/0.3x/plugins/require_resolvable_fromhost
==============================================================================
--- branches/0.3x/plugins/require_resolvable_fromhost (original)
+++ branches/0.3x/plugins/require_resolvable_fromhost Sun Aug 27 16:17:33 2006
@@ -3,6 +3,7 @@
use Socket;
my %invalid = ();
+my $has_ipv6 = Qpsmtpd::Constants::has_ipv6;
sub hook_mail {
my ($self, $transaction, $sender, %param) = @_;
@@ -38,6 +39,7 @@
sub check_dns {
my ($self, $host) = @_;
+ my @host_answers;
# for stuff where we can't even parse a hostname out of the address
return 0 unless $host;
@@ -53,15 +55,24 @@
}
my $query = $res->search($host);
if ($query) {
- foreach my $rr ($query->answer) {
- if ($rr->type eq "A") {
- return is_valid($rr->address);
- }
- elsif ($rr->type eq "MX") {
- return mx_valid($self, $rr->exchange, $host);
+ foreach my $rrA ($query->answer) {
+ push(@host_answers, $rrA);
+ }
+ }
+ if ($has_ipv6) {
+ my $query = $res->search($host, 'AAAA');
+ if ($query) {
+ foreach my $rrAAAA ($query->answer) {
+ push(@host_answers, $rrAAAA);
}
}
}
+ if (@host_answers) {
+ foreach my $rr (@host_answers) {
+ return is_valid($rr->address) if $rr->type eq "A" or $rr->type eq "AAAA";
+ return mx_valid($self, $rr->exchange, $host) if $rr->type eq "MX";
+ }
+ }
else {
$self->log(LOGWARN, "$$ query for $host failed: ", $res->errorstring)
unless $res->errorstring eq "NXDOMAIN";
@@ -88,10 +99,24 @@
sub mx_valid {
my ($self, $name, $host) = @_;
my $res = new Net::DNS::Resolver;
- my $query = $res->search($name);
+ my @mx_answers;
+ my $query = $res->search($name, 'A');
if ($query) {
- foreach my $rr ($query->answer) {
- next unless $rr->type eq "A";
+ foreach my $rrA ($query->answer) {
+ push(@mx_answers, $rrA);
+ }
+ }
+ if ($has_ipv6) {
+ my $query = $res->search($name, 'AAAA');
+ if ($query) {
+ foreach my $rrAAAA ($query->answer) {
+ push(@mx_answers, $rrAAAA);
+ }
+ }
+ }
+ if (@mx_answers) {
+ foreach my $rr (@mx_answers) {
+ next unless $rr->type eq "A" or $rr->type eq "AAAA";
return is_valid($rr->address);
}
}
Modified: branches/0.3x/qpsmtpd-forkserver
==============================================================================
--- branches/0.3x/qpsmtpd-forkserver (original)
+++ branches/0.3x/qpsmtpd-forkserver Sun Aug 27 16:17:33 2006
@@ -17,6 +17,12 @@
use strict;
$| = 1;
+my $has_ipv6 = Qpsmtpd::Constants::has_ipv6;
+
+if ($has_ipv6) {
+ use Socket6;
+}
+
# Configuration
my $MAXCONN = 15; # max simultaneous connections
my @PORT; # port number(s)
@@ -54,12 +60,17 @@
) || &usage;
# detaint the commandline
-@LOCALADDR = ( '0.0.0.0' ) if !@LOCALADDR;
+if ($has_ipv6) {
+ @LOCALADDR = ( '[::]' ) if !@LOCALADDR;
+}
+else {
+ @LOCALADDR = ( '0.0.0.0' ) if !@LOCALADDR;
+}
@PORT = ( 2525 ) if !@PORT;
my @LISTENADDR;
for (0..$#LOCALADDR) {
- if ($LOCALADDR[$_] =~ /^([\d\w\-.]+)(?::(\d+))?$/) {
+ if ($LOCALADDR[$_] =~ /^(\[.*\]|[\d\w\-.]+)(?::(\d+))?$/) {
if ( defined $2 ) {
push @LISTENADDR, { 'addr' => $1, 'port' => $2 };
} else {
@@ -106,16 +117,24 @@
$SIG{TERM} = \&HUNTSMAN;
my $select = new IO::Select;
+my $server;
# establish SERVER socket(s), bind and listen.
for my $listen_addr (@LISTENADDR) {
- my $server = IO::Socket::INET->new(LocalPort => $listen_addr->{'port'},
+ my @Socket_opts = (LocalPort => $listen_addr->{'port'},
LocalAddr => $listen_addr->{'addr'},
Proto => 'tcp',
Reuse => 1,
Blocking => 0,
- Listen => SOMAXCONN )
- or die "Creating TCP socket $listen_addr->{'addr'}:$listen_addr->{'port'}: $!\n";
+ Listen => SOMAXCONN);
+ if ($has_ipv6) {
+ $server = IO::Socket::INET6->new(@Socket_opts)
+ or die "Creating TCP socket $listen_addr->{'addr'}:$listen_addr->{'port'}: $!\n";
+ }
+ else {
+ $server = IO::Socket::INET->new(@Socket_opts)
+ or die "Creating TCP socket $listen_addr->{'addr'}:$listen_addr->{'port'}: $!\n";
+ }
IO::Handle::blocking($server, 0);
$select->add($server);
}
@@ -208,14 +227,19 @@
next;
}
IO::Handle::blocking($client, 1);
- my ($port, $iaddr) = sockaddr_in($hisaddr);
+ my ($port, $iaddr) = ($server->sockdomain == AF_INET) ? (sockaddr_in($hisaddr)) : (sockaddr_in6($hisaddr));
my $localsockaddr = getsockname($client);
- my ($lport, $laddr) = sockaddr_in($localsockaddr);
+ my ($lport, $laddr) = ($server->sockdomain == AF_INET) ? (sockaddr_in($localsockaddr)) : (sockaddr_in6($localsockaddr));
+ my $nto_iaddr = ($server->sockdomain == AF_INET) ? (inet_ntoa($iaddr)) : (inet_ntop(AF_INET6, $iaddr));
+ my $ton_iaddr = ($server->sockdomain == AF_INET) ? (inet_aton($iaddr)) : (inet_pton(AF_INET6, $iaddr));
+ my $nto_laddr = ($server->sockdomain == AF_INET) ? (inet_ntoa($laddr)) : (inet_ntop(AF_INET6, $laddr));
+ $nto_iaddr =~ s/::ffff://;
+ $nto_laddr =~ s/::ffff://;
my ($rc, @msg) = $qpsmtpd->run_hooks("pre-connection",
- remote_ip => inet_ntoa($iaddr),
+ remote_ip => $nto_iaddr,
remote_port => $port,
- local_ip => inet_ntoa($laddr),
+ local_ip => $nto_laddr,
local_port => $lport,
max_conn_ip => $MAXCONNIP,
child_addrs => [values %childstatus],
@@ -259,11 +283,18 @@
::log(LOGINFO, "Connection Timed Out");
exit; };
- $ENV{TCPLOCALIP} = inet_ntoa($laddr);
+ $ENV{TCPLOCALIP} = $nto_laddr;
# my ($port, $iaddr) = sockaddr_in($hisaddr);
- $ENV{TCPREMOTEIP} = inet_ntoa($iaddr);
- $ENV{TCPREMOTEHOST} = gethostbyaddr($iaddr, AF_INET) || "Unknown";
-
+ $ENV{TCPREMOTEIP} = $nto_iaddr;
+
+ if ($server->sockdomain == AF_INET) {
+ $ENV{TCPREMOTEHOST} = gethostbyaddr($iaddr, AF_INET) || "Unknown";
+ }
+ else {
+ my ($family, $socktype, $proto, $saddr, $canonname, @res) = getaddrinfo($iaddr, $port, AF_UNSPEC);
+ $ENV{TCPREMOTEHOST} = $canonname || "Unknown";
+ }
+
# don't do this!
#$0 = "qpsmtpd-forkserver: $ENV{TCPREMOTEIP} / $ENV{TCPREMOTEHOST}";