]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: dns: Properly handle error when a response consumed
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 30 Mar 2023 13:49:30 +0000 (15:49 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 5 Apr 2023 06:57:05 +0000 (08:57 +0200)
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

index 839c41f82c53727fcd2521d0591d03e1f85ee198..23f423f0514e057da69210a7051451c3ccd168d0 100644 (file)
--- 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);