Hi All
Wondering if there’s a way to pass an unencrypted connections traffic to an alternative location if a client does not SSL/TLS with the stunnel server?
So considering stunnel running as a server to wrap an unencrypted SMTP server. If the SMTP client/server talks SSL/TLS all is good and as expected. If the client tries to talk without encryption it gets disconnect.
Is there any way to send this traffic elsewhere rather than disconnecting the client? So that stunnel is adding an SSL/TLS option to a service rather than enforcing it. Splitting the traffic to destination servers based on if the client was encrypted or not.
Thoughts?
Thanks
Mark
On Thu, Feb 02, 2017 at 09:54:38PM +0000, Mark Boyce wrote:
Hi All
Wondering if there’s a way to pass an unencrypted connections traffic to an alternative location if a client does not SSL/TLS with the stunnel server?
So considering stunnel running as a server to wrap an unencrypted SMTP server. If the SMTP client/server talks SSL/TLS all is good and as expected. If the client tries to talk without encryption it gets disconnect.
Is there any way to send this traffic elsewhere rather than disconnecting the client? So that stunnel is adding an SSL/TLS option to a service rather than enforcing it. Splitting the traffic to destination servers based on if the client was encrypted or not.
stunnel itself cannot do this; one might write a trivial wrapper to do it, but I believe that there might be a larger problem here.
You mention SMTP. Doesn't the SMTP protocol *require* the server to send its banner (220 Hi there, I'm an SMTP server, who are you?) before the client sends its first command? I think that there are servers that actually enforce this requirement for spam control - some spambots are dumb enough to just open a TCP connection and blast a series of SMTP commands without waiting for the server's greeting (to save on round-trip times and such), and some servers deliberately delay their 220 greeting for a little while and immediately reject the connection if the client tries to talk to them before that.
So, um, how does the redirector know whether this is an SSL/TLS client or not if the server has to send its greeting first? :) Of course, one could do something like "wait for a second or two, see if the client starts an SSL/TLS session; if not, pass it on to the unencrypted server thing", but this will fail badly if the connection has a really high latency or the client machine is badly overloaded so that it doesn't send its SSL/TLS Client Hello in time, and it would also enforce an additional delay on *every* unencrypted connection.
G'luck, Peter
Hi Peter & all
I’ve only been looking at stunnnel a short while but looking at a simple server setup it appears to do the following;
Scenario 1 Client connects on SSL - stream is forwarded as unencrypted
Scenario 2 Client connects unencrypted and does / offers STARTTLS - stream is forwarded as unencrypted
Scenario 3 Client connects unencrypted and does NOT do or offer a STARTTLS - server disconnects
Scenario 1 & 2 work with stunnel as intended. What I’m looking to do is make scenario 3 connect to an alternative location rather than disconnect.
So looking at SMTP the disconnection seems to be when a client connects unencrypted and does a helo/ehelo which doesn’t end in STARTTLS.
What I’ve not managed to find yet is the point in the code where stunnel establishes the connection to the real server and if that is already connected by the time stunnel makes its disconnection decision.
Mark
On 3 Feb 2017, at 08:40, Peter Pentchev roam@ringlet.net wrote:
On Thu, Feb 02, 2017 at 09:54:38PM +0000, Mark Boyce wrote:
Hi All
Wondering if there’s a way to pass an unencrypted connections traffic to an alternative location if a client does not SSL/TLS with the stunnel server?
So considering stunnel running as a server to wrap an unencrypted SMTP server. If the SMTP client/server talks SSL/TLS all is good and as expected. If the client tries to talk without encryption it gets disconnect.
Is there any way to send this traffic elsewhere rather than disconnecting the client? So that stunnel is adding an SSL/TLS option to a service rather than enforcing it. Splitting the traffic to destination servers based on if the client was encrypted or not.
stunnel itself cannot do this; one might write a trivial wrapper to do it, but I believe that there might be a larger problem here.
You mention SMTP. Doesn't the SMTP protocol *require* the server to send its banner (220 Hi there, I'm an SMTP server, who are you?) before the client sends its first command? I think that there are servers that actually enforce this requirement for spam control - some spambots are dumb enough to just open a TCP connection and blast a series of SMTP commands without waiting for the server's greeting (to save on round-trip times and such), and some servers deliberately delay their 220 greeting for a little while and immediately reject the connection if the client tries to talk to them before that.
So, um, how does the redirector know whether this is an SSL/TLS client or not if the server has to send its greeting first? :) Of course, one could do something like "wait for a second or two, see if the client starts an SSL/TLS session; if not, pass it on to the unencrypted server thing", but this will fail badly if the connection has a really high latency or the client machine is badly overloaded so that it doesn't send its SSL/TLS Client Hello in time, and it would also enforce an additional delay on *every* unencrypted connection.
G'luck, Peter
-- Peter Pentchev roam@ringlet.net roam@FreeBSD.org pp@storpool.com PGP key: http://people.FreeBSD.org/~roam/roam.key.asc Key fingerprint 2EE7 A7A5 17FC 124C F115 C354 651E EFB0 2527 DF13
Mark
On Fri, Feb 03, 2017 at 09:47:10AM +0000, Mark Boyce wrote: [formatting fixed; top-posting is not the best way to carry out a conversation]
On 3 Feb 2017, at 08:40, Peter Pentchev roam@ringlet.net wrote:
On Thu, Feb 02, 2017 at 09:54:38PM +0000, Mark Boyce wrote:
Hi All
Wondering if there’s a way to pass an unencrypted connections traffic to an alternative location if a client does not SSL/TLS with the stunnel server?
So considering stunnel running as a server to wrap an unencrypted SMTP server. If the SMTP client/server talks SSL/TLS all is good and as expected. If the client tries to talk without encryption it gets disconnect.
Is there any way to send this traffic elsewhere rather than disconnecting the client? So that stunnel is adding an SSL/TLS option to a service rather than enforcing it. Splitting the traffic to destination servers based on if the client was encrypted or not.
stunnel itself cannot do this; one might write a trivial wrapper to do it, but I believe that there might be a larger problem here.
You mention SMTP. Doesn't the SMTP protocol *require* the server to send its banner (220 Hi there, I'm an SMTP server, who are you?) before the client sends its first command? I think that there are servers that actually enforce this requirement for spam control - some spambots are dumb enough to just open a TCP connection and blast a series of SMTP commands without waiting for the server's greeting (to save on round-trip times and such), and some servers deliberately delay their 220 greeting for a little while and immediately reject the connection if the client tries to talk to them before that.
So, um, how does the redirector know whether this is an SSL/TLS client or not if the server has to send its greeting first? :) Of course, one could do something like "wait for a second or two, see if the client starts an SSL/TLS session; if not, pass it on to the unencrypted server thing", but this will fail badly if the connection has a really high latency or the client machine is badly overloaded so that it doesn't send its SSL/TLS Client Hello in time, and it would also enforce an additional delay on *every* unencrypted connection.
Hi Peter & all
I’ve only been looking at stunnnel a short while but looking at a simple server setup it appears to do the following;
Scenario 1 Client connects on SSL - stream is forwarded as unencrypted
Scenario 2 Client connects unencrypted and does / offers STARTTLS - stream is forwarded as unencrypted
Scenario 3 Client connects unencrypted and does NOT do or offer a STARTTLS - server disconnects
Scenario 1 & 2 work with stunnel as intended. What I’m looking to do is make scenario 3 connect to an alternative location rather than disconnect.
Oh, I did not realize that you were using stunnel with "protocol smtp". This does change things a bit :)
OK, before going into details, let me first ask something: why are you actually doing this? What exactly is the setup that you're trying to use stunnel in?
- you have an SMTP server that supposedly does not understand STARTTLS; what kind of server is this, and do you really need to use it instead of another implementation?
- you have an SMTP client that knows how to use STARTTLS; good!
- you have another SMTP client that does not know how to use STARTTLS; do you really need to support that? Is it a mail user agent trying to send a message out into the world through a local SMTP forwarder, or is it a random SMTP server from the Internet trying to have a message delivered to your server? Well, if it's the latter, then yeah, there might still be servers out there that don't necessarily do STARTTLS.
So I guess it all boils down to "are you really sure that you cannot run an SMTP server that handles STARTTLS by itself?"
So looking at SMTP the disconnection seems to be when a client connects unencrypted and does a helo/ehelo which doesn’t end in STARTTLS.
What I’ve not managed to find yet is the point in the code where stunnel establishes the connection to the real server and if that is already connected by the time stunnel makes its disconnection decision.
OK, if you're interested in the stunnel code, this interaction happens in the protocol() and smtp_server() functions in src/protocol.c, invoked by the client_try() function in src/client.c.
If you're interested in how things actually happen: - the SMTP client connects to the stunnel server - stunnel immediately establishes an unencrypted connection to the real SMTP server so that it may forward the greeting (see below for the EHLO options discussion) - stunnel waits a little bit to check if the client will actually start a TLS session... erm, yeah, it seems that stunnel actually does what I wrote above might fail on high-latency connections; apparently this doesn't happen so often in the real world :) - if the client does send anything, the smtp_server() function assumes that this "anything" is a TLS Client Hello message, skips the STARTTLS negotiation altogether and lets stunnel do its TLS negotiation and normal forwarding - if the client does NOT send anything, smtp_server() assumes that this is an SMTP client that is really trying to establish an unencrypted connection first and then send STARTTLS. Now stunnel reads the SMTP server's greeting, replaces the first line a little bit to announce its own STARTTLS capability, and sends it to the client. - the client now sends its own EHLO, stunnel swallows it, ignoring its actual contents (no need to forward it to the server, the client will send another EHLO after the TLS session is established) - the client now sends the STARTTLS command... or if it doesn't, stunnel aborts the connection - if the client does indeed send a STARTTLS command, smtp_server() says "great, everything is fine now, let's go to the actual TLS negotiation phase!" and stunnel goes into its real work mode - negotiate TLS, then forward between the encrypted and the unencrypted connections
So... What you want to do is modify stunnel's behavior in the next-to-last point, the "if it doesn't, stunnel aborts the connection" step. Well, as I said before, stunnel itself cannot do that - it's written to always forward between an encrypted and an unencrypted connection. It might be possible to write another wrapper, a program that listens in front of stunnel and does something like:
- wait for a client connection - establish a connection to stunnel - wait for either the client or stunnel to say something - if the first thing received from the client is a TLS Client Hello message, just forward everything between the two - if stunnel says something first, read its 220 greeting (the one that stunnel, in its turn, forwarded from the real SMTP server behint it), and echo it to the client - read the client's EHLO, forward it to stunnel, but also remember it - read stunnel's "250 STARTTLS" response, forward it to the client - read the client's next command... - if it is a STARTTLS command, forward it to stunnel and then just keep forwarding everything between the two - if it is not a STARTTLS command, then close the connection to stunnel and, well, here comes the tricky part: - establish a new connection to a real SMTP server (either the same one that sits behind stunnel or another one) - wait for the server's greeting - send the remembered client EHLO to the server - wait for the server's "250 OK" response - send the client's command (the one that was not STARTTLS) to the server - just keep forwarding everything between the two
Now, there is at least one problem with that: if the server that you're forwarding to is not the same as the one that stunnel will forward the encrypted connection to, then the two servers may have different capabilities announced in their 220 banners, and the client's EHLO as sent to the server behind stunnel might not be the same EHLO that the client would've sent to the other server. Even worse, the server behind stunnel might have advertised some SMTP options that the other server may not support, and the client will try to use them with potentially disastrous consequences (most probably failed attempts to send a message, but also possibly "almost successful" attempts to send *mangled* messages, which would be way worse).
In theory, I might be able to write such a forwarder in a couple of days; however, I cannot give you any guarantees as to exactly when it'll be ready, and there remains the problem of the mismatched capabilities if the two real SMTP servers are different.
G'luck, Peter