r4175@embla: ask | 2006-08-28 01:17:10 +0200
Experimental IPv6 support (forkserver only). (Mike Williams) git-svn-id: https://svn.perl.org/qpsmtpd/branches/0.3x@657 958fd67b-6ff1-0310-b445-bb7760255be9
This commit is contained in:
parent
52f38f9459
commit
6ef0bf27c7
2
Changes
2
Changes
@ -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
|
||||
|
@ -27,6 +27,24 @@ my %return_codes = (
|
||||
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");
|
||||
|
@ -19,7 +19,7 @@ sub hook_connect {
|
||||
$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);
|
||||
|
@ -3,6 +3,7 @@ use Net::DNS qw(mx);
|
||||
use Socket;
|
||||
|
||||
my %invalid = ();
|
||||
my $has_ipv6 = Qpsmtpd::Constants::has_ipv6;
|
||||
|
||||
sub hook_mail {
|
||||
my ($self, $transaction, $sender, %param) = @_;
|
||||
@ -38,6 +39,7 @@ sub hook_mail {
|
||||
|
||||
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 @@ sub check_dns {
|
||||
}
|
||||
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 is_valid {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,12 @@ use POSIX qw(:sys_wait_h :errno_h :signal_h);
|
||||
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 @@ GetOptions('h|help' => \&usage,
|
||||
) || &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{INT} = \&HUNTSMAN;
|
||||
$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 @@ while (1) {
|
||||
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 @@ while (1) {
|
||||
::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}";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user