From 28975e1e1012e4a009b4208f3fc022ea2bfb8b82 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 30 Mar 2023 15:49:30 +0200 Subject: [PATCH] BUG/MEDIUM: dns: Properly handle error when a response consumed When a response is consumed, result for co_getblk() is never checked. It seems ok because amount of output data is always checked first. But There is an issue when we try to get the first 2 bytes to read the message length. If there is only one byte followed by a shutdown, the applet ignore the shutdown and loop till the timeout to get more data. So to avoid any issue and improve shutdown detection, the co_getblk() return value is always tested. In addition, if there is not enough data, the applet explicitly ask for more data by calling applet_need_more_data(). This patch relies on the previous one: * BUG/MEDIUM: channel: Improve reports for shut in co_getblk() Both should be backported as far as 2.4. On 2.5 and 2.4, applet_need_more_data() must be replaced by si_rx_endp_more(). --- src/dns.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/dns.c b/src/dns.c index 839c41f82..23f423f05 100644 --- a/src/dns.c +++ b/src/dns.c @@ -661,30 +661,35 @@ read: struct dns_query *query; if (!ds->rx_msg.len) { - /* next message len is not fully available into the channel */ - if (co_data(sc_oc(sc)) < 2) - break; - /* retrieve message len */ - co_getblk(sc_oc(sc), (char *)&msg_len, 2, 0); + ret = co_getblk(sc_oc(sc), (char *)&msg_len, 2, 0); + if (ret <= 0) { + if (ret == -1) + goto close; + applet_need_more_data(appctx); + break; + } /* mark as consumed */ co_skip(sc_oc(sc), 2); /* store message len */ ds->rx_msg.len = ntohs(msg_len); - } - - if (!co_data(sc_oc(sc))) { - /* we need more data but nothing is available */ - break; + if (!ds->rx_msg.len) + continue; } if (co_data(sc_oc(sc)) + ds->rx_msg.offset < ds->rx_msg.len) { /* message only partially available */ /* read available data */ - co_getblk(sc_oc(sc), ds->rx_msg.area + ds->rx_msg.offset, co_data(sc_oc(sc)), 0); + ret = co_getblk(sc_oc(sc), ds->rx_msg.area + ds->rx_msg.offset, co_data(sc_oc(sc)), 0); + if (ret <= 0) { + if (ret == -1) + goto close; + applet_need_more_data(appctx); + break; + } /* update message offset */ ds->rx_msg.offset += co_data(sc_oc(sc)); @@ -693,13 +698,20 @@ read: co_skip(sc_oc(sc), co_data(sc_oc(sc))); /* we need to wait for more data */ + applet_need_more_data(appctx); break; } /* enough data is available into the channel to read the message until the end */ /* read from the channel until the end of the message */ - co_getblk(sc_oc(sc), ds->rx_msg.area + ds->rx_msg.offset, ds->rx_msg.len - ds->rx_msg.offset, 0); + ret = co_getblk(sc_oc(sc), ds->rx_msg.area + ds->rx_msg.offset, ds->rx_msg.len - ds->rx_msg.offset, 0); + if (ret <= 0) { + if (ret == -1) + goto close; + applet_need_more_data(appctx); + break; + } /* consume all data until the end of the message from the channel */ co_skip(sc_oc(sc), ds->rx_msg.len - ds->rx_msg.offset);