From 7adc9ca07a9a870f92a14d16740abfecde0bdfa4 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 9 May 2020 21:04:49 +0100 Subject: [PATCH] Move the native SRS implementation from Experimental to mainline --- doc/doc-docbook/spec.xfpt | 117 ++++++++++++++++++++++++++++++ doc/doc-txt/NewStuff | 3 + doc/doc-txt/experimental-spec.txt | 78 ++------------------ src/src/EDITME | 8 +- src/src/config.h.defaults | 2 +- src/src/exim.c | 5 +- src/src/expand.c | 22 +++--- src/src/globals.c | 2 +- src/src/globals.h | 2 +- src/src/macro_predef.c | 8 +- test/scripts/4620-SRS/REQUIRES | 2 +- 11 files changed, 153 insertions(+), 96 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index f1940bb1e..748f81cc0 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -10597,6 +10597,14 @@ ${sort {${lookup dnsdb{>:,,mx=example.com}}} {<} {${listextract{1}{<,$item}}}} will sort an MX lookup into priority order. + +.new +.vitem &*${srs_encode&~{*&<&'secret'&>&*}{*&<&'return&~path'&>&*}{*&<&'original&~domain'&>&*}}*& +SRS encoding. See SECT &<>& for details. +.wen + + + .vitem &*${substr{*&<&'string1'&>&*}{*&<&'string2'&>&*}{*&<&'string3'&>&*}}*& .cindex "&%substr%& expansion item" .cindex "substring extraction" @@ -11659,6 +11667,13 @@ includes the case of letters, whereas for &%gti%& the comparison is case-independent. Case and collation order are defined per the system C locale. + +.new +.vitem &*inbound_srs&~{*&<&'local&~part'&>&*}{*&<&'secret'&>&*}*& +SRS decode. See SECT &<>& for details. +.wen + + .vitem &*inlist&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*& &&& &*inlisti&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*& .cindex "string" "comparison" @@ -41078,6 +41093,108 @@ The lookup will return the same result strings as can appear in +.section "SRS (Sender Rewriting Scheme)" SECTSRS +.cindex SRS "sender rewriting scheme" + +.new +SRS can be used to modify sender addresses when forwarding so that +SPF verification does not object to them. +It operates by encoding the original envelope sender in a new +sender local part and using a domain run by the forwarding site +as the new domain for the sender. Any DSN message should be returned +to this new sender at the forwarding site, which can extract the +original sender from the coded local part and forward the DSN to +the originator. + +This is a way of avoiding the breakage that SPF does to forwarding. +The constructed local-part will be longer than the original, +leading to possible problems with very long addresses. +The changing of the sender address also hinders the tracing of mail +problems. + +Exim can be built to include native SRS support. To do this +SUPPORT_SRS=yes must be defined in &_Local/Makefile_&. +If this has been done, the macros _HAVE_SRS and _HAVE_NATIVE_SRS +will be defined. +The support is limited to SRS0-encoding; SRS1 is not supported. + +.cindex SRS excoding +To encode an address use this expansion item: +.vlist +.vitem &*${srs_encode&~{*&<&'secret'&>&*}{*&<&'return&~path'&>&*}{*&<&'original&~domain'&>&*}}*& +.cindex "&%srs_encode%& expansion item" +.cindex SRS "expansion item" +The first argument should be a secret known and used by all systems +handling the recipient domain for the original message. +There is no need to periodically change this key; a timestamp is also +encoded. +The second argument should be given as the envelope sender address before this +encoding operation. +The third argument should be the recipient domain of the message when +it arrived at this system. +.endlist + +.cindex SRS decoding +To decode an address use this expansion condition: +.vlist +.vitem &*inbound_srs&~{*&<&'local&~part'&>&*}{*&<&'secret'&>&*}*& +The first argument should be the recipient local prt as is was received. +The second argument is the site secret. + +If the messages is not for an SRS-encoded recipient the condition will +return false. If it is, the condition will return true and the variable +&$srs_recipient$& will be set to the decoded (original) value. +.endlist + +Example usage: +.code + #macro + SRS_SECRET = + + #routers + + outbound: + driver = dnslookup + # if outbound, and forwarding has been done, use an alternate transport + domains = ! +my_domains + transport = ${if eq {$local_part@$domain} \ + {$original_local_part@$original_domain} \ + {remote_smtp} {remote_forwarded_smtp}} + + inbound_srs: + driver = redirect + senders = : + domains = +my_domains + # detect inbound bounces which are SRS'd, and decode them + condition = ${if inbound_srs {$local_part} {SRS_SECRET}} + data = $srs_recipient + + inbound_srs_failure: + driver = redirect + senders = : + domains = +my_domains + # detect inbound bounces which look SRS'd but are invalid + condition = ${if inbound_srs {$local_part} {}} + allow_fail + data = :fail: Invalid SRS recipient address + + #... further routers here + + + # transport; should look like the non-forward outbound + # one, plus the max_rcpt and return_path options + remote_forwarded_smtp: + driver = smtp + # modify the envelope from, for mails that we forward + max_rcpt = 1 + return_path = ${srs_encode {SRS_SECRET} {$return_path} {$original_domain}} +.endd + + +.wen + + + .section DMARC SECDMARC .cindex DMARC verification diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 7f8f628f9..53d7b5c9a 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -12,6 +12,9 @@ Version 4.95 1. The fast-ramp two phase queue run support, previously experimental, is now supported by default. + 2. The native SRS support, previously experimental, is now supported. It is + not built unless specified in the Local/Makefile. + Version 4.94 ------------ diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 68d04cce7..2b6d01f33 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -292,81 +292,11 @@ These four steps are explained in more details below. -SRS (Sender Rewriting Scheme) Support (native) --------------------------------------------------------------- -This is less full-featured than the libsrs_alt version below. - -The Exim build needs to be done with this in Local/Makefile: -EXPERIMENTAL_SRS_NATIVE=yes - -The following are provided: -- an expansion item "srs_encode" - This takes three arguments: - - a site SRS secret - - the return_path - - the pre-forwarding domain - -- an expansion condition "inbound_srs" - This takes two arguments: the local_part to check, and a site SRS secret. - If the secret is zero-length, only the pattern of the local_part is checked. - The $srs_recipient variable is set as a side-effect. - -- an expansion variable $srs_recipient - This gets the original return_path encoded in the SRS'd local_part - -- predefined macros _HAVE_SRS and _HAVE_NATIVE_SRS - -Sample usage: - - #macro - SRS_SECRET = - - #routers - - outbound: - driver = dnslookup - # if outbound, and forwarding has been done, use an alternate transport - domains = ! +my_domains - transport = ${if eq {$local_part@$domain} \ - {$original_local_part@$original_domain} \ - {remote_smtp} {remote_forwarded_smtp}} - - inbound_srs: - driver = redirect - senders = : - domains = +my_domains - # detect inbound bounces which are SRS'd, and decode them - condition = ${if inbound_srs {$local_part} {SRS_SECRET}} - data = $srs_recipient - - inbound_srs_failure: - driver = redirect - senders = : - domains = +my_domains - # detect inbound bounces which look SRS'd but are invalid - condition = ${if inbound_srs {$local_part} {}} - allow_fail - data = :fail: Invalid SRS recipient address - - #... further routers here - - - # transport; should look like the non-forward outbound - # one, plus the max_rcpt and return_path options - remote_forwarded_smtp: - driver = smtp - # modify the envelope from, for mails that we forward - max_rcpt = 1 - return_path = ${srs_encode {SRS_SECRET} {$return_path} {$original_domain}} - - - - SRS (Sender Rewriting Scheme) Support (using libsrs_alt) -------------------------------------------------------------- -See also above, for an alternative native support implementation. +See also the main docs, for an alternative native support implementation. -Exim currently includes SRS support via Miles Wilton's +Exim can be built with SRS support using Miles Wilton's libsrs_alt library. The current version of the supported library is 0.5, there are reports of 1.0 working. @@ -383,6 +313,10 @@ EXPERIMENTAL_SRS_ALT=yes in your Local/Makefile. +The built-in support, included by SUPPORT_SRS, +shuold *not* be enabled if you wish to use the libsrs_alt +version. + The following main-section options become available: srs_config string srs_hashlength int diff --git a/src/src/EDITME b/src/src/EDITME index 340d30d76..cf671afd1 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -572,6 +572,10 @@ DISABLE_MAL_MKS=yes # Uncomment the following to remove the fast-ramp two-phase-queue-run support # DISABLE_QUEUE_RAMP=yes +# Uncomment the following lines to add SRS (Sender Rewriting Scheme) support +# using only native facilities. See EXPERIMENTAL_SRS_ALT for an alternative. +# SUPPORT_SRS=yes + #------------------------------------------------------------------------------ # Compiling Exim with experimental features. These are documented in @@ -584,10 +588,6 @@ DISABLE_MAL_MKS=yes # EXPERIMENTAL_DCC=yes -# Uncomment the following lines to add SRS (Sender rewriting scheme) support -# using only native facilities. -# EXPERIMENTAL_SRS_NATIVE=yes - # Uncomment the following lines to add SRS (Sender rewriting scheme) support # using the implementation in linbsrs_alt. # You need to have libsrs_alt installed on your system (srs.mirtol.com). diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 5347f7a8e..a91c3c3aa 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -157,6 +157,7 @@ Do not put spaces between # and the 'define'. #define SUPPORT_PROXY #define SUPPORT_SOCKS #define SUPPORT_SPF +#define SUPPORT_SRS #define SUPPORT_TRANSLATE_IP_ADDRESS #define SYSLOG_LOG_PID @@ -205,7 +206,6 @@ Do not put spaces between # and the 'define'. #define EXPERIMENTAL_LMDB #define EXPERIMENTAL_QUEUEFILE #define EXPERIMENTAL_SRS_ALT -#define EXPERIMENTAL_SRS_NATIVE #define EXPERIMENTAL_TLS_RESUME diff --git a/src/src/exim.c b/src/src/exim.c index cd6d25323..ab2d673dd 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -979,6 +979,9 @@ g = string_cat(NULL, US"Support for:"); #ifdef SUPPORT_SPF g = string_cat(g, US" SPF"); #endif +#if defined(SUPPORT_SRS) + g = string_cat(g, US" SRS"); +#endif #ifdef TCP_FASTOPEN tcp_init(); if (f.tcp_fastopen_ok) g = string_cat(g, US" TCP_Fast_Open"); @@ -1001,7 +1004,7 @@ g = string_cat(NULL, US"Support for:"); #ifdef EXPERIMENTAL_QUEUEFILE g = string_cat(g, US" Experimental_QUEUEFILE"); #endif -#if defined(EXPERIMENTAL_SRS_ALT) || defined(EXPERIMENTAL_SRS_NATIVE) +#if defined(EXPERIMENTAL_SRS_ALT) g = string_cat(g, US" Experimental_SRS"); #endif #ifdef EXPERIMENTAL_TLS_RESUME diff --git a/src/src/expand.c b/src/src/expand.c index 95b5d02e1..4abde0af6 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -131,7 +131,7 @@ static uschar *item_table[] = { US"run", US"sg", US"sort", -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS US"srs_encode", #endif US"substr", @@ -166,7 +166,7 @@ enum { EITEM_RUN, EITEM_SG, EITEM_SORT, -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS EITEM_SRS_ENCODE, #endif EITEM_SUBSTR, @@ -334,7 +334,7 @@ static uschar *cond_table[] = { US"gei", US"gt", US"gti", -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS US"inbound_srs", #endif US"inlist", @@ -387,7 +387,7 @@ enum { ECOND_STR_GEI, ECOND_STR_GT, ECOND_STR_GTI, -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS ECOND_INBOUND_SRS, #endif ECOND_INLIST, @@ -758,7 +758,7 @@ static var_entry var_table[] = { { "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient }, { "srs_orig_sender", vtype_stringptr, &srs_orig_sender }, #endif -#if defined(EXPERIMENTAL_SRS_ALT) || defined(EXPERIMENTAL_SRS_NATIVE) +#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS) { "srs_recipient", vtype_stringptr, &srs_recipient }, #endif #ifdef EXPERIMENTAL_SRS_ALT @@ -2438,7 +2438,7 @@ else -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS /* Do an hmac_md5. The result is _not_ nul-terminated, and is sized as the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer. @@ -2513,7 +2513,7 @@ for (int i = 0, j = len; i < MD5_HASHLEN; i++) } return; } -#endif /*EXPERIMENTAL_SRS_NATIVE*/ +#endif /*SUPPORT_SRS*/ /************************************************* @@ -3443,7 +3443,7 @@ switch(cond_type = identify_operator(&s, &opname)) return s; } -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS case ECOND_INBOUND_SRS: /* ${if inbound_srs {local_part}{secret} {yes}{no}} */ { @@ -3535,7 +3535,7 @@ srs_result: if (yield) *yield = (boolvalue == testfor); return s; } -#endif /*EXPERIMENTAL_SRS_NATIVE*/ +#endif /*SUPPORT_SRS*/ /* Unknown condition */ @@ -6783,7 +6783,7 @@ while (*s != 0) continue; } -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS case EITEM_SRS_ENCODE: /* ${srs_encode {secret} {return_path} {orig_domain}} */ { @@ -6837,7 +6837,7 @@ while (*s != 0) yield = string_cat(yield, sub[2]); continue; } -#endif /*EXPERIMENTAL_SRS_NATIVE*/ +#endif /*SUPPORT_SRS*/ } /* EITEM_* switch */ /* Control reaches here if the name is not recognized as one of the more diff --git a/src/src/globals.c b/src/src/globals.c index 880db98f4..561054981 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1517,7 +1517,7 @@ uschar *srs_recipient = NULL; uschar *srs_secrets = NULL; uschar *srs_status = NULL; #endif -#ifdef EXPERIMENTAL_SRS_ALT +#ifdef SUPPORT_SRS uschar *srs_recipient = NULL; #endif int string_datestamp_offset= -1; diff --git a/src/src/globals.h b/src/src/globals.h index 3b9e6fb40..fffe74441 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -1002,7 +1002,7 @@ extern uschar *srs_status; /* SRS staus */ extern BOOL srs_usehash; /* SRS use hash flag */ extern BOOL srs_usetimestamp; /* SRS use timestamp flag */ #endif -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS extern uschar *srs_recipient; /* SRS recipient */ #endif extern BOOL strict_acl_vars; /* ACL variables have to be set before being used */ diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index 17aad2e4b..f6cfcb14c 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -174,6 +174,9 @@ due to conflicts with other common macros. */ #ifdef SUPPORT_SOCKS builtin_macro_create(US"_HAVE_SOCKS"); #endif +#if defined(SUPPORT_SRS) + builtin_macro_create(US"_HAVE_NATIVE_SRS"); /* beware clash with _HAVE_SRS */ +#endif #ifdef TCP_FASTOPEN builtin_macro_create(US"_HAVE_TCP_FASTOPEN"); #endif @@ -183,12 +186,9 @@ due to conflicts with other common macros. */ #ifdef SUPPORT_SPF builtin_macro_create(US"_HAVE_SPF"); #endif -#if defined(EXPERIMENTAL_SRS_ALT) || defined(EXPERIMENTAL_SRS_NATIVE) +#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS) builtin_macro_create(US"_HAVE_SRS"); #endif -#if defined(EXPERIMENTAL_SRS_NATIVE) - builtin_macro_create(US"_HAVE_NATIVE_SRS"); /* beware clash with _HAVE_SRS */ -#endif #ifdef EXPERIMENTAL_ARC builtin_macro_create(US"_HAVE_ARC"); #endif diff --git a/test/scripts/4620-SRS/REQUIRES b/test/scripts/4620-SRS/REQUIRES index 7286713d6..a32fd44f6 100644 --- a/test/scripts/4620-SRS/REQUIRES +++ b/test/scripts/4620-SRS/REQUIRES @@ -1,2 +1,2 @@ -support Experimental_SRS +support SRS feature _HAVE_NATIVE_SRS -- 2.30.2