#!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; }