SSL+ProxyProtocol: Fix connection hang when a header-only packet is received

James Hamlin jfhamlin at cotap.com
Mon Mar 2 19:27:42 UTC 2015


Hi, Roman,

On Mon, Mar 2, 2015 at 10:36 AM, Roman Arutyunyan <arut at nginx.com> wrote:
> Hello James,
>
> On Sun, Mar 01, 2015 at 06:24:28PM -0800, James Hamlin wrote:
>> # HG changeset patch
>> # User James Hamlin <jfhamlin at gmail.com>
>> # Date 1425260813 28800
>> #      Sun Mar 01 17:46:53 2015 -0800
>> # Branch fix-deferred-with-proxy-protocol
>> # Node ID 3835928c9e046bab0f6bc8d35d3ede468b6a07ce
>> # Parent  6a7c6973d6fc3b628b38e000f0ed192c99bdfc49
>> SSL+ProxyProtocol: Fix conn. hang when header-only packet received
>>
>> This is a fix for a bug exposed when using deferred accept, SSL, and the proxy
>> protocol.
>>
>> When accept deferral is enabled (the "deferred" option on "listen"
>> directives), the "ready" bit is preemptively set on the connection's "read"
>> event. If the data first received contains _only_ the proxy protocol header,
>> then the "ready" bit will not be cleared by the call to ngx_recv(), since the
>> call does not attempt to read more than the header itself. If the first byte
>> from the client has not been received by the time the posted event is run, the
>> call to ngx_handle_read_event will do nothing, as "ready" will still be set,
>> and the connection will time out despite later receipt of the bytes.
>>
>> The fix is to clear the "ready" bit from within ngx_http_ssl_handshake when
>> it is known that only the header was available.
>>
>> This is not a problem when using KQUEUE, as the "ready" bit is cleared based
>> on available byte tracking.
>>
>> diff -r 6a7c6973d6fc -r 3835928c9e04 src/http/ngx_http_request.c
>> --- a/src/http/ngx_http_request.c Fri Feb 27 16:28:31 2015 +0300
>> +++ b/src/http/ngx_http_request.c Sun Mar 01 17:46:53 2015 -0800
>> @@ -691,6 +691,12 @@
>>          c->log->action = "SSL handshaking";
>>
>>          if (n == (ssize_t) size) {
>> +#if (NGX_HAVE_KQUEUE)
>> +            if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) == 0)
>> +#endif
>> +            {
>> +                rev->ready = 0;
>> +            }
>>              ngx_post_event(rev, &ngx_posted_events);
>>              return;
>>          }
>
> Thanks for reporting the issue.
> We've committed a slightly different solution for this.

Thanks for the quick resolution with the improved fix! I wasn't aware
of TCP_DEFER_ACCEPT expiration; very good to know.

Cheers,
James



More information about the nginx-devel mailing list