diff --git a/plugins/stunnel b/plugins/stunnel new file mode 100644 index 0000000..535c544 --- /dev/null +++ b/plugins/stunnel @@ -0,0 +1,96 @@ +#!perl -w + +=head1 NAME + +stunnel - stunnel proxy protocol client ip helper. + +=head1 DESCRIPTION + +stunnel proxy protocol remote ip,port setting feature added for smtps. +reference : http://www.stunnel.org/static/stunnel.html +protocol spec : http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt + +config/plugins file example +stunnel proxy on +... + +=head1 CONFIGURATION + +=head2 proxy [ ON | OFF ] + +proxy protocol handler on/off + +=cut + +use strict; +use warnings; +use Qpsmtpd::Constants; + +my $proxy_enabled; +sub init { + my ($self, $qp, %args) = @_; + + return if ( uc $args{proxy} ne 'ON' ); + + $self->log(LOGINFO, "proxy protocol enabled"); + $proxy_enabled = 1; +} + +sub hook_unrecognized_command { + my ($self, $transaction, $cmd, @args) = @_; + + return OK if ( uc $cmd ne 'PROXY' ); + return OK if ( !defined $proxy_enabled ); + return DENY_DISCONNECT if ( $self->connection->remote_ip() ne '127.0.0.1' ); + return DENY_DISCONNECT if ( $self->connection->notes('proxy') ); + + # TCP4 192.168.41.227 10.27.11.106 50060 465 + if ( $args[0] =~ m/^(.*?) (.*?) (.*?) (.*?) (.*?)$/ ) { + my $protocol = $1; + my $remote_ip = $2; + my $local_ip = $3; + my $remote_port = $4; + my $local_port = $5; + $self->connection->remote_ip( $remote_ip ); + $self->connection->remote_port( $remote_port ); + $self->connection->remote_info( "[$remote_ip]"); + + $self->connection->notes('proxy', 'YES'); + $self->connection->notes('protocol', $protocol); + $self->connection->notes('remote_ip', $remote_ip); + $self->connection->notes('remote_port', $remote_port); + $self->connection->notes('local_ip', $local_ip); + $self->connection->notes('local_port', $local_port); + $self->log(LOGINFO, "stunnel : $remote_ip:$remote_port"); + + # DNS reverse + if ( $self->isa('Qpsmtpd::PollServer') ) { + eval { + use ParaDNS; + ParaDNS->new( + finished => sub { $self->continue_read() }, + callback => sub { $self->connection->remote_host($_[0]) }, + host => $remote_ip, + ); + + }; + } + else { + my $res = Net::DNS::Resolver->new( dnsrch => 0 ); + $res->tcp_timeout(3); + $res->udp_timeout(3); + my $query = $res->query( $remote_ip, 'PTR' ); + if ($query) { + foreach my $rr ($query->answer) { + next if $rr->type ne 'PTR'; + $self->connection->remote_host( $rr->ptrdname ); + } + } + } + } + else { + return DENY_DISCONNECT; + } + return DONE; +} +