SSL FD Leak
Igor Sysoev
is at rambler-co.ru
Fri Jan 4 11:43:43 MSK 2008
On Sun, Dec 30, 2007 at 05:55:51PM -0500, Ben Maurer wrote:
> Ben Maurer wrote:
> >Ben Maurer wrote:
> >>Hi,
> >>
> >>On a server that has quite a few SSL connections, I started to notice
> >>that FDs were leaking. I set the load balancer in front of nginx to
> >>stop sending new requests to one server for a few minutes (to let the
> >>keepalive time expire) and found that there were a few thousand FDs
> >>open. netstat says that there are many sockets in the CLOSE_WAIT and
> >>ESTABLISHED state for the SSL server. Many of them have data in
> >>receive queue.
> >>
> >>Any ideas what might cause this? This is an up-to-date 0.5.x install.
> >
> >Some progress on debugging this -- it may have to to do with the
> >deferred setting.
> >
> >I've managed to get straces like this:
> >
> >accept(6, {sa_family=AF_INET, sin_port=htons(35327),
> >sin_addr=inet_addr("127.0.0.1")}, [16]) = 92
> >ioctl(92, FIONBIO, [1]) = 0
> >recv(92, 0xbf9c6c2b, 1, MSG_PEEK) = -1 EAGAIN (Resource
> >temporarily unavailable)
> >
> >by using:
> >
> >ab -c500 -n2000 https://localhost:8095/
> >
> >and aborting in the middle. It seems that these straces are the ones
> >that result in leaked FDs. The trace really doesn't make much sense to
> >me. Deferred accept promises that the socket only goes into accept once
> >it has data or if it's ready to be closed. Neither of these should
> >result in an EAGAIN. Regardless, it seems the problem is that the FD
> >never gets added to epoll at this point.
>
> It seems like commenting out the check for HTTP requests on the socket
> made everything work. There's probably a way to do this more correctly
> (eg, get the event added back into the epoll structure). With that said,
> maybe it'd be possible to avoid the MSG_PEEK call completely. Openssl is
> good at detecting this error:
>
> 2007/12/30 17:16:43 [crit] 18303#0: *2 SSL_do_handshake() failed (SSL:
> error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request) while
> reading client request line, client: 127.0.0.1, server: warp10
>
> The only disadvantage to doing this is that currently, nginx seems to
> wait until the header has been fully parsed to send an error. However,
> the client wouldn't be able to notice a difference unless:
>
> 1. The initial request didn't fit in a single write() (it'd have to be a
> few KB for this to happen)
> 2. It was super-picky about getting input before output.
>
> Given that this is a rare error condition anyways, it doesn't seem worth
> the extra system call to handle this case...
Yes, OpenSSL detects plain HTTP request, however, the request is lost,
so nginx uses MSG_PEEK to test SSL handshake message.
This allows to redirect a plain request to HTTPS using special 497 code:
error_page 497 = https://$host$request_uri redirect;
create custom error_page, log it, etc.
--
Igor Sysoev
http://sysoev.ru/en/
More information about the nginx
mailing list