hs_dos.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /* Copyright (c) 2019, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file hs_dos.c
  5. * \brief Implement denial of service mitigation for the onion service
  6. * subsystem.
  7. *
  8. * This module defenses:
  9. *
  10. * - Introduction Rate Limiting: If enabled by the consensus, an introduction
  11. * point will rate limit client introduction towards the service (INTRODUCE2
  12. * cells). It uses a token bucket model with a rate and burst per second.
  13. *
  14. * Proposal 305 will expand this module by allowing an operator to define
  15. * these values into the ESTABLISH_INTRO cell. Not yet implemented.
  16. **/
  17. #define HS_DOS_PRIVATE
  18. #include "core/or/or.h"
  19. #include "app/config/config.h"
  20. #include "core/or/circuitlist.h"
  21. #include "feature/hs/hs_circuitmap.h"
  22. #include "feature/nodelist/networkstatus.h"
  23. #include "feature/relay/routermode.h"
  24. #include "lib/evloop/token_bucket.h"
  25. #include "hs_dos.h"
  26. /* Default value of the allowed INTRODUCE2 cell rate per second. Above that
  27. * value per second, the introduction is denied. */
  28. #define HS_DOS_INTRODUCE_CELL_RATE_PER_SEC 25
  29. /* Default value of the allowed INTRODUCE2 cell burst per second. This is the
  30. * maximum value a token bucket has per second. We thus allow up to this value
  31. * of INTRODUCE2 cell per second but the bucket is refilled by the rate value
  32. * but never goes above that burst value. */
  33. #define HS_DOS_INTRODUCE_CELL_BURST_PER_SEC 200
  34. /* Default value of the consensus parameter enabling or disabling the
  35. * introduction DoS defense. Disabled by default. */
  36. #define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0
  37. /* Consensus parameters. */
  38. static uint32_t hs_dos_introduce_rate_per_sec =
  39. HS_DOS_INTRODUCE_CELL_RATE_PER_SEC;
  40. static uint32_t hs_dos_introduce_burst_per_sec =
  41. HS_DOS_INTRODUCE_CELL_BURST_PER_SEC;
  42. static uint32_t hs_dos_introduce_enabled =
  43. HS_DOS_INTRODUCE_ENABLED_DEFAULT;
  44. static uint32_t
  45. get_param_intro_dos_enabled(const networkstatus_t *ns)
  46. {
  47. return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSDefense",
  48. HS_DOS_INTRODUCE_ENABLED_DEFAULT, 0, 1);
  49. }
  50. /* Return the parameter for the introduction rate per sec. */
  51. static uint32_t
  52. get_param_rate_per_sec(const networkstatus_t *ns)
  53. {
  54. return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSRatePerSec",
  55. HS_DOS_INTRODUCE_CELL_RATE_PER_SEC,
  56. 0, INT32_MAX);
  57. }
  58. /* Return the parameter for the introduction burst per sec. */
  59. static uint32_t
  60. get_param_burst_per_sec(const networkstatus_t *ns)
  61. {
  62. return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSBurstPerSec",
  63. HS_DOS_INTRODUCE_CELL_BURST_PER_SEC,
  64. 0, INT32_MAX);
  65. }
  66. /* Go over all introduction circuit relay side and adjust their rate/burst
  67. * values using the global parameters. This is called right after the
  68. * consensus parameters might have changed. */
  69. static void
  70. update_intro_circuits(void)
  71. {
  72. /* Returns all HS version intro circuits. */
  73. smartlist_t *intro_circs = hs_circuitmap_get_all_intro_circ_relay_side();
  74. SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) {
  75. /* Adjust the rate/burst value that might have changed. */
  76. token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
  77. hs_dos_get_intro2_rate(),
  78. hs_dos_get_intro2_burst());
  79. } SMARTLIST_FOREACH_END(circ);
  80. smartlist_free(intro_circs);
  81. }
  82. /* Set consensus parameters. */
  83. static void
  84. set_consensus_parameters(const networkstatus_t *ns)
  85. {
  86. hs_dos_introduce_rate_per_sec = get_param_rate_per_sec(ns);
  87. hs_dos_introduce_burst_per_sec = get_param_burst_per_sec(ns);
  88. hs_dos_introduce_enabled = get_param_intro_dos_enabled(ns);
  89. /* The above might have changed which means we need to go through all
  90. * introduction circuits (relay side) and update the token buckets. */
  91. update_intro_circuits();
  92. }
  93. /*
  94. * Public API.
  95. */
  96. /* Return the INTRODUCE2 cell rate per second. */
  97. uint32_t
  98. hs_dos_get_intro2_rate(void)
  99. {
  100. return hs_dos_introduce_rate_per_sec;
  101. }
  102. /* Return the INTRODUCE2 cell burst per second. */
  103. uint32_t
  104. hs_dos_get_intro2_burst(void)
  105. {
  106. return hs_dos_introduce_burst_per_sec;
  107. }
  108. /* Called when the consensus has changed. We might have new consensus
  109. * parameters to look at. */
  110. void
  111. hs_dos_consensus_has_changed(const networkstatus_t *ns)
  112. {
  113. /* No point on updating these values if we are not a public relay that can
  114. * be picked to be an introduction point. */
  115. if (!public_server_mode(get_options())) {
  116. return;
  117. }
  118. set_consensus_parameters(ns);
  119. }
  120. /* Return true iff an INTRODUCE2 cell can be sent on the given service
  121. * introduction circuit. */
  122. bool
  123. hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
  124. {
  125. tor_assert(s_intro_circ);
  126. /* Always allowed if the defense is disabled. */
  127. if (!hs_dos_introduce_enabled) {
  128. return true;
  129. }
  130. /* Should not happen but if so, scream loudly. */
  131. if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
  132. return false;
  133. }
  134. /* This is called just after we got a valid and parsed INTRODUCE1 cell. The
  135. * service has been found and we have its introduction circuit.
  136. *
  137. * First, the INTRODUCE2 bucket will be refilled (if any). Then, decremented
  138. * because we are about to send or not the cell we just got. Finally,
  139. * evaluate if we can send it based on our token bucket state. */
  140. /* Refill INTRODUCE2 bucket. */
  141. token_bucket_ctr_refill(&s_intro_circ->introduce2_bucket,
  142. (uint32_t) approx_time());
  143. /* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't
  144. * underflow else we end up with a too big of a bucket. */
  145. if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
  146. token_bucket_ctr_dec(&s_intro_circ->introduce2_bucket, 1);
  147. }
  148. /* Finally, we can send a new INTRODUCE2 if there are still tokens. */
  149. return token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0;
  150. }
  151. /* Initialize the onion service Denial of Service subsystem. */
  152. void
  153. hs_dos_init(void)
  154. {
  155. set_consensus_parameters(NULL);
  156. }