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 */
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.
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"
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"
34 * Allocate and return a blank node family with space to hold <b>n_members</b>
38 nodefamily_alloc(int n_members
)
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
;
48 * Hashtable hash implementation.
50 static inline unsigned int
51 nodefamily_hash(const nodefamily_t
*nf
)
53 return (unsigned) siphash24g(nf
->family_members
,
54 NODEFAMILY_ARRAY_SIZE(nf
->n_members
));
58 * Hashtable equality implementation.
60 static inline unsigned int
61 nodefamily_eq(const nodefamily_t
*a
, const nodefamily_t
*b
)
63 return (a
->n_members
== b
->n_members
) &&
64 fast_memeq(a
->family_members
, b
->family_members
,
65 NODEFAMILY_ARRAY_SIZE(a
->n_members
));
68 static HT_HEAD(nodefamily_map
, nodefamily_t
) the_node_families
71 HT_PROTOTYPE(nodefamily_map
, nodefamily_t
, ht_ent
, nodefamily_hash
,
73 HT_GENERATE2(nodefamily_map
, nodefamily_t
, ht_ent
, nodefamily_hash
,
74 node_family_eq
, 0.6, tor_reallocarray_
, tor_free_
);
77 * Parse the family declaration in <b>s</b>, returning the canonical
78 * <b>nodefamily_t</b> for its members. Return NULL on error.
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.
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.)
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.)
91 nodefamily_parse(const char *s
, const uint8_t *rsa_id_self
,
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
));
103 * Canonicalize the family list <b>s</b>, returning a newly allocated string.
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.
111 nodefamily_canonicalize(const char *s
, const uint8_t *rsa_id_self
,
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
,
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
);
127 SMARTLIST_FOREACH(sl
, char *, cp
, tor_free(cp
));
129 SMARTLIST_FOREACH(result_members
, char *, cp
, tor_free(cp
));
130 smartlist_free(result_members
);
137 * qsort helper for encoded nodefamily elements.
140 compare_members(const void *a
, const void *b
)
142 return fast_memcmp(a
, b
, NODEFAMILY_MEMBER_LEN
);
146 * Parse the member strings in <b>members</b>, returning their canonical
147 * <b>nodefamily_t</b>. Return NULL on error.
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.
153 * The <b>flags</b> element is interpreted as in nodefamily_parse().
155 * If <b>unrecognized</b> is provided, fill it copies of any unrecognized
156 * members. (Note that malformed $hexids are not considered unrecognized.)
159 nodefamily_from_members(const smartlist_t
*members
,
160 const uint8_t *rsa_id_self
,
162 smartlist_t
*unrecognized_out
)
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);
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);
178 } else if (is_legal_hexdigest(cp
)) {
179 char digest_buf
[DIGEST_LEN
];
180 char nn_buf
[MAX_NICKNAME_LEN
+1];
182 if (hex_digest_nickname_decode(cp
, digest_buf
, &nn_char
, nn_buf
)==0) {
184 ptr
[0] = NODEFAMILY_BY_RSA_ID
;
185 memcpy(ptr
+1, digest_buf
, DIGEST_LEN
);
188 if (unrecognized_out
)
189 smartlist_add_strdup(unrecognized_out
, cp
);
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.",
199 ptr
+= NODEFAMILY_MEMBER_LEN
;
201 } SMARTLIST_FOREACH_END(cp
);
203 if (n_bad_elements
&& (flags
& NF_REJECT_MALFORMED
))
208 ptr
[0] = NODEFAMILY_BY_RSA_ID
;
209 memcpy(ptr
+1, rsa_id_self
, DIGEST_LEN
);
212 n_members
-= n_bad_elements
;
214 /* Sort tmp into canonical order. */
215 qsort(tmp
->family_members
, n_members
, NODEFAMILY_MEMBER_LEN
,
218 /* Remove duplicates. */
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
);
229 int n_members_alloc
= tmp
->n_members
;
230 tmp
->n_members
= n_members
;
232 /* See if we already allocated this family. */
233 nodefamily_t
*found
= HT_FIND(nodefamily_map
, &the_node_families
, tmp
);
235 /* If we did, great: incref it and return it. */
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
);
251 HT_INSERT(nodefamily_map
, &the_node_families
, tmp
);
261 * Drop our reference to <b>family</b>, freeing it if there are no more
265 nodefamily_free_(nodefamily_t
*family
)
272 if (family
->refcnt
== 0) {
273 HT_REMOVE(nodefamily_map
, &the_node_families
, family
);
279 * Return true iff <b>family</b> contains the SHA1 RSA1024 identity
283 nodefamily_contains_rsa_id(const nodefamily_t
*family
,
284 const uint8_t *rsa_id
)
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
)) {
301 * Return true iff <b>family</b> contains the nickname <b>name</b>.
304 nodefamily_contains_nickname(const nodefamily_t
*family
,
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
)) {
324 * Return true if <b>family</b> contains the nickname or the RSA ID for
328 nodefamily_contains_node(const nodefamily_t
*family
,
332 nodefamily_contains_nickname(family
, node_get_nickname(node
))
334 nodefamily_contains_rsa_id(family
, node_get_rsa_id_digest(node
));
338 * Look up every entry in <b>family</b>, and add add the corresponding
339 * node_t to <b>out</b>.
342 nodefamily_add_nodes_to_smartlist(const nodefamily_t
*family
,
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
;
353 case NODEFAMILY_BY_NICKNAME
:
354 node
= node_get_by_nickname((char*)ptr
+1, NNF_NO_WARN_UNNAMED
);
356 case NODEFAMILY_BY_RSA_ID
:
357 node
= node_get_by_id((char*)ptr
+1);
360 /* LCOV_EXCL_START */
361 tor_assert_nonfatal_unreached();
366 smartlist_add(out
, (void *)node
);
371 * Encode <b>family</b> as a space-separated string.
374 nodefamily_format(const nodefamily_t
*family
)
377 return tor_strdup("");
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
);
384 case NODEFAMILY_BY_NICKNAME
:
385 smartlist_add_strdup(sl
, (char*)ptr
+1);
387 case NODEFAMILY_BY_RSA_ID
: {
388 char buf
[HEX_DIGEST_LEN
+2];
390 base16_encode(buf
+1, sizeof(buf
)-1, (char*)ptr
+1, DIGEST_LEN
);
392 smartlist_add_strdup(sl
, buf
);
396 /* LCOV_EXCL_START */
397 tor_assert_nonfatal_unreached();
403 char *result
= smartlist_join_strings(sl
, " ", 0, NULL
);
404 SMARTLIST_FOREACH(sl
, char *, cp
, tor_free(cp
));
410 * Free all storage held in the nodefamily map.
413 nodefamily_free_all(void)
415 HT_CLEAR(nodefamily_map
, &the_node_families
);