commit 6fdf76d0eae42ce4507fe317f095572100c5d6b8 Author: Jeremy Harris Date: Mon Mar 13 00:43:01 2023 +0000 SNI for ${readsocket } diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 0ba62ce5e..bdc0eb30e 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -10495,6 +10495,11 @@ Defines whether or not a write-shutdown is done on the connection after sending the request. Values are &"yes"& (the default) or &"no"& (preferred, eg. by some webservers). +.next +&*sni*& +Controls the use of Server Name Identification on the connection. +Any nonempty value will be the SNI sent; TLS will be forced. + .next &*tls*& Controls the use of TLS on the connection. diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index d12246e03..84db8ea58 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -29,6 +29,8 @@ Version 4.97 10. A commandline option to print just the message IDs of the queue + 11. An option for the ${readsocket } expansion to set an SNI for TLS. + Version 4.96 ------------ diff --git a/src/src/functions.h b/src/src/functions.h index 5fbb426ec..896122a69 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -54,6 +54,8 @@ extern uschar * tls_cert_fprt_sha256(void *); extern void tls_clean_env(void); extern BOOL tls_client_start(client_conn_ctx *, smtp_connect_args *, void *, tls_support *, uschar **); +extern BOOL tls_client_adjunct_start(host_item *, client_conn_ctx *, + const uschar *, uschar **); extern void tls_client_creds_reload(BOOL); extern void tls_close(void *, int); diff --git a/src/src/lookups/readsock.c b/src/src/lookups/readsock.c index b1ea42c7f..a3f87108a 100644 --- a/src/src/lookups/readsock.c +++ b/src/src/lookups/readsock.c @@ -13,7 +13,7 @@ static int internal_readsock_open(client_conn_ctx * cctx, const uschar * sspec, - int timeout, BOOL do_tls, uschar ** errmsg) + int timeout, uschar * do_tls, uschar ** errmsg) { const uschar * server_name; host_item host; @@ -116,27 +116,8 @@ else #ifndef DISABLE_TLS if (do_tls) - { - union sockaddr_46 interface_sock; - EXIM_SOCKLEN_T size = sizeof(interface_sock); - smtp_connect_args conn_args = {.host = &host }; - tls_support tls_dummy = { .sni = NULL }; - uschar * errstr; - - if (getsockname(cctx->sock, (struct sockaddr *) &interface_sock, &size) == 0) - conn_args.sending_ip_address = host_ntoa(-1, &interface_sock, NULL, NULL); - else - { - *errmsg = string_sprintf("getsockname failed: %s", strerror(errno)); + if (!tls_client_adjunct_start(&host, cctx, do_tls, errmsg)) goto bad; - } - - if (!tls_client_start(cctx, &conn_args, NULL, &tls_dummy, &errstr)) - { - *errmsg = string_sprintf("TLS connect failed: %s", errstr); - goto bad; - } - } #endif DEBUG(D_expand|D_lookup) debug_printf_indent(" connected to socket %s\n", sspec); @@ -187,8 +168,8 @@ client_conn_ctx * cctx = handle; int sep = ','; struct { BOOL do_shutdown:1; - BOOL do_tls:1; BOOL cache:1; + uschar * do_tls; /* NULL, empty-string, or SNI */ } lf = {.do_shutdown = TRUE}; uschar * eol = NULL; int timeout = 5; @@ -207,8 +188,10 @@ if (opts) for (uschar * s; s = string_nextinlist(&opts, &sep, NULL, 0); ) else if (Ustrncmp(s, "shutdown=", 9) == 0) lf.do_shutdown = Ustrcmp(s + 9, "no") != 0; #ifndef DISABLE_TLS - else if (Ustrncmp(s, "tls=", 4) == 0 && Ustrcmp(s + 4, US"no") != 0) - lf.do_tls = TRUE; + else if (Ustrncmp(s, "tls=", 4) == 0 && Ustrcmp(s + 4, US"no") != 0 && !lf.do_tls) + lf.do_tls = US""; + else if (Ustrncmp(s, "sni=", 4) == 0) + lf.do_tls = s + 4; #endif else if (Ustrncmp(s, "eol=", 4) == 0) eol = string_unprinting(s + 4); diff --git a/src/src/tls.c b/src/src/tls.c index ba7c2de38..825313a9a 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -852,6 +852,57 @@ DEBUG(D_tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index); #endif } + + +/* Start TLS as a client for an ajunct connection, eg. readsocket +Return boolean success. +*/ + +BOOL +tls_client_adjunct_start(host_item * host, client_conn_ctx * cctx, + const uschar * sni, uschar ** errmsg) +{ +union sockaddr_46 interface_sock; +EXIM_SOCKLEN_T size = sizeof(interface_sock); +smtp_connect_args conn_args = {.host = host }; +tls_support tls_dummy = { .sni = NULL }; +uschar * errstr; + +if (getsockname(cctx->sock, (struct sockaddr *) &interface_sock, &size) == 0) + conn_args.sending_ip_address = host_ntoa(-1, &interface_sock, NULL, NULL); +else + { + *errmsg = string_sprintf("getsockname failed: %s", strerror(errno)); + return FALSE; + } + +/* To handle SNI we need to emulate more of a real transport because the +base tls code assumes that is where the SNI string lives. */ + +if (*sni) + { + transport_instance * tb; + smtp_transport_options_block * ob; + + conn_args.tblock = tb = store_get(sizeof(*tb), GET_UNTAINTED); + memset(tb, 0, sizeof(*tb)); + + tb->options_block = ob = store_get(sizeof(*ob), GET_UNTAINTED); + memcpy(ob, &smtp_transport_option_defaults, sizeof(*ob)); + + ob->tls_sni = sni; + } + +if (!tls_client_start(cctx, &conn_args, NULL, &tls_dummy, &errstr)) + { + *errmsg = string_sprintf("TLS connect failed: %s", errstr); + return FALSE; + } +return TRUE; +} + + + #endif /*!DISABLE_TLS*/ #endif /*!MACRO_PREDEF*/ diff --git a/test/confs/1149 b/test/confs/1149 index 737753109..dfe5b33cb 100644 --- a/test/confs/1149 +++ b/test/confs/1149 @@ -13,4 +13,6 @@ tls_advertise_hosts = * tls_certificate = DIR/aux-fixed/cert1 tls_privatekey = DIR/aux-fixed/cert1 +acl_smtp_helo = accept logwrite = HELO <$sender_helo_name> SNI <$tls_in_sni> + # End diff --git a/test/log/1149 b/test/log/1149 index bc6ac7f77..efcef1b23 100644 --- a/test/log/1149 +++ b/test/log/1149 @@ -1,3 +1,4 @@ ******** SERVER ******** 1999-03-02 09:44:33 exim x.yz daemon started: pid=p1234, no queue runs, listening for SMTPS on port PORT_D +1999-03-02 09:44:33 HELO SNI diff --git a/test/scripts/1100-Basic-TLS/1149 b/test/scripts/1100-Basic-TLS/1149 index 501a9c9da..29702b049 100644 --- a/test/scripts/1100-Basic-TLS/1149 +++ b/test/scripts/1100-Basic-TLS/1149 @@ -8,6 +8,7 @@ exim -DSERVER=server -tls-on-connect -bd -oX PORT_D millisleep 500 exim -be 1 >>${readsocket{inet:thisloop:PORT_D}{QUIT\n}{2s:tls=yes}}<< +2 >>${readsocket{inet:thisloop:PORT_D}{EHLO tester\n}{1s:tls=yes:sni=fubar}}<< **** millisleep 500 # diff --git a/test/stdout/1149 b/test/stdout/1149 index a3eab5117..c67e31cfe 100644 --- a/test/stdout/1149 +++ b/test/stdout/1149 @@ -1,4 +1,5 @@ > 1 >>220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 221 myhost.test.ex closing connection << +> Failed: socket read timed out >