Quispiam

power computing

So yesterday I get an email saying “Hey, this person from this company is trying to send me and email and they keep getting bounces…”  and a quick grep of the maillog revealed:

May 19 11:02:24 barweb1 postfix/smtpd[30761]: NOQUEUE: reject: RCPT from
 mx0a-000e6001.pphosted.com[67.231.144.81]: 450 Server configuration 
 problem; from=; to= proto=ESMTP helo=

No worries, apart from the reject this looks OK, but I wonder why they were rejected ? I take a peek at the lines before this one

May 19 11:02:24 mailserver postfix/spawn[30752]: warning: command 
 /usr/bin/perl exit status 255
May 19 11:02:24 mailserver postfix/smtpd[30761]: warning: premature end-of-input on 
 private/spf while reading input attribute name
May 19 11:02:24 barweb1 postfix/smtpd[30761]: warning: problem talking to server 
 private/spf: Success

Ahh crap, this means there is an error in the spf perl process, I didnt write this and have a limited understanding of the code, hope its easy to find the problem I think to myself.

Running the command by hand and feeding it the required data yielded the following:

Bad arg length for Socket::unpack_sockaddr_in, length is 4096, should be 16 at 
/usr/lib/perl5/i386-linux/Socket.pm line 383.

What the hell does that mean ? I started tracking it down through the perl process postfix-policyd-spf-perl.pl ( that can be found at https://launchpad.net/postfix-policyd-spf-perl/ ) and eventually worked out that it was somewhere in the Mail::SPF module. So then I whip out my trusty CPAN and install Mail::SPF assuming the elderly unit is in need of a module update. This does nothing and the problem still exists. Ok, fine, now its time to get dirty and write a script, may be that will help narrow down the issue

use Mail::SPF;
use Data::Dumper;
my $spf_server  = Mail::SPF::Server->new();
$request = eval {
    Mail::SPF::Request->new(
        scope      => 'mfrom',
        identity   => 'some.user@pearson.com',
        ip_address => '67.231.144.81',
        helo_identity   => 'mx0b-000e6001.pphosted.com'
    );
};
$result = $spf_server->process($request);
print "$result";

Same error, as expected, but now I can trace it through Mail::SPF::Server->process routine. This leads me to the Net::DNS::Resolver module and once again I turn to CPAN to update Net::DNS. But same problem, it looks like its not these modules.

Back for another dirty test script to help narrow the problem even further.

use Net::DNS::Resolver;
use Data::Dumper;
$res = Net::DNS::Resolver->new(
   debug => 1
);
$packet = $res->send('spf.pearson.com', 'A');
print Dumper($packet);

Error still exists, but now I am sure the send routine of the Net::DNS::Resolver module can help point the way. I eventually tracked the problem down to Net::DNS::Resolver::Base.pm and the line which updates the answerfrom property

$buf = read_tcp($sock, $len, $self->{'debug'});
$self->answerfrom($sock->peerhost);

Looking at the answerfrom routine tells me nothing and didn’t look like it would be buggy, so I look at the peerhost routine in IO::Socket.pm

sub peername {
    @_ == 1 or croak 'usage: $sock->peername()';
    my($sock) = @_;
    ${*$sock}{'io_socket_peername'} ||= getpeername($sock);
}

This is all well beyond my skills at this stage as it seems that getpeername is inbuilt to Perl, so I thinks to myself “update Perl”. But as alluded to before this machine is elderly and has some pretty legacy perl code running on it, I dont want to jump up to the latest and greatest Perl. I did update Perl to 5.8.9 from v5.8.8, but alas that did nothing. I am beginning to suspect we probably have the problem on this machine because it is a little long on the tooth and running some old kernel and the c header files are out of date. We have a couple of XEN virtuals around here that I can verify this on. I log into one and test Perl is the same, yep 5.8.8 and the test code runs fine ! Bugger it.

It is advisable to update this old unit, but right now that is impossible, so I hack around the error by placing the following code, highlighted, in Net::DNS::Resolver::Base.pm

$buf = read_tcp($sock, $len, $self->{'debug'});
eval {
    $self->answerfrom($sock->peerhost);
};
if($@ && $self->{'debug'}) {
    print "An error with the socket probably: 
           Bad arg length for Socket::unpack_sockaddr_in, length is 4096,
           should be 16 skipping n";
}
print ';; received ', length($buf), " bytesn"
    if $self->{'debug'};

Now when I run my test-spf on the geriatric unit I get the right response

 user@host:~# perl test-spf.pl
 pass (Mechanism 'include:spf.pearson.com' matched)

So, we all agree this is far from ideal this it does get us out of hot water for the time being.

Matt.

Share