MODES += usersat
OPTIONS_usersat = auth.m4 local.m4 satellite.m4
+-include site.mk
-include local.mk
###--------------------------------------------------------------------------
SECTION(global, resource)m4_dnl
deliver_queue_load_max = 8
+message_size_limit = 500M
queue_only_load = 12
smtp_accept_max = 16
smtp_accept_queue = 32
helo:
## Don't worry if this is local submission. MUAs won't necessarily
## have a clear idea of their hostnames. (For some reason.)
- accept condition = ${if !eq{$acl_c_mode}{submission}}
+ accept condition = ${if eq{$acl_c_mode}{submission}}
## Check that the caller's claimed identity is actually plausible.
## This seems like it's a fairly effective filter on spamminess, but
## See whether there's a special exception for this sender domain.
accept senders = ${LOOKUP_DOMAIN($sender_address_domain,
- {KV(senders, {$value}{})},
- {})}
+ {KV(senders)})}
## Ensure that the sender is routable. This is important to prevent
## undeliverable bounces.
<:${if def:acl_m_hdrrm{$acl_m_hdrrm:}}\
$2:>):>)
+m4_define(<:DKIM_SIGN_P:>,
+ <:and {{exists{CONF_sysconf_dir/dkim-sign.conf}} \
+ {!def:h_DKIM-Signature:} \
+ {!def:h_List-ID:} \
+ {or {{def:authenticated_id} \
+ {def:authenticated_sender}}}}:>)
+
+m4_define(<:DKIM_KEYS_INSTANCE:>,
+ <:${lookup {${domain:$h_From:}} partial0-lsearch \
+ {CONF_sysconf_dir/dkim-sign.conf} \
+ _LOOKUP_ARGS(<:$1:>, <:$2:>)}:>)
+m4_define(<:DKIM_KEYS_STATE:>, <:${lookup {$1} lsearch \
+ {DKIM_KEYS_INSTANCE(<:{CONF_dkim_keys_dir/$value/active/dkim-keys.state}:>)} \
+ _LOOKUP_ARGS(<:$2:>, <:$3:>, <:fail:>)}:>)
+m4_define(<:DKIM_KEYS_INFO:>, <:DKIM_KEYS_STATE(<:params:>,
+ <:{${if and {{>={$tod_epoch}{KV(t0)}} \
+ {<{$tod_epoch}{${eval:KV(t0) + KV(n)*KV(step)}}}} \
+ {DKIM_KEYS_STATE(<:info.${eval:($tod_epoch - KV(t0))/KV(step)}:>,
+ <:$1:>, <:$2:>)} \
+ m4_ifelse(<:$2:>, <::>, <:fail:>, <:$2:>)}}:>,
+ m4_ifelse(<:$2:>, <::>, <:fail:>, <:$2:>)):>)
+
+m4_define(<:DKIM_SIGN:>,
+ <:dkim_domain = \
+ ${if DKIM_SIGN_P \
+ {DKIM_KEYS_INSTANCE({${domain:$h_From:}})}}
+ dkim_selector = DKIM_KEYS_INFO(<:{KV(k)}:>)
+ dkim_private_key = \
+ DKIM_KEYS_INSTANCE(<:m4_dnl
+ {CONF_dkim_keys_dir/$value/active/$dkim_selector.priv}:>)
+ dkim_canon = relaxed
+ dkim_strict = true
+ ## The following ridiculous stunt does two important jobs. Firstly,
+ ## and more obviously, it arranges to include one more copy of each
+ ## header name than the message actually contains, thereby causing
+ ## the signature to fail if another header with the same name is
+ ## added. And secondly, and far more subtly, it also trims the
+ ## spaces from the header names so that they're in the format that
+ ## the signing machinery secretly wants.
+ dkim_sign_headers = \
+ ${sg {${map {CONF_dkim_headers : \
+ X-CONF_header_token-DKIM-Key-Publication} \
+ {$item${sg {${expand:\$h_$item:}\n} \
+ {((?:[^\n]+|\n\\s+)*)\n} \
+ {:$item}}}}} \
+ {::}{:}}
+ headers_add = \
+ ${if DKIM_SIGN_P \
+ {DKIM_KEYS_INFO(<:m4_dnl
+ {X-CONF_header_token-DKIM-Key-Publication: \
+ DKIM signature not suitable \
+ as evidence after delivery;\n\t\
+ DKIM private key KV(k) will be \
+ published\n\t\
+ at KV(u)\n\t\
+ on or before KV(tpub)}:>)}}:>)
+
+
m4_define(<:SMTP_DELIVERY:>,
<:## Prevent sending messages with overly long lines. The use of
## `message_size_limit' here is somewhat misleading.
## it into the transport name. This is very unpleasant, of course.
smtp:
driver = smtp
+ SMTP_DELIVERY
APPLY_HEADER_CHANGES
+ DKIM_SIGN
tls_require_ciphers = CONF_acceptable_ciphers
tls_dh_min_bits = 508
tls_tempfail_tryclear = true
<:driver = smtp
SMTP_DELIVERY
APPLY_HEADER_CHANGES
+ DKIM_SIGN
hosts_try_auth = *
hosts_require_tls = DOMKV(tls-peer-ca, {*}{})
hosts_require_auth = \
DEFCONF(trusted_groups, root : adm)
## Where the spam filter is.
-DEFCONF(spamd_address, 172.29.199.179)
+DEFCONF(spamd_address, 172.29.199.8)
DEFCONF(spamd_port, 783)
## Default spam limit for incoming mail (multiplied by ten).
DEFCONF(userconf_dir, $home/.mail)
DEFCONF(alias_file, /etc/aliases)
DEFCONF(ca_dir, /etc/ca)
+DEFCONF(dkim_keys_dir, /var/lib/dkim-keys)
## User address suffix handling.
DEFCONF(user_suffix_list, +* : -*)
## Other hosts allowed to relay mail through us.
DEFCONF(relay_clients, <m4_dnl
-; +trusted m4_dnl
+; +allnets m4_dnl
; 172.31.80.8 m4_dnl chiark (VPN)
-; 172.29.198.161 ; 2001:ba8:1d9:a000::1:1 m4_dnl national
+)
+
+## DKIM headers list.
+## Surprise! Internal whitespace isn't allowed here.
+DEFCONF(dkim_headers, m4_dnl
+References : In-Reply-To : Subject : To : Date : Message-ID : m4_dnl
+From : Sender : Reply-To : Cc : m4_dnl
+Content-Transfer-Encoding : Content-Type : MIME-Version : m4_dnl
+Content-ID : Content-Description m4_dnl
)
## TLS certificate list.
m4_define(<:WARNING_HEADER:>,
<:add_header = X-CONF_header_token-Warning: $1 $2:>)
+## _LOOKUP_ARGS([if-found], [if-not-found], [default])
+##
+## Processing for lookup arguments. Use as
+##
+## ${lookup {K} ST {F} _LOOKUP_ARGS(...)}$.
+##
+## IF-FOUND defaults to `{$value}'; IF-NOT-FOUND defaults to DEFAULT, which
+## defaults to `{}'.
+m4_define(<:_LOOKUP_ARGS:>,
+ <:m4_ifelse(<:$1$2$3:>, <::>, <::>,
+ <:$1$2:>, <::>, <:{$value}$3:>,
+ <:$2:>, <::>, <:$1$3:>,
+ <:$1$2:>):>)
+
## LOOKUP_DOMAIN(dom, [if-found], [if-not-found])
##
## Look up DOM in the master domains file. If it's found, put the
m4_define(<:LOOKUP_DOMAIN:>,
<:if exists{CONF_sysconf_dir/domains.conf} \
{${lookup {$1}partial0-lsearch{CONF_sysconf_dir/domains.conf} \
- m4_ifelse(<:$2$3:>, <::>, <::>,
- <:$2:>, <::>, <:{$value}$3:>,
- <:$2$3:>)}} \
+ _LOOKUP_ARGS(<:$2:>, <:$3:>)}} \
$3:>)
-## KV(key, result)
+## KV(key, [result])
##
## Extract the value of the named KEY in the ${extract ...}-style string in
## the current $value (where it may have been left by `LOOKUP-DOMAIN'). The
## RESULT is a pair {IF-FOUND}{IF-NOT-FOUND}; the former may use $value to
## refer to the value; the latter may be `fail' (not in braces) to force
-## expansion failure.
+## expansion failure. The default is to expand to the extracted value or
+## nothing.
m4_define(<:KV:>, <:${extract {$1}{$value}$2}:>)
-## DOMKV(key, result)
+## DOMKV(key, [result])
##
## Extract the value of the named KEY in the ${extract ...}-style string in
## $domain_data; see `KV'.
127.0.0.0/8 ; ::1
hostlist thishost = <; \
+localnet ; @[]
-hostlist foreign = <; \
- 212.13.198.76 ; 2001:ba8:0:1d9::1:1
+hostlist foreign = <;
hostlist border = <; \
! +foreign ; \
- 62.49.204.144/28 ; 2001:470:1f09:1b98::/64 ; \
- 81.2.113.195 ; 81.187.238.128/28 ; \
- 212.13.198.64/28 ; 2001:ba8:0:1d9::/64
+ 81.2.113.195 ; 81.187.238.128/28 ; 217.169.12.64/28 ; \
+ 2001:8b0:c92:fff::/64
hostlist trusted = <; \
+localnet ; +border ; \
- 172.29.199.0/24 ; 2001:8b0:c92::/49 ; \
- 2001:ba8:1d9::/49 ; 2001:470:9740::/49
+ 172.29.199.0/24 ; 2001:8b0:c92::/49
hostlist allnets = <; \
+localnet ; +border ; \
- 172.29.198.0/23 ; 2001:8b0:c92::/48 ; \
- 2001:ba8:1d9::/48 ; 2001:470:9740::/48
+ 172.29.198.0/23 ; 2001:8b0:c92::/48
## Addresses which are likely to be bogus. These are zero, loopback,
## multicast, broadcast (IPv4), and blocks reserved for documentation.
--- /dev/null
+### -*-makefile-*-
+
+HOSTS_hub += stratocaster
+
+HOSTS_srv += telecaster
+
+HOSTS_usersat += jem artist jazz #vampire
+
+HOSTS_satellite += gibson spirit #crybaby
+HOSTS_satellite += ibanez radius roadstar universe
+HOSTS_satellite += fender precision
+HOSTS_satellite += eggle national
+HOSTS_satellite += groove
## If the client is trusted, or this is a new submission, don't
## bother with any of this. We will have verified the sender
## fairly aggressively before granting this level of trust.
- accept hosts = +trusted
+ accept hosts = CONF_relay_clients
accept condition = ${if eq{$acl_c_mode}{submission}}
## If all domains have disabled spam checking then don't check.
VHOST
condition = DOMKV(sysusers, {$value}{false})
local_part_suffix = CONF_user_suffix_list
- local_part_suffix_optional = true
- :>)
+ local_part_suffix_optional = true:>)
SECTION(routers, virtual-sysusers-spam)m4_dnl
## If we're letting general system users receive mail through this vhost then
<:CURRENT_LOCAL_PART:>, <:$domain:>, <:$sender_address:>,
<:VHOST
condition = DOMKV(sysusers, {$value}{false})
- :>)
+:>)
+DIVERT(null)
###----- That's all, folks --------------------------------------------------