[tor-commits] [tor/master] dos: Track new and closed OR client connections

nickm at torproject.org nickm at torproject.org
Tue Jan 30 23:18:27 UTC 2018


commit c05272783d0164363023ddd4b3ee93c2e12c8911
Author: David Goulet <dgoulet at torproject.org>
Date:   Thu Jan 25 16:05:59 2018 -0500

    dos: Track new and closed OR client connections
    
    Implement a basic connection tracking that counts the number of concurrent
    connections when they open and close.
    
    This commit also adds the circuit creation mitigation data structure that will
    be needed at later commit to keep track of the circuit rate.
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/or/channel.c    |  5 ++++
 src/or/connection.c |  8 ++++++
 src/or/dos.c        | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/dos.h        |  3 +++
 src/or/geoip.h      |  5 ++++
 src/or/or.h         |  4 +++
 6 files changed, 100 insertions(+)

diff --git a/src/or/channel.c b/src/or/channel.c
index f547aea1b..fdd3f81e8 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -2583,6 +2583,7 @@ channel_do_open_actions(channel_t *chan)
     if (!router_get_by_id_digest(chan->identity_digest)) {
       if (channel_get_addr_if_possible(chan, &remote_addr)) {
         char *transport_name = NULL;
+        channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
         if (chan->get_transport_name(chan, &transport_name) < 0)
           transport_name = NULL;
 
@@ -2590,6 +2591,10 @@ channel_do_open_actions(channel_t *chan)
                                &remote_addr, transport_name,
                                now);
         tor_free(transport_name);
+        /* Notify the DoS subsystem of a new client. */
+        if (tlschan && tlschan->conn) {
+          dos_new_client_conn(tlschan->conn);
+        }
       }
       /* Otherwise the underlying transport can't tell us this, so skip it */
     }
diff --git a/src/or/connection.c b/src/or/connection.c
index 8b00d637f..15f489c6b 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -78,6 +78,7 @@
 #include "dirserv.h"
 #include "dns.h"
 #include "dnsserv.h"
+#include "dos.h"
 #include "entrynodes.h"
 #include "ext_orport.h"
 #include "geoip.h"
@@ -687,6 +688,13 @@ connection_free,(connection_t *conn))
                                                   "connection_free");
   }
 #endif
+
+  /* Notify the circuit creation DoS mitigation subsystem that an OR client
+   * connection has been closed. And only do that if we track it. */
+  if (conn->type == CONN_TYPE_OR) {
+    dos_close_client_conn(TO_OR_CONN(conn));
+  }
+
   connection_unregister_events(conn);
   connection_free_(conn);
 }
diff --git a/src/or/dos.c b/src/or/dos.c
index 4b5983d16..d1a2c6a28 100644
--- a/src/or/dos.c
+++ b/src/or/dos.c
@@ -246,6 +246,81 @@ dos_is_enabled(void)
 
 /* General API */
 
+/* Called when a new client connection has been established on the given
+ * address. */
+void
+dos_new_client_conn(or_connection_t *or_conn)
+{
+  clientmap_entry_t *entry;
+
+  tor_assert(or_conn);
+
+  /* Past that point, we know we have at least one DoS detection subsystem
+   * enabled so we'll start allocating stuff. */
+  if (!dos_is_enabled()) {
+    goto end;
+  }
+
+  /* We are only interested in client connection from the geoip cache. */
+  entry = geoip_lookup_client(&or_conn->real_addr, NULL,
+                              GEOIP_CLIENT_CONNECT);
+  if (BUG(entry == NULL)) {
+    /* Should never happen because we note down the address in the geoip
+     * cache before this is called. */
+    goto end;
+  }
+
+  entry->dos_stats.concurrent_count++;
+  or_conn->tracked_for_dos_mitigation = 1;
+  log_debug(LD_DOS, "Client address %s has now %u concurrent connections.",
+            fmt_addr(&or_conn->real_addr),
+            entry->dos_stats.concurrent_count);
+
+ end:
+  return;
+}
+
+/* Called when a client connection for the given IP address has been closed. */
+void
+dos_close_client_conn(const or_connection_t *or_conn)
+{
+  clientmap_entry_t *entry;
+
+  tor_assert(or_conn);
+
+  /* We have to decrement the count on tracked connection only even if the
+   * subsystem has been disabled at runtime because it might be re-enabled
+   * after and we need to keep a synchronized counter at all time. */
+  if (!or_conn->tracked_for_dos_mitigation) {
+    goto end;
+  }
+
+  /* We are only interested in client connection from the geoip cache. */
+  entry = geoip_lookup_client(&or_conn->real_addr, NULL,
+                              GEOIP_CLIENT_CONNECT);
+  if (entry == NULL) {
+    /* This can happen because we can close a connection before the channel
+     * got to be noted down in the geoip cache. */
+    goto end;
+  }
+
+  /* Extra super duper safety. Going below 0 means an underflow which could
+   * lead to most likely a false positive. In theory, this should never happen
+   * but lets be extra safe. */
+  if (BUG(entry->dos_stats.concurrent_count == 0)) {
+    goto end;
+  }
+
+  entry->dos_stats.concurrent_count--;
+  log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent "
+                    "connections are now at %u",
+            fmt_addr(&or_conn->real_addr),
+            entry->dos_stats.concurrent_count);
+
+ end:
+  return;
+}
+
 /* Called when the consensus has changed. We might have new consensus
  * parameters to look at. */
 void
diff --git a/src/or/dos.h b/src/or/dos.h
index dc36aaa40..3cc10d3f9 100644
--- a/src/or/dos.h
+++ b/src/or/dos.h
@@ -48,6 +48,9 @@ void dos_free_all(void);
 void dos_consensus_has_changed(const networkstatus_t *ns);
 int dos_enabled(void);
 
+void dos_new_client_conn(or_connection_t *or_conn);
+void dos_close_client_conn(const or_connection_t *or_conn);
+
 /*
  * Circuit creation DoS mitigation subsystemn interface.
  */
diff --git a/src/or/geoip.h b/src/or/geoip.h
index b80efceb3..aa0fca50f 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -13,6 +13,7 @@
 #define TOR_GEOIP_H
 
 #include "testsupport.h"
+#include "dos.h"
 
 #ifdef GEOIP_PRIVATE
 STATIC int geoip_parse_entry(const char *line, sa_family_t family);
@@ -37,6 +38,10 @@ typedef struct clientmap_entry_t {
    * 4000 CE, please remember to add more bits to last_seen_in_minutes.) */
   unsigned int last_seen_in_minutes:30;
   unsigned int action:2;
+
+  /* This object is used to keep some statistics per client address for the
+   * DoS mitigation subsystem. */
+  dos_client_stats_t dos_stats;
 } clientmap_entry_t;
 
 int should_record_bridge_info(const or_options_t *options);
diff --git a/src/or/or.h b/src/or/or.h
index 2cf9e9735..454d05ed5 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1500,6 +1500,10 @@ typedef struct or_connection_t {
   /** True iff this connection has had its bootstrap failure logged with
    * control_event_bootstrap_problem. */
   unsigned int have_noted_bootstrap_problem:1;
+  /** True iff this is a client connection and its address has been put in the
+   * geoip cache and handled by the DoS mitigation subsystem. We use this to
+   * insure we have a coherent count of concurrent connection. */
+  unsigned int tracked_for_dos_mitigation : 1;
 
   uint16_t link_proto; /**< What protocol version are we using? 0 for
                         * "none negotiated yet." */





More information about the tor-commits mailing list