# -*- perl -*- =pod An Identification Plugin ./p0f -u qpsmtpd -d -q -Q /tmp/.p0f_socket 'dst port 25' -o /dev/null && \ chown qpsmtpd /tmp/.p0f_socket and add ident/p0f /tmp/.p0f_socket to config/plugins it puts things into the 'p0f' connection notes so other plugins can do things based on source OS. All code heavily based upon the p0fq.pl included with the p0f distribution. =cut use IO::Socket; use Net::IP; my $QUERY_MAGIC = 0x0defaced; sub register { my ($self, $qp, $p0f_socket) = @_; $p0f_socket =~ /(.*)/; # untaint $self->{_args}->{p0f_socket} = $1; } sub hook_connect { my($self, $qp) = @_; my $p0f_socket = $self->{_args}->{p0f_socket}; my $srcport = my $destport = $self->qp->connection->local_port; 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) or $self->log(LOGERROR, "p0f: ".NET::IP::Error()), return (DECLINED); my $query = pack("L L L N N S S", $QUERY_MAGIC, 1, rand ^ 42 ^ time, $src->intip(), $dst->intip(), $self->qp->connection->remote_port, $self->qp->connection->local_port); # Open the connection to p0f socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or $self->log(LOGERROR, "p0f: socket: $!"), return (DECLINED); connect(SOCK, sockaddr_un($p0f_socket)) or $self->log(LOGERROR, "p0f: connect: $!"), return (DECLINED); defined syswrite SOCK, $query or $self->log(LOGERROR, "p0f: write: $!"), close SOCK, return (DECLINED); my $response; defined sysread SOCK, $response, 1024 or $self->log(LOGERROR, "p0f: read: $!"), close SOCK, return (DECLINED); close SOCK; # Extract the response from p0f my ($magic, $id, $type, $genre, $detail, $dist, $link, $tos, $fw, $nat, $real, $score, $mflags, $uptime) = unpack ("L L C Z20 Z40 c Z30 Z30 C C C s S N", $response); if ($magic != $QUERY_MAGIC) { $self->log(LOGERROR, "p0f: Bad response magic."); return (DECLINED); } if ($type == 1) { $self->log(LOGERROR, "p0f: P0f did not honor our query"); return (DECLINED); } if ($type == 2) { $self->log(LOGWARN, "p0f: This connection is no longer in the cache"); return (DECLINED); } my $p0f = { genre => $genre, detail => $detail, distance => $dist, link => $link, uptime => $uptime, }; $self->qp->connection->notes('p0f', $p0f); $self->log(LOGINFO, "Results: ".$p0f->{genre}." (".$p0f->{detail}.")"); $self->log(LOGERROR,"error: $@") if $@; return DECLINED; }