tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

nodefamily.c (11962B)


      1 /* Copyright (c) 2001 Matej Pfajfar.
      2 * Copyright (c) 2001-2004, Roger Dingledine.
      3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      5 /* See LICENSE for licensing information */
      6 
      7 /**
      8 * \file nodefamily.c
      9 * \brief Code to manipulate encoded, reference-counted node families.  We
     10 *  use these tricks to save space, since these families would otherwise
     11 *  require a large number of tiny allocations.
     12 **/
     13 
     14 #include "core/or/or.h"
     15 #include "feature/nodelist/nickname.h"
     16 #include "feature/nodelist/nodefamily.h"
     17 #include "feature/nodelist/nodefamily_st.h"
     18 #include "feature/nodelist/nodelist.h"
     19 #include "feature/relay/router.h"
     20 #include "feature/nodelist/routerlist.h"
     21 
     22 #include "ht.h"
     23 #include "siphash.h"
     24 
     25 #include "lib/container/smartlist.h"
     26 #include "lib/ctime/di_ops.h"
     27 #include "lib/defs/digest_sizes.h"
     28 #include "lib/log/util_bug.h"
     29 
     30 #include <stdlib.h>
     31 #include <string.h>
     32 
     33 /**
     34 * Allocate and return a blank node family with space to hold <b>n_members</b>
     35 * members.
     36 */
     37 static nodefamily_t *
     38 nodefamily_alloc(int n_members)
     39 {
     40  size_t alloc_len = offsetof(nodefamily_t, family_members) +
     41    NODEFAMILY_ARRAY_SIZE(n_members);
     42  nodefamily_t *nf = tor_malloc_zero(alloc_len);
     43  nf->n_members = n_members;
     44  return nf;
     45 }
     46 
     47 /**
     48 * Hashtable hash implementation.
     49 */
     50 static inline unsigned int
     51 nodefamily_hash(const nodefamily_t *nf)
     52 {
     53  return (unsigned) siphash24g(nf->family_members,
     54                               NODEFAMILY_ARRAY_SIZE(nf->n_members));
     55 }
     56 
     57 /**
     58 * Hashtable equality implementation.
     59 */
     60 static inline unsigned int
     61 nodefamily_eq(const nodefamily_t *a, const nodefamily_t *b)
     62 {
     63  return (a->n_members == b->n_members) &&
     64    fast_memeq(a->family_members, b->family_members,
     65               NODEFAMILY_ARRAY_SIZE(a->n_members));
     66 }
     67 
     68 static HT_HEAD(nodefamily_map, nodefamily_t) the_node_families
     69  = HT_INITIALIZER();
     70 
     71 HT_PROTOTYPE(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
     72             nodefamily_eq);
     73 HT_GENERATE2(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
     74             node_family_eq, 0.6, tor_reallocarray_, tor_free_);
     75 
     76 /**
     77 * Parse the family declaration in <b>s</b>, returning the canonical
     78 * <b>nodefamily_t</b> for its members.  Return NULL on error.
     79 *
     80 * If <b>rsa_id_self</b> is provided, it is a DIGEST_LEN-byte digest
     81 * for the router that declared this family: insert it into the
     82 * family declaration if it is not there already.
     83 *
     84 * If NF_WARN_MALFORMED is set in <b>flags</b>, warn about any
     85 * elements that we can't parse.  (By default, we log at info.)
     86 *
     87 * If NF_REJECT_MALFORMED is set in <b>flags</b>, treat any unparseable
     88 * elements as an error. (By default, we simply omit them.)
     89 **/
     90 nodefamily_t *
     91 nodefamily_parse(const char *s, const uint8_t *rsa_id_self,
     92                 unsigned flags)
     93 {
     94  smartlist_t *sl = smartlist_new();
     95  smartlist_split_string(sl, s, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
     96  nodefamily_t *result = nodefamily_from_members(sl, rsa_id_self, flags, NULL);
     97  SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
     98  smartlist_free(sl);
     99  return result;
    100 }
    101 
    102 /**
    103 * Canonicalize the family list <b>s</b>, returning a newly allocated string.
    104 *
    105 * The canonicalization rules are fully specified in dir-spec.txt, but,
    106 * briefly: $hexid entries are put in caps, $hexid[=~]foo entries are
    107 * truncated, nicknames are put into lowercase, unrecognized entries are left
    108 * alone, and everything is sorted.
    109 **/
    110 char *
    111 nodefamily_canonicalize(const char *s, const uint8_t *rsa_id_self,
    112                        unsigned flags)
    113 {
    114  smartlist_t *sl = smartlist_new();
    115  smartlist_t *result_members = smartlist_new();
    116  smartlist_split_string(sl, s, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    117  nodefamily_t *nf = nodefamily_from_members(sl, rsa_id_self, flags,
    118                                             result_members);
    119 
    120  char *formatted = nodefamily_format(nf);
    121  smartlist_split_string(result_members, formatted, NULL,
    122                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    123  smartlist_sort_strings(result_members);
    124  char *combined = smartlist_join_strings(result_members, " ", 0, NULL);
    125 
    126  nodefamily_free(nf);
    127  SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
    128  smartlist_free(sl);
    129  SMARTLIST_FOREACH(result_members, char *, cp, tor_free(cp));
    130  smartlist_free(result_members);
    131  tor_free(formatted);
    132 
    133  return combined;
    134 }
    135 
    136 /**
    137 * qsort helper for encoded nodefamily elements.
    138 **/
    139 static int
    140 compare_members(const void *a, const void *b)
    141 {
    142  return fast_memcmp(a, b, NODEFAMILY_MEMBER_LEN);
    143 }
    144 
    145 /**
    146 * Parse the member strings in <b>members</b>, returning their canonical
    147 * <b>nodefamily_t</b>.  Return NULL on error.
    148 *
    149 * If <b>rsa_id_self</b> is provided, it is a DIGEST_LEN-byte digest
    150 * for the router that declared this family: insert it into the
    151 * family declaration if it is not there already.
    152 *
    153 * The <b>flags</b> element is interpreted as in nodefamily_parse().
    154 *
    155 * If <b>unrecognized</b> is provided, fill it copies of any unrecognized
    156 * members.  (Note that malformed $hexids are not considered unrecognized.)
    157 **/
    158 nodefamily_t *
    159 nodefamily_from_members(const smartlist_t *members,
    160                        const uint8_t *rsa_id_self,
    161                        unsigned flags,
    162                        smartlist_t *unrecognized_out)
    163 {
    164  const int n_self = rsa_id_self ? 1 : 0;
    165  int n_bad_elements = 0;
    166  int n_members = smartlist_len(members) + n_self;
    167  nodefamily_t *tmp = nodefamily_alloc(n_members);
    168  uint8_t *ptr = NODEFAMILY_MEMBER_PTR(tmp, 0);
    169 
    170  SMARTLIST_FOREACH_BEGIN(members, const char *, cp) {
    171    bool bad_element = true;
    172    if (is_legal_nickname(cp)) {
    173      ptr[0] = NODEFAMILY_BY_NICKNAME;
    174      tor_assert(strlen(cp) < DIGEST_LEN); // guaranteed by is_legal_nickname
    175      memcpy(ptr+1, cp, strlen(cp));
    176      tor_strlower((char*) ptr+1);
    177      bad_element = false;
    178    } else if (is_legal_hexdigest(cp)) {
    179      char digest_buf[DIGEST_LEN];
    180      char nn_buf[MAX_NICKNAME_LEN+1];
    181      char nn_char=0;
    182      if (hex_digest_nickname_decode(cp, digest_buf, &nn_char, nn_buf)==0) {
    183        bad_element = false;
    184        ptr[0] = NODEFAMILY_BY_RSA_ID;
    185        memcpy(ptr+1, digest_buf, DIGEST_LEN);
    186      }
    187    } else {
    188      if (unrecognized_out)
    189        smartlist_add_strdup(unrecognized_out, cp);
    190    }
    191 
    192    if (bad_element) {
    193      const int severity = (flags & NF_WARN_MALFORMED) ? LOG_WARN : LOG_INFO;
    194      log_fn(severity, LD_GENERAL,
    195             "Bad element %s while parsing a node family.",
    196             escaped(cp));
    197      ++n_bad_elements;
    198    } else {
    199      ptr += NODEFAMILY_MEMBER_LEN;
    200    }
    201  } SMARTLIST_FOREACH_END(cp);
    202 
    203  if (n_bad_elements && (flags & NF_REJECT_MALFORMED))
    204    goto err;
    205 
    206  if (rsa_id_self) {
    207    /* Add self. */
    208    ptr[0] = NODEFAMILY_BY_RSA_ID;
    209    memcpy(ptr+1, rsa_id_self, DIGEST_LEN);
    210  }
    211 
    212  n_members -= n_bad_elements;
    213 
    214  /* Sort tmp into canonical order. */
    215  qsort(tmp->family_members, n_members, NODEFAMILY_MEMBER_LEN,
    216        compare_members);
    217 
    218  /* Remove duplicates. */
    219  int i;
    220  for (i = 0; i < n_members-1; ++i) {
    221    uint8_t *thisptr = NODEFAMILY_MEMBER_PTR(tmp, i);
    222    uint8_t *nextptr = NODEFAMILY_MEMBER_PTR(tmp, i+1);
    223    if (fast_memeq(thisptr, nextptr, NODEFAMILY_MEMBER_LEN)) {
    224      memmove(thisptr, nextptr, (n_members-i-1)*NODEFAMILY_MEMBER_LEN);
    225      --n_members;
    226      --i;
    227    }
    228  }
    229  int n_members_alloc = tmp->n_members;
    230  tmp->n_members = n_members;
    231 
    232  /* See if we already allocated this family. */
    233  nodefamily_t *found = HT_FIND(nodefamily_map, &the_node_families, tmp);
    234  if (found) {
    235    /* If we did, great: incref it and return it. */
    236    ++found->refcnt;
    237    tor_free(tmp);
    238    return found;
    239  } else {
    240    /* If not, insert it into the hashtable. */
    241    if (n_members_alloc != n_members) {
    242      /* Compact the family if needed */
    243      nodefamily_t *tmp2 = nodefamily_alloc(n_members);
    244      memcpy(tmp2->family_members, tmp->family_members,
    245             n_members * NODEFAMILY_MEMBER_LEN);
    246      tor_free(tmp);
    247      tmp = tmp2;
    248    }
    249 
    250    tmp->refcnt = 1;
    251    HT_INSERT(nodefamily_map, &the_node_families, tmp);
    252    return tmp;
    253  }
    254 
    255 err:
    256  tor_free(tmp);
    257  return NULL;
    258 }
    259 
    260 /**
    261 * Drop our reference to <b>family</b>, freeing it if there are no more
    262 * references.
    263 */
    264 void
    265 nodefamily_free_(nodefamily_t *family)
    266 {
    267  if (family == NULL)
    268    return;
    269 
    270  --family->refcnt;
    271 
    272  if (family->refcnt == 0) {
    273    HT_REMOVE(nodefamily_map, &the_node_families, family);
    274    tor_free(family);
    275  }
    276 }
    277 
    278 /**
    279 * Return true iff <b>family</b> contains the SHA1 RSA1024 identity
    280 * <b>rsa_id</b>.
    281 */
    282 bool
    283 nodefamily_contains_rsa_id(const nodefamily_t *family,
    284                           const uint8_t *rsa_id)
    285 {
    286  if (family == NULL)
    287    return false;
    288 
    289  unsigned i;
    290  for (i = 0; i < family->n_members; ++i) {
    291    const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
    292    if (ptr[0] == NODEFAMILY_BY_RSA_ID &&
    293        fast_memeq(ptr+1, rsa_id, DIGEST_LEN)) {
    294      return true;
    295    }
    296  }
    297  return false;
    298 }
    299 
    300 /**
    301 * Return true iff <b>family</b> contains the nickname <b>name</b>.
    302 */
    303 bool
    304 nodefamily_contains_nickname(const nodefamily_t *family,
    305                             const char *name)
    306 {
    307  if (family == NULL)
    308    return false;
    309 
    310  unsigned i;
    311  for (i = 0; i < family->n_members; ++i) {
    312    const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
    313    // note that the strcasecmp() is safe because there is always at least one
    314    // NUL in the encoded nickname, because all legal nicknames are less than
    315    // DIGEST_LEN bytes long.
    316    if (ptr[0] == NODEFAMILY_BY_NICKNAME && !strcasecmp((char*)ptr+1, name)) {
    317      return true;
    318    }
    319  }
    320  return false;
    321 }
    322 
    323 /**
    324 * Return true if <b>family</b> contains the nickname or the RSA ID for
    325 * <b>node</b>
    326 **/
    327 bool
    328 nodefamily_contains_node(const nodefamily_t *family,
    329                         const node_t *node)
    330 {
    331  return
    332    nodefamily_contains_nickname(family, node_get_nickname(node))
    333    ||
    334    nodefamily_contains_rsa_id(family, node_get_rsa_id_digest(node));
    335 }
    336 
    337 /**
    338 * Look up every entry in <b>family</b>, and add add the corresponding
    339 * node_t to <b>out</b>.
    340 **/
    341 void
    342 nodefamily_add_nodes_to_smartlist(const nodefamily_t *family,
    343                                  smartlist_t *out)
    344 {
    345  if (!family)
    346    return;
    347 
    348  unsigned i;
    349  for (i = 0; i < family->n_members; ++i) {
    350    const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
    351    const node_t *node = NULL;
    352    switch (ptr[0]) {
    353      case NODEFAMILY_BY_NICKNAME:
    354        node = node_get_by_nickname((char*)ptr+1, NNF_NO_WARN_UNNAMED);
    355        break;
    356      case NODEFAMILY_BY_RSA_ID:
    357        node = node_get_by_id((char*)ptr+1);
    358        break;
    359      default:
    360        /* LCOV_EXCL_START */
    361        tor_assert_nonfatal_unreached();
    362        break;
    363        /* LCOV_EXCL_STOP */
    364    }
    365    if (node)
    366      smartlist_add(out, (void *)node);
    367  }
    368 }
    369 
    370 /**
    371 * Encode <b>family</b> as a space-separated string.
    372 */
    373 char *
    374 nodefamily_format(const nodefamily_t *family)
    375 {
    376  if (!family)
    377    return tor_strdup("");
    378 
    379  unsigned i;
    380  smartlist_t *sl = smartlist_new();
    381  for (i = 0; i < family->n_members; ++i) {
    382    const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
    383    switch (ptr[0]) {
    384      case NODEFAMILY_BY_NICKNAME:
    385        smartlist_add_strdup(sl, (char*)ptr+1);
    386        break;
    387      case NODEFAMILY_BY_RSA_ID: {
    388        char buf[HEX_DIGEST_LEN+2];
    389        buf[0]='$';
    390        base16_encode(buf+1, sizeof(buf)-1, (char*)ptr+1, DIGEST_LEN);
    391        tor_strupper(buf);
    392        smartlist_add_strdup(sl, buf);
    393        break;
    394      }
    395      default:
    396        /* LCOV_EXCL_START */
    397        tor_assert_nonfatal_unreached();
    398        break;
    399        /* LCOV_EXCL_STOP */
    400    }
    401  }
    402 
    403  char *result = smartlist_join_strings(sl, " ", 0, NULL);
    404  SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
    405  smartlist_free(sl);
    406  return result;
    407 }
    408 
    409 /**
    410 * Free all storage held in the nodefamily map.
    411 **/
    412 void
    413 nodefamily_free_all(void)
    414 {
    415  HT_CLEAR(nodefamily_map, &the_node_families);
    416 }