Skip to content

Commit f0fabd5

Browse files
committed
bugfix: setkeepalive failure on TLSv1.3
When TLSv1.3 is used, the server may send a NewSessionTicket message after the handshake. While this message is ssl-layer data, `tcpsock:sslhandshake` does not consume it. In the implementation of `setkeepalive`, `recv` is used to confirm the connection is still open and there is no unread data in the buffer. But it treats the NewSessionTicket message as application layer data and then `setkeepalive` fails with this error `connection in dubious state`. In fact we don't need to peek here, because if the application data is read successfully then the connection is going to be closed anyway. Therefore, `c->recv` can be used instead which will consume the ssl-layer data implicitly.
1 parent 69f0cd7 commit f0fabd5

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

src/ngx_stream_lua_socket_tcp.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5596,7 +5596,7 @@ ngx_stream_lua_socket_keepalive_close_handler(ngx_event_t *ev)
55965596

55975597
int n;
55985598
int err;
5599-
char buf[1];
5599+
unsigned char buf[1];
56005600
ngx_connection_t *c;
56015601

56025602
c = ev->data;
@@ -5618,20 +5618,10 @@ ngx_stream_lua_socket_keepalive_close_handler(ngx_event_t *ev)
56185618
"stream lua tcp socket keepalive close handler "
56195619
"check stale events");
56205620

5621-
n = recv(c->fd, buf, 1, MSG_PEEK);
5622-
err = ngx_socket_errno;
5623-
#if (NGX_STREAM_SSL)
5624-
/* ignore ssl protocol data like change cipher spec */
5625-
if (n == 1 && c->ssl != NULL) {
5626-
n = c->recv(c, (unsigned char *) buf, 1);
5627-
if (n == NGX_AGAIN) {
5628-
n = -1;
5629-
err = NGX_EAGAIN;
5630-
}
5631-
}
5632-
#endif /* NGX_STREAM_SSL */
5621+
/* consume the possible ssl-layer data implicitly */
5622+
n = c->recv(c, buf, 1);
56335623

5634-
if (n == -1 && err == NGX_EAGAIN) {
5624+
if (n == NGX_AGAIN) {
56355625
/* stale event */
56365626

56375627
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {

t/058-tcp-socket.t

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use Test::Nginx::Socket::Lua::Stream;
44

55
repeat_each(2);
66

7-
plan tests => repeat_each() * 221;
7+
plan tests => repeat_each() * 224;
88

99
our $HtmlDir = html_dir;
1010

1111
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
1212
$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8';
13+
$ENV{TEST_NGINX_HTML_DIR} ||= html_dir();
1314

1415
#log_level 'warn';
1516
log_level 'debug';
@@ -3545,3 +3546,58 @@ lua tcp socket calling receiveany() method to read at most 7 bytes
35453546
35463547
--- error_log
35473548
shutdown on a not connected socket: closed
3549+
3550+
3551+
3552+
=== TEST 68: setkeepalive with TLSv1.3
3553+
--- skip_openssl: 3: < 1.1.1
3554+
--- stream_config
3555+
server {
3556+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
3557+
ssl_certificate ../../cert/test_ecdsa.crt;
3558+
ssl_certificate_key ../../cert/test_ecdsa.key;
3559+
ssl_protocols TLSv1.3;
3560+
content_by_lua_block {
3561+
local sock = assert(ngx.req.socket(true))
3562+
local data
3563+
while true do
3564+
data = assert(sock:receive())
3565+
assert(data == "hello")
3566+
end
3567+
}
3568+
}
3569+
--- stream_server_config
3570+
lua_ssl_protocols TLSv1.3;
3571+
content_by_lua_block {
3572+
local sock = ngx.socket.tcp()
3573+
sock:settimeout(2000)
3574+
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
3575+
if not ok then
3576+
ngx.say("failed to connect: ", err)
3577+
return
3578+
end
3579+
ngx.say("connected: ", ok)
3580+
local ok, err = sock:sslhandshake(false, nil, false)
3581+
if not ok then
3582+
ngx.say("failed to sslhandshake: ", err)
3583+
return
3584+
end
3585+
local ok, err = sock:send("hello\n")
3586+
if not ok then
3587+
ngx.say("failed to send: ", err)
3588+
return
3589+
end
3590+
-- sleep a while to make sure the NewSessionTicket message has arrived
3591+
ngx.sleep(1)
3592+
local ok, err = sock:setkeepalive()
3593+
if not ok then
3594+
ngx.say("failed to setkeepalive: ", err)
3595+
else
3596+
ngx.say("setkeepalive: ", ok)
3597+
end
3598+
}
3599+
--- stream_response
3600+
connected: 1
3601+
setkeepalive: 1
3602+
--- no_error_log
3603+
[error]

0 commit comments

Comments
 (0)