LCOV - code coverage report
Current view: top level - core/or - dos.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 244 297 82.2 %
Date: 2021-11-24 03:28:48 Functions: 37 40 92.5 %

          Line data    Source code
       1             : /* Copyright (c) 2018-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /*
       5             :  * \file dos.c
       6             :  * \brief Implement Denial of Service mitigation subsystem.
       7             :  */
       8             : 
       9             : #define DOS_PRIVATE
      10             : 
      11             : #include "core/or/or.h"
      12             : #include "app/config/config.h"
      13             : #include "core/mainloop/connection.h"
      14             : #include "core/mainloop/mainloop.h"
      15             : #include "core/or/channel.h"
      16             : #include "core/or/connection_or.h"
      17             : #include "core/or/relay.h"
      18             : #include "feature/hs/hs_dos.h"
      19             : #include "feature/nodelist/networkstatus.h"
      20             : #include "feature/nodelist/nodelist.h"
      21             : #include "feature/relay/routermode.h"
      22             : #include "feature/stats/geoip_stats.h"
      23             : #include "lib/crypt_ops/crypto_rand.h"
      24             : 
      25             : #include "core/or/dos.h"
      26             : #include "core/or/dos_sys.h"
      27             : 
      28             : #include "core/or/dos_options_st.h"
      29             : #include "core/or/or_connection_st.h"
      30             : 
      31             : /*
      32             :  * Circuit creation denial of service mitigation.
      33             :  *
      34             :  * Namespace used for this mitigation framework is "dos_cc_" where "cc" is for
      35             :  * Circuit Creation.
      36             :  */
      37             : 
      38             : /* Is the circuit creation DoS mitigation enabled? */
      39             : static unsigned int dos_cc_enabled = 0;
      40             : 
      41             : /* Consensus parameters. They can be changed when a new consensus arrives.
      42             :  * They are initialized with the hardcoded default values. */
      43             : static uint32_t dos_cc_min_concurrent_conn;
      44             : static uint32_t dos_cc_circuit_rate;
      45             : static uint32_t dos_cc_circuit_burst;
      46             : static dos_cc_defense_type_t dos_cc_defense_type;
      47             : static int32_t dos_cc_defense_time_period;
      48             : 
      49             : /* Keep some stats for the heartbeat so we can report out. */
      50             : static uint64_t cc_num_rejected_cells;
      51             : static uint32_t cc_num_marked_addrs;
      52             : 
      53             : /*
      54             :  * Concurrent connection denial of service mitigation.
      55             :  *
      56             :  * Namespace used for this mitigation framework is "dos_conn_".
      57             :  */
      58             : 
      59             : /* Is the connection DoS mitigation enabled? */
      60             : static unsigned int dos_conn_enabled = 0;
      61             : 
      62             : /* Consensus parameters. They can be changed when a new consensus arrives.
      63             :  * They are initialized with the hardcoded default values. */
      64             : static uint32_t dos_conn_max_concurrent_count;
      65             : static dos_conn_defense_type_t dos_conn_defense_type;
      66             : static uint32_t dos_conn_connect_rate = DOS_CONN_CONNECT_RATE_DEFAULT;
      67             : static uint32_t dos_conn_connect_burst = DOS_CONN_CONNECT_BURST_DEFAULT;
      68             : static int32_t dos_conn_connect_defense_time_period =
      69             :   DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT;
      70             : 
      71             : /* Keep some stats for the heartbeat so we can report out. */
      72             : static uint64_t conn_num_addr_rejected;
      73             : static uint64_t conn_num_addr_connect_rejected;
      74             : 
      75             : /*
      76             :  * General interface of the denial of service mitigation subsystem.
      77             :  */
      78             : 
      79             : /* Keep stats for the heartbeat. */
      80             : static uint64_t num_single_hop_client_refused;
      81             : 
      82             : /* Return true iff the circuit creation mitigation is enabled. We look at the
      83             :  * consensus for this else a default value is returned. */
      84           4 : MOCK_IMPL(STATIC unsigned int,
      85             : get_param_cc_enabled, (const networkstatus_t *ns))
      86             : {
      87           4 :   if (dos_get_options()->DoSCircuitCreationEnabled != -1) {
      88           0 :     return dos_get_options()->DoSCircuitCreationEnabled;
      89             :   }
      90             : 
      91           4 :   return !!networkstatus_get_param(ns, "DoSCircuitCreationEnabled",
      92             :                                    DOS_CC_ENABLED_DEFAULT, 0, 1);
      93             : }
      94             : 
      95             : /* Return the parameter for the minimum concurrent connection at which we'll
      96             :  * start counting circuit for a specific client address. */
      97             : STATIC uint32_t
      98          10 : get_param_cc_min_concurrent_connection(const networkstatus_t *ns)
      99             : {
     100          10 :   if (dos_get_options()->DoSCircuitCreationMinConnections) {
     101           0 :     return dos_get_options()->DoSCircuitCreationMinConnections;
     102             :   }
     103          10 :   return networkstatus_get_param(ns, "DoSCircuitCreationMinConnections",
     104             :                                  DOS_CC_MIN_CONCURRENT_CONN_DEFAULT,
     105             :                                  1, INT32_MAX);
     106             : }
     107             : 
     108             : /* Return the parameter for the time rate that is how many circuits over this
     109             :  * time span. */
     110             : static uint32_t
     111           9 : get_param_cc_circuit_rate(const networkstatus_t *ns)
     112             : {
     113             :   /* This is in seconds. */
     114           9 :   if (dos_get_options()->DoSCircuitCreationRate) {
     115           0 :     return dos_get_options()->DoSCircuitCreationRate;
     116             :   }
     117           9 :   return networkstatus_get_param(ns, "DoSCircuitCreationRate",
     118             :                                  DOS_CC_CIRCUIT_RATE_DEFAULT,
     119             :                                  1, INT32_MAX);
     120             : }
     121             : 
     122             : /* Return the parameter for the maximum circuit count for the circuit time
     123             :  * rate. */
     124             : STATIC uint32_t
     125          11 : get_param_cc_circuit_burst(const networkstatus_t *ns)
     126             : {
     127          11 :   if (dos_get_options()->DoSCircuitCreationBurst) {
     128           0 :     return dos_get_options()->DoSCircuitCreationBurst;
     129             :   }
     130          11 :   return networkstatus_get_param(ns, "DoSCircuitCreationBurst",
     131             :                                  DOS_CC_CIRCUIT_BURST_DEFAULT,
     132             :                                  1, INT32_MAX);
     133             : }
     134             : 
     135             : /* Return the consensus parameter of the circuit creation defense type. */
     136             : static uint32_t
     137           9 : get_param_cc_defense_type(const networkstatus_t *ns)
     138             : {
     139           9 :   if (dos_get_options()->DoSCircuitCreationDefenseType) {
     140           0 :     return dos_get_options()->DoSCircuitCreationDefenseType;
     141             :   }
     142           9 :   return networkstatus_get_param(ns, "DoSCircuitCreationDefenseType",
     143             :                                  DOS_CC_DEFENSE_TYPE_DEFAULT,
     144             :                                  DOS_CC_DEFENSE_NONE, DOS_CC_DEFENSE_MAX);
     145             : }
     146             : 
     147             : /* Return the consensus parameter of the defense time period which is how much
     148             :  * time should we defend against a malicious client address. */
     149             : static int32_t
     150           9 : get_param_cc_defense_time_period(const networkstatus_t *ns)
     151             : {
     152             :   /* Time in seconds. */
     153           9 :   if (dos_get_options()->DoSCircuitCreationDefenseTimePeriod) {
     154           0 :     return dos_get_options()->DoSCircuitCreationDefenseTimePeriod;
     155             :   }
     156           9 :   return networkstatus_get_param(ns, "DoSCircuitCreationDefenseTimePeriod",
     157             :                                  DOS_CC_DEFENSE_TIME_PERIOD_DEFAULT,
     158             :                                  0, INT32_MAX);
     159             : }
     160             : 
     161             : /* Return true iff connection mitigation is enabled. We look at the consensus
     162             :  * for this else a default value is returned. */
     163           5 : MOCK_IMPL(STATIC unsigned int,
     164             : get_param_conn_enabled, (const networkstatus_t *ns))
     165             : {
     166           5 :   if (dos_get_options()->DoSConnectionEnabled != -1) {
     167           0 :     return dos_get_options()->DoSConnectionEnabled;
     168             :   }
     169           5 :   return !!networkstatus_get_param(ns, "DoSConnectionEnabled",
     170             :                                    DOS_CONN_ENABLED_DEFAULT, 0, 1);
     171             : }
     172             : 
     173             : /* Return the consensus parameter for the maximum concurrent connection
     174             :  * allowed. */
     175             : STATIC uint32_t
     176          10 : get_param_conn_max_concurrent_count(const networkstatus_t *ns)
     177             : {
     178          10 :   if (dos_get_options()->DoSConnectionMaxConcurrentCount) {
     179           0 :     return dos_get_options()->DoSConnectionMaxConcurrentCount;
     180             :   }
     181          10 :   return networkstatus_get_param(ns, "DoSConnectionMaxConcurrentCount",
     182             :                                  DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT,
     183             :                                  1, INT32_MAX);
     184             : }
     185             : 
     186             : /* Return the consensus parameter of the connection defense type. */
     187             : static uint32_t
     188           9 : get_param_conn_defense_type(const networkstatus_t *ns)
     189             : {
     190           9 :   if (dos_get_options()->DoSConnectionDefenseType) {
     191           0 :     return dos_get_options()->DoSConnectionDefenseType;
     192             :   }
     193           9 :   return networkstatus_get_param(ns, "DoSConnectionDefenseType",
     194             :                                  DOS_CONN_DEFENSE_TYPE_DEFAULT,
     195             :                                  DOS_CONN_DEFENSE_NONE, DOS_CONN_DEFENSE_MAX);
     196             : }
     197             : 
     198             : /* Return the connection connect rate parameters either from the configuration
     199             :  * file or, if not found, consensus parameter. */
     200             : static uint32_t
     201           9 : get_param_conn_connect_rate(const networkstatus_t *ns)
     202             : {
     203           9 :   if (dos_get_options()->DoSConnectionConnectRate) {
     204           0 :     return dos_get_options()->DoSConnectionConnectRate;
     205             :   }
     206           9 :   return networkstatus_get_param(ns, "DoSConnectionConnectRate",
     207             :                                  DOS_CONN_CONNECT_RATE_DEFAULT,
     208             :                                  1, INT32_MAX);
     209             : }
     210             : 
     211             : /* Return the connection connect burst parameters either from the
     212             :  * configuration file or, if not found, consensus parameter. */
     213             : STATIC uint32_t
     214          10 : get_param_conn_connect_burst(const networkstatus_t *ns)
     215             : {
     216          10 :   if (dos_get_options()->DoSConnectionConnectBurst) {
     217           0 :     return dos_get_options()->DoSConnectionConnectBurst;
     218             :   }
     219          10 :   return networkstatus_get_param(ns, "DoSConnectionConnectBurst",
     220             :                                  DOS_CONN_CONNECT_BURST_DEFAULT,
     221             :                                  1, INT32_MAX);
     222             : }
     223             : 
     224             : /* Return the connection connect defense time period from the configuration
     225             :  * file or, if not found, the consensus parameter. */
     226             : static int32_t
     227           9 : get_param_conn_connect_defense_time_period(const networkstatus_t *ns)
     228             : {
     229             :   /* Time in seconds. */
     230           9 :   if (dos_get_options()->DoSConnectionConnectDefenseTimePeriod) {
     231           0 :     return dos_get_options()->DoSConnectionConnectDefenseTimePeriod;
     232             :   }
     233           9 :   return networkstatus_get_param(ns, "DoSConnectionConnectDefenseTimePeriod",
     234             :                                  DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT,
     235             :                                  DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN,
     236             :                                  INT32_MAX);
     237             : }
     238             : 
     239             : /* Set circuit creation parameters located in the consensus or their default
     240             :  * if none are present. Called at initialization or when the consensus
     241             :  * changes. */
     242             : static void
     243           9 : set_dos_parameters(const networkstatus_t *ns)
     244             : {
     245             :   /* Get the default consensus param values. */
     246           9 :   dos_cc_enabled = get_param_cc_enabled(ns);
     247           9 :   dos_cc_min_concurrent_conn = get_param_cc_min_concurrent_connection(ns);
     248           9 :   dos_cc_circuit_rate = get_param_cc_circuit_rate(ns);
     249           9 :   dos_cc_circuit_burst = get_param_cc_circuit_burst(ns);
     250           9 :   dos_cc_defense_time_period = get_param_cc_defense_time_period(ns);
     251           9 :   dos_cc_defense_type = get_param_cc_defense_type(ns);
     252             : 
     253             :   /* Connection detection. */
     254           9 :   dos_conn_enabled = get_param_conn_enabled(ns);
     255           9 :   dos_conn_max_concurrent_count = get_param_conn_max_concurrent_count(ns);
     256           9 :   dos_conn_defense_type = get_param_conn_defense_type(ns);
     257           9 :   dos_conn_connect_rate = get_param_conn_connect_rate(ns);
     258           9 :   dos_conn_connect_burst = get_param_conn_connect_burst(ns);
     259          18 :   dos_conn_connect_defense_time_period =
     260           9 :     get_param_conn_connect_defense_time_period(ns);
     261           9 : }
     262             : 
     263             : /* Free everything for the circuit creation DoS mitigation subsystem. */
     264             : static void
     265         240 : cc_free_all(void)
     266             : {
     267             :   /* If everything is freed, the circuit creation subsystem is not enabled. */
     268         240 :   dos_cc_enabled = 0;
     269         240 : }
     270             : 
     271             : /* Called when the consensus has changed. Do appropriate actions for the
     272             :  * circuit creation subsystem. */
     273             : static void
     274           0 : cc_consensus_has_changed(const networkstatus_t *ns)
     275             : {
     276             :   /* Looking at the consensus, is the circuit creation subsystem enabled? If
     277             :    * not and it was enabled before, clean it up. */
     278           0 :   if (dos_cc_enabled && !get_param_cc_enabled(ns)) {
     279           0 :     cc_free_all();
     280             :   }
     281           0 : }
     282             : 
     283             : /** Return the number of circuits we allow per second under the current
     284             :  *  configuration. */
     285             : STATIC uint64_t
     286          13 : get_circuit_rate_per_second(void)
     287             : {
     288          13 :   return dos_cc_circuit_rate;
     289             : }
     290             : 
     291             : /* Given the circuit creation client statistics object, refill the circuit
     292             :  * bucket if needed. This also works if the bucket was never filled in the
     293             :  * first place. The addr is only used for logging purposes. */
     294             : STATIC void
     295         829 : cc_stats_refill_bucket(cc_client_stats_t *stats, const tor_addr_t *addr)
     296             : {
     297         829 :   uint32_t new_circuit_bucket_count;
     298         829 :   uint64_t num_token, elapsed_time_last_refill = 0, circuit_rate = 0;
     299         829 :   time_t now;
     300         829 :   int64_t last_refill_ts;
     301             : 
     302         829 :   tor_assert(stats);
     303         829 :   tor_assert(addr);
     304             : 
     305         829 :   now = approx_time();
     306         829 :   last_refill_ts = (int64_t)stats->last_circ_bucket_refill_ts;
     307             : 
     308             :   /* If less than a second has elapsed, don't add any tokens.
     309             :    * Note: If a relay's clock is ever 0, any new clients won't get a refill
     310             :    * until the next second. But a relay that thinks it is 1970 will never
     311             :    * validate the public consensus. */
     312         829 :   if ((int64_t)now == last_refill_ts) {
     313         817 :     goto done;
     314             :   }
     315             : 
     316             :   /* At this point, we know we might need to add token to the bucket. We'll
     317             :    * first get the circuit rate that is how many circuit are we allowed to do
     318             :    * per second. */
     319          12 :   circuit_rate = get_circuit_rate_per_second();
     320             : 
     321             :   /* We've never filled the bucket so fill it with the maximum being the burst
     322             :    * and we are done.
     323             :    * Note: If a relay's clock is ever 0, all clients that were last refilled
     324             :    * in that zero second will get a full refill here. */
     325          12 :   if (last_refill_ts == 0) {
     326           2 :     num_token = dos_cc_circuit_burst;
     327           2 :     goto end;
     328             :   }
     329             : 
     330             :   /* Our clock jumped backward so fill it up to the maximum. Not filling it
     331             :    * could trigger a detection for a valid client. Also, if the clock jumped
     332             :    * negative but we didn't notice until the elapsed time became positive
     333             :    * again, then we potentially spent many seconds not refilling the bucket
     334             :    * when we should have been refilling it. But the fact that we didn't notice
     335             :    * until now means that no circuit creation requests came in during that
     336             :    * time, so the client doesn't end up punished that much from this hopefully
     337             :    * rare situation.*/
     338          10 :   if ((int64_t)now < last_refill_ts) {
     339             :     /* Use the maximum allowed value of token. */
     340           3 :     num_token = dos_cc_circuit_burst;
     341           3 :     goto end;
     342             :   }
     343             : 
     344             :   /* How many seconds have elapsed between now and the last refill?
     345             :    * This subtraction can't underflow, because now >= last_refill_ts.
     346             :    * And it can't overflow, because INT64_MAX - (-INT64_MIN) == UINT64_MAX. */
     347           7 :   elapsed_time_last_refill = (uint64_t)now - last_refill_ts;
     348             : 
     349             :   /* If the elapsed time is very large, it means our clock jumped forward.
     350             :    * If the multiplication would overflow, use the maximum allowed value. */
     351           7 :   if (elapsed_time_last_refill > UINT32_MAX) {
     352           1 :     num_token = dos_cc_circuit_burst;
     353           1 :     goto end;
     354             :   }
     355             : 
     356             :   /* Compute how many circuits we are allowed in that time frame which we'll
     357             :    * add to the bucket. This can't overflow, because both multiplicands
     358             :    * are less than or equal to UINT32_MAX, and num_token is uint64_t. */
     359           6 :   num_token = elapsed_time_last_refill * circuit_rate;
     360             : 
     361          12 :  end:
     362             :   /* If the sum would overflow, use the maximum allowed value. */
     363          12 :   if (num_token > UINT32_MAX - stats->circuit_bucket) {
     364           1 :     new_circuit_bucket_count = dos_cc_circuit_burst;
     365             :   } else {
     366             :     /* We cap the bucket to the burst value else this could overflow uint32_t
     367             :      * over time. */
     368          11 :     new_circuit_bucket_count = MIN(stats->circuit_bucket + (uint32_t)num_token,
     369             :                                    dos_cc_circuit_burst);
     370             :   }
     371             : 
     372             :   /* This function is not allowed to make the bucket count larger than the
     373             :    * burst value */
     374          12 :   tor_assert_nonfatal(new_circuit_bucket_count <= dos_cc_circuit_burst);
     375             :   /* This function is not allowed to make the bucket count smaller, unless it
     376             :    * is decreasing it to a newly configured, lower burst value. We allow the
     377             :    * bucket to stay the same size, in case the circuit rate is zero. */
     378          12 :   tor_assert_nonfatal(new_circuit_bucket_count >= stats->circuit_bucket ||
     379             :                       new_circuit_bucket_count == dos_cc_circuit_burst);
     380             : 
     381          12 :   log_debug(LD_DOS, "DoS address %s has its circuit bucket value: %" PRIu32
     382             :                     ". Filling it to %" PRIu32 ". Circuit rate is %" PRIu64
     383             :                     ". Elapsed time is %" PRIi64,
     384             :             fmt_addr(addr), stats->circuit_bucket, new_circuit_bucket_count,
     385             :             circuit_rate, (int64_t)elapsed_time_last_refill);
     386             : 
     387          12 :   stats->circuit_bucket = new_circuit_bucket_count;
     388          12 :   stats->last_circ_bucket_refill_ts = now;
     389             : 
     390         829 :  done:
     391         829 :   return;
     392             : }
     393             : 
     394             : /* Return true iff the circuit bucket is down to 0 and the number of
     395             :  * concurrent connections is greater or equal the minimum threshold set the
     396             :  * consensus parameter. */
     397             : static int
     398         819 : cc_has_exhausted_circuits(const dos_client_stats_t *stats)
     399             : {
     400         819 :   tor_assert(stats);
     401         819 :   return stats->cc_stats.circuit_bucket == 0 &&
     402          11 :          stats->conn_stats.concurrent_count >= dos_cc_min_concurrent_conn;
     403             : }
     404             : 
     405             : /* Mark client address by setting a timestamp in the stats object which tells
     406             :  * us until when it is marked as positively detected. */
     407             : static void
     408           1 : cc_mark_client(cc_client_stats_t *stats)
     409             : {
     410           1 :   tor_assert(stats);
     411             :   /* We add a random offset of a maximum of half the defense time so it is
     412             :    * less predictable. */
     413           2 :   stats->marked_until_ts =
     414           1 :     approx_time() + dos_cc_defense_time_period +
     415           1 :     crypto_rand_int_range(1, dos_cc_defense_time_period / 2);
     416           1 : }
     417             : 
     418             : /* Return true iff the given channel address is marked as malicious. This is
     419             :  * called a lot and part of the fast path of handling cells. It has to remain
     420             :  * as fast as we can. */
     421             : static int
     422           2 : cc_channel_addr_is_marked(channel_t *chan)
     423             : {
     424           2 :   time_t now;
     425           2 :   tor_addr_t addr;
     426           2 :   clientmap_entry_t *entry;
     427           2 :   cc_client_stats_t *stats = NULL;
     428             : 
     429           2 :   if (chan == NULL) {
     430           0 :     goto end;
     431             :   }
     432             :   /* Must be a client connection else we ignore. */
     433           2 :   if (!channel_is_client(chan)) {
     434           0 :     goto end;
     435             :   }
     436             :   /* Without an IP address, nothing can work. */
     437           2 :   if (!channel_get_addr_if_possible(chan, &addr)) {
     438           0 :     goto end;
     439             :   }
     440             : 
     441             :   /* We are only interested in client connection from the geoip cache. */
     442           2 :   entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT);
     443           2 :   if (entry == NULL) {
     444             :     /* We can have a connection creating circuits but not tracked by the geoip
     445             :      * cache. Once this DoS subsystem is enabled, we can end up here with no
     446             :      * entry for the channel. */
     447           0 :     goto end;
     448             :   }
     449           2 :   now = approx_time();
     450           2 :   stats = &entry->dos_stats.cc_stats;
     451             : 
     452           2 :  end:
     453           2 :   return stats && stats->marked_until_ts >= now;
     454             : }
     455             : 
     456             : /* Concurrent connection private API. */
     457             : 
     458             : /* Mark client connection stats by setting a timestamp which tells us until
     459             :  * when it is marked as positively detected. */
     460             : static void
     461           1 : conn_mark_client(conn_client_stats_t *stats)
     462             : {
     463           1 :   tor_assert(stats);
     464             : 
     465             :   /* We add a random offset of a maximum of half the defense time so it is
     466             :    * less predictable and thus more difficult to game. */
     467           2 :   stats->marked_until_ts =
     468           1 :     approx_time() + dos_conn_connect_defense_time_period +
     469           1 :     crypto_rand_int_range(1, dos_conn_connect_defense_time_period / 2);
     470           1 : }
     471             : 
     472             : /* Free everything for the connection DoS mitigation subsystem. */
     473             : static void
     474         240 : conn_free_all(void)
     475             : {
     476         240 :   dos_conn_enabled = 0;
     477         240 : }
     478             : 
     479             : /* Called when the consensus has changed. Do appropriate actions for the
     480             :  * connection mitigation subsystem. */
     481             : static void
     482           0 : conn_consensus_has_changed(const networkstatus_t *ns)
     483             : {
     484             :   /* Looking at the consensus, is the connection mitigation subsystem enabled?
     485             :    * If not and it was enabled before, clean it up. */
     486           0 :   if (dos_conn_enabled && !get_param_conn_enabled(ns)) {
     487           0 :     conn_free_all();
     488             :   }
     489           0 : }
     490             : 
     491             : /** Called when a new client connection has arrived. The following will update
     492             :  * the client connection statistics.
     493             :  *
     494             :  * The addr is used for logging purposes only.
     495             :  *
     496             :  * If the connect counter reaches its limit, it is marked. */
     497             : static void
     498         148 : conn_update_on_connect(conn_client_stats_t *stats, const tor_addr_t *addr)
     499             : {
     500         148 :   tor_assert(stats);
     501         148 :   tor_assert(addr);
     502             : 
     503             :   /* Update concurrent count for this new connect. */
     504         148 :   stats->concurrent_count++;
     505             : 
     506             :   /* Refill connect connection count. */
     507         148 :   token_bucket_ctr_refill(&stats->connect_count, (uint32_t) approx_time());
     508             : 
     509             :   /* Decrement counter for this new connection. */
     510         148 :   if (token_bucket_ctr_get(&stats->connect_count) > 0) {
     511         148 :     token_bucket_ctr_dec(&stats->connect_count, 1);
     512             :   }
     513             : 
     514             :   /* Assess connect counter. Mark it if counter is down to 0 and we haven't
     515             :    * marked it before or it was reset. This is to avoid to re-mark it over and
     516             :    * over again extending continously the blocked time. */
     517         148 :   if (token_bucket_ctr_get(&stats->connect_count) == 0 &&
     518           1 :       stats->marked_until_ts == 0) {
     519           1 :     conn_mark_client(stats);
     520             :   }
     521             : 
     522         148 :   log_debug(LD_DOS, "Client address %s has now %u concurrent connections. "
     523             :                     "Remaining %" TOR_PRIuSZ "/sec connections are allowed.",
     524             :             fmt_addr(addr), stats->concurrent_count,
     525             :             token_bucket_ctr_get(&stats->connect_count));
     526         148 : }
     527             : 
     528             : /** Called when a client connection is closed. The following will update
     529             :  * the client connection statistics.
     530             :  *
     531             :  * The addr is used for logging purposes only. */
     532             : static void
     533           1 : conn_update_on_close(conn_client_stats_t *stats, const tor_addr_t *addr)
     534             : {
     535             :   /* Extra super duper safety. Going below 0 means an underflow which could
     536             :    * lead to most likely a false positive. In theory, this should never happen
     537             :    * but lets be extra safe. */
     538           1 :   if (BUG(stats->concurrent_count == 0)) {
     539           0 :     return;
     540             :   }
     541             : 
     542           1 :   stats->concurrent_count--;
     543           1 :   log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent "
     544             :                     "connections are now at %u",
     545             :             fmt_addr(addr), stats->concurrent_count);
     546             : }
     547             : 
     548             : /* General private API */
     549             : 
     550             : /* Return true iff we have at least one DoS detection enabled. This is used to
     551             :  * decide if we need to allocate any kind of high level DoS object. */
     552             : static inline int
     553         390 : dos_is_enabled(void)
     554             : {
     555         390 :   return (dos_cc_enabled || dos_conn_enabled);
     556             : }
     557             : 
     558             : /* Circuit creation public API. */
     559             : 
     560             : /* Called when a CREATE cell is received from the given channel. */
     561             : void
     562         819 : dos_cc_new_create_cell(channel_t *chan)
     563             : {
     564         819 :   tor_addr_t addr;
     565         819 :   clientmap_entry_t *entry;
     566             : 
     567         819 :   tor_assert(chan);
     568             : 
     569             :   /* Skip everything if not enabled. */
     570         819 :   if (!dos_cc_enabled) {
     571           0 :     goto end;
     572             :   }
     573             : 
     574             :   /* Must be a client connection else we ignore. */
     575         819 :   if (!channel_is_client(chan)) {
     576           0 :     goto end;
     577             :   }
     578             :   /* Without an IP address, nothing can work. */
     579         819 :   if (!channel_get_addr_if_possible(chan, &addr)) {
     580           0 :     goto end;
     581             :   }
     582             : 
     583             :   /* We are only interested in client connection from the geoip cache. */
     584         819 :   entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT);
     585         819 :   if (entry == NULL) {
     586             :     /* We can have a connection creating circuits but not tracked by the geoip
     587             :      * cache. Once this DoS subsystem is enabled, we can end up here with no
     588             :      * entry for the channel. */
     589           0 :     goto end;
     590             :   }
     591             : 
     592             :   /* General comment. Even though the client can already be marked as
     593             :    * malicious, we continue to track statistics. If it keeps going above
     594             :    * threshold while marked, the defense period time will grow longer. There
     595             :    * is really no point at unmarking a client that keeps DoSing us. */
     596             : 
     597             :   /* First of all, we'll try to refill the circuit bucket opportunistically
     598             :    * before we assess. */
     599         819 :   cc_stats_refill_bucket(&entry->dos_stats.cc_stats, &addr);
     600             : 
     601             :   /* Take a token out of the circuit bucket if we are above 0 so we don't
     602             :    * underflow the bucket. */
     603         819 :   if (entry->dos_stats.cc_stats.circuit_bucket > 0) {
     604         819 :     entry->dos_stats.cc_stats.circuit_bucket--;
     605             :   }
     606             : 
     607             :   /* This is the detection. Assess at every CREATE cell if the client should
     608             :    * get marked as malicious. This should be kept as fast as possible. */
     609         819 :   if (cc_has_exhausted_circuits(&entry->dos_stats)) {
     610             :     /* If this is the first time we mark this entry, log it a info level.
     611             :      * Under heavy DDoS, logging each time we mark would results in lots and
     612             :      * lots of logs. */
     613           1 :     if (entry->dos_stats.cc_stats.marked_until_ts == 0) {
     614           1 :       log_debug(LD_DOS, "Detected circuit creation DoS by address: %s",
     615             :                 fmt_addr(&addr));
     616           1 :       cc_num_marked_addrs++;
     617             :     }
     618           1 :     cc_mark_client(&entry->dos_stats.cc_stats);
     619             :   }
     620             : 
     621         818 :  end:
     622         819 :   return;
     623             : }
     624             : 
     625             : /* Return the defense type that should be used for this circuit.
     626             :  *
     627             :  * This is part of the fast path and called a lot. */
     628             : dos_cc_defense_type_t
     629           2 : dos_cc_get_defense_type(channel_t *chan)
     630             : {
     631           2 :   tor_assert(chan);
     632             : 
     633             :   /* Skip everything if not enabled. */
     634           2 :   if (!dos_cc_enabled) {
     635           0 :     goto end;
     636             :   }
     637             : 
     638             :   /* On an OR circuit, we'll check if the previous channel is a marked client
     639             :    * connection detected by our DoS circuit creation mitigation subsystem. */
     640           2 :   if (cc_channel_addr_is_marked(chan)) {
     641             :     /* We've just assess that this circuit should trigger a defense for the
     642             :      * cell it just seen. Note it down. */
     643           1 :     cc_num_rejected_cells++;
     644           1 :     return dos_cc_defense_type;
     645             :   }
     646             : 
     647           1 :  end:
     648             :   return DOS_CC_DEFENSE_NONE;
     649             : }
     650             : 
     651             : /* Concurrent connection detection public API. */
     652             : 
     653             : /* Return true iff the given address is permitted to open another connection.
     654             :  * A defense value is returned for the caller to take appropriate actions. */
     655             : dos_conn_defense_type_t
     656           8 : dos_conn_addr_get_defense_type(const tor_addr_t *addr)
     657             : {
     658           8 :   clientmap_entry_t *entry;
     659             : 
     660           8 :   tor_assert(addr);
     661             : 
     662             :   /* Skip everything if not enabled. */
     663           8 :   if (!dos_conn_enabled) {
     664           0 :     goto end;
     665             :   }
     666             : 
     667             :   /* We are only interested in client connection from the geoip cache. */
     668           8 :   entry = geoip_lookup_client(addr, NULL, GEOIP_CLIENT_CONNECT);
     669           8 :   if (entry == NULL) {
     670           0 :     goto end;
     671             :   }
     672             : 
     673             :   /* Is this address marked as making too many client connections? */
     674           8 :   if (entry->dos_stats.conn_stats.marked_until_ts >= approx_time()) {
     675           2 :     conn_num_addr_connect_rejected++;
     676           2 :     return dos_conn_defense_type;
     677             :   }
     678             :   /* Reset it to 0 here so that if the marked timestamp has expired that is
     679             :    * we've gone beyond it, we have to reset it so the detection can mark it
     680             :    * again in the future. */
     681           6 :   entry->dos_stats.conn_stats.marked_until_ts = 0;
     682             : 
     683             :   /* Need to be above the maximum concurrent connection count to trigger a
     684             :    * defense. */
     685           6 :   if (entry->dos_stats.conn_stats.concurrent_count >
     686             :       dos_conn_max_concurrent_count) {
     687           2 :     conn_num_addr_rejected++;
     688           2 :     return dos_conn_defense_type;
     689             :   }
     690             : 
     691           4 :  end:
     692             :   return DOS_CONN_DEFENSE_NONE;
     693             : }
     694             : 
     695             : /* General API */
     696             : 
     697             : /* Take any appropriate actions for the given geoip entry that is about to get
     698             :  * freed. This is called for every entry that is being freed.
     699             :  *
     700             :  * This function will clear out the connection tracked flag if the concurrent
     701             :  * count of the entry is above 0 so if those connections end up being seen by
     702             :  * this subsystem, we won't try to decrement the counter for a new geoip entry
     703             :  * that might have been added after this call for the same address. */
     704             : void
     705         206 : dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent)
     706             : {
     707         206 :   tor_assert(geoip_ent);
     708             : 
     709             :   /* The count is down to 0 meaning no connections right now, we can safely
     710             :    * clear the geoip entry from the cache. */
     711         206 :   if (geoip_ent->dos_stats.conn_stats.concurrent_count == 0) {
     712         206 :     goto end;
     713             :   }
     714             : 
     715             :   /* For each connection matching the geoip entry address, we'll clear the
     716             :    * tracked flag because the entry is about to get removed from the geoip
     717             :    * cache. We do not try to decrement if the flag is not set. */
     718           0 :   SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
     719           0 :     if (conn->type == CONN_TYPE_OR) {
     720           0 :       or_connection_t *or_conn = TO_OR_CONN(conn);
     721           0 :       if (!tor_addr_compare(&geoip_ent->addr, &TO_CONN(or_conn)->addr,
     722             :                             CMP_EXACT)) {
     723           0 :         or_conn->tracked_for_dos_mitigation = 0;
     724             :       }
     725             :     }
     726           0 :   } SMARTLIST_FOREACH_END(conn);
     727             : 
     728           0 :  end:
     729         206 :   return;
     730             : }
     731             : 
     732             : /** A new geoip client entry has been allocated, initialize its DoS object. */
     733             : void
     734         213 : dos_geoip_entry_init(clientmap_entry_t *geoip_ent)
     735             : {
     736         213 :   tor_assert(geoip_ent);
     737             : 
     738             :   /* Initialize the connection count counter with the rate and burst
     739             :    * parameters taken either from configuration or consensus.
     740             :    *
     741             :    * We do this even if the DoS connection detection is not enabled because it
     742             :    * can be enabled at runtime and these counters need to be valid. */
     743         213 :   token_bucket_ctr_init(&geoip_ent->dos_stats.conn_stats.connect_count,
     744             :                         dos_conn_connect_rate, dos_conn_connect_burst,
     745         213 :                         (uint32_t) approx_time());
     746         213 : }
     747             : 
     748             : /* Note down that we've just refused a single hop client. This increments a
     749             :  * counter later used for the heartbeat. */
     750             : void
     751           0 : dos_note_refuse_single_hop_client(void)
     752             : {
     753           0 :   num_single_hop_client_refused++;
     754           0 : }
     755             : 
     756             : /* Return true iff single hop client connection (ESTABLISH_RENDEZVOUS) should
     757             :  * be refused. */
     758             : int
     759           1 : dos_should_refuse_single_hop_client(void)
     760             : {
     761             :   /* If we aren't a public relay, this shouldn't apply to anything. */
     762           1 :   if (!public_server_mode(get_options())) {
     763             :     return 0;
     764             :   }
     765             : 
     766           1 :   if (dos_get_options()->DoSRefuseSingleHopClientRendezvous != -1) {
     767           0 :     return dos_get_options()->DoSRefuseSingleHopClientRendezvous;
     768             :   }
     769             : 
     770           1 :   return (int) networkstatus_get_param(NULL,
     771             :                                        "DoSRefuseSingleHopClientRendezvous",
     772             :                                        0 /* default */, 0, 1);
     773             : }
     774             : 
     775             : /* Log a heartbeat message with some statistics. */
     776             : void
     777           1 : dos_log_heartbeat(void)
     778             : {
     779           1 :   smartlist_t *elems = smartlist_new();
     780             : 
     781             :   /* Stats number coming from relay.c append_cell_to_circuit_queue(). */
     782           1 :   smartlist_add_asprintf(elems,
     783             :                          "%" PRIu64 " circuits killed with too many cells",
     784             :                          stats_n_circ_max_cell_reached);
     785             : 
     786           1 :   if (dos_cc_enabled) {
     787           0 :     smartlist_add_asprintf(elems,
     788             :                            "%" PRIu64 " circuits rejected, "
     789             :                            "%" PRIu32 " marked addresses",
     790             :                            cc_num_rejected_cells, cc_num_marked_addrs);
     791             :   } else {
     792           1 :     smartlist_add_asprintf(elems, "[DoSCircuitCreationEnabled disabled]");
     793             :   }
     794             : 
     795           1 :   if (dos_conn_enabled) {
     796           0 :     smartlist_add_asprintf(elems,
     797             :                            "%" PRIu64 " same address concurrent "
     798             :                            "connections rejected", conn_num_addr_rejected);
     799           0 :     smartlist_add_asprintf(elems,
     800             :                            "%" PRIu64 " connections rejected",
     801             :                            conn_num_addr_connect_rejected);
     802             :   } else {
     803           1 :     smartlist_add_asprintf(elems, "[DoSConnectionEnabled disabled]");
     804             :   }
     805             : 
     806           1 :   if (dos_should_refuse_single_hop_client()) {
     807           0 :     smartlist_add_asprintf(elems,
     808             :                            "%" PRIu64 " single hop clients refused",
     809             :                            num_single_hop_client_refused);
     810             :   } else {
     811           1 :     smartlist_add_asprintf(elems,
     812             :                            "[DoSRefuseSingleHopClientRendezvous disabled]");
     813             :   }
     814             : 
     815             :   /* HS DoS stats. */
     816           1 :   smartlist_add_asprintf(elems,
     817             :                          "%" PRIu64 " INTRODUCE2 rejected",
     818             :                          hs_dos_get_intro2_rejected_count());
     819             : 
     820           1 :   char *msg = smartlist_join_strings(elems, ", ", 0, NULL);
     821             : 
     822           1 :   log_notice(LD_HEARTBEAT,
     823             :              "Heartbeat: DoS mitigation since startup: %s.", msg);
     824             : 
     825           1 :   tor_free(msg);
     826           6 :   SMARTLIST_FOREACH(elems, char *, e, tor_free(e));
     827           1 :   smartlist_free(elems);
     828           1 : }
     829             : 
     830             : /* Called when a new client connection has been established on the given
     831             :  * address. */
     832             : void
     833         153 : dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
     834             : {
     835         153 :   clientmap_entry_t *entry;
     836             : 
     837         153 :   tor_assert(or_conn);
     838             : 
     839             :   /* Past that point, we know we have at least one DoS detection subsystem
     840             :    * enabled so we'll start allocating stuff. */
     841         153 :   if (!dos_is_enabled()) {
     842           0 :     goto end;
     843             :   }
     844             : 
     845             :   /* We ignore any known address meaning an address of a known relay. The
     846             :    * reason to do so is because network reentry is possible where a client
     847             :    * connection comes from an Exit node. Even when we'll fix reentry, this is
     848             :    * a robust defense to keep in place. */
     849         153 :   if (nodelist_probably_contains_address(&TO_CONN(or_conn)->addr)) {
     850           5 :     goto end;
     851             :   }
     852             : 
     853             :   /* We are only interested in client connection from the geoip cache. */
     854         148 :   entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, transport_name,
     855             :                               GEOIP_CLIENT_CONNECT);
     856         148 :   if (BUG(entry == NULL)) {
     857             :     /* Should never happen because we note down the address in the geoip
     858             :      * cache before this is called. */
     859           0 :     goto end;
     860             :   }
     861             : 
     862             :   /* Update stats from this new connect. */
     863         148 :   conn_update_on_connect(&entry->dos_stats.conn_stats,
     864             :                          &TO_CONN(or_conn)->addr);
     865             : 
     866         148 :   or_conn->tracked_for_dos_mitigation = 1;
     867             : 
     868         153 :  end:
     869         153 :   return;
     870             : }
     871             : 
     872             : /* Called when a client connection for the given IP address has been closed. */
     873             : void
     874           2 : dos_close_client_conn(const or_connection_t *or_conn)
     875             : {
     876           2 :   clientmap_entry_t *entry;
     877             : 
     878           2 :   tor_assert(or_conn);
     879             : 
     880             :   /* We have to decrement the count on tracked connection only even if the
     881             :    * subsystem has been disabled at runtime because it might be re-enabled
     882             :    * after and we need to keep a synchronized counter at all time. */
     883           2 :   if (!or_conn->tracked_for_dos_mitigation) {
     884           1 :     goto end;
     885             :   }
     886             : 
     887             :   /* We are only interested in client connection from the geoip cache. */
     888           1 :   entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, NULL,
     889             :                               GEOIP_CLIENT_CONNECT);
     890           1 :   if (entry == NULL) {
     891             :     /* This can happen because we can close a connection before the channel
     892             :      * got to be noted down in the geoip cache. */
     893           0 :     goto end;
     894             :   }
     895             : 
     896             :   /* Update stats from this new close. */
     897           1 :   conn_update_on_close(&entry->dos_stats.conn_stats, &TO_CONN(or_conn)->addr);
     898             : 
     899           2 :  end:
     900           2 :   return;
     901             : }
     902             : 
     903             : /* Called when the consensus has changed. We might have new consensus
     904             :  * parameters to look at. */
     905             : void
     906           5 : dos_consensus_has_changed(const networkstatus_t *ns)
     907             : {
     908             :   /* There are two ways to configure this subsystem, one at startup through
     909             :    * dos_init() which is called when the options are parsed. And this one
     910             :    * through the consensus. We don't want to enable any DoS mitigation if we
     911             :    * aren't a public relay. */
     912           5 :   if (!public_server_mode(get_options())) {
     913             :     return;
     914             :   }
     915             : 
     916           0 :   cc_consensus_has_changed(ns);
     917           0 :   conn_consensus_has_changed(ns);
     918             : 
     919             :   /* We were already enabled or we just became enabled but either way, set the
     920             :    * consensus parameters for all subsystems. */
     921           0 :   set_dos_parameters(ns);
     922             : }
     923             : 
     924             : /* Return true iff the DoS mitigation subsystem is enabled. */
     925             : int
     926         237 : dos_enabled(void)
     927             : {
     928         237 :   return dos_is_enabled();
     929             : }
     930             : 
     931             : /* Free everything from the Denial of Service subsystem. */
     932             : void
     933         240 : dos_free_all(void)
     934             : {
     935             :   /* Free the circuit creation mitigation subsystem. It is safe to do this
     936             :    * even if it wasn't initialized. */
     937         240 :   cc_free_all();
     938             : 
     939             :   /* Free the connection mitigation subsystem. It is safe to do this even if
     940             :    * it wasn't initialized. */
     941         240 :   conn_free_all();
     942         240 : }
     943             : 
     944             : /* Initialize the Denial of Service subsystem. */
     945             : void
     946           9 : dos_init(void)
     947             : {
     948             :   /* To initialize, we only need to get the parameters. */
     949           9 :   set_dos_parameters(NULL);
     950           9 : }

Generated by: LCOV version 1.14