]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
dos: Track new and closed OR client connections
authorDavid Goulet <dgoulet@torproject.org>
Thu, 25 Jan 2018 21:05:59 +0000 (16:05 -0500)
committerDavid Goulet <dgoulet@torproject.org>
Tue, 30 Jan 2018 14:18:15 +0000 (09:18 -0500)
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@torproject.org>
src/or/channel.c
src/or/connection.c
src/or/dos.c
src/or/dos.h
src/or/geoip.h
src/or/or.h

index f547aea1b3e40c5df142628dfa9a3bd091cc1739..fdd3f81e8148b4877ec4abd8ddcf193cd264d249 100644 (file)
@@ -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 */
     }
index 8b00d637f63c08f8d6981f62f3244dab6e2d9796..15f489c6b4748164c3c06562ffc90d616fd0302d 100644 (file)
@@ -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);
 }
index 4b5983d16d0ea2cd67ee08bcf94f56f7f4db9aa7..d1a2c6a28177261d411363a078d0f698b8da68cf 100644 (file)
@@ -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
index dc36aaa40609314deec5cf3e0256dc2721359300..3cc10d3f995bb051f5d663694048529a7cb1e9cf 100644 (file)
@@ -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.
  */
index b80efceb3570196c2e924ff2e375368e8b668d83..aa0fca50f58ea856180e04a2660c8f28bf426003 100644 (file)
@@ -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);
index 2cf9e97356fd8f746771b2255bb15583ffe8ac2c..454d05ed52fb50e05257cfe0833dab4b8d74bb70 100644 (file)
@@ -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." */