directory.c (26541B)
1 /* Copyright (c) 2001-2004, Roger Dingledine. 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 #include "core/or/or.h" 7 8 #include "app/config/config.h" 9 #include "core/mainloop/connection.h" 10 #include "core/or/circuitlist.h" 11 #include "core/or/connection_edge.h" 12 #include "core/or/connection_or.h" 13 #include "core/or/channeltls.h" 14 #include "feature/dircache/dircache.h" 15 #include "feature/dircache/dirserv.h" 16 #include "feature/dirclient/dirclient.h" 17 #include "feature/dircommon/directory.h" 18 #include "feature/dircommon/fp_pair.h" 19 #include "feature/hs/hs_cache.h" 20 #include "feature/stats/geoip_stats.h" 21 #include "lib/compress/compress.h" 22 23 #include "core/or/circuit_st.h" 24 #include "core/or/or_circuit_st.h" 25 #include "core/or/edge_connection_st.h" 26 #include "core/or/or_connection_st.h" 27 #include "feature/dircommon/dir_connection_st.h" 28 #include "feature/nodelist/routerinfo_st.h" 29 30 /** 31 * \file directory.c 32 * \brief Code to send and fetch information from directory authorities and 33 * caches via HTTP. 34 * 35 * Directory caches and authorities use dirserv.c to generate the results of a 36 * query and stream them to the connection; clients use routerparse.c to parse 37 * them. 38 * 39 * Every directory request has a dir_connection_t on the client side and on 40 * the server side. In most cases, the dir_connection_t object is a linked 41 * connection, tunneled through an edge_connection_t so that it can be a 42 * stream on the Tor network. The only non-tunneled connections are those 43 * that are used to upload material (descriptors and votes) to authorities. 44 * Among tunneled connections, some use one-hop circuits, and others use 45 * multi-hop circuits for anonymity. 46 * 47 * Directory requests are launched by calling 48 * directory_initiate_request(). This 49 * launch the connection, will construct an HTTP request with 50 * directory_send_command(), send the and wait for a response. The client 51 * later handles the response with connection_dir_client_reached_eof(), 52 * which passes the information received to another part of Tor. 53 * 54 * On the server side, requests are read in directory_handle_command(), 55 * which dispatches first on the request type (GET or POST), and then on 56 * the URL requested. GET requests are processed with a table-based 57 * dispatcher in url_table[]. The process of handling larger GET requests 58 * is complicated because we need to avoid allocating a copy of all the 59 * data to be sent to the client in one huge buffer. Instead, we spool the 60 * data into the buffer using logic in connection_dirserv_flushed_some() in 61 * dirserv.c. (TODO: If we extended buf.c to have a zero-copy 62 * reference-based buffer type, we could remove most of that code, at the 63 * cost of a bit more reference counting.) 64 **/ 65 66 /* In-points to directory.c: 67 * 68 * - directory_post_to_dirservers(), called from 69 * router_upload_dir_desc_to_dirservers() in router.c 70 * upload_service_descriptor() in rendservice.c 71 * - directory_get_from_dirserver(), called from 72 * run_scheduled_events() in main.c 73 * do_hup() in main.c 74 * - connection_dir_process_inbuf(), called from 75 * connection_process_inbuf() in connection.c 76 * - connection_dir_finished_flushing(), called from 77 * connection_finished_flushing() in connection.c 78 * - connection_dir_finished_connecting(), called from 79 * connection_finished_connecting() in connection.c 80 */ 81 82 /** 83 * Cast a `connection_t *` to a `dir_connection_t *`. 84 * 85 * Exit with an assertion failure if the input is not a 86 * `dir_connection_t`. 87 **/ 88 dir_connection_t * 89 TO_DIR_CONN(connection_t *c) 90 { 91 tor_assert(c->magic == DIR_CONNECTION_MAGIC); 92 return DOWNCAST(dir_connection_t, c); 93 } 94 95 /** 96 * Cast a `const connection_t *` to a `const dir_connection_t *`. 97 * 98 * Exit with an assertion failure if the input is not a 99 * `dir_connection_t`. 100 **/ 101 const dir_connection_t * 102 CONST_TO_DIR_CONN(const connection_t *c) 103 { 104 return TO_DIR_CONN((connection_t *)c); 105 } 106 107 /** Return false if the directory purpose <b>dir_purpose</b> 108 * does not require an anonymous (three-hop) connection. 109 * 110 * Return true 1) by default, 2) if all directory actions have 111 * specifically been configured to be over an anonymous connection, 112 * or 3) if the router is a bridge */ 113 int 114 purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose, 115 const char *resource) 116 { 117 if (get_options()->AllDirActionsPrivate) 118 return 1; 119 120 if (router_purpose == ROUTER_PURPOSE_BRIDGE) { 121 if (dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC 122 && resource && !strcmp(resource, "authority.z")) { 123 /* We are asking a bridge for its own descriptor. That doesn't need 124 anonymity. */ 125 return 0; 126 } 127 /* Assume all other bridge stuff needs anonymity. */ 128 return 1; /* if no circuits yet, this might break bootstrapping, but it's 129 * needed to be safe. */ 130 } 131 132 switch (dir_purpose) 133 { 134 case DIR_PURPOSE_UPLOAD_DIR: 135 case DIR_PURPOSE_UPLOAD_VOTE: 136 case DIR_PURPOSE_UPLOAD_SIGNATURES: 137 case DIR_PURPOSE_FETCH_STATUS_VOTE: 138 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: 139 case DIR_PURPOSE_FETCH_CONSENSUS: 140 case DIR_PURPOSE_FETCH_CERTIFICATE: 141 case DIR_PURPOSE_FETCH_SERVERDESC: 142 case DIR_PURPOSE_FETCH_EXTRAINFO: 143 case DIR_PURPOSE_FETCH_MICRODESC: 144 return 0; 145 case DIR_PURPOSE_HAS_FETCHED_HSDESC: 146 case DIR_PURPOSE_FETCH_HSDESC: 147 case DIR_PURPOSE_UPLOAD_HSDESC: 148 return 1; 149 case DIR_PURPOSE_SERVER: 150 default: 151 log_warn(LD_BUG, "Called with dir_purpose=%d, router_purpose=%d", 152 dir_purpose, router_purpose); 153 tor_assert_nonfatal_unreached(); 154 return 1; /* Assume it needs anonymity; better safe than sorry. */ 155 } 156 } 157 158 /** Return a newly allocated string describing <b>auth</b>. Only describes 159 * authority features. */ 160 char * 161 authdir_type_to_string(dirinfo_type_t auth) 162 { 163 char *result; 164 smartlist_t *lst = smartlist_new(); 165 if (auth & V3_DIRINFO) 166 smartlist_add(lst, (void*)"V3"); 167 if (auth & BRIDGE_DIRINFO) 168 smartlist_add(lst, (void*)"Bridge"); 169 if (smartlist_len(lst)) { 170 result = smartlist_join_strings(lst, ", ", 0, NULL); 171 } else { 172 result = tor_strdup("[Not an authority]"); 173 } 174 smartlist_free(lst); 175 return result; 176 } 177 178 /** Return true iff anything we say on <b>conn</b> is being encrypted before 179 * we send it to the client/server. */ 180 int 181 connection_dir_is_encrypted(const dir_connection_t *conn) 182 { 183 /* Right now it's sufficient to see if conn is or has been linked, since 184 * the only thing it could be linked to is an edge connection on a 185 * circuit, and the only way it could have been unlinked is at the edge 186 * connection getting closed. 187 */ 188 return TO_CONN(conn)->linked; 189 } 190 191 /** Return true iff the given directory connection <b>dir_conn</b> is 192 * anonymous, that is, it is on a circuit via a public relay and not directly 193 * from a client or bridge. 194 * 195 * For client circuits via relays: true for 2-hop+ paths. 196 * For client circuits via bridges: true for 3-hop+ paths. 197 * 198 * This first test if the connection is encrypted since it is a strong 199 * requirement for anonymity. */ 200 bool 201 connection_dir_is_anonymous(const dir_connection_t *dir_conn) 202 { 203 const connection_t *conn, *linked_conn; 204 const edge_connection_t *edge_conn; 205 const circuit_t *circ; 206 207 tor_assert(dir_conn); 208 209 if (!connection_dir_is_encrypted(dir_conn)) { 210 return false; 211 } 212 213 /* 214 * Buckle up, we'll do a deep dive into the connection in order to get the 215 * final connection channel of that connection in order to figure out if 216 * this is a client or relay link. 217 * 218 * We go: dir_conn -> linked_conn -> edge_conn -> on_circuit -> p_chan. 219 */ 220 221 conn = TO_CONN(dir_conn); 222 linked_conn = conn->linked_conn; 223 224 /* The dir connection should be connected to an edge connection. It can not 225 * be closed or marked for close. */ 226 if (linked_conn == NULL || linked_conn->magic != EDGE_CONNECTION_MAGIC || 227 conn->linked_conn_is_closed || conn->linked_conn->marked_for_close) { 228 log_debug(LD_DIR, "Directory connection is not anonymous: " 229 "not linked to edge"); 230 return false; 231 } 232 233 edge_conn = CONST_TO_EDGE_CONN(linked_conn); 234 circ = edge_conn->on_circuit; 235 236 /* Can't be a circuit we initiated and without a circuit, no channel. */ 237 if (circ == NULL || CIRCUIT_IS_ORIGIN(circ)) { 238 log_debug(LD_DIR, "Directory connection is not anonymous: " 239 "not on OR circuit"); 240 return false; 241 } 242 243 /* It is possible that the circuit was closed because one of the channel was 244 * closed or a DESTROY cell was received. Either way, this connection can 245 * not continue so return that it is not anonymous since we can not know for 246 * sure if it is. */ 247 if (circ->marked_for_close) { 248 log_debug(LD_DIR, "Directory connection is not anonymous: " 249 "circuit marked for close"); 250 return false; 251 } 252 253 /* Get the previous channel to learn if it is a client or relay link. We 254 * BUG() because if the circuit is not mark for close, we ought to have a 255 * p_chan else we have a code flow issue. */ 256 if (BUG(CONST_TO_OR_CIRCUIT(circ)->p_chan == NULL)) { 257 log_debug(LD_DIR, "Directory connection is not anonymous: " 258 "no p_chan on circuit"); 259 return false; 260 } 261 262 /* Will be true if the channel is an unauthenticated peer which is only true 263 * for clients and bridges. */ 264 return !channel_is_client(CONST_TO_OR_CIRCUIT(circ)->p_chan); 265 } 266 267 /** Did <b>conn</b> ever send us a version 0 sendme cell and we allowed 268 * it? Used to decide whether to count consensus fetches from it in our 269 * geoip stats. 270 * 271 * Note that this function might have false negatives in some cases, i.e. 272 * it could tell us that the conn never sent a v0 sendme when actually it 273 * did but its linked edge connection or OR connection got broken before 274 * we called this function. For our geoip stats these false negatives 275 * would mean overcounting users by including some of the v0-using 276 * clients. 277 * 278 * We think these false positives should be unlikely or maybe even 279 * impossible when called from connection_dirserv_flushed_some(), but 280 * be careful calling it from elsewhere. 281 * */ 282 bool 283 connection_dir_used_obsolete_sendme(const dir_connection_t *conn) 284 { 285 const edge_connection_t *edge_conn = NULL; 286 const circuit_t *circ = NULL; 287 bool used_obsolete_sendme = 0; 288 const connection_t *linked_conn = TO_CONN(conn)->linked_conn; 289 if (linked_conn) 290 edge_conn = CONST_TO_EDGE_CONN(linked_conn); 291 if (edge_conn) 292 circ = edge_conn->on_circuit; 293 if (circ && CIRCUIT_IS_ORCIRC(circ)) 294 used_obsolete_sendme = CONST_TO_OR_CIRCUIT(circ)->used_obsolete_sendme; 295 296 return used_obsolete_sendme; 297 } 298 299 /** Parse an HTTP request line at the start of a headers string. On failure, 300 * return -1. On success, set *<b>command_out</b> to a copy of the HTTP 301 * command ("get", "post", etc), set *<b>url_out</b> to a copy of the URL, and 302 * return 0. */ 303 int 304 parse_http_command(const char *headers, char **command_out, char **url_out) 305 { 306 const char *command, *end_of_command; 307 char *s, *start, *tmp; 308 309 s = (char *)eat_whitespace_no_nl(headers); 310 if (!*s) return -1; 311 command = s; 312 s = (char *)find_whitespace(s); /* get past GET/POST */ 313 if (!*s) return -1; 314 end_of_command = s; 315 s = (char *)eat_whitespace_no_nl(s); 316 if (!*s) return -1; 317 start = s; /* this is the URL, assuming it's valid */ 318 s = (char *)find_whitespace(start); 319 if (!*s) return -1; 320 321 /* tolerate the http[s] proxy style of putting the hostname in the url */ 322 if (s-start >= 4 && !strcmpstart(start,"http")) { 323 tmp = start + 4; 324 if (*tmp == 's') 325 tmp++; 326 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) { 327 tmp = strchr(tmp+3, '/'); 328 if (tmp && tmp < s) { 329 log_debug(LD_DIR,"Skipping over 'http[s]://hostname/' string"); 330 start = tmp; 331 } 332 } 333 } 334 335 /* Check if the header is well formed (next sequence 336 * should be HTTP/1.X\r\n). Assumes we're supporting 1.0? */ 337 { 338 unsigned minor_ver; 339 char ch; 340 char *e = (char *)eat_whitespace_no_nl(s); 341 if (2 != tor_sscanf(e, "HTTP/1.%u%c", &minor_ver, &ch)) { 342 return -1; 343 } 344 if (ch != '\r') 345 return -1; 346 } 347 348 *url_out = tor_memdup_nulterm(start, s-start); 349 *command_out = tor_memdup_nulterm(command, end_of_command - command); 350 return 0; 351 } 352 353 /** Return a copy of the first HTTP header in <b>headers</b> whose key is 354 * <b>which</b>. The key should be given with a terminating colon and space; 355 * this function copies everything after, up to but not including the 356 * following \\r\\n. */ 357 char * 358 http_get_header(const char *headers, const char *which) 359 { 360 const char *cp = headers; 361 while (cp) { 362 if (!strcasecmpstart(cp, which)) { 363 const char *eos; 364 cp += strlen(which); 365 if ((eos = strchr(cp,'\r'))) 366 return tor_strndup(cp, eos-cp); 367 else 368 return tor_strdup(cp); 369 } 370 cp = strchr(cp, '\n'); 371 if (cp) 372 ++cp; 373 } 374 return NULL; 375 } 376 /** Parse an HTTP response string <b>headers</b> of the form 377 * \verbatim 378 * "HTTP/1.\%d \%d\%s\r\n...". 379 * \endverbatim 380 * 381 * If it's well-formed, assign the status code to *<b>code</b> and 382 * return 0. Otherwise, return -1. 383 * 384 * On success: If <b>date</b> is provided, set *date to the Date 385 * header in the http headers, or 0 if no such header is found. If 386 * <b>compression</b> is provided, set *<b>compression</b> to the 387 * compression method given in the Content-Encoding header, or 0 if no 388 * such header is found, or -1 if the value of the header is not 389 * recognized. If <b>reason</b> is provided, strdup the reason string 390 * into it. 391 */ 392 int 393 parse_http_response(const char *headers, int *code, time_t *date, 394 compress_method_t *compression, char **reason) 395 { 396 unsigned n1, n2; 397 char datestr[RFC1123_TIME_LEN+1]; 398 smartlist_t *parsed_headers; 399 tor_assert(headers); 400 tor_assert(code); 401 402 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */ 403 404 if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 || 405 (n1 != 0 && n1 != 1) || 406 (n2 < 100 || n2 >= 600)) { 407 log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers)); 408 return -1; 409 } 410 *code = n2; 411 412 parsed_headers = smartlist_new(); 413 smartlist_split_string(parsed_headers, headers, "\n", 414 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); 415 if (reason) { 416 smartlist_t *status_line_elements = smartlist_new(); 417 tor_assert(smartlist_len(parsed_headers)); 418 smartlist_split_string(status_line_elements, 419 smartlist_get(parsed_headers, 0), 420 " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3); 421 tor_assert(smartlist_len(status_line_elements) <= 3); 422 if (smartlist_len(status_line_elements) == 3) { 423 *reason = smartlist_get(status_line_elements, 2); 424 smartlist_set(status_line_elements, 2, NULL); /* Prevent free */ 425 } 426 SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp)); 427 smartlist_free(status_line_elements); 428 } 429 if (date) { 430 *date = 0; 431 SMARTLIST_FOREACH(parsed_headers, const char *, s, 432 if (!strcmpstart(s, "Date: ")) { 433 strlcpy(datestr, s+6, sizeof(datestr)); 434 /* This will do nothing on failure, so we don't need to check 435 the result. We shouldn't warn, since there are many other valid 436 date formats besides the one we use. */ 437 parse_rfc1123_time(datestr, date); 438 break; 439 }); 440 } 441 if (compression) { 442 const char *enc = NULL; 443 SMARTLIST_FOREACH(parsed_headers, const char *, s, 444 if (!strcmpstart(s, "Content-Encoding: ")) { 445 enc = s+18; break; 446 }); 447 448 if (enc == NULL) 449 *compression = NO_METHOD; 450 else { 451 *compression = compression_method_get_by_name(enc); 452 453 if (*compression == UNKNOWN_METHOD) 454 log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.", 455 escaped(enc)); 456 } 457 } 458 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s)); 459 smartlist_free(parsed_headers); 460 461 return 0; 462 } 463 464 /** If any directory object is arriving, and it's over 10MB large, we're 465 * getting DoS'd. (As of 0.1.2.x, raw directories are about 1MB, and we never 466 * ask for more than 96 router descriptors at a time.) 467 */ 468 #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20)) 469 470 #define MAX_VOTE_DL_SIZE (MAX_DIRECTORY_OBJECT_SIZE * 5) 471 472 /** Read handler for directory connections. (That's connections <em>to</em> 473 * directory servers and connections <em>at</em> directory servers.) 474 */ 475 int 476 connection_dir_process_inbuf(dir_connection_t *conn) 477 { 478 size_t max_size; 479 tor_assert(conn); 480 tor_assert(conn->base_.type == CONN_TYPE_DIR); 481 482 /* Directory clients write, then read data until they receive EOF; 483 * directory servers read data until they get an HTTP command, then 484 * write their response (when it's finished flushing, they mark for 485 * close). 486 */ 487 488 /* If we're on the dirserver side, look for a command. */ 489 if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { 490 if (directory_handle_command(conn) < 0) { 491 connection_mark_for_close(TO_CONN(conn)); 492 return -1; 493 } 494 return 0; 495 } 496 497 max_size = 498 (TO_CONN(conn)->purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) ? 499 MAX_VOTE_DL_SIZE : MAX_DIRECTORY_OBJECT_SIZE; 500 501 if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) { 502 log_warn(LD_HTTP, 503 "Too much data received from %s: " 504 "denial of service attempt, or you need to upgrade?", 505 connection_describe(TO_CONN(conn))); 506 connection_mark_for_close(TO_CONN(conn)); 507 return -1; 508 } 509 510 if (!conn->base_.inbuf_reached_eof) 511 log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf."); 512 return 0; 513 } 514 515 /** Called when we're about to finally unlink and free a directory connection: 516 * perform necessary accounting and cleanup */ 517 void 518 connection_dir_about_to_close(dir_connection_t *dir_conn) 519 { 520 connection_t *conn = TO_CONN(dir_conn); 521 522 if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) { 523 /* It's a directory connection and connecting or fetching 524 * failed: forget about this router, and maybe try again. */ 525 connection_dir_client_request_failed(dir_conn); 526 } 527 528 /* If we are an HSDir, mark the corresponding descriptor as downloaded. This 529 * is needed for the OOM cache cleanup. 530 * 531 * This is done when the direction connection is closed in order to raise the 532 * attack cost of filling the cache with bogus descriptors. That attacker 533 * would need to increase that downloaded counter for the attack to be 534 * successful which is expensive. */ 535 if (conn->purpose == DIR_PURPOSE_SERVER && dir_conn->hs_ident) { 536 hs_cache_mark_dowloaded_as_dir(dir_conn->hs_ident); 537 } 538 539 connection_dir_client_refetch_hsdesc_if_needed(dir_conn); 540 } 541 542 /** Write handler for directory connections; called when all data has 543 * been flushed. Close the connection or wait for a response as 544 * appropriate. 545 */ 546 int 547 connection_dir_finished_flushing(dir_connection_t *conn) 548 { 549 tor_assert(conn); 550 tor_assert(conn->base_.type == CONN_TYPE_DIR); 551 552 if (conn->base_.marked_for_close) 553 return 0; 554 555 /* Note that we have finished writing the directory response. For direct 556 * connections this means we're done; for tunneled connections it's only 557 * an intermediate step. */ 558 if (conn->dirreq_id) 559 geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED, 560 DIRREQ_FLUSHING_DIR_CONN_FINISHED); 561 else 562 geoip_change_dirreq_state(TO_CONN(conn)->global_identifier, 563 DIRREQ_DIRECT, 564 DIRREQ_FLUSHING_DIR_CONN_FINISHED); 565 switch (conn->base_.state) { 566 case DIR_CONN_STATE_CONNECTING: 567 case DIR_CONN_STATE_CLIENT_SENDING: 568 log_debug(LD_DIR,"client finished sending command."); 569 conn->base_.state = DIR_CONN_STATE_CLIENT_READING; 570 return 0; 571 case DIR_CONN_STATE_SERVER_WRITING: 572 if (conn->spool) { 573 log_warn(LD_BUG, "Emptied a dirserv buffer, but it's still spooling!"); 574 connection_mark_for_close(TO_CONN(conn)); 575 } else { 576 log_debug(LD_DIRSERV, "Finished writing server response. Closing."); 577 connection_mark_for_close(TO_CONN(conn)); 578 } 579 return 0; 580 default: 581 log_warn(LD_BUG,"called in unexpected state %d.", 582 conn->base_.state); 583 tor_fragile_assert(); 584 return -1; 585 } 586 return 0; 587 } 588 589 /** Connected handler for directory connections: begin sending data to the 590 * server, and return 0. 591 * Only used when connections don't immediately connect. */ 592 int 593 connection_dir_finished_connecting(dir_connection_t *conn) 594 { 595 tor_assert(conn); 596 tor_assert(conn->base_.type == CONN_TYPE_DIR); 597 tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING); 598 599 log_debug(LD_HTTP,"Dir connection to %s established.", 600 connection_describe_peer(TO_CONN(conn))); 601 602 /* start flushing conn */ 603 conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; 604 return 0; 605 } 606 607 /** Helper. Compare two fp_pair_t objects, and return negative, 0, or 608 * positive as appropriate. */ 609 static int 610 compare_pairs_(const void **a, const void **b) 611 { 612 const fp_pair_t *fp1 = *a, *fp2 = *b; 613 int r; 614 if ((r = fast_memcmp(fp1->first, fp2->first, DIGEST_LEN))) 615 return r; 616 else 617 return fast_memcmp(fp1->second, fp2->second, DIGEST_LEN); 618 } 619 620 /** Divide a string <b>res</b> of the form FP1-FP2+FP3-FP4...[.z], where each 621 * FP is a hex-encoded fingerprint, into a sequence of distinct sorted 622 * fp_pair_t. Skip malformed pairs. On success, return 0 and add those 623 * fp_pair_t into <b>pairs_out</b>. On failure, return -1. */ 624 int 625 dir_split_resource_into_fingerprint_pairs(const char *res, 626 smartlist_t *pairs_out) 627 { 628 smartlist_t *pairs_tmp = smartlist_new(); 629 smartlist_t *pairs_result = smartlist_new(); 630 631 smartlist_split_string(pairs_tmp, res, "+", 0, 0); 632 if (smartlist_len(pairs_tmp)) { 633 char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1); 634 size_t last_len = strlen(last); 635 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { 636 last[last_len-2] = '\0'; 637 } 638 } 639 SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) { 640 if (strlen(cp) != HEX_DIGEST_LEN*2+1) { 641 log_info(LD_DIR, 642 "Skipping digest pair %s with non-standard length.", escaped(cp)); 643 } else if (cp[HEX_DIGEST_LEN] != '-') { 644 log_info(LD_DIR, 645 "Skipping digest pair %s with missing dash.", escaped(cp)); 646 } else { 647 fp_pair_t pair; 648 if (base16_decode(pair.first, DIGEST_LEN, 649 cp, HEX_DIGEST_LEN) != DIGEST_LEN || 650 base16_decode(pair.second,DIGEST_LEN, 651 cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN) != DIGEST_LEN) { 652 log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp)); 653 } else { 654 smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair))); 655 } 656 } 657 tor_free(cp); 658 } SMARTLIST_FOREACH_END(cp); 659 smartlist_free(pairs_tmp); 660 661 /* Uniq-and-sort */ 662 smartlist_sort(pairs_result, compare_pairs_); 663 smartlist_uniq(pairs_result, compare_pairs_, tor_free_); 664 665 smartlist_add_all(pairs_out, pairs_result); 666 smartlist_free(pairs_result); 667 return 0; 668 } 669 670 /** Given a directory <b>resource</b> request, containing zero 671 * or more strings separated by plus signs, followed optionally by ".z", store 672 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is 673 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. 674 * 675 * If (flags & DSR_HEX), then delete all elements that aren't hex digests, and 676 * decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as 677 * a separator, delete all the elements that aren't base64-encoded digests, 678 * and decode the rest. If (flags & DSR_DIGEST256), these digests should be 679 * 256 bits long; else they should be 160. 680 * 681 * If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates. 682 */ 683 int 684 dir_split_resource_into_fingerprints(const char *resource, 685 smartlist_t *fp_out, int *compressed_out, 686 int flags) 687 { 688 const int decode_hex = flags & DSR_HEX; 689 const int decode_base64 = flags & DSR_BASE64; 690 const int digests_are_256 = flags & DSR_DIGEST256; 691 const int sort_uniq = flags & DSR_SORT_UNIQ; 692 693 const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN; 694 const int hex_digest_len = digests_are_256 ? 695 HEX_DIGEST256_LEN : HEX_DIGEST_LEN; 696 const int base64_digest_len = digests_are_256 ? 697 BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN; 698 smartlist_t *fp_tmp = smartlist_new(); 699 700 tor_assert(!(decode_hex && decode_base64)); 701 tor_assert(fp_out); 702 703 smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0); 704 if (compressed_out) 705 *compressed_out = 0; 706 if (smartlist_len(fp_tmp)) { 707 char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1); 708 size_t last_len = strlen(last); 709 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { 710 last[last_len-2] = '\0'; 711 if (compressed_out) 712 *compressed_out = 1; 713 } 714 } 715 if (decode_hex || decode_base64) { 716 const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len; 717 int i; 718 char *cp, *d = NULL; 719 for (i = 0; i < smartlist_len(fp_tmp); ++i) { 720 cp = smartlist_get(fp_tmp, i); 721 if (strlen(cp) != encoded_len) { 722 log_info(LD_DIR, 723 "Skipping digest %s with non-standard length.", escaped(cp)); 724 smartlist_del_keeporder(fp_tmp, i--); 725 goto again; 726 } 727 d = tor_malloc_zero(digest_len); 728 if (decode_hex ? 729 (base16_decode(d, digest_len, cp, hex_digest_len) != digest_len) : 730 (base64_decode(d, digest_len, cp, base64_digest_len) 731 != digest_len)) { 732 log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp)); 733 smartlist_del_keeporder(fp_tmp, i--); 734 goto again; 735 } 736 smartlist_set(fp_tmp, i, d); 737 d = NULL; 738 again: 739 tor_free(cp); 740 tor_free(d); 741 } 742 } 743 if (sort_uniq) { 744 if (decode_hex || decode_base64) { 745 if (digests_are_256) { 746 smartlist_sort_digests256(fp_tmp); 747 smartlist_uniq_digests256(fp_tmp); 748 } else { 749 smartlist_sort_digests(fp_tmp); 750 smartlist_uniq_digests(fp_tmp); 751 } 752 } else { 753 smartlist_sort_strings(fp_tmp); 754 smartlist_uniq_strings(fp_tmp); 755 } 756 } 757 smartlist_add_all(fp_out, fp_tmp); 758 smartlist_free(fp_tmp); 759 return 0; 760 }