The p0f plugin defaulted to binding to TCPLOCALIP, which doesn't work when the mail server is running behind a firewall with a private IP. If the local_ip option is set in the config file, it overrides TCPLOCALIP.
Added POD documentation for local_ip option and p0f general usage --- plugins/ident/p0f | 82 +++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 71 insertions(+), 11 deletions(-) diff --git a/plugins/ident/p0f b/plugins/ident/p0f index 06be0a3..4ad62fb 100644 --- a/plugins/ident/p0f +++ b/plugins/ident/p0f @@ -1,23 +1,80 @@ # -*- perl -*- -=pod +=head1 NAME -An Identification Plugin +p0f - A TCP Fingerprinting Identification Plugin - ./p0f -u qpsmtpd -d -q -Q /tmp/.p0f_socket 'dst port 25' -o /dev/null && \ - chown qpsmtpd /tmp/.p0f_socket +=head1 SYNOPSIS -and add +Use TCP fingerprint info (remote computer OS, network distance, etc) to +implement more sophisticated anti-spam policies. + +=head1 DESCRIPTION + +This p0f module inserts a 'p0f' note that other qpsmtpd plugins can inspect. +It includes the following information about the TCP fingerprint (link, +detail, distance, uptime, genre). Here's an example connection note: + + genre => FreeBSD + detail => 6.x (1) + uptime => 1390 + link => ethernet/modem + distance => 17 + +Which was parsed from this p0f fingerprint: + + 24.18.227.2:39435 - FreeBSD 6.x (1) (up: 1390 hrs) + -> 208.75.177.101:25 (distance 17, link: ethernet/modem) + +=head1 MOTIVATION + +This p0f plugin provides a way to make sophisticated policies for email +messages. For example, the vast majority of email connections to my server +from Windows computers are spam (>99%). But, I have a few clients that use +Exchange servers so I can't just block email from all Windows computers. + +Same goes for greylisting. Finance companies (AmEx, BoA, etc) just love to +send notices that they won't queue and retry. Either they deliver at that +instant or never. When I enable greylisting, I lose valid messages. Grrr. + +So, while I'm not willing to use greylisting, and I'm not willing to block +connections from Windows computers, I am quite willing to greylist all email +from Windows computers. + +=head1 CONFIGURATION + +Create a startup script for PF that creates a communication socket when your +server starts up. + + p0f -u qpsmtpd -d -q -Q /tmp/.p0f_socket 'dst port 25' -o /dev/null + chown qpsmtpd /tmp/.p0f_socket + +add an entry to config/plugins to enable p0f: ident/p0f /tmp/.p0f_socket -to config/plugins +=head2 local_ip + +Use the local_ip option to override the IP address of your mail server. This +is useful if your mail server has a private IP because it is running behind +a firewall. For example, my mail server has the IP 127.0.0.6, but the world +knows my mail server as 208.75.177.101. + +Example config/plugins entry with local_ip override: -it puts things into the 'p0f' connection notes so other plugins can do -things based on source OS. + ident/p0f /tmp/.p0f_socket local_ip 208.75.177.101 All code heavily based upon the p0fq.pl included with the p0f distribution. +=head1 ACKNOWLEDGEMENTS + +Heavily based upon the p0fq.pl included with the p0f distribution. + +=head1 AUTHORS + + Matt Simerson <msimer...@cpan.org> - 5/1/2010 + previous unnamed author + =cut use IO::Socket; @@ -26,21 +83,24 @@ use Net::IP; my $QUERY_MAGIC = 0x0defaced; sub register { - my ($self, $qp, $p0f_socket) = @_; + my ($self, $qp, $p0f_socket, %args) = @_; $p0f_socket =~ /(.*)/; # untaint $self->{_args}->{p0f_socket} = $1; + foreach (keys %args) { + $self->{_args}->{$_} = $args{$_}; + } } sub hook_connect { my ($self, $qp) = @_; my $p0f_socket = $self->{_args}->{p0f_socket}; - my $srcport = my $destport = $self->qp->connection->local_port; + my $local_ip = $self->{_args}{local_ip} || $self->qp->connection->local_ip; my $src = new Net::IP($self->qp->connection->remote_ip) or $self->log(LOGERROR, "p0f: " . Net::IP::Error()), return (DECLINED); - my $dst = new Net::IP($self->qp->connection->local_ip) + my $dst = new Net::IP($local_ip) or $self->log(LOGERROR, "p0f: " . NET::IP::Error()), return (DECLINED); my $query = pack("L L L N N S S", $QUERY_MAGIC, -- 1.7.0.6