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…
	
	Add table
		Add a link
		
	
		Reference in a new issue