[openssl-users] Close TCP socket after SSL_clear()?
Charles Mills
charlesm at mcn.org
Mon Jan 14 19:08:32 UTC 2019
Thanks @Michael. I read up on TIME_WAIT Assassination.
I think that sort of thing may have been the problem I was trying to fix.
After an "error" disconnection, the customer was reporting that their client
could not re-connect. I had trouble getting good traces out of the customer,
but I suspect the problem was that the underlying TCP connection was still
hanging.
I have never in my life touched SO_LINGER. There is no socket duplication,
fork(), or the like.
Thanks again,
Charles
-----Original Message-----
From: openssl-users [mailto:openssl-users-bounces at openssl.org] On Behalf Of
Michael Wojcik
Sent: Saturday, January 12, 2019 6:20 AM
To: openssl-users at openssl.org
Subject: Re: [openssl-users] Close TCP socket after SSL_clear()?
> From: openssl-users [mailto:openssl-users-bounces at openssl.org] On Behalf
Of
> Charles Mills
> Sent: Friday, January 11, 2019 17:06
>
> > SSL_shutdown(connection) || SSL_shutdown(connection);
>
> I like it! (Not!)
>
> I don't pretend to be a bits and bytes expert on TCP protocol. You can't
be
> an expert on everything.
>
> So I will listen to expert advice. I know 99% of you all are 'nix guys and
> this is a Windows problem. I am seeing OTOH where my Windows doc says
> closesocket() does an abortive termination, and OTOH a discussion of a
> graceful closesocket() with SO_LINGER/SO_DONTLINGER.
>
> (1) This code is (at the application level) purely a receiver of data and
> (2) without the TLS layer in place it is hard to picture any meaningful
data
> transfer and (3) we are in a session cleanup situation anyway -- so it
seems
> to me that an abortive disconnect is perfectly fine. Am I wrong?
Yes, you're wrong. You don't want an abortive disconnect.
A TCP connection can be closed in four (or five) ways:
1. Normal close, which involves the FIN / FIN-ACK / ACK sequence. When the
last ACK is received, both sides know that all data has been received by the
peer stack, and at the point when the corresponding ACK was generated, the
peer "believed" it would be able to deliver the data to the application
eventually. (That is, the stack hadn't been informed that the application's
identifier for the connection - the socket - had been closed.)
2. Abortive close, which involves a RST from one side to the peer, and
that's it. RST is a one-way, unacknowledged flow. There are a number of
reasons why it's undesirable, some of which I'll go into below.
3. Abortive close due to network management message: the stack receives an
ICMP message indicating a packet could not be delivered, such as
HOST_UNREACH. From the application's point of view, the result is similar to
#2, except for the particular error code it sees.
4. Timeout from TCP retransmit, either for an application send or, if it's
enabled, TCP keepalive.
5. Arguably a separate case: 1-3 but generated by a middlebox, such as as a
router, or an application firewall. In other words, the connection is forced
closed by someone spoofing the peer. From the application's point of view,
that makes no difference.
Applications should almost never use an abortive close. TCP is intended to
be a reliable (best-effort) stream transport, and it can only meet its
(already weak) service guarantees if you let it acknowledge all application
data and close the conversation cleanly.
Now, when you have a higher-level conversation protocol such as TLS, and the
higher-level protocol has already negotiated end-of-conversation, that may
not seem important; the peers have agreed that they're not going to send
anything more. That assumes, however, that the peers are well-behaved. And
it is at the very least notionally cleaner to let the conversation close
normally.
Beyond that, an abortive close can cause TIME_WAIT Assassination, which is a
Bad Thing. If you don't know what TIME_WAIT Assassination is, that's a sign
you shouldn't be doing abortive closes. Don't invoke extraordinary behavior
you don't understand.
Now, all that said: Winsock closesocket will NOT do an abortive disconnect
if you have not mucked with the SO_LINGER socket option (which you should
not do unless you understand TCP). I don't know what documentation you saw
that claims otherwise, but it's wrong.
Calling shutdown before closesocket won't hurt anything, but (if you use the
pattern that we've discussed in this thread) won't do anything useful
either, in most cases.
One case I forgot in my previous discussion: It's worth remembering that
close/closesocket operates on a single reference to the connection, while
shutdown operates on the connection itself. That is, the logic for
close/closesocket is notionally something like this:
close the descriptor/handle
decrement the conversation's reference count
if the reference count is 0
if connection is still open for sending
shutdown(SHUT_WR)
if connection is still open for receiving
shutdown(SHUT_RD)
In the case where you have multiple descriptors or handles for a
conversation - for example due to dup'ing a socket or forking on UNIX, or
duplicating a handle (possibly into a different process) on Windows - then
close/closesocket won't do the shutdown-equivalent until they have *all*
been closed. An explicit shutdown, on the other hand, doesn't close any of
the descriptors/handles, but it does send a FIN (for SHUT_WR) or flush
inbound data and refuse to receive any more (for SHUT_RD) on the
conversation, which of course affects all descriptors/handles.
So if your application creates multiple references to the conversation, then
depending on your design, you might want the shutdown. Or you might not, if
you want the shutdown-on-last-close semantics. Neither option is correct for
all applications.
More information about the openssl-users
mailing list