summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/channel.c5
-rw-r--r--src/or/connection.c8
-rw-r--r--src/or/dos.c75
-rw-r--r--src/or/dos.h3
-rw-r--r--src/or/geoip.h5
-rw-r--r--src/or/or.h4
6 files changed, 100 insertions, 0 deletions
diff --git a/src/or/channel.c b/src/or/channel.c
index f547aea1b3..fdd3f81e81 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 8b00d637f6..15f489c6b4 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 4b5983d16d..d1a2c6a281 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 dc36aaa406..3cc10d3f99 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 b80efceb35..aa0fca50f5 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 2cf9e97356..454d05ed52 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." */