Alternate bookkeeping proposal (MVP) [was: design specifics --- the config label]
Raymond S Brand <[email protected]> Wed, 08 Oct 2003 13:12:46 -0400
| Newsgroups | gmane.ietf.asrg.rmx |
|---|---|
| Message-ID | <[email protected]> |
Note: This is a restatement of my earlier message with some minor
changes so that HELO verification can use the same bookkeeping
method.
Mail Verification Protocol (MVP)
Unlike checking the HELO parameter, checking the sender domain needs
to handle the case of more that one outbound sending administrative
organizations (ISPs). And the domain owner may not be reasonably able
to implement dynamic DNS updates from the sending administrative
organizations.
I propose the following (using the notation from the DRIP document).
Domain name owners implement the following "provider delegation"
records that point to the list of authorized outbound IP addresses
for each valid outbound sending administrative organization (provider)
for the domain name.
senders._email_.${DOMAIN}. IN PTR ${SENDER_PROVIDER1}
IN PTR ${SENDER_PROVIDER2}
HELO parameter checking can also be modified to use the ``provider
delegation'' scheme.
relays._email_.${DOMAIN}. IN PTR ${HELO_PROVIDER1}
IN PTR ${HELO_PROVIDER2}
COMMENT: MX RRs could be used instead of PTR RRs; with the advantage
that MX RRs can be sorted by priority. Some people have STRONG
feelings about the use of MX RRs for other than the original
intent. This would be somewhat mitigated because the use of
MX RRs here would be in a different name space and the
${*_PROVIDER*} names should never resolve to A (AAAA) RRs.
Each outbound provider lists the IPs that are authorized to send mail
(for one or more domains) using the same DNS method that DRIP uses;
only in the ``${SENDER_PROVIDER1}.'' DNS name space instead of the
``relays._email_.${DOMAIN}.'' space used by DRIP draft.
${IPS}.${IPV}.${SENDER_PROVIDER1}. IN ${TYPE} ${IP}
Wildcard ``unauthorized'' records are not needed since the "provider
delegation" supplies the ``implemented'' flag and the MTA must still
check all the providers until an ``authorized'' hit is made.
The ${SENDER_PROVIDER*} domain name would likely be something like:
pool7.cust.${ISP}
${HELO_PROVIDER1} and ${SENDER_PROVIDER1} can have the same value
for those configurations where the list of IP addresses that are
authorized to use the domain name as the HELO parameter is the same
list of IP addresses that are authorized to send for the domain name.
This proposal is easy for MTAs to implement, domain name owners to
implement, and sending administrative organizations to implement. It's
fast, the number of lookups is two (best case). Parsing the lookup
results is very simple.
Attached is perl pseudo code to demonstrate how a server MTA would
use this.
Raymond S Brand
SMTP_Validate.txt
(text/plain, 2.4 KB)
sub Validate_SMTP_Session_Parameters
{
my ($VerifyType, $IP, $IPType, $Domain) = @_;
my @Providers = ();
my $status;
$status = GetProviders($VerifyType, $Domain, \@Providers);
if ($status eq $NXDOMAIN)
{
/*
* See if any of the domain's ancestors have providers.
* If so, the result here should be $RESULT_NOT_AUTHORIZED;
* otherwise, it is $RESULT_UNKNOWN;
*/
# FIXME #
}
elsif ($status eq $SERVFAIL)
{
return $RESULT_TEMP_FAIL
}
# elsif ($status eq $FORMERR)
# elsif ($status eq $NOTIMP)
# elsif ($status eq $REFUSED)
elsif ($status ne $NOERROR)
{
/*
* Everything else is a failure!
*/
return $RESULT_UNKNOWN;
}
/*
* Have a list of providers
*/
my $IPS = FormatIP($IP, $IPType);
my $TempFail = 0;
foreach $Provider (@Providers)
{
next if (IsBlocked($VerifyType, $Provider));
$status = LookupIP($IPS, $Provider, $IPType, $IP)
if ($status eq $RESULT_AUTHORIZED)
{
return $RESULT_AUTHORIZED;
}
elsif ($status eq $RESULT_TEMP_FAIL)
{
$TempFail++;
}
}
if ($TempFail > 0)
{
return $RESULT_TEMP_FAIL;
}
return $RESULT_NOT_AUTHORIZED;
}
sub GetProviders
{
my ($VerifyType, $Domain, $Array_ref) = @_;
my $SubSpace;
if ($VerifyType eq "HELO")
{
$SubSpace = "relays._email_";
}
elsif ($VerifyType eq "SENDER")
{
$SubSpace = "senders._email_";
}
else
{
die "How did we get here?";
}
/*
* Get the list of PTR RRs for ${SubSpace}.${Domain} and put them in
* the array.
* Return the rcode from the query as the subroutine value.
*/
# FIXME #
}
sub FormatIP
{
my ($IP, $IPType) = @_;
if ($IPType == 4)
{
use Socket;
my $IPS = inet_ntoa(inet_aton($IP));
$IPS ~= s/\./_/g;
return $IPS;
}
elsif ($IPType == 6)
{
/*
* $IPType == 6 is left as an exercise for the implementor.
*/
# FIXME #
die "Fix me.";
}
die "Unknown IP address type.";
}
sub LookupIP
{
my ($IPS, $Provider, $IPType, $IP) = @_;
/*
* Lookup "${IPS}.${Provider}" $IPType RRs.
* If exactly one answer is returned, and it is of the correct
* record type, and it is IP $IP, then return
* $RESULT_AUTHORIZED.
* Otherwise, return $RESULT_TEMP_FAIL for temporary DNS failures
* (SERVFAIL) or $RESULT_NOT_AUTHORIZED for everything else.
*/
# FIXME #
}
sub IsBlocked
{
my ($VerifyType, $ProviderName) = @_;
/*
* Return undef if Provider domain name is NOT on any block
* list queried.
*/
# FIXME #
return undef;
}