[tor-commits] [tor/master] conn: Properly close MetricsPort socket on EOF

nickm at torproject.org nickm at torproject.org
Mon Feb 8 19:28:25 UTC 2021


commit 01c4abc2d41a7d140a0c0931528fc680dcbac0ee
Author: David Goulet <dgoulet at torproject.org>
Date:   Wed Jan 27 09:34:34 2021 -0500

    conn: Properly close MetricsPort socket on EOF
    
    Handle the EOF situation for a metrics connection. Furthermore, if we failed
    to fetch the data from the inbuf properly, mark the socket as closed because
    the caller, connection_process_inbuf(), assumes that we did so on error.
    
    Fixes #40257
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 changes/ticket40257            |  3 +++
 src/core/mainloop/connection.c |  2 ++
 src/feature/metrics/metrics.c  | 21 ++++++++++++++++++---
 src/feature/metrics/metrics.h  |  1 +
 src/test/test_metrics.c        | 32 +++++++++++++++++++++++++++-----
 5 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/changes/ticket40257 b/changes/ticket40257
new file mode 100644
index 0000000000..4bcebc45a1
--- /dev/null
+++ b/changes/ticket40257
@@ -0,0 +1,3 @@
+  o Minor bugfixes (metrics port):
+    - Fix a bug warning when the socket was unexpectedly closed. Fixes bug
+      40257; bugfix on 0.4.5.1-alpha
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index 3d551c4ba8..85cdec6e1e 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -5242,6 +5242,8 @@ connection_reached_eof(connection_t *conn)
       return connection_dir_reached_eof(TO_DIR_CONN(conn));
     case CONN_TYPE_CONTROL:
       return connection_control_reached_eof(TO_CONTROL_CONN(conn));
+    case CONN_TYPE_METRICS:
+      return metrics_connection_reached_eof(conn);
     default:
       log_err(LD_BUG,"got unexpected conn type %d.", conn->type);
       tor_fragile_assert();
diff --git a/src/feature/metrics/metrics.c b/src/feature/metrics/metrics.c
index 886182bc90..7a77ab1104 100644
--- a/src/feature/metrics/metrics.c
+++ b/src/feature/metrics/metrics.c
@@ -20,6 +20,7 @@
 #include "lib/net/address.h"
 
 #include "core/mainloop/connection.h"
+#include "core/or/connection_or.h"
 #include "core/or/connection_st.h"
 #include "core/or/policies.h"
 #include "core/or/port_cfg_st.h"
@@ -93,7 +94,8 @@ metrics_get_output(const metrics_format_t fmt)
 
 /** Process what is in the inbuf of this connection of type metrics.
  *
- * Return 0 on success else -1 on error which will close the connection. */
+ * Return 0 on success else -1 on error for which the connection is marked for
+ * close. */
 int
 metrics_connection_process_inbuf(connection_t *conn)
 {
@@ -111,13 +113,14 @@ metrics_connection_process_inbuf(connection_t *conn)
     goto err;
   }
 
-  const int http_status = fetch_from_buf_http(conn->inbuf, &headers, 1024,
-                                              NULL, NULL, 1024, 0);
+  const int http_status =
+    connection_fetch_from_buf_http(conn, &headers, 1024, NULL, NULL, 1024, 0);
   if (http_status < 0) {
     errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n";
     goto err;
   } else if (http_status == 0) {
     /* no HTTP request yet. */
+    ret = 0;
     goto done;
   }
 
@@ -155,6 +158,7 @@ metrics_connection_process_inbuf(connection_t *conn)
     log_info(LD_EDGE, "HTTP metrics error: saying %s", escaped(errmsg));
     connection_buf_add(errmsg, strlen(errmsg), conn);
   }
+  connection_mark_and_flush(conn);
 
  done:
   tor_free(headers);
@@ -243,6 +247,17 @@ metrics_parse_ports(or_options_t *options, smartlist_t *ports,
   return ret;
 }
 
+/** Called when conn has gotten its socket closed. */
+int
+metrics_connection_reached_eof(connection_t *conn)
+{
+  tor_assert(conn);
+
+  log_info(LD_EDGE, "Metrics connection reached EOF. Closing.");
+  connection_mark_for_close(conn);
+  return 0;
+}
+
 /** Initialize the subsystem. */
 void
 metrics_init(void)
diff --git a/src/feature/metrics/metrics.h b/src/feature/metrics/metrics.h
index b4bbe28b27..858722de59 100644
--- a/src/feature/metrics/metrics.h
+++ b/src/feature/metrics/metrics.h
@@ -27,6 +27,7 @@ buf_t *metrics_get_output(const metrics_format_t fmt);
 
 /* Connection. */
 int metrics_connection_process_inbuf(struct connection_t *conn);
+int metrics_connection_reached_eof(struct connection_t *conn);
 
 /* Configuration. */
 int metrics_parse_ports(or_options_t *options, smartlist_t *ports,
diff --git a/src/test/test_metrics.c b/src/test/test_metrics.c
index 96eadc6b43..152dd99d23 100644
--- a/src/test/test_metrics.c
+++ b/src/test/test_metrics.c
@@ -8,6 +8,7 @@
 
 #define CONFIG_PRIVATE
 #define CONNECTION_PRIVATE
+#define MAINLOOP_PRIVATE
 #define METRICS_STORE_ENTRY_PRIVATE
 
 #include "test/test.h"
@@ -17,6 +18,7 @@
 #include "app/config/config.h"
 
 #include "core/mainloop/connection.h"
+#include "core/mainloop/mainloop.h"
 #include "core/or/connection_st.h"
 #include "core/or/policies.h"
 #include "core/or/port_cfg_st.h"
@@ -96,43 +98,62 @@ static char _c_buf[256];
 #define WRITE(conn, msg) \
   buf_add(conn->inbuf, (msg), (strlen(msg)));
 
+/* Free the previous conn object if any and allocate a new connection. In
+ * order to be allowed, set its address to 1.2.3.4 as per the policy. */
+#define NEW_ALLOWED_CONN()                              \
+  do {                                                  \
+    close_closeable_connections();                      \
+    conn = connection_new(CONN_TYPE_METRICS, AF_INET);  \
+    tor_addr_from_ipv4h(&conn->addr, 0x01020304);       \
+  } while (0)
+
 static void
 test_connection(void *arg)
 {
   int ret;
-  connection_t *conn = connection_new(CONN_TYPE_METRICS, AF_INET);
+  connection_t *conn = NULL;
   or_options_t *options = get_options_mutable();
 
   (void) arg;
 
+  /* Notice that in this test, we will allocate a new connection at every test
+   * case. This is because the metrics_connection_process_inbuf() marks for
+   * close the connection in case of an error and thus we can't call again an
+   * inbuf process function on a marked for close connection. */
+
+  tor_init_connection_lists();
+
   /* Setup policy. */
   set_metrics_port(options);
 
   /* Set 1.2.3.5 IP, we should get rejected. */
+  NEW_ALLOWED_CONN();
   tor_addr_from_ipv4h(&conn->addr, 0x01020305);
   ret = metrics_connection_process_inbuf(conn);
   tt_int_op(ret, OP_EQ, -1);
 
-  /* Set 1.2.3.4 so from now on we are allowed to process the inbuf. */
-  tor_addr_from_ipv4h(&conn->addr, 0x01020304);
-
   /* No HTTP request yet. */
+  NEW_ALLOWED_CONN();
   ret = metrics_connection_process_inbuf(conn);
-  tt_int_op(ret, OP_EQ, -1);
+  tt_int_op(ret, OP_EQ, 0);
+  connection_free_minimal(conn);
 
   /* Bad request. */
+  NEW_ALLOWED_CONN();
   WRITE(conn, "HTTP 4.7\r\n\r\n");
   ret = metrics_connection_process_inbuf(conn);
   tt_int_op(ret, OP_EQ, -1);
   CONTAINS(conn, "HTTP/1.0 400 Bad Request\r\n\r\n");
 
   /* Path not found. */
+  NEW_ALLOWED_CONN();
   WRITE(conn, "GET /badpath HTTP/1.0\r\n\r\n");
   ret = metrics_connection_process_inbuf(conn);
   tt_int_op(ret, OP_EQ, -1);
   CONTAINS(conn, "HTTP/1.0 404 Not Found\r\n\r\n");
 
   /* Method not allowed. */
+  NEW_ALLOWED_CONN();
   WRITE(conn, "POST /something HTTP/1.0\r\n\r\n");
   ret = metrics_connection_process_inbuf(conn);
   tt_int_op(ret, OP_EQ, -1);
@@ -140,6 +161,7 @@ test_connection(void *arg)
 
   /* Ask for metrics. The content should be above 0. We don't test the
    * validity of the returned content but it is certainly not an error. */
+  NEW_ALLOWED_CONN();
   WRITE(conn, "GET /metrics HTTP/1.0\r\n\r\n");
   ret = metrics_connection_process_inbuf(conn);
   tt_int_op(ret, OP_EQ, 0);





More information about the tor-commits mailing list