Add sender rewriting scheme (SRS).
This commit is contained in:
parent
f24ce8295d
commit
43fd2da518
4 changed files with 116 additions and 15 deletions
|
@ -146,6 +146,7 @@
|
|||
- t timestamp default now()
|
||||
- original varchar(250) not null
|
||||
- rewritten varchar(250) not null
|
||||
- srs_id bigint
|
||||
|
||||
- name: database index mail_from__rewritten
|
||||
postgresql_idx:
|
||||
|
@ -158,3 +159,15 @@
|
|||
table: mail_from
|
||||
columns: rewritten
|
||||
idxname: mail_from__rewritten
|
||||
|
||||
- name: database index mail_from__srs_id
|
||||
postgresql_idx:
|
||||
login_host: "{{ mailserver.postgresql.host }}"
|
||||
port: "{{ mailserver.postgresql.port }}"
|
||||
login_user: "{{ mailserver.postgresql.username }}"
|
||||
login_password: "{{ mailserver.postgresql.password }}"
|
||||
db: "{{ mailserver.postgresql.dbname }}"
|
||||
ssl_mode: disable
|
||||
table: mail_from
|
||||
columns: srs_id
|
||||
idxname: mail_from__srs_id
|
||||
|
|
|
@ -99,10 +99,10 @@ smtpd_relay_restrictions =
|
|||
# VERP marking
|
||||
# Envelope sender addresses matching mydomains are marked.
|
||||
# The marker is removed from envelope recipient addresses.
|
||||
canonical_classes = envelope_sender, envelope_recipient
|
||||
canonical_classes = envelope_sender, envelope_recipient, header_recipient
|
||||
sender_canonical_classes = envelope_sender
|
||||
sender_canonical_maps = pgsql:/etc/postfix/sender_canonical_maps.cf
|
||||
recipient_canonical_classes = envelope_recipient
|
||||
recipient_canonical_classes = envelope_recipient, header_recipient
|
||||
recipient_canonical_maps = pgsql:/etc/postfix/recipient_canonical_maps.cf
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# THIS FILE IS CONTROLLED BY ANSIBLE - DO NOT CHANGE IN DEPLOYMENT!
|
||||
|
||||
# Rewrite (envelope and header) recipient addresses:
|
||||
# - if the recipient address has a local domain and does
|
||||
# not begin with SRS0 or SRS1, then strip our verp_marker
|
||||
# - if the recipient address has a local domain and does
|
||||
# begin with SRS0 or SRS1, try to extract our srs_id
|
||||
# and lookup the corresponding original address
|
||||
|
||||
# man pgsql_table
|
||||
|
||||
|
@ -7,4 +13,35 @@ user = {{ mailserver.postgresql.username }}
|
|||
password = {{ mailserver.postgresql.password }}
|
||||
dbname = {{ mailserver.postgresql.dbname }}
|
||||
hosts = {{ mailserver.postgresql.host }}
|
||||
query = select regexp_replace('%s', '\+(.*){{ mailserver.postfix.verp_marker }}-\d+@', '+\1@')
|
||||
query =
|
||||
with
|
||||
mydomains as (select regexp_replace('%s', '.*@([^@]+)$', '\1') in (select name from domains) v),
|
||||
srs0 as (select lower(substr('%s', 1, 4)) = 'srs0' v),
|
||||
srs1 as (select lower(substr('%s', 1, 4)) = 'srs1' v)
|
||||
select
|
||||
case
|
||||
when mydomains.v and not srs0.v and not srs1.v
|
||||
then regexp_replace('%s', '^(.*)\+{{ mailserver.postfix.verp_marker }}-\d+@', '\1@')
|
||||
else
|
||||
case
|
||||
when mydomains.v
|
||||
then
|
||||
case
|
||||
when srs0.v
|
||||
then
|
||||
case
|
||||
when '%s' ~* '^SRS0=\d+@[^@]+$'
|
||||
then (select original from mail_from
|
||||
where srs_id = regexp_replace('%s', '^.....(\d+)@[^@]+$', '\1')::bigint
|
||||
and original<>rewritten)
|
||||
else '%s'
|
||||
end
|
||||
else (with t2 as (select regexp_replace('%s', '^(.*)@[^@]+$', '\1') v)
|
||||
select original from mail_from, t2
|
||||
where lower(substr(rewritten, 1, length(t2.v))) = lower(t2.v)
|
||||
and lower(substr(original, 1, 4)) = 'srs0')
|
||||
end
|
||||
else '%s'
|
||||
end
|
||||
end
|
||||
from mydomains, srs0, srs1
|
||||
|
|
|
@ -1,5 +1,21 @@
|
|||
# THIS FILE IS CONTROLLED BY ANSIBLE - DO NOT CHANGE IN DEPLOYMENT!
|
||||
|
||||
# Rewrite envelope sender addresses:
|
||||
# - if the sender address has a local domain, then add our verp_marker
|
||||
# - else implement sender rewriting scheme (cf.
|
||||
# https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme,
|
||||
# http://www.libsrs2.org/srs/srs.pdf
|
||||
# ):
|
||||
# * if the address does not begin with SRS0 or SRS1:
|
||||
# rewrite address to srs0={random_bigint}@main_local_domain
|
||||
# * if the address begins with SRS0:
|
||||
# replace SRS0 with srs1={random_bigint}= and
|
||||
# replace the domain with our main local domain
|
||||
# * if the address begins with SRS0:
|
||||
# replace the domain with our main local domain
|
||||
# The main local domain is the first domain with a name
|
||||
# that is not equal to 'role_specific'.
|
||||
# The random_bigint has at not 15 decimal digits.
|
||||
|
||||
# man pgsql_table
|
||||
|
||||
|
@ -7,15 +23,50 @@ user = {{ mailserver.postgresql.username }}
|
|||
password = {{ mailserver.postgresql.password }}
|
||||
dbname = {{ mailserver.postgresql.dbname }}
|
||||
hosts = {{ mailserver.postgresql.host }}
|
||||
query = insert into mail_from (id, original, rewritten)
|
||||
values (nextval('mail_from_id_seq'), '%s',
|
||||
case
|
||||
when regexp_replace('%s', '.*@([^@]+)$', '\1') in (select name from domains)
|
||||
then case
|
||||
when '%s'~*'{{ mailserver.postfix.verp_marker }}-\d+@'
|
||||
then '%s'
|
||||
else regexp_replace('%s', '^(.*)@[^@]+$', '\1') || case when '%s'~'\+' then '{{ mailserver.postfix.verp_marker }}-' else '+{{ mailserver.postfix.verp_marker }}-' end || lastval()::text || '@' || regexp_replace('%s', '.*@([^@]+)$', '\1')
|
||||
end
|
||||
else '%s'
|
||||
end
|
||||
) returning rewritten
|
||||
query =
|
||||
with
|
||||
rnd as (select (random() * 1000000000000000)::bigint v),
|
||||
mydomains as (select regexp_replace('%s', '.*@([^@]+)$', '\1') in (select name from domains) v),
|
||||
srs0 as (select lower(substr('%s', 1, 4)) = 'srs0' v),
|
||||
srs1 as (select lower(substr('%s', 1, 4)) = 'srs1' v),
|
||||
new_row as (
|
||||
select
|
||||
nextval('mail_from_id_seq') new_id,
|
||||
'%s' original,
|
||||
case
|
||||
when mydomains.v and not srs0.v and not srs1.v
|
||||
then
|
||||
case
|
||||
when '%s'~*'\+{{ mailserver.postfix.verp_marker }}-\d+@'
|
||||
then '%s'
|
||||
else regexp_replace('%s', '^(.*)@[^@]+$', '\1') || '+{{ mailserver.postfix.verp_marker }}-'
|
||||
|| lastval()::text || '@' || regexp_replace('%s', '.*@([^@]+)$', '\1')
|
||||
end
|
||||
else
|
||||
case
|
||||
when not mydomains.v and not srs0.v and not srs1.v
|
||||
then 'SRS0=' || LPAD(rnd.v::text, 15 , '0') || '@' || (select name from domains where name<>'role_specific' order by id limit 1)
|
||||
else
|
||||
case
|
||||
when srs0.v
|
||||
then
|
||||
case
|
||||
when mydomains.v
|
||||
then '%s'
|
||||
else 'SRS1=' || LPAD(rnd.v::text, 15 , '0') || '='
|
||||
|| regexp_replace(substr('%s', 5), '^(.*)@[^@]+$', '\1@'
|
||||
|| (select name from domains where name<>'role_specific' order by id limit 1))
|
||||
end
|
||||
else regexp_replace('%s', '^(.*)@[^@]+$', '\1@' || (select name from domains where name<>'role_specific' order by id limit 1))
|
||||
end
|
||||
end
|
||||
end rewritten,
|
||||
rnd.v srs_id
|
||||
from rnd, mydomains, srs0, srs1
|
||||
where '%s' <> '""'
|
||||
),
|
||||
ins_row as (insert into mail_from (id, original, rewritten, srs_id)
|
||||
select new_row.new_id, new_row.original, new_row.rewritten, case when mydomains.v and not srs0.v and not srs1.v then null else new_row.srs_id end
|
||||
from new_row, mydomains, srs0, srs1 where new_row.original<>new_row.rewritten),
|
||||
orig(o) as (values('%s'))
|
||||
select rewritten from new_row
|
||||
|
|
Loading…
Reference in a new issue