| 1 | From: David Woodhouse <dwmw2@infradead.org> |
| 2 | Date: Thu, 18 Dec 2003 14:25:47 +0000 |
| 3 | |
| 4 | Given a domain in DNS of the form... |
| 5 | |
| 6 | $ORIGIN vdns.infradead.org.mailtarget. |
| 7 | fish 604800 IN TXT dwmw2@infradead.org |
| 8 | |
| 9 | (It doesn't _have_ to be in private namespace; you can put it anywhere but I |
| 10 | prefer to have it private) |
| 11 | |
| 12 | The following routers use it to implement a virtual domain. You could of course |
| 13 | omit the first and just make sure you have postmaster in all the zones you use |
| 14 | this way... |
| 15 | |
| 16 | Rather than hardcoding the DNS domain to use in the router, we can put it into |
| 17 | a flat file with the list of domains for which we should be doing this. |
| 18 | |
| 19 | We put this into /etc/exim/dns-virtual-domains: |
| 20 | |
| 21 | vdns.infradead.org: vdns.infradead.org.mailtarget |
| 22 | |
| 23 | In the main section of the configuration file we have: |
| 24 | |
| 25 | domainlist dns_virtual_domains = lsearch;CONFDIR/dns-virtual-domains |
| 26 | |
| 27 | The following routers handle unqualified addresses, multiple TXT records, and |
| 28 | entries of the form '@domain'. Also if we're not primary MX for the virtual |
| 29 | domain in question we'll fall back to forwarding to a higher-priority MX host |
| 30 | if the DNS isn't talking to us.... |
| 31 | |
| 32 | virtual_postmaster: |
| 33 | driver = redirect |
| 34 | domains = +dns_virtual_domains |
| 35 | local_parts = postmaster:root:abuse:mailer-daemon |
| 36 | data = postmaster@$primary_hostname |
| 37 | |
| 38 | # For virtual domains, look up the target in DNS and rewrite... |
| 39 | |
| 40 | dns_virtual_domains: |
| 41 | driver = redirect |
| 42 | domains = +dns_virtual_domains |
| 43 | check_ancestor |
| 44 | repeat_use |
| 45 | one_time |
| 46 | allow_defer |
| 47 | allow_fail |
| 48 | forbid_file |
| 49 | forbid_pipe |
| 50 | retry_use_local_part |
| 51 | qualify_preserve_domain |
| 52 | |
| 53 | # Stash the lookup domain root for use in the next router. |
| 54 | address_data = ${lookup{$domain}lsearch{CONFDIR/dns-virtual-domains}} |
| 55 | |
| 56 | # The lookup failure won't distinguish between absent record, absent |
| 57 | # domain, or other temporary failures. So we make this router just |
| 58 | # give up, and sort out the various failure modes later. |
| 59 | |
| 60 | # The ${sg...} bits turn multiple TXT records (which Exim gives us |
| 61 | # separated by \n) into a comma-separated list, and also rewrite |
| 62 | # any element of that list of the form '@domain' (i.e. without a |
| 63 | # local part) to $local_part@domain, using the original local part |
| 64 | # from the address being routed, at the newly-provided domain. |
| 65 | |
| 66 | # Addresses containing _only_ a localpart are qualified at the |
| 67 | # same domain as is being looked up, by qualify_preserve_domain |
| 68 | # above. |
| 69 | data = ${sg{\ |
| 70 | ${sg{\ |
| 71 | ${lookup dnsdb{txt=$local_part.$address_data}{$value}fail}\ |
| 72 | }{\n}{,}}\ |
| 73 | }{(,|^)[ ]*@}{\$1\$local_part@}} |
| 74 | |
| 75 | dns_virtual_failed: |
| 76 | driver = redirect |
| 77 | domains = +dns_virtual_domains |
| 78 | allow_fail |
| 79 | allow_defer |
| 80 | data = ${lookup dnsdb{ns=$address_data}\ |
| 81 | # If NS lookup succeeded, the domain exists and we can find it. |
| 82 | # Therefore, the above lookup failure meant that the user |
| 83 | # just doesn't exist. Fail appropriately: |
| 84 | {:fail:Unknown user at virtual domain}\ |
| 85 | # NS lookup failed. This means there's a DNS problem -- so we |
| 86 | # shouldn't fail the delivery; let the following routers handle |
| 87 | # it... Note "fail" not "{:fail:}". It means 'pass'. :) |
| 88 | fail} |
| 89 | |
| 90 | |
| 91 | # We have DNS problems. If we're actually _delivering_, then try to |
| 92 | # deliver to a higher-priority MX if one exists. Otherwise, we defer and |
| 93 | # let it stay on the queue until the problem is fixed. |
| 94 | # You may prefer to freeze or bounce in this situation; I don't. |
| 95 | dns_virtual_relay: |
| 96 | driver = dnslookup |
| 97 | domains = +dns_virtual_domains |
| 98 | transport = remote_smtp |
| 99 | self = defer |
| 100 | no_verify |
| 101 | no_more |
| 102 | |
| 103 | # On the other hand, if there's a DNS problem and we're only _verifying_, |
| 104 | # as we do when accepting incoming mail, then accept it for now and |
| 105 | # it'll get queued for when the DNS works again. |
| 106 | dns_virtual_verify_fallback: |
| 107 | driver = accept |
| 108 | domains = +dns_virtual_domains |
| 109 | verify_only |
| 110 | no_more |
| 111 | |
| 112 | > Now I just need to investigate DDNS and see if it'll let individual |
| 113 | > users update the TXT records for their own aliases in the DNS... :) |
| 114 | |
| 115 | This is remarkably simple to set up -- Google is your friend. I'm now |
| 116 | able to set up HMAC-MD5 keys to 'own' certain mail domains, and the |
| 117 | owners of those virtual mail domains can happily change the TXT records |
| 118 | to their hearts content, without bugging me to make changes and roll out |
| 119 | new alias files to all the MX hosts. |
| 120 | |
| 121 | A setuid app which is able to read the key file, and which will update |
| 122 | the alias only for the user it's invoked by, is also fairly trivial to |
| 123 | implement -- inspired by the 'cammail' alias system. |
| 124 | |