NAME

Mail::SPF::Iterator - iterative SPF lookup

SYNOPSIS

use Net::DNS;
use Mail::SPF::Iterator;
my $spf = Mail::SPF::Iterator->new(
	$ip,       # IP4|IP6 of client
	$mailfrom, # from MAIL FROM:
	$helo,     # from HELO|EHLO
	$myname,   # optional: my hostname
);

# could be other resolvers too
my $resolver = Net::DNS::Resolver->new;

my ($result,@ans) = $spf->next; # initial query
while ( ! $status ) {
	my ($cbid,@query) = @ans;
	die "no queries" if ! @query;
	for my $q (@query) {
		# resolve query
		my $answer = $resolver->send( $q );
		($result,@ans) = $spf->next( $cbid,$answer
			? $answer                          # valid answer
			: [ $q, $resolver->errorstring ]   # DNS problem
		);
		last if $result; # got final result
		last if @ans;    # got more DNS queries
	}
}

# $result = Fail|Pass|...
# $ans[0] = comment for Received-SPF
# $ans[1] = problem for Received-SPF on Fail

DESCRIPTION

This module provides an iterative resolving of SPF records. Contrary to Mail::SPF, which does blocking DNS lookups, this module just returns the DNS queries and later expects the responses.

Lookup of the DNS records will be done outside of the module and can be done in a event driven way.

METHODS

new( IP, MAILFROM, HELO, [ MYNAME ] )

Construct a new Mail::SPF::Iterator object, which maintains the state between the steps of the iteration. For each new SPF check a new object has to be created.

IP is the IP if the client as string (IP4 or IP6).

MAILFROM is the user@domain part from the MAIL FROM handshake, e.g. '<','>' and any parameters removed. If only '<>' was given (like in bounces) the value is empty.

HELO is the string send within the HELO|EHLO dialog which should be a domain according to the RFC but often is not.

MYNAME is the name of the local host. It's only used if required by macros inside the SPF record.

Returns the new object.

next([ CBID, ANSWER ])

next will be initially called with no arguments to get initial DNS queries and then will be called with the DNS answers.

ANSWER is either a DNS packet with the response to a former query or [ QUERY, REASON ] on failures, where QUERY is the DNS packet containing the failed query and REASON the reason, why the query failed (like TIMEOUT).

CBID is the id for the query returned from the last call to next. It is given to control, if the answer is for the current query.

If a final result was achieved it will return ( RESULT, COMMENT, PROBLEM ). RESULT is the result, e.g. "Fail", "Pass",.... COMMENT is the comment for the Received-SPF header. PROBLEM is the problem for this header in the case of a failure (Fail, *Error)

EXPORTED SYMBOLS

For convienience the constants SPF_TempError, SPF_PermError, SPF_Pass, SPF_Fail, SPF_SoftFail, SPF_Neutral, SPF_None are exported, which have the values "TempError", "PermError" ...

BUGS

The module currently needs to have the A|AAAA records in the additional data of the DNS reply when doing a MX lookup. This will usually done by recursiv resolvers.

Apart from that it passes the SPF test suite from opensf.org.

AUTHOR

Steffen Ullrich <sullr@cpan.org>

COPYRIGHT

Copyright by Steffen Ullrich.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.