adrian ilarion ciobanu:
> > 
> > You associate a fixed nexthop with each authenticated client, and their
> > entire set of domains. You flush either all their domains, or the subset
> > they requested. The scache entry is for the client-specific nexthop, not
> > the recipient domain.
> > 
> >     example.com     atrn:[client1.atrn.invalid]
> >     example.net     atrn:[client1.atrn.invalid]
> >     example.org     atrn:[client2.atrn.invalid]
> > 
> > The scache slot is for "[client1.atrn.invalid]".
> 
> Got it. I mixed scache manpage missreadings with flush records.

If the architecture is like this:

    Customer <--> smtpd(8) <--> atrnd(8) <--> smtp(8)

Then the transport map would look like:

    example.com atrn:[example.com]
    example.org atrn:[example.org]

with in master.cf:

    atrnd  unix  -       -       n       -       -       atrnd

    atrn   unix  -       -       n       -       -       smtp
        -o smtp_connection_cache_destinations=static:all
        -o smtp_connection_reuse_time_limit=0

- smtpd(8) can rate-limit the ATRN command via the anvil(8) server.

- Each time smtpd(8) receives a valid ATRN command it connects to
atrnd(8), passes the customer domain name, and waits for atrnd(8)
to respond.

- atrnd(8) either rejects the request (perhaps because it's still
proxying mail for that domain) or stores a socket with scache(8)
under the customer domain name.

- Once mail starts flowing, smtp(8) retrieves that socket from
scache(8) and saves that socket to scache(8) upon each delivery
completion.

Other things to keep in mind:

- There need to be generous timeouts before the first delivery, and
perhaps smaller timeouts between successive deliveries.

- smtpd(8) needs to reset its watchdog timer periodically otherwise
bad things happen when the ATRN session lasts more than $daemon_timeout
seconds.

- smtpd(8) uses two atrn client APIs that encapsulate interaction
with atrnd(8), namely, sending the customer domain information,
and pushing bytes between customer and atrnd(8) without any
understanding of the content. 

- By playing byte-pusher-in-the-middle, smtpd(8) processes TLS
messages as soon as they become available, so there is a possibility
of enabling the TLS session renegotation bug. For background on this
see http://www.postfix.org/wip.html.

Below is a preliminary design document about implementing ATRN in
Postfix.  In this document I try to minimize the number of parameters
that need to be changed from their defaults. To achieve that goal
I introduce a new address class with its own main.cf settings.

Before a line of code gets written, I would like to see an updated
version of that design document. It needs to consider the choices
that need to be made.

Finally I have introduced earlier in this thread the requirement
that smtpd(8) be changed only minimally, and that most of the ATRN
smarts are implemented outside smtpd(8), by a separate daemon.

This principle has worked well in Postfix. Whenever a major feature
is added, don't mess up the existing programs. Instead, write a
new daemon process and a client library module that implements a
narrow protocol. This effectively guarantees that the new feature
will have zero impact on Postfix performance and reliability except
when a site decides to use that feature.

        Wietse

[ATRN design document dated Jun 26, 2005]

Below are some notes on what it would take to implement ATRN support
in Postfix. This is an updated version of notes that I made before
connection caching was added to Postfix.

In summary:

- Postfix can support ATRN requests with only one domain parameter,

- Postfix can support ATRN over TLS encrypted sessions,

- Postfix ATRN support needs only one mandatory parameter that
specifies an (ATRN domain name -> SASL login name) mapping,

- Postfix ATRN support needs one optional but recommended parameter
that specifies a table for recipient address validation.

- ATRN configuration is kept to the minimum by introducing a new
"atrn" mail delivery transport with its own address class (in
addition to the local, virtual alias, virtual mailbox, and relay
address classes) with its own default configuration parameters.

- Migration from ETRN <=> ATRN is not transparent.

One question: how much need is there for this functionality?  Most
of the infrastructure exists, so it's not a terrible amount of work
to implement. ATRN Support adds another notch to the list of RFCs
that Postfix implements.

        Wietse

Table of contents:

1 - ATRN Protocol basics
2 - Implementing ATRN with the Postfix connection cache
3 - Multi-domain ATRN requests
4 - Interactions with TLS
5 - ATRN User interface
6 - Migration between ETRN and ATRN

1 - ATRN Protocol basics
========================

ATRN is described in RFC 2645 as: ON-DEMAND MAIL RELAY (ODMR), SMTP
with Dynamic IP Addresses. The basic operation is easily explained
with the following quote:

RFC 2645 section 5.2.1.  ATRN (Authenticated TURN)

   Unlike the TURN command in [SMTP], the ATRN command optionally takes
   one or more domains as a parameter.  The ATRN command MUST be
   rejected if the session has not been authenticated.  Response code
   530 [AUTH] is used for this.

   The timeout for this command MUST be at least 10 minutes to allow the
   provider time to process its mail queue.

The protocol looks like this (P = provider, C = customer).

   P:  220 EXAMPLE.NET on-demand mail relay server ready
   C:  EHLO example.org
   P:  250-EXAMPLE.NET
   P:  250-AUTH CRAM-MD5 EXTERNAL
   P:  250 ATRN

Once the client has authenticated, the conversation proceeds:

   C:  ATRN example.org,example.com
   P:  250 OK now reversing the connection

At this point, the customer becomes the server, and the provider
becomes the client:

   C:  220 example.org ready to receive email
   P:  EHLO EXAMPLE.NET
   C:  250-example.org
   C:  250 SIZE
   P:  MAIL FROM: <lester.tes...@dot.foo.bar>
   C:  250 OK
   P:  RCPT TO: <l.eva....@example.com>
   C:  250 OK, recipient accepted
   ...
   P:  QUIT
   C:  221 example.org closing connection

All this makes sense only after the client has authenticated,
otherwise ATRN could be used to steal mail.

2 - Implementing ATRN with the Postfix connection cache
=======================================================

Postfix is a modular mail systen. Different processes implement the
SMTP server function, the queue manager/scheduler function, and the
SMTP client function. ATRN is in apparent conflict with this division
of concerns.

ATRN provides one customer-initiated TCP connection between customer
and provider, over which mail is to be delivered to the customer.
This was not possible with Postfix before connection caching was
implemented.  The reason is a conflict in connection management:
the Postfix SMTP clients always attempted to make their own connection
to the addresses listed for the recipient domain, and were unable
to (re)use an existing connection.

This is where SMTP connection caching comes to the rescue. If the
SMTP server makes an SMTP connection cache entry for the connection
that was initiated by the customer's domain, and if Postfix is
configured so that at most one SMTP client process tries to deliver
mail to the customer domain, then this Postfix SMTP client process
can use the connection that the SMTP server entered into the
connection cache. The cached connection can be used multiple times;
it is not tied to any particular SMTP client process.

Postfix ATRN can build on the code that already implements support
for ETRN; this avoids the need to search a potentially large number
of queue files.

Why not implement a dedicated ATRN queue, or even one queue per
domain?  One message can have multiple recipients, and Postfix does
not support queue file splitting.

3 - Multi-domain ATRN requests
==============================

The first complication is that ATRN allows the client to specify
multiple domains in the ATRN command. This is a problem for Postfix.
Suppose that the client sends two domain names with the command
"ATRN X,Y".  Once the cache manager gives the connection to a Postfix
SMTP client that has mail for domain X, that connection is no longer
in the cache. The Postfix SMTP client with mail for domain Y receives
a "not found" reply from the cache manager. Although the Postfix
SMTP client could be configured not to make SMTP connections by
itself, it would have no way to find out when, if ever, a cached
connection becomes available.

Changing this would introduce a great deal of complexity: Postfix
SMTP clients would have to block on a connection cache lookup
request, and the connection cache manager would have to know that
a client does not return a connection to the cache (perhaps the
client has crashed), so that the connection cache manager can inform
a blocked SMTP client that the request can no longer be satisfied.
All this for marginal benefit, because very few potential users of
ATRN are expected to run multiple domains on a dynamic IP address.

Another limitation of this scheme is that if a customer makes
multiple overlapping SMTP connections with ATRN requests for the
same domain, only one connection will be used for mail delivery,
because Postfix will deliver mail to ATRN domains with an SMTP
destination concurrency of only one connection. There is no problem,
however, when the customer makes multiple overlapping connections
with ATRN requests for different domains.

4 - Interactions with TLS
=========================

The TLS implementation introduces one additional complication. TLS
is implemented inside Postfix SMTP server and client processes; it
is not possible to transfer TLS state from one process to another
without closing the connection. Note that this complication would
not exist had Postfix TLS support been implemented outside the SMTP
client and sever processes; in that case we would simply pass around
a local socket that connects to the TLS proxy process.

Because of this complication, the Postfix SMTP server process has
to act as a proxy between the remote customer and the local Postfix
SMTP client; instead of entering the SMTP server socket into the
connection cache, the SMTP server enters one endpoint of a local
socketpair with a large reuse count and expiration time.  When the
Postfix SMTP client retrieves a connection from the cache it actually
gets that end of the local socketpair.  All communication with the
customer is sent through the Postfix SMTP server process, which
also does the TLS encapsulation/decapsulation.  After a mail
transaction, the Postfix SMTP client caches a good connection with
a large expiration time and decrements the connection reuse count.
This repeats until the connection expires from the cache, until the
customer disconnects, or until there is no more mail for the customer.

5 - ATRN User interface
=======================

Setting up ETRN is as simple as listing the domain in relay_domains,
and providing a valid recipient list.  It would be nice if ATRN
setup is just as easy.

Setting up ATRN requires:

- Authorization table with (ATRN domain name -> SASL login name)
mapping.  Without this table any SASL user could invoke ATRN and
steal mail.

- Postfix needs the list of ATRN domains to disable spontaneous
creation of connections for ATRN domains, and to defer delivery if
no connection is cached for such a domain.

- Postfix needs a dedicated "atrn" transport in master.cf, with a
main.cf destination concurrency of 1. This transport can be installed
as a default entry in future master.cf files (the alternative is
to add a completely new scheduling mechanism in the form of a
per-domain concurrency map).

- If we use a dedicated "atrn" mail delivery transport, then we either
need transport map entries for all ATRN domains (ugly), or we need
to introduce an "atrn" address class. The latter is preferable, but
implies that ATRN domains are in a different address class than
ETRN domains (which are in the relay domains class). See also the
section on migration issues below.

In conclusion, ATRN support can be configured with one configuration
paramater, and with a bunch of defaults that never need to be
changed:

Non-default entries: this is the only thing that you must specify:

    main.cf:
        atrn_domain_login_maps = type:table 
            (this provides the ATRN domain name -> SASL login name mapping)

Optional, but highly recommended:

        atrn_recipient_maps = type:table
            (this provides the list of valid recipients)

Default entries, never to be changed:

    main.cf:
        atrn_destination_concurrency_limit=1
        atrn_domains = $atrn_domain_login_maps
            (this uses the authorization table as a list of ATRN domains)
        atrn_transport = atrn
        fast_flush_domains = $relay_domains $atrn_domains

    master.cf:
        atrn      unix  -       -       n       -       -       smtp
            -o smtp_session_cache_only=yes

So, the upshot is that ATRN can be done with one configuration
parameter that specifies the (ATRN domain name -> SASL login name)
mapping, and an optional table for recipient address validation.
With ATRN sesions proxied by the Postfix SMTP server process, Postfix
can handle ATRN requests that specify a single domain, even over
STARTTLS sessions. This will work well as long as the active queue
is not saturated, so that ATRN connections won't expire from the
connection cache before Postfix finishes delivering mail for the
domain.

6 - Migration between ETRN and ATRN
===================================

The above implementation is elegant but has one down-side: a given
domain cannot use both ETRN and ATRN, which complicates migration.
Migration from ETRN to ATRN, or vice versa, requires that customer
and provider make the transition at the same time.

On the provider's end, the following steps are taken when migrating
a customer from ETRN to ATRN:

1 - Copy the customer's valid recipient list from relay_recipient_maps
    to atrn_recipient_maps. Do not update relay_recipient_maps.

2 - Populate the atrn_domain_login_maps table with (domain->login)
    mapping to prevent theft of mail.

3 - Remove the customer domain from relay_domains, to stop nagging
    warnings from Postfix that the domain is listed in multiple
    address classes.

4 - Remove the customer's valid recipient list from relay_recipient_maps.

The migration from ATRN to ETRN is as follows:

1 - Copy the customer's valid recipient list from atrn_recipient_maps
    to relay_recipient_maps. Do not update atrn_recipient_maps.

2 - List the customer domain in relay_domains.

3 - Remove the customer domain from atrn_domain_login_maps, to stop
    nagging warnings from Postfix that the domain is listed in
    multiple address classes.

4 - Remove the customer's valid recipient list from atrn_recipient_maps.

        Wietse

Reply via email to