[stunnel-users] [PATCH] SMTP server with PROXY

Michał Mirosław mirq-linux at rere.qmqm.pl
Sat Apr 4 05:57:24 CEST 2020


Hi,

I've been using stunnel as a SSL frontend to an SMTP server. The server
usually has use for original client's address, so I made a patch that
adds PROXY protocol headers on backend (unwrapped) connection.

Best Regards,
Michał Mirosław

Index: stunnel4-5.56/src/protocol.c
===================================================================
--- stunnel4-5.56.orig/src/protocol.c
+++ stunnel4-5.56/src/protocol.c
@@ -58,7 +58,9 @@ NOEXPORT char *smtp_client(CLI *, SERVIC
 NOEXPORT void smtp_client_negotiate(CLI *);
 NOEXPORT void smtp_client_plain(CLI *, const char *, const char *);
 NOEXPORT void smtp_client_login(CLI *, const char *, const char *);
+NOEXPORT void smtp_server_negotiate(CLI *, char *, int);
 NOEXPORT char *smtp_server(CLI *, SERVICE_OPTIONS *, const PHASE);
+NOEXPORT char *smtp_proxy_server(CLI *, SERVICE_OPTIONS *, const PHASE);
 NOEXPORT char *pop3_client(CLI *, SERVICE_OPTIONS *, const PHASE);
 NOEXPORT char *pop3_server(CLI *, SERVICE_OPTIONS *, const PHASE);
 NOEXPORT char *imap_client(CLI *, SERVICE_OPTIONS *, const PHASE);
@@ -97,6 +99,10 @@ char *protocol(CLI *c, SERVICE_OPTIONS *
         return opt->option.client ?
             pgsql_client(c, opt, phase) :
             pgsql_server(c, opt, phase);
+    if(!strcasecmp(opt->protocol, "smtp+proxy"))
+        return opt->option.client ?
+            "The 'proxy' protocol is not supported in the client mode" :
+            smtp_proxy_server(c, opt, phase);
     if(!strcasecmp(opt->protocol, "smtp"))
         return opt->option.client ?
             smtp_client(c, opt, phase) :
@@ -837,6 +843,12 @@ NOEXPORT void smtp_client_login(CLI *c,
 NOEXPORT char *smtp_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) {
     char *line, *domain, *greeting;
 
+    if (opt->protocol_domain) {
+        if(phase==PROTOCOL_EARLY)
+            smtp_server_negotiate(c, opt->protocol_domain, 1);
+        return NULL;
+    }
+
     if(phase==PROTOCOL_CHECK)
         opt->option.connect_before_ssl=1; /* c->remote_fd needed */
     if(phase!=PROTOCOL_MIDDLE)
@@ -881,17 +893,32 @@ NOEXPORT char *smtp_server(CLI *c, SERVI
     }
     str_free(line);
 
+    smtp_server_negotiate(c, domain, 0);
+    return NULL;
+}
+
+NOEXPORT void smtp_server_negotiate(CLI *c, char *domain, int static_domain) {
+    char *line;
+
+    if (static_domain) {
+        if (!domain)
+            domain=(char *)"smtp.example.com";
+        fd_printf(c, c->local_wfd.fd, "220 %s stunnel", domain);
+    }
+
     /* process client's EHLO */
     line=fd_getline(c, c->local_rfd.fd);
     if(!is_prefix(line, "EHLO ")) {
         s_log(LOG_ERR, "Unknown client EHLO");
         str_free(line);
-        str_free(domain);
+        if (!static_domain)
+            str_free(domain);
         throw_exception(c, 1);
     }
     str_free(line);
     fd_printf(c, c->local_wfd.fd, "250-%s", domain);
-    str_free(domain);
+    if (!static_domain)
+        str_free(domain);
     fd_putline(c, c->local_wfd.fd, "250 STARTTLS");
 
     /* process client's STARTTLS */
@@ -903,7 +930,13 @@ NOEXPORT char *smtp_server(CLI *c, SERVI
     }
     fd_putline(c, c->local_wfd.fd, "220 Go ahead");
     str_free(line);
+}
 
+NOEXPORT char *smtp_proxy_server(CLI *c, SERVICE_OPTIONS *opt, const PHASE phase) {
+    if(phase==PROTOCOL_LATE)
+        return proxy_server(c, opt, phase);
+    if(phase==PROTOCOL_EARLY)
+        smtp_server_negotiate(c, opt->protocol_domain, 1);
     return NULL;
 }
 


More information about the stunnel-users mailing list