address_set.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /* Copyright (c) 2018, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file address_set.c
  5. * \brief Implementation for a set of addresses.
  6. *
  7. * This module was first written on a semi-emergency basis to improve the
  8. * robustness of the anti-DoS module. As such, it's written in a pretty
  9. * conservative way, and should be susceptible to improvement later on.
  10. **/
  11. #include "orconfig.h"
  12. #include "address_set.h"
  13. #include "address.h"
  14. #include "compat.h"
  15. #include "container.h"
  16. #include "crypto.h"
  17. #include "util.h"
  18. #include "siphash.h"
  19. /** How many 64-bit siphash values to extract per address */
  20. #define N_HASHES 2
  21. /** How many bloom-filter bits we set per address. This is twice the N_HASHES
  22. * value, since we split the siphash output into two 32-bit values. */
  23. #define N_BITS_PER_ITEM (N_HASHES * 2)
  24. /* XXXX This code is largely duplicated with digestset_t. We should merge
  25. * them together into a common bloom-filter implementation. I'm keeping
  26. * them separate for now, though, since this module needs to be backported
  27. * all the way to 0.2.9.
  28. *
  29. * The main difference between digestset_t and this code is that we use
  30. * independent siphashes rather than messing around with bit-shifts. The
  31. * approach here is probably more sound, and we should prefer it if&when we
  32. * unify the implementations.
  33. **/
  34. struct address_set_t {
  35. /** siphash keys to make N_HASHES independent hashes for each address. */
  36. struct sipkey key[N_HASHES];
  37. int mask; /**< One less than the number of bits in <b>ba</b>; always one less
  38. * than a power of two. */
  39. bitarray_t *ba; /**< A bit array to implement the Bloom filter. */
  40. };
  41. /**
  42. * Allocate and return an address_set, suitable for holding up to
  43. * <b>max_address_guess</b> distinct values.
  44. */
  45. address_set_t *
  46. address_set_new(int max_addresses_guess)
  47. {
  48. /* See digestset_new() for rationale on this equation. */
  49. int n_bits = 1u << (tor_log2(max_addresses_guess)+5);
  50. address_set_t *set = tor_malloc_zero(sizeof(address_set_t));
  51. set->mask = n_bits - 1;
  52. set->ba = bitarray_init_zero(n_bits);
  53. crypto_rand((char*) set->key, sizeof(set->key));
  54. return set;
  55. }
  56. /**
  57. * Release all storage associated with <b>set</b>
  58. */
  59. void
  60. address_set_free(address_set_t *set)
  61. {
  62. if (! set)
  63. return;
  64. bitarray_free(set->ba);
  65. tor_free(set);
  66. }
  67. /** Yield the bit index corresponding to 'val' for set. */
  68. #define BIT(set, val) ((val) & (set)->mask)
  69. /**
  70. * Add <b>addr</b> to <b>set</b>.
  71. *
  72. * All future queries for <b>addr</b> in set will return true. Removing
  73. * items is not possible.
  74. */
  75. void
  76. address_set_add(address_set_t *set, const struct tor_addr_t *addr)
  77. {
  78. int i;
  79. for (i = 0; i < N_HASHES; ++i) {
  80. uint64_t h = tor_addr_keyed_hash(&set->key[i], addr);
  81. uint32_t high_bits = (uint32_t)(h >> 32);
  82. uint32_t low_bits = (uint32_t)(h);
  83. bitarray_set(set->ba, BIT(set, high_bits));
  84. bitarray_set(set->ba, BIT(set, low_bits));
  85. }
  86. }
  87. /** As address_set_add(), but take an ipv4 address in host order. */
  88. void
  89. address_set_add_ipv4h(address_set_t *set, uint32_t addr)
  90. {
  91. tor_addr_t a;
  92. tor_addr_from_ipv4h(&a, addr);
  93. address_set_add(set, &a);
  94. }
  95. /**
  96. * Return true if <b>addr</b> if a member of <b>set</b>. (And probably,
  97. * return false if <b>addr</b> is not a member of set.)
  98. */
  99. int
  100. address_set_probably_contains(address_set_t *set,
  101. const struct tor_addr_t *addr)
  102. {
  103. int i, matches = 0;
  104. for (i = 0; i < N_HASHES; ++i) {
  105. uint64_t h = tor_addr_keyed_hash(&set->key[i], addr);
  106. uint32_t high_bits = (uint32_t)(h >> 32);
  107. uint32_t low_bits = (uint32_t)(h);
  108. // Note that !! is necessary here, since bitarray_is_set does not
  109. // necessarily return 1 on true.
  110. matches += !! bitarray_is_set(set->ba, BIT(set, high_bits));
  111. matches += !! bitarray_is_set(set->ba, BIT(set, low_bits));
  112. }
  113. return matches == N_BITS_PER_ITEM;
  114. }