diff options
Diffstat (limited to 'src/or')
85 files changed, 5112 insertions, 4922 deletions
diff --git a/src/or/buffers.h b/src/or/buffers.h index a5886adc7a..f31d2910f7 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -9,8 +9,8 @@ * \brief Header file for buffers.c. **/ -#ifndef _TOR_BUFFERS_H -#define _TOR_BUFFERS_H +#ifndef TOR_BUFFERS_H +#define TOR_BUFFERS_H buf_t *buf_new(void); buf_t *buf_new_with_capacity(size_t size); diff --git a/src/or/channel.c b/src/or/channel.c index 2642431267..cbf7f99be1 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -11,15 +11,17 @@ * should touch. */ -#define _TOR_CHANNEL_INTERNAL +#define TOR_CHANNEL_INTERNAL_ #include "or.h" #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "circuitstats.h" #include "connection_or.h" /* For var_cell_free() */ #include "circuitmux.h" +#include "entrynodes.h" #include "geoip.h" #include "nodelist.h" #include "relay.h" @@ -31,6 +33,7 @@ typedef struct cell_queue_entry_s cell_queue_entry_t; struct cell_queue_entry_s { + SIMPLEQ_ENTRY(cell_queue_entry_s) next; enum { CELL_QUEUE_FIXED, CELL_QUEUE_VAR, @@ -80,7 +83,37 @@ static uint64_t n_channels_allocated = 0; * If more than one channel exists, follow the next_with_same_id pointer * as a linked list. */ -static digestmap_t *channel_identity_map = NULL; +HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map = + HT_INITIALIZER(); + +typedef struct channel_idmap_entry_s { + HT_ENTRY(channel_idmap_entry_s) node; + uint8_t digest[DIGEST_LEN]; + LIST_HEAD(channel_list_s, channel_s) channel_list; +} channel_idmap_entry_t; + +static INLINE unsigned +channel_idmap_hash(const channel_idmap_entry_t *ent) +{ + const unsigned *a = (const unsigned *)ent->digest; +#if SIZEOF_INT == 4 + return a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4]; +#elif SIZEOF_INT == 8 + return a[0] ^ a[1]; +#endif +} + +static INLINE int +channel_idmap_eq(const channel_idmap_entry_t *a, + const channel_idmap_entry_t *b) +{ + return tor_memeq(a->digest, b->digest, DIGEST_LEN); +} + +HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, + channel_idmap_eq); +HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, + channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_); static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q); static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off); @@ -504,7 +537,7 @@ channel_listener_unregister(channel_listener_t *chan_l) static void channel_add_to_digest_map(channel_t *chan) { - channel_t *tmp; + channel_idmap_entry_t *ent, search; tor_assert(chan); @@ -516,23 +549,15 @@ channel_add_to_digest_map(channel_t *chan) /* Assert that there is a digest */ tor_assert(!tor_digest_is_zero(chan->identity_digest)); - /* Allocate the identity map if we have to */ - if (!channel_identity_map) channel_identity_map = digestmap_new(); - - /* Insert it */ - tmp = digestmap_set(channel_identity_map, - chan->identity_digest, - chan); - if (tmp) { - /* There already was one, this goes at the head of the list */ - chan->next_with_same_id = tmp; - chan->prev_with_same_id = NULL; - tmp->prev_with_same_id = chan; - } else { - /* First with this digest */ - chan->next_with_same_id = NULL; - chan->prev_with_same_id = NULL; + memcpy(search.digest, chan->identity_digest, DIGEST_LEN); + ent = HT_FIND(channel_idmap, &channel_identity_map, &search); + if (! ent) { + ent = tor_malloc(sizeof(channel_idmap_entry_t)); + memcpy(ent->digest, chan->identity_digest, DIGEST_LEN); + LIST_INIT(&ent->channel_list); + HT_INSERT(channel_idmap, &channel_identity_map, ent); } + LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id); log_debug(LD_CHANNEL, "Added channel %p (global ID " U64_FORMAT ") " @@ -552,13 +577,14 @@ channel_add_to_digest_map(channel_t *chan) static void channel_remove_from_digest_map(channel_t *chan) { - channel_t *tmp; + channel_idmap_entry_t *ent, search; tor_assert(chan); /* Assert that there is a digest */ tor_assert(!tor_digest_is_zero(chan->identity_digest)); +#if 0 /* Make sure we have a map */ if (!channel_identity_map) { /* @@ -583,66 +609,29 @@ channel_remove_from_digest_map(channel_t *chan) return; } +#endif - /* Look for it in the map */ - tmp = digestmap_get(channel_identity_map, chan->identity_digest); - if (tmp) { - /* Okay, it's here */ - /* Look for this channel */ - while (tmp && tmp != chan) { - tmp = tmp->next_with_same_id; - } + /* Pull it out of its list, wherever that list is */ + LIST_REMOVE(chan, next_with_same_id); - if (tmp == chan) { - /* Found it, good */ - if (chan->next_with_same_id) { - chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; - } - /* else we're the tail of the list */ - if (chan->prev_with_same_id) { - /* We're not the head of the list, so we can *just* unlink */ - chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; - } else { - /* We're the head, so we have to point the digest map entry at our - * next if we have one, or remove it if we're also the tail */ - if (chan->next_with_same_id) { - digestmap_set(channel_identity_map, - chan->identity_digest, - chan->next_with_same_id); - } else { - digestmap_remove(channel_identity_map, - chan->identity_digest); - } - } + memcpy(search.digest, chan->identity_digest, DIGEST_LEN); + ent = HT_FIND(channel_idmap, &channel_identity_map, &search); - /* NULL out its next/prev pointers, and we're finished */ - chan->next_with_same_id = NULL; - chan->prev_with_same_id = NULL; + /* Look for it in the map */ + if (ent) { + /* Okay, it's here */ - log_debug(LD_CHANNEL, - "Removed channel %p (global ID " U64_FORMAT ") from " - "identity map in state %s (%d) with digest %s", - chan, U64_PRINTF_ARG(chan->global_identifier), - channel_state_to_string(chan->state), chan->state, - hex_str(chan->identity_digest, DIGEST_LEN)); - } else { - /* This is not good */ - log_warn(LD_BUG, - "Trying to remove channel %p (global ID " U64_FORMAT ") " - "with digest %s from identity map, but couldn't find it in " - "the list for that digest", - chan, U64_PRINTF_ARG(chan->global_identifier), - hex_str(chan->identity_digest, DIGEST_LEN)); - /* Unlink it and hope for the best */ - if (chan->next_with_same_id) { - chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; - } - if (chan->prev_with_same_id) { - chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; - } - chan->next_with_same_id = NULL; - chan->prev_with_same_id = NULL; + if (LIST_EMPTY(&ent->channel_list)) { + HT_REMOVE(channel_idmap, &channel_identity_map, ent); + tor_free(ent); } + + log_debug(LD_CHANNEL, + "Removed channel %p (global ID " U64_FORMAT ") from " + "identity map in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state, + hex_str(chan->identity_digest, DIGEST_LEN)); } else { /* Shouldn't happen */ log_warn(LD_BUG, @@ -651,15 +640,6 @@ channel_remove_from_digest_map(channel_t *chan) "that digest", chan, U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN)); - /* Clear out its next/prev pointers */ - if (chan->next_with_same_id) { - chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; - } - if (chan->prev_with_same_id) { - chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; - } - chan->next_with_same_id = NULL; - chan->prev_with_same_id = NULL; } } @@ -697,20 +677,21 @@ channel_find_by_global_id(uint64_t global_identifier) * * This function looks up a channel by the digest of its remote endpoint in * the channel digest map. It's possible that more than one channel to a - * given endpoint exists. Use channel_next_with_digest() and - * channel_prev_with_digest() to walk the list. + * given endpoint exists. Use channel_next_with_digest() to walk the list. */ channel_t * channel_find_by_remote_digest(const char *identity_digest) { channel_t *rv = NULL; + channel_idmap_entry_t *ent, search; tor_assert(identity_digest); - /* Search for it in the identity map */ - if (channel_identity_map) { - rv = digestmap_get(channel_identity_map, identity_digest); + memcpy(search.digest, identity_digest, DIGEST_LEN); + ent = HT_FIND(channel_idmap, &channel_identity_map, &search); + if (ent) { + rv = LIST_FIRST(&ent->channel_list); } return rv; @@ -728,22 +709,7 @@ channel_next_with_digest(channel_t *chan) { tor_assert(chan); - return chan->next_with_same_id; -} - -/** - * Get previous channel with digest - * - * This function takes a channel and finds the previos channel in the list - * with the same digest. - */ - -channel_t * -channel_prev_with_digest(channel_t *chan) -{ - tor_assert(chan); - - return chan->prev_with_same_id; + return LIST_NEXT(chan, next_with_same_id); } /** @@ -768,6 +734,13 @@ channel_init(channel_t *chan) /* Init next_circ_id */ chan->next_circ_id = crypto_rand_int(1 << 15); + /* Initialize queues. */ + SIMPLEQ_INIT(&chan->incoming_queue); + SIMPLEQ_INIT(&chan->outgoing_queue); + + /* Initialize list entries. */ + memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id)); + /* Timestamp it */ channel_timestamp_created(chan); } @@ -848,6 +821,11 @@ channel_listener_free(channel_listener_t *chan_l) { if (!chan_l) return; + log_debug(LD_CHANNEL, + "Freeing channel_listener_t " U64_FORMAT " at %p", + U64_PRINTF_ARG(chan_l->global_identifier), + chan_l); + /* It must be closed or errored */ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR); @@ -874,6 +852,7 @@ channel_listener_free(channel_listener_t *chan_l) static void channel_force_free(channel_t *chan) { + cell_queue_entry_t *cell, *cell_tmp; tor_assert(chan); log_debug(LD_CHANNEL, @@ -900,26 +879,16 @@ channel_force_free(channel_t *chan) } /* We might still have a cell queue; kill it */ - if (chan->incoming_queue) { - SMARTLIST_FOREACH_BEGIN(chan->incoming_queue, - cell_queue_entry_t *, q) { - cell_queue_entry_free(q, 0); - } SMARTLIST_FOREACH_END(q); - - smartlist_free(chan->incoming_queue); - chan->incoming_queue = NULL; + SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) { + cell_queue_entry_free(cell, 0); } + SIMPLEQ_INIT(&chan->incoming_queue); /* Outgoing cell queue is similar, but we can have to free packed cells */ - if (chan->outgoing_queue) { - SMARTLIST_FOREACH_BEGIN(chan->outgoing_queue, - cell_queue_entry_t *, q) { - cell_queue_entry_free(q, 0); - } SMARTLIST_FOREACH_END(q); - - smartlist_free(chan->outgoing_queue); - chan->outgoing_queue = NULL; + SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) { + cell_queue_entry_free(cell, 0); } + SIMPLEQ_INIT(&chan->outgoing_queue); tor_free(chan); } @@ -935,6 +904,11 @@ channel_listener_force_free(channel_listener_t *chan_l) { tor_assert(chan_l); + log_debug(LD_CHANNEL, + "Force-freeing channel_listener_t " U64_FORMAT " at %p", + U64_PRINTF_ARG(chan_l->global_identifier), + chan_l); + /* Call a free method if there is one */ if (chan_l->free) chan_l->free(chan_l); @@ -1077,8 +1051,7 @@ channel_set_cell_handlers(channel_t *chan, chan->var_cell_handler = var_cell_handler; /* Re-run the queue if we have one and there's any reason to */ - if (chan->incoming_queue && - (smartlist_len(chan->incoming_queue) > 0) && + if (! SIMPLEQ_EMPTY(&chan->incoming_queue) && try_again && (chan->cell_handler || chan->var_cell_handler)) channel_process_cells(chan); @@ -1700,9 +1673,8 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) } /* Can we send it right out? If so, try */ - if (!(chan->outgoing_queue && - (smartlist_len(chan->outgoing_queue) > 0)) && - chan->state == CHANNEL_STATE_OPEN) { + if (SIMPLEQ_EMPTY(&chan->outgoing_queue) && + chan->state == CHANNEL_STATE_OPEN) { /* Pick the right write function for this cell type and save the result */ switch (q->type) { case CELL_QUEUE_FIXED: @@ -1738,14 +1710,12 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) if (!sent) { /* Not sent, queue it */ - if (!(chan->outgoing_queue)) - chan->outgoing_queue = smartlist_new(); /* * We have to copy the queue entry passed in, since the caller probably * used the stack. */ tmp = cell_queue_entry_dup(q); - smartlist_add(chan->outgoing_queue, tmp); + SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next); /* Try to process the queue? */ if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan); } @@ -1931,19 +1901,15 @@ channel_change_state(channel_t *chan, channel_state_t to_state) channel_do_open_actions(chan); /* Check for queued cells to process */ - if (chan->incoming_queue && - smartlist_len(chan->incoming_queue) > 0) + if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) channel_process_cells(chan); - if (chan->outgoing_queue && - smartlist_len(chan->outgoing_queue) > 0) + if (! SIMPLEQ_EMPTY(&chan->outgoing_queue)) channel_flush_cells(chan); } else if (to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR) { /* Assert that all queues are empty */ - tor_assert(!(chan->incoming_queue) || - smartlist_len(chan->incoming_queue) == 0); - tor_assert(!(chan->outgoing_queue) || - smartlist_len(chan->outgoing_queue) == 0); + tor_assert(SIMPLEQ_EMPTY(&chan->incoming_queue)); + tor_assert(SIMPLEQ_EMPTY(&chan->outgoing_queue)); } } @@ -2117,16 +2083,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ if (chan->state == CHANNEL_STATE_OPEN) { while ((unlimited || num_cells > flushed) && - (chan->outgoing_queue && - (smartlist_len(chan->outgoing_queue) > 0))) { - /* - * Ewww, smartlist_del_keeporder() is O(n) in list length; maybe a - * a linked list would make more sense for the queue. - */ - - /* Get the head of the queue */ - q = smartlist_get(chan->outgoing_queue, 0); - if (q) { + NULL != (q = SIMPLEQ_FIRST(&chan->outgoing_queue))) { + + if (1) { /* * Okay, we have a good queue entry, try to give it to the lower * layer. @@ -2211,26 +2170,17 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, cell_queue_entry_free(q, 0); q = NULL; } - } else { - /* This shouldn't happen; log and throw it away */ - log_info(LD_CHANNEL, - "Saw a NULL entry in the outgoing cell queue on channel %p " - "(global ID " U64_FORMAT "); this is definitely a bug.", - chan, U64_PRINTF_ARG(chan->global_identifier)); - /* q is already NULL, so we know to delete that queue entry */ - } - /* if q got NULLed out, we used it and should remove the queue entry */ - if (!q) smartlist_del_keeporder(chan->outgoing_queue, 0); - /* No cell removed from list, so we can't go on any further */ - else break; + /* if q got NULLed out, we used it and should remove the queue entry */ + if (!q) SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next); + /* No cell removed from list, so we can't go on any further */ + else break; + } } } /* Did we drain the queue? */ - if (!(chan->outgoing_queue) || - smartlist_len(chan->outgoing_queue) == 0) { - /* Timestamp it */ + if (SIMPLEQ_EMPTY(&chan->outgoing_queue)) { channel_timestamp_drained(chan); } @@ -2264,8 +2214,8 @@ channel_more_to_flush(channel_t *chan) tor_assert(chan); /* Check if we have any queued */ - if (chan->incoming_queue && - smartlist_len(chan->incoming_queue) > 0) return 1; + if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) + return 1; /* Check if any circuits would like to queue some */ if (circuitmux_num_cells(chan->cmux) > 0) return 1; @@ -2458,8 +2408,7 @@ channel_listener_queue_incoming(channel_listener_t *listener, void channel_process_cells(channel_t *chan) { - smartlist_t *queue; - int putback = 0; + cell_queue_entry_t *q; tor_assert(chan); tor_assert(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_MAINT || @@ -2473,24 +2422,21 @@ channel_process_cells(channel_t *chan) if (!(chan->cell_handler || chan->var_cell_handler)) return; /* Nothing we can do if we have no cells */ - if (!(chan->incoming_queue)) return; + if (SIMPLEQ_EMPTY(&chan->incoming_queue)) return; - queue = chan->incoming_queue; - chan->incoming_queue = NULL; /* * Process cells until we're done or find one we have no current handler * for. */ - SMARTLIST_FOREACH_BEGIN(queue, cell_queue_entry_t *, q) { + while (NULL != (q = SIMPLEQ_FIRST(&chan->incoming_queue))) { tor_assert(q); tor_assert(q->type == CELL_QUEUE_FIXED || q->type == CELL_QUEUE_VAR); - if (putback) { - smartlist_add(chan->incoming_queue, q); - } else if (q->type == CELL_QUEUE_FIXED && + if (q->type == CELL_QUEUE_FIXED && chan->cell_handler) { /* Handle a fixed-length cell */ + SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); tor_assert(q->u.fixed.cell); log_debug(LD_CHANNEL, "Processing incoming cell_t %p for channel %p (global ID " @@ -2502,6 +2448,7 @@ channel_process_cells(channel_t *chan) } else if (q->type == CELL_QUEUE_VAR && chan->var_cell_handler) { /* Handle a variable-length cell */ + SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); tor_assert(q->u.var.var_cell); log_debug(LD_CHANNEL, "Processing incoming var_cell_t %p for channel %p (global ID " @@ -2512,15 +2459,9 @@ channel_process_cells(channel_t *chan) tor_free(q); } else { /* Can't handle this one */ - if (!chan->incoming_queue) - chan->incoming_queue = smartlist_new(); - smartlist_add(chan->incoming_queue, q); - putback = 1; + break; } - } SMARTLIST_FOREACH_END(q); - - /* If the list is empty, free it */ - smartlist_free(queue); + } } /** @@ -2542,15 +2483,9 @@ channel_queue_cell(channel_t *chan, cell_t *cell) /* Do we need to queue it, or can we just call the handler right away? */ if (!(chan->cell_handler)) need_to_queue = 1; - if (chan->incoming_queue && - (smartlist_len(chan->incoming_queue) > 0)) + if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) need_to_queue = 1; - /* If we need to queue and have no queue, create one */ - if (need_to_queue && !(chan->incoming_queue)) { - chan->incoming_queue = smartlist_new(); - } - /* Timestamp for receiving */ channel_timestamp_recv(chan); @@ -2568,14 +2503,13 @@ channel_queue_cell(channel_t *chan, cell_t *cell) chan->cell_handler(chan, cell); } else { /* Otherwise queue it and then process the queue if possible. */ - tor_assert(chan->incoming_queue); q = cell_queue_entry_new_fixed(cell); log_debug(LD_CHANNEL, "Queueing incoming cell_t %p for channel %p " "(global ID " U64_FORMAT ")", cell, chan, U64_PRINTF_ARG(chan->global_identifier)); - smartlist_add(chan->incoming_queue, q); + SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); if (chan->cell_handler || chan->var_cell_handler) { channel_process_cells(chan); @@ -2602,15 +2536,9 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) /* Do we need to queue it, or can we just call the handler right away? */ if (!(chan->var_cell_handler)) need_to_queue = 1; - if (chan->incoming_queue && - (smartlist_len(chan->incoming_queue) > 0)) + if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) need_to_queue = 1; - /* If we need to queue and have no queue, create one */ - if (need_to_queue && !(chan->incoming_queue)) { - chan->incoming_queue = smartlist_new(); - } - /* Timestamp for receiving */ channel_timestamp_recv(chan); @@ -2628,14 +2556,13 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) chan->var_cell_handler(chan, var_cell); } else { /* Otherwise queue it and then process the queue if possible. */ - tor_assert(chan->incoming_queue); q = cell_queue_entry_new_var(var_cell); log_debug(LD_CHANNEL, "Queueing incoming var_cell_t %p for channel %p " "(global ID " U64_FORMAT ")", var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); - smartlist_add(chan->incoming_queue, q); + SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); if (chan->cell_handler || chan->var_cell_handler) { channel_process_cells(chan); @@ -2927,13 +2854,10 @@ channel_free_all(void) } /* Now free channel_identity_map */ - if (channel_identity_map) { - log_debug(LD_CHANNEL, - "Freeing channel_identity_map"); - /* Geez, anything still left over just won't die ... let it leak then */ - digestmap_free(channel_identity_map, NULL); - channel_identity_map = NULL; - } + log_debug(LD_CHANNEL, + "Freeing channel_identity_map"); + /* Geez, anything still left over just won't die ... let it leak then */ + HT_CLEAR(channel_idmap, &channel_identity_map); log_debug(LD_CHANNEL, "Done cleaning up after channels"); @@ -3040,12 +2964,6 @@ channel_get_for_extend(const char *digest, tor_assert(msg_out); tor_assert(launch_out); - if (!channel_identity_map) { - *msg_out = "Router not connected (nothing is). Connecting."; - *launch_out = 1; - return NULL; - } - chan = channel_find_by_remote_digest(digest); /* Walk the list, unrefing the old one and refing the new at each @@ -3165,6 +3083,19 @@ channel_listener_describe_transport(channel_listener_t *chan_l) } /** + * Return the number of entries in <b>queue</b> + */ +static int +chan_cell_queue_len(const chan_cell_queue_t *queue) +{ + int r = 0; + cell_queue_entry_t *cell; + SIMPLEQ_FOREACH(cell, queue, next) + ++r; + return r; +} + +/** * Dump channel statistics * * Dump statistics for one channel to the log @@ -3233,6 +3164,7 @@ channel_dump_statistics(channel_t *chan, int severity) /* Handle remote address and descriptions */ have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr); if (have_remote_addr) { + char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); remote_addr_str = tor_dup_addr(&remote_addr); log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says its remote address" @@ -3241,16 +3173,19 @@ channel_dump_statistics(channel_t *chan, int severity) U64_PRINTF_ARG(chan->global_identifier), remote_addr_str, channel_get_canonical_remote_descr(chan), - channel_get_actual_remote_descr(chan)); + actual); tor_free(remote_addr_str); + tor_free(actual); } else { + char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know its remote " "address, but gives a canonical description of \"%s\" and an " "actual description of \"%s\"", U64_PRINTF_ARG(chan->global_identifier), channel_get_canonical_remote_descr(chan), - channel_get_actual_remote_descr(chan)); + actual); + tor_free(actual); } /* Handle marks */ @@ -3277,10 +3212,8 @@ channel_dump_statistics(channel_t *chan, int severity) " * Channel " U64_FORMAT " has %d queued incoming cells" " and %d queued outgoing cells", U64_PRINTF_ARG(chan->global_identifier), - (chan->incoming_queue != NULL) ? - smartlist_len(chan->incoming_queue) : 0, - (chan->outgoing_queue != NULL) ? - smartlist_len(chan->outgoing_queue) : 0); + chan_cell_queue_len(&chan->incoming_queue), + chan_cell_queue_len(&chan->outgoing_queue)); /* Describe circuits */ log(severity, LD_GENERAL, @@ -3465,8 +3398,10 @@ channel_listener_dump_transport_statistics(channel_listener_t *chan_l, * This function return a test provided by the lower layer of the remote * endpoint for this channel; it should specify the actual address connected * to/from. + * + * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} + * may invalidate the return value from this function. */ - const char * channel_get_actual_remote_descr(channel_t *chan) { @@ -3474,7 +3409,20 @@ channel_get_actual_remote_descr(channel_t *chan) tor_assert(chan->get_remote_descr); /* Param 1 indicates the actual description */ - return chan->get_remote_descr(chan, 1); + return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL); +} + +/** + * Return the text address of the remote endpoint. + * + * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} + * may invalidate the return value from this function. + */ +const char * +channel_get_actual_remote_address(channel_t *chan) +{ + /* Param 1 indicates the actual description */ + return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY); } /** @@ -3483,8 +3431,10 @@ channel_get_actual_remote_descr(channel_t *chan) * This function return a test provided by the lower layer of the remote * endpoint for this channel; it should use the known canonical address for * this OR's identity digest if possible. + * + * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} + * may invalidate the return value from this function. */ - const char * channel_get_canonical_remote_descr(channel_t *chan) { @@ -3496,12 +3446,12 @@ channel_get_canonical_remote_descr(channel_t *chan) } /** - * Get remote address if possible + * Get remote address if possible. * * Write the remote address out to a tor_addr_t if the underlying transport - * supports this operation. + * supports this operation, and return 1. Return 0 if the underlying transport + * doesn't let us do this. */ - int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out) { @@ -3529,8 +3479,7 @@ channel_has_queued_writes(channel_t *chan) tor_assert(chan); tor_assert(chan->has_queued_writes); - if (chan->outgoing_queue && - smartlist_len(chan->outgoing_queue) > 0) { + if (! SIMPLEQ_EMPTY(&chan->outgoing_queue)) { has_writes = 1; } else { /* Check with the lower layer */ diff --git a/src/or/channel.h b/src/or/channel.h index cb9835a9f5..d2106551aa 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -6,10 +6,11 @@ * \brief Header file for channel.c **/ -#ifndef _TOR_CHANNEL_H -#define _TOR_CHANNEL_H +#ifndef TOR_CHANNEL_H +#define TOR_CHANNEL_H #include "or.h" +#include "tor_queue.h" #include "circuitmux.h" /* Channel handler function pointer typedefs */ @@ -17,6 +18,10 @@ typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *); typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *); typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *); +struct cell_queue_entry_s; +SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue; +typedef struct chan_cell_queue chan_cell_queue_t; + /* * Channel struct; see the channel_t typedef in or.h. A channel is an * abstract interface for the OR-to-OR connection, similar to connection_or_t, @@ -79,10 +84,13 @@ struct channel_s { * available. */ int (*get_remote_addr)(channel_t *, tor_addr_t *); +#define GRD_FLAG_ORIGINAL 1 +#define GRD_FLAG_ADDR_ONLY 2 /* - * Get a text description of the remote endpoint; canonicalized if the - * arg is 0, or the one we originally connected to/received from if it's - * 1. + * Get a text description of the remote endpoint; canonicalized if the flag + * GRD_FLAG_ORIGINAL is not set, or the one we originally connected + * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only + * the original address. */ const char * (*get_remote_descr)(channel_t *, int); /* Check if the lower layer has queued writes */ @@ -117,13 +125,13 @@ struct channel_s { * Linked list of channels with the same identity digest, for the * digest->channel map */ - channel_t *next_with_same_id, *prev_with_same_id; + LIST_ENTRY(channel_s) next_with_same_id; /* List of incoming cells to handle */ - smartlist_t *incoming_queue; + chan_cell_queue_t incoming_queue; /* List of queued outgoing cells */ - smartlist_t *outgoing_queue; + chan_cell_queue_t outgoing_queue; /* Circuit mux for circuits sending on this channel */ circuitmux_t *cmux; @@ -294,7 +302,7 @@ void channel_listener_dumpstats(int severity); /* Set the cmux policy on all active channels */ void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol); -#ifdef _TOR_CHANNEL_INTERNAL +#ifdef TOR_CHANNEL_INTERNAL_ /* Channel operations for subclasses and internal use only */ @@ -412,9 +420,7 @@ channel_t * channel_find_by_remote_digest(const char *identity_digest); /** For things returned by channel_find_by_remote_digest(), walk the list. */ - channel_t * channel_next_with_digest(channel_t *chan); -channel_t * channel_prev_with_digest(channel_t *chan); /* * Metadata queries/updates @@ -424,6 +430,7 @@ const char * channel_describe_transport(channel_t *chan); void channel_dump_statistics(channel_t *chan, int severity); void channel_dump_transport_statistics(channel_t *chan, int severity); const char * channel_get_actual_remote_descr(channel_t *chan); +const char * channel_get_actual_remote_address(channel_t *chan); int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out); const char * channel_get_canonical_remote_descr(channel_t *chan); int channel_has_queued_writes(channel_t *chan); diff --git a/src/or/channeltls.c b/src/or/channeltls.c index 1a2956b755..d094d15af0 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -11,7 +11,7 @@ * should touch. */ -#define _TOR_CHANNEL_INTERNAL +#define TOR_CHANNEL_INTERNAL_ #include "or.h" #include "channel.h" @@ -46,6 +46,9 @@ uint64_t stats_n_authorize_cells_processed = 0; /** Active listener, if any */ channel_listener_t *channel_tls_listener = NULL; +/* Utility function declarations */ +static void channel_tls_common_init(channel_tls_t *tlschan); + /* channel_tls_t method declarations */ static void channel_tls_close_method(channel_t *chan); @@ -53,7 +56,7 @@ static const char * channel_tls_describe_transport_method(channel_t *chan); static int channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out); static const char * -channel_tls_get_remote_descr_method(channel_t *chan, int req); +channel_tls_get_remote_descr_method(channel_t *chan, int flags); static int channel_tls_has_queued_writes_method(channel_t *chan); static int channel_tls_is_canonical_method(channel_t *chan, int req); static int @@ -92,19 +95,18 @@ static int enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *tlschan); /** - * Start a new TLS channel - * - * Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to - * handshake with an OR with identity digest <b>id_digest</b>, and wrap - * it in a channel_tls_t. + * Do parts of channel_tls_t initialization common to channel_tls_connect() + * and channel_tls_handle_incoming(). */ -channel_t * -channel_tls_connect(const tor_addr_t *addr, uint16_t port, - const char *id_digest) +static void +channel_tls_common_init(channel_tls_t *tlschan) { - channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan)); - channel_t *chan = &(tlschan->_base); + channel_t *chan; + + tor_assert(tlschan); + + chan = &(tlschan->base_); channel_init(chan); chan->magic = TLS_CHAN_MAGIC; chan->state = CHANNEL_STATE_OPENING; @@ -120,6 +122,29 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, chan->write_packed_cell = channel_tls_write_packed_cell_method; chan->write_var_cell = channel_tls_write_var_cell_method; + chan->cmux = circuitmux_alloc(); + if (cell_ewma_enabled()) { + circuitmux_set_policy(chan->cmux, &ewma_policy); + } +} + +/** + * Start a new TLS channel + * + * Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to + * handshake with an OR with identity digest <b>id_digest</b>, and wrap + * it in a channel_tls_t. + */ + +channel_t * +channel_tls_connect(const tor_addr_t *addr, uint16_t port, + const char *id_digest) +{ + channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan)); + channel_t *chan = &(tlschan->base_); + + channel_tls_common_init(tlschan); + log_debug(LD_CHANNEL, "In channel_tls_connect() for channel %p " "(global id " U64_FORMAT ")", @@ -129,11 +154,6 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, if (is_local_addr(addr)) channel_mark_local(chan); channel_mark_outgoing(chan); - chan->cmux = circuitmux_alloc(); - if (cell_ewma_enabled()) { - circuitmux_set_policy(chan->cmux, &ewma_policy); - } - /* Set up or_connection stuff */ tlschan->conn = connection_or_connect(addr, port, id_digest, tlschan); /* connection_or_connect() will fill in tlschan->conn */ @@ -216,14 +236,26 @@ channel_tls_start_listener(void) void channel_tls_free_all(void) { + channel_listener_t *old_listener = NULL; + log_debug(LD_CHANNEL, "Shutting down TLS channels..."); if (channel_tls_listener) { - channel_listener_unregister(channel_tls_listener); - channel_listener_mark_for_close(channel_tls_listener); - channel_listener_free(channel_tls_listener); - channel_tls_listener = NULL; + /* + * When we close it, channel_tls_listener will get nulled out, so save + * a pointer so we can free it. + */ + old_listener = channel_tls_listener; + log_debug(LD_CHANNEL, + "Closing channel_tls_listener with ID " U64_FORMAT + " at %p.", + U64_PRINTF_ARG(old_listener->global_identifier), + old_listener); + channel_listener_unregister(old_listener); + channel_listener_mark_for_close(old_listener); + channel_listener_free(old_listener); + tor_assert(channel_tls_listener == NULL); } log_debug(LD_CHANNEL, @@ -238,24 +270,12 @@ channel_t * channel_tls_handle_incoming(or_connection_t *orconn) { channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan)); - channel_t *chan = &(tlschan->_base); + channel_t *chan = &(tlschan->base_); tor_assert(orconn); tor_assert(!(orconn->chan)); - channel_init(chan); - chan->magic = TLS_CHAN_MAGIC; - chan->state = CHANNEL_STATE_OPENING; - chan->close = channel_tls_close_method; - chan->describe_transport = channel_tls_describe_transport_method; - chan->get_remote_descr = channel_tls_get_remote_descr_method; - chan->has_queued_writes = channel_tls_has_queued_writes_method; - chan->is_canonical = channel_tls_is_canonical_method; - chan->matches_extend_info = channel_tls_matches_extend_info_method; - chan->matches_target = channel_tls_matches_target_method; - chan->write_cell = channel_tls_write_cell_method; - chan->write_packed_cell = channel_tls_write_packed_cell_method; - chan->write_var_cell = channel_tls_write_var_cell_method; + channel_tls_common_init(tlschan); /* Link the channel and orconn to each other */ tlschan->conn = orconn; @@ -264,11 +284,6 @@ channel_tls_handle_incoming(or_connection_t *orconn) if (is_local_addr(&(TO_CONN(orconn)->addr))) channel_mark_local(chan); channel_mark_incoming(chan); - chan->cmux = circuitmux_alloc(); - if (cell_ewma_enabled()) { - circuitmux_set_policy(chan->cmux, &ewma_policy); - } - /* If we got one, we should register it */ if (chan) channel_register(chan); @@ -288,7 +303,7 @@ channel_tls_to_base(channel_tls_t *tlschan) { if (!tlschan) return NULL; - return &(tlschan->_base); + return &(tlschan->base_); } /** @@ -400,7 +415,7 @@ channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out) */ static const char * -channel_tls_get_remote_descr_method(channel_t *chan, int req) +channel_tls_get_remote_descr_method(channel_t *chan, int flags) { #define MAX_DESCR_LEN 32 @@ -415,21 +430,34 @@ channel_tls_get_remote_descr_method(channel_t *chan, int req) conn = TO_CONN(tlschan->conn); - switch (req) { + switch (flags) { case 0: - /* Canonical address */ + /* Canonical address with port*/ tor_snprintf(buf, MAX_DESCR_LEN + 1, "%s:%u", conn->address, conn->port); answer = buf; break; - case 1: - /* Actual address */ + case GRD_FLAG_ORIGINAL: + /* Actual address with port */ addr_str = tor_dup_addr(&(tlschan->conn->real_addr)); tor_snprintf(buf, MAX_DESCR_LEN + 1, "%s:%u", addr_str, conn->port); tor_free(addr_str); answer = buf; break; + case GRD_FLAG_ADDR_ONLY: + /* Canonical address, no port */ + strlcpy(buf, conn->address, sizeof(buf)); + answer = buf; + break; + case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY: + /* Actual address, no port */ + addr_str = tor_dup_addr(&(tlschan->conn->real_addr)); + strlcpy(buf, addr_str, sizeof(buf)); + tor_free(addr_str); + answer = buf; + break; + default: /* Something's broken in channel.c */ tor_assert(1); @@ -441,7 +469,7 @@ channel_tls_get_remote_descr_method(channel_t *chan, int req) /** * Tell the upper layer if we have queued writes * - * This implements the has_queued_writes method for channel_tls _t; it returns + * This implements the has_queued_writes method for channel_tls t_; it returns * 1 iff we have queued writes on the outbuf of the underlying or_connection_t. */ @@ -520,7 +548,7 @@ channel_tls_matches_extend_info_method(channel_t *chan, /** * Check if we match a target address * - * This implements the matches_target method for channel_tls _t; the upper + * This implements the matches_target method for channel_tls t_; the upper * layer wants to know if this channel matches a target address when extending * a circuit. */ @@ -847,7 +875,7 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) handshaking = (TO_CONN(conn)->state != OR_CONN_STATE_OPEN); - if (conn->_base.marked_for_close) + if (conn->base_.marked_for_close) return; /* Reject all but VERSIONS and NETINFO when handshaking. */ @@ -864,7 +892,7 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) return; } - if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) + if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_cell(conn->handshake_state, cell, 1); switch (cell->command) { @@ -1118,7 +1146,8 @@ enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *chan) "Received a cell while TLS-handshaking, not in " "OR_HANDSHAKING_V3, on a connection we originated."); } - chan->conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V3; + connection_or_block_renegotiation(chan->conn); + chan->conn->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3; if (connection_init_or_handshake_state(chan->conn, started_here) < 0) { connection_or_close_for_error(chan->conn, 0); return -1; @@ -1159,7 +1188,7 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) (int)(chan->conn->link_proto)); return; } - switch (chan->conn->_base.state) + switch (chan->conn->base_.state) { case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: @@ -1194,12 +1223,21 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) connection_or_close_for_error(chan->conn, 0); return; } else if (highest_supported_version < 3 && - chan->conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { + chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { log_fn(LOG_PROTOCOL_WARN, LD_OR, "Negotiated link protocol 2 or lower after doing a v3 TLS " "handshake. Closing connection."); connection_or_close_for_error(chan->conn, 0); return; + } else if (highest_supported_version != 2 && + chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V2) { + /* XXXX This should eventually be a log_protocol_warn */ + log_fn(LOG_WARN, LD_OR, + "Negotiated link with non-2 protocol after doing a v2 TLS " + "handshake with %s. Closing connection.", + fmt_addr(&chan->conn->base_.addr)); + connection_or_close_for_error(chan->conn, 0); + return; } chan->conn->link_proto = highest_supported_version; @@ -1209,8 +1247,8 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) log_info(LD_OR, "Negotiated version %d with %s:%d; sending NETINFO.", highest_supported_version, - safe_str_client(chan->conn->_base.address), - chan->conn->_base.port); + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port); if (connection_or_send_netinfo(chan->conn) < 0) { connection_or_close_for_error(chan->conn, 0); @@ -1232,8 +1270,8 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) log_info(LD_OR, "Negotiated version %d with %s:%d; %s%s%s%s%s", highest_supported_version, - safe_str_client(chan->conn->_base.address), - chan->conn->_base.port, + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port, send_any ? "Sending cells:" : "Waiting for CERTS cell", send_versions ? " VERSIONS" : "", send_certs ? " CERTS" : "", @@ -1309,8 +1347,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) chan->conn->link_proto == 0 ? "non-versioned" : "a v1"); return; } - if (chan->conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V2 && - chan->conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 && + chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { log_fn(LOG_PROTOCOL_WARN, LD_OR, "Received a NETINFO cell on non-handshaking connection; dropping."); return; @@ -1318,7 +1356,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) tor_assert(chan->conn->handshake_state && chan->conn->handshake_state->received_versions); - if (chan->conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { + if (chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { tor_assert(chan->conn->link_proto >= 3); if (chan->conn->handshake_state->started_here) { if (!(chan->conn->handshake_state->authenticated)) { @@ -1338,8 +1376,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL); connection_or_init_conn_from_address(chan->conn, - &(chan->conn->_base.addr), - chan->conn->_base.port, + &(chan->conn->base_.addr), + chan->conn->base_.port, (const char*)(chan->conn->handshake_state-> authenticated_peer_id), 0); @@ -1408,8 +1446,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) "server at %s:%d. It seems that our clock is %s by %s, or " "that theirs is %s. Tor requires an accurate clock to work: " "please check your time and date settings.", - chan->conn->_base.address, - (int)(chan->conn->_base.port), + chan->conn->base_.address, + (int)(chan->conn->base_.port), apparent_skew > 0 ? "ahead" : "behind", dbuf, apparent_skew > 0 ? "behind" : "ahead"); @@ -1417,8 +1455,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) control_event_general_status(LOG_WARN, "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d", apparent_skew, - chan->conn->_base.address, - chan->conn->_base.port); + chan->conn->base_.address, + chan->conn->base_.port); } /* XXX maybe act on my_apparent_addr, if the source is sufficiently @@ -1428,16 +1466,16 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got good NETINFO cell from %s:%d; but " "was unable to make the OR connection become open.", - safe_str_client(chan->conn->_base.address), - chan->conn->_base.port); + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port); connection_or_close_for_error(chan->conn, 0); } else { log_info(LD_OR, "Got good NETINFO cell from %s:%d; OR connection is now " "open, using protocol version %d. Its ID digest is %s. " "Our address is apparently %s.", - safe_str_client(chan->conn->_base.address), - chan->conn->_base.port, + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port, (int)(chan->conn->link_proto), hex_str(TLS_CHAN_TO_BASE(chan)->identity_digest, DIGEST_LEN), @@ -1481,13 +1519,13 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ "Received a bad CERTS cell from %s:%d: %s", \ - safe_str(chan->conn->_base.address), \ - chan->conn->_base.port, (s)); \ + safe_str(chan->conn->base_.address), \ + chan->conn->base_.port, (s)); \ connection_or_close_for_error(chan->conn, 0); \ return; \ } while (0) - if (chan->conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) ERR("We're not doing a v3 handshake!"); if (chan->conn->link_proto < 3) ERR("We're not using link protocol >= 3"); @@ -1522,8 +1560,8 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) if (!cert) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received undecodable certificate in CERTS cell from %s:%d", - safe_str(chan->conn->_base.address), - chan->conn->_base.port); + safe_str(chan->conn->base_.address), + chan->conn->base_.port); } else { if (cert_type == OR_CERT_TYPE_TLS_LINK) { if (link_cert) { @@ -1599,7 +1637,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) log_info(LD_OR, "Got some good certificates from %s:%d: Authenticated it.", - safe_str(chan->conn->_base.address), chan->conn->_base.port); + safe_str(chan->conn->base_.address), chan->conn->base_.port); chan->conn->handshake_state->id_cert = id_cert; id_cert = NULL; @@ -1623,8 +1661,8 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) log_info(LD_OR, "Got some good certificates from %s:%d: " "Waiting for AUTHENTICATE.", - safe_str(chan->conn->_base.address), - chan->conn->_base.port); + safe_str(chan->conn->base_.address), + chan->conn->base_.port); /* XXXX check more stuff? */ chan->conn->handshake_state->id_cert = id_cert; @@ -1674,13 +1712,13 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \ - safe_str(chan->conn->_base.address), \ - chan->conn->_base.port, (s)); \ + safe_str(chan->conn->base_.address), \ + chan->conn->base_.port, (s)); \ connection_or_close_for_error(chan->conn, 0); \ return; \ } while (0) - if (chan->conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) ERR("We're not currently doing a v3 handshake"); if (chan->conn->link_proto < 3) ERR("We're not using link protocol >= 3"); @@ -1720,8 +1758,8 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d: Sending " "authentication", - safe_str(chan->conn->_base.address), - chan->conn->_base.port); + safe_str(chan->conn->base_.address), + chan->conn->base_.port); if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) { log_warn(LD_OR, @@ -1733,8 +1771,8 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d, but we don't " "know any of its authentication types. Not authenticating.", - safe_str(chan->conn->_base.address), - chan->conn->_base.port); + safe_str(chan->conn->base_.address), + chan->conn->base_.port); } if (connection_or_send_netinfo(chan->conn) < 0) { @@ -1771,13 +1809,13 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ "Received a bad AUTHENTICATE cell from %s:%d: %s", \ - safe_str(chan->conn->_base.address), \ - chan->conn->_base.port, (s)); \ + safe_str(chan->conn->base_.address), \ + chan->conn->base_.port, (s)); \ connection_or_close_for_error(chan->conn, 0); \ return; \ } while (0) - if (chan->conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) ERR("We're not doing a v3 handshake"); if (chan->conn->link_proto < 3) ERR("We're not using link protocol >= 3"); @@ -1877,16 +1915,16 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) crypto_pk_free(identity_rcvd); connection_or_init_conn_from_address(chan->conn, - &(chan->conn->_base.addr), - chan->conn->_base.port, + &(chan->conn->base_.addr), + chan->conn->base_.port, (const char*)(chan->conn->handshake_state-> authenticated_peer_id), 0); log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.", - safe_str(chan->conn->_base.address), - chan->conn->_base.port); + safe_str(chan->conn->base_.address), + chan->conn->base_.port); } #undef ERR diff --git a/src/or/channeltls.h b/src/or/channeltls.h index ca2fc88940..b7e0475de6 100644 --- a/src/or/channeltls.h +++ b/src/or/channeltls.h @@ -6,8 +6,8 @@ * \brief Header file for channeltls.c **/ -#ifndef _TOR_CHANNEL_TLS_H -#define _TOR_CHANNEL_TLS_H +#ifndef TOR_CHANNELTLS_H +#define TOR_CHANNELTLS_H #include "or.h" #include "channel.h" @@ -17,16 +17,16 @@ #define TLS_CHAN_MAGIC 0x8a192427U -#ifdef _TOR_CHANNEL_INTERNAL +#ifdef TOR_CHANNEL_INTERNAL_ struct channel_tls_s { /* Base channel_t struct */ - channel_t _base; + channel_t base_; /* or_connection_t pointer */ or_connection_t *conn; }; -#endif /* _TOR_CHANNEL_INTERNAL */ +#endif /* TOR_CHANNEL_INTERNAL_ */ channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port, const char *id_digest); diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index adf3c41fe3..1fb93bbd2c 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -9,12 +9,11 @@ * \brief The actual details of building circuits. **/ -#define CIRCUIT_PRIVATE - #include "or.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "circuitstats.h" #include "circuituse.h" #include "command.h" #include "config.h" @@ -24,6 +23,7 @@ #include "connection_or.h" #include "control.h" #include "directory.h" +#include "entrynodes.h" #include "main.h" #include "networkstatus.h" #include "nodelist.h" @@ -36,95 +36,17 @@ #include "routerlist.h" #include "routerparse.h" #include "routerset.h" -#include "statefile.h" #include "crypto.h" -#undef log -#include <math.h> #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif -#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2)) - /********* START VARIABLES **********/ -/** Global list of circuit build times */ -// XXXX: Add this as a member for entry_guard_t instead of global? -// Then we could do per-guard statistics, as guards are likely to -// vary in their own latency. The downside of this is that guards -// can change frequently, so we'd be building a lot more circuits -// most likely. -/* XXXX024 Make this static; add accessor functions. */ -circuit_build_times_t circ_times; /** A global list of all circuits at this hop. */ extern circuit_t *global_circuitlist; -/** An entry_guard_t represents our information about a chosen long-term - * first hop, known as a "helper" node in the literature. We can't just - * use a node_t, since we want to remember these even when we - * don't have any directory info. */ -typedef struct { - char nickname[MAX_NICKNAME_LEN+1]; - char identity[DIGEST_LEN]; - time_t chosen_on_date; /**< Approximately when was this guard added? - * "0" if we don't know. */ - char *chosen_by_version; /**< What tor version added this guard? NULL - * if we don't know. */ - unsigned int made_contact : 1; /**< 0 if we have never connected to this - * router, 1 if we have. */ - unsigned int can_retry : 1; /**< Should we retry connecting to this entry, - * in spite of having it marked as unreachable?*/ - unsigned int path_bias_notice : 1; /**< Did we alert the user about path bias - * for this node already? */ - unsigned int path_bias_disabled : 1; /**< Have we disabled this node because - * of path bias issues? */ - time_t bad_since; /**< 0 if this guard is currently usable, or the time at - * which it was observed to become (according to the - * directory or the user configuration) unusable. */ - time_t unreachable_since; /**< 0 if we can connect to this guard, or the - * time at which we first noticed we couldn't - * connect to it. */ - time_t last_attempted; /**< 0 if we can connect to this guard, or the time - * at which we last failed to connect to it. */ - - unsigned first_hops; /**< Number of first hops this guard has completed */ - unsigned circuit_successes; /**< Number of successfully built circuits using - * this guard as first hop. */ -} entry_guard_t; - -/** Information about a configured bridge. Currently this just matches the - * ones in the torrc file, but one day we may be able to learn about new - * bridges on our own, and remember them in the state file. */ -typedef struct { - /** Address of the bridge. */ - tor_addr_t addr; - /** TLS port for the bridge. */ - uint16_t port; - /** Boolean: We are re-parsing our bridge list, and we are going to remove - * this one if we don't find it in the list of configured bridges. */ - unsigned marked_for_removal : 1; - /** Expected identity digest, or all zero bytes if we don't know what the - * digest should be. */ - char identity[DIGEST_LEN]; - - /** Name of pluggable transport protocol taken from its config line. */ - char *transport_name; - - /** When should we next try to fetch a descriptor for this bridge? */ - download_status_t fetch_status; -} bridge_info_t; - -/** A list of our chosen entry guards. */ -static smartlist_t *entry_guards = NULL; -/** A value of 1 means that the entry_guards list has changed - * and those changes need to be flushed to disk. */ -static int entry_guards_dirty = 0; - -/** If set, we're running the unit tests: we should avoid clobbering - * our state file or accessing get_options() or get_or_state() */ -static int unit_tests = 0; - /********* END VARIABLES ************/ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, @@ -137,12 +59,6 @@ static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); static int onion_extend_cpath(origin_circuit_t *circ); static int count_acceptable_nodes(smartlist_t *routers); static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); - -static void entry_guards_changed(void); -static entry_guard_t *entry_guard_get_by_id_digest(const char *digest); - -static void bridge_free(bridge_info_t *bridge); - static int entry_guard_inc_first_hop_count(entry_guard_t *guard); static void pathbias_count_success(origin_circuit_t *circ); @@ -162,1541 +78,6 @@ channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, return chan; } -/** - * This function decides if CBT learning should be disabled. It returns - * true if one or more of the following four conditions are met: - * - * 1. If the cbtdisabled consensus parameter is set. - * 2. If the torrc option LearnCircuitBuildTimeout is false. - * 3. If we are a directory authority - * 4. If we fail to write circuit build time history to our state file. - */ -static int -circuit_build_times_disabled(void) -{ - if (unit_tests) { - return 0; - } else { - int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", - 0, 0, 1); - int config_disabled = !get_options()->LearnCircuitBuildTimeout; - int dirauth_disabled = get_options()->AuthoritativeDir; - int state_disabled = did_last_state_file_write_fail() ? 1 : 0; - - if (consensus_disabled || config_disabled || dirauth_disabled || - state_disabled) { - log_debug(LD_CIRC, - "CircuitBuildTime learning is disabled. " - "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", - consensus_disabled, config_disabled, dirauth_disabled, - state_disabled); - return 1; - } else { - log_debug(LD_CIRC, - "CircuitBuildTime learning is not disabled. " - "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", - consensus_disabled, config_disabled, dirauth_disabled, - state_disabled); - return 0; - } - } -} - -/** - * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter. - * - * Effect: When this many timeouts happen in the last 'cbtrecentcount' - * circuit attempts, the client should discard all of its history and - * begin learning a fresh timeout value. - */ -static int32_t -circuit_build_times_max_timeouts(void) -{ - int32_t cbt_maxtimeouts; - - cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts", - CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT, - CBT_MIN_MAX_RECENT_TIMEOUT_COUNT, - CBT_MAX_MAX_RECENT_TIMEOUT_COUNT); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is" - " %d", - cbt_maxtimeouts); - } - - return cbt_maxtimeouts; -} - -/** - * Retrieve and bounds-check the cbtnummodes consensus paramter. - * - * Effect: This value governs how many modes to use in the weighted - * average calculation of Pareto parameter Xm. A value of 3 introduces - * some bias (2-5% of CDF) under ideal conditions, but allows for better - * performance in the event that a client chooses guard nodes of radically - * different performance characteristics. - */ -static int32_t -circuit_build_times_default_num_xm_modes(void) -{ - int32_t num = networkstatus_get_param(NULL, "cbtnummodes", - CBT_DEFAULT_NUM_XM_MODES, - CBT_MIN_NUM_XM_MODES, - CBT_MAX_NUM_XM_MODES); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_default_num_xm_modes() called, cbtnummodes" - " is %d", - num); - } - - return num; -} - -/** - * Retrieve and bounds-check the cbtmincircs consensus paramter. - * - * Effect: This is the minimum number of circuits to build before - * computing a timeout. - */ -static int32_t -circuit_build_times_min_circs_to_observe(void) -{ - int32_t num = networkstatus_get_param(NULL, "cbtmincircs", - CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE, - CBT_MIN_MIN_CIRCUITS_TO_OBSERVE, - CBT_MAX_MIN_CIRCUITS_TO_OBSERVE); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_min_circs_to_observe() called, cbtmincircs" - " is %d", - num); - } - - return num; -} - -/** Return true iff <b>cbt</b> has recorded enough build times that we - * want to start acting on the timeout it implies. */ -int -circuit_build_times_enough_to_compute(circuit_build_times_t *cbt) -{ - return cbt->total_build_times >= circuit_build_times_min_circs_to_observe(); -} - -/** - * Retrieve and bounds-check the cbtquantile consensus paramter. - * - * Effect: This is the position on the quantile curve to use to set the - * timeout value. It is a percent (10-99). - */ -double -circuit_build_times_quantile_cutoff(void) -{ - int32_t num = networkstatus_get_param(NULL, "cbtquantile", - CBT_DEFAULT_QUANTILE_CUTOFF, - CBT_MIN_QUANTILE_CUTOFF, - CBT_MAX_QUANTILE_CUTOFF); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_quantile_cutoff() called, cbtquantile" - " is %d", - num); - } - - return num/100.0; -} - -/* DOCDOC circuit_build_times_get_bw_scale */ -int -circuit_build_times_get_bw_scale(networkstatus_t *ns) -{ - return networkstatus_get_param(ns, "bwweightscale", - BW_WEIGHT_SCALE, - BW_MIN_WEIGHT_SCALE, - BW_MAX_WEIGHT_SCALE); -} - -/** - * Retrieve and bounds-check the cbtclosequantile consensus paramter. - * - * Effect: This is the position on the quantile curve to use to set the - * timeout value to use to actually close circuits. It is a percent - * (0-99). - */ -static double -circuit_build_times_close_quantile(void) -{ - int32_t param; - /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */ - int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff()); - param = networkstatus_get_param(NULL, "cbtclosequantile", - CBT_DEFAULT_CLOSE_QUANTILE, - CBT_MIN_CLOSE_QUANTILE, - CBT_MAX_CLOSE_QUANTILE); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_close_quantile() called, cbtclosequantile" - " is %d", param); - } - - if (param < min) { - log_warn(LD_DIR, "Consensus parameter cbtclosequantile is " - "too small, raising to %d", min); - param = min; - } - return param / 100.0; -} - -/** - * Retrieve and bounds-check the cbttestfreq consensus paramter. - * - * Effect: Describes how often in seconds to build a test circuit to - * gather timeout values. Only applies if less than 'cbtmincircs' - * have been recorded. - */ -static int32_t -circuit_build_times_test_frequency(void) -{ - int32_t num = networkstatus_get_param(NULL, "cbttestfreq", - CBT_DEFAULT_TEST_FREQUENCY, - CBT_MIN_TEST_FREQUENCY, - CBT_MAX_TEST_FREQUENCY); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_test_frequency() called, cbttestfreq is %d", - num); - } - - return num; -} - -/** - * Retrieve and bounds-check the cbtmintimeout consensus parameter. - * - * Effect: This is the minimum allowed timeout value in milliseconds. - * The minimum is to prevent rounding to 0 (we only check once - * per second). - */ -static int32_t -circuit_build_times_min_timeout(void) -{ - int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", - CBT_DEFAULT_TIMEOUT_MIN_VALUE, - CBT_MIN_TIMEOUT_MIN_VALUE, - CBT_MAX_TIMEOUT_MIN_VALUE); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_min_timeout() called, cbtmintimeout is %d", - num); - } - - return num; -} - -/** - * Retrieve and bounds-check the cbtinitialtimeout consensus paramter. - * - * Effect: This is the timeout value to use before computing a timeout, - * in milliseconds. - */ -int32_t -circuit_build_times_initial_timeout(void) -{ - int32_t min = circuit_build_times_min_timeout(); - int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout", - CBT_DEFAULT_TIMEOUT_INITIAL_VALUE, - CBT_MIN_TIMEOUT_INITIAL_VALUE, - CBT_MAX_TIMEOUT_INITIAL_VALUE); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_initial_timeout() called, " - "cbtinitialtimeout is %d", - param); - } - - if (param < min) { - log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, " - "raising to %d", min); - param = min; - } - return param; -} - -/** - * Retrieve and bounds-check the cbtrecentcount consensus paramter. - * - * Effect: This is the number of circuit build times to keep track of - * for deciding if we hit cbtmaxtimeouts and need to reset our state - * and learn a new timeout. - */ -static int32_t -circuit_build_times_recent_circuit_count(networkstatus_t *ns) -{ - int32_t num; - num = networkstatus_get_param(ns, "cbtrecentcount", - CBT_DEFAULT_RECENT_CIRCUITS, - CBT_MIN_RECENT_CIRCUITS, - CBT_MAX_RECENT_CIRCUITS); - - if (!(get_options()->LearnCircuitBuildTimeout)) { - log_debug(LD_BUG, - "circuit_build_times_recent_circuit_count() called, " - "cbtrecentcount is %d", - num); - } - - return num; -} - -/** - * This function is called when we get a consensus update. - * - * It checks to see if we have changed any consensus parameters - * that require reallocation or discard of previous stats. - */ -void -circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, - networkstatus_t *ns) -{ - int32_t num; - - /* - * First check if we're doing adaptive timeouts at all; nothing to - * update if we aren't. - */ - - if (!circuit_build_times_disabled()) { - num = circuit_build_times_recent_circuit_count(ns); - - if (num > 0) { - if (num != cbt->liveness.num_recent_circs) { - int8_t *recent_circs; - log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many " - "circuits we must track to detect network failures from %d " - "to %d.", cbt->liveness.num_recent_circs, num); - - tor_assert(cbt->liveness.timeouts_after_firsthop || - cbt->liveness.num_recent_circs == 0); - - /* - * Technically this is a circular array that we are reallocating - * and memcopying. However, since it only consists of either 1s - * or 0s, and is only used in a statistical test to determine when - * we should discard our history after a sufficient number of 1's - * have been reached, it is fine if order is not preserved or - * elements are lost. - * - * cbtrecentcount should only be changing in cases of severe network - * distress anyway, so memory correctness here is paramount over - * doing acrobatics to preserve the array. - */ - recent_circs = tor_malloc_zero(sizeof(int8_t)*num); - if (cbt->liveness.timeouts_after_firsthop && - cbt->liveness.num_recent_circs > 0) { - memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, - sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); - } - - // Adjust the index if it needs it. - if (num < cbt->liveness.num_recent_circs) { - cbt->liveness.after_firsthop_idx = MIN(num-1, - cbt->liveness.after_firsthop_idx); - } - - tor_free(cbt->liveness.timeouts_after_firsthop); - cbt->liveness.timeouts_after_firsthop = recent_circs; - cbt->liveness.num_recent_circs = num; - } - /* else no change, nothing to do */ - } else { /* num == 0 */ - /* - * Weird. This probably shouldn't happen, so log a warning, but try - * to do something sensible anyway. - */ - - log_warn(LD_CIRC, - "The cbtrecentcircs consensus parameter came back zero! " - "This disables adaptive timeouts since we can't keep track of " - "any recent circuits."); - - circuit_build_times_free_timeouts(cbt); - } - } else { - /* - * Adaptive timeouts are disabled; this might be because of the - * LearnCircuitBuildTimes config parameter, and hence permanent, or - * the cbtdisabled consensus parameter, so it may be a new condition. - * Treat it like getting num == 0 above and free the circuit history - * if we have any. - */ - - circuit_build_times_free_timeouts(cbt); - } -} - -/** Make a note that we're running unit tests (rather than running Tor - * itself), so we avoid clobbering our state file. */ -void -circuitbuild_running_unit_tests(void) -{ - unit_tests = 1; -} - -/** - * Return the initial default or configured timeout in milliseconds - */ -static double -circuit_build_times_get_initial_timeout(void) -{ - double timeout; - - /* - * Check if we have LearnCircuitBuildTimeout, and if we don't, - * always use CircuitBuildTimeout, no questions asked. - */ - if (get_options()->LearnCircuitBuildTimeout) { - if (!unit_tests && get_options()->CircuitBuildTimeout) { - timeout = get_options()->CircuitBuildTimeout*1000; - if (timeout < circuit_build_times_min_timeout()) { - log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", - circuit_build_times_min_timeout()/1000); - timeout = circuit_build_times_min_timeout(); - } - } else { - timeout = circuit_build_times_initial_timeout(); - } - } else { - timeout = get_options()->CircuitBuildTimeout*1000; - } - - return timeout; -} - -/** - * Reset the build time state. - * - * Leave estimated parameters, timeout and network liveness intact - * for future use. - */ -void -circuit_build_times_reset(circuit_build_times_t *cbt) -{ - memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times)); - cbt->total_build_times = 0; - cbt->build_times_idx = 0; - cbt->have_computed_timeout = 0; -} - -/** - * Initialize the buildtimes structure for first use. - * - * Sets the initial timeout values based on either the config setting, - * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE). - */ -void -circuit_build_times_init(circuit_build_times_t *cbt) -{ - memset(cbt, 0, sizeof(*cbt)); - /* - * Check if we really are using adaptive timeouts, and don't keep - * track of this stuff if not. - */ - if (!circuit_build_times_disabled()) { - cbt->liveness.num_recent_circs = - circuit_build_times_recent_circuit_count(NULL); - cbt->liveness.timeouts_after_firsthop = - tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs); - } else { - cbt->liveness.num_recent_circs = 0; - cbt->liveness.timeouts_after_firsthop = NULL; - } - cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); - control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); -} - -/** - * Free the saved timeouts, if the cbtdisabled consensus parameter got turned - * on or something. - */ - -void -circuit_build_times_free_timeouts(circuit_build_times_t *cbt) -{ - if (!cbt) return; - - if (cbt->liveness.timeouts_after_firsthop) { - tor_free(cbt->liveness.timeouts_after_firsthop); - } - - cbt->liveness.num_recent_circs = 0; -} - -#if 0 -/** - * Rewind our build time history by n positions. - */ -static void -circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) -{ - int i = 0; - - cbt->build_times_idx -= n; - cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE; - - for (i = 0; i < n; i++) { - cbt->circuit_build_times[(i+cbt->build_times_idx) - %CBT_NCIRCUITS_TO_OBSERVE]=0; - } - - if (cbt->total_build_times > n) { - cbt->total_build_times -= n; - } else { - cbt->total_build_times = 0; - } - - log_info(LD_CIRC, - "Rewound history by %d places. Current index: %d. " - "Total: %d", n, cbt->build_times_idx, cbt->total_build_times); -} -#endif - -/** - * Add a new build time value <b>time</b> to the set of build times. Time - * units are milliseconds. - * - * circuit_build_times <b>cbt</b> is a circular array, so loop around when - * array is full. - */ -int -circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) -{ - if (time <= 0 || time > CBT_BUILD_TIME_MAX) { - log_warn(LD_BUG, "Circuit build time is too large (%u)." - "This is probably a bug.", time); - tor_fragile_assert(); - return -1; - } - - log_debug(LD_CIRC, "Adding circuit build time %u", time); - - cbt->circuit_build_times[cbt->build_times_idx] = time; - cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; - if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) - cbt->total_build_times++; - - if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { - /* Save state every n circuit builds */ - if (!unit_tests && !get_options()->AvoidDiskWrites) - or_state_mark_dirty(get_or_state(), 0); - } - - return 0; -} - -/** - * Return maximum circuit build time - */ -static build_time_t -circuit_build_times_max(circuit_build_times_t *cbt) -{ - int i = 0; - build_time_t max_build_time = 0; - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] > max_build_time - && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED) - max_build_time = cbt->circuit_build_times[i]; - } - return max_build_time; -} - -#if 0 -/** Return minimum circuit build time */ -build_time_t -circuit_build_times_min(circuit_build_times_t *cbt) -{ - int i = 0; - build_time_t min_build_time = CBT_BUILD_TIME_MAX; - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */ - cbt->circuit_build_times[i] < min_build_time) - min_build_time = cbt->circuit_build_times[i]; - } - if (min_build_time == CBT_BUILD_TIME_MAX) { - log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!"); - } - return min_build_time; -} -#endif - -/** - * Calculate and return a histogram for the set of build times. - * - * Returns an allocated array of histrogram bins representing - * the frequency of index*CBT_BIN_WIDTH millisecond - * build times. Also outputs the number of bins in nbins. - * - * The return value must be freed by the caller. - */ -static uint32_t * -circuit_build_times_create_histogram(circuit_build_times_t *cbt, - build_time_t *nbins) -{ - uint32_t *histogram; - build_time_t max_build_time = circuit_build_times_max(cbt); - int i, c; - - *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); - histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); - - // calculate histogram - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] == 0 - || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) - continue; /* 0 <-> uninitialized */ - - c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH); - histogram[c]++; - } - - return histogram; -} - -/** - * Return the Pareto start-of-curve parameter Xm. - * - * Because we are not a true Pareto curve, we compute this as the - * weighted average of the N most frequent build time bins. N is either - * 1 if we don't have enough circuit build time data collected, or - * determined by the consensus parameter cbtnummodes (default 3). - */ -static build_time_t -circuit_build_times_get_xm(circuit_build_times_t *cbt) -{ - build_time_t i, nbins; - build_time_t *nth_max_bin; - int32_t bin_counts=0; - build_time_t ret = 0; - uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins); - int n=0; - int num_modes = circuit_build_times_default_num_xm_modes(); - - tor_assert(nbins > 0); - tor_assert(num_modes > 0); - - // Only use one mode if < 1000 buildtimes. Not enough data - // for multiple. - if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) - num_modes = 1; - - nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t)); - - /* Determine the N most common build times */ - for (i = 0; i < nbins; i++) { - if (histogram[i] >= histogram[nth_max_bin[0]]) { - nth_max_bin[0] = i; - } - - for (n = 1; n < num_modes; n++) { - if (histogram[i] >= histogram[nth_max_bin[n]] && - (!histogram[nth_max_bin[n-1]] - || histogram[i] < histogram[nth_max_bin[n-1]])) { - nth_max_bin[n] = i; - } - } - } - - for (n = 0; n < num_modes; n++) { - bin_counts += histogram[nth_max_bin[n]]; - ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]]; - log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]), - histogram[nth_max_bin[n]]); - } - - /* The following assert is safe, because we don't get called when we - * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */ - tor_assert(bin_counts > 0); - - ret /= bin_counts; - tor_free(histogram); - tor_free(nth_max_bin); - - return ret; -} - -/** - * Output a histogram of current circuit build times to - * the or_state_t state structure. - */ -void -circuit_build_times_update_state(circuit_build_times_t *cbt, - or_state_t *state) -{ - uint32_t *histogram; - build_time_t i = 0; - build_time_t nbins = 0; - config_line_t **next, *line; - - histogram = circuit_build_times_create_histogram(cbt, &nbins); - // write to state - config_free_lines(state->BuildtimeHistogram); - next = &state->BuildtimeHistogram; - *next = NULL; - - state->TotalBuildTimes = cbt->total_build_times; - state->CircuitBuildAbandonedCount = 0; - - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) - state->CircuitBuildAbandonedCount++; - } - - for (i = 0; i < nbins; i++) { - // compress the histogram by skipping the blanks - if (histogram[i] == 0) continue; - *next = line = tor_malloc_zero(sizeof(config_line_t)); - line->key = tor_strdup("CircuitBuildTimeBin"); - tor_asprintf(&line->value, "%d %d", - CBT_BIN_TO_MS(i), histogram[i]); - next = &(line->next); - } - - if (!unit_tests) { - if (!get_options()->AvoidDiskWrites) - or_state_mark_dirty(get_or_state(), 0); - } - - tor_free(histogram); -} - -/** - * Shuffle the build times array. - * - * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - */ -static void -circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, - build_time_t *raw_times, - uint32_t num_times) -{ - uint32_t n = num_times; - if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { - log_notice(LD_CIRC, "The number of circuit times that this Tor version " - "uses to calculate build times is less than the number stored " - "in your state file. Decreasing the circuit time history from " - "%lu to %d.", (unsigned long)num_times, - CBT_NCIRCUITS_TO_OBSERVE); - } - - if (n > INT_MAX-1) { - log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build " - "observations in your state file. That's far too many; probably " - "there's a bug here.", (unsigned long)n); - n = INT_MAX-1; - } - - /* This code can only be run on a compact array */ - while (n-- > 1) { - int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */ - build_time_t tmp = raw_times[k]; - raw_times[k] = raw_times[n]; - raw_times[n] = tmp; - } - - /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE - * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ - for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { - circuit_build_times_add_time(cbt, raw_times[n]); - } -} - -/** - * Filter old synthetic timeouts that were created before the - * new right-censored Pareto calculation was deployed. - * - * Once all clients before 0.2.1.13-alpha are gone, this code - * will be unused. - */ -static int -circuit_build_times_filter_timeouts(circuit_build_times_t *cbt) -{ - int num_filtered=0, i=0; - double timeout_rate = 0; - build_time_t max_timeout = 0; - - timeout_rate = circuit_build_times_timeout_rate(cbt); - max_timeout = (build_time_t)cbt->close_ms; - - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] > max_timeout) { - build_time_t replaced = cbt->circuit_build_times[i]; - num_filtered++; - cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED; - - log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced, - cbt->circuit_build_times[i]); - } - } - - log_info(LD_CIRC, - "We had %d timeouts out of %d build times, " - "and filtered %d above the max of %u", - (int)(cbt->total_build_times*timeout_rate), - cbt->total_build_times, num_filtered, max_timeout); - - return num_filtered; -} - -/** - * Load histogram from <b>state</b>, shuffling the resulting array - * after we do so. Use this result to estimate parameters and - * calculate the timeout. - * - * Return -1 on error. - */ -int -circuit_build_times_parse_state(circuit_build_times_t *cbt, - or_state_t *state) -{ - int tot_values = 0; - uint32_t loaded_cnt = 0, N = 0; - config_line_t *line; - unsigned int i; - build_time_t *loaded_times; - int err = 0; - circuit_build_times_init(cbt); - - if (circuit_build_times_disabled()) { - return 0; - } - - /* build_time_t 0 means uninitialized */ - loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes); - - for (line = state->BuildtimeHistogram; line; line = line->next) { - smartlist_t *args = smartlist_new(); - smartlist_split_string(args, line->value, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(args) < 2) { - log_warn(LD_GENERAL, "Unable to parse circuit build times: " - "Too few arguments to CircuitBuildTime"); - err = 1; - SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); - smartlist_free(args); - break; - } else { - const char *ms_str = smartlist_get(args,0); - const char *count_str = smartlist_get(args,1); - uint32_t count, k; - build_time_t ms; - int ok; - ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, - CBT_BUILD_TIME_MAX, &ok, NULL); - if (!ok) { - log_warn(LD_GENERAL, "Unable to parse circuit build times: " - "Unparsable bin number"); - err = 1; - SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); - smartlist_free(args); - break; - } - count = (uint32_t)tor_parse_ulong(count_str, 0, 0, - UINT32_MAX, &ok, NULL); - if (!ok) { - log_warn(LD_GENERAL, "Unable to parse circuit build times: " - "Unparsable bin count"); - err = 1; - SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); - smartlist_free(args); - break; - } - - if (loaded_cnt+count+state->CircuitBuildAbandonedCount - > state->TotalBuildTimes) { - log_warn(LD_CIRC, - "Too many build times in state file. " - "Stopping short before %d", - loaded_cnt+count); - SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); - smartlist_free(args); - break; - } - - for (k = 0; k < count; k++) { - loaded_times[loaded_cnt++] = ms; - } - N++; - SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); - smartlist_free(args); - } - } - - log_info(LD_CIRC, - "Adding %d timeouts.", state->CircuitBuildAbandonedCount); - for (i=0; i < state->CircuitBuildAbandonedCount; i++) { - loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED; - } - - if (loaded_cnt != state->TotalBuildTimes) { - log_warn(LD_CIRC, - "Corrupt state file? Build times count mismatch. " - "Read %d times, but file says %d", loaded_cnt, - state->TotalBuildTimes); - err = 1; - circuit_build_times_reset(cbt); - goto done; - } - - circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); - - /* Verify that we didn't overwrite any indexes */ - for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (!cbt->circuit_build_times[i]) - break; - tot_values++; - } - log_info(LD_CIRC, - "Loaded %d/%d values from %d lines in circuit time histogram", - tot_values, cbt->total_build_times, N); - - if (cbt->total_build_times != tot_values - || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) { - log_warn(LD_CIRC, - "Corrupt state file? Shuffled build times mismatch. " - "Read %d times, but file says %d", tot_values, - state->TotalBuildTimes); - err = 1; - circuit_build_times_reset(cbt); - goto done; - } - - circuit_build_times_set_timeout(cbt); - - if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) { - circuit_build_times_filter_timeouts(cbt); - } - - done: - tor_free(loaded_times); - return err ? -1 : 0; -} - -/** - * Estimates the Xm and Alpha parameters using - * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation - * - * The notable difference is that we use mode instead of min to estimate Xm. - * This is because our distribution is frechet-like. We claim this is - * an acceptable approximation because we are only concerned with the - * accuracy of the CDF of the tail. - */ -int -circuit_build_times_update_alpha(circuit_build_times_t *cbt) -{ - build_time_t *x=cbt->circuit_build_times; - double a = 0; - int n=0,i=0,abandoned_count=0; - build_time_t max_time=0; - - /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */ - /* We sort of cheat here and make our samples slightly more pareto-like - * and less frechet-like. */ - cbt->Xm = circuit_build_times_get_xm(cbt); - - tor_assert(cbt->Xm > 0); - - for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (!x[i]) { - continue; - } - - if (x[i] < cbt->Xm) { - a += tor_mathlog(cbt->Xm); - } else if (x[i] == CBT_BUILD_ABANDONED) { - abandoned_count++; - } else { - a += tor_mathlog(x[i]); - if (x[i] > max_time) - max_time = x[i]; - } - n++; - } - - /* - * We are erring and asserting here because this can only happen - * in codepaths other than startup. The startup state parsing code - * performs this same check, and resets state if it hits it. If we - * hit it at runtime, something serious has gone wrong. - */ - if (n!=cbt->total_build_times) { - log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n, - cbt->total_build_times); - } - tor_assert(n==cbt->total_build_times); - - if (max_time <= 0) { - /* This can happen if Xm is actually the *maximum* value in the set. - * It can also happen if we've abandoned every single circuit somehow. - * In either case, tell the caller not to compute a new build timeout. */ - log_warn(LD_BUG, - "Could not determine largest build time (%d). " - "Xm is %dms and we've abandoned %d out of %d circuits.", max_time, - cbt->Xm, abandoned_count, n); - return 0; - } - - a += abandoned_count*tor_mathlog(max_time); - - a -= n*tor_mathlog(cbt->Xm); - // Estimator comes from Eq #4 in: - // "Bayesian estimation based on trimmed samples from Pareto populations" - // by Arturo J. Fernández. We are right-censored only. - a = (n-abandoned_count)/a; - - cbt->alpha = a; - - return 1; -} - -/** - * This is the Pareto Quantile Function. It calculates the point x - * in the distribution such that F(x) = quantile (ie quantile*100% - * of the mass of the density function is below x on the curve). - * - * We use it to calculate the timeout and also to generate synthetic - * values of time for circuits that timeout before completion. - * - * See http://en.wikipedia.org/wiki/Quantile_function, - * http://en.wikipedia.org/wiki/Inverse_transform_sampling and - * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_ - * random_sample_from_Pareto_distribution - * That's right. I'll cite wikipedia all day long. - * - * Return value is in milliseconds. - */ -double -circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, - double quantile) -{ - double ret; - tor_assert(quantile >= 0); - tor_assert(1.0-quantile > 0); - tor_assert(cbt->Xm > 0); - - ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha); - if (ret > INT32_MAX) { - ret = INT32_MAX; - } - tor_assert(ret > 0); - return ret; -} - -/** Pareto CDF */ -double -circuit_build_times_cdf(circuit_build_times_t *cbt, double x) -{ - double ret; - tor_assert(cbt->Xm > 0); - ret = 1.0-pow(cbt->Xm/x,cbt->alpha); - tor_assert(0 <= ret && ret <= 1.0); - return ret; -} - -/** - * Generate a synthetic time using our distribution parameters. - * - * The return value will be within the [q_lo, q_hi) quantile points - * on the CDF. - */ -build_time_t -circuit_build_times_generate_sample(circuit_build_times_t *cbt, - double q_lo, double q_hi) -{ - double randval = crypto_rand_double(); - build_time_t ret; - double u; - - /* Generate between [q_lo, q_hi) */ - /*XXXX This is what nextafter is supposed to be for; we should use it on the - * platforms that support it. */ - q_hi -= 1.0/(INT32_MAX); - - tor_assert(q_lo >= 0); - tor_assert(q_hi < 1); - tor_assert(q_lo < q_hi); - - u = q_lo + (q_hi-q_lo)*randval; - - tor_assert(0 <= u && u < 1.0); - /* circuit_build_times_calculate_timeout returns <= INT32_MAX */ - ret = (build_time_t) - tor_lround(circuit_build_times_calculate_timeout(cbt, u)); - tor_assert(ret > 0); - return ret; -} - -/** - * Estimate an initial alpha parameter by solving the quantile - * function with a quantile point and a specific timeout value. - */ -void -circuit_build_times_initial_alpha(circuit_build_times_t *cbt, - double quantile, double timeout_ms) -{ - // Q(u) = Xm/((1-u)^(1/a)) - // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout - // CircBuildTimeout = Xm/((1-0.8))^(1/a)) - // CircBuildTimeout = Xm*((1-0.8))^(-1/a)) - // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a) - // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a - tor_assert(quantile >= 0); - tor_assert(cbt->Xm > 0); - cbt->alpha = tor_mathlog(1.0-quantile)/ - (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms)); - tor_assert(cbt->alpha > 0); -} - -/** - * Returns true if we need circuits to be built - */ -int -circuit_build_times_needs_circuits(circuit_build_times_t *cbt) -{ - /* Return true if < MIN_CIRCUITS_TO_OBSERVE */ - return !circuit_build_times_enough_to_compute(cbt); -} - -/** - * Returns true if we should build a timeout test circuit - * right now. - */ -int -circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt) -{ - return circuit_build_times_needs_circuits(cbt) && - approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); -} - -/** - * Called to indicate that the network showed some signs of liveness, - * i.e. we received a cell. - * - * This is used by circuit_build_times_network_check_live() to decide - * if we should record the circuit build timeout or not. - * - * This function is called every time we receive a cell. Avoid - * syscalls, events, and other high-intensity work. - */ -void -circuit_build_times_network_is_live(circuit_build_times_t *cbt) -{ - time_t now = approx_time(); - if (cbt->liveness.nonlive_timeouts > 0) { - log_notice(LD_CIRC, - "Tor now sees network activity. Restoring circuit build " - "timeout recording. Network was down for %d seconds " - "during %d circuit attempts.", - (int)(now - cbt->liveness.network_last_live), - cbt->liveness.nonlive_timeouts); - } - cbt->liveness.network_last_live = now; - cbt->liveness.nonlive_timeouts = 0; -} - -/** - * Called to indicate that we completed a circuit. Because this circuit - * succeeded, it doesn't count as a timeout-after-the-first-hop. - * - * This is used by circuit_build_times_network_check_changed() to determine - * if we had too many recent timeouts and need to reset our learned timeout - * to something higher. - */ -void -circuit_build_times_network_circ_success(circuit_build_times_t *cbt) -{ - /* Check for NULLness because we might not be using adaptive timeouts */ - if (cbt->liveness.timeouts_after_firsthop && - cbt->liveness.num_recent_circs > 0) { - cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] - = 0; - cbt->liveness.after_firsthop_idx++; - cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; - } -} - -/** - * A circuit just timed out. If it failed after the first hop, record it - * in our history for later deciding if the network speed has changed. - * - * This is used by circuit_build_times_network_check_changed() to determine - * if we had too many recent timeouts and need to reset our learned timeout - * to something higher. - */ -static void -circuit_build_times_network_timeout(circuit_build_times_t *cbt, - int did_onehop) -{ - /* Check for NULLness because we might not be using adaptive timeouts */ - if (cbt->liveness.timeouts_after_firsthop && - cbt->liveness.num_recent_circs > 0) { - if (did_onehop) { - cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] - = 1; - cbt->liveness.after_firsthop_idx++; - cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; - } - } -} - -/** - * A circuit was just forcibly closed. If there has been no recent network - * activity at all, but this circuit was launched back when we thought the - * network was live, increment the number of "nonlive" circuit timeouts. - * - * This is used by circuit_build_times_network_check_live() to decide - * if we should record the circuit build timeout or not. - */ -static void -circuit_build_times_network_close(circuit_build_times_t *cbt, - int did_onehop, time_t start_time) -{ - time_t now = time(NULL); - /* - * Check if this is a timeout that was for a circuit that spent its - * entire existence during a time where we have had no network activity. - */ - if (cbt->liveness.network_last_live < start_time) { - if (did_onehop) { - char last_live_buf[ISO_TIME_LEN+1]; - char start_time_buf[ISO_TIME_LEN+1]; - char now_buf[ISO_TIME_LEN+1]; - format_local_iso_time(last_live_buf, cbt->liveness.network_last_live); - format_local_iso_time(start_time_buf, start_time); - format_local_iso_time(now_buf, now); - log_warn(LD_BUG, - "Circuit somehow completed a hop while the network was " - "not live. Network was last live at %s, but circuit launched " - "at %s. It's now %s.", last_live_buf, start_time_buf, - now_buf); - } - cbt->liveness.nonlive_timeouts++; - if (cbt->liveness.nonlive_timeouts == 1) { - log_notice(LD_CIRC, - "Tor has not observed any network activity for the past %d " - "seconds. Disabling circuit build timeout recording.", - (int)(now - cbt->liveness.network_last_live)); - } else { - log_info(LD_CIRC, - "Got non-live timeout. Current count is: %d", - cbt->liveness.nonlive_timeouts); - } - } -} - -/** - * When the network is not live, we do not record circuit build times. - * - * The network is considered not live if there has been at least one - * circuit build that began and ended (had its close_ms measurement - * period expire) since we last received a cell. - * - * Also has the side effect of rewinding the circuit time history - * in the case of recent liveness changes. - */ -int -circuit_build_times_network_check_live(circuit_build_times_t *cbt) -{ - if (cbt->liveness.nonlive_timeouts > 0) { - return 0; - } - - return 1; -} - -/** - * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of - * the past RECENT_CIRCUITS time out after the first hop. Used to detect - * if the network connection has changed significantly, and if so, - * resets our circuit build timeout to the default. - * - * Also resets the entire timeout history in this case and causes us - * to restart the process of building test circuits and estimating a - * new timeout. - */ -int -circuit_build_times_network_check_changed(circuit_build_times_t *cbt) -{ - int total_build_times = cbt->total_build_times; - int timeout_count=0; - int i; - - if (cbt->liveness.timeouts_after_firsthop && - cbt->liveness.num_recent_circs > 0) { - /* how many of our recent circuits made it to the first hop but then - * timed out? */ - for (i = 0; i < cbt->liveness.num_recent_circs; i++) { - timeout_count += cbt->liveness.timeouts_after_firsthop[i]; - } - } - - /* If 80% of our recent circuits are timing out after the first hop, - * we need to re-estimate a new initial alpha and timeout. */ - if (timeout_count < circuit_build_times_max_timeouts()) { - return 0; - } - - circuit_build_times_reset(cbt); - if (cbt->liveness.timeouts_after_firsthop && - cbt->liveness.num_recent_circs > 0) { - memset(cbt->liveness.timeouts_after_firsthop, 0, - sizeof(*cbt->liveness.timeouts_after_firsthop)* - cbt->liveness.num_recent_circs); - } - cbt->liveness.after_firsthop_idx = 0; - - /* Check to see if this has happened before. If so, double the timeout - * to give people on abysmally bad network connections a shot at access */ - if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) { - if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) { - log_warn(LD_CIRC, "Insanely large circuit build timeout value. " - "(timeout = %fmsec, close = %fmsec)", - cbt->timeout_ms, cbt->close_ms); - } else { - cbt->timeout_ms *= 2; - cbt->close_ms *= 2; - } - } else { - cbt->close_ms = cbt->timeout_ms - = circuit_build_times_get_initial_timeout(); - } - - control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); - - log_notice(LD_CIRC, - "Your network connection speed appears to have changed. Resetting " - "timeout to %lds after %d timeouts and %d buildtimes.", - tor_lround(cbt->timeout_ms/1000), timeout_count, - total_build_times); - - return 1; -} - -/** - * Count the number of timeouts in a set of cbt data. - */ -double -circuit_build_times_timeout_rate(const circuit_build_times_t *cbt) -{ - int i=0,timeouts=0; - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] >= cbt->timeout_ms) { - timeouts++; - } - } - - if (!cbt->total_build_times) - return 0; - - return ((double)timeouts)/cbt->total_build_times; -} - -/** - * Count the number of closed circuits in a set of cbt data. - */ -double -circuit_build_times_close_rate(const circuit_build_times_t *cbt) -{ - int i=0,closed=0; - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) { - closed++; - } - } - - if (!cbt->total_build_times) - return 0; - - return ((double)closed)/cbt->total_build_times; -} - -/** - * Store a timeout as a synthetic value. - * - * Returns true if the store was successful and we should possibly - * update our timeout estimate. - */ -int -circuit_build_times_count_close(circuit_build_times_t *cbt, - int did_onehop, - time_t start_time) -{ - if (circuit_build_times_disabled()) { - cbt->close_ms = cbt->timeout_ms - = circuit_build_times_get_initial_timeout(); - return 0; - } - - /* Record this force-close to help determine if the network is dead */ - circuit_build_times_network_close(cbt, did_onehop, start_time); - - /* Only count timeouts if network is live.. */ - if (!circuit_build_times_network_check_live(cbt)) { - return 0; - } - - circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED); - return 1; -} - -/** - * Update timeout counts to determine if we need to expire - * our build time history due to excessive timeouts. - * - * We do not record any actual time values at this stage; - * we are only interested in recording the fact that a timeout - * happened. We record the time values via - * circuit_build_times_count_close() and circuit_build_times_add_time(). - */ -void -circuit_build_times_count_timeout(circuit_build_times_t *cbt, - int did_onehop) -{ - if (circuit_build_times_disabled()) { - cbt->close_ms = cbt->timeout_ms - = circuit_build_times_get_initial_timeout(); - return; - } - - /* Register the fact that a timeout just occurred. */ - circuit_build_times_network_timeout(cbt, did_onehop); - - /* If there are a ton of timeouts, we should reset - * the circuit build timeout. */ - circuit_build_times_network_check_changed(cbt); -} - -/** - * Estimate a new timeout based on history and set our timeout - * variable accordingly. - */ -static int -circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt) -{ - build_time_t max_time; - if (!circuit_build_times_enough_to_compute(cbt)) - return 0; - - if (!circuit_build_times_update_alpha(cbt)) - return 0; - - cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt, - circuit_build_times_quantile_cutoff()); - - cbt->close_ms = circuit_build_times_calculate_timeout(cbt, - circuit_build_times_close_quantile()); - - max_time = circuit_build_times_max(cbt); - - /* Sometimes really fast guard nodes give us such a steep curve - * that this ends up being not that much greater than timeout_ms. - * Make it be at least 1 min to handle this case. */ - cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout()); - - if (cbt->timeout_ms > max_time) { - log_info(LD_CIRC, - "Circuit build timeout of %dms is beyond the maximum build " - "time we have ever observed. Capping it to %dms.", - (int)cbt->timeout_ms, max_time); - cbt->timeout_ms = max_time; - } - - if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) { - log_info(LD_CIRC, - "Circuit build measurement period of %dms is more than twice " - "the maximum build time we have ever observed. Capping it to " - "%dms.", (int)cbt->close_ms, 2*max_time); - cbt->close_ms = 2*max_time; - } - - cbt->have_computed_timeout = 1; - return 1; -} - -/** - * Exposed function to compute a new timeout. Dispatches events and - * also filters out extremely high timeout values. - */ -void -circuit_build_times_set_timeout(circuit_build_times_t *cbt) -{ - long prev_timeout = tor_lround(cbt->timeout_ms/1000); - double timeout_rate; - - /* - * Just return if we aren't using adaptive timeouts - */ - if (circuit_build_times_disabled()) - return; - - if (!circuit_build_times_set_timeout_worker(cbt)) - return; - - if (cbt->timeout_ms < circuit_build_times_min_timeout()) { - log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms", - cbt->timeout_ms, circuit_build_times_min_timeout()); - cbt->timeout_ms = circuit_build_times_min_timeout(); - if (cbt->close_ms < cbt->timeout_ms) { - /* This shouldn't happen because of MAX() in timeout_worker above, - * but doing it just in case */ - cbt->close_ms = circuit_build_times_initial_timeout(); - } - } - - control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED); - - timeout_rate = circuit_build_times_timeout_rate(cbt); - - if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) { - log_info(LD_CIRC, - "Based on %d circuit times, it looks like we don't need to " - "wait so long for circuits to finish. We will now assume a " - "circuit is too slow to use after waiting %ld seconds.", - cbt->total_build_times, - tor_lround(cbt->timeout_ms/1000)); - log_info(LD_CIRC, - "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", - cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, - timeout_rate); - } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) { - log_info(LD_CIRC, - "Based on %d circuit times, it looks like we need to wait " - "longer for circuits to finish. We will now assume a " - "circuit is too slow to use after waiting %ld seconds.", - cbt->total_build_times, - tor_lround(cbt->timeout_ms/1000)); - log_info(LD_CIRC, - "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", - cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, - timeout_rate); - } else { - log_info(LD_CIRC, - "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f," - " r: %f) based on %d circuit times", - tor_lround(cbt->timeout_ms/1000), - cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate, - cbt->total_build_times); - } -} - /** Iterate over values of circ_id, starting from conn-\>next_circ_id, * and with the high bit specified by conn-\>circ_id_type, until we get * a circ_id that is not in use by any other circuit on that conn. @@ -1763,8 +144,8 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names) circ->build_state->is_internal ? "internal" : "exit", circ->build_state->need_uptime ? " (high-uptime)" : "", circ->build_state->desired_path_len, - circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ", - circ->_base.state == CIRCUIT_STATE_OPEN ? "" : + circ->base_.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ", + circ->base_.state == CIRCUIT_STATE_OPEN ? "" : (nickname?nickname:"*unnamed*")); } @@ -1927,7 +308,7 @@ origin_circuit_init(uint8_t purpose, int flags) ((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0); circ->build_state->is_internal = ((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0); - circ->_base.purpose = purpose; + circ->base_.purpose = purpose; return circ; } @@ -1993,7 +374,7 @@ circuit_handle_first_hop(origin_circuit_t *circ) log_info(LD_CIRC, "Next router is %s: %s", safe_str_client(extend_info_describe(firsthop->extend_info)), msg?msg:"???"); - circ->_base.n_hop = extend_info_dup(firsthop->extend_info); + circ->base_.n_hop = extend_info_dup(firsthop->extend_info); if (should_launch) { if (circ->build_state->onehop_tunnel) @@ -2015,8 +396,8 @@ circuit_handle_first_hop(origin_circuit_t *circ) */ return 0; } else { /* it's already open. use it. */ - tor_assert(!circ->_base.n_hop); - circ->_base.n_chan = n_chan; + tor_assert(!circ->base_.n_hop); + circ->base_.n_chan = n_chan; log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { log_info(LD_CIRC,"circuit_send_next_onion_skin failed."); @@ -2244,7 +625,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) else control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0); - node = node_get_by_id(circ->_base.n_chan->identity_digest); + node = node_get_by_id(circ->base_.n_chan->identity_digest); fast = should_use_create_fast_for_circuit(circ); if (!fast) { /* We are an OR and we know the right onion key: we should @@ -2281,7 +662,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) node ? node_describe(node) : "<unnamed>"); } else { tor_assert(circ->cpath->state == CPATH_STATE_OPEN); - tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING); + tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING); log_debug(LD_CIRC,"starting to send subsequent skin."); hop = onion_next_hop_in_cpath(circ->cpath); if (!hop) { @@ -2291,7 +672,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) struct timeval end; long timediff; tor_gettimeofday(&end); - timediff = tv_mdiff(&circ->_base.timestamp_created, &end); + timediff = tv_mdiff(&circ->base_.timestamp_created, &end); /* * If the circuit build time is much greater than we would have cut @@ -2301,8 +682,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) if (timediff < 0 || timediff > 2*circ_times.close_ms+1000) { log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. " "Assuming clock jump. Purpose %d (%s)", timediff, - circ->_base.purpose, - circuit_purpose_to_string(circ->_base.purpose)); + circ->base_.purpose, + circuit_purpose_to_string(circ->base_.purpose)); } else if (!circuit_build_times_disabled()) { /* Only count circuit times if the network is live */ if (circuit_build_times_network_check_live(&circ_times)) { @@ -2310,7 +691,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) circuit_build_times_set_timeout(&circ_times); } - if (circ->_base.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { circuit_build_times_network_circ_success(&circ_times); } } @@ -2343,7 +724,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) circuit_has_opened(circ); /* do other actions as necessary */ /* We're done with measurement circuits here. Just close them */ - if (circ->_base.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) + if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); return 0; } @@ -2612,7 +993,8 @@ pathbias_get_notice_rate(const or_options_t *options) DFLT_PATH_BIAS_NOTICE_PCT, 0, 100)/100.0; } -static double +/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ +double pathbias_get_disable_rate(const or_options_t *options) { // XXX: This needs tuning based on use + experimentation before we set it @@ -2679,8 +1061,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) /* We can't do path bias accounting without entry guards. * Testing and controller circuits also have no guards. */ if (get_options()->UseEntryGuards == 0 || - circ->_base.purpose == CIRCUIT_PURPOSE_TESTING || - circ->_base.purpose == CIRCUIT_PURPOSE_CONTROLLER) { + circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || + circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) { return 0; } @@ -2697,8 +1079,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) "Circuit is a %s currently %s.%s", circ->build_state->desired_path_len, pathbias_state_to_string(circ->path_state), - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2716,8 +1098,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) "Opened circuit is in strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2728,7 +1110,7 @@ pathbias_count_first_hop(origin_circuit_t *circ) entry_guard_t *guard; guard = - entry_guard_get_by_id_digest(circ->_base.n_chan->identity_digest); + entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest); if (guard) { if (circ->path_state == PATH_STATE_NEW_CIRC) { circ->path_state = PATH_STATE_DID_FIRST_HOP; @@ -2744,8 +1126,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) "Unopened circuit has strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2756,8 +1138,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) log_info(LD_BUG, "Unopened circuit has no known guard. " "Circuit is a %s currently %s.%s", - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2773,8 +1155,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), circ->cpath->state, circ->has_opened, - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2803,8 +1185,8 @@ pathbias_count_success(origin_circuit_t *circ) /* We can't do path bias accounting without entry guards. * Testing and controller circuits also have no guards. */ if (get_options()->UseEntryGuards == 0 || - circ->_base.purpose == CIRCUIT_PURPOSE_TESTING || - circ->_base.purpose == CIRCUIT_PURPOSE_CONTROLLER) { + circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || + circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) { return; } @@ -2821,8 +1203,8 @@ pathbias_count_success(origin_circuit_t *circ) "Circuit is a %s currently %s.%s", circ->build_state->desired_path_len, pathbias_state_to_string(circ->path_state), - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2834,7 +1216,7 @@ pathbias_count_success(origin_circuit_t *circ) /* Don't count cannibalized/reused circs for path bias */ if (!circ->has_opened) { guard = - entry_guard_get_by_id_digest(circ->_base.n_chan->identity_digest); + entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest); if (guard) { if (circ->path_state == PATH_STATE_DID_FIRST_HOP) { @@ -2851,8 +1233,8 @@ pathbias_count_success(origin_circuit_t *circ) "Succeeded circuit is in strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2867,14 +1249,14 @@ pathbias_count_success(origin_circuit_t *circ) /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. * No need to log that case. */ - } else if (circ->_base.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { if ((rate_msg = rate_limit_log(&success_notice_limit, approx_time()))) { log_info(LD_BUG, "Completed circuit has no known guard. " "Circuit is a %s currently %s.%s", - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -2887,8 +1269,8 @@ pathbias_count_success(origin_circuit_t *circ) "Opened circuit is in strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), - circuit_purpose_to_string(circ->_base.purpose), - circuit_state_to_string(circ->_base.state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } @@ -3050,7 +1432,7 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason) * just give up. */ circuit_mark_for_close(TO_CIRCUIT(circ), - END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_CHANNEL_CLOSED|reason); + END_CIRC_REASON_FLAG_REMOTE|reason); return 0; #if 0 @@ -3331,7 +1713,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) n_supported[i] = -1; continue; } - if (routerset_contains_node(options->_ExcludeExitNodesUnion, node)) { + if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) { n_supported[i] = -1; continue; /* user asked us not to use it, no matter what */ } @@ -3348,7 +1730,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) * we'll retry later in this function with need_update and * need_capacity set to 0. */ } - if (!(node->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) { + if (!(node->is_valid || options->AllowInvalid_ & ALLOW_INVALID_EXIT)) { /* if it's invalid and we don't want it */ n_supported[i] = -1; // log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.", @@ -3434,7 +1816,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) } log_notice(LD_CIRC, "All routers are down or won't exit%s -- " "choosing a doomed exit at random.", - options->_ExcludeExitNodesUnion ? " or are Excluded" : ""); + options->ExcludeExitNodesUnion_ ? " or are Excluded" : ""); } supporting = smartlist_new(); needed_ports = circuit_get_unhandled_ports(time(NULL)); @@ -3473,7 +1855,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) log_warn(LD_CIRC, "No specified %sexit routers seem to be running: " "can't choose an exit.", - options->_ExcludeExitNodesUnion ? "non-excluded " : ""); + options->ExcludeExitNodesUnion_ ? "non-excluded " : ""); } return NULL; } @@ -3501,14 +1883,14 @@ choose_good_exit_server(uint8_t purpose, switch (purpose) { case CIRCUIT_PURPOSE_C_GENERAL: - if (options->_AllowInvalid & ALLOW_INVALID_MIDDLE) + if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE) flags |= CRN_ALLOW_INVALID; if (is_internal) /* pick it like a middle hop */ return router_choose_random_node(NULL, options->ExcludeNodes, flags); else return choose_good_exit_server_general(need_uptime,need_capacity); case CIRCUIT_PURPOSE_C_ESTABLISH_REND: - if (options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS) + if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS) flags |= CRN_ALLOW_INVALID; return router_choose_random_node(NULL, options->ExcludeNodes, flags); } @@ -3525,7 +1907,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) const or_options_t *options = get_options(); routerset_t *rs = options->ExcludeNodes; const char *description; - uint8_t purpose = circ->_base.purpose; + uint8_t purpose = circ->base_.purpose; if (circ->build_state->onehop_tunnel) return; @@ -3545,7 +1927,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) if (circ->build_state->is_internal) return; description = "requested exit node"; - rs = options->_ExcludeExitNodesUnion; + rs = options->ExcludeExitNodesUnion_; break; case CIRCUIT_PURPOSE_C_INTRODUCING: case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: @@ -3562,7 +1944,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) description = "chosen rendezvous point"; break; case CIRCUIT_PURPOSE_CONTROLLER: - rs = options->_ExcludeExitNodesUnion; + rs = options->ExcludeExitNodesUnion_; description = "controller-selected circuit target"; break; } @@ -3604,7 +1986,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel."); state->desired_path_len = 1; } else { - int r = new_route_len(circ->_base.purpose, exit, nodelist_get_list()); + int r = new_route_len(circ->base_.purpose, exit, nodelist_get_list()); if (r < 1) /* must be at least 1 */ return -1; state->desired_path_len = r; @@ -3617,7 +1999,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) exit = extend_info_dup(exit); } else { /* we have to decide one */ const node_t *node = - choose_good_exit_server(circ->_base.purpose, state->need_uptime, + choose_good_exit_server(circ->base_.purpose, state->need_uptime, state->need_capacity, state->is_internal); if (!node) { log_warn(LD_CIRC,"failed to choose an exit server"); @@ -3738,8 +2120,8 @@ choose_good_middle_server(uint8_t purpose, smartlist_t *excluded; const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_DESC; - tor_assert(_CIRCUIT_PURPOSE_MIN <= purpose && - purpose <= _CIRCUIT_PURPOSE_MAX); + tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose && + purpose <= CIRCUIT_PURPOSE_MAX_); log_debug(LD_CIRC, "Contemplating intermediate hop: random choice."); excluded = smartlist_new(); @@ -3756,7 +2138,7 @@ choose_good_middle_server(uint8_t purpose, flags |= CRN_NEED_UPTIME; if (state->need_capacity) flags |= CRN_NEED_CAPACITY; - if (options->_AllowInvalid & ALLOW_INVALID_MIDDLE) + if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE) flags |= CRN_ALLOW_INVALID; choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); smartlist_free(excluded); @@ -3771,7 +2153,8 @@ choose_good_middle_server(uint8_t purpose, * If <b>state</b> is NULL, we're choosing a router to serve as an entry * guard, not for any particular circuit. */ -static const node_t * +/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ +const node_t * choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) { const node_t *choice; @@ -3803,8 +2186,8 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) }); } /* and exclude current entry guards and their families, if applicable */ - if (options->UseEntryGuards && entry_guards) { - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + if (options->UseEntryGuards) { + SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry, { if ((node = node_get_by_id(entry->identity))) { nodelist_add_node_and_family(excluded, node); @@ -3818,7 +2201,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) if (state->need_capacity) flags |= CRN_NEED_CAPACITY; } - if (options->_AllowInvalid & ALLOW_INVALID_ENTRY) + if (options->AllowInvalid_ & ALLOW_INVALID_ENTRY) flags |= CRN_ALLOW_INVALID; choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); @@ -3846,7 +2229,7 @@ onion_next_hop_in_cpath(crypt_path_t *cpath) static int onion_extend_cpath(origin_circuit_t *circ) { - uint8_t purpose = circ->_base.purpose; + uint8_t purpose = circ->base_.purpose; cpath_build_state_t *state = circ->build_state; int cur_len = circuit_get_cpath_len(circ); extend_info_t *info = NULL; @@ -4025,1878 +2408,3 @@ build_state_get_exit_nickname(cpath_build_state_t *state) return state->chosen_exit->nickname; } -/** Check whether the entry guard <b>e</b> is usable, given the directory - * authorities' opinion about the router (stored in <b>ri</b>) and the user's - * configuration (in <b>options</b>). Set <b>e</b>->bad_since - * accordingly. Return true iff the entry guard's status changes. - * - * If it's not usable, set *<b>reason</b> to a static string explaining why. - */ -static int -entry_guard_set_status(entry_guard_t *e, const node_t *node, - time_t now, const or_options_t *options, - const char **reason) -{ - char buf[HEX_DIGEST_LEN+1]; - int changed = 0; - - *reason = NULL; - - /* Do we want to mark this guard as bad? */ - if (!node) - *reason = "unlisted"; - else if (!node->is_running) - *reason = "down"; - else if (options->UseBridges && (!node->ri || - node->ri->purpose != ROUTER_PURPOSE_BRIDGE)) - *reason = "not a bridge"; - else if (options->UseBridges && !node_is_a_configured_bridge(node)) - *reason = "not a configured bridge"; - else if (!options->UseBridges && !node->is_possible_guard && - !routerset_contains_node(options->EntryNodes,node)) - *reason = "not recommended as a guard"; - else if (routerset_contains_node(options->ExcludeNodes, node)) - *reason = "excluded"; - else if (e->path_bias_disabled) - *reason = "path-biased"; - - if (*reason && ! e->bad_since) { - /* Router is newly bad. */ - base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN); - log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.", - e->nickname, buf, *reason); - - e->bad_since = now; - control_event_guard(e->nickname, e->identity, "BAD"); - changed = 1; - } else if (!*reason && e->bad_since) { - /* There's nothing wrong with the router any more. */ - base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN); - log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: " - "marking as ok.", e->nickname, buf); - - e->bad_since = 0; - control_event_guard(e->nickname, e->identity, "GOOD"); - changed = 1; - } - return changed; -} - -/** Return true iff enough time has passed since we last tried to connect - * to the unreachable guard <b>e</b> that we're willing to try again. */ -static int -entry_is_time_to_retry(entry_guard_t *e, time_t now) -{ - long diff; - if (e->last_attempted < e->unreachable_since) - return 1; - diff = now - e->unreachable_since; - if (diff < 6*60*60) - return now > (e->last_attempted + 60*60); - else if (diff < 3*24*60*60) - return now > (e->last_attempted + 4*60*60); - else if (diff < 7*24*60*60) - return now > (e->last_attempted + 18*60*60); - else - return now > (e->last_attempted + 36*60*60); -} - -/** Return the node corresponding to <b>e</b>, if <b>e</b> is - * working well enough that we are willing to use it as an entry - * right now. (Else return NULL.) In particular, it must be - * - Listed as either up or never yet contacted; - * - Present in the routerlist; - * - Listed as 'stable' or 'fast' by the current dirserver consensus, - * if demanded by <b>need_uptime</b> or <b>need_capacity</b> - * (unless it's a configured EntryNode); - * - Allowed by our current ReachableORAddresses config option; and - * - Currently thought to be reachable by us (unless <b>assume_reachable</b> - * is true). - * - * If the answer is no, set *<b>msg</b> to an explanation of why. - */ -static INLINE const node_t * -entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, - int assume_reachable, const char **msg) -{ - const node_t *node; - const or_options_t *options = get_options(); - tor_assert(msg); - - if (e->path_bias_disabled) { - *msg = "path-biased"; - return NULL; - } - if (e->bad_since) { - *msg = "bad"; - return NULL; - } - /* no good if it's unreachable, unless assume_unreachable or can_retry. */ - if (!assume_reachable && !e->can_retry && - e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) { - *msg = "unreachable"; - return NULL; - } - node = node_get_by_id(e->identity); - if (!node || !node_has_descriptor(node)) { - *msg = "no descriptor"; - return NULL; - } - if (get_options()->UseBridges) { - if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) { - *msg = "not a bridge"; - return NULL; - } - if (!node_is_a_configured_bridge(node)) { - *msg = "not a configured bridge"; - return NULL; - } - } else { /* !get_options()->UseBridges */ - if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) { - *msg = "not general-purpose"; - return NULL; - } - } - if (routerset_contains_node(options->EntryNodes, node)) { - /* they asked for it, they get it */ - need_uptime = need_capacity = 0; - } - if (node_is_unreliable(node, need_uptime, need_capacity, 0)) { - *msg = "not fast/stable"; - return NULL; - } - if (!fascist_firewall_allows_node(node)) { - *msg = "unreachable by config"; - return NULL; - } - return node; -} - -/** Return the number of entry guards that we think are usable. */ -static int -num_live_entry_guards(void) -{ - int n = 0; - const char *msg; - if (! entry_guards) - return 0; - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, - { - if (entry_is_live(entry, 0, 1, 0, &msg)) - ++n; - }); - return n; -} - -/** If <b>digest</b> matches the identity of any node in the - * entry_guards list, return that node. Else return NULL. */ -static entry_guard_t * -entry_guard_get_by_id_digest(const char *digest) -{ - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, - if (tor_memeq(digest, entry->identity, DIGEST_LEN)) - return entry; - ); - return NULL; -} - -/** Dump a description of our list of entry guards to the log at level - * <b>severity</b>. */ -static void -log_entry_guards(int severity) -{ - smartlist_t *elements = smartlist_new(); - char *s; - - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) - { - const char *msg = NULL; - if (entry_is_live(e, 0, 1, 0, &msg)) - smartlist_add_asprintf(elements, "%s [%s] (up %s)", - e->nickname, - hex_str(e->identity, DIGEST_LEN), - e->made_contact ? "made-contact" : "never-contacted"); - else - smartlist_add_asprintf(elements, "%s [%s] (%s, %s)", - e->nickname, - hex_str(e->identity, DIGEST_LEN), - msg, - e->made_contact ? "made-contact" : "never-contacted"); - } - SMARTLIST_FOREACH_END(e); - - s = smartlist_join_strings(elements, ",", 0, NULL); - SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); - smartlist_free(elements); - log_fn(severity,LD_CIRC,"%s",s); - tor_free(s); -} - -/** Called when one or more guards that we would previously have used for some - * purpose are no longer in use because a higher-priority guard has become - * usable again. */ -static void -control_event_guard_deferred(void) -{ - /* XXXX We don't actually have a good way to figure out _how many_ entries - * are live for some purpose. We need an entry_is_even_slightly_live() - * function for this to work right. NumEntryGuards isn't reliable: if we - * need guards with weird properties, we can have more than that number - * live. - **/ -#if 0 - int n = 0; - const char *msg; - const or_options_t *options = get_options(); - if (!entry_guards) - return; - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, - { - if (entry_is_live(entry, 0, 1, 0, &msg)) { - if (n++ == options->NumEntryGuards) { - control_event_guard(entry->nickname, entry->identity, "DEFERRED"); - return; - } - } - }); -#endif -} - -/** Add a new (preferably stable and fast) router to our - * entry_guards list. Return a pointer to the router if we succeed, - * or NULL if we can't find any more suitable entries. - * - * If <b>chosen</b> is defined, use that one, and if it's not - * already in our entry_guards list, put it at the *beginning*. - * Else, put the one we pick at the end of the list. */ -static const node_t * -add_an_entry_guard(const node_t *chosen, int reset_status, int prepend) -{ - const node_t *node; - entry_guard_t *entry; - - if (chosen) { - node = chosen; - entry = entry_guard_get_by_id_digest(node->identity); - if (entry) { - if (reset_status) { - entry->bad_since = 0; - entry->can_retry = 1; - } - return NULL; - } - } else { - node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL); - if (!node) - return NULL; - } - entry = tor_malloc_zero(sizeof(entry_guard_t)); - log_info(LD_CIRC, "Chose %s as new entry guard.", - node_describe(node)); - strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname)); - memcpy(entry->identity, node->identity, DIGEST_LEN); - /* Choose expiry time smudged over the past month. The goal here - * is to a) spread out when Tor clients rotate their guards, so they - * don't all select them on the same day, and b) avoid leaving a - * precise timestamp in the state file about when we first picked - * this guard. For details, see the Jan 2010 or-dev thread. */ - entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); - entry->chosen_by_version = tor_strdup(VERSION); - if (prepend) - smartlist_insert(entry_guards, 0, entry); - else - smartlist_add(entry_guards, entry); - control_event_guard(entry->nickname, entry->identity, "NEW"); - control_event_guard_deferred(); - log_entry_guards(LOG_INFO); - return node; -} - -/** If the use of entry guards is configured, choose more entry guards - * until we have enough in the list. */ -static void -pick_entry_guards(const or_options_t *options) -{ - int changed = 0; - - tor_assert(entry_guards); - - while (num_live_entry_guards() < options->NumEntryGuards) { - if (!add_an_entry_guard(NULL, 0, 0)) - break; - changed = 1; - } - if (changed) - entry_guards_changed(); -} - -/** How long (in seconds) do we allow an entry guard to be nonfunctional, - * unlisted, excluded, or otherwise nonusable before we give up on it? */ -#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60) - -/** Release all storage held by <b>e</b>. */ -static void -entry_guard_free(entry_guard_t *e) -{ - if (!e) - return; - tor_free(e->chosen_by_version); - tor_free(e); -} - -/** Remove any entry guard which was selected by an unknown version of Tor, - * or which was selected by a version of Tor that's known to select - * entry guards badly, or which was selected more 2 months ago. */ -/* XXXX The "obsolete guards" and "chosen long ago guards" things should - * probably be different functions. */ -static int -remove_obsolete_entry_guards(time_t now) -{ - int changed = 0, i; - - for (i = 0; i < smartlist_len(entry_guards); ++i) { - entry_guard_t *entry = smartlist_get(entry_guards, i); - const char *ver = entry->chosen_by_version; - const char *msg = NULL; - tor_version_t v; - int version_is_bad = 0, date_is_bad = 0; - if (!ver) { - msg = "does not say what version of Tor it was selected by"; - version_is_bad = 1; - } else if (tor_version_parse(ver, &v)) { - msg = "does not seem to be from any recognized version of Tor"; - version_is_bad = 1; - } else { - char *tor_ver = NULL; - tor_asprintf(&tor_ver, "Tor %s", ver); - if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") && - !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) || - (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") && - !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) || - /* above are bug 440; below are bug 1217 */ - (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") && - !tor_version_as_new_as(tor_ver, "0.2.1.23")) || - (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") && - !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) { - msg = "was selected without regard for guard bandwidth"; - version_is_bad = 1; - } - tor_free(tor_ver); - } - if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) { - /* It's been 2 months since the date listed in our state file. */ - msg = "was selected several months ago"; - date_is_bad = 1; - } - - if (version_is_bad || date_is_bad) { /* we need to drop it */ - char dbuf[HEX_DIGEST_LEN+1]; - tor_assert(msg); - base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); - log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC, - "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.", - entry->nickname, dbuf, msg, ver?escaped(ver):"none"); - control_event_guard(entry->nickname, entry->identity, "DROPPED"); - entry_guard_free(entry); - smartlist_del_keeporder(entry_guards, i--); - log_entry_guards(LOG_INFO); - changed = 1; - } - } - - return changed ? 1 : 0; -} - -/** Remove all entry guards that have been down or unlisted for so - * long that we don't think they'll come up again. Return 1 if we - * removed any, or 0 if we did nothing. */ -static int -remove_dead_entry_guards(time_t now) -{ - char dbuf[HEX_DIGEST_LEN+1]; - char tbuf[ISO_TIME_LEN+1]; - int i; - int changed = 0; - - for (i = 0; i < smartlist_len(entry_guards); ) { - entry_guard_t *entry = smartlist_get(entry_guards, i); - if (entry->bad_since && - ! entry->path_bias_disabled && - entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) { - - base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); - format_local_iso_time(tbuf, entry->bad_since); - log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted " - "since %s local time; removing.", - entry->nickname, dbuf, tbuf); - control_event_guard(entry->nickname, entry->identity, "DROPPED"); - entry_guard_free(entry); - smartlist_del_keeporder(entry_guards, i); - log_entry_guards(LOG_INFO); - changed = 1; - } else - ++i; - } - return changed ? 1 : 0; -} - -/** A new directory or router-status has arrived; update the down/listed - * status of the entry guards. - * - * An entry is 'down' if the directory lists it as nonrunning. - * An entry is 'unlisted' if the directory doesn't include it. - * - * Don't call this on startup; only on a fresh download. Otherwise we'll - * think that things are unlisted. - */ -void -entry_guards_compute_status(const or_options_t *options, time_t now) -{ - int changed = 0; - digestmap_t *reasons; - - if (! entry_guards) - return; - - if (options->EntryNodes) /* reshuffle the entry guard list if needed */ - entry_nodes_should_be_added(); - - reasons = digestmap_new(); - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) - { - const node_t *r = node_get_by_id(entry->identity); - const char *reason = NULL; - if (entry_guard_set_status(entry, r, now, options, &reason)) - changed = 1; - - if (entry->bad_since) - tor_assert(reason); - if (reason) - digestmap_set(reasons, entry->identity, (char*)reason); - } - SMARTLIST_FOREACH_END(entry); - - if (remove_dead_entry_guards(now)) - changed = 1; - if (remove_obsolete_entry_guards(now)) - changed = 1; - - if (changed) { - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { - const char *reason = digestmap_get(reasons, entry->identity); - const char *live_msg = ""; - const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg); - log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.", - entry->nickname, - hex_str(entry->identity, DIGEST_LEN), - entry->unreachable_since ? "unreachable" : "reachable", - entry->bad_since ? "unusable" : "usable", - reason ? ", ": "", - reason ? reason : "", - r ? "live" : "not live / ", - r ? "" : live_msg); - } SMARTLIST_FOREACH_END(entry); - log_info(LD_CIRC, " (%d/%d entry guards are usable/new)", - num_live_entry_guards(), smartlist_len(entry_guards)); - log_entry_guards(LOG_INFO); - entry_guards_changed(); - } - - digestmap_free(reasons, NULL); -} - -/** Called when a connection to an OR with the identity digest <b>digest</b> - * is established (<b>succeeded</b>==1) or has failed (<b>succeeded</b>==0). - * If the OR is an entry, change that entry's up/down status. - * Return 0 normally, or -1 if we want to tear down the new connection. - * - * If <b>mark_relay_status</b>, also call router_set_status() on this - * relay. - * - * XXX024 change succeeded and mark_relay_status into 'int flags'. - */ -int -entry_guard_register_connect_status(const char *digest, int succeeded, - int mark_relay_status, time_t now) -{ - int changed = 0; - int refuse_conn = 0; - int first_contact = 0; - entry_guard_t *entry = NULL; - int idx = -1; - char buf[HEX_DIGEST_LEN+1]; - - if (! entry_guards) - return 0; - - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { - tor_assert(e); - if (tor_memeq(e->identity, digest, DIGEST_LEN)) { - entry = e; - idx = e_sl_idx; - break; - } - } SMARTLIST_FOREACH_END(e); - - if (!entry) - return 0; - - base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN); - - if (succeeded) { - if (entry->unreachable_since) { - log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.", - entry->nickname, buf); - entry->can_retry = 0; - entry->unreachable_since = 0; - entry->last_attempted = now; - control_event_guard(entry->nickname, entry->identity, "UP"); - changed = 1; - } - if (!entry->made_contact) { - entry->made_contact = 1; - first_contact = changed = 1; - } - } else { /* ! succeeded */ - if (!entry->made_contact) { - /* We've never connected to this one. */ - log_info(LD_CIRC, - "Connection to never-contacted entry guard '%s' (%s) failed. " - "Removing from the list. %d/%d entry guards usable/new.", - entry->nickname, buf, - num_live_entry_guards()-1, smartlist_len(entry_guards)-1); - control_event_guard(entry->nickname, entry->identity, "DROPPED"); - entry_guard_free(entry); - smartlist_del_keeporder(entry_guards, idx); - log_entry_guards(LOG_INFO); - changed = 1; - } else if (!entry->unreachable_since) { - log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). " - "Marking as unreachable.", entry->nickname, buf); - entry->unreachable_since = entry->last_attempted = now; - control_event_guard(entry->nickname, entry->identity, "DOWN"); - changed = 1; - entry->can_retry = 0; /* We gave it an early chance; no good. */ - } else { - char tbuf[ISO_TIME_LEN+1]; - format_iso_time(tbuf, entry->unreachable_since); - log_debug(LD_CIRC, "Failed to connect to unreachable entry guard " - "'%s' (%s). It has been unreachable since %s.", - entry->nickname, buf, tbuf); - entry->last_attempted = now; - entry->can_retry = 0; /* We gave it an early chance; no good. */ - } - } - - /* if the caller asked us to, also update the is_running flags for this - * relay */ - if (mark_relay_status) - router_set_status(digest, succeeded); - - if (first_contact) { - /* We've just added a new long-term entry guard. Perhaps the network just - * came back? We should give our earlier entries another try too, - * and close this connection so we don't use it before we've given - * the others a shot. */ - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { - if (e == entry) - break; - if (e->made_contact) { - const char *msg; - const node_t *r = entry_is_live(e, 0, 1, 1, &msg); - if (r && e->unreachable_since) { - refuse_conn = 1; - e->can_retry = 1; - } - } - } SMARTLIST_FOREACH_END(e); - if (refuse_conn) { - log_info(LD_CIRC, - "Connected to new entry guard '%s' (%s). Marking earlier " - "entry guards up. %d/%d entry guards usable/new.", - entry->nickname, buf, - num_live_entry_guards(), smartlist_len(entry_guards)); - log_entry_guards(LOG_INFO); - changed = 1; - } - } - - if (changed) - entry_guards_changed(); - return refuse_conn ? -1 : 0; -} - -/** When we try to choose an entry guard, should we parse and add - * config's EntryNodes first? */ -static int should_add_entry_nodes = 0; - -/** Called when the value of EntryNodes changes in our configuration. */ -void -entry_nodes_should_be_added(void) -{ - log_info(LD_CIRC, "EntryNodes config option set. Putting configured " - "relays at the front of the entry guard list."); - should_add_entry_nodes = 1; -} - -/** Adjust the entry guards list so that it only contains entries from - * EntryNodes, adding new entries from EntryNodes to the list as needed. */ -static void -entry_guards_set_from_config(const or_options_t *options) -{ - smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps; - smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list; - tor_assert(entry_guards); - - should_add_entry_nodes = 0; - - if (!options->EntryNodes) { - /* It's possible that a controller set EntryNodes, thus making - * should_add_entry_nodes set, then cleared it again, all before the - * call to choose_random_entry() that triggered us. If so, just return. - */ - return; - } - - { - char *string = routerset_to_string(options->EntryNodes); - log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string); - tor_free(string); - } - - entry_nodes = smartlist_new(); - worse_entry_nodes = smartlist_new(); - entry_fps = smartlist_new(); - old_entry_guards_on_list = smartlist_new(); - old_entry_guards_not_on_list = smartlist_new(); - - /* Split entry guards into those on the list and those not. */ - - routerset_get_all_nodes(entry_nodes, options->EntryNodes, - options->ExcludeNodes, 0); - SMARTLIST_FOREACH(entry_nodes, const node_t *,node, - smartlist_add(entry_fps, (void*)node->identity)); - - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, { - if (smartlist_digest_isin(entry_fps, e->identity)) - smartlist_add(old_entry_guards_on_list, e); - else - smartlist_add(old_entry_guards_not_on_list, e); - }); - - /* Remove all currently configured guard nodes, excluded nodes, unreachable - * nodes, or non-Guard nodes from entry_nodes. */ - SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { - if (entry_guard_get_by_id_digest(node->identity)) { - SMARTLIST_DEL_CURRENT(entry_nodes, node); - continue; - } else if (routerset_contains_node(options->ExcludeNodes, node)) { - SMARTLIST_DEL_CURRENT(entry_nodes, node); - continue; - } else if (!fascist_firewall_allows_node(node)) { - SMARTLIST_DEL_CURRENT(entry_nodes, node); - continue; - } else if (! node->is_possible_guard) { - smartlist_add(worse_entry_nodes, (node_t*)node); - SMARTLIST_DEL_CURRENT(entry_nodes, node); - } - } SMARTLIST_FOREACH_END(node); - - /* Now build the new entry_guards list. */ - smartlist_clear(entry_guards); - /* First, the previously configured guards that are in EntryNodes. */ - smartlist_add_all(entry_guards, old_entry_guards_on_list); - /* Next, scramble the rest of EntryNodes, putting the guards first. */ - smartlist_shuffle(entry_nodes); - smartlist_shuffle(worse_entry_nodes); - smartlist_add_all(entry_nodes, worse_entry_nodes); - - /* Next, the rest of EntryNodes */ - SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { - add_an_entry_guard(node, 0, 0); - if (smartlist_len(entry_guards) > options->NumEntryGuards * 10) - break; - } SMARTLIST_FOREACH_END(node); - log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards)); - /* Finally, free the remaining previously configured guards that are not in - * EntryNodes. */ - SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e, - entry_guard_free(e)); - - smartlist_free(entry_nodes); - smartlist_free(worse_entry_nodes); - smartlist_free(entry_fps); - smartlist_free(old_entry_guards_on_list); - smartlist_free(old_entry_guards_not_on_list); - entry_guards_changed(); -} - -/** Return 0 if we're fine adding arbitrary routers out of the - * directory to our entry guard list, or return 1 if we have a - * list already and we must stick to it. - */ -int -entry_list_is_constrained(const or_options_t *options) -{ - if (options->EntryNodes) - return 1; - if (options->UseBridges) - return 1; - return 0; -} - -/** Pick a live (up and listed) entry guard from entry_guards. If - * <b>state</b> is non-NULL, this is for a specific circuit -- - * make sure not to pick this circuit's exit or any node in the - * exit's family. If <b>state</b> is NULL, we're looking for a random - * guard (likely a bridge). */ -const node_t * -choose_random_entry(cpath_build_state_t *state) -{ - const or_options_t *options = get_options(); - smartlist_t *live_entry_guards = smartlist_new(); - smartlist_t *exit_family = smartlist_new(); - const node_t *chosen_exit = - state?build_state_get_exit_node(state) : NULL; - const node_t *node = NULL; - int need_uptime = state ? state->need_uptime : 0; - int need_capacity = state ? state->need_capacity : 0; - int preferred_min, consider_exit_family = 0; - - if (chosen_exit) { - nodelist_add_node_and_family(exit_family, chosen_exit); - consider_exit_family = 1; - } - - if (!entry_guards) - entry_guards = smartlist_new(); - - if (should_add_entry_nodes) - entry_guards_set_from_config(options); - - if (!entry_list_is_constrained(options) && - smartlist_len(entry_guards) < options->NumEntryGuards) - pick_entry_guards(options); - - retry: - smartlist_clear(live_entry_guards); - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { - const char *msg; - node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg); - if (!node) - continue; /* down, no point */ - if (node == chosen_exit) - continue; /* don't pick the same node for entry and exit */ - if (consider_exit_family && smartlist_isin(exit_family, node)) - continue; /* avoid relays that are family members of our exit */ -#if 0 /* since EntryNodes is always strict now, this clause is moot */ - if (options->EntryNodes && - !routerset_contains_node(options->EntryNodes, node)) { - /* We've come to the end of our preferred entry nodes. */ - if (smartlist_len(live_entry_guards)) - goto choose_and_finish; /* only choose from the ones we like */ - if (options->StrictNodes) { - /* in theory this case should never happen, since - * entry_guards_set_from_config() drops unwanted relays */ - tor_fragile_assert(); - } else { - log_info(LD_CIRC, - "No relays from EntryNodes available. Using others."); - } - } -#endif - smartlist_add(live_entry_guards, (void*)node); - if (!entry->made_contact) { - /* Always start with the first not-yet-contacted entry - * guard. Otherwise we might add several new ones, pick - * the second new one, and now we've expanded our entry - * guard list without needing to. */ - goto choose_and_finish; - } - if (smartlist_len(live_entry_guards) >= options->NumEntryGuards) - goto choose_and_finish; /* we have enough */ - } SMARTLIST_FOREACH_END(entry); - - if (entry_list_is_constrained(options)) { - /* If we prefer the entry nodes we've got, and we have at least - * one choice, that's great. Use it. */ - preferred_min = 1; - } else { - /* Try to have at least 2 choices available. This way we don't - * get stuck with a single live-but-crummy entry and just keep - * using him. - * (We might get 2 live-but-crummy entry guards, but so be it.) */ - preferred_min = 2; - } - - if (smartlist_len(live_entry_guards) < preferred_min) { - if (!entry_list_is_constrained(options)) { - /* still no? try adding a new entry then */ - /* XXX if guard doesn't imply fast and stable, then we need - * to tell add_an_entry_guard below what we want, or it might - * be a long time til we get it. -RD */ - node = add_an_entry_guard(NULL, 0, 0); - if (node) { - entry_guards_changed(); - /* XXX we start over here in case the new node we added shares - * a family with our exit node. There's a chance that we'll just - * load up on entry guards here, if the network we're using is - * one big family. Perhaps we should teach add_an_entry_guard() - * to understand nodes-to-avoid-if-possible? -RD */ - goto retry; - } - } - if (!node && need_uptime) { - need_uptime = 0; /* try without that requirement */ - goto retry; - } - if (!node && need_capacity) { - /* still no? last attempt, try without requiring capacity */ - need_capacity = 0; - goto retry; - } -#if 0 - /* Removing this retry logic: if we only allow one exit, and it is in the - same family as all our entries, then we are just plain not going to win - here. */ - if (!node && entry_list_is_constrained(options) && consider_exit_family) { - /* still no? if we're using bridges or have strictentrynodes - * set, and our chosen exit is in the same family as all our - * bridges/entry guards, then be flexible about families. */ - consider_exit_family = 0; - goto retry; - } -#endif - /* live_entry_guards may be empty below. Oh well, we tried. */ - } - - choose_and_finish: - if (entry_list_is_constrained(options)) { - /* We need to weight by bandwidth, because our bridges or entryguards - * were not already selected proportional to their bandwidth. */ - node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD); - } else { - /* We choose uniformly at random here, because choose_good_entry_server() - * already weights its choices by bandwidth, so we don't want to - * *double*-weight our guard selection. */ - node = smartlist_choose(live_entry_guards); - } - smartlist_free(live_entry_guards); - smartlist_free(exit_family); - return node; -} - -/** Parse <b>state</b> and learn about the entry guards it describes. - * If <b>set</b> is true, and there are no errors, replace the global - * entry_list with what we find. - * On success, return 0. On failure, alloc into *<b>msg</b> a string - * describing the error, and return -1. - */ -int -entry_guards_parse_state(or_state_t *state, int set, char **msg) -{ - entry_guard_t *node = NULL; - smartlist_t *new_entry_guards = smartlist_new(); - config_line_t *line; - time_t now = time(NULL); - const char *state_version = state->TorVersion; - digestmap_t *added_by = digestmap_new(); - - *msg = NULL; - for (line = state->EntryGuards; line; line = line->next) { - if (!strcasecmp(line->key, "EntryGuard")) { - smartlist_t *args = smartlist_new(); - node = tor_malloc_zero(sizeof(entry_guard_t)); - /* all entry guards on disk have been contacted */ - node->made_contact = 1; - smartlist_add(new_entry_guards, node); - smartlist_split_string(args, line->value, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(args)<2) { - *msg = tor_strdup("Unable to parse entry nodes: " - "Too few arguments to EntryGuard"); - } else if (!is_legal_nickname(smartlist_get(args,0))) { - *msg = tor_strdup("Unable to parse entry nodes: " - "Bad nickname for EntryGuard"); - } else { - strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1); - if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1), - strlen(smartlist_get(args,1)))<0) { - *msg = tor_strdup("Unable to parse entry nodes: " - "Bad hex digest for EntryGuard"); - } - } - SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); - smartlist_free(args); - if (*msg) - break; - } else if (!strcasecmp(line->key, "EntryGuardDownSince") || - !strcasecmp(line->key, "EntryGuardUnlistedSince")) { - time_t when; - time_t last_try = 0; - if (!node) { - *msg = tor_strdup("Unable to parse entry nodes: " - "EntryGuardDownSince/UnlistedSince without EntryGuard"); - break; - } - if (parse_iso_time(line->value, &when)<0) { - *msg = tor_strdup("Unable to parse entry nodes: " - "Bad time in EntryGuardDownSince/UnlistedSince"); - break; - } - if (when > now) { - /* It's a bad idea to believe info in the future: you can wind - * up with timeouts that aren't allowed to happen for years. */ - continue; - } - if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) { - /* ignore failure */ - (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try); - } - if (!strcasecmp(line->key, "EntryGuardDownSince")) { - node->unreachable_since = when; - node->last_attempted = last_try; - } else { - node->bad_since = when; - } - } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) { - char d[DIGEST_LEN]; - /* format is digest version date */ - if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) { - log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough."); - continue; - } - if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 || - line->value[HEX_DIGEST_LEN] != ' ') { - log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with " - "hex digest", escaped(line->value)); - continue; - } - digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1)); - } else if (!strcasecmp(line->key, "EntryGuardPathBias")) { - const or_options_t *options = get_options(); - unsigned hop_cnt, success_cnt; - - if (!node) { - *msg = tor_strdup("Unable to parse entry nodes: " - "EntryGuardPathBias without EntryGuard"); - break; - } - - if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) { - log_warn(LD_GENERAL, "Unable to parse guard path bias info: " - "Misformated EntryGuardPathBias %s", escaped(line->value)); - continue; - } - - node->first_hops = hop_cnt; - node->circuit_successes = success_cnt; - log_info(LD_GENERAL, "Read %u/%u path bias for node %s", - node->circuit_successes, node->first_hops, node->nickname); - /* Note: We rely on the < comparison here to allow us to set a 0 - * rate and disable the feature entirely. If refactoring, don't - * change to <= */ - if (node->circuit_successes/((double)node->first_hops) - < pathbias_get_disable_rate(options)) { - node->path_bias_disabled = 1; - log_info(LD_GENERAL, - "Path bias is too high (%u/%u); disabling node %s", - node->circuit_successes, node->first_hops, node->nickname); - } - - } else { - log_warn(LD_BUG, "Unexpected key %s", line->key); - } - } - - SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) { - char *sp; - char *val = digestmap_get(added_by, e->identity); - if (val && (sp = strchr(val, ' '))) { - time_t when; - *sp++ = '\0'; - if (parse_iso_time(sp, &when)<0) { - log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp); - } else { - e->chosen_by_version = tor_strdup(val); - e->chosen_on_date = when; - } - } else { - if (state_version) { - e->chosen_by_version = tor_strdup(state_version); - e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); - } - } - if (e->path_bias_disabled && !e->bad_since) - e->bad_since = time(NULL); - } - SMARTLIST_FOREACH_END(e); - - if (*msg || !set) { - SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e, - entry_guard_free(e)); - smartlist_free(new_entry_guards); - } else { /* !err && set */ - if (entry_guards) { - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, - entry_guard_free(e)); - smartlist_free(entry_guards); - } - entry_guards = new_entry_guards; - entry_guards_dirty = 0; - /* XXX024 hand new_entry_guards to this func, and move it up a - * few lines, so we don't have to re-dirty it */ - if (remove_obsolete_entry_guards(now)) - entry_guards_dirty = 1; - } - digestmap_free(added_by, _tor_free); - return *msg ? -1 : 0; -} - -/** Our list of entry guards has changed, or some element of one - * of our entry guards has changed. Write the changes to disk within - * the next few minutes. - */ -static void -entry_guards_changed(void) -{ - time_t when; - entry_guards_dirty = 1; - - /* or_state_save() will call entry_guards_update_state(). */ - when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600; - or_state_mark_dirty(get_or_state(), when); -} - -/** If the entry guard info has not changed, do nothing and return. - * Otherwise, free the EntryGuards piece of <b>state</b> and create - * a new one out of the global entry_guards list, and then mark - * <b>state</b> dirty so it will get saved to disk. - */ -void -entry_guards_update_state(or_state_t *state) -{ - config_line_t **next, *line; - if (! entry_guards_dirty) - return; - - config_free_lines(state->EntryGuards); - next = &state->EntryGuards; - *next = NULL; - if (!entry_guards) - entry_guards = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { - char dbuf[HEX_DIGEST_LEN+1]; - if (!e->made_contact) - continue; /* don't write this one to disk */ - *next = line = tor_malloc_zero(sizeof(config_line_t)); - line->key = tor_strdup("EntryGuard"); - base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN); - tor_asprintf(&line->value, "%s %s", e->nickname, dbuf); - next = &(line->next); - if (e->unreachable_since) { - *next = line = tor_malloc_zero(sizeof(config_line_t)); - line->key = tor_strdup("EntryGuardDownSince"); - line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1); - format_iso_time(line->value, e->unreachable_since); - if (e->last_attempted) { - line->value[ISO_TIME_LEN] = ' '; - format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted); - } - next = &(line->next); - } - if (e->bad_since) { - *next = line = tor_malloc_zero(sizeof(config_line_t)); - line->key = tor_strdup("EntryGuardUnlistedSince"); - line->value = tor_malloc(ISO_TIME_LEN+1); - format_iso_time(line->value, e->bad_since); - next = &(line->next); - } - if (e->chosen_on_date && e->chosen_by_version && - !strchr(e->chosen_by_version, ' ')) { - char d[HEX_DIGEST_LEN+1]; - char t[ISO_TIME_LEN+1]; - *next = line = tor_malloc_zero(sizeof(config_line_t)); - line->key = tor_strdup("EntryGuardAddedBy"); - base16_encode(d, sizeof(d), e->identity, DIGEST_LEN); - format_iso_time(t, e->chosen_on_date); - tor_asprintf(&line->value, "%s %s %s", - d, e->chosen_by_version, t); - next = &(line->next); - } - if (e->first_hops) { - *next = line = tor_malloc_zero(sizeof(config_line_t)); - line->key = tor_strdup("EntryGuardPathBias"); - tor_asprintf(&line->value, "%u %u", - e->circuit_successes, e->first_hops); - next = &(line->next); - } - - } SMARTLIST_FOREACH_END(e); - if (!get_options()->AvoidDiskWrites) - or_state_mark_dirty(get_or_state(), 0); - entry_guards_dirty = 0; -} - -/** If <b>question</b> is the string "entry-guards", then dump - * to *<b>answer</b> a newly allocated string describing all of - * the nodes in the global entry_guards list. See control-spec.txt - * for details. - * For backward compatibility, we also handle the string "helper-nodes". - * */ -int -getinfo_helper_entry_guards(control_connection_t *conn, - const char *question, char **answer, - const char **errmsg) -{ - (void) conn; - (void) errmsg; - - if (!strcmp(question,"entry-guards") || - !strcmp(question,"helper-nodes")) { - smartlist_t *sl = smartlist_new(); - char tbuf[ISO_TIME_LEN+1]; - char nbuf[MAX_VERBOSE_NICKNAME_LEN+1]; - if (!entry_guards) - entry_guards = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { - const char *status = NULL; - time_t when = 0; - const node_t *node; - - if (!e->made_contact) { - status = "never-connected"; - } else if (e->bad_since) { - when = e->bad_since; - status = "unusable"; - } else { - status = "up"; - } - - node = node_get_by_id(e->identity); - if (node) { - node_get_verbose_nickname(node, nbuf); - } else { - nbuf[0] = '$'; - base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN); - /* e->nickname field is not very reliable if we don't know about - * this router any longer; don't include it. */ - } - - if (when) { - format_iso_time(tbuf, when); - smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf); - } else { - smartlist_add_asprintf(sl, "%s %s\n", nbuf, status); - } - } SMARTLIST_FOREACH_END(e); - *answer = smartlist_join_strings(sl, "", 0, NULL); - SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); - smartlist_free(sl); - } - return 0; -} - -/** A list of configured bridges. Whenever we actually get a descriptor - * for one, we add it as an entry guard. Note that the order of bridges - * in this list does not necessarily correspond to the order of bridges - * in the torrc. */ -static smartlist_t *bridge_list = NULL; - -/** Mark every entry of the bridge list to be removed on our next call to - * sweep_bridge_list unless it has first been un-marked. */ -void -mark_bridge_list(void) -{ - if (!bridge_list) - bridge_list = smartlist_new(); - SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, - b->marked_for_removal = 1); -} - -/** Remove every entry of the bridge list that was marked with - * mark_bridge_list if it has not subsequently been un-marked. */ -void -sweep_bridge_list(void) -{ - if (!bridge_list) - bridge_list = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { - if (b->marked_for_removal) { - SMARTLIST_DEL_CURRENT(bridge_list, b); - bridge_free(b); - } - } SMARTLIST_FOREACH_END(b); -} - -/** Initialize the bridge list to empty, creating it if needed. */ -static void -clear_bridge_list(void) -{ - if (!bridge_list) - bridge_list = smartlist_new(); - SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b)); - smartlist_clear(bridge_list); -} - -/** Free the bridge <b>bridge</b>. */ -static void -bridge_free(bridge_info_t *bridge) -{ - if (!bridge) - return; - - tor_free(bridge->transport_name); - tor_free(bridge); -} - -/** If we have a bridge configured whose digest matches <b>digest</b>, or a - * bridge with no known digest whose address matches any of the - * tor_addr_port_t's in <b>orports</b>, return that bridge. Else return - * NULL. */ -static bridge_info_t * -get_configured_bridge_by_orports_digest(const char *digest, - const smartlist_t *orports) -{ - if (!bridge_list) - return NULL; - SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) - { - if (tor_digest_is_zero(bridge->identity)) { - SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, ap) - { - if (tor_addr_compare(&bridge->addr, &ap->addr, CMP_EXACT) == 0 && - bridge->port == ap->port) - return bridge; - } - SMARTLIST_FOREACH_END(ap); - } - if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) - return bridge; - } - SMARTLIST_FOREACH_END(bridge); - return NULL; -} - -/** If we have a bridge configured whose digest matches <b>digest</b>, or a - * bridge with no known digest whose address matches <b>addr</b>:<b>/port</b>, - * return that bridge. Else return NULL. */ -static bridge_info_t * -get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr, - uint16_t port, - const char *digest) -{ - if (!bridge_list) - return NULL; - SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) - { - if (tor_digest_is_zero(bridge->identity) && - !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) && - bridge->port == port) - return bridge; - if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) - return bridge; - } - SMARTLIST_FOREACH_END(bridge); - return NULL; -} - -/** Wrapper around get_configured_bridge_by_addr_port_digest() to look - * it up via router descriptor <b>ri</b>. */ -static bridge_info_t * -get_configured_bridge_by_routerinfo(const routerinfo_t *ri) -{ - bridge_info_t *bi = NULL; - smartlist_t *orports = router_get_all_orports(ri); - bi = get_configured_bridge_by_orports_digest(ri->cache_info.identity_digest, - orports); - SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); - smartlist_free(orports); - return bi; -} - -/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */ -int -routerinfo_is_a_configured_bridge(const routerinfo_t *ri) -{ - return get_configured_bridge_by_routerinfo(ri) ? 1 : 0; -} - -/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */ -int -node_is_a_configured_bridge(const node_t *node) -{ - int retval = 0; - smartlist_t *orports = node_get_all_orports(node); - retval = get_configured_bridge_by_orports_digest(node->identity, - orports) != NULL; - SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); - smartlist_free(orports); - return retval; -} - -/** We made a connection to a router at <b>addr</b>:<b>port</b> - * without knowing its digest. Its digest turned out to be <b>digest</b>. - * If it was a bridge, and we still don't know its digest, record it. - */ -void -learned_router_identity(const tor_addr_t *addr, uint16_t port, - const char *digest) -{ - bridge_info_t *bridge = - get_configured_bridge_by_addr_port_digest(addr, port, digest); - if (bridge && tor_digest_is_zero(bridge->identity)) { - memcpy(bridge->identity, digest, DIGEST_LEN); - log_notice(LD_DIR, "Learned fingerprint %s for bridge %s", - hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port)); - } -} - -/** Return true if <b>bridge</b> has the same identity digest as - * <b>digest</b>. If <b>digest</b> is NULL, it matches - * bridges with unspecified identity digests. */ -static int -bridge_has_digest(const bridge_info_t *bridge, const char *digest) -{ - if (digest) - return tor_memeq(digest, bridge->identity, DIGEST_LEN); - else - return tor_digest_is_zero(bridge->identity); -} - -/** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional - * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously - * existing bridge with the same address and port, and warn the user as - * appropriate. - */ -static void -bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port, - const char *digest, const char *transport_name) -{ - /* Iterate the already-registered bridge list: - - If you find a bridge with the same adress and port, mark it for - removal. It doesn't make sense to have two active bridges with - the same IP:PORT. If the bridge in question has a different - digest or transport than <b>digest</b>/<b>transport_name</b>, - it's probably a misconfiguration and we should warn the user. - */ - SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) { - if (bridge->marked_for_removal) - continue; - - if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) { - - bridge->marked_for_removal = 1; - - if (!bridge_has_digest(bridge, digest) || - strcmp_opt(bridge->transport_name, transport_name)) { - /* warn the user */ - char *bridge_description_new, *bridge_description_old; - tor_asprintf(&bridge_description_new, "%s:%s:%s", - fmt_addrport(addr, port), - digest ? hex_str(digest, DIGEST_LEN) : "", - transport_name ? transport_name : ""); - tor_asprintf(&bridge_description_old, "%s:%s:%s", - fmt_addrport(&bridge->addr, bridge->port), - tor_digest_is_zero(bridge->identity) ? - "" : hex_str(bridge->identity,DIGEST_LEN), - bridge->transport_name ? bridge->transport_name : ""); - - log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict" - " with the already registered bridge '%s'. We will discard" - " the old bridge and keep '%s'. If this is not what you" - " wanted, please change your configuration file accordingly.", - bridge_description_new, bridge_description_old, - bridge_description_new); - - tor_free(bridge_description_new); - tor_free(bridge_description_old); - } - } - } SMARTLIST_FOREACH_END(bridge); -} - -/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b> - * is set, it tells us the identity key too. If we already had the - * bridge in our list, unmark it, and don't actually add anything new. - * If <b>transport_name</b> is non-NULL - the bridge is associated with a - * pluggable transport - we assign the transport to the bridge. */ -void -bridge_add_from_config(const tor_addr_t *addr, uint16_t port, - const char *digest, const char *transport_name) -{ - bridge_info_t *b; - - bridge_resolve_conflicts(addr, port, digest, transport_name); - - b = tor_malloc_zero(sizeof(bridge_info_t)); - tor_addr_copy(&b->addr, addr); - b->port = port; - if (digest) - memcpy(b->identity, digest, DIGEST_LEN); - if (transport_name) - b->transport_name = tor_strdup(transport_name); - b->fetch_status.schedule = DL_SCHED_BRIDGE; - if (!bridge_list) - bridge_list = smartlist_new(); - - smartlist_add(bridge_list, b); -} - -/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */ -static int -routerset_contains_bridge(const routerset_t *routerset, - const bridge_info_t *bridge) -{ - int result; - extend_info_t *extinfo; - tor_assert(bridge); - if (!routerset) - return 0; - - extinfo = extend_info_new( - NULL, bridge->identity, NULL, &bridge->addr, bridge->port); - result = routerset_contains_extendinfo(routerset, extinfo); - extend_info_free(extinfo); - return result; -} - -/** If <b>digest</b> is one of our known bridges, return it. */ -static bridge_info_t * -find_bridge_by_digest(const char *digest) -{ - SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge, - { - if (tor_memeq(bridge->identity, digest, DIGEST_LEN)) - return bridge; - }); - return NULL; -} - -/* DOCDOC find_transport_name_by_bridge_addrport */ -const char * -find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) -{ - if (!bridge_list) - return NULL; - - SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { - if (tor_addr_eq(&bridge->addr, addr) && - (bridge->port == port)) - return bridge->transport_name; - } SMARTLIST_FOREACH_END(bridge); - - return NULL; -} - -/** If <b>addr</b> and <b>port</b> match the address and port of a - * bridge of ours that uses pluggable transports, place its transport - * in <b>transport</b>. - * - * Return 0 on success (found a transport, or found a bridge with no - * transport, or found no bridge); return -1 if we should be using a - * transport, but the transport could not be found. - */ -int -find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, - const transport_t **transport) -{ - *transport = NULL; - if (!bridge_list) - return 0; - - SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { - if (tor_addr_eq(&bridge->addr, addr) && - (bridge->port == port)) { /* bridge matched */ - if (bridge->transport_name) { /* it also uses pluggable transports */ - *transport = transport_get_by_name(bridge->transport_name); - if (*transport == NULL) { /* it uses pluggable transports, but - the transport could not be found! */ - return -1; - } - return 0; - } else { /* bridge matched, but it doesn't use transports. */ - break; - } - } - } SMARTLIST_FOREACH_END(bridge); - - *transport = NULL; - return 0; -} - -/** We need to ask <b>bridge</b> for its server descriptor. */ -static void -launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) -{ - char *address; - const or_options_t *options = get_options(); - - if (connection_get_by_type_addr_port_purpose( - CONN_TYPE_DIR, &bridge->addr, bridge->port, - DIR_PURPOSE_FETCH_SERVERDESC)) - return; /* it's already on the way */ - - if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { - download_status_mark_impossible(&bridge->fetch_status); - log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", - safe_str_client(fmt_and_decorate_addr(&bridge->addr))); - return; - } - - address = tor_dup_addr(&bridge->addr); - - directory_initiate_command(address, &bridge->addr, - bridge->port, 0/*no dirport*/, - bridge->identity, - DIR_PURPOSE_FETCH_SERVERDESC, - ROUTER_PURPOSE_BRIDGE, - DIRIND_ONEHOP, "authority.z", NULL, 0, 0); - tor_free(address); -} - -/** Fetching the bridge descriptor from the bridge authority returned a - * "not found". Fall back to trying a direct fetch. */ -void -retry_bridge_descriptor_fetch_directly(const char *digest) -{ - bridge_info_t *bridge = find_bridge_by_digest(digest); - if (!bridge) - return; /* not found? oh well. */ - - launch_direct_bridge_descriptor_fetch(bridge); -} - -/** For each bridge in our list for which we don't currently have a - * descriptor, fetch a new copy of its descriptor -- either directly - * from the bridge or via a bridge authority. */ -void -fetch_bridge_descriptors(const or_options_t *options, time_t now) -{ - int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO); - int ask_bridge_directly; - int can_use_bridge_authority; - - if (!bridge_list) - return; - - /* If we still have unconfigured managed proxies, don't go and - connect to a bridge. */ - if (pt_proxies_configuration_pending()) - return; - - SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) - { - if (!download_status_is_ready(&bridge->fetch_status, now, - IMPOSSIBLE_TO_DOWNLOAD)) - continue; /* don't bother, no need to retry yet */ - if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { - download_status_mark_impossible(&bridge->fetch_status); - log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", - safe_str_client(fmt_and_decorate_addr(&bridge->addr))); - continue; - } - - /* schedule another fetch as if this one will fail, in case it does */ - download_status_failed(&bridge->fetch_status, 0); - - can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) && - num_bridge_auths; - ask_bridge_directly = !can_use_bridge_authority || - !options->UpdateBridgesFromAuthority; - log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)", - ask_bridge_directly, tor_digest_is_zero(bridge->identity), - !options->UpdateBridgesFromAuthority, !num_bridge_auths); - - if (ask_bridge_directly && - !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) { - log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our " - "firewall policy. %s.", - fmt_addrport(&bridge->addr, bridge->port), - can_use_bridge_authority ? - "Asking bridge authority instead" : "Skipping"); - if (can_use_bridge_authority) - ask_bridge_directly = 0; - else - continue; - } - - if (ask_bridge_directly) { - /* we need to ask the bridge itself for its descriptor. */ - launch_direct_bridge_descriptor_fetch(bridge); - } else { - /* We have a digest and we want to ask an authority. We could - * combine all the requests into one, but that may give more - * hints to the bridge authority than we want to give. */ - char resource[10 + HEX_DIGEST_LEN]; - memcpy(resource, "fp/", 3); - base16_encode(resource+3, HEX_DIGEST_LEN+1, - bridge->identity, DIGEST_LEN); - memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3); - log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.", - resource); - directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC, - ROUTER_PURPOSE_BRIDGE, resource, 0); - } - } - SMARTLIST_FOREACH_END(bridge); -} - -/** If our <b>bridge</b> is configured to be a different address than - * the bridge gives in <b>node</b>, rewrite the routerinfo - * we received to use the address we meant to use. Now we handle - * multihomed bridges better. - */ -static void -rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) -{ - /* XXXX move this function. */ - /* XXXX overridden addresses should really live in the node_t, so that the - * routerinfo_t and the microdesc_t can be immutable. But we can only - * do that safely if we know that no function that connects to an OR - * does so through an address from any source other than node_get_addr(). - */ - tor_addr_t addr; - - if (node->ri) { - routerinfo_t *ri = node->ri; - tor_addr_from_ipv4h(&addr, ri->addr); - - if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && - bridge->port == ri->or_port) || - (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) && - bridge->port == ri->ipv6_orport)) { - /* they match, so no need to do anything */ - } else { - if (tor_addr_family(&bridge->addr) == AF_INET) { - ri->addr = tor_addr_to_ipv4h(&bridge->addr); - tor_free(ri->address); - ri->address = tor_dup_ip(ri->addr); - ri->or_port = bridge->port; - log_info(LD_DIR, - "Adjusted bridge routerinfo for '%s' to match configured " - "address %s:%d.", - ri->nickname, ri->address, ri->or_port); - } else if (tor_addr_family(&bridge->addr) == AF_INET6) { - tor_addr_copy(&ri->ipv6_addr, &bridge->addr); - ri->ipv6_orport = bridge->port; - log_info(LD_DIR, - "Adjusted bridge routerinfo for '%s' to match configured " - "address %s.", - ri->nickname, fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); - } else { - log_err(LD_BUG, "Address family not supported: %d.", - tor_addr_family(&bridge->addr)); - return; - } - } - - /* Mark which address to use based on which bridge_t we got. */ - node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && - !tor_addr_is_null(&node->ri->ipv6_addr)); - - /* XXXipv6 we lack support for falling back to another address for - the same relay, warn the user */ - if (!tor_addr_is_null(&ri->ipv6_addr)) { - tor_addr_port_t ap; - node_get_pref_orport(node, &ap); - log_notice(LD_CONFIG, - "Bridge '%s' has both an IPv4 and an IPv6 address. " - "Will prefer using its %s address (%s).", - ri->nickname, - tor_addr_family(&ap.addr) == AF_INET6 ? "IPv6" : "IPv4", - fmt_addrport(&ap.addr, ap.port)); - } - } - if (node->rs) { - routerstatus_t *rs = node->rs; - tor_addr_from_ipv4h(&addr, rs->addr); - - if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && - bridge->port == rs->or_port) { - /* they match, so no need to do anything */ - } else { - rs->addr = tor_addr_to_ipv4h(&bridge->addr); - rs->or_port = bridge->port; - log_info(LD_DIR, - "Adjusted bridge routerstatus for '%s' to match " - "configured address %s.", - rs->nickname, fmt_addrport(&bridge->addr, rs->or_port)); - } - } -} - -/** We just learned a descriptor for a bridge. See if that - * digest is in our entry guard list, and add it if not. */ -void -learned_bridge_descriptor(routerinfo_t *ri, int from_cache) -{ - tor_assert(ri); - tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE); - if (get_options()->UseBridges) { - int first = !any_bridge_descriptors_known(); - bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri); - time_t now = time(NULL); - router_set_status(ri->cache_info.identity_digest, 1); - - if (bridge) { /* if we actually want to use this one */ - node_t *node; - /* it's here; schedule its re-fetch for a long time from now. */ - if (!from_cache) - download_status_reset(&bridge->fetch_status); - - node = node_get_mutable_by_id(ri->cache_info.identity_digest); - tor_assert(node); - rewrite_node_address_for_bridge(bridge, node); - add_an_entry_guard(node, 1, 1); - - log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, - from_cache ? "cached" : "fresh", router_describe(ri)); - /* set entry->made_contact so if it goes down we don't drop it from - * our entry node list */ - entry_guard_register_connect_status(ri->cache_info.identity_digest, - 1, 0, now); - if (first) - routerlist_retry_directory_downloads(now); - } - } -} - -/** Return 1 if any of our entry guards have descriptors that - * are marked with purpose 'bridge' and are running. Else return 0. - * - * We use this function to decide if we're ready to start building - * circuits through our bridges, or if we need to wait until the - * directory "server/authority" requests finish. */ -int -any_bridge_descriptors_known(void) -{ - tor_assert(get_options()->UseBridges); - return choose_random_entry(NULL)!=NULL ? 1 : 0; -} - -/** Return 1 if there are any directory conns fetching bridge descriptors - * that aren't marked for close. We use this to guess if we should tell - * the controller that we have a problem. */ -int -any_pending_bridge_descriptor_fetches(void) -{ - smartlist_t *conns = get_connection_array(); - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { - if (conn->type == CONN_TYPE_DIR && - conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC && - TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE && - !conn->marked_for_close && - conn->linked && - conn->linked_conn && !conn->linked_conn->marked_for_close) { - log_debug(LD_DIR, "found one: %s", conn->address); - return 1; - } - } SMARTLIST_FOREACH_END(conn); - return 0; -} - -/** Return 1 if we have at least one descriptor for an entry guard - * (bridge or member of EntryNodes) and all descriptors we know are - * down. Else return 0. If <b>act</b> is 1, then mark the down guards - * up; else just observe and report. */ -static int -entries_retry_helper(const or_options_t *options, int act) -{ - const node_t *node; - int any_known = 0; - int any_running = 0; - int need_bridges = options->UseBridges != 0; - if (!entry_guards) - entry_guards = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { - node = node_get_by_id(e->identity); - if (node && node_has_descriptor(node) && - node_is_bridge(node) == need_bridges) { - any_known = 1; - if (node->is_running) - any_running = 1; /* some entry is both known and running */ - else if (act) { - /* Mark all current connections to this OR as unhealthy, since - * otherwise there could be one that started 30 seconds - * ago, and in 30 seconds it will time out, causing us to mark - * the node down and undermine the retry attempt. We mark even - * the established conns, since if the network just came back - * we'll want to attach circuits to fresh conns. */ - connection_or_set_bad_connections(node->identity, 1); - - /* mark this entry node for retry */ - router_set_status(node->identity, 1); - e->can_retry = 1; - e->bad_since = 0; - } - } - } SMARTLIST_FOREACH_END(e); - log_debug(LD_DIR, "%d: any_known %d, any_running %d", - act, any_known, any_running); - return any_known && !any_running; -} - -/** Do we know any descriptors for our bridges / entrynodes, and are - * all the ones we have descriptors for down? */ -int -entries_known_but_down(const or_options_t *options) -{ - tor_assert(entry_list_is_constrained(options)); - return entries_retry_helper(options, 0); -} - -/** Mark all down known bridges / entrynodes up. */ -void -entries_retry_all(const or_options_t *options) -{ - tor_assert(entry_list_is_constrained(options)); - entries_retry_helper(options, 1); -} - -/** Return true if we've ever had a bridge running a Tor version that can't - * provide microdescriptors to us. In that case fall back to asking for - * full descriptors. Eventually all bridges will support microdescriptors - * and we can take this check out; see bug 4013. */ -int -any_bridges_dont_support_microdescriptors(void) -{ - const node_t *node; - static int ever_answered_yes = 0; - if (!get_options()->UseBridges || !entry_guards) - return 0; - if (ever_answered_yes) - return 1; /* if we ever answer 'yes', always answer 'yes' */ - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { - node = node_get_by_id(e->identity); - if (node && node->ri && - node_is_bridge(node) && node_is_a_configured_bridge(node) && - !tor_version_supports_microdescriptors(node->ri->platform)) { - /* This is one of our current bridges, and we know enough about - * it to know that it won't be able to answer our microdescriptor - * questions. */ - ever_answered_yes = 1; - return 1; - } - } SMARTLIST_FOREACH_END(e); - return 0; -} - -/** Release all storage held by the list of entry guards and related - * memory structs. */ -void -entry_guards_free_all(void) -{ - if (entry_guards) { - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, - entry_guard_free(e)); - smartlist_free(entry_guards); - entry_guards = NULL; - } - clear_bridge_list(); - smartlist_free(bridge_list); - bridge_list = NULL; - circuit_build_times_free_timeouts(&circ_times); -} - diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 0abffc5166..78575afcf2 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -9,8 +9,8 @@ * \brief Header file for circuitbuild.c. **/ -#ifndef _TOR_CIRCUITBUILD_H -#define _TOR_CIRCUITBUILD_H +#ifndef TOR_CIRCUITBUILD_H +#define TOR_CIRCUITBUILD_H char *circuit_list_path(origin_circuit_t *circ, int verbose); char *circuit_list_path_for_controller(origin_circuit_t *circ); @@ -51,95 +51,9 @@ void extend_info_free(extend_info_t *info); const node_t *build_state_get_exit_node(cpath_build_state_t *state); const char *build_state_get_exit_nickname(cpath_build_state_t *state); -void entry_guards_compute_status(const or_options_t *options, time_t now); -int entry_guard_register_connect_status(const char *digest, int succeeded, - int mark_relay_status, time_t now); -void entry_nodes_should_be_added(void); -int entry_list_is_constrained(const or_options_t *options); -const node_t *choose_random_entry(cpath_build_state_t *state); -int entry_guards_parse_state(or_state_t *state, int set, char **msg); -void entry_guards_update_state(or_state_t *state); -int getinfo_helper_entry_guards(control_connection_t *conn, - const char *question, char **answer, - const char **errmsg); - -void mark_bridge_list(void); -void sweep_bridge_list(void); - -int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); -int node_is_a_configured_bridge(const node_t *node); -void learned_router_identity(const tor_addr_t *addr, uint16_t port, - const char *digest); -void bridge_add_from_config(const tor_addr_t *addr, uint16_t port, - const char *digest, - const char *transport_name); -void retry_bridge_descriptor_fetch_directly(const char *digest); -void fetch_bridge_descriptors(const or_options_t *options, time_t now); -void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); -int any_bridge_descriptors_known(void); -int any_pending_bridge_descriptor_fetches(void); -int entries_known_but_down(const or_options_t *options); -void entries_retry_all(const or_options_t *options); - -int any_bridges_dont_support_microdescriptors(void); - -void entry_guards_free_all(void); - -extern circuit_build_times_t circ_times; -int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt); -void circuit_build_times_update_state(circuit_build_times_t *cbt, - or_state_t *state); -int circuit_build_times_parse_state(circuit_build_times_t *cbt, - or_state_t *state); -void circuit_build_times_count_timeout(circuit_build_times_t *cbt, - int did_onehop); -int circuit_build_times_count_close(circuit_build_times_t *cbt, - int did_onehop, time_t start_time); -void circuit_build_times_set_timeout(circuit_build_times_t *cbt); -int circuit_build_times_add_time(circuit_build_times_t *cbt, - build_time_t time); -int circuit_build_times_needs_circuits(circuit_build_times_t *cbt); - -int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt); -void circuit_build_times_init(circuit_build_times_t *cbt); -void circuit_build_times_free_timeouts(circuit_build_times_t *cbt); -void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, - networkstatus_t *ns); -double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt); -double circuit_build_times_close_rate(const circuit_build_times_t *cbt); - -#ifdef CIRCUIT_PRIVATE -double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, - double quantile); -build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt, - double q_lo, double q_hi); -void circuit_build_times_initial_alpha(circuit_build_times_t *cbt, - double quantile, double time_ms); -int circuit_build_times_update_alpha(circuit_build_times_t *cbt); -double circuit_build_times_cdf(circuit_build_times_t *cbt, double x); -void circuitbuild_running_unit_tests(void); -void circuit_build_times_reset(circuit_build_times_t *cbt); - -/* Network liveness functions */ -int circuit_build_times_network_check_changed(circuit_build_times_t *cbt); -#endif - -/* Network liveness functions */ -void circuit_build_times_network_is_live(circuit_build_times_t *cbt); -int circuit_build_times_network_check_live(circuit_build_times_t *cbt); -void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); - -/* DOCDOC circuit_build_times_get_bw_scale */ -int circuit_build_times_get_bw_scale(networkstatus_t *ns); - -/* DOCDOC find_transport_name_by_bridge_addrport */ -const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, - uint16_t port); -struct transport_t; -int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, - const struct transport_t **transport); - -int validate_pluggable_transports_config(void); +const node_t *choose_good_entry_server(uint8_t purpose, + cpath_build_state_t *state); +double pathbias_get_disable_rate(const or_options_t *options); #endif diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index b73822635d..3ec2bf15bb 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -14,6 +14,7 @@ #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" +#include "circuitstats.h" #include "connection.h" #include "config.h" #include "connection_edge.h" @@ -58,7 +59,7 @@ typedef struct chan_circid_circuit_map_t { * b, and return less than, equal to, or greater than zero appropriately. */ static INLINE int -_chan_circid_entries_eq(chan_circid_circuit_map_t *a, +chan_circid_entries_eq_(chan_circid_circuit_map_t *a, chan_circid_circuit_map_t *b) { return a->chan == b->chan && a->circ_id == b->circ_id; @@ -67,7 +68,7 @@ _chan_circid_entries_eq(chan_circid_circuit_map_t *a, /** Helper: return a hash based on circuit ID and the pointer value of * chan in <b>a</b>. */ static INLINE unsigned int -_chan_circid_entry_hash(chan_circid_circuit_map_t *a) +chan_circid_entry_hash_(chan_circid_circuit_map_t *a) { return (((unsigned)a->circ_id)<<8) ^ (unsigned)(uintptr_t)(a->chan); } @@ -76,9 +77,9 @@ _chan_circid_entry_hash(chan_circid_circuit_map_t *a) static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t) chan_circid_map = HT_INITIALIZER(); HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node, - _chan_circid_entry_hash, _chan_circid_entries_eq) + chan_circid_entry_hash_, chan_circid_entries_eq_) HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node, - _chan_circid_entry_hash, _chan_circid_entries_eq, 0.6, + chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6, malloc, realloc, free) /** The most recently returned entry from circuit_get_by_circid_chan; @@ -350,7 +351,7 @@ circuit_close_all_marked(void) /** Return the head of the global linked list of circuits. */ circuit_t * -_circuit_get_global_list(void) +circuit_get_global_list_(void) { return global_circuitlist; } @@ -572,7 +573,7 @@ origin_circuit_new(void) static uint32_t n_circuits_allocated = 1; circ = tor_malloc_zero(sizeof(origin_circuit_t)); - circ->_base.magic = ORIGIN_CIRCUIT_MAGIC; + circ->base_.magic = ORIGIN_CIRCUIT_MAGIC; circ->next_stream_id = crypto_rand_int(1<<16); circ->global_identifier = n_circuits_allocated++; @@ -595,7 +596,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan) or_circuit_t *circ; circ = tor_malloc_zero(sizeof(or_circuit_t)); - circ->_base.magic = OR_CIRCUIT_MAGIC; + circ->base_.magic = OR_CIRCUIT_MAGIC; if (p_chan) circuit_set_p_circid_chan(circ, p_circ_id, p_chan); @@ -659,7 +660,7 @@ circuit_free(circuit_t *circ) if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; - tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC); + tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC); other->rend_splice = NULL; } @@ -1162,7 +1163,7 @@ origin_circuit_t * circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags) { - circuit_t *_circ; + circuit_t *circ_; origin_circuit_t *best=NULL; int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0; int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0; @@ -1178,13 +1179,13 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, "capacity %d, internal %d", purpose, need_uptime, need_capacity, internal); - for (_circ=global_circuitlist; _circ; _circ = _circ->next) { - if (CIRCUIT_IS_ORIGIN(_circ) && - _circ->state == CIRCUIT_STATE_OPEN && - !_circ->marked_for_close && - _circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && - !_circ->timestamp_dirty) { - origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ); + for (circ_=global_circuitlist; circ_; circ_ = circ_->next) { + if (CIRCUIT_IS_ORIGIN(circ_) && + circ_->state == CIRCUIT_STATE_OPEN && + !circ_->marked_for_close && + circ_->purpose == CIRCUIT_PURPOSE_C_GENERAL && + !circ_->timestamp_dirty) { + origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(circ_); if ((!need_uptime || circ->build_state->need_uptime) && (!need_capacity || circ->build_state->need_capacity) && (internal == circ->build_state->is_internal) && @@ -1318,7 +1319,7 @@ circuit_expire_all_dirty_circs(void) * rendezvous stream), then mark the other circuit to close as well. */ void -_circuit_mark_for_close(circuit_t *circ, int reason, int line, +circuit_mark_for_close_(circuit_t *circ, int reason, int line, const char *file) { int orig_reason = reason; /* Passed to the controller */ @@ -1349,7 +1350,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, if (reason & END_CIRC_REASON_FLAG_REMOTE) reason &= ~END_CIRC_REASON_FLAG_REMOTE; - if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) { + if (reason < END_CIRC_REASON_MIN_ || reason > END_CIRC_REASON_MAX_) { if (!(orig_reason & END_CIRC_REASON_FLAG_REMOTE)) log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line); reason = END_CIRC_REASON_NONE; @@ -1424,7 +1425,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, while (or_circ->resolving_streams) { conn = or_circ->resolving_streams; or_circ->resolving_streams = conn->next_stream; - if (!conn->_base.marked_for_close) { + if (!conn->base_.marked_for_close) { /* The client will see a DESTROY, and infer that the connections * are closing because the circuit is getting torn down. No need * to send an end cell. */ @@ -1455,7 +1456,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, if (!CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (or_circ->rend_splice) { - if (!or_circ->rend_splice->_base.marked_for_close) { + if (!or_circ->rend_splice->base_.marked_for_close) { /* do this after marking this circuit, to avoid infinite recursion. */ circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason); } @@ -1529,8 +1530,8 @@ assert_circuit_ok(const circuit_t *c) tor_assert(c); tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC); - tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN && - c->purpose <= _CIRCUIT_PURPOSE_MAX); + tor_assert(c->purpose >= CIRCUIT_PURPOSE_MIN_ && + c->purpose <= CIRCUIT_PURPOSE_MAX_); { /* Having a separate variable for this pleases GCC 4.2 in ways I hope I @@ -1563,7 +1564,7 @@ assert_circuit_ok(const circuit_t *c) } if (or_circ) for (conn = or_circ->n_streams; conn; conn = conn->next_stream) - tor_assert(conn->_base.type == CONN_TYPE_EXIT); + tor_assert(conn->base_.type == CONN_TYPE_EXIT); tor_assert(c->deliver_window >= 0); tor_assert(c->package_window >= 0); diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 89e957c70a..a885af2fa0 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -9,10 +9,10 @@ * \brief Header file for circuitlist.c. **/ -#ifndef _TOR_CIRCUITLIST_H -#define _TOR_CIRCUITLIST_H +#ifndef TOR_CIRCUITLIST_H +#define TOR_CIRCUITLIST_H -circuit_t * _circuit_get_global_list(void); +circuit_t * circuit_get_global_list_(void); const char *circuit_state_to_string(int state); const char *circuit_purpose_to_controller_string(uint8_t purpose); const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); @@ -47,7 +47,7 @@ origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags); void circuit_mark_all_unused_circs(void); void circuit_expire_all_dirty_circs(void); -void _circuit_mark_for_close(circuit_t *circ, int reason, +void circuit_mark_for_close_(circuit_t *circ, int reason, int line, const char *file); int circuit_get_cpath_len(origin_circuit_t *circ); crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum); @@ -56,7 +56,7 @@ void circuit_get_all_pending_on_channel(smartlist_t *out, int circuit_count_pending_on_channel(channel_t *chan); #define circuit_mark_for_close(c, reason) \ - _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_) + circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__) void assert_cpath_layer_ok(const crypt_path_t *cp); void assert_circuit_ok(const circuit_t *c); diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h index a3eacaf7d4..ebab1ba7d3 100644 --- a/src/or/circuitmux.h +++ b/src/or/circuitmux.h @@ -6,8 +6,8 @@ * \brief Header file for circuitmux.c **/ -#ifndef _TOR_CIRCUITMUX_H -#define _TOR_CIRCUITMUX_H +#ifndef TOR_CIRCUITMUX_H +#define TOR_CIRCUITMUX_H #include "or.h" @@ -84,14 +84,14 @@ struct circuitmux_policy_circ_data_s { * Convert a circuitmux_policy_data_t subtype to a circuitmux_policy_data_t. */ -#define TO_CMUX_POL_DATA(x) (&((x)->_base)) +#define TO_CMUX_POL_DATA(x) (&((x)->base_)) /** * Convert a circuitmux_policy_circ_data_t subtype to a * circuitmux_policy_circ_data_t. */ -#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->_base)) +#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->base_)) /* Consistency check */ void circuitmux_assert_okay(circuitmux_t *cmux); @@ -132,5 +132,5 @@ void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ); void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells); -#endif /* _TOR_CIRCUITMUX_H */ +#endif /* TOR_CIRCUITMUX_H */ diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c index c280bf4ab0..e1964d2383 100644 --- a/src/or/circuitmux_ewma.c +++ b/src/or/circuitmux_ewma.c @@ -6,7 +6,7 @@ * \brief EWMA circuit selection as a circuitmux_t policy **/ -#define _TOR_CIRCUITMUX_EWMA_C +#define TOR_CIRCUITMUX_EWMA_C_ #include <math.h> @@ -62,7 +62,7 @@ struct cell_ewma_s { }; struct ewma_policy_data_s { - circuitmux_policy_data_t _base; + circuitmux_policy_data_t base_; /** * Priority queue of cell_ewma_t for circuits with queued cells waiting @@ -81,7 +81,7 @@ struct ewma_policy_data_s { }; struct ewma_policy_circ_data_s { - circuitmux_policy_circ_data_t _base; + circuitmux_policy_circ_data_t base_; /** * The EWMA count for the number of cells flushed from this circuit @@ -200,15 +200,16 @@ static int ewma_enabled = 0; /*** EWMA circuitmux_policy_t method table ***/ -circuitmux_policy_t ewma_policy = { .alloc_cmux_data = ewma_alloc_cmux_data, - .free_cmux_data = ewma_free_cmux_data, - .alloc_circ_data = ewma_alloc_circ_data, - .free_circ_data = ewma_free_circ_data, - .notify_circ_active = ewma_notify_circ_active, - .notify_circ_inactive = ewma_notify_circ_inactive, - .notify_set_n_cells = NULL, /* EWMA doesn't need this */ - .notify_xmit_cells = ewma_notify_xmit_cells, - .pick_active_circuit = ewma_pick_active_circuit +circuitmux_policy_t ewma_policy = { + /*.alloc_cmux_data =*/ ewma_alloc_cmux_data, + /*.free_cmux_data =*/ ewma_free_cmux_data, + /*.alloc_circ_data =*/ ewma_alloc_circ_data, + /*.free_circ_data =*/ ewma_free_circ_data, + /*.notify_circ_active =*/ ewma_notify_circ_active, + /*.notify_circ_inactive =*/ ewma_notify_circ_inactive, + /*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */ + /*.notify_xmit_cells =*/ ewma_notify_xmit_cells, + /*.pick_active_circuit =*/ ewma_pick_active_circuit }; /*** EWMA method implementations using the below EWMA helper functions ***/ @@ -226,7 +227,7 @@ ewma_alloc_cmux_data(circuitmux_t *cmux) tor_assert(cmux); pol = tor_malloc_zero(sizeof(*pol)); - pol->_base.magic = EWMA_POL_DATA_MAGIC; + pol->base_.magic = EWMA_POL_DATA_MAGIC; pol->active_circuit_pqueue = smartlist_new(); pol->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick(); @@ -276,7 +277,7 @@ ewma_alloc_circ_data(circuitmux_t *cmux, tor_assert(cell_count == cell_count); cdata = tor_malloc_zero(sizeof(*cdata)); - cdata->_base.magic = EWMA_POL_CIRC_DATA_MAGIC; + cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC; cdata->circ = circ; /* diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h index eec16f3729..5621acc936 100644 --- a/src/or/circuitmux_ewma.h +++ b/src/or/circuitmux_ewma.h @@ -6,18 +6,18 @@ * \brief Header file for circuitmux_ewma.c **/ -#ifndef _TOR_CIRCUITMUX_EWMA_H -#define _TOR_CIRCUITMUX_EWMA_H +#ifndef TOR_CIRCUITMUX_EWMA_H +#define TOR_CIRCUITMUX_EWMA_H #include "or.h" #include "circuitmux.h" /* Everything but circuitmux_ewma.c should see this extern */ -#ifndef _TOR_CIRCUITMUX_EWMA_C +#ifndef TOR_CIRCUITMUX_EWMA_C_ extern circuitmux_policy_t ewma_policy; -#endif /* !(_TOR_CIRCUITMUX_EWMA_C) */ +#endif /* !(TOR_CIRCUITMUX_EWMA_C_) */ /* Externally visible EWMA functions */ int cell_ewma_enabled(void); @@ -25,5 +25,5 @@ unsigned int cell_ewma_get_tick(void); void cell_ewma_set_scale_factor(const or_options_t *options, const networkstatus_t *consensus); -#endif /* _TOR_CIRCUITMUX_EWMA_H */ +#endif /* TOR_CIRCUITMUX_EWMA_H */ diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c new file mode 100644 index 0000000000..6d529d1e43 --- /dev/null +++ b/src/or/circuitstats.c @@ -0,0 +1,1569 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2012, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CIRCUITSTATS_PRIVATE + +#include "or.h" +#include "circuitbuild.h" +#include "circuitstats.h" +#include "config.h" +#include "confparse.h" +#include "control.h" +#include "networkstatus.h" +#include "statefile.h" + +#undef log +#include <math.h> + +#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2)) + +/** Global list of circuit build times */ +// XXXX: Add this as a member for entry_guard_t instead of global? +// Then we could do per-guard statistics, as guards are likely to +// vary in their own latency. The downside of this is that guards +// can change frequently, so we'd be building a lot more circuits +// most likely. +/* XXXX024 Make this static; add accessor functions. */ +circuit_build_times_t circ_times; + +/** If set, we're running the unit tests: we should avoid clobbering + * our state file or accessing get_options() or get_or_state() */ +static int unit_tests = 0; + +/** + * This function decides if CBT learning should be disabled. It returns + * true if one or more of the following four conditions are met: + * + * 1. If the cbtdisabled consensus parameter is set. + * 2. If the torrc option LearnCircuitBuildTimeout is false. + * 3. If we are a directory authority + * 4. If we fail to write circuit build time history to our state file. + */ +int +circuit_build_times_disabled(void) +{ + if (unit_tests) { + return 0; + } else { + int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", + 0, 0, 1); + int config_disabled = !get_options()->LearnCircuitBuildTimeout; + int dirauth_disabled = get_options()->AuthoritativeDir; + int state_disabled = did_last_state_file_write_fail() ? 1 : 0; + + if (consensus_disabled || config_disabled || dirauth_disabled || + state_disabled) { + log_debug(LD_CIRC, + "CircuitBuildTime learning is disabled. " + "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", + consensus_disabled, config_disabled, dirauth_disabled, + state_disabled); + return 1; + } else { + log_debug(LD_CIRC, + "CircuitBuildTime learning is not disabled. " + "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", + consensus_disabled, config_disabled, dirauth_disabled, + state_disabled); + return 0; + } + } +} + +/** + * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter. + * + * Effect: When this many timeouts happen in the last 'cbtrecentcount' + * circuit attempts, the client should discard all of its history and + * begin learning a fresh timeout value. + */ +static int32_t +circuit_build_times_max_timeouts(void) +{ + int32_t cbt_maxtimeouts; + + cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts", + CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT, + CBT_MIN_MAX_RECENT_TIMEOUT_COUNT, + CBT_MAX_MAX_RECENT_TIMEOUT_COUNT); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is" + " %d", + cbt_maxtimeouts); + } + + return cbt_maxtimeouts; +} + +/** + * Retrieve and bounds-check the cbtnummodes consensus paramter. + * + * Effect: This value governs how many modes to use in the weighted + * average calculation of Pareto parameter Xm. A value of 3 introduces + * some bias (2-5% of CDF) under ideal conditions, but allows for better + * performance in the event that a client chooses guard nodes of radically + * different performance characteristics. + */ +static int32_t +circuit_build_times_default_num_xm_modes(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtnummodes", + CBT_DEFAULT_NUM_XM_MODES, + CBT_MIN_NUM_XM_MODES, + CBT_MAX_NUM_XM_MODES); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_default_num_xm_modes() called, cbtnummodes" + " is %d", + num); + } + + return num; +} + +/** + * Retrieve and bounds-check the cbtmincircs consensus paramter. + * + * Effect: This is the minimum number of circuits to build before + * computing a timeout. + */ +static int32_t +circuit_build_times_min_circs_to_observe(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtmincircs", + CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE, + CBT_MIN_MIN_CIRCUITS_TO_OBSERVE, + CBT_MAX_MIN_CIRCUITS_TO_OBSERVE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_min_circs_to_observe() called, cbtmincircs" + " is %d", + num); + } + + return num; +} + +/** Return true iff <b>cbt</b> has recorded enough build times that we + * want to start acting on the timeout it implies. */ +int +circuit_build_times_enough_to_compute(circuit_build_times_t *cbt) +{ + return cbt->total_build_times >= circuit_build_times_min_circs_to_observe(); +} + +/** + * Retrieve and bounds-check the cbtquantile consensus paramter. + * + * Effect: This is the position on the quantile curve to use to set the + * timeout value. It is a percent (10-99). + */ +double +circuit_build_times_quantile_cutoff(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtquantile", + CBT_DEFAULT_QUANTILE_CUTOFF, + CBT_MIN_QUANTILE_CUTOFF, + CBT_MAX_QUANTILE_CUTOFF); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_quantile_cutoff() called, cbtquantile" + " is %d", + num); + } + + return num/100.0; +} + +/* DOCDOC circuit_build_times_get_bw_scale */ +int +circuit_build_times_get_bw_scale(networkstatus_t *ns) +{ + return networkstatus_get_param(ns, "bwweightscale", + BW_WEIGHT_SCALE, + BW_MIN_WEIGHT_SCALE, + BW_MAX_WEIGHT_SCALE); +} + +/** + * Retrieve and bounds-check the cbtclosequantile consensus paramter. + * + * Effect: This is the position on the quantile curve to use to set the + * timeout value to use to actually close circuits. It is a percent + * (0-99). + */ +static double +circuit_build_times_close_quantile(void) +{ + int32_t param; + /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */ + int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff()); + param = networkstatus_get_param(NULL, "cbtclosequantile", + CBT_DEFAULT_CLOSE_QUANTILE, + CBT_MIN_CLOSE_QUANTILE, + CBT_MAX_CLOSE_QUANTILE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_close_quantile() called, cbtclosequantile" + " is %d", param); + } + + if (param < min) { + log_warn(LD_DIR, "Consensus parameter cbtclosequantile is " + "too small, raising to %d", min); + param = min; + } + return param / 100.0; +} + +/** + * Retrieve and bounds-check the cbttestfreq consensus paramter. + * + * Effect: Describes how often in seconds to build a test circuit to + * gather timeout values. Only applies if less than 'cbtmincircs' + * have been recorded. + */ +static int32_t +circuit_build_times_test_frequency(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbttestfreq", + CBT_DEFAULT_TEST_FREQUENCY, + CBT_MIN_TEST_FREQUENCY, + CBT_MAX_TEST_FREQUENCY); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_test_frequency() called, cbttestfreq is %d", + num); + } + + return num; +} + +/** + * Retrieve and bounds-check the cbtmintimeout consensus parameter. + * + * Effect: This is the minimum allowed timeout value in milliseconds. + * The minimum is to prevent rounding to 0 (we only check once + * per second). + */ +static int32_t +circuit_build_times_min_timeout(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", + CBT_DEFAULT_TIMEOUT_MIN_VALUE, + CBT_MIN_TIMEOUT_MIN_VALUE, + CBT_MAX_TIMEOUT_MIN_VALUE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_min_timeout() called, cbtmintimeout is %d", + num); + } + + return num; +} + +/** + * Retrieve and bounds-check the cbtinitialtimeout consensus paramter. + * + * Effect: This is the timeout value to use before computing a timeout, + * in milliseconds. + */ +int32_t +circuit_build_times_initial_timeout(void) +{ + int32_t min = circuit_build_times_min_timeout(); + int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout", + CBT_DEFAULT_TIMEOUT_INITIAL_VALUE, + CBT_MIN_TIMEOUT_INITIAL_VALUE, + CBT_MAX_TIMEOUT_INITIAL_VALUE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_initial_timeout() called, " + "cbtinitialtimeout is %d", + param); + } + + if (param < min) { + log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, " + "raising to %d", min); + param = min; + } + return param; +} + +/** + * Retrieve and bounds-check the cbtrecentcount consensus paramter. + * + * Effect: This is the number of circuit build times to keep track of + * for deciding if we hit cbtmaxtimeouts and need to reset our state + * and learn a new timeout. + */ +static int32_t +circuit_build_times_recent_circuit_count(networkstatus_t *ns) +{ + int32_t num; + num = networkstatus_get_param(ns, "cbtrecentcount", + CBT_DEFAULT_RECENT_CIRCUITS, + CBT_MIN_RECENT_CIRCUITS, + CBT_MAX_RECENT_CIRCUITS); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_recent_circuit_count() called, " + "cbtrecentcount is %d", + num); + } + + return num; +} + +/** + * This function is called when we get a consensus update. + * + * It checks to see if we have changed any consensus parameters + * that require reallocation or discard of previous stats. + */ +void +circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, + networkstatus_t *ns) +{ + int32_t num; + + /* + * First check if we're doing adaptive timeouts at all; nothing to + * update if we aren't. + */ + + if (!circuit_build_times_disabled()) { + num = circuit_build_times_recent_circuit_count(ns); + + if (num > 0) { + if (num != cbt->liveness.num_recent_circs) { + int8_t *recent_circs; + log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many " + "circuits we must track to detect network failures from %d " + "to %d.", cbt->liveness.num_recent_circs, num); + + tor_assert(cbt->liveness.timeouts_after_firsthop || + cbt->liveness.num_recent_circs == 0); + + /* + * Technically this is a circular array that we are reallocating + * and memcopying. However, since it only consists of either 1s + * or 0s, and is only used in a statistical test to determine when + * we should discard our history after a sufficient number of 1's + * have been reached, it is fine if order is not preserved or + * elements are lost. + * + * cbtrecentcount should only be changing in cases of severe network + * distress anyway, so memory correctness here is paramount over + * doing acrobatics to preserve the array. + */ + recent_circs = tor_malloc_zero(sizeof(int8_t)*num); + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, + sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); + } + + // Adjust the index if it needs it. + if (num < cbt->liveness.num_recent_circs) { + cbt->liveness.after_firsthop_idx = MIN(num-1, + cbt->liveness.after_firsthop_idx); + } + + tor_free(cbt->liveness.timeouts_after_firsthop); + cbt->liveness.timeouts_after_firsthop = recent_circs; + cbt->liveness.num_recent_circs = num; + } + /* else no change, nothing to do */ + } else { /* num == 0 */ + /* + * Weird. This probably shouldn't happen, so log a warning, but try + * to do something sensible anyway. + */ + + log_warn(LD_CIRC, + "The cbtrecentcircs consensus parameter came back zero! " + "This disables adaptive timeouts since we can't keep track of " + "any recent circuits."); + + circuit_build_times_free_timeouts(cbt); + } + } else { + /* + * Adaptive timeouts are disabled; this might be because of the + * LearnCircuitBuildTimes config parameter, and hence permanent, or + * the cbtdisabled consensus parameter, so it may be a new condition. + * Treat it like getting num == 0 above and free the circuit history + * if we have any. + */ + + circuit_build_times_free_timeouts(cbt); + } +} + +/** + * Return the initial default or configured timeout in milliseconds + */ +static double +circuit_build_times_get_initial_timeout(void) +{ + double timeout; + + /* + * Check if we have LearnCircuitBuildTimeout, and if we don't, + * always use CircuitBuildTimeout, no questions asked. + */ + if (get_options()->LearnCircuitBuildTimeout) { + if (!unit_tests && get_options()->CircuitBuildTimeout) { + timeout = get_options()->CircuitBuildTimeout*1000; + if (timeout < circuit_build_times_min_timeout()) { + log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", + circuit_build_times_min_timeout()/1000); + timeout = circuit_build_times_min_timeout(); + } + } else { + timeout = circuit_build_times_initial_timeout(); + } + } else { + timeout = get_options()->CircuitBuildTimeout*1000; + } + + return timeout; +} + +/** + * Reset the build time state. + * + * Leave estimated parameters, timeout and network liveness intact + * for future use. + */ +void +circuit_build_times_reset(circuit_build_times_t *cbt) +{ + memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times)); + cbt->total_build_times = 0; + cbt->build_times_idx = 0; + cbt->have_computed_timeout = 0; +} + +/** + * Initialize the buildtimes structure for first use. + * + * Sets the initial timeout values based on either the config setting, + * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE). + */ +void +circuit_build_times_init(circuit_build_times_t *cbt) +{ + memset(cbt, 0, sizeof(*cbt)); + /* + * Check if we really are using adaptive timeouts, and don't keep + * track of this stuff if not. + */ + if (!circuit_build_times_disabled()) { + cbt->liveness.num_recent_circs = + circuit_build_times_recent_circuit_count(NULL); + cbt->liveness.timeouts_after_firsthop = + tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs); + } else { + cbt->liveness.num_recent_circs = 0; + cbt->liveness.timeouts_after_firsthop = NULL; + } + cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); + control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); +} + +/** + * Free the saved timeouts, if the cbtdisabled consensus parameter got turned + * on or something. + */ + +void +circuit_build_times_free_timeouts(circuit_build_times_t *cbt) +{ + if (!cbt) return; + + if (cbt->liveness.timeouts_after_firsthop) { + tor_free(cbt->liveness.timeouts_after_firsthop); + } + + cbt->liveness.num_recent_circs = 0; +} + +#if 0 +/** + * Rewind our build time history by n positions. + */ +static void +circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) +{ + int i = 0; + + cbt->build_times_idx -= n; + cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE; + + for (i = 0; i < n; i++) { + cbt->circuit_build_times[(i+cbt->build_times_idx) + %CBT_NCIRCUITS_TO_OBSERVE]=0; + } + + if (cbt->total_build_times > n) { + cbt->total_build_times -= n; + } else { + cbt->total_build_times = 0; + } + + log_info(LD_CIRC, + "Rewound history by %d places. Current index: %d. " + "Total: %d", n, cbt->build_times_idx, cbt->total_build_times); +} +#endif + +/** + * Add a new build time value <b>time</b> to the set of build times. Time + * units are milliseconds. + * + * circuit_build_times <b>cbt</b> is a circular array, so loop around when + * array is full. + */ +int +circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) +{ + if (time <= 0 || time > CBT_BUILD_TIME_MAX) { + log_warn(LD_BUG, "Circuit build time is too large (%u)." + "This is probably a bug.", time); + tor_fragile_assert(); + return -1; + } + + log_debug(LD_CIRC, "Adding circuit build time %u", time); + + cbt->circuit_build_times[cbt->build_times_idx] = time; + cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; + if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) + cbt->total_build_times++; + + if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { + /* Save state every n circuit builds */ + if (!unit_tests && !get_options()->AvoidDiskWrites) + or_state_mark_dirty(get_or_state(), 0); + } + + return 0; +} + +/** + * Return maximum circuit build time + */ +static build_time_t +circuit_build_times_max(circuit_build_times_t *cbt) +{ + int i = 0; + build_time_t max_build_time = 0; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] > max_build_time + && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED) + max_build_time = cbt->circuit_build_times[i]; + } + return max_build_time; +} + +#if 0 +/** Return minimum circuit build time */ +build_time_t +circuit_build_times_min(circuit_build_times_t *cbt) +{ + int i = 0; + build_time_t min_build_time = CBT_BUILD_TIME_MAX; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */ + cbt->circuit_build_times[i] < min_build_time) + min_build_time = cbt->circuit_build_times[i]; + } + if (min_build_time == CBT_BUILD_TIME_MAX) { + log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!"); + } + return min_build_time; +} +#endif + +/** + * Calculate and return a histogram for the set of build times. + * + * Returns an allocated array of histrogram bins representing + * the frequency of index*CBT_BIN_WIDTH millisecond + * build times. Also outputs the number of bins in nbins. + * + * The return value must be freed by the caller. + */ +static uint32_t * +circuit_build_times_create_histogram(circuit_build_times_t *cbt, + build_time_t *nbins) +{ + uint32_t *histogram; + build_time_t max_build_time = circuit_build_times_max(cbt); + int i, c; + + *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); + histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); + + // calculate histogram + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] == 0 + || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) + continue; /* 0 <-> uninitialized */ + + c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH); + histogram[c]++; + } + + return histogram; +} + +/** + * Return the Pareto start-of-curve parameter Xm. + * + * Because we are not a true Pareto curve, we compute this as the + * weighted average of the N most frequent build time bins. N is either + * 1 if we don't have enough circuit build time data collected, or + * determined by the consensus parameter cbtnummodes (default 3). + */ +static build_time_t +circuit_build_times_get_xm(circuit_build_times_t *cbt) +{ + build_time_t i, nbins; + build_time_t *nth_max_bin; + int32_t bin_counts=0; + build_time_t ret = 0; + uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins); + int n=0; + int num_modes = circuit_build_times_default_num_xm_modes(); + + tor_assert(nbins > 0); + tor_assert(num_modes > 0); + + // Only use one mode if < 1000 buildtimes. Not enough data + // for multiple. + if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) + num_modes = 1; + + nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t)); + + /* Determine the N most common build times */ + for (i = 0; i < nbins; i++) { + if (histogram[i] >= histogram[nth_max_bin[0]]) { + nth_max_bin[0] = i; + } + + for (n = 1; n < num_modes; n++) { + if (histogram[i] >= histogram[nth_max_bin[n]] && + (!histogram[nth_max_bin[n-1]] + || histogram[i] < histogram[nth_max_bin[n-1]])) { + nth_max_bin[n] = i; + } + } + } + + for (n = 0; n < num_modes; n++) { + bin_counts += histogram[nth_max_bin[n]]; + ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]]; + log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]), + histogram[nth_max_bin[n]]); + } + + /* The following assert is safe, because we don't get called when we + * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */ + tor_assert(bin_counts > 0); + + ret /= bin_counts; + tor_free(histogram); + tor_free(nth_max_bin); + + return ret; +} + +/** + * Output a histogram of current circuit build times to + * the or_state_t state structure. + */ +void +circuit_build_times_update_state(circuit_build_times_t *cbt, + or_state_t *state) +{ + uint32_t *histogram; + build_time_t i = 0; + build_time_t nbins = 0; + config_line_t **next, *line; + + histogram = circuit_build_times_create_histogram(cbt, &nbins); + // write to state + config_free_lines(state->BuildtimeHistogram); + next = &state->BuildtimeHistogram; + *next = NULL; + + state->TotalBuildTimes = cbt->total_build_times; + state->CircuitBuildAbandonedCount = 0; + + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) + state->CircuitBuildAbandonedCount++; + } + + for (i = 0; i < nbins; i++) { + // compress the histogram by skipping the blanks + if (histogram[i] == 0) continue; + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("CircuitBuildTimeBin"); + tor_asprintf(&line->value, "%d %d", + CBT_BIN_TO_MS(i), histogram[i]); + next = &(line->next); + } + + if (!unit_tests) { + if (!get_options()->AvoidDiskWrites) + or_state_mark_dirty(get_or_state(), 0); + } + + tor_free(histogram); +} + +/** + * Shuffle the build times array. + * + * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + */ +static void +circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, + build_time_t *raw_times, + uint32_t num_times) +{ + uint32_t n = num_times; + if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { + log_notice(LD_CIRC, "The number of circuit times that this Tor version " + "uses to calculate build times is less than the number stored " + "in your state file. Decreasing the circuit time history from " + "%lu to %d.", (unsigned long)num_times, + CBT_NCIRCUITS_TO_OBSERVE); + } + + if (n > INT_MAX-1) { + log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build " + "observations in your state file. That's far too many; probably " + "there's a bug here.", (unsigned long)n); + n = INT_MAX-1; + } + + /* This code can only be run on a compact array */ + while (n-- > 1) { + int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */ + build_time_t tmp = raw_times[k]; + raw_times[k] = raw_times[n]; + raw_times[n] = tmp; + } + + /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE + * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ + for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { + circuit_build_times_add_time(cbt, raw_times[n]); + } +} + +/** + * Filter old synthetic timeouts that were created before the + * new right-censored Pareto calculation was deployed. + * + * Once all clients before 0.2.1.13-alpha are gone, this code + * will be unused. + */ +static int +circuit_build_times_filter_timeouts(circuit_build_times_t *cbt) +{ + int num_filtered=0, i=0; + double timeout_rate = 0; + build_time_t max_timeout = 0; + + timeout_rate = circuit_build_times_timeout_rate(cbt); + max_timeout = (build_time_t)cbt->close_ms; + + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] > max_timeout) { + build_time_t replaced = cbt->circuit_build_times[i]; + num_filtered++; + cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED; + + log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced, + cbt->circuit_build_times[i]); + } + } + + log_info(LD_CIRC, + "We had %d timeouts out of %d build times, " + "and filtered %d above the max of %u", + (int)(cbt->total_build_times*timeout_rate), + cbt->total_build_times, num_filtered, max_timeout); + + return num_filtered; +} + +/** + * Load histogram from <b>state</b>, shuffling the resulting array + * after we do so. Use this result to estimate parameters and + * calculate the timeout. + * + * Return -1 on error. + */ +int +circuit_build_times_parse_state(circuit_build_times_t *cbt, + or_state_t *state) +{ + int tot_values = 0; + uint32_t loaded_cnt = 0, N = 0; + config_line_t *line; + unsigned int i; + build_time_t *loaded_times; + int err = 0; + circuit_build_times_init(cbt); + + if (circuit_build_times_disabled()) { + return 0; + } + + /* build_time_t 0 means uninitialized */ + loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes); + + for (line = state->BuildtimeHistogram; line; line = line->next) { + smartlist_t *args = smartlist_new(); + smartlist_split_string(args, line->value, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(args) < 2) { + log_warn(LD_GENERAL, "Unable to parse circuit build times: " + "Too few arguments to CircuitBuildTime"); + err = 1; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } else { + const char *ms_str = smartlist_get(args,0); + const char *count_str = smartlist_get(args,1); + uint32_t count, k; + build_time_t ms; + int ok; + ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, + CBT_BUILD_TIME_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_GENERAL, "Unable to parse circuit build times: " + "Unparsable bin number"); + err = 1; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } + count = (uint32_t)tor_parse_ulong(count_str, 0, 0, + UINT32_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_GENERAL, "Unable to parse circuit build times: " + "Unparsable bin count"); + err = 1; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } + + if (loaded_cnt+count+state->CircuitBuildAbandonedCount + > state->TotalBuildTimes) { + log_warn(LD_CIRC, + "Too many build times in state file. " + "Stopping short before %d", + loaded_cnt+count); + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } + + for (k = 0; k < count; k++) { + loaded_times[loaded_cnt++] = ms; + } + N++; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + } + } + + log_info(LD_CIRC, + "Adding %d timeouts.", state->CircuitBuildAbandonedCount); + for (i=0; i < state->CircuitBuildAbandonedCount; i++) { + loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED; + } + + if (loaded_cnt != state->TotalBuildTimes) { + log_warn(LD_CIRC, + "Corrupt state file? Build times count mismatch. " + "Read %d times, but file says %d", loaded_cnt, + state->TotalBuildTimes); + err = 1; + circuit_build_times_reset(cbt); + goto done; + } + + circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); + + /* Verify that we didn't overwrite any indexes */ + for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (!cbt->circuit_build_times[i]) + break; + tot_values++; + } + log_info(LD_CIRC, + "Loaded %d/%d values from %d lines in circuit time histogram", + tot_values, cbt->total_build_times, N); + + if (cbt->total_build_times != tot_values + || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) { + log_warn(LD_CIRC, + "Corrupt state file? Shuffled build times mismatch. " + "Read %d times, but file says %d", tot_values, + state->TotalBuildTimes); + err = 1; + circuit_build_times_reset(cbt); + goto done; + } + + circuit_build_times_set_timeout(cbt); + + if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) { + circuit_build_times_filter_timeouts(cbt); + } + + done: + tor_free(loaded_times); + return err ? -1 : 0; +} + +/** + * Estimates the Xm and Alpha parameters using + * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation + * + * The notable difference is that we use mode instead of min to estimate Xm. + * This is because our distribution is frechet-like. We claim this is + * an acceptable approximation because we are only concerned with the + * accuracy of the CDF of the tail. + */ +int +circuit_build_times_update_alpha(circuit_build_times_t *cbt) +{ + build_time_t *x=cbt->circuit_build_times; + double a = 0; + int n=0,i=0,abandoned_count=0; + build_time_t max_time=0; + + /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */ + /* We sort of cheat here and make our samples slightly more pareto-like + * and less frechet-like. */ + cbt->Xm = circuit_build_times_get_xm(cbt); + + tor_assert(cbt->Xm > 0); + + for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (!x[i]) { + continue; + } + + if (x[i] < cbt->Xm) { + a += tor_mathlog(cbt->Xm); + } else if (x[i] == CBT_BUILD_ABANDONED) { + abandoned_count++; + } else { + a += tor_mathlog(x[i]); + if (x[i] > max_time) + max_time = x[i]; + } + n++; + } + + /* + * We are erring and asserting here because this can only happen + * in codepaths other than startup. The startup state parsing code + * performs this same check, and resets state if it hits it. If we + * hit it at runtime, something serious has gone wrong. + */ + if (n!=cbt->total_build_times) { + log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n, + cbt->total_build_times); + } + tor_assert(n==cbt->total_build_times); + + if (max_time <= 0) { + /* This can happen if Xm is actually the *maximum* value in the set. + * It can also happen if we've abandoned every single circuit somehow. + * In either case, tell the caller not to compute a new build timeout. */ + log_warn(LD_BUG, + "Could not determine largest build time (%d). " + "Xm is %dms and we've abandoned %d out of %d circuits.", max_time, + cbt->Xm, abandoned_count, n); + return 0; + } + + a += abandoned_count*tor_mathlog(max_time); + + a -= n*tor_mathlog(cbt->Xm); + // Estimator comes from Eq #4 in: + // "Bayesian estimation based on trimmed samples from Pareto populations" + // by Arturo J. Fernández. We are right-censored only. + a = (n-abandoned_count)/a; + + cbt->alpha = a; + + return 1; +} + +/** + * This is the Pareto Quantile Function. It calculates the point x + * in the distribution such that F(x) = quantile (ie quantile*100% + * of the mass of the density function is below x on the curve). + * + * We use it to calculate the timeout and also to generate synthetic + * values of time for circuits that timeout before completion. + * + * See http://en.wikipedia.org/wiki/Quantile_function, + * http://en.wikipedia.org/wiki/Inverse_transform_sampling and + * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_ + * random_sample_from_Pareto_distribution + * That's right. I'll cite wikipedia all day long. + * + * Return value is in milliseconds. + */ +double +circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, + double quantile) +{ + double ret; + tor_assert(quantile >= 0); + tor_assert(1.0-quantile > 0); + tor_assert(cbt->Xm > 0); + + ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha); + if (ret > INT32_MAX) { + ret = INT32_MAX; + } + tor_assert(ret > 0); + return ret; +} + +/** Pareto CDF */ +double +circuit_build_times_cdf(circuit_build_times_t *cbt, double x) +{ + double ret; + tor_assert(cbt->Xm > 0); + ret = 1.0-pow(cbt->Xm/x,cbt->alpha); + tor_assert(0 <= ret && ret <= 1.0); + return ret; +} + +/** + * Generate a synthetic time using our distribution parameters. + * + * The return value will be within the [q_lo, q_hi) quantile points + * on the CDF. + */ +build_time_t +circuit_build_times_generate_sample(circuit_build_times_t *cbt, + double q_lo, double q_hi) +{ + double randval = crypto_rand_double(); + build_time_t ret; + double u; + + /* Generate between [q_lo, q_hi) */ + /*XXXX This is what nextafter is supposed to be for; we should use it on the + * platforms that support it. */ + q_hi -= 1.0/(INT32_MAX); + + tor_assert(q_lo >= 0); + tor_assert(q_hi < 1); + tor_assert(q_lo < q_hi); + + u = q_lo + (q_hi-q_lo)*randval; + + tor_assert(0 <= u && u < 1.0); + /* circuit_build_times_calculate_timeout returns <= INT32_MAX */ + ret = (build_time_t) + tor_lround(circuit_build_times_calculate_timeout(cbt, u)); + tor_assert(ret > 0); + return ret; +} + +/** + * Estimate an initial alpha parameter by solving the quantile + * function with a quantile point and a specific timeout value. + */ +void +circuit_build_times_initial_alpha(circuit_build_times_t *cbt, + double quantile, double timeout_ms) +{ + // Q(u) = Xm/((1-u)^(1/a)) + // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout + // CircBuildTimeout = Xm/((1-0.8))^(1/a)) + // CircBuildTimeout = Xm*((1-0.8))^(-1/a)) + // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a) + // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a + tor_assert(quantile >= 0); + tor_assert(cbt->Xm > 0); + cbt->alpha = tor_mathlog(1.0-quantile)/ + (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms)); + tor_assert(cbt->alpha > 0); +} + +/** + * Returns true if we need circuits to be built + */ +int +circuit_build_times_needs_circuits(circuit_build_times_t *cbt) +{ + /* Return true if < MIN_CIRCUITS_TO_OBSERVE */ + return !circuit_build_times_enough_to_compute(cbt); +} + +/** + * Returns true if we should build a timeout test circuit + * right now. + */ +int +circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt) +{ + return circuit_build_times_needs_circuits(cbt) && + approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); +} + +/** + * Called to indicate that the network showed some signs of liveness, + * i.e. we received a cell. + * + * This is used by circuit_build_times_network_check_live() to decide + * if we should record the circuit build timeout or not. + * + * This function is called every time we receive a cell. Avoid + * syscalls, events, and other high-intensity work. + */ +void +circuit_build_times_network_is_live(circuit_build_times_t *cbt) +{ + time_t now = approx_time(); + if (cbt->liveness.nonlive_timeouts > 0) { + log_notice(LD_CIRC, + "Tor now sees network activity. Restoring circuit build " + "timeout recording. Network was down for %d seconds " + "during %d circuit attempts.", + (int)(now - cbt->liveness.network_last_live), + cbt->liveness.nonlive_timeouts); + } + cbt->liveness.network_last_live = now; + cbt->liveness.nonlive_timeouts = 0; +} + +/** + * Called to indicate that we completed a circuit. Because this circuit + * succeeded, it doesn't count as a timeout-after-the-first-hop. + * + * This is used by circuit_build_times_network_check_changed() to determine + * if we had too many recent timeouts and need to reset our learned timeout + * to something higher. + */ +void +circuit_build_times_network_circ_success(circuit_build_times_t *cbt) +{ + /* Check for NULLness because we might not be using adaptive timeouts */ + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] + = 0; + cbt->liveness.after_firsthop_idx++; + cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + } +} + +/** + * A circuit just timed out. If it failed after the first hop, record it + * in our history for later deciding if the network speed has changed. + * + * This is used by circuit_build_times_network_check_changed() to determine + * if we had too many recent timeouts and need to reset our learned timeout + * to something higher. + */ +static void +circuit_build_times_network_timeout(circuit_build_times_t *cbt, + int did_onehop) +{ + /* Check for NULLness because we might not be using adaptive timeouts */ + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + if (did_onehop) { + cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] + = 1; + cbt->liveness.after_firsthop_idx++; + cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + } + } +} + +/** + * A circuit was just forcibly closed. If there has been no recent network + * activity at all, but this circuit was launched back when we thought the + * network was live, increment the number of "nonlive" circuit timeouts. + * + * This is used by circuit_build_times_network_check_live() to decide + * if we should record the circuit build timeout or not. + */ +static void +circuit_build_times_network_close(circuit_build_times_t *cbt, + int did_onehop, time_t start_time) +{ + time_t now = time(NULL); + /* + * Check if this is a timeout that was for a circuit that spent its + * entire existence during a time where we have had no network activity. + */ + if (cbt->liveness.network_last_live < start_time) { + if (did_onehop) { + char last_live_buf[ISO_TIME_LEN+1]; + char start_time_buf[ISO_TIME_LEN+1]; + char now_buf[ISO_TIME_LEN+1]; + format_local_iso_time(last_live_buf, cbt->liveness.network_last_live); + format_local_iso_time(start_time_buf, start_time); + format_local_iso_time(now_buf, now); + log_warn(LD_BUG, + "Circuit somehow completed a hop while the network was " + "not live. Network was last live at %s, but circuit launched " + "at %s. It's now %s.", last_live_buf, start_time_buf, + now_buf); + } + cbt->liveness.nonlive_timeouts++; + if (cbt->liveness.nonlive_timeouts == 1) { + log_notice(LD_CIRC, + "Tor has not observed any network activity for the past %d " + "seconds. Disabling circuit build timeout recording.", + (int)(now - cbt->liveness.network_last_live)); + } else { + log_info(LD_CIRC, + "Got non-live timeout. Current count is: %d", + cbt->liveness.nonlive_timeouts); + } + } +} + +/** + * When the network is not live, we do not record circuit build times. + * + * The network is considered not live if there has been at least one + * circuit build that began and ended (had its close_ms measurement + * period expire) since we last received a cell. + * + * Also has the side effect of rewinding the circuit time history + * in the case of recent liveness changes. + */ +int +circuit_build_times_network_check_live(circuit_build_times_t *cbt) +{ + if (cbt->liveness.nonlive_timeouts > 0) { + return 0; + } + + return 1; +} + +/** + * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of + * the past RECENT_CIRCUITS time out after the first hop. Used to detect + * if the network connection has changed significantly, and if so, + * resets our circuit build timeout to the default. + * + * Also resets the entire timeout history in this case and causes us + * to restart the process of building test circuits and estimating a + * new timeout. + */ +int +circuit_build_times_network_check_changed(circuit_build_times_t *cbt) +{ + int total_build_times = cbt->total_build_times; + int timeout_count=0; + int i; + + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + /* how many of our recent circuits made it to the first hop but then + * timed out? */ + for (i = 0; i < cbt->liveness.num_recent_circs; i++) { + timeout_count += cbt->liveness.timeouts_after_firsthop[i]; + } + } + + /* If 80% of our recent circuits are timing out after the first hop, + * we need to re-estimate a new initial alpha and timeout. */ + if (timeout_count < circuit_build_times_max_timeouts()) { + return 0; + } + + circuit_build_times_reset(cbt); + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + memset(cbt->liveness.timeouts_after_firsthop, 0, + sizeof(*cbt->liveness.timeouts_after_firsthop)* + cbt->liveness.num_recent_circs); + } + cbt->liveness.after_firsthop_idx = 0; + + /* Check to see if this has happened before. If so, double the timeout + * to give people on abysmally bad network connections a shot at access */ + if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) { + if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) { + log_warn(LD_CIRC, "Insanely large circuit build timeout value. " + "(timeout = %fmsec, close = %fmsec)", + cbt->timeout_ms, cbt->close_ms); + } else { + cbt->timeout_ms *= 2; + cbt->close_ms *= 2; + } + } else { + cbt->close_ms = cbt->timeout_ms + = circuit_build_times_get_initial_timeout(); + } + + control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); + + log_notice(LD_CIRC, + "Your network connection speed appears to have changed. Resetting " + "timeout to %lds after %d timeouts and %d buildtimes.", + tor_lround(cbt->timeout_ms/1000), timeout_count, + total_build_times); + + return 1; +} + +/** + * Count the number of timeouts in a set of cbt data. + */ +double +circuit_build_times_timeout_rate(const circuit_build_times_t *cbt) +{ + int i=0,timeouts=0; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] >= cbt->timeout_ms) { + timeouts++; + } + } + + if (!cbt->total_build_times) + return 0; + + return ((double)timeouts)/cbt->total_build_times; +} + +/** + * Count the number of closed circuits in a set of cbt data. + */ +double +circuit_build_times_close_rate(const circuit_build_times_t *cbt) +{ + int i=0,closed=0; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) { + closed++; + } + } + + if (!cbt->total_build_times) + return 0; + + return ((double)closed)/cbt->total_build_times; +} + +/** + * Store a timeout as a synthetic value. + * + * Returns true if the store was successful and we should possibly + * update our timeout estimate. + */ +int +circuit_build_times_count_close(circuit_build_times_t *cbt, + int did_onehop, + time_t start_time) +{ + if (circuit_build_times_disabled()) { + cbt->close_ms = cbt->timeout_ms + = circuit_build_times_get_initial_timeout(); + return 0; + } + + /* Record this force-close to help determine if the network is dead */ + circuit_build_times_network_close(cbt, did_onehop, start_time); + + /* Only count timeouts if network is live.. */ + if (!circuit_build_times_network_check_live(cbt)) { + return 0; + } + + circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED); + return 1; +} + +/** + * Update timeout counts to determine if we need to expire + * our build time history due to excessive timeouts. + * + * We do not record any actual time values at this stage; + * we are only interested in recording the fact that a timeout + * happened. We record the time values via + * circuit_build_times_count_close() and circuit_build_times_add_time(). + */ +void +circuit_build_times_count_timeout(circuit_build_times_t *cbt, + int did_onehop) +{ + if (circuit_build_times_disabled()) { + cbt->close_ms = cbt->timeout_ms + = circuit_build_times_get_initial_timeout(); + return; + } + + /* Register the fact that a timeout just occurred. */ + circuit_build_times_network_timeout(cbt, did_onehop); + + /* If there are a ton of timeouts, we should reset + * the circuit build timeout. */ + circuit_build_times_network_check_changed(cbt); +} + +/** + * Estimate a new timeout based on history and set our timeout + * variable accordingly. + */ +static int +circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt) +{ + build_time_t max_time; + if (!circuit_build_times_enough_to_compute(cbt)) + return 0; + + if (!circuit_build_times_update_alpha(cbt)) + return 0; + + cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt, + circuit_build_times_quantile_cutoff()); + + cbt->close_ms = circuit_build_times_calculate_timeout(cbt, + circuit_build_times_close_quantile()); + + max_time = circuit_build_times_max(cbt); + + /* Sometimes really fast guard nodes give us such a steep curve + * that this ends up being not that much greater than timeout_ms. + * Make it be at least 1 min to handle this case. */ + cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout()); + + if (cbt->timeout_ms > max_time) { + log_info(LD_CIRC, + "Circuit build timeout of %dms is beyond the maximum build " + "time we have ever observed. Capping it to %dms.", + (int)cbt->timeout_ms, max_time); + cbt->timeout_ms = max_time; + } + + if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) { + log_info(LD_CIRC, + "Circuit build measurement period of %dms is more than twice " + "the maximum build time we have ever observed. Capping it to " + "%dms.", (int)cbt->close_ms, 2*max_time); + cbt->close_ms = 2*max_time; + } + + cbt->have_computed_timeout = 1; + return 1; +} + +/** + * Exposed function to compute a new timeout. Dispatches events and + * also filters out extremely high timeout values. + */ +void +circuit_build_times_set_timeout(circuit_build_times_t *cbt) +{ + long prev_timeout = tor_lround(cbt->timeout_ms/1000); + double timeout_rate; + + /* + * Just return if we aren't using adaptive timeouts + */ + if (circuit_build_times_disabled()) + return; + + if (!circuit_build_times_set_timeout_worker(cbt)) + return; + + if (cbt->timeout_ms < circuit_build_times_min_timeout()) { + log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms", + cbt->timeout_ms, circuit_build_times_min_timeout()); + cbt->timeout_ms = circuit_build_times_min_timeout(); + if (cbt->close_ms < cbt->timeout_ms) { + /* This shouldn't happen because of MAX() in timeout_worker above, + * but doing it just in case */ + cbt->close_ms = circuit_build_times_initial_timeout(); + } + } + + control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED); + + timeout_rate = circuit_build_times_timeout_rate(cbt); + + if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) { + log_info(LD_CIRC, + "Based on %d circuit times, it looks like we don't need to " + "wait so long for circuits to finish. We will now assume a " + "circuit is too slow to use after waiting %ld seconds.", + cbt->total_build_times, + tor_lround(cbt->timeout_ms/1000)); + log_info(LD_CIRC, + "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", + cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, + timeout_rate); + } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) { + log_info(LD_CIRC, + "Based on %d circuit times, it looks like we need to wait " + "longer for circuits to finish. We will now assume a " + "circuit is too slow to use after waiting %ld seconds.", + cbt->total_build_times, + tor_lround(cbt->timeout_ms/1000)); + log_info(LD_CIRC, + "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", + cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, + timeout_rate); + } else { + log_info(LD_CIRC, + "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f," + " r: %f) based on %d circuit times", + tor_lround(cbt->timeout_ms/1000), + cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate, + cbt->total_build_times); + } +} +/** Make a note that we're running unit tests (rather than running Tor + * itself), so we avoid clobbering our state file. */ +void +circuitbuild_running_unit_tests(void) +{ + unit_tests = 1; +} + diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h new file mode 100644 index 0000000000..efe2799b0f --- /dev/null +++ b/src/or/circuitstats.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2012, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitstats.h + * \brief Header file for circuitstats.c + **/ + +#ifndef TOR_CIRCUITSTATS_H +#define TOR_CIRCUITSTATS_H + +extern circuit_build_times_t circ_times; + +int circuit_build_times_disabled(void); +int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt); +void circuit_build_times_update_state(circuit_build_times_t *cbt, + or_state_t *state); +int circuit_build_times_parse_state(circuit_build_times_t *cbt, + or_state_t *state); +void circuit_build_times_count_timeout(circuit_build_times_t *cbt, + int did_onehop); +int circuit_build_times_count_close(circuit_build_times_t *cbt, + int did_onehop, time_t start_time); +void circuit_build_times_set_timeout(circuit_build_times_t *cbt); +int circuit_build_times_add_time(circuit_build_times_t *cbt, + build_time_t time); +int circuit_build_times_needs_circuits(circuit_build_times_t *cbt); + +int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt); +void circuit_build_times_init(circuit_build_times_t *cbt); +void circuit_build_times_free_timeouts(circuit_build_times_t *cbt); +void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, + networkstatus_t *ns); +double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt); +double circuit_build_times_close_rate(const circuit_build_times_t *cbt); + +#ifdef CIRCUITSTATS_PRIVATE +double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, + double quantile); +build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt, + double q_lo, double q_hi); +void circuit_build_times_initial_alpha(circuit_build_times_t *cbt, + double quantile, double time_ms); +int circuit_build_times_update_alpha(circuit_build_times_t *cbt); +double circuit_build_times_cdf(circuit_build_times_t *cbt, double x); +void circuitbuild_running_unit_tests(void); +void circuit_build_times_reset(circuit_build_times_t *cbt); + +/* Network liveness functions */ +int circuit_build_times_network_check_changed(circuit_build_times_t *cbt); +#endif + +/* Network liveness functions */ +void circuit_build_times_network_is_live(circuit_build_times_t *cbt); +int circuit_build_times_network_check_live(circuit_build_times_t *cbt); +void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); + +/* DOCDOC circuit_build_times_get_bw_scale */ +int circuit_build_times_get_bw_scale(networkstatus_t *ns); + +#endif + diff --git a/src/or/circuituse.c b/src/or/circuituse.c index be79b30bc9..ded78550f2 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -13,11 +13,13 @@ #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "circuitstats.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "control.h" +#include "entrynodes.h" #include "nodelist.h" #include "networkstatus.h" #include "policies.h" @@ -809,7 +811,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) tor_assert(circ); tor_assert(conn); - if (conn->_base.type == CONN_TYPE_AP) { + if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); entry_conn->may_use_optimistic_data = 0; } @@ -1126,7 +1128,7 @@ static int circuit_try_clearing_isolation_state(origin_circuit_t *circ) { if (/* The circuit may have become non-open if it was cannibalized.*/ - circ->_base.state == CIRCUIT_STATE_OPEN && + circ->base_.state == CIRCUIT_STATE_OPEN && /* If !isolation_values_set, there is nothing to clear. */ circ->isolation_values_set && /* It's not legal to clear a circuit's isolation info if it's ever had @@ -1183,8 +1185,8 @@ circuit_build_failed(origin_circuit_t *circ) * fail any one-hop directory fetches destined for it. */ const char *n_chan_id = circ->cpath->extend_info->identity_digest; int already_marked = 0; - if (circ->_base.n_chan) { - n_chan = circ->_base.n_chan; + if (circ->base_.n_chan) { + n_chan = circ->base_.n_chan; if (n_chan->is_bad_for_new_circs) { /* We only want to blame this router when a fresh healthy @@ -1213,7 +1215,7 @@ circuit_build_failed(origin_circuit_t *circ) } } - switch (circ->_base.purpose) { + switch (circ->base_.purpose) { case CIRCUIT_PURPOSE_C_GENERAL: /* If we never built the circuit, note it as a failure. */ circuit_increment_failure_count(); @@ -1228,7 +1230,7 @@ circuit_build_failed(origin_circuit_t *circ) break; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* at Bob, waiting for introductions */ - if (circ->_base.state != CIRCUIT_STATE_OPEN) { + if (circ->base_.state != CIRCUIT_STATE_OPEN) { circuit_increment_failure_count(); } /* no need to care here, because bob will rebuild intro @@ -1312,7 +1314,7 @@ circuit_launch_by_extend_info(uint8_t purpose, * internal circs rather than exit circs? -RD */ circ = circuit_find_to_cannibalize(purpose, extend_info, flags); if (circ) { - uint8_t old_purpose = circ->_base.purpose; + uint8_t old_purpose = circ->base_.purpose; struct timeval old_timestamp_created; log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)", @@ -1323,7 +1325,7 @@ circuit_launch_by_extend_info(uint8_t purpose, /* reset the birth date of this circ, else expire_building * will see it and think it's been trying to build since it * began. */ - tor_gettimeofday(&circ->_base.timestamp_created); + tor_gettimeofday(&circ->base_.timestamp_created); control_event_circuit_cannibalized(circ, old_purpose, &old_timestamp_created); @@ -1637,8 +1639,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, if (circ) { /* write the service_id into circ */ circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data); - if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && - circ->_base.state == CIRCUIT_STATE_OPEN) + if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && + circ->base_.state == CIRCUIT_STATE_OPEN) rend_client_rendcirc_has_opened(circ); } } @@ -1701,7 +1703,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, /* add it into the linked list of streams on this circuit */ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.", - circ->_base.n_circ_id); + circ->base_.n_circ_id); /* reset it, so we can measure circ timeouts */ ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL); ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams; @@ -1737,7 +1739,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, exitnode->rs) { /* Okay; we know what exit node this is. */ if (optimistic_data_enabled() && - circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL && + circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL && exitnode->rs->version_supports_optimistic_data) apconn->may_use_optimistic_data = 1; else @@ -1823,12 +1825,12 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, base_conn->state == AP_CONN_STATE_CONTROLLER_WAIT); tor_assert(conn->socks_request); tor_assert(circ); - tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN); + tor_assert(circ->base_.state == CIRCUIT_STATE_OPEN); base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - if (!circ->_base.timestamp_dirty) - circ->_base.timestamp_dirty = time(NULL); + if (!circ->base_.timestamp_dirty) + circ->base_.timestamp_dirty = time(NULL); link_apconn_to_circ(conn, circ, cpath); tor_assert(conn->socks_request); @@ -1924,7 +1926,7 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) log_debug(LD_APP|LD_CIRC, "Attaching apconn to circ %d (stream %d sec old).", - circ->_base.n_circ_id, conn_age); + circ->base_.n_circ_id, conn_age); /* print the circ's path, so people can figure out which circs are * sucking. */ circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ); @@ -1949,25 +1951,25 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) log_info(LD_REND, "rend joined circ %d already here. attaching. " "(stream %d sec old)", - rendcirc->_base.n_circ_id, conn_age); + rendcirc->base_.n_circ_id, conn_age); /* Mark rendezvous circuits as 'newly dirty' every time you use * them, since the process of rebuilding a rendezvous circ is so * expensive. There is a tradeoff between linkability and * feasibility, at this point. */ - rendcirc->_base.timestamp_dirty = time(NULL); + rendcirc->base_.timestamp_dirty = time(NULL); link_apconn_to_circ(conn, rendcirc, NULL); if (connection_ap_handshake_send_begin(conn) < 0) return 0; /* already marked, let them fade away */ return 1; } - if (rendcirc && (rendcirc->_base.purpose == + if (rendcirc && (rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) { log_info(LD_REND, "pending-join circ %d already here, with intro ack. " "Stalling. (stream %d sec old)", - rendcirc->_base.n_circ_id, conn_age); + rendcirc->base_.n_circ_id, conn_age); return 0; } @@ -1982,8 +1984,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) tor_assert(introcirc); log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). " "Stalling. (stream %d sec old)", - introcirc->_base.n_circ_id, - rendcirc ? rendcirc->_base.n_circ_id : 0, + introcirc->base_.n_circ_id, + rendcirc ? rendcirc->base_.n_circ_id : 0, conn_age); /* abort parallel intro circs, if any */ for (c = global_circuitlist; c; c = c->next) { @@ -2006,23 +2008,23 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) /* now rendcirc and introcirc are each either undefined or not finished */ if (rendcirc && introcirc && - rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) { + rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY) { log_info(LD_REND, "ready rend circ %d already here (no intro-ack yet on " "intro %d). (stream %d sec old)", - rendcirc->_base.n_circ_id, - introcirc->_base.n_circ_id, conn_age); + rendcirc->base_.n_circ_id, + introcirc->base_.n_circ_id, conn_age); - tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - if (introcirc->_base.state == CIRCUIT_STATE_OPEN) { + tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + if (introcirc->base_.state == CIRCUIT_STATE_OPEN) { log_info(LD_REND,"found open intro circ %d (rend %d); sending " "introduction. (stream %d sec old)", - introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id, + introcirc->base_.n_circ_id, rendcirc->base_.n_circ_id, conn_age); switch (rend_client_send_introduction(introcirc, rendcirc)) { case 0: /* success */ - rendcirc->_base.timestamp_dirty = time(NULL); - introcirc->_base.timestamp_dirty = time(NULL); + rendcirc->base_.timestamp_dirty = time(NULL); + introcirc->base_.timestamp_dirty = time(NULL); assert_circuit_ok(TO_CIRCUIT(rendcirc)); assert_circuit_ok(TO_CIRCUIT(introcirc)); return 0; @@ -2039,8 +2041,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. " "Stalling conn. (%d sec old)", - introcirc ? introcirc->_base.n_circ_id : 0, - rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age); + introcirc ? introcirc->base_.n_circ_id : 0, + rendcirc ? rendcirc->base_.n_circ_id : 0, conn_age); return 0; } } diff --git a/src/or/circuituse.h b/src/or/circuituse.h index be2bd7ec51..e8760c22d3 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -9,8 +9,8 @@ * \brief Header file for circuituse.c. **/ -#ifndef _TOR_CIRCUITUSE_H -#define _TOR_CIRCUITUSE_H +#ifndef TOR_CIRCUITUSE_H +#define TOR_CIRCUITUSE_H void circuit_expire_building(void); void circuit_remove_handled_ports(smartlist_t *needed_ports); diff --git a/src/or/command.c b/src/or/command.c index 2ccd44e784..39eccdf82d 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -250,7 +250,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan) } circ = or_circuit_new(cell->circ_id, chan); - circ->_base.purpose = CIRCUIT_PURPOSE_OR; + circ->base_.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); diff --git a/src/or/command.h b/src/or/command.h index f9a0ef20b7..375d704561 100644 --- a/src/or/command.h +++ b/src/or/command.h @@ -9,8 +9,8 @@ * \brief Header file for command.c. **/ -#ifndef _TOR_COMMAND_H -#define _TOR_COMMAND_H +#ifndef TOR_COMMAND_H +#define TOR_COMMAND_H #include "channel.h" diff --git a/src/or/config.c b/src/or/config.c index b81f319206..be9144074a 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -27,6 +27,7 @@ #include "dirserv.h" #include "dirvote.h" #include "dns.h" +#include "entrynodes.h" #include "geoip.h" #include "hibernate.h" #include "main.h" @@ -54,7 +55,7 @@ extern int quiet_level; /** A list of abbreviations and aliases to map command-line options, obsolete * option names, or alternative option names, to their current values. */ -static config_abbrev_t _option_abbrevs[] = { +static config_abbrev_t option_abbrevs_[] = { PLURAL(AuthDirBadDirCC), PLURAL(AuthDirBadExitCC), PLURAL(AuthDirInvalidCC), @@ -119,7 +120,7 @@ static config_abbrev_t _option_abbrevs[] = { * abbreviations, order is significant, since the first matching option will * be chosen first. */ -static config_var_t _option_vars[] = { +static config_var_t option_vars_[] = { OBSOLETE("AccountingMaxKB"), V(AccountingMax, MEMUNIT, "0 bytes"), V(AccountingStart, STRING, NULL), @@ -406,7 +407,7 @@ static config_var_t _option_vars[] = { VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"), V(VoteOnHidServDirectoriesV2, BOOL, "1"), - VAR("___UsingTestNetworkDefaults", BOOL, _UsingTestNetworkDefaults, "0"), + VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"), { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } }; @@ -434,7 +435,7 @@ static const config_var_t testing_tor_network_defaults[] = { V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"), V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"), V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"), - VAR("___UsingTestNetworkDefaults", BOOL, _UsingTestNetworkDefaults, "1"), + VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"), { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } }; @@ -492,9 +493,9 @@ static void config_maybe_load_geoip_files_(const or_options_t *options, static config_format_t options_format = { sizeof(or_options_t), OR_OPTIONS_MAGIC, - STRUCT_OFFSET(or_options_t, _magic), - _option_abbrevs, - _option_vars, + STRUCT_OFFSET(or_options_t, magic_), + option_abbrevs_, + option_vars_, (validate_fn_t)options_validate, NULL }; @@ -647,13 +648,13 @@ or_options_free(or_options_t *options) if (!options) return; - routerset_free(options->_ExcludeExitNodesUnion); + routerset_free(options->ExcludeExitNodesUnion_); if (options->NodeFamilySets) { SMARTLIST_FOREACH(options->NodeFamilySets, routerset_t *, rs, routerset_free(rs)); smartlist_free(options->NodeFamilySets); } - tor_free(options->_BridgePassword_AuthDigest); + tor_free(options->BridgePassword_AuthDigest_); config_free(&options_format, options); } @@ -696,7 +697,7 @@ const char * safe_str_client(const char *address) { tor_assert(address); - if (get_options()->_SafeLogging == SAFELOG_SCRUB_ALL) + if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL) return "[scrubbed]"; else return address; @@ -713,7 +714,7 @@ const char * safe_str(const char *address) { tor_assert(address); - if (get_options()->_SafeLogging != SAFELOG_SCRUB_NONE) + if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) return "[scrubbed]"; else return address; @@ -725,7 +726,7 @@ safe_str(const char *address) const char * escaped_safe_str_client(const char *address) { - if (get_options()->_SafeLogging == SAFELOG_SCRUB_ALL) + if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL) return "[scrubbed]"; else return escaped(address); @@ -737,7 +738,7 @@ escaped_safe_str_client(const char *address) const char * escaped_safe_str(const char *address) { - if (get_options()->_SafeLogging != SAFELOG_SCRUB_NONE) + if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) return "[scrubbed]"; else return escaped(address); @@ -934,7 +935,7 @@ options_act_reversible(const or_options_t *old_options, char **msg) int n_ports=0; /* We need to set the connection limit before we can open the listeners. */ if (set_max_file_descriptors((unsigned)options->ConnLimit, - &options->_ConnLimit) < 0) { + &options->ConnLimit_) < 0) { *msg = tor_strdup("Problem with ConnLimit value. See logs for details."); goto rollback; } @@ -1075,7 +1076,7 @@ options_act_reversible(const or_options_t *old_options, char **msg) if (set_conn_limit && old_options) set_max_file_descriptors((unsigned)old_options->ConnLimit, - &options->_ConnLimit); + &options->ConnLimit_); SMARTLIST_FOREACH(new_listeners, connection_t *, conn, { @@ -1408,8 +1409,8 @@ options_act(const or_options_t *old_options) "BridgePassword."); return -1; } - options->_BridgePassword_AuthDigest = tor_malloc(DIGEST256_LEN); - crypto_digest256(options->_BridgePassword_AuthDigest, + options->BridgePassword_AuthDigest_ = tor_malloc(DIGEST256_LEN); + crypto_digest256(options->BridgePassword_AuthDigest_, http_authenticator, strlen(http_authenticator), DIGEST_SHA256); tor_free(http_authenticator); @@ -1807,8 +1808,8 @@ list_torrc_options(void) { int i; smartlist_t *lines = smartlist_new(); - for (i = 0; _option_vars[i].name; ++i) { - const config_var_t *var = &_option_vars[i]; + for (i = 0; option_vars_[i].name; ++i) { + const config_var_t *var = &option_vars_[i]; if (var->type == CONFIG_TYPE_OBSOLETE || var->type == CONFIG_TYPE_LINELIST_V) continue; @@ -2073,16 +2074,16 @@ ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg) } /** Parse an authority type from <b>options</b>-\>PublishServerDescriptor - * and write it to <b>options</b>-\>_PublishServerDescriptor. Treat "1" + * and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1" * as "v2,v3" unless BridgeRelay is 1, in which case treat it as "bridge". * Treat "0" as "". * Return 0 on success or -1 if not a recognized authority type (in which - * case the value of _PublishServerDescriptor is undefined). */ + * case the value of PublishServerDescriptor_ is undefined). */ static int compute_publishserverdescriptor(or_options_t *options) { smartlist_t *list = options->PublishServerDescriptor; - dirinfo_type_t *auth = &options->_PublishServerDescriptor; + dirinfo_type_t *auth = &options->PublishServerDescriptor_; *auth = NO_DIRINFO; if (!list) /* empty list, answer is none */ return 0; @@ -2245,9 +2246,9 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->ExcludeExitNodes || options->ExcludeNodes) { - options->_ExcludeExitNodesUnion = routerset_new(); - routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeExitNodes); - routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeNodes); + options->ExcludeExitNodesUnion_ = routerset_new(); + routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes); + routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeNodes); } if (options->NodeFamilies) { @@ -2446,19 +2447,19 @@ options_validate(or_options_t *old_options, or_options_t *options, log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. " "EntryNodes will be ignored."); - options->_AllowInvalid = 0; + options->AllowInvalid_ = 0; if (options->AllowInvalidNodes) { SMARTLIST_FOREACH_BEGIN(options->AllowInvalidNodes, const char *, cp) { if (!strcasecmp(cp, "entry")) - options->_AllowInvalid |= ALLOW_INVALID_ENTRY; + options->AllowInvalid_ |= ALLOW_INVALID_ENTRY; else if (!strcasecmp(cp, "exit")) - options->_AllowInvalid |= ALLOW_INVALID_EXIT; + options->AllowInvalid_ |= ALLOW_INVALID_EXIT; else if (!strcasecmp(cp, "middle")) - options->_AllowInvalid |= ALLOW_INVALID_MIDDLE; + options->AllowInvalid_ |= ALLOW_INVALID_MIDDLE; else if (!strcasecmp(cp, "introduction")) - options->_AllowInvalid |= ALLOW_INVALID_INTRODUCTION; + options->AllowInvalid_ |= ALLOW_INVALID_INTRODUCTION; else if (!strcasecmp(cp, "rendezvous")) - options->_AllowInvalid |= ALLOW_INVALID_RENDEZVOUS; + options->AllowInvalid_ |= ALLOW_INVALID_RENDEZVOUS; else { tor_asprintf(msg, "Unrecognized value '%s' in AllowInvalidNodes", cp); @@ -2469,11 +2470,11 @@ options_validate(or_options_t *old_options, or_options_t *options, if (!options->SafeLogging || !strcasecmp(options->SafeLogging, "0")) { - options->_SafeLogging = SAFELOG_SCRUB_NONE; + options->SafeLogging_ = SAFELOG_SCRUB_NONE; } else if (!strcasecmp(options->SafeLogging, "relay")) { - options->_SafeLogging = SAFELOG_SCRUB_RELAY; + options->SafeLogging_ = SAFELOG_SCRUB_RELAY; } else if (!strcasecmp(options->SafeLogging, "1")) { - options->_SafeLogging = SAFELOG_SCRUB_ALL; + options->SafeLogging_ = SAFELOG_SCRUB_ALL; } else { tor_asprintf(msg, "Unrecognized value '%s' in SafeLogging", @@ -2487,8 +2488,8 @@ options_validate(or_options_t *old_options, or_options_t *options, } if ((options->BridgeRelay - || options->_PublishServerDescriptor & BRIDGE_DIRINFO) - && (options->_PublishServerDescriptor + || options->PublishServerDescriptor_ & BRIDGE_DIRINFO) + && (options->PublishServerDescriptor_ & (V1_DIRINFO|V2_DIRINFO|V3_DIRINFO))) { REJECT("Bridges are not supposed to publish router descriptors to the " "directory authorities. Please correct your " @@ -2959,7 +2960,7 @@ options_validate(or_options_t *old_options, or_options_t *options, /* Keep changes to hard-coded values synchronous to man page and default * values table. */ if (options->TestingV3AuthInitialVotingInterval != 30*60 && - !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) { + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing " "Tor networks!"); } else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) { @@ -2970,7 +2971,7 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->TestingV3AuthInitialVoteDelay != 5*60 && - !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) { + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing " "Tor networks!"); @@ -2979,7 +2980,7 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->TestingV3AuthInitialDistDelay != 5*60 && - !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) { + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { REJECT("TestingV3AuthInitialDistDelay may only be changed in testing " "Tor networks!"); } else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) { @@ -2994,7 +2995,7 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->TestingAuthDirTimeToLearnReachability != 30*60 && - !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) { + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { REJECT("TestingAuthDirTimeToLearnReachability may only be changed in " "testing Tor networks!"); } else if (options->TestingAuthDirTimeToLearnReachability < 0) { @@ -3004,7 +3005,7 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->TestingEstimatedDescriptorPropagationTime != 10*60 && - !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) { + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in " "testing Tor networks!"); } else if (options->TestingEstimatedDescriptorPropagationTime < 0) { @@ -3140,7 +3141,7 @@ options_transition_affects_workers(const or_options_t *old_options, !config_lines_eq(old_options->ORPort_lines, new_options->ORPort_lines) || old_options->ServerDNSSearchDomains != new_options->ServerDNSSearchDomains || - old_options->_SafeLogging != new_options->_SafeLogging || + old_options->SafeLogging_ != new_options->SafeLogging_ || old_options->ClientOnly != new_options->ClientOnly || public_server_mode(old_options) != public_server_mode(new_options) || !config_lines_eq(old_options->Logs, new_options->Logs) || @@ -3173,8 +3174,8 @@ options_transition_affects_descriptor(const or_options_t *old_options, new_options->DirPort_lines) || old_options->ClientOnly != new_options->ClientOnly || old_options->DisableNetwork != new_options->DisableNetwork || - old_options->_PublishServerDescriptor != - new_options->_PublishServerDescriptor || + old_options->PublishServerDescriptor_ != + new_options->PublishServerDescriptor_ || get_effective_bwrate(old_options) != get_effective_bwrate(new_options) || get_effective_bwburst(old_options) != get_effective_bwburst(new_options) || @@ -3531,7 +3532,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, this is the first time we run*/ newoptions = tor_malloc_zero(sizeof(or_options_t)); - newoptions->_magic = OR_OPTIONS_MAGIC; + newoptions->magic_ = OR_OPTIONS_MAGIC; options_init(newoptions); newoptions->command = command; newoptions->command_arg = command_arg; @@ -3591,7 +3592,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, config_free(&options_format, newdefaultoptions); newdefaultoptions = NULL; newoptions = tor_malloc_zero(sizeof(or_options_t)); - newoptions->_magic = OR_OPTIONS_MAGIC; + newoptions->magic_ = OR_OPTIONS_MAGIC; options_init(newoptions); newoptions->command = command; newoptions->command_arg = command_arg; @@ -5457,11 +5458,11 @@ getinfo_helper_config(control_connection_t *conn, if (!strcmp(question, "config/names")) { smartlist_t *sl = smartlist_new(); int i; - for (i = 0; _option_vars[i].name; ++i) { - const config_var_t *var = &_option_vars[i]; + for (i = 0; option_vars_[i].name; ++i) { + const config_var_t *var = &option_vars_[i]; const char *type; /* don't tell controller about triple-underscore options */ - if (!strncmp(_option_vars[i].name, "___", 3)) + if (!strncmp(option_vars_[i].name, "___", 3)) continue; switch (var->type) { case CONFIG_TYPE_STRING: type = "String"; break; @@ -5495,8 +5496,8 @@ getinfo_helper_config(control_connection_t *conn, } else if (!strcmp(question, "config/defaults")) { smartlist_t *sl = smartlist_new(); int i; - for (i = 0; _option_vars[i].name; ++i) { - const config_var_t *var = &_option_vars[i]; + for (i = 0; option_vars_[i].name; ++i) { + const config_var_t *var = &option_vars_[i]; if (var->initvalue != NULL) { char *val = esc_for_log(var->initvalue); smartlist_add_asprintf(sl, "%s %s\n",var->name,val); @@ -5511,8 +5512,8 @@ getinfo_helper_config(control_connection_t *conn, } /** Parse outbound bind address option lines. If <b>validate_only</b> - * is not 0 update _OutboundBindAddressIPv4 and - * _OutboundBindAddressIPv6 in <b>options</b>. On failure, set + * is not 0 update OutboundBindAddressIPv4_ and + * OutboundBindAddressIPv6_ in <b>options</b>. On failure, set * <b>msg</b> (if provided) to a newly allocated string containing a * description of the problem and return -1. */ static int @@ -5522,10 +5523,10 @@ parse_outbound_addresses(or_options_t *options, int validate_only, char **msg) int found_v4 = 0, found_v6 = 0; if (!validate_only) { - memset(&options->_OutboundBindAddressIPv4, 0, - sizeof(options->_OutboundBindAddressIPv4)); - memset(&options->_OutboundBindAddressIPv6, 0, - sizeof(options->_OutboundBindAddressIPv6)); + memset(&options->OutboundBindAddressIPv4_, 0, + sizeof(options->OutboundBindAddressIPv4_)); + memset(&options->OutboundBindAddressIPv6_, 0, + sizeof(options->OutboundBindAddressIPv6_)); } while (lines) { tor_addr_t addr, *dst_addr = NULL; @@ -5539,7 +5540,7 @@ parse_outbound_addresses(or_options_t *options, int validate_only, char **msg) return -1; } found_v4 = 1; - dst_addr = &options->_OutboundBindAddressIPv4; + dst_addr = &options->OutboundBindAddressIPv4_; break; case AF_INET6: if (found_v6) { @@ -5549,7 +5550,7 @@ parse_outbound_addresses(or_options_t *options, int validate_only, char **msg) return -1; } found_v6 = 1; - dst_addr = &options->_OutboundBindAddressIPv6; + dst_addr = &options->OutboundBindAddressIPv6_; break; default: if (msg) diff --git a/src/or/config.h b/src/or/config.h index 9d170b8af5..f3b28adb78 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -9,8 +9,8 @@ * \brief Header file for config.c. **/ -#ifndef _TOR_CONFIG_H -#define _TOR_CONFIG_H +#ifndef TOR_CONFIG_H +#define TOR_CONFIG_H const char *get_dirportfrontpage(void); const or_options_t *get_options(void); diff --git a/src/or/connection.c b/src/or/connection.c index fb6c77d7f3..1fbce418a4 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -16,7 +16,7 @@ * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ -#define _TOR_CHANNEL_INTERNAL +#define TOR_CHANNEL_INTERNAL_ #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" @@ -32,6 +32,7 @@ #include "dirserv.h" #include "dns.h" #include "dnsserv.h" +#include "entrynodes.h" #include "geoip.h" #include "main.h" #include "policies.h" @@ -427,7 +428,7 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b) * if <b>conn</b> is an OR or OP connection. */ static void -_connection_free(connection_t *conn) +connection_free_(connection_t *conn) { void *mem; size_t memlen; @@ -604,7 +605,7 @@ connection_free(connection_t *conn) connection_control_closed(TO_CONTROL_CONN(conn)); } connection_unregister_events(conn); - _connection_free(conn); + connection_free_(conn); } /** @@ -680,7 +681,7 @@ connection_close_immediate(connection_t *conn) /** Mark <b>conn</b> to be closed next time we loop through * conn_close_if_marked() in main.c. */ void -_connection_mark_for_close(connection_t *conn, int line, const char *file) +connection_mark_for_close_(connection_t *conn, int line, const char *file) { assert_connection_ok(conn,0); tor_assert(line); @@ -903,7 +904,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, static int global_next_session_group = SESSION_GROUP_FIRST_AUTO; tor_addr_t addr; - if (get_n_open_sockets() >= get_options()->_ConnLimit-1) { + if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { warn_too_many_conns(); return NULL; } @@ -1310,7 +1311,7 @@ connection_init_accepted_conn(connection_t *conn, TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags; TO_ENTRY_CONN(conn)->session_group = listener->session_group; TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch(); - TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->_base.type; + TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type; switch (TO_CONN(listener)->type) { case CONN_TYPE_AP_LISTENER: conn->state = AP_CONN_STATE_SOCKS_WAIT; @@ -1357,7 +1358,7 @@ connection_connect(connection_t *conn, const char *address, const or_options_t *options = get_options(); int protocol_family; - if (get_n_open_sockets() >= get_options()->_ConnLimit-1) { + if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { warn_too_many_conns(); *socket_error = SOCK_ERRNO(ENOBUFS); return -1; @@ -1399,11 +1400,11 @@ connection_connect(connection_t *conn, const char *address, if (!tor_addr_is_loopback(addr)) { const tor_addr_t *ext_addr = NULL; if (protocol_family == AF_INET && - !tor_addr_is_null(&options->_OutboundBindAddressIPv4)) - ext_addr = &options->_OutboundBindAddressIPv4; + !tor_addr_is_null(&options->OutboundBindAddressIPv4_)) + ext_addr = &options->OutboundBindAddressIPv4_; else if (protocol_family == AF_INET6 && - !tor_addr_is_null(&options->_OutboundBindAddressIPv6)) - ext_addr = &options->_OutboundBindAddressIPv6; + !tor_addr_is_null(&options->OutboundBindAddressIPv6_)) + ext_addr = &options->OutboundBindAddressIPv6_; if (ext_addr) { struct sockaddr_storage ext_addr_sa; socklen_t ext_addr_len = 0; @@ -2570,7 +2571,7 @@ connection_bucket_should_increase(int bucket, or_connection_t *conn) { tor_assert(conn); - if (conn->_base.state != OR_CONN_STATE_OPEN) + if (conn->base_.state != OR_CONN_STATE_OPEN) return 0; /* only open connections play the rate limiting game */ if (bucket >= conn->bandwidthburst) return 0; @@ -3428,7 +3429,7 @@ connection_flush(connection_t *conn) * once. */ void -_connection_write_to_buf_impl(const char *string, size_t len, +connection_write_to_buf_impl_(const char *string, size_t len, connection_t *conn, int zlib) { /* XXXX This function really needs to return -1 on failure. */ @@ -3995,9 +3996,9 @@ connection_reached_eof(connection_t *conn) void connection_dump_buffer_mem_stats(int severity) { - uint64_t used_by_type[_CONN_TYPE_MAX+1]; - uint64_t alloc_by_type[_CONN_TYPE_MAX+1]; - int n_conns_by_type[_CONN_TYPE_MAX+1]; + uint64_t used_by_type[CONN_TYPE_MAX_+1]; + uint64_t alloc_by_type[CONN_TYPE_MAX_+1]; + int n_conns_by_type[CONN_TYPE_MAX_+1]; uint64_t total_alloc = 0; uint64_t total_used = 0; int i; @@ -4019,7 +4020,7 @@ connection_dump_buffer_mem_stats(int severity) alloc_by_type[tp] += buf_allocation(c->outbuf); } } SMARTLIST_FOREACH_END(c); - for (i=0; i <= _CONN_TYPE_MAX; ++i) { + for (i=0; i <= CONN_TYPE_MAX_; ++i) { total_used += used_by_type[i]; total_alloc += alloc_by_type[i]; } @@ -4028,7 +4029,7 @@ connection_dump_buffer_mem_stats(int severity) "In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated", smartlist_len(conns), U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc)); - for (i=_CONN_TYPE_MIN; i <= _CONN_TYPE_MAX; ++i) { + for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) { if (!n_conns_by_type[i]) continue; log(severity, LD_GENERAL, @@ -4046,8 +4047,8 @@ assert_connection_ok(connection_t *conn, time_t now) { (void) now; /* XXXX unused. */ tor_assert(conn); - tor_assert(conn->type >= _CONN_TYPE_MIN); - tor_assert(conn->type <= _CONN_TYPE_MAX); + tor_assert(conn->type >= CONN_TYPE_MIN_); + tor_assert(conn->type <= CONN_TYPE_MAX_); #ifdef USE_BUFFEREVENTS if (conn->bufev) { @@ -4162,33 +4163,33 @@ assert_connection_ok(connection_t *conn, time_t now) tor_assert(conn->state == LISTENER_STATE_READY); break; case CONN_TYPE_OR: - tor_assert(conn->state >= _OR_CONN_STATE_MIN); - tor_assert(conn->state <= _OR_CONN_STATE_MAX); + tor_assert(conn->state >= OR_CONN_STATE_MIN_); + tor_assert(conn->state <= OR_CONN_STATE_MAX_); break; case CONN_TYPE_EXIT: - tor_assert(conn->state >= _EXIT_CONN_STATE_MIN); - tor_assert(conn->state <= _EXIT_CONN_STATE_MAX); - tor_assert(conn->purpose >= _EXIT_PURPOSE_MIN); - tor_assert(conn->purpose <= _EXIT_PURPOSE_MAX); + tor_assert(conn->state >= EXIT_CONN_STATE_MIN_); + tor_assert(conn->state <= EXIT_CONN_STATE_MAX_); + tor_assert(conn->purpose >= EXIT_PURPOSE_MIN_); + tor_assert(conn->purpose <= EXIT_PURPOSE_MAX_); break; case CONN_TYPE_AP: - tor_assert(conn->state >= _AP_CONN_STATE_MIN); - tor_assert(conn->state <= _AP_CONN_STATE_MAX); + tor_assert(conn->state >= AP_CONN_STATE_MIN_); + tor_assert(conn->state <= AP_CONN_STATE_MAX_); tor_assert(TO_ENTRY_CONN(conn)->socks_request); break; case CONN_TYPE_DIR: - tor_assert(conn->state >= _DIR_CONN_STATE_MIN); - tor_assert(conn->state <= _DIR_CONN_STATE_MAX); - tor_assert(conn->purpose >= _DIR_PURPOSE_MIN); - tor_assert(conn->purpose <= _DIR_PURPOSE_MAX); + tor_assert(conn->state >= DIR_CONN_STATE_MIN_); + tor_assert(conn->state <= DIR_CONN_STATE_MAX_); + tor_assert(conn->purpose >= DIR_PURPOSE_MIN_); + tor_assert(conn->purpose <= DIR_PURPOSE_MAX_); break; case CONN_TYPE_CPUWORKER: - tor_assert(conn->state >= _CPUWORKER_STATE_MIN); - tor_assert(conn->state <= _CPUWORKER_STATE_MAX); + tor_assert(conn->state >= CPUWORKER_STATE_MIN_); + tor_assert(conn->state <= CPUWORKER_STATE_MAX_); break; case CONN_TYPE_CONTROL: - tor_assert(conn->state >= _CONTROL_CONN_STATE_MIN); - tor_assert(conn->state <= _CONTROL_CONN_STATE_MAX); + tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_); + tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_); break; default: tor_assert(0); @@ -4293,7 +4294,7 @@ proxy_type_to_string(int proxy_type) return NULL; /*Unreached*/ } -/** Call _connection_free() on every connection in our array, and release all +/** Call connection_free_() on every connection in our array, and release all * storage held by connection.c. This is used by cpuworkers and dnsworkers * when they fork, so they don't keep resources held open (especially * sockets). @@ -4319,7 +4320,7 @@ connection_free_all(void) /* Clear out our list of broken connections */ clear_broken_connection_map(0); - SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn)); + SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn)); if (outgoing_addrs) { SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr)); diff --git a/src/or/connection.h b/src/or/connection.h index 785625e44b..6ed9e4a41f 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -9,8 +9,8 @@ * \brief Header file for connection.c. **/ -#ifndef _TOR_CONNECTION_H -#define _TOR_CONNECTION_H +#ifndef TOR_CONNECTION_H +#define TOR_CONNECTION_H /* XXXX For buf_datalen in inline function */ #include "buffers.h" @@ -31,25 +31,25 @@ void connection_free(connection_t *conn); void connection_free_all(void); void connection_about_to_close_connection(connection_t *conn); void connection_close_immediate(connection_t *conn); -void _connection_mark_for_close(connection_t *conn,int line, const char *file); +void connection_mark_for_close_(connection_t *conn,int line, const char *file); #define connection_mark_for_close(c) \ - _connection_mark_for_close((c), __LINE__, _SHORT_FILE_) + connection_mark_for_close_((c), __LINE__, SHORT_FILE__) /** * Mark 'c' for close, but try to hold it open until all the data is written. */ -#define _connection_mark_and_flush(c,line,file) \ +#define connection_mark_and_flush_(c,line,file) \ do { \ connection_t *tmp_conn_ = (c); \ - _connection_mark_for_close(tmp_conn_, (line), (file)); \ + connection_mark_for_close_(tmp_conn_, (line), (file)); \ tmp_conn_->hold_open_until_flushed = 1; \ IF_HAS_BUFFEREVENT(tmp_conn_, \ connection_start_writing(tmp_conn_)); \ } while (0) #define connection_mark_and_flush(c) \ - _connection_mark_and_flush((c), __LINE__, _SHORT_FILE_) + connection_mark_and_flush_((c), __LINE__, SHORT_FILE__) void connection_expire_held_open(void); @@ -90,7 +90,7 @@ int connection_outbuf_too_full(connection_t *conn); int connection_handle_write(connection_t *conn, int force); int connection_flush(connection_t *conn); -void _connection_write_to_buf_impl(const char *string, size_t len, +void connection_write_to_buf_impl_(const char *string, size_t len, connection_t *conn, int zlib); /* DOCDOC connection_write_to_buf */ static void connection_write_to_buf(const char *string, size_t len, @@ -101,13 +101,13 @@ static void connection_write_to_buf_zlib(const char *string, size_t len, static INLINE void connection_write_to_buf(const char *string, size_t len, connection_t *conn) { - _connection_write_to_buf_impl(string, len, conn, 0); + connection_write_to_buf_impl_(string, len, conn, 0); } static INLINE void connection_write_to_buf_zlib(const char *string, size_t len, dir_connection_t *conn, int done) { - _connection_write_to_buf_impl(string, len, TO_CONN(conn), done ? -1 : 1); + connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); } /* DOCDOC connection_get_inbuf_len */ diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index d1a7e3e7a3..4d528a810e 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -66,7 +66,7 @@ static int connection_ap_supports_optimistic_data(const entry_connection_t *); * has_sent_end to 1, and mark the conn. */ void -_connection_mark_unattached_ap(entry_connection_t *conn, int endreason, +connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, int line, const char *file) { connection_t *base_conn = ENTRY_TO_CONN(conn); @@ -89,7 +89,7 @@ _connection_mark_unattached_ap(entry_connection_t *conn, int endreason, if (base_conn->marked_for_close) { /* This call will warn as appropriate. */ - _connection_mark_for_close(base_conn, line, file); + connection_mark_for_close_(base_conn, line, file); return; } @@ -109,7 +109,7 @@ _connection_mark_unattached_ap(entry_connection_t *conn, int endreason, conn->socks_request->has_finished = 1; } - _connection_mark_and_flush(base_conn, line, file); + connection_mark_and_flush_(base_conn, line, file); ENTRY_TO_EDGE_CONN(conn)->end_reason = endreason; } @@ -124,12 +124,12 @@ connection_edge_reached_eof(edge_connection_t *conn) /* it still has stuff to process. don't let it die yet. */ return 0; } - log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->_base.s); - if (!conn->_base.marked_for_close) { + log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->base_.s); + if (!conn->base_.marked_for_close) { /* only mark it if not already marked. it's possible to * get the 'end' right around when the client hangs up on us. */ connection_edge_end(conn, END_STREAM_REASON_DONE); - if (conn->_base.type == CONN_TYPE_AP) { + if (conn->base_.type == CONN_TYPE_AP) { /* eof, so don't send a socks reply back */ if (EDGE_TO_ENTRY_CONN(conn)->socks_request) EDGE_TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; @@ -154,7 +154,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) { tor_assert(conn); - switch (conn->_base.state) { + switch (conn->base_.state) { case AP_CONN_STATE_SOCKS_WAIT: if (connection_ap_handshake_process_socks(EDGE_TO_ENTRY_CONN(conn)) <0) { /* already marked */ @@ -180,7 +180,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) log_info(LD_EDGE, "data from edge while in '%s' state. Sending it anyway. " "package_partial=%d, buflen=%ld", - conn_state_to_string(conn->_base.type, conn->_base.state), + conn_state_to_string(conn->base_.type, conn->base_.state), package_partial, (long)connection_get_inbuf_len(TO_CONN(conn))); if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) { @@ -199,10 +199,10 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) case AP_CONN_STATE_CONTROLLER_WAIT: log_info(LD_EDGE, "data from edge while in '%s' state. Leaving it on buffer.", - conn_state_to_string(conn->_base.type, conn->_base.state)); + conn_state_to_string(conn->base_.type, conn->base_.state)); return 0; } - log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->_base.state); + log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->base_.state); tor_fragile_assert(); connection_edge_end(conn, END_STREAM_REASON_INTERNAL); connection_mark_for_close(TO_CONN(conn)); @@ -215,10 +215,10 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn) { - if (!conn->_base.marked_for_close) { + if (!conn->base_.marked_for_close) { log_info(LD_EDGE, "CircID %d: At an edge. Marking connection for close.", circ_id); - if (conn->_base.type == CONN_TYPE_AP) { + if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DESTROY); control_event_stream_bandwidth(conn); @@ -282,10 +282,10 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason) return -1; } - if (conn->_base.marked_for_close) { + if (conn->base_.marked_for_close) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", - conn->_base.marked_for_close_file, conn->_base.marked_for_close); + conn->base_.marked_for_close_file, conn->base_.marked_for_close); return 0; } @@ -301,11 +301,11 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason) if (reason == END_STREAM_REASON_EXITPOLICY && !connection_edge_is_rendezvous_stream(conn)) { int addrlen; - if (tor_addr_family(&conn->_base.addr) == AF_INET) { - set_uint32(payload+1, tor_addr_to_ipv4n(&conn->_base.addr)); + if (tor_addr_family(&conn->base_.addr) == AF_INET) { + set_uint32(payload+1, tor_addr_to_ipv4n(&conn->base_.addr)); addrlen = 4; } else { - memcpy(payload+1, tor_addr_to_in6_addr8(&conn->_base.addr), 16); + memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16); addrlen = 16; } set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl))); @@ -313,12 +313,12 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason) } if (circ && !circ->marked_for_close) { - log_debug(LD_EDGE,"Sending end on conn (fd %d).",conn->_base.s); + log_debug(LD_EDGE,"Sending end on conn (fd %d).",conn->base_.s); connection_edge_send_command(conn, RELAY_COMMAND_END, payload, payload_len); } else { log_debug(LD_EDGE,"No circ to send end on conn (fd %d).", - conn->_base.s); + conn->base_.s); } conn->edge_has_sent_end = 1; @@ -335,7 +335,7 @@ connection_edge_end_errno(edge_connection_t *conn) { uint8_t reason; tor_assert(conn); - reason = errno_to_stream_end_reason(tor_socket_errno(conn->_base.s)); + reason = errno_to_stream_end_reason(tor_socket_errno(conn->base_.s)); return connection_edge_end(conn, reason); } @@ -347,7 +347,7 @@ connection_edge_end_errno(edge_connection_t *conn) int connection_edge_flushed_some(edge_connection_t *conn) { - switch (conn->_base.state) { + switch (conn->base_.state) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: connection_edge_consider_sending_sendme(conn); @@ -371,7 +371,7 @@ connection_edge_finished_flushing(edge_connection_t *conn) { tor_assert(conn); - switch (conn->_base.state) { + switch (conn->base_.state) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: connection_edge_consider_sending_sendme(conn); @@ -385,7 +385,7 @@ connection_edge_finished_flushing(edge_connection_t *conn) case AP_CONN_STATE_RESOLVE_WAIT: return 0; default: - log_warn(LD_BUG, "Called in unexpected state %d.",conn->_base.state); + log_warn(LD_BUG, "Called in unexpected state %d.",conn->base_.state); tor_fragile_assert(); return -1; } @@ -401,7 +401,7 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn) connection_t *conn; tor_assert(edge_conn); - tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT); + tor_assert(edge_conn->base_.type == CONN_TYPE_EXIT); conn = TO_CONN(edge_conn); tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING); @@ -628,7 +628,7 @@ connection_ap_expire_beginning(void) tor_assert(circ->timestamp_dirty); circ->timestamp_dirty -= options->MaxCircuitDirtiness; /* give our stream another 'cutoff' seconds to try */ - conn->_base.timestamp_lastread += cutoff; + conn->base_.timestamp_lastread += cutoff; if (entry_conn->num_socks_retries < 250) /* avoid overflow */ entry_conn->num_socks_retries++; /* move it back into 'pending' state, and try to attach. */ @@ -934,7 +934,7 @@ void addressmap_clear_excluded_trackexithosts(const or_options_t *options) { const routerset_t *allow_nodes = options->ExitNodes; - const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion; + const routerset_t *exclude_nodes = options->ExcludeExitNodesUnion_; if (!addressmap) return; @@ -1688,15 +1688,15 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires, { strmap_iter_t *iter; const char *key; - void *_val; + void *val_; addressmap_entry_t *val; if (!addressmap) addressmap_init(); for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) { - strmap_iter_get(iter, &key, &_val); - val = _val; + strmap_iter_get(iter, &key, &val_); + val = val_; if (val->expires >= min_expires && val->expires <= max_expires) { if (!sl) { iter = strmap_iter_next_rmv(addressmap,iter); @@ -1925,7 +1925,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */ routerset_t *excludeset = options->StrictNodes ? - options->_ExcludeExitNodesUnion : options->ExcludeExitNodes; + options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes; const node_t *node; if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) { @@ -2587,13 +2587,13 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn) /* Mark this circuit "unusable for new streams". */ /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->_base.timestamp_dirty); - circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + tor_assert(circ->base_.timestamp_dirty); + circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness; return -1; } tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", - (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ? + (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ? ap_conn->socks_request->address : "", ap_conn->socks_request->port); payload_len = (int)strlen(payload)+1; @@ -2620,7 +2620,7 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn) edge_conn->deliver_window = STREAMWINDOW_START; base_conn->state = AP_CONN_STATE_CONNECT_WAIT; log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d", - base_conn->s, circ->_base.n_circ_id); + base_conn->s, circ->base_.n_circ_id); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0); /* If there's queued-up data, send it now */ @@ -2659,7 +2659,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) tor_assert(base_conn->type == CONN_TYPE_AP); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); - tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL); command = ap_conn->socks_request->command; tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); @@ -2672,8 +2672,8 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) /* Mark this circuit "unusable for new streams". */ /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->_base.timestamp_dirty); - circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + tor_assert(circ->base_.timestamp_dirty); + circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness; return -1; } @@ -2721,7 +2721,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) base_conn->address = tor_strdup("(Tor_internal)"); base_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d", - base_conn->s, circ->_base.n_circ_id); + base_conn->s, circ->base_.n_circ_id); control_event_stream_status(ap_conn, STREAM_EVENT_NEW, 0); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0); return 0; @@ -3102,10 +3102,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) } /* Make sure to get the 'real' address of the previous hop: the * caller might want to know whether his IP address has changed, and - * we might already have corrected _base.addr[ess] for the relay's + * we might already have corrected base_.addr[ess] for the relay's * canonical IP address. */ if (or_circ && or_circ->p_chan) - address = tor_strdup(channel_get_actual_remote_descr(or_circ->p_chan)); + address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan)); else address = tor_strdup("127.0.0.1"); port = 1; /* XXXX This value is never actually used anywhere, and there @@ -3125,10 +3125,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * we can measure download times. */ n_stream->dirreq_id = circ->dirreq_id; - n_stream->_base.purpose = EXIT_PURPOSE_CONNECT; + n_stream->base_.purpose = EXIT_PURPOSE_CONNECT; n_stream->stream_id = rh.stream_id; - n_stream->_base.port = port; + n_stream->base_.port = port; /* leave n_stream->s at -1, because it's not yet valid */ n_stream->package_window = STREAMWINDOW_START; n_stream->deliver_window = STREAMWINDOW_START; @@ -3136,14 +3136,14 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); log_info(LD_REND,"begin is for rendezvous. configuring stream."); - n_stream->_base.address = tor_strdup("(rendezvous)"); - n_stream->_base.state = EXIT_CONN_STATE_CONNECTING; + n_stream->base_.address = tor_strdup("(rendezvous)"); + n_stream->base_.state = EXIT_CONN_STATE_CONNECTING; n_stream->rend_data = rend_data_dup(origin_circ->rend_data); tor_assert(connection_edge_is_rendezvous_stream(n_stream)); assert_circuit_ok(circ); if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) { log_info(LD_REND,"Didn't find rendezvous service (port %d)", - n_stream->_base.port); + n_stream->base_.port); relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_EXITPOLICY, origin_circ->cpath->prev); @@ -3166,8 +3166,8 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) return 0; } tor_strlower(address); - n_stream->_base.address = address; - n_stream->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; + n_stream->base_.address = address; + n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; /* default to failed, change in dns_resolve if it turns out not to fail */ if (we_are_hibernating()) { @@ -3180,7 +3180,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) n_stream->on_circuit = circ; if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + tor_addr_t tmp_addr; tor_assert(or_circ); + if (or_circ->p_chan && + channel_get_addr_if_possible(or_circ->p_chan, &tmp_addr)) { + tor_addr_copy(&n_stream->base_.addr, &tmp_addr); + } return connection_exit_connect_dir(n_stream); } @@ -3230,12 +3235,12 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) */ dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET); dummy_conn->stream_id = rh.stream_id; - dummy_conn->_base.address = tor_strndup( + dummy_conn->base_.address = tor_strndup( (char*)cell->payload+RELAY_HEADER_SIZE, rh.length); - dummy_conn->_base.port = 0; - dummy_conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; - dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE; + dummy_conn->base_.port = 0; + dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE; dummy_conn->on_circuit = TO_CIRCUIT(circ); @@ -3245,7 +3250,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) /* Connection freed; don't touch it. */ return 0; case 1: /* The result was cached; a resolved cell was sent. */ - if (!dummy_conn->_base.marked_for_close) + if (!dummy_conn->base_.marked_for_close) connection_free(TO_CONN(dummy_conn)); return 0; case 0: /* resolve added to pending list */ @@ -3352,16 +3357,16 @@ connection_exit_connect_dir(edge_connection_t *exitconn) log_info(LD_EXIT, "Opening local connection for anonymized directory exit"); - exitconn->_base.state = EXIT_CONN_STATE_OPEN; + exitconn->base_.state = EXIT_CONN_STATE_OPEN; - dirconn = dir_connection_new(tor_addr_family(&exitconn->_base.addr)); + dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr)); - tor_addr_copy(&dirconn->_base.addr, &exitconn->_base.addr); - dirconn->_base.port = 0; - dirconn->_base.address = tor_strdup(exitconn->_base.address); - dirconn->_base.type = CONN_TYPE_DIR; - dirconn->_base.purpose = DIR_PURPOSE_SERVER; - dirconn->_base.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT; + tor_addr_copy(&dirconn->base_.addr, &exitconn->base_.addr); + dirconn->base_.port = 0; + dirconn->base_.address = tor_strdup(exitconn->base_.address); + dirconn->base_.type = CONN_TYPE_DIR; + dirconn->base_.purpose = DIR_PURPOSE_SERVER; + dirconn->base_.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT; /* Note that the new dir conn belongs to the same tunneled request as * the edge conn, so that we can measure download times. */ @@ -3467,7 +3472,7 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit) if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit)) return 0; } - if (routerset_contains_node(options->_ExcludeExitNodesUnion, exit)) { + if (routerset_contains_node(options->ExcludeExitNodesUnion_, exit)) { /* Not a suitable exit. Refuse it. */ return 0; } diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index c320d6ba49..42fb73c036 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -9,13 +9,13 @@ * \brief Header file for connection_edge.c. **/ -#ifndef _TOR_CONNECTION_EDGE_H -#define _TOR_CONNECTION_EDGE_H +#ifndef TOR_CONNECTION_EDGE_H +#define TOR_CONNECTION_EDGE_H #define connection_mark_unattached_ap(conn, endreason) \ - _connection_mark_unattached_ap((conn), (endreason), __LINE__, _SHORT_FILE_) + connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__) -void _connection_mark_unattached_ap(entry_connection_t *conn, int endreason, +void connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, int line, const char *file); int connection_edge_reached_eof(edge_connection_t *conn); int connection_edge_process_inbuf(edge_connection_t *conn, diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 9fedbf4c68..9cd56bb89c 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -16,17 +16,19 @@ * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ -#define _TOR_CHANNEL_INTERNAL +#define TOR_CHANNEL_INTERNAL_ #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "circuitstats.h" #include "command.h" #include "config.h" #include "connection.h" #include "connection_or.h" #include "control.h" #include "dirserv.h" +#include "entrynodes.h" #include "geoip.h" #include "main.h" #include "networkstatus.h" @@ -318,8 +320,8 @@ connection_or_change_state(or_connection_t *conn, uint8_t state) tor_assert(conn); - old_state = conn->_base.state; - conn->_base.state = state; + old_state = conn->base_.state; + conn->base_.state = state; if (conn->chan) channel_tls_handle_state_change_on_orconn(conn->chan, conn, @@ -427,7 +429,7 @@ connection_or_process_inbuf(or_connection_t *conn) int ret = 0; tor_assert(conn); - switch (conn->_base.state) { + switch (conn->base_.state) { case OR_CONN_STATE_PROXY_HANDSHAKING: ret = connection_read_proxy_handshake(TO_CONN(conn)); @@ -449,7 +451,7 @@ connection_or_process_inbuf(or_connection_t *conn) #ifdef USE_BUFFEREVENTS if (tor_tls_server_got_renegotiate(conn->tls)) connection_or_tls_renegotiated_cb(conn->tls, conn); - if (conn->_base.marked_for_close) + if (conn->base_.marked_for_close) return 0; /* fall through. */ #endif @@ -467,13 +469,13 @@ connection_or_process_inbuf(or_connection_t *conn) * * XXX024 Remove this check once we verify that the above paragraph is * 100% true. */ - if (buf_datalen(conn->_base.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) { + if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) { log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) " "on nonopen OR connection %s %s:%u in state %s; closing.", - (int)buf_datalen(conn->_base.inbuf), + (int)buf_datalen(conn->base_.inbuf), connection_or_nonopen_was_started_here(conn) ? "to" : "from", - conn->_base.address, conn->_base.port, - conn_state_to_string(conn->_base.type, conn->_base.state)); + conn->base_.address, conn->base_.port, + conn_state_to_string(conn->base_.type, conn->base_.state)); connection_or_close_for_error(conn, 0); ret = -1; } @@ -536,14 +538,14 @@ connection_or_finished_flushing(or_connection_t *conn) tor_assert(conn); assert_connection_ok(TO_CONN(conn),0); - switch (conn->_base.state) { + switch (conn->base_.state) { case OR_CONN_STATE_PROXY_HANDSHAKING: case OR_CONN_STATE_OPEN: case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: break; default: - log_err(LD_BUG,"Called in unexpected state %d.", conn->_base.state); + log_err(LD_BUG,"Called in unexpected state %d.", conn->base_.state); tor_fragile_assert(); return -1; } @@ -691,8 +693,8 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset, cfg = ev_token_bucket_cfg_new(rate_per_tick, burst, rate_per_tick, burst, tick); old_cfg = conn->bucket_cfg; - if (conn->_base.bufev) - tor_set_bufferevent_rate_limit(conn->_base.bufev, cfg); + if (conn->base_.bufev) + tor_set_bufferevent_rate_limit(conn->base_.bufev, cfg); if (old_cfg) ev_token_bucket_cfg_free(old_cfg); conn->bucket_cfg = cfg; @@ -741,15 +743,15 @@ connection_or_init_conn_from_address(or_connection_t *conn, connection_or_set_identity_digest(conn, id_digest); connection_or_update_token_buckets_helper(conn, 1, get_options()); - conn->_base.port = port; - tor_addr_copy(&conn->_base.addr, addr); + conn->base_.port = port; + tor_addr_copy(&conn->base_.addr, addr); tor_addr_copy(&conn->real_addr, addr); if (r) { tor_addr_port_t node_ap; node_get_pref_orport(r, &node_ap); /* XXXX proposal 186 is making this more complex. For now, a conn is canonical when it uses the _preferred_ address. */ - if (tor_addr_eq(&conn->_base.addr, &node_ap.addr)) + if (tor_addr_eq(&conn->base_.addr, &node_ap.addr)) conn->is_canonical = 1; if (!started_here) { /* Override the addr/port, so our log messages will make sense. @@ -762,12 +764,12 @@ connection_or_init_conn_from_address(or_connection_t *conn, * right IP address and port 56244, that wouldn't be as helpful. now we * log the "right" port too, so we know if it's moria1 or moria2. */ - tor_addr_copy(&conn->_base.addr, &node_ap.addr); - conn->_base.port = node_ap.port; + tor_addr_copy(&conn->base_.addr, &node_ap.addr); + conn->base_.port = node_ap.port; } conn->nickname = tor_strdup(node_get_nickname(r)); - tor_free(conn->_base.address); - conn->_base.address = tor_dup_addr(&node_ap.addr); + tor_free(conn->base_.address); + conn->base_.address = tor_dup_addr(&node_ap.addr); } else { const char *n; /* If we're an authoritative directory server, we may know a @@ -781,8 +783,8 @@ connection_or_init_conn_from_address(or_connection_t *conn, base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN); } - tor_free(conn->_base.address); - conn->_base.address = tor_dup_addr(addr); + tor_free(conn->base_.address); + conn->base_.address = tor_dup_addr(addr); } } @@ -839,23 +841,23 @@ connection_or_group_set_badness(or_connection_t *head, int force) /* Pass 1: expire everything that's old, and see what the status of * everything else is. */ for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { - if (or_conn->_base.marked_for_close || + if (or_conn->base_.marked_for_close || connection_or_is_bad_for_new_circs(or_conn)) continue; if (force || - or_conn->_base.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD + or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD < now) { log_info(LD_OR, "Marking OR conn to %s:%d as too old for new circuits " "(fd %d, %d secs old).", - or_conn->_base.address, or_conn->_base.port, or_conn->_base.s, - (int)(now - or_conn->_base.timestamp_created)); + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } if (connection_or_is_bad_for_new_circs(or_conn)) { ++n_old; - } else if (or_conn->_base.state != OR_CONN_STATE_OPEN) { + } else if (or_conn->base_.state != OR_CONN_STATE_OPEN) { ++n_inprogress; } else if (or_conn->is_canonical) { ++n_canonical; @@ -867,10 +869,10 @@ connection_or_group_set_badness(or_connection_t *head, int force) /* Pass 2: We know how about how good the best connection is. * expire everything that's worse, and find the very best if we can. */ for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { - if (or_conn->_base.marked_for_close || + if (or_conn->base_.marked_for_close || connection_or_is_bad_for_new_circs(or_conn)) continue; /* This one doesn't need to be marked bad. */ - if (or_conn->_base.state != OR_CONN_STATE_OPEN) + if (or_conn->base_.state != OR_CONN_STATE_OPEN) continue; /* Don't mark anything bad until we have seen what happens * when the connection finishes. */ if (n_canonical && !or_conn->is_canonical) { @@ -880,8 +882,8 @@ connection_or_group_set_badness(or_connection_t *head, int force) "Marking OR conn to %s:%d as unsuitable for new circuits: " "(fd %d, %d secs old). It is not canonical, and we have " "another connection to that OR that is.", - or_conn->_base.address, or_conn->_base.port, or_conn->_base.s, - (int)(now - or_conn->_base.timestamp_created)); + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); continue; } @@ -913,9 +915,9 @@ connection_or_group_set_badness(or_connection_t *head, int force) * "mostly harmless", so a fix can wait until somebody is bored. */ for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { - if (or_conn->_base.marked_for_close || + if (or_conn->base_.marked_for_close || connection_or_is_bad_for_new_circs(or_conn) || - or_conn->_base.state != OR_CONN_STATE_OPEN) + or_conn->base_.state != OR_CONN_STATE_OPEN) continue; if (or_conn != best && channel_is_better(now, @@ -928,9 +930,9 @@ connection_or_group_set_badness(or_connection_t *head, int force) "Marking OR conn to %s:%d as unsuitable for new circuits: " "(fd %d, %d secs old). We have a better canonical one " "(fd %d; %d secs old).", - or_conn->_base.address, or_conn->_base.port, or_conn->_base.s, - (int)(now - or_conn->_base.timestamp_created), - best->_base.s, (int)(now - best->_base.timestamp_created)); + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created), + best->base_.s, (int)(now - best->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } else if (!tor_addr_compare(&or_conn->real_addr, &best->real_addr, CMP_EXACT)) { @@ -938,9 +940,9 @@ connection_or_group_set_badness(or_connection_t *head, int force) "Marking OR conn to %s:%d as unsuitable for new circuits: " "(fd %d, %d secs old). We have a better one with the " "same address (fd %d; %d secs old).", - or_conn->_base.address, or_conn->_base.port, or_conn->_base.s, - (int)(now - or_conn->_base.timestamp_created), - best->_base.s, (int)(now - best->_base.timestamp_created)); + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created), + best->base_.s, (int)(now - best->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } } @@ -1074,7 +1076,7 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port, if (proxy_type != PROXY_NONE) { tor_addr_copy(&addr, &proxy_addr); port = proxy_port; - conn->_base.proxy_state = PROXY_INFANT; + conn->base_.proxy_state = PROXY_INFANT; } } else { /* get_proxy_addrport() might fail if we have a Bridge line that @@ -1103,12 +1105,12 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port, return NULL; } - switch (connection_connect(TO_CONN(conn), conn->_base.address, + switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, port, &socket_error)) { case -1: /* If the connection failed immediately, and we're using * a proxy, our proxy is down. Don't blame the Tor server. */ - if (conn->_base.proxy_state == PROXY_INFANT) + if (conn->base_.proxy_state == PROXY_INFANT) entry_guard_register_connect_status(conn->identity_digest, 0, 1, time(NULL)); connection_or_connect_failed(conn, @@ -1207,27 +1209,27 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving) connection_or_change_state(conn, OR_CONN_STATE_TLS_HANDSHAKING); tor_assert(!conn->tls); - conn->tls = tor_tls_new(conn->_base.s, receiving); + conn->tls = tor_tls_new(conn->base_.s, receiving); if (!conn->tls) { log_warn(LD_BUG,"tor_tls_new failed. Closing."); return -1; } tor_tls_set_logged_address(conn->tls, // XXX client and relay? - escaped_safe_str(conn->_base.address)); + escaped_safe_str(conn->base_.address)); #ifdef USE_BUFFEREVENTS if (connection_type_uses_bufferevent(TO_CONN(conn))) { const int filtering = get_options()->UseFilteringSSLBufferevents; struct bufferevent *b = - tor_tls_init_bufferevent(conn->tls, conn->_base.bufev, conn->_base.s, + tor_tls_init_bufferevent(conn->tls, conn->base_.bufev, conn->base_.s, receiving, filtering); if (!b) { log_warn(LD_BUG,"tor_tls_init_bufferevent failed. Closing."); return -1; } - conn->_base.bufev = b; + conn->base_.bufev = b; if (conn->bucket_cfg) - tor_set_bufferevent_rate_limit(conn->_base.bufev, conn->bucket_cfg); + tor_set_bufferevent_rate_limit(conn->base_.bufev, conn->bucket_cfg); connection_enable_rate_limiting(TO_CONN(conn)); connection_configure_bufferevent_callbacks(TO_CONN(conn)); @@ -1239,7 +1241,7 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving) } #endif connection_start_reading(TO_CONN(conn)); - log_debug(LD_HANDSHAKE,"starting TLS handshake on fd %d", conn->_base.s); + log_debug(LD_HANDSHAKE,"starting TLS handshake on fd %d", conn->base_.s); note_crypto_pk_op(receiving ? TLS_HANDSHAKE_S : TLS_HANDSHAKE_C); IF_HAS_BUFFEREVENT(TO_CONN(conn), { @@ -1251,6 +1253,17 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving) return 0; } +/** Block all future attempts to renegotiate on 'conn' */ +void +connection_or_block_renegotiation(or_connection_t *conn) +{ + tor_tls_t *tls = conn->tls; + if (!tls) + return; + tor_tls_set_renegotiate_callback(tls, NULL, NULL); + tor_tls_block_renegotiation(tls); +} + /** Invoked on the server side from inside tor_tls_read() when the server * gets a successful TLS renegotiation from the client. */ static void @@ -1260,8 +1273,7 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) (void)tls; /* Don't invoke this again. */ - tor_tls_set_renegotiate_callback(tls, NULL, NULL); - tor_tls_block_renegotiation(tls); + connection_or_block_renegotiation(conn); if (connection_tls_finish_handshake(conn) < 0) { /* XXXX_TLS double-check that it's ok to do this from inside read. */ @@ -1281,12 +1293,12 @@ connection_tls_continue_handshake(or_connection_t *conn) int result; check_no_tls_errors(); again: - if (conn->_base.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { + if (conn->base_.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { // log_notice(LD_OR, "Renegotiate with %p", conn->tls); result = tor_tls_renegotiate(conn->tls); // log_notice(LD_OR, "Result: %d", result); } else { - tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING); + tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING); // log_notice(LD_OR, "Continue handshake with %p", conn->tls); result = tor_tls_handshake(conn->tls); // log_notice(LD_OR, "Result: %d", result); @@ -1299,7 +1311,7 @@ connection_tls_continue_handshake(or_connection_t *conn) case TOR_TLS_DONE: if (! tor_tls_used_v1_handshake(conn->tls)) { if (!tor_tls_is_server(conn->tls)) { - if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) { + if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { if (tor_tls_received_v3_certificate(conn->tls)) { log_info(LD_OR, "Client got a v3 cert! Moving on to v3 " "handshake."); @@ -1312,7 +1324,7 @@ connection_tls_continue_handshake(or_connection_t *conn) goto again; } } - // log_notice(LD_OR,"Done. state was %d.", conn->_base.state); + // log_notice(LD_OR,"Done. state was %d.", conn->base_.state); } else { /* v2/v3 handshake, but not a client. */ log_debug(LD_OR, "Done with initial SSL handshake (server-side). " @@ -1351,7 +1363,7 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, /* XXXX cut-and-paste code; should become a function. */ if (event & BEV_EVENT_CONNECTED) { - if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) { + if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { if (tor_tls_finish_handshake(conn->tls) < 0) { log_warn(LD_OR, "Problem finishing handshake"); connection_or_close_for_error(conn, 0); @@ -1361,7 +1373,7 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, if (! tor_tls_used_v1_handshake(conn->tls)) { if (!tor_tls_is_server(conn->tls)) { - if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) { + if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { if (tor_tls_received_v3_certificate(conn->tls)) { log_info(LD_OR, "Client got a v3 cert!"); if (connection_or_launch_v3_or_handshake(conn) < 0) @@ -1371,7 +1383,7 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, connection_or_change_state(conn, OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING); tor_tls_unblock_renegotiation(conn->tls); - if (bufferevent_ssl_renegotiate(conn->_base.bufev)<0) { + if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) { log_warn(LD_OR, "Start_renegotiating went badly."); connection_or_close_for_error(conn, 0); } @@ -1431,7 +1443,7 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event, int connection_or_nonopen_was_started_here(or_connection_t *conn) { - tor_assert(conn->_base.type == CONN_TYPE_OR); + tor_assert(conn->base_.type == CONN_TYPE_OR); if (!conn->tls) return 1; /* it's still in proxy states or something */ if (conn->handshake_state) @@ -1473,8 +1485,8 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, const or_options_t *options = get_options(); int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; const char *safe_address = - started_here ? conn->_base.address : - safe_str_client(conn->_base.address); + started_here ? conn->base_.address : + safe_str_client(conn->base_.address); const char *conn_type = started_here ? "outgoing" : "incoming"; int has_cert = 0; @@ -1483,7 +1495,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, if (started_here && !has_cert) { log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't " "send a cert! Closing.", - safe_address, conn->_base.port); + safe_address, conn->base_.port); return -1; } else if (!has_cert) { log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. " @@ -1497,7 +1509,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, if (started_here && v<0) { log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It" " has a cert but it's invalid. Closing.", - safe_address, conn->_base.port); + safe_address, conn->base_.port); return -1; } else if (v<0) { log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert " @@ -1505,7 +1517,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, } else { log_debug(LD_HANDSHAKE, "The certificate seems to be valid on %s connection " - "with %s:%d", conn_type, safe_address, conn->_base.port); + "with %s:%d", conn_type, safe_address, conn->base_.port); } check_no_tls_errors(); } @@ -1558,10 +1570,10 @@ connection_or_client_learned_peer_id(or_connection_t *conn, conn->identity_digest, DIGEST_LEN); log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing " "its key. Hoping for the best.", - conn->nickname, conn->_base.address, conn->_base.port); + conn->nickname, conn->base_.address, conn->base_.port); /* if it's a bridge and we didn't know its identity fingerprint, now * we do -- remember it for future attempts. */ - learned_router_identity(&conn->_base.addr, conn->_base.port, + learned_router_identity(&conn->base_.addr, conn->base_.port, (const char*)peer_id); } @@ -1575,7 +1587,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn, log_fn(severity, LD_HANDSHAKE, "Tried connecting to router at %s:%d, but identity key was not " "as expected: wanted %s but got %s.", - conn->_base.address, conn->_base.port, expected, seen); + conn->base_.address, conn->base_.port, expected, seen); entry_guard_register_connect_status(conn->identity_digest, 0, 1, time(NULL)); control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, @@ -1587,7 +1599,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn, return -1; } if (authdir_mode_tests_reachability(options)) { - dirserv_orconn_tls_done(&conn->_base.addr, conn->_base.port, + dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port, (const char*)peer_id); } @@ -1629,7 +1641,7 @@ connection_tls_finish_handshake(or_connection_t *conn) log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done. verifying.", started_here?"outgoing":"incoming", conn, - safe_str_client(conn->_base.address)); + safe_str_client(conn->base_.address)); directory_set_dirty(); @@ -1642,8 +1654,8 @@ connection_tls_finish_handshake(or_connection_t *conn) if (tor_tls_used_v1_handshake(conn->tls)) { conn->link_proto = 1; if (!started_here) { - connection_or_init_conn_from_address(conn, &conn->_base.addr, - conn->_base.port, digest_rcvd, 0); + connection_or_init_conn_from_address(conn, &conn->base_.addr, + conn->base_.port, digest_rcvd, 0); } tor_tls_block_renegotiation(conn->tls); return connection_or_set_state_open(conn); @@ -1652,8 +1664,8 @@ connection_tls_finish_handshake(or_connection_t *conn) if (connection_init_or_handshake_state(conn, started_here) < 0) return -1; if (!started_here) { - connection_or_init_conn_from_address(conn, &conn->_base.addr, - conn->_base.port, digest_rcvd, 0); + connection_or_init_conn_from_address(conn, &conn->base_.addr, + conn->base_.port, digest_rcvd, 0); } return connection_or_send_versions(conn, 0); } @@ -1826,7 +1838,7 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); - if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) + if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_cell(conn->handshake_state, cell, 0); if (cell->command != CELL_PADDING) @@ -1848,7 +1860,7 @@ connection_or_write_var_cell_to_buf(const var_cell_t *cell, connection_write_to_buf(hdr, sizeof(hdr), TO_CONN(conn)); connection_write_to_buf((char*)cell->payload, cell->payload_len, TO_CONN(conn)); - if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) + if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_var_cell(conn->handshake_state, cell, 0); if (cell->command != CELL_PADDING) conn->timestamp_last_added_nonpadding = approx_time(); @@ -1887,7 +1899,7 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn) while (1) { log_debug(LD_OR, "%d: starting, inbuf_datalen %d (%d pending in tls object).", - conn->_base.s,(int)connection_get_inbuf_len(TO_CONN(conn)), + conn->base_.s,(int)connection_get_inbuf_len(TO_CONN(conn)), tor_tls_get_pending_bytes(conn->tls)); if (connection_fetch_var_cell_from_buf(conn, &var_cell)) { if (!var_cell) @@ -2000,10 +2012,10 @@ connection_or_send_netinfo(or_connection_t *conn) /* Their address. */ out = cell.payload + 4; /* We use &conn->real_addr below, unless it hasn't yet been set. If it - * hasn't yet been set, we know that _base.addr hasn't been tampered with + * hasn't yet been set, we know that base_.addr hasn't been tampered with * yet either. */ len = append_address_to_payload(out, !tor_addr_is_null(&conn->real_addr) - ? &conn->real_addr : &conn->_base.addr); + ? &conn->real_addr : &conn->base_.addr); if (len<0) return -1; out += len; @@ -2050,7 +2062,7 @@ connection_or_send_certs_cell(or_connection_t *conn) ssize_t pos; int server_mode; - tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3); + tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); if (! conn->handshake_state) return -1; @@ -2097,7 +2109,7 @@ connection_or_send_auth_challenge_cell(or_connection_t *conn) var_cell_t *cell; uint8_t *cp; uint8_t challenge[OR_AUTH_CHALLENGE_LEN]; - tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3); + tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); if (! conn->handshake_state) return -1; diff --git a/src/or/connection_or.h b/src/or/connection_or.h index 22126b05fe..727de211b0 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -9,8 +9,8 @@ * \brief Header file for connection_or.c. **/ -#ifndef _TOR_CONNECTION_OR_H -#define _TOR_CONNECTION_OR_H +#ifndef TOR_CONNECTION_OR_H +#define TOR_CONNECTION_OR_H void connection_or_remove_from_identity_map(or_connection_t *conn); void connection_or_clear_identity_map(void); @@ -21,6 +21,7 @@ or_connection_t *connection_or_get_for_extend(const char *digest, int *launch_out); void connection_or_set_bad_connections(const char *digest, int force); +void connection_or_block_renegotiation(or_connection_t *conn); int connection_or_reached_eof(or_connection_t *conn); int connection_or_process_inbuf(or_connection_t *conn); int connection_or_flushed_some(or_connection_t *conn); diff --git a/src/or/control.c b/src/or/control.c index 75a8f5939a..ad2f2788f4 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -16,6 +16,7 @@ #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "circuitstats.h" #include "circuituse.h" #include "config.h" #include "confparse.h" @@ -26,6 +27,7 @@ #include "directory.h" #include "dirserv.h" #include "dnsserv.h" +#include "entrynodes.h" #include "geoip.h" #include "hibernate.h" #include "main.h" @@ -53,7 +55,7 @@ * because it is used both as a list of v0 event types, and as indices * into the bitfield to determine which controllers want which events. */ -#define _EVENT_MIN 0x0001 +#define EVENT_MIN_ 0x0001 #define EVENT_CIRCUIT_STATUS 0x0001 #define EVENT_STREAM_STATUS 0x0002 #define EVENT_OR_CONN_STATUS 0x0003 @@ -79,8 +81,8 @@ #define EVENT_BUILDTIMEOUT_SET 0x0017 #define EVENT_SIGNAL 0x0018 #define EVENT_CONF_CHANGED 0x0019 -#define _EVENT_MAX 0x0019 -/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */ +#define EVENT_MAX_ 0x0019 +/* If EVENT_MAX_ ever hits 0x0020, we need to make the mask wider. */ /** Bitfield: The bit 1<<e is set if <b>any</b> open control * connection is interested in events of type <b>e</b>. We use this @@ -595,7 +597,7 @@ send_control_event_string(uint16_t event, event_format_t which, { smartlist_t *conns = get_connection_array(); (void)which; - tor_assert(event >= _EVENT_MIN && event <= _EVENT_MAX); + tor_assert(event >= EVENT_MIN_ && event <= EVENT_MAX_); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (conn->type == CONN_TYPE_CONTROL && @@ -1218,9 +1220,9 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, connection_mark_for_close(TO_CONN(conn)); return 0; ok: - log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->_base.s); + log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->base_.s); send_control_done(conn); - conn->_base.state = CONTROL_CONN_STATE_OPEN; + conn->base_.state = CONTROL_CONN_STATE_OPEN; tor_free(password); if (sl) { /* clean up */ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); @@ -1323,7 +1325,7 @@ handle_control_takeownership(control_connection_t *conn, uint32_t len, log_info(LD_CONTROL, "Control connection %d has taken ownership of this " "Tor instance.", - (int)(conn->_base.s)); + (int)(conn->base_.s)); send_control_done(conn); return 0; @@ -1880,11 +1882,11 @@ circuit_describe_status_for_controller(origin_circuit_t *circ) } smartlist_add_asprintf(descparts, "PURPOSE=%s", - circuit_purpose_to_controller_string(circ->_base.purpose)); + circuit_purpose_to_controller_string(circ->base_.purpose)); { const char *hs_state = - circuit_purpose_to_controller_hs_state_string(circ->_base.purpose); + circuit_purpose_to_controller_hs_state_string(circ->base_.purpose); if (hs_state != NULL) { smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state); @@ -1898,7 +1900,7 @@ circuit_describe_status_for_controller(origin_circuit_t *circ) { char tbuf[ISO_TIME_USEC_LEN+1]; - format_iso_time_nospace_usec(tbuf, &circ->_base.timestamp_created); + format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created); smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf); } @@ -1922,7 +1924,7 @@ getinfo_helper_events(control_connection_t *control_conn, if (!strcmp(question, "circuit-status")) { circuit_t *circ_; smartlist_t *status = smartlist_new(); - for (circ_ = _circuit_get_global_list(); circ_; circ_ = circ_->next) { + for (circ_ = circuit_get_global_list_(); circ_; circ_ = circ_->next) { origin_circuit_t *circ; char *circdesc; const char *state; @@ -1930,7 +1932,7 @@ getinfo_helper_events(control_connection_t *control_conn, continue; circ = TO_ORIGIN_CIRCUIT(circ_); - if (circ->_base.state == CIRCUIT_STATE_OPEN) + if (circ->base_.state == CIRCUIT_STATE_OPEN) state = "BUILT"; else if (circ->cpath) state = "EXTENDED"; @@ -2007,7 +2009,7 @@ getinfo_helper_events(control_connection_t *control_conn, if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close) continue; conn = TO_OR_CONN(base_conn); - if (conn->_base.state == OR_CONN_STATE_OPEN) + if (conn->base_.state == OR_CONN_STATE_OPEN) state = "CONNECTED"; else if (conn->nickname) state = "LAUNCHED"; @@ -2534,7 +2536,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len, goto done; } } else { - if (circ->_base.state == CIRCUIT_STATE_OPEN) { + if (circ->base_.state == CIRCUIT_STATE_OPEN) { int err_reason = 0; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { @@ -2667,7 +2669,7 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len, TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; } - if (circ && (circ->_base.state != CIRCUIT_STATE_OPEN)) { + if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) { connection_write_str_to_buf( "551 Can't attach stream to non-open origin circuit\r\n", conn); @@ -3235,7 +3237,7 @@ connection_control_closed(control_connection_t *conn) static int is_valid_initial_command(control_connection_t *conn, const char *cmd) { - if (conn->_base.state == CONTROL_CONN_STATE_OPEN) + if (conn->base_.state == CONTROL_CONN_STATE_OPEN) return 1; if (!strcasecmp(cmd, "PROTOCOLINFO")) return (!conn->have_sent_protocolinfo && @@ -3280,8 +3282,8 @@ connection_control_process_inbuf(control_connection_t *conn) char *args; tor_assert(conn); - tor_assert(conn->_base.state == CONTROL_CONN_STATE_OPEN || - conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH); + tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN || + conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH); if (!conn->incoming_cmd) { conn->incoming_cmd = tor_malloc(1024); @@ -3289,7 +3291,7 @@ connection_control_process_inbuf(control_connection_t *conn) conn->incoming_cmd_cur_len = 0; } - if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH && + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && peek_connection_has_control0_command(TO_CONN(conn))) { /* Detect v0 commands and send a "no more v0" message. */ size_t body_len; @@ -3388,7 +3390,7 @@ connection_control_process_inbuf(control_connection_t *conn) return 0; } - if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH && + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && !is_valid_initial_command(conn, conn->incoming_cmd)) { connection_write_str_to_buf("514 Authentication required.\r\n", conn); connection_mark_for_close(TO_CONN(conn)); @@ -3792,7 +3794,7 @@ orconn_target_get_name(char *name, size_t len, or_connection_t *conn) DIGEST_LEN); } else { tor_snprintf(name, len, "%s:%d", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); } } @@ -3858,7 +3860,7 @@ control_event_stream_bandwidth(edge_connection_t *edge_conn) send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS, "650 STREAM_BW "U64_FORMAT" %lu %lu\r\n", - U64_PRINTF_ARG(edge_conn->_base.global_identifier), + U64_PRINTF_ARG(edge_conn->base_.global_identifier), (unsigned long)edge_conn->n_read, (unsigned long)edge_conn->n_written); @@ -3887,7 +3889,7 @@ control_event_stream_bandwidth_used(void) send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS, "650 STREAM_BW "U64_FORMAT" %lu %lu\r\n", - U64_PRINTF_ARG(edge_conn->_base.global_identifier), + U64_PRINTF_ARG(edge_conn->base_.global_identifier), (unsigned long)edge_conn->n_read, (unsigned long)edge_conn->n_written); diff --git a/src/or/control.h b/src/or/control.h index f301ce91be..eea3af724c 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -9,8 +9,8 @@ * \brief Header file for control.c. **/ -#ifndef _TOR_CONTROL_H -#define _TOR_CONTROL_H +#ifndef TOR_CONTROL_H +#define TOR_CONTROL_H void control_update_global_event_mask(void); void control_adjust_event_log_severity(void); diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h index 91172caa56..73c7eefd4c 100644 --- a/src/or/cpuworker.h +++ b/src/or/cpuworker.h @@ -9,8 +9,8 @@ * \brief Header file for cpuworker.c. **/ -#ifndef _TOR_CPUWORKER_H -#define _TOR_CPUWORKER_H +#ifndef TOR_CPUWORKER_H +#define TOR_CPUWORKER_H void cpu_init(void); void cpuworkers_rotate(void); diff --git a/src/or/directory.c b/src/or/directory.c index 8003444c6f..1d511b5749 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -13,6 +13,7 @@ #include "directory.h" #include "dirserv.h" #include "dirvote.h" +#include "entrynodes.h" #include "geoip.h" #include "main.h" #include "microdesc.h" @@ -246,7 +247,7 @@ directories_have_accepted_server_descriptor(void) smartlist_t *servers = router_get_trusted_dir_servers(); const or_options_t *options = get_options(); SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, { - if ((d->type & options->_PublishServerDescriptor) && + if ((d->type & options->PublishServerDescriptor_) && d->has_accepted_serverdesc) { return 1; } @@ -645,8 +646,8 @@ directory_conn_is_self_reachability_test(dir_connection_t *conn) const routerinfo_t *me = router_get_my_routerinfo(); if (me && router_digest_is_me(conn->identity_digest) && - tor_addr_eq_ipv4h(&conn->_base.addr, me->addr) && /*XXXX prop 118*/ - me->dir_port == conn->_base.port) + tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/ + me->dir_port == conn->base_.port) return 1; } return 0; @@ -664,35 +665,35 @@ connection_dir_request_failed(dir_connection_t *conn) } if (!entry_list_is_constrained(get_options())) router_set_status(conn->identity_digest, 0); /* don't try him again */ - if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", - conn->_base.address); + conn->base_.address); connection_dir_download_v2_networkstatus_failed(conn, -1); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC || - conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from " "directory server at '%s'; retrying", - conn->_base.address); + conn->base_.address); if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) connection_dir_bridge_routerdesc_failed(conn); connection_dir_download_routerdesc_failed(conn); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { if (conn->requested_resource) networkstatus_consensus_download_failed(0, conn->requested_resource); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { log_info(LD_DIR, "Giving up on certificate fetch from directory server " "at '%s'; retrying", - conn->_base.address); + conn->base_.address); connection_dir_download_cert_failed(conn, 0); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { log_info(LD_DIR, "Giving up downloading detached signatures from '%s'", - conn->_base.address); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { + conn->base_.address); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { log_info(LD_DIR, "Giving up downloading votes from '%s'", - conn->_base.address); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) { + conn->base_.address); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { log_info(LD_DIR, "Giving up on downloading microdescriptors from " - " directory server at '%s'; will retry", conn->_base.address); + " directory server at '%s'; will retry", conn->base_.address); connection_dir_download_routerdesc_failed(conn); } } @@ -718,7 +719,7 @@ connection_dir_download_v2_networkstatus_failed(dir_connection_t *conn, smartlist_t *trusted_dirs = router_get_trusted_dir_servers(); SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds, download_status_failed(&ds->v2_ns_dl_status, 0)); - directory_get_from_dirserver(conn->_base.purpose, conn->router_purpose, + directory_get_from_dirserver(conn->base_.purpose, conn->router_purpose, "all.z", 0 /* don't retry_if_no_servers */); } else if (!strcmpstart(conn->requested_resource, "fp/")) { /* We were trying to download by fingerprint; mark them all as having @@ -763,9 +764,9 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn) /* No need to relaunch descriptor downloads here: we already do it * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ - tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC || - conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || - conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC); + tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || + conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); (void) conn; } @@ -789,7 +790,7 @@ connection_dir_bridge_routerdesc_failed(dir_connection_t *conn) + strlen("fp/"), which, NULL, 0); - tor_assert(conn->_base.purpose != DIR_PURPOSE_FETCH_EXTRAINFO); + tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO); if (smartlist_len(which)) { connection_dir_retry_bridges(which); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); @@ -802,7 +803,7 @@ static void connection_dir_download_cert_failed(dir_connection_t *conn, int status) { smartlist_t *failed; - tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE); + tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE); if (!conn->requested_resource) return; @@ -934,16 +935,16 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, conn = dir_connection_new(tor_addr_family(&addr)); /* set up conn so it's got all the data we need to remember */ - tor_addr_copy(&conn->_base.addr, &addr); - conn->_base.port = use_begindir ? or_port : dir_port; - conn->_base.address = tor_strdup(address); + tor_addr_copy(&conn->base_.addr, &addr); + conn->base_.port = use_begindir ? or_port : dir_port; + conn->base_.address = tor_strdup(address); memcpy(conn->identity_digest, digest, DIGEST_LEN); - conn->_base.purpose = dir_purpose; + conn->base_.purpose = dir_purpose; conn->router_purpose = router_purpose; /* give it an initial state */ - conn->_base.state = DIR_CONN_STATE_CONNECTING; + conn->base_.state = DIR_CONN_STATE_CONNECTING; /* decide whether we can learn our IP address from this conn */ /* XXXX This is a bad name for this field now. */ @@ -961,7 +962,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, dir_port = options->HTTPProxyPort; } - switch (connection_connect(TO_CONN(conn), conn->_base.address, &addr, + switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, dir_port, &socket_error)) { case -1: connection_dir_request_failed(conn); /* retry if we want */ @@ -971,7 +972,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, return; case 1: /* start flushing conn */ - conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; + conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* fall through */ case 0: /* queue the command on the outbuf */ @@ -994,7 +995,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, if (anonymized_connection && use_begindir) rep_hist_note_used_internal(time(NULL), 0, 1); else if (anonymized_connection && !use_begindir) - rep_hist_note_used_port(time(NULL), conn->_base.port); + rep_hist_note_used_port(time(NULL), conn->base_.port); /* make an AP connection * populate it and add it at the right state @@ -1002,7 +1003,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, */ linked_conn = connection_ap_make_link(TO_CONN(conn), - conn->_base.address, conn->_base.port, + conn->base_.address, conn->base_.port, digest, SESSION_GROUP_DIRCONN, iso_flags, use_begindir, conn->dirconn_direct); @@ -1017,7 +1018,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, connection_mark_for_close(TO_CONN(conn)); return; } - conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; + conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* queue the command on the outbuf */ directory_send_command(conn, dir_purpose, 0, resource, payload, payload_len, @@ -1050,7 +1051,7 @@ connection_dir_is_encrypted(dir_connection_t *conn) * sort strings alphabetically */ static int -_compare_strs(const void **a, const void **b) +compare_strs_(const void **a, const void **b) { const char *s1 = *a, *s2 = *b; return strcmp(s1, s2); @@ -1097,7 +1098,7 @@ directory_get_consensus_url(const char *resource) ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN); smartlist_add(authority_digests, hex); } SMARTLIST_FOREACH_END(ds); - smartlist_sort(authority_digests, _compare_strs); + smartlist_sort(authority_digests, compare_strs_); authority_id_list = smartlist_join_strings(authority_digests, "+", 0, NULL); @@ -1128,18 +1129,18 @@ directory_send_command(dir_connection_t *conn, const char *httpcommand = NULL; tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->base_.type == CONN_TYPE_DIR); tor_free(conn->requested_resource); if (resource) conn->requested_resource = tor_strdup(resource); /* come up with a string for which Host: we want */ - if (conn->_base.port == 80) { - strlcpy(hoststring, conn->_base.address, sizeof(hoststring)); + if (conn->base_.port == 80) { + strlcpy(hoststring, conn->base_.address, sizeof(hoststring)); } else { tor_snprintf(hoststring, sizeof(hoststring),"%s:%d", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); } /* Format if-modified-since */ @@ -1574,9 +1575,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn) compress_method_t compression; int plausible; int skewed=0; - int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC || - conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || - conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC); + int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || + conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); int was_compressed=0; time_t now = time(NULL); @@ -1587,7 +1588,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case -1: /* overflow */ log_warn(LD_PROTOCOL, "'fetch' response too large (server '%s:%d'). Closing.", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); return -1; case 0: log_info(LD_HTTP, @@ -1600,7 +1601,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (parse_http_response(headers, &status_code, &date_header, &compression, &reason) < 0) { log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); return -1; } @@ -1609,9 +1610,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_debug(LD_DIR, "Received response from directory server '%s:%d': %d %s " "(purpose: %d)", - conn->_base.address, conn->_base.port, status_code, + conn->base_.address, conn->base_.port, status_code, escaped(reason), - conn->_base.purpose); + conn->base_.purpose); /* now check if it's got any hints for us about our IP address. */ if (conn->dirconn_direct) { @@ -1628,7 +1629,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * and the date header. (We used to check now-date_header, but that's * inaccurate if we spend a lot of time downloading.) */ - delta = conn->_base.timestamp_lastwritten - date_header; + delta = conn->base_.timestamp_lastwritten - date_header; if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) { char dbuf[64]; int trusted = router_digest_is_trusted_dir(conn->identity_digest); @@ -1639,14 +1640,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "It seems that our clock is %s by %s, or that theirs is %s. " "Tor requires an accurate clock to work: please check your time, " "timezone, and date settings.", - conn->_base.address, conn->_base.port, + conn->base_.address, conn->base_.port, delta>0 ? "ahead" : "behind", dbuf, delta>0 ? "behind" : "ahead"); skewed = 1; /* don't check the recommended-versions line */ if (trusted) control_event_general_status(LOG_WARN, "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d", - delta, conn->_base.address, conn->_base.port); + delta, conn->base_.address, conn->base_.port); } else { log_debug(LD_HTTP, "Time on received directory is within tolerance; " "we are %ld seconds skewed. (That's okay.)", delta); @@ -1660,8 +1661,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) const char *id_digest = conn->identity_digest; log_info(LD_DIR,"Received http status code %d (%s) from server " "'%s:%d'. I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); if ((rs = router_get_mutable_consensus_status_by_id(id_digest))) rs->last_dir_503_at = now; if ((ds = router_get_trusteddirserver_by_digest(id_digest))) @@ -1671,7 +1672,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) return -1; } - plausible = body_is_plausible(body, body_len, conn->_base.purpose); + plausible = body_is_plausible(body, body_len, conn->base_.purpose); if (compression != NO_METHOD || !plausible) { char *new_body = NULL; size_t new_len = 0; @@ -1698,7 +1699,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, " "but it seems to be %s.%s", - conn->_base.address, conn->_base.port, description1, + conn->base_.address, conn->base_.port, description1, description2, (compression>0 && guessed>0)?" Trying both.":""); } @@ -1718,7 +1719,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (!plausible && !new_body) { log_fn(LOG_PROTOCOL_WARN, LD_HTTP, "Unable to decompress HTTP body (server '%s:%d').", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } @@ -1730,12 +1731,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { smartlist_t *which = NULL; v2_networkstatus_source_t source; char *cp; log_info(LD_DIR,"Received networkstatus objects (size %d) from server " - "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port); + "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); if (status_code != 200) { static ratelim_t warning_limit = RATELIM_INIT(3600); char *m; @@ -1744,8 +1745,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/status/%s\". " "I'll try again soon.%s", - status_code, escaped(reason), conn->_base.address, - conn->_base.port, conn->requested_resource, m); + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource, m); tor_free(m); } tor_free(body); tor_free(headers); tor_free(reason); @@ -1801,7 +1802,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { int r; const char *flavname = conn->requested_resource; if (status_code != 200) { @@ -1809,19 +1810,19 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log(severity, LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching consensus directory.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); networkstatus_consensus_download_failed(status_code, flavname); return -1; } log_info(LD_DIR,"Received consensus directory (size %d) from server " - "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port); + "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) { log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR, "Unable to load %s consensus directory downloaded from " "server '%s:%d'. I'll try again soon.", - flavname, conn->_base.address, conn->_base.port); + flavname, conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); networkstatus_consensus_download_failed(0, flavname); return -1; @@ -1834,19 +1835,19 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_DIR, "Successfully loaded consensus."); } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/keys/%s\".", - status_code, escaped(reason), conn->_base.address, - conn->_base.port, conn->requested_resource); + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource); connection_dir_download_cert_failed(conn, status_code); tor_free(body); tor_free(headers); tor_free(reason); return -1; } log_info(LD_DIR,"Received authority certificates (size %d) from server " - "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port); + "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) { log_warn(LD_DIR, "Unable to parse fetched certificates"); /* if we fetched more than one and only some failed, the successful @@ -1857,17 +1858,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_DIR, "Successfully loaded certificates from fetch."); } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { const char *msg; int st; log_info(LD_DIR,"Got votes (size %d) from server %s:%d", - (int)body_len, conn->_base.address, conn->_base.port); + (int)body_len, conn->base_.address, conn->base_.port); if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".", - status_code, escaped(reason), conn->_base.address, - conn->_base.port, conn->requested_resource); + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource); tor_free(body); tor_free(headers); tor_free(reason); return -1; } @@ -1878,35 +1879,35 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg); } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { const char *msg = NULL; log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d", - (int)body_len, conn->_base.address, conn->_base.port); + (int)body_len, conn->base_.address, conn->base_.port); if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server '%s:%d' while fetching " "\"/tor/status-vote/next/consensus-signatures.z\".", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } - if (dirvote_add_signatures(body, conn->_base.address, &msg)<0) { + if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) { log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s", - conn->_base.address, conn->_base.port, msg?msg:"???"); + conn->base_.address, conn->base_.port, msg?msg:"???"); } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC || - conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { - int was_ei = conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO; + if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { + int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO; smartlist_t *which = NULL; int n_asked_for = 0; int descriptor_digests = conn->requested_resource && !strcmpstart(conn->requested_resource,"d/"); log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'", was_ei ? "extra server info" : "server info", - (int)body_len, conn->_base.address, conn->_base.port); + (int)body_len, conn->base_.address, conn->base_.port); if (conn->requested_resource && (!strcmpstart(conn->requested_resource,"d/") || !strcmpstart(conn->requested_resource,"fp/"))) { @@ -1924,8 +1925,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR, "Received http status code %d (%s) from server '%s:%d' " "while fetching \"/tor/server/%s\". I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port, conn->requested_resource); + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource); if (!which) { connection_dir_download_routerdesc_failed(conn); } else { @@ -1959,7 +1960,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) // descriptor_digests, conn->router_purpose); if (load_downloaded_routers(body, which, descriptor_digests, conn->router_purpose, - conn->_base.address)) + conn->base_.address)) directory_info_has_arrived(now, 0); } } @@ -1967,7 +1968,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_DIR, "Received %d/%d %s requested from %s:%d", n_asked_for-smartlist_len(which), n_asked_for, was_ei ? "extra-info documents" : "router descriptors", - conn->_base.address, (int)conn->_base.port); + conn->base_.address, (int)conn->base_.port); if (smartlist_len(which)) { dir_routerdesc_download_failed(which, status_code, conn->router_purpose, @@ -1979,12 +1980,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (directory_conn_is_self_reachability_test(conn)) router_dirport_found_reachable(); } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { smartlist_t *which = NULL; log_info(LD_DIR,"Received answer to microdescriptor request (status %d, " "size %d) from server '%s:%d'", - status_code, (int)body_len, conn->_base.address, - conn->_base.port); + status_code, (int)body_len, conn->base_.address, + conn->base_.port); tor_assert(conn->requested_resource && !strcmpstart(conn->requested_resource, "d/")); which = smartlist_new(); @@ -1995,8 +1996,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_DIR, "Received status code %d (%s) from server " "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again " "soon.", - status_code, escaped(reason), conn->_base.address, - (int)conn->_base.port, conn->requested_resource); + status_code, escaped(reason), conn->base_.address, + (int)conn->base_.port, conn->requested_resource); dir_microdesc_download_failed(which, status_code); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); @@ -2017,7 +2018,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } } - if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) { + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR) { switch (status_code) { case 200: { trusted_dir_server_t *ds = @@ -2043,7 +2044,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "descriptor: finished."); control_event_server_status( LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); ds->has_accepted_serverdesc = 1; if (directories_have_accepted_server_descriptor()) @@ -2053,72 +2054,72 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case 400: log_warn(LD_GENERAL,"http status 400 (%s) response from " "dirserver '%s:%d'. Please correct.", - escaped(reason), conn->_base.address, conn->_base.port); + escaped(reason), conn->base_.address, conn->base_.port); control_event_server_status(LOG_WARN, "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"", - conn->_base.address, conn->_base.port, escaped(reason)); + conn->base_.address, conn->base_.port, escaped(reason)); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected while uploading " "descriptor to server '%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } - if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) { + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE) { switch (status_code) { case 200: { log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); } break; case 400: log_warn(LD_DIR,"http status 400 (%s) response after uploading " "vote to dirserver '%s:%d'. Please correct.", - escaped(reason), conn->_base.address, conn->_base.port); + escaped(reason), conn->base_.address, conn->base_.port); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected while uploading " "vote to server '%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } - if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) { + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) { switch (status_code) { case 200: { log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d", - conn->_base.address, conn->_base.port); + conn->base_.address, conn->base_.port); } break; case 400: log_warn(LD_DIR,"http status 400 (%s) response after uploading " "signatures to dirserver '%s:%d'. Please correct.", - escaped(reason), conn->_base.address, conn->_base.port); + escaped(reason), conn->base_.address, conn->base_.port); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected while uploading " "signatures to server '%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC) { tor_assert(conn->rend_data); log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", @@ -2136,7 +2137,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } else { /* Success, or at least there's a v2 descriptor already * present. Notify pending connections about this. */ - conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; rend_client_desc_trynow(conn->rend_data->onion_address); } break; @@ -2152,13 +2153,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn) default: log_warn(LD_REND,"http status %d (%s) response unexpected while " "fetching hidden service descriptor (server '%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); break; } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) { + if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) { tor_assert(conn->rend_data); log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", @@ -2177,13 +2178,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * and _not_ performing another request. */ log_info(LD_REND, "Successfully fetched v2 rendezvous " "descriptor, but we already have a v0 descriptor."); - conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; break; default: /* success. notify pending connections about this. */ log_info(LD_REND, "Successfully fetched v2 rendezvous " "descriptor."); - conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; rend_client_desc_trynow(conn->rend_data->onion_address); break; } @@ -2205,14 +2206,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "http status %d (%s) response unexpected while " "fetching v2 hidden service descriptor (server '%s:%d'). " "Retrying at another directory.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); break; } } - if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC || - conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) { + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC || + conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) { log_info(LD_REND,"Uploaded rendezvous descriptor (status %d " "(%s))", status_code, escaped(reason)); @@ -2225,17 +2226,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case 400: log_warn(LD_REND,"http status 400 (%s) response from dirserver " "'%s:%d'. Malformed rendezvous descriptor?", - escaped(reason), conn->_base.address, conn->_base.port); + escaped(reason), conn->base_.address, conn->base_.port); break; default: log_warn(LD_REND,"http status %d (%s) response unexpected (server " "'%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->base_.address, + conn->base_.port); break; } } - note_client_request(conn->_base.purpose, was_compressed, orig_len); + note_client_request(conn->base_.purpose, was_compressed, orig_len); tor_free(body); tor_free(headers); tor_free(reason); return 0; } @@ -2245,9 +2246,9 @@ int connection_dir_reached_eof(dir_connection_t *conn) { int retval; - if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) { + if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) { log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.", - conn->_base.state); + conn->base_.state); connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */ connection_mark_for_close(TO_CONN(conn)); return -1; @@ -2255,7 +2256,7 @@ connection_dir_reached_eof(dir_connection_t *conn) retval = connection_dir_client_reached_eof(conn); if (retval == 0) /* success */ - conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED; + conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED; connection_mark_for_close(TO_CONN(conn)); return retval; } @@ -2273,7 +2274,7 @@ int connection_dir_process_inbuf(dir_connection_t *conn) { tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->base_.type == CONN_TYPE_DIR); /* Directory clients write, then read data until they receive EOF; * directory servers read data until they get an HTTP command, then @@ -2282,7 +2283,7 @@ connection_dir_process_inbuf(dir_connection_t *conn) */ /* If we're on the dirserver side, look for a command. */ - if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { + if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { if (directory_handle_command(conn) < 0) { connection_mark_for_close(TO_CONN(conn)); return -1; @@ -2297,7 +2298,7 @@ connection_dir_process_inbuf(dir_connection_t *conn) return -1; } - if (!conn->_base.inbuf_reached_eof) + if (!conn->base_.inbuf_reached_eof) log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf."); return 0; } @@ -2370,12 +2371,12 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length, tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type); cp += strlen(cp); } - if (!is_local_addr(&conn->_base.addr)) { + if (!is_local_addr(&conn->base_.addr)) { /* Don't report the source address for a nearby/private connection. * Otherwise we tend to mis-report in cases where incoming ports are * being forwarded to a Tor server running behind the firewall. */ tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - X_ADDRESS_HEADER "%s\r\n", conn->_base.address); + X_ADDRESS_HEADER "%s\r\n", conn->base_.address); cp += strlen(cp); } if (encoding) { @@ -2627,7 +2628,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, log_debug(LD_DIRSERV,"Received GET command."); - conn->_base.state = DIR_CONN_STATE_SERVER_WRITING; + conn->base_.state = DIR_CONN_STATE_SERVER_WRITING; if (parse_http_url(headers, &url) < 0) { write_http_status_line(conn, 400, "Bad request"); @@ -3168,6 +3169,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, } if (options->HidServDirectoryV2 && + connection_dir_is_encrypted(conn) && !strcmpstart(url,"/tor/rendezvous2/")) { /* Handle v2 rendezvous descriptor fetch request. */ const char *descp; @@ -3220,7 +3222,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, } if (options->BridgeAuthoritativeDir && - options->_BridgePassword_AuthDigest && + options->BridgePassword_AuthDigest_ && connection_dir_is_encrypted(conn) && !strcmp(url,"/tor/networkstatus-bridges")) { char *status; @@ -3233,7 +3235,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, /* now make sure the password is there and right */ if (!header || tor_memneq(digest, - options->_BridgePassword_AuthDigest, DIGEST256_LEN)) { + options->BridgePassword_AuthDigest_, DIGEST256_LEN)) { write_http_status_line(conn, 404, "Not found"); tor_free(header); goto done; @@ -3289,7 +3291,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, }while(0); if (!strcmp(url,"/tor/mallinfo.txt") && - (tor_addr_eq_ipv4h(&conn->_base.addr, 0x7f000001ul))) { + (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) { char *result; size_t len; struct mallinfo mi; @@ -3344,7 +3346,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, log_debug(LD_DIRSERV,"Received POST command."); - conn->_base.state = DIR_CONN_STATE_SERVER_WRITING; + conn->base_.state = DIR_CONN_STATE_SERVER_WRITING; if (parse_http_url(headers, &url) < 0) { write_http_status_line(conn, 400, "Bad request"); @@ -3354,18 +3356,19 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, /* Handle v2 rendezvous service publish request. */ if (options->HidServDirectoryV2 && + connection_dir_is_encrypted(conn) && !strcmpstart(url,"/tor/rendezvous2/publish")) { switch (rend_cache_store_v2_desc_as_dir(body)) { case -2: log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s " "since we're not currently a hidden service directory.", - (int)body_len, conn->_base.address); + (int)body_len, conn->base_.address); write_http_status_line(conn, 503, "Currently not acting as v2 " "hidden service directory"); break; case -1: log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.", - (int)body_len, conn->_base.address); + (int)body_len, conn->base_.address); write_http_status_line(conn, 400, "Invalid v2 service descriptor rejected"); break; @@ -3390,7 +3393,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, uint8_t purpose = authdir_mode_bridge(options) ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL; was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose, - conn->_base.address, &msg); + conn->base_.address, &msg); tor_assert(msg); if (WRA_WAS_ADDED(r)) dirserv_get_directory(); /* rebuild and write to disk */ @@ -3400,7 +3403,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, log_info(LD_DIRSERV, "Problematic router descriptor or extra-info from %s " "(\"%s\").", - conn->_base.address, msg); + conn->base_.address, msg); write_http_status_line(conn, 400, msg); } else if (r == ROUTER_ADDED_SUCCESSFULLY) { write_http_status_line(conn, 200, msg); @@ -3411,7 +3414,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, log_info(LD_DIRSERV, "Rejected router descriptor or extra-info from %s " "(\"%s\").", - conn->_base.address, msg); + conn->base_.address, msg); write_http_status_line(conn, 400, msg); } goto done; @@ -3424,7 +3427,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, if (rend_cache_store(body, body_len, 1, NULL) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV, "Rejected rend descriptor (length %d) from %s.", - (int)body_len, conn->_base.address); + (int)body_len, conn->base_.address); write_http_status_line(conn, 400, "Invalid v0 service descriptor rejected"); } else { @@ -3442,7 +3445,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, } else { tor_assert(msg); log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").", - conn->_base.address, msg); + conn->base_.address, msg); write_http_status_line(conn, status, msg); } goto done; @@ -3451,11 +3454,11 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, if (authdir_mode_v3(options) && !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */ const char *msg = NULL; - if (dirvote_add_signatures(body, conn->_base.address, &msg)>=0) { + if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) { write_http_status_line(conn, 200, msg?msg:"Signatures stored"); } else { log_warn(LD_DIR, "Unable to store signatures posted by %s: %s", - conn->_base.address, msg?msg:"???"); + conn->base_.address, msg?msg:"???"); write_http_status_line(conn, 400, msg?msg:"Unable to store signatures"); } goto done; @@ -3482,7 +3485,7 @@ directory_handle_command(dir_connection_t *conn) int r; tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->base_.type == CONN_TYPE_DIR); switch (connection_fetch_from_buf_http(TO_CONN(conn), &headers, MAX_HEADERS_SIZE, @@ -3490,7 +3493,7 @@ directory_handle_command(dir_connection_t *conn) case -1: /* overflow */ log_warn(LD_DIRSERV, "Request too large from address '%s' to DirPort. Closing.", - safe_str(conn->_base.address)); + safe_str(conn->base_.address)); return -1; case 0: log_debug(LD_DIRSERV,"command not all here yet."); @@ -3524,7 +3527,7 @@ int connection_dir_finished_flushing(dir_connection_t *conn) { tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->base_.type == CONN_TYPE_DIR); /* Note that we have finished writing the directory response. For direct * connections this means we're done, for tunneled connections its only @@ -3536,11 +3539,11 @@ connection_dir_finished_flushing(dir_connection_t *conn) geoip_change_dirreq_state(TO_CONN(conn)->global_identifier, DIRREQ_DIRECT, DIRREQ_FLUSHING_DIR_CONN_FINISHED); - switch (conn->_base.state) { + switch (conn->base_.state) { case DIR_CONN_STATE_CONNECTING: case DIR_CONN_STATE_CLIENT_SENDING: log_debug(LD_DIR,"client finished sending command."); - conn->_base.state = DIR_CONN_STATE_CLIENT_READING; + conn->base_.state = DIR_CONN_STATE_CLIENT_READING; return 0; case DIR_CONN_STATE_SERVER_WRITING: if (conn->dir_spool_src != DIR_SPOOL_NONE) { @@ -3561,7 +3564,7 @@ connection_dir_finished_flushing(dir_connection_t *conn) return 0; default: log_warn(LD_BUG,"called in unexpected state %d.", - conn->_base.state); + conn->base_.state); tor_fragile_assert(); return -1; } @@ -3574,13 +3577,13 @@ int connection_dir_finished_connecting(dir_connection_t *conn) { tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); - tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING); + tor_assert(conn->base_.type == CONN_TYPE_DIR); + tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING); log_debug(LD_HTTP,"Dir connection to router %s:%u established.", - conn->_base.address,conn->_base.port); + conn->base_.address,conn->base_.port); - conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ + conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ return 0; } @@ -3817,7 +3820,7 @@ dir_microdesc_download_failed(smartlist_t *failed, /** Helper. Compare two fp_pair_t objects, and return negative, 0, or * positive as appropriate. */ static int -_compare_pairs(const void **a, const void **b) +compare_pairs_(const void **a, const void **b) { const fp_pair_t *fp1 = *a, *fp2 = *b; int r; @@ -3868,8 +3871,8 @@ dir_split_resource_into_fingerprint_pairs(const char *res, smartlist_free(pairs_tmp); /* Uniq-and-sort */ - smartlist_sort(pairs_result, _compare_pairs); - smartlist_uniq(pairs_result, _compare_pairs, _tor_free); + smartlist_sort(pairs_result, compare_pairs_); + smartlist_uniq(pairs_result, compare_pairs_, tor_free_); smartlist_add_all(pairs_out, pairs_result); smartlist_free(pairs_result); diff --git a/src/or/directory.h b/src/or/directory.h index fef671a0ef..9ff78d12c4 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -9,8 +9,8 @@ * \brief Header file for directory.c. **/ -#ifndef _TOR_DIRECTORY_H -#define _TOR_DIRECTORY_H +#ifndef TOR_DIRECTORY_H +#define TOR_DIRECTORY_H int directories_have_accepted_server_descriptor(void); void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, diff --git a/src/or/dirserv.c b/src/or/dirserv.c index ec4ecfa426..e7aa582cfc 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -93,7 +93,8 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp( const char *fp, int extrainfo, time_t publish_cutoff); -static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg); +static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, + const char **msg); /************** Measured Bandwidth parsing code ******/ #define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ @@ -515,8 +516,8 @@ dirserv_free_fingerprint_list(void) if (!fingerprint_list) return; - strmap_free(fingerprint_list->fp_by_name, _tor_free); - digestmap_free(fingerprint_list->status_by_digest, _tor_free); + strmap_free(fingerprint_list->fp_by_name, tor_free_); + digestmap_free(fingerprint_list->status_by_digest, tor_free_); tor_free(fingerprint_list); } @@ -1426,7 +1427,7 @@ clear_cached_dir(cached_dir_t *d) /** Free all storage held by the cached_dir_t in <b>d</b>. */ static void -_free_cached_dir(void *_d) +free_cached_dir_(void *_d) { cached_dir_t *d; if (!_d) @@ -2257,7 +2258,7 @@ routerstatus_format_entry(char *buf, size_t buf_len, * and a router with more bandwidth is more useful than one with less.) **/ static int -_compare_routerinfo_by_ip_and_bw(const void **a, const void **b) +compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) { routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; int first_is_auth, second_is_auth; @@ -2332,7 +2333,7 @@ get_possible_sybil_list(const smartlist_t *routers) max_with_same_addr_on_authority = INT_MAX; smartlist_add_all(routers_by_ip, routers); - smartlist_sort(routers_by_ip, _compare_routerinfo_by_ip_and_bw); + smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_); omit_as_sybil = digestmap_new(); last_addr = 0; @@ -3848,7 +3849,7 @@ connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn) int connection_dirserv_flushed_some(dir_connection_t *conn) { - tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING); + tor_assert(conn->base_.state == DIR_CONN_STATE_SERVER_WRITING); if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN) return 0; @@ -3883,9 +3884,9 @@ dirserv_free_all(void) cached_dir_decref(cached_directory); clear_cached_dir(&cached_runningrouters); - digestmap_free(cached_v2_networkstatus, _free_cached_dir); + digestmap_free(cached_v2_networkstatus, free_cached_dir_); cached_v2_networkstatus = NULL; - strmap_free(cached_consensuses, _free_cached_dir); + strmap_free(cached_consensuses, free_cached_dir_); cached_consensuses = NULL; } diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 8508c938a8..ca401407d5 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -9,8 +9,8 @@ * \brief Header file for dirserv.c. **/ -#ifndef _TOR_DIRSERV_H -#define _TOR_DIRSERV_H +#ifndef TOR_DIRSERV_H +#define TOR_DIRSERV_H /** What fraction (1 over this number) of the relay ID space do we * (as a directory authority) launch connections to at each reachability diff --git a/src/or/dirvote.c b/src/or/dirvote.c index d98e18b437..70209435cb 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -323,7 +323,7 @@ typedef struct dir_src_ent_t { /** Helper for sorting networkstatus_t votes (not consensuses) by the * hash of their voters' identity digests. */ static int -_compare_votes_by_authority_id(const void **_a, const void **_b) +compare_votes_by_authority_id_(const void **_a, const void **_b) { const networkstatus_t *a = *_a, *b = *_b; return fast_memcmp(get_voter(a)->identity_digest, @@ -334,7 +334,7 @@ _compare_votes_by_authority_id(const void **_a, const void **_b) * their identity digests, and return -1, 0, or 1 depending on their * ordering */ static int -_compare_dir_src_ents_by_authority_id(const void **_a, const void **_b) +compare_dir_src_ents_by_authority_id_(const void **_a, const void **_b) { const dir_src_ent_t *a = *_a, *b = *_b; const networkstatus_voter_info_t *a_v = get_voter(a->v), @@ -401,7 +401,7 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b) /** Helper for sorting routerlists based on compare_vote_rs. */ static int -_compare_vote_rs(const void **_a, const void **_b) +compare_vote_rs_(const void **_a, const void **_b) { const vote_routerstatus_t *a = *_a, *b = *_b; return compare_vote_rs(a,b); @@ -409,7 +409,7 @@ _compare_vote_rs(const void **_a, const void **_b) /** Helper for sorting OR ports. */ static int -_compare_orports(const void **_a, const void **_b) +compare_orports_(const void **_a, const void **_b) { const tor_addr_port_t *a = *_a, *b = *_b; int r; @@ -436,11 +436,11 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method, int most_n = 0, cur_n = 0; time_t most_published = 0; - /* _compare_vote_rs() sorts the items by identity digest (all the same), + /* compare_vote_rs_() sorts the items by identity digest (all the same), * then by SD digest. That way, if we have a tie that the published_on * date cannot tie, we use the descriptor with the smaller digest. */ - smartlist_sort(votes, _compare_vote_rs); + smartlist_sort(votes, compare_vote_rs_); SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) { if (cur && !compare_vote_rs(cur, rs)) { ++cur_n; @@ -484,9 +484,9 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method, } } SMARTLIST_FOREACH_END(rs); - smartlist_sort(alt_orports, _compare_orports); + smartlist_sort(alt_orports, compare_orports_); most_alt_orport = smartlist_get_most_frequent(alt_orports, - _compare_orports); + compare_orports_); if (most_alt_orport) { memcpy(best_alt_orport_out, most_alt_orport, sizeof(tor_addr_port_t)); log_debug(LD_DIR, "\"a\" line winner for %s is %s", @@ -543,7 +543,7 @@ hash_list_members(char *digest_out, size_t len_out, * positive integers. (Non-integers are treated as prior to all integers, and * compared lexically.) */ static int -_cmp_int_strings(const void **_a, const void **_b) +cmp_int_strings_(const void **_a, const void **_b) { const char *a = *_a, *b = *_b; int ai = (int)tor_parse_long(a, 10, 1, INT_MAX, NULL, NULL); @@ -574,13 +574,13 @@ compute_consensus_method(smartlist_t *votes) { tor_assert(vote->supported_methods); smartlist_add_all(tmp, vote->supported_methods); - smartlist_sort(tmp, _cmp_int_strings); - smartlist_uniq(tmp, _cmp_int_strings, NULL); + smartlist_sort(tmp, cmp_int_strings_); + smartlist_uniq(tmp, cmp_int_strings_, NULL); smartlist_add_all(all_methods, tmp); smartlist_clear(tmp); }); - smartlist_sort(all_methods, _cmp_int_strings); + smartlist_sort(all_methods, cmp_int_strings_); get_frequent_members(acceptable_methods, all_methods, min); n_ok = smartlist_len(acceptable_methods); if (n_ok) { @@ -1529,7 +1529,7 @@ networkstatus_compute_consensus(smartlist_t *votes, } /* Sort the votes. */ - smartlist_sort(votes, _compare_votes_by_authority_id); + smartlist_sort(votes, compare_votes_by_authority_id_); /* Add the authority sections. */ { smartlist_t *dir_sources = smartlist_new(); @@ -1548,7 +1548,7 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_add(dir_sources, e_legacy); } } SMARTLIST_FOREACH_END(v); - smartlist_sort(dir_sources, _compare_dir_src_ents_by_authority_id); + smartlist_sort(dir_sources, compare_dir_src_ents_by_authority_id_); SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) { char fingerprint[HEX_DIGEST_LEN+1]; @@ -2487,7 +2487,7 @@ ns_detached_signatures_free(ns_detached_signatures_t *s) smartlist_free(sigs); } STRMAP_FOREACH_END; strmap_free(s->signatures, NULL); - strmap_free(s->digests, _tor_free); + strmap_free(s->digests, tor_free_); } tor_free(s); diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 6211218641..04cf2f9710 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -9,8 +9,8 @@ * \brief Header file for dirvote.c. **/ -#ifndef _TOR_DIRVOTE_H -#define _TOR_DIRVOTE_H +#ifndef TOR_DIRVOTE_H +#define TOR_DIRVOTE_H /** Lowest allowable value for VoteSeconds. */ #define MIN_VOTE_SECONDS 20 diff --git a/src/or/dns.c b/src/or/dns.c index 5f8591383c..5e1d0b48db 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -171,8 +171,8 @@ static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, or_circuit_t *oncirc, char **resolved_to_hostname, int *made_connection_pending_out); #ifdef DEBUG_DNS_CACHE -static void _assert_cache_ok(void); -#define assert_cache_ok() _assert_cache_ok() +static void assert_cache_ok_(void); +#define assert_cache_ok() assert_cache_ok_() #else #define assert_cache_ok() STMT_NIL #endif @@ -254,7 +254,7 @@ evdns_log_cb(int warn, const char *msg) /** Helper: passed to eventdns.c as a callback so it can generate random * numbers for transaction IDs and 0x20-hack coding. */ static void -_dns_randfn(char *b, size_t n) +dns_randfn_(char *b, size_t n) { crypto_rand(b,n); } @@ -264,7 +264,7 @@ int dns_init(void) { init_cache_map(); - evdns_set_random_bytes_fn(_dns_randfn); + evdns_set_random_bytes_fn(dns_randfn_); if (server_mode(get_options())) { int r = configure_nameservers(1); return r; @@ -336,7 +336,7 @@ dns_get_expiry_ttl(uint32_t ttl) /** Helper: free storage held by an entry in the DNS cache. */ static void -_free_cached_resolve(cached_resolve_t *r) +free_cached_resolve_(cached_resolve_t *r) { if (!r) return; @@ -355,7 +355,7 @@ _free_cached_resolve(cached_resolve_t *r) * less-than-zero, zero, or greater-than-zero as appropriate. Used for * the priority queue implementation. */ static int -_compare_cached_resolves_by_expiry(const void *_a, const void *_b) +compare_cached_resolves_by_expiry_(const void *_a, const void *_b) { const cached_resolve_t *a = _a, *b = _b; if (a->expire < b->expire) @@ -380,7 +380,7 @@ set_expiry(cached_resolve_t *resolve, time_t expires) cached_resolve_pqueue = smartlist_new(); resolve->expire = expires; smartlist_pqueue_add(cached_resolve_pqueue, - _compare_cached_resolves_by_expiry, + compare_cached_resolves_by_expiry_, STRUCT_OFFSET(cached_resolve_t, minheap_idx), resolve); } @@ -395,13 +395,13 @@ dns_free_all(void) SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, { if (res->state == CACHE_STATE_DONE) - _free_cached_resolve(res); + free_cached_resolve_(res); }); } for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) { item = *ptr; next = HT_NEXT_RMV(cache_map, &cache_root, ptr); - _free_cached_resolve(item); + free_cached_resolve_(item); } HT_CLEAR(cache_map, &cache_root); smartlist_free(cached_resolve_pqueue); @@ -427,7 +427,7 @@ purge_expired_resolves(time_t now) if (resolve->expire > now) break; smartlist_pqueue_pop(cached_resolve_pqueue, - _compare_cached_resolves_by_expiry, + compare_cached_resolves_by_expiry_, STRUCT_OFFSET(cached_resolve_t, minheap_idx)); if (resolve->state == CACHE_STATE_PENDING) { @@ -454,9 +454,9 @@ purge_expired_resolves(time_t now) pend = resolve->pending_connections; resolve->pending_connections = pend->next; /* Connections should only be pending if they have no socket. */ - tor_assert(!SOCKET_OK(pend->conn->_base.s)); + tor_assert(!SOCKET_OK(pend->conn->base_.s)); pendconn = pend->conn; - if (!pendconn->_base.marked_for_close) { + if (!pendconn->base_.marked_for_close) { connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT); circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); connection_free(TO_CONN(pendconn)); @@ -512,7 +512,7 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type) { case RESOLVED_TYPE_IPV4: buf[1] = 4; - set_uint32(buf+2, tor_addr_to_ipv4n(&conn->_base.addr)); + set_uint32(buf+2, tor_addr_to_ipv4n(&conn->base_.addr)); set_uint32(buf+6, htonl(ttl)); buflen = 10; break; @@ -600,7 +600,7 @@ dns_resolve(edge_connection_t *exitconn) int is_resolve, r; int made_connection_pending = 0; char *hostname = NULL; - is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE; + is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname, &made_connection_pending); @@ -626,7 +626,7 @@ dns_resolve(edge_connection_t *exitconn) case 0: /* The request is pending: add the connection into the linked list of * resolving_streams on this circuit. */ - exitconn->_base.state = EXIT_CONN_STATE_RESOLVING; + exitconn->base_.state = EXIT_CONN_STATE_RESOLVING; exitconn->next_stream = oncirc->resolving_streams; oncirc->resolving_streams = exitconn; break; @@ -641,9 +641,9 @@ dns_resolve(edge_connection_t *exitconn) exitconn->on_circuit = NULL; - dns_cancel_pending_resolve(exitconn->_base.address); + dns_cancel_pending_resolve(exitconn->base_.address); - if (!made_connection_pending && !exitconn->_base.marked_for_close) { + if (!made_connection_pending && !exitconn->base_.marked_for_close) { /* If we made the connection pending, then we freed it already in * dns_cancel_pending_resolve(). If we marked it for close, it'll * get freed from the main loop. Otherwise, can free it now. */ @@ -685,16 +685,16 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, uint8_t is_reverse = 0; int r; assert_connection_ok(TO_CONN(exitconn), 0); - tor_assert(!SOCKET_OK(exitconn->_base.s)); + tor_assert(!SOCKET_OK(exitconn->base_.s)); assert_cache_ok(); tor_assert(oncirc); *made_connection_pending_out = 0; - /* first check if exitconn->_base.address is an IP. If so, we already + /* first check if exitconn->base_.address is an IP. If so, we already * know the answer. */ - if (tor_addr_parse(&addr, exitconn->_base.address) >= 0) { + if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) { if (tor_addr_family(&addr) == AF_INET) { - tor_addr_copy(&exitconn->_base.addr, &addr); + tor_addr_copy(&exitconn->base_.addr, &addr); exitconn->address_ttl = DEFAULT_DNS_TTL; return 1; } else { @@ -708,10 +708,10 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, policy_is_reject_star(me->exit_policy)) { return -1; } - if (address_is_invalid_destination(exitconn->_base.address, 0)) { + if (address_is_invalid_destination(exitconn->base_.address, 0)) { log(LOG_PROTOCOL_WARN, LD_EXIT, "Rejecting invalid destination address %s", - escaped_safe_str(exitconn->_base.address)); + escaped_safe_str(exitconn->base_.address)); return -1; } @@ -719,14 +719,14 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, * resolves in the hash table. */ purge_expired_resolves(now); - /* lower-case exitconn->_base.address, so it's in canonical form */ - tor_strlower(exitconn->_base.address); + /* lower-case exitconn->base_.address, so it's in canonical form */ + tor_strlower(exitconn->base_.address); /* Check whether this is a reverse lookup. If it's malformed, or it's a * .in-addr.arpa address but this isn't a resolve request, kill the * connection. */ - if ((r = tor_addr_parse_PTR_name(&addr, exitconn->_base.address, + if ((r = tor_addr_parse_PTR_name(&addr, exitconn->base_.address, AF_UNSPEC, 0)) != 0) { if (r == 1) { is_reverse = 1; @@ -737,21 +737,21 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, if (!is_reverse || !is_resolve) { if (!is_reverse) log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.", - escaped_safe_str(exitconn->_base.address)); + escaped_safe_str(exitconn->base_.address)); else if (!is_resolve) log_info(LD_EXIT, "Attempt to connect to a .in-addr.arpa address \"%s\"; " "sending error.", - escaped_safe_str(exitconn->_base.address)); + escaped_safe_str(exitconn->base_.address)); return -1; } //log_notice(LD_EXIT, "Looks like an address %s", - //exitconn->_base.address); + //exitconn->base_.address); } /* now check the hash table to see if 'address' is already there. */ - strlcpy(search.address, exitconn->_base.address, sizeof(search.address)); + strlcpy(search.address, exitconn->base_.address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (resolve && resolve->expire > now) { /* already there */ switch (resolve->state) { @@ -764,25 +764,25 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, resolve->pending_connections = pending_connection; *made_connection_pending_out = 1; log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS " - "resolve of %s", exitconn->_base.s, - escaped_safe_str(exitconn->_base.address)); + "resolve of %s", exitconn->base_.s, + escaped_safe_str(exitconn->base_.address)); return 0; case CACHE_STATE_CACHED_VALID: log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s", - exitconn->_base.s, + exitconn->base_.s, escaped_safe_str(resolve->address)); exitconn->address_ttl = resolve->ttl; if (resolve->is_reverse) { tor_assert(is_resolve); *hostname_out = tor_strdup(resolve->result.hostname); } else { - tor_addr_from_ipv4h(&exitconn->_base.addr, resolve->result.a.addr); + tor_addr_from_ipv4h(&exitconn->base_.addr, resolve->result.a.addr); } return 1; case CACHE_STATE_CACHED_FAILED: log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s", - exitconn->_base.s, - escaped_safe_str(exitconn->_base.address)); + exitconn->base_.s, + escaped_safe_str(exitconn->base_.address)); return -1; case CACHE_STATE_DONE: log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache."); @@ -797,7 +797,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, resolve->state = CACHE_STATE_PENDING; resolve->minheap_idx = -1; resolve->is_reverse = is_reverse; - strlcpy(resolve->address, exitconn->_base.address, sizeof(resolve->address)); + strlcpy(resolve->address, exitconn->base_.address, sizeof(resolve->address)); /* add this connection to the pending list */ pending_connection = tor_malloc_zero(sizeof(pending_connection_t)); @@ -810,7 +810,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT); log_debug(LD_EXIT,"Launching %s.", - escaped_safe_str(exitconn->_base.address)); + escaped_safe_str(exitconn->base_.address)); assert_cache_ok(); return launch_resolve(exitconn); @@ -826,7 +826,7 @@ assert_connection_edge_not_dns_pending(edge_connection_t *conn) #if 1 cached_resolve_t *resolve; - strlcpy(search.address, conn->_base.address, sizeof(search.address)); + strlcpy(search.address, conn->base_.address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) return; @@ -856,7 +856,7 @@ assert_all_pending_dns_resolves_ok(void) pend; pend = pend->next) { assert_connection_ok(TO_CONN(pend->conn), 0); - tor_assert(!SOCKET_OK(pend->conn->_base.s)); + tor_assert(!SOCKET_OK(pend->conn->base_.s)); tor_assert(!connection_in_array(TO_CONN(pend->conn))); } } @@ -871,15 +871,15 @@ connection_dns_remove(edge_connection_t *conn) cached_resolve_t search; cached_resolve_t *resolve; - tor_assert(conn->_base.type == CONN_TYPE_EXIT); - tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING); + tor_assert(conn->base_.type == CONN_TYPE_EXIT); + tor_assert(conn->base_.state == EXIT_CONN_STATE_RESOLVING); - strlcpy(search.address, conn->_base.address, sizeof(search.address)); + strlcpy(search.address, conn->base_.address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) { log_notice(LD_BUG, "Address %s is not pending. Dropping.", - escaped_safe_str(conn->_base.address)); + escaped_safe_str(conn->base_.address)); return; } @@ -893,8 +893,8 @@ connection_dns_remove(edge_connection_t *conn) tor_free(pend); log_debug(LD_EXIT, "First connection (fd %d) no longer waiting " "for resolve of %s", - conn->_base.s, - escaped_safe_str(conn->_base.address)); + conn->base_.s, + escaped_safe_str(conn->base_.address)); return; } else { for ( ; pend->next; pend = pend->next) { @@ -904,7 +904,7 @@ connection_dns_remove(edge_connection_t *conn) tor_free(victim); log_debug(LD_EXIT, "Connection (fd %d) no longer waiting for resolve of %s", - conn->_base.s, escaped_safe_str(conn->_base.address)); + conn->base_.s, escaped_safe_str(conn->base_.address)); return; /* more are pending */ } } @@ -959,17 +959,17 @@ dns_cancel_pending_resolve(const char *address) escaped_safe_str(address)); while (resolve->pending_connections) { pend = resolve->pending_connections; - pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; + pend->conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; pendconn = pend->conn; assert_connection_ok(TO_CONN(pendconn), 0); - tor_assert(!SOCKET_OK(pendconn->_base.s)); - if (!pendconn->_base.marked_for_close) { + tor_assert(!SOCKET_OK(pendconn->base_.s)); + if (!pendconn->base_.marked_for_close) { connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); } circ = circuit_get_by_edge_conn(pendconn); if (circ) circuit_detach_stream(circ, pendconn); - if (!pendconn->_base.marked_for_close) + if (!pendconn->base_.marked_for_close) connection_free(TO_CONN(pendconn)); resolve->pending_connections = pend->next; tor_free(pend); @@ -1092,20 +1092,20 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr, pendconn = pend->conn; /* don't pass complex things to the connection_mark_for_close macro */ assert_connection_ok(TO_CONN(pendconn),time(NULL)); - if (pendconn->_base.marked_for_close) { + if (pendconn->base_.marked_for_close) { /* prevent double-remove. */ - pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; + pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; resolve->pending_connections = pend->next; tor_free(pend); continue; } - tor_addr_from_ipv4h(&pendconn->_base.addr, addr); + tor_addr_from_ipv4h(&pendconn->base_.addr, addr); pendconn->address_ttl = ttl; if (outcome != DNS_RESOLVE_SUCCEEDED) { /* prevent double-remove. */ - pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; - if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) { + pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); /* This detach must happen after we send the end cell. */ circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); @@ -1117,10 +1117,10 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr, } connection_free(TO_CONN(pendconn)); } else { - if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) { + if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { tor_assert(!is_reverse); /* prevent double-remove. */ - pend->conn->_base.state = EXIT_CONN_STATE_CONNECTING; + pend->conn->base_.state = EXIT_CONN_STATE_CONNECTING; circ = circuit_get_by_edge_conn(pend->conn); tor_assert(circ); @@ -1136,7 +1136,7 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr, } else { /* prevent double-remove. This isn't really an accurate state, * but it does the right thing. */ - pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; + pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; if (is_reverse) send_resolved_hostname_cell(pendconn, hostname); else @@ -1210,10 +1210,10 @@ configure_nameservers(int force) } #ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS - if (! tor_addr_is_null(&options->_OutboundBindAddressIPv4)) { + if (! tor_addr_is_null(&options->OutboundBindAddressIPv4_)) { int socklen; struct sockaddr_storage ss; - socklen = tor_addr_to_sockaddr(&options->_OutboundBindAddressIPv4, 0, + socklen = tor_addr_to_sockaddr(&options->OutboundBindAddressIPv4_, 0, (struct sockaddr *)&ss, sizeof(ss)); if (socklen <= 0) { log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr." @@ -1416,21 +1416,21 @@ launch_resolve(edge_connection_t *exitconn) } } - addr = tor_strdup(exitconn->_base.address); + addr = tor_strdup(exitconn->base_.address); r = tor_addr_parse_PTR_name( - &a, exitconn->_base.address, AF_UNSPEC, 0); + &a, exitconn->base_.address, AF_UNSPEC, 0); tor_assert(the_evdns_base); if (r == 0) { log_info(LD_EXIT, "Launching eventdns request for %s", - escaped_safe_str(exitconn->_base.address)); + escaped_safe_str(exitconn->base_.address)); req = evdns_base_resolve_ipv4(the_evdns_base, - exitconn->_base.address, options, + exitconn->base_.address, options, evdns_callback, addr); } else if (r == 1) { log_info(LD_EXIT, "Launching eventdns reverse request for %s", - escaped_safe_str(exitconn->_base.address)); + escaped_safe_str(exitconn->base_.address)); if (tor_addr_family(&a) == AF_INET) req = evdns_base_resolve_reverse(the_evdns_base, tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH, @@ -1707,7 +1707,7 @@ dns_seems_to_be_broken(void) void dns_reset_correctness_checks(void) { - strmap_free(dns_wildcard_response_count, _tor_free); + strmap_free(dns_wildcard_response_count, tor_free_); dns_wildcard_response_count = NULL; n_wildcard_requests = 0; @@ -1781,7 +1781,7 @@ dump_dns_mem_usage(int severity) #ifdef DEBUG_DNS_CACHE /** Exit with an assertion if the DNS cache is corrupt. */ static void -_assert_cache_ok(void) +assert_cache_ok_(void) { cached_resolve_t **resolve; int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root); @@ -1798,7 +1798,7 @@ _assert_cache_ok(void) return; smartlist_pqueue_assert_ok(cached_resolve_pqueue, - _compare_cached_resolves_by_expiry, + compare_cached_resolves_by_expiry_, STRUCT_OFFSET(cached_resolve_t, minheap_idx)); SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, diff --git a/src/or/dns.h b/src/or/dns.h index 8c8b476ac8..441a6c3506 100644 --- a/src/or/dns.h +++ b/src/or/dns.h @@ -9,8 +9,8 @@ * \brief Header file for dns.c. **/ -#ifndef _TOR_DNS_H -#define _TOR_DNS_H +#ifndef TOR_DNS_H +#define TOR_DNS_H int dns_init(void); int has_dns_init_failed(void); diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index 69adcef9ea..5875d96b8b 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -133,7 +133,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) strlcpy(entry_conn->socks_request->address, q->name, sizeof(entry_conn->socks_request->address)); - entry_conn->socks_request->listener_type = listener->_base.type; + entry_conn->socks_request->listener_type = listener->base_.type; entry_conn->dns_server_request = req; entry_conn->isolation_flags = listener->isolation_flags; entry_conn->session_group = listener->session_group; @@ -178,7 +178,7 @@ dnsserv_launch_request(const char *name, int reverse) /* Make a new dummy AP connection, and attach the request to it. */ entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET); conn = ENTRY_TO_EDGE_CONN(entry_conn); - conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT; + conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; if (reverse) entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; diff --git a/src/or/dnsserv.h b/src/or/dnsserv.h index 3aaa038d2b..39bd1d33b2 100644 --- a/src/or/dnsserv.h +++ b/src/or/dnsserv.h @@ -9,8 +9,8 @@ * \brief Header file for dnsserv.c. **/ -#ifndef _TOR_DNSSERV_H -#define _TOR_DNSSERV_H +#ifndef TOR_DNSSERV_H +#define TOR_DNSSERV_H void dnsserv_configure_listener(connection_t *conn); void dnsserv_close_listener(connection_t *conn); diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c new file mode 100644 index 0000000000..edb26dc088 --- /dev/null +++ b/src/or/entrynodes.c @@ -0,0 +1,1948 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2012, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file entrynodes.c + * \brief Code to manage our fixed first nodes for various functions. + * + * Entry nodes can be guards (for general use) or bridges (for censorship + * circumvention). + **/ + +#include "or.h" +#include "circuitbuild.h" +#include "circuitstats.h" +#include "config.h" +#include "confparse.h" +#include "connection.h" +#include "connection_or.h" +#include "control.h" +#include "directory.h" +#include "entrynodes.h" +#include "main.h" +#include "nodelist.h" +#include "policies.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" +#include "routerset.h" +#include "transports.h" +#include "statefile.h" + +/** Information about a configured bridge. Currently this just matches the + * ones in the torrc file, but one day we may be able to learn about new + * bridges on our own, and remember them in the state file. */ +typedef struct { + /** Address of the bridge. */ + tor_addr_t addr; + /** TLS port for the bridge. */ + uint16_t port; + /** Boolean: We are re-parsing our bridge list, and we are going to remove + * this one if we don't find it in the list of configured bridges. */ + unsigned marked_for_removal : 1; + /** Expected identity digest, or all zero bytes if we don't know what the + * digest should be. */ + char identity[DIGEST_LEN]; + + /** Name of pluggable transport protocol taken from its config line. */ + char *transport_name; + + /** When should we next try to fetch a descriptor for this bridge? */ + download_status_t fetch_status; +} bridge_info_t; + +/** A list of our chosen entry guards. */ +static smartlist_t *entry_guards = NULL; +/** A value of 1 means that the entry_guards list has changed + * and those changes need to be flushed to disk. */ +static int entry_guards_dirty = 0; + +static void bridge_free(bridge_info_t *bridge); + +/** Return the list of entry guards, creating it if necessary. */ +const smartlist_t * +get_entry_guards(void) +{ + if (! entry_guards) + entry_guards = smartlist_new(); + return entry_guards; +} + +/** Check whether the entry guard <b>e</b> is usable, given the directory + * authorities' opinion about the router (stored in <b>ri</b>) and the user's + * configuration (in <b>options</b>). Set <b>e</b>->bad_since + * accordingly. Return true iff the entry guard's status changes. + * + * If it's not usable, set *<b>reason</b> to a static string explaining why. + */ +static int +entry_guard_set_status(entry_guard_t *e, const node_t *node, + time_t now, const or_options_t *options, + const char **reason) +{ + char buf[HEX_DIGEST_LEN+1]; + int changed = 0; + + *reason = NULL; + + /* Do we want to mark this guard as bad? */ + if (!node) + *reason = "unlisted"; + else if (!node->is_running) + *reason = "down"; + else if (options->UseBridges && (!node->ri || + node->ri->purpose != ROUTER_PURPOSE_BRIDGE)) + *reason = "not a bridge"; + else if (options->UseBridges && !node_is_a_configured_bridge(node)) + *reason = "not a configured bridge"; + else if (!options->UseBridges && !node->is_possible_guard && + !routerset_contains_node(options->EntryNodes,node)) + *reason = "not recommended as a guard"; + else if (routerset_contains_node(options->ExcludeNodes, node)) + *reason = "excluded"; + else if (e->path_bias_disabled) + *reason = "path-biased"; + + if (*reason && ! e->bad_since) { + /* Router is newly bad. */ + base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN); + log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.", + e->nickname, buf, *reason); + + e->bad_since = now; + control_event_guard(e->nickname, e->identity, "BAD"); + changed = 1; + } else if (!*reason && e->bad_since) { + /* There's nothing wrong with the router any more. */ + base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN); + log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: " + "marking as ok.", e->nickname, buf); + + e->bad_since = 0; + control_event_guard(e->nickname, e->identity, "GOOD"); + changed = 1; + } + return changed; +} + +/** Return true iff enough time has passed since we last tried to connect + * to the unreachable guard <b>e</b> that we're willing to try again. */ +static int +entry_is_time_to_retry(entry_guard_t *e, time_t now) +{ + long diff; + if (e->last_attempted < e->unreachable_since) + return 1; + diff = now - e->unreachable_since; + if (diff < 6*60*60) + return now > (e->last_attempted + 60*60); + else if (diff < 3*24*60*60) + return now > (e->last_attempted + 4*60*60); + else if (diff < 7*24*60*60) + return now > (e->last_attempted + 18*60*60); + else + return now > (e->last_attempted + 36*60*60); +} + +/** Return the node corresponding to <b>e</b>, if <b>e</b> is + * working well enough that we are willing to use it as an entry + * right now. (Else return NULL.) In particular, it must be + * - Listed as either up or never yet contacted; + * - Present in the routerlist; + * - Listed as 'stable' or 'fast' by the current dirserver consensus, + * if demanded by <b>need_uptime</b> or <b>need_capacity</b> + * (unless it's a configured EntryNode); + * - Allowed by our current ReachableORAddresses config option; and + * - Currently thought to be reachable by us (unless <b>assume_reachable</b> + * is true). + * + * If the answer is no, set *<b>msg</b> to an explanation of why. + */ +static INLINE const node_t * +entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, + int assume_reachable, const char **msg) +{ + const node_t *node; + const or_options_t *options = get_options(); + tor_assert(msg); + + if (e->path_bias_disabled) { + *msg = "path-biased"; + return NULL; + } + if (e->bad_since) { + *msg = "bad"; + return NULL; + } + /* no good if it's unreachable, unless assume_unreachable or can_retry. */ + if (!assume_reachable && !e->can_retry && + e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) { + *msg = "unreachable"; + return NULL; + } + node = node_get_by_id(e->identity); + if (!node || !node_has_descriptor(node)) { + *msg = "no descriptor"; + return NULL; + } + if (get_options()->UseBridges) { + if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) { + *msg = "not a bridge"; + return NULL; + } + if (!node_is_a_configured_bridge(node)) { + *msg = "not a configured bridge"; + return NULL; + } + } else { /* !get_options()->UseBridges */ + if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) { + *msg = "not general-purpose"; + return NULL; + } + } + if (routerset_contains_node(options->EntryNodes, node)) { + /* they asked for it, they get it */ + need_uptime = need_capacity = 0; + } + if (node_is_unreliable(node, need_uptime, need_capacity, 0)) { + *msg = "not fast/stable"; + return NULL; + } + if (!fascist_firewall_allows_node(node)) { + *msg = "unreachable by config"; + return NULL; + } + return node; +} + +/** Return the number of entry guards that we think are usable. */ +static int +num_live_entry_guards(void) +{ + int n = 0; + const char *msg; + if (! entry_guards) + return 0; + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + { + if (entry_is_live(entry, 0, 1, 0, &msg)) + ++n; + }); + return n; +} + +/** If <b>digest</b> matches the identity of any node in the + * entry_guards list, return that node. Else return NULL. */ +entry_guard_t * +entry_guard_get_by_id_digest(const char *digest) +{ + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + if (tor_memeq(digest, entry->identity, DIGEST_LEN)) + return entry; + ); + return NULL; +} + +/** Dump a description of our list of entry guards to the log at level + * <b>severity</b>. */ +static void +log_entry_guards(int severity) +{ + smartlist_t *elements = smartlist_new(); + char *s; + + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) + { + const char *msg = NULL; + if (entry_is_live(e, 0, 1, 0, &msg)) + smartlist_add_asprintf(elements, "%s [%s] (up %s)", + e->nickname, + hex_str(e->identity, DIGEST_LEN), + e->made_contact ? "made-contact" : "never-contacted"); + else + smartlist_add_asprintf(elements, "%s [%s] (%s, %s)", + e->nickname, + hex_str(e->identity, DIGEST_LEN), + msg, + e->made_contact ? "made-contact" : "never-contacted"); + } + SMARTLIST_FOREACH_END(e); + + s = smartlist_join_strings(elements, ",", 0, NULL); + SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); + smartlist_free(elements); + log_fn(severity,LD_CIRC,"%s",s); + tor_free(s); +} + +/** Called when one or more guards that we would previously have used for some + * purpose are no longer in use because a higher-priority guard has become + * usable again. */ +static void +control_event_guard_deferred(void) +{ + /* XXXX We don't actually have a good way to figure out _how many_ entries + * are live for some purpose. We need an entry_is_even_slightly_live() + * function for this to work right. NumEntryGuards isn't reliable: if we + * need guards with weird properties, we can have more than that number + * live. + **/ +#if 0 + int n = 0; + const char *msg; + const or_options_t *options = get_options(); + if (!entry_guards) + return; + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + { + if (entry_is_live(entry, 0, 1, 0, &msg)) { + if (n++ == options->NumEntryGuards) { + control_event_guard(entry->nickname, entry->identity, "DEFERRED"); + return; + } + } + }); +#endif +} + +/** Add a new (preferably stable and fast) router to our + * entry_guards list. Return a pointer to the router if we succeed, + * or NULL if we can't find any more suitable entries. + * + * If <b>chosen</b> is defined, use that one, and if it's not + * already in our entry_guards list, put it at the *beginning*. + * Else, put the one we pick at the end of the list. */ +static const node_t * +add_an_entry_guard(const node_t *chosen, int reset_status, int prepend) +{ + const node_t *node; + entry_guard_t *entry; + + if (chosen) { + node = chosen; + entry = entry_guard_get_by_id_digest(node->identity); + if (entry) { + if (reset_status) { + entry->bad_since = 0; + entry->can_retry = 1; + } + return NULL; + } + } else { + node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL); + if (!node) + return NULL; + } + entry = tor_malloc_zero(sizeof(entry_guard_t)); + log_info(LD_CIRC, "Chose %s as new entry guard.", + node_describe(node)); + strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname)); + memcpy(entry->identity, node->identity, DIGEST_LEN); + /* Choose expiry time smudged over the past month. The goal here + * is to a) spread out when Tor clients rotate their guards, so they + * don't all select them on the same day, and b) avoid leaving a + * precise timestamp in the state file about when we first picked + * this guard. For details, see the Jan 2010 or-dev thread. */ + entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); + entry->chosen_by_version = tor_strdup(VERSION); + if (prepend) + smartlist_insert(entry_guards, 0, entry); + else + smartlist_add(entry_guards, entry); + control_event_guard(entry->nickname, entry->identity, "NEW"); + control_event_guard_deferred(); + log_entry_guards(LOG_INFO); + return node; +} + +/** If the use of entry guards is configured, choose more entry guards + * until we have enough in the list. */ +static void +pick_entry_guards(const or_options_t *options) +{ + int changed = 0; + + tor_assert(entry_guards); + + while (num_live_entry_guards() < options->NumEntryGuards) { + if (!add_an_entry_guard(NULL, 0, 0)) + break; + changed = 1; + } + if (changed) + entry_guards_changed(); +} + +/** How long (in seconds) do we allow an entry guard to be nonfunctional, + * unlisted, excluded, or otherwise nonusable before we give up on it? */ +#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60) + +/** Release all storage held by <b>e</b>. */ +static void +entry_guard_free(entry_guard_t *e) +{ + if (!e) + return; + tor_free(e->chosen_by_version); + tor_free(e); +} + +/** Remove any entry guard which was selected by an unknown version of Tor, + * or which was selected by a version of Tor that's known to select + * entry guards badly, or which was selected more 2 months ago. */ +/* XXXX The "obsolete guards" and "chosen long ago guards" things should + * probably be different functions. */ +static int +remove_obsolete_entry_guards(time_t now) +{ + int changed = 0, i; + + for (i = 0; i < smartlist_len(entry_guards); ++i) { + entry_guard_t *entry = smartlist_get(entry_guards, i); + const char *ver = entry->chosen_by_version; + const char *msg = NULL; + tor_version_t v; + int version_is_bad = 0, date_is_bad = 0; + if (!ver) { + msg = "does not say what version of Tor it was selected by"; + version_is_bad = 1; + } else if (tor_version_parse(ver, &v)) { + msg = "does not seem to be from any recognized version of Tor"; + version_is_bad = 1; + } else { + char *tor_ver = NULL; + tor_asprintf(&tor_ver, "Tor %s", ver); + if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") && + !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) || + (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") && + !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) || + /* above are bug 440; below are bug 1217 */ + (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") && + !tor_version_as_new_as(tor_ver, "0.2.1.23")) || + (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") && + !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) { + msg = "was selected without regard for guard bandwidth"; + version_is_bad = 1; + } + tor_free(tor_ver); + } + if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) { + /* It's been 2 months since the date listed in our state file. */ + msg = "was selected several months ago"; + date_is_bad = 1; + } + + if (version_is_bad || date_is_bad) { /* we need to drop it */ + char dbuf[HEX_DIGEST_LEN+1]; + tor_assert(msg); + base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); + log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC, + "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.", + entry->nickname, dbuf, msg, ver?escaped(ver):"none"); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del_keeporder(entry_guards, i--); + log_entry_guards(LOG_INFO); + changed = 1; + } + } + + return changed ? 1 : 0; +} + +/** Remove all entry guards that have been down or unlisted for so + * long that we don't think they'll come up again. Return 1 if we + * removed any, or 0 if we did nothing. */ +static int +remove_dead_entry_guards(time_t now) +{ + char dbuf[HEX_DIGEST_LEN+1]; + char tbuf[ISO_TIME_LEN+1]; + int i; + int changed = 0; + + for (i = 0; i < smartlist_len(entry_guards); ) { + entry_guard_t *entry = smartlist_get(entry_guards, i); + if (entry->bad_since && + ! entry->path_bias_disabled && + entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) { + + base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); + format_local_iso_time(tbuf, entry->bad_since); + log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted " + "since %s local time; removing.", + entry->nickname, dbuf, tbuf); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del_keeporder(entry_guards, i); + log_entry_guards(LOG_INFO); + changed = 1; + } else + ++i; + } + return changed ? 1 : 0; +} + +/** A new directory or router-status has arrived; update the down/listed + * status of the entry guards. + * + * An entry is 'down' if the directory lists it as nonrunning. + * An entry is 'unlisted' if the directory doesn't include it. + * + * Don't call this on startup; only on a fresh download. Otherwise we'll + * think that things are unlisted. + */ +void +entry_guards_compute_status(const or_options_t *options, time_t now) +{ + int changed = 0; + digestmap_t *reasons; + + if (! entry_guards) + return; + + if (options->EntryNodes) /* reshuffle the entry guard list if needed */ + entry_nodes_should_be_added(); + + reasons = digestmap_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) + { + const node_t *r = node_get_by_id(entry->identity); + const char *reason = NULL; + if (entry_guard_set_status(entry, r, now, options, &reason)) + changed = 1; + + if (entry->bad_since) + tor_assert(reason); + if (reason) + digestmap_set(reasons, entry->identity, (char*)reason); + } + SMARTLIST_FOREACH_END(entry); + + if (remove_dead_entry_guards(now)) + changed = 1; + if (remove_obsolete_entry_guards(now)) + changed = 1; + + if (changed) { + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + const char *reason = digestmap_get(reasons, entry->identity); + const char *live_msg = ""; + const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg); + log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.", + entry->nickname, + hex_str(entry->identity, DIGEST_LEN), + entry->unreachable_since ? "unreachable" : "reachable", + entry->bad_since ? "unusable" : "usable", + reason ? ", ": "", + reason ? reason : "", + r ? "live" : "not live / ", + r ? "" : live_msg); + } SMARTLIST_FOREACH_END(entry); + log_info(LD_CIRC, " (%d/%d entry guards are usable/new)", + num_live_entry_guards(), smartlist_len(entry_guards)); + log_entry_guards(LOG_INFO); + entry_guards_changed(); + } + + digestmap_free(reasons, NULL); +} + +/** Called when a connection to an OR with the identity digest <b>digest</b> + * is established (<b>succeeded</b>==1) or has failed (<b>succeeded</b>==0). + * If the OR is an entry, change that entry's up/down status. + * Return 0 normally, or -1 if we want to tear down the new connection. + * + * If <b>mark_relay_status</b>, also call router_set_status() on this + * relay. + * + * XXX024 change succeeded and mark_relay_status into 'int flags'. + */ +int +entry_guard_register_connect_status(const char *digest, int succeeded, + int mark_relay_status, time_t now) +{ + int changed = 0; + int refuse_conn = 0; + int first_contact = 0; + entry_guard_t *entry = NULL; + int idx = -1; + char buf[HEX_DIGEST_LEN+1]; + + if (! entry_guards) + return 0; + + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + tor_assert(e); + if (tor_memeq(e->identity, digest, DIGEST_LEN)) { + entry = e; + idx = e_sl_idx; + break; + } + } SMARTLIST_FOREACH_END(e); + + if (!entry) + return 0; + + base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN); + + if (succeeded) { + if (entry->unreachable_since) { + log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.", + entry->nickname, buf); + entry->can_retry = 0; + entry->unreachable_since = 0; + entry->last_attempted = now; + control_event_guard(entry->nickname, entry->identity, "UP"); + changed = 1; + } + if (!entry->made_contact) { + entry->made_contact = 1; + first_contact = changed = 1; + } + } else { /* ! succeeded */ + if (!entry->made_contact) { + /* We've never connected to this one. */ + log_info(LD_CIRC, + "Connection to never-contacted entry guard '%s' (%s) failed. " + "Removing from the list. %d/%d entry guards usable/new.", + entry->nickname, buf, + num_live_entry_guards()-1, smartlist_len(entry_guards)-1); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del_keeporder(entry_guards, idx); + log_entry_guards(LOG_INFO); + changed = 1; + } else if (!entry->unreachable_since) { + log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). " + "Marking as unreachable.", entry->nickname, buf); + entry->unreachable_since = entry->last_attempted = now; + control_event_guard(entry->nickname, entry->identity, "DOWN"); + changed = 1; + entry->can_retry = 0; /* We gave it an early chance; no good. */ + } else { + char tbuf[ISO_TIME_LEN+1]; + format_iso_time(tbuf, entry->unreachable_since); + log_debug(LD_CIRC, "Failed to connect to unreachable entry guard " + "'%s' (%s). It has been unreachable since %s.", + entry->nickname, buf, tbuf); + entry->last_attempted = now; + entry->can_retry = 0; /* We gave it an early chance; no good. */ + } + } + + /* if the caller asked us to, also update the is_running flags for this + * relay */ + if (mark_relay_status) + router_set_status(digest, succeeded); + + if (first_contact) { + /* We've just added a new long-term entry guard. Perhaps the network just + * came back? We should give our earlier entries another try too, + * and close this connection so we don't use it before we've given + * the others a shot. */ + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + if (e == entry) + break; + if (e->made_contact) { + const char *msg; + const node_t *r = entry_is_live(e, 0, 1, 1, &msg); + if (r && e->unreachable_since) { + refuse_conn = 1; + e->can_retry = 1; + } + } + } SMARTLIST_FOREACH_END(e); + if (refuse_conn) { + log_info(LD_CIRC, + "Connected to new entry guard '%s' (%s). Marking earlier " + "entry guards up. %d/%d entry guards usable/new.", + entry->nickname, buf, + num_live_entry_guards(), smartlist_len(entry_guards)); + log_entry_guards(LOG_INFO); + changed = 1; + } + } + + if (changed) + entry_guards_changed(); + return refuse_conn ? -1 : 0; +} + +/** When we try to choose an entry guard, should we parse and add + * config's EntryNodes first? */ +static int should_add_entry_nodes = 0; + +/** Called when the value of EntryNodes changes in our configuration. */ +void +entry_nodes_should_be_added(void) +{ + log_info(LD_CIRC, "EntryNodes config option set. Putting configured " + "relays at the front of the entry guard list."); + should_add_entry_nodes = 1; +} + +/** Adjust the entry guards list so that it only contains entries from + * EntryNodes, adding new entries from EntryNodes to the list as needed. */ +static void +entry_guards_set_from_config(const or_options_t *options) +{ + smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps; + smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list; + tor_assert(entry_guards); + + should_add_entry_nodes = 0; + + if (!options->EntryNodes) { + /* It's possible that a controller set EntryNodes, thus making + * should_add_entry_nodes set, then cleared it again, all before the + * call to choose_random_entry() that triggered us. If so, just return. + */ + return; + } + + { + char *string = routerset_to_string(options->EntryNodes); + log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string); + tor_free(string); + } + + entry_nodes = smartlist_new(); + worse_entry_nodes = smartlist_new(); + entry_fps = smartlist_new(); + old_entry_guards_on_list = smartlist_new(); + old_entry_guards_not_on_list = smartlist_new(); + + /* Split entry guards into those on the list and those not. */ + + routerset_get_all_nodes(entry_nodes, options->EntryNodes, + options->ExcludeNodes, 0); + SMARTLIST_FOREACH(entry_nodes, const node_t *,node, + smartlist_add(entry_fps, (void*)node->identity)); + + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, { + if (smartlist_digest_isin(entry_fps, e->identity)) + smartlist_add(old_entry_guards_on_list, e); + else + smartlist_add(old_entry_guards_not_on_list, e); + }); + + /* Remove all currently configured guard nodes, excluded nodes, unreachable + * nodes, or non-Guard nodes from entry_nodes. */ + SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { + if (entry_guard_get_by_id_digest(node->identity)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); + continue; + } else if (routerset_contains_node(options->ExcludeNodes, node)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); + continue; + } else if (!fascist_firewall_allows_node(node)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); + continue; + } else if (! node->is_possible_guard) { + smartlist_add(worse_entry_nodes, (node_t*)node); + SMARTLIST_DEL_CURRENT(entry_nodes, node); + } + } SMARTLIST_FOREACH_END(node); + + /* Now build the new entry_guards list. */ + smartlist_clear(entry_guards); + /* First, the previously configured guards that are in EntryNodes. */ + smartlist_add_all(entry_guards, old_entry_guards_on_list); + /* Next, scramble the rest of EntryNodes, putting the guards first. */ + smartlist_shuffle(entry_nodes); + smartlist_shuffle(worse_entry_nodes); + smartlist_add_all(entry_nodes, worse_entry_nodes); + + /* Next, the rest of EntryNodes */ + SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { + add_an_entry_guard(node, 0, 0); + if (smartlist_len(entry_guards) > options->NumEntryGuards * 10) + break; + } SMARTLIST_FOREACH_END(node); + log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards)); + /* Finally, free the remaining previously configured guards that are not in + * EntryNodes. */ + SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e, + entry_guard_free(e)); + + smartlist_free(entry_nodes); + smartlist_free(worse_entry_nodes); + smartlist_free(entry_fps); + smartlist_free(old_entry_guards_on_list); + smartlist_free(old_entry_guards_not_on_list); + entry_guards_changed(); +} + +/** Return 0 if we're fine adding arbitrary routers out of the + * directory to our entry guard list, or return 1 if we have a + * list already and we must stick to it. + */ +int +entry_list_is_constrained(const or_options_t *options) +{ + if (options->EntryNodes) + return 1; + if (options->UseBridges) + return 1; + return 0; +} + +/** Pick a live (up and listed) entry guard from entry_guards. If + * <b>state</b> is non-NULL, this is for a specific circuit -- + * make sure not to pick this circuit's exit or any node in the + * exit's family. If <b>state</b> is NULL, we're looking for a random + * guard (likely a bridge). */ +const node_t * +choose_random_entry(cpath_build_state_t *state) +{ + const or_options_t *options = get_options(); + smartlist_t *live_entry_guards = smartlist_new(); + smartlist_t *exit_family = smartlist_new(); + const node_t *chosen_exit = + state?build_state_get_exit_node(state) : NULL; + const node_t *node = NULL; + int need_uptime = state ? state->need_uptime : 0; + int need_capacity = state ? state->need_capacity : 0; + int preferred_min, consider_exit_family = 0; + + if (chosen_exit) { + nodelist_add_node_and_family(exit_family, chosen_exit); + consider_exit_family = 1; + } + + if (!entry_guards) + entry_guards = smartlist_new(); + + if (should_add_entry_nodes) + entry_guards_set_from_config(options); + + if (!entry_list_is_constrained(options) && + smartlist_len(entry_guards) < options->NumEntryGuards) + pick_entry_guards(options); + + retry: + smartlist_clear(live_entry_guards); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + const char *msg; + node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg); + if (!node) + continue; /* down, no point */ + if (node == chosen_exit) + continue; /* don't pick the same node for entry and exit */ + if (consider_exit_family && smartlist_isin(exit_family, node)) + continue; /* avoid relays that are family members of our exit */ +#if 0 /* since EntryNodes is always strict now, this clause is moot */ + if (options->EntryNodes && + !routerset_contains_node(options->EntryNodes, node)) { + /* We've come to the end of our preferred entry nodes. */ + if (smartlist_len(live_entry_guards)) + goto choose_and_finish; /* only choose from the ones we like */ + if (options->StrictNodes) { + /* in theory this case should never happen, since + * entry_guards_set_from_config() drops unwanted relays */ + tor_fragile_assert(); + } else { + log_info(LD_CIRC, + "No relays from EntryNodes available. Using others."); + } + } +#endif + smartlist_add(live_entry_guards, (void*)node); + if (!entry->made_contact) { + /* Always start with the first not-yet-contacted entry + * guard. Otherwise we might add several new ones, pick + * the second new one, and now we've expanded our entry + * guard list without needing to. */ + goto choose_and_finish; + } + if (smartlist_len(live_entry_guards) >= options->NumEntryGuards) + goto choose_and_finish; /* we have enough */ + } SMARTLIST_FOREACH_END(entry); + + if (entry_list_is_constrained(options)) { + /* If we prefer the entry nodes we've got, and we have at least + * one choice, that's great. Use it. */ + preferred_min = 1; + } else { + /* Try to have at least 2 choices available. This way we don't + * get stuck with a single live-but-crummy entry and just keep + * using him. + * (We might get 2 live-but-crummy entry guards, but so be it.) */ + preferred_min = 2; + } + + if (smartlist_len(live_entry_guards) < preferred_min) { + if (!entry_list_is_constrained(options)) { + /* still no? try adding a new entry then */ + /* XXX if guard doesn't imply fast and stable, then we need + * to tell add_an_entry_guard below what we want, or it might + * be a long time til we get it. -RD */ + node = add_an_entry_guard(NULL, 0, 0); + if (node) { + entry_guards_changed(); + /* XXX we start over here in case the new node we added shares + * a family with our exit node. There's a chance that we'll just + * load up on entry guards here, if the network we're using is + * one big family. Perhaps we should teach add_an_entry_guard() + * to understand nodes-to-avoid-if-possible? -RD */ + goto retry; + } + } + if (!node && need_uptime) { + need_uptime = 0; /* try without that requirement */ + goto retry; + } + if (!node && need_capacity) { + /* still no? last attempt, try without requiring capacity */ + need_capacity = 0; + goto retry; + } +#if 0 + /* Removing this retry logic: if we only allow one exit, and it is in the + same family as all our entries, then we are just plain not going to win + here. */ + if (!node && entry_list_is_constrained(options) && consider_exit_family) { + /* still no? if we're using bridges or have strictentrynodes + * set, and our chosen exit is in the same family as all our + * bridges/entry guards, then be flexible about families. */ + consider_exit_family = 0; + goto retry; + } +#endif + /* live_entry_guards may be empty below. Oh well, we tried. */ + } + + choose_and_finish: + if (entry_list_is_constrained(options)) { + /* We need to weight by bandwidth, because our bridges or entryguards + * were not already selected proportional to their bandwidth. */ + node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD); + } else { + /* We choose uniformly at random here, because choose_good_entry_server() + * already weights its choices by bandwidth, so we don't want to + * *double*-weight our guard selection. */ + node = smartlist_choose(live_entry_guards); + } + smartlist_free(live_entry_guards); + smartlist_free(exit_family); + return node; +} + +/** Parse <b>state</b> and learn about the entry guards it describes. + * If <b>set</b> is true, and there are no errors, replace the global + * entry_list with what we find. + * On success, return 0. On failure, alloc into *<b>msg</b> a string + * describing the error, and return -1. + */ +int +entry_guards_parse_state(or_state_t *state, int set, char **msg) +{ + entry_guard_t *node = NULL; + smartlist_t *new_entry_guards = smartlist_new(); + config_line_t *line; + time_t now = time(NULL); + const char *state_version = state->TorVersion; + digestmap_t *added_by = digestmap_new(); + + *msg = NULL; + for (line = state->EntryGuards; line; line = line->next) { + if (!strcasecmp(line->key, "EntryGuard")) { + smartlist_t *args = smartlist_new(); + node = tor_malloc_zero(sizeof(entry_guard_t)); + /* all entry guards on disk have been contacted */ + node->made_contact = 1; + smartlist_add(new_entry_guards, node); + smartlist_split_string(args, line->value, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(args)<2) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Too few arguments to EntryGuard"); + } else if (!is_legal_nickname(smartlist_get(args,0))) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Bad nickname for EntryGuard"); + } else { + strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1); + if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1), + strlen(smartlist_get(args,1)))<0) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Bad hex digest for EntryGuard"); + } + } + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + if (*msg) + break; + } else if (!strcasecmp(line->key, "EntryGuardDownSince") || + !strcasecmp(line->key, "EntryGuardUnlistedSince")) { + time_t when; + time_t last_try = 0; + if (!node) { + *msg = tor_strdup("Unable to parse entry nodes: " + "EntryGuardDownSince/UnlistedSince without EntryGuard"); + break; + } + if (parse_iso_time(line->value, &when)<0) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Bad time in EntryGuardDownSince/UnlistedSince"); + break; + } + if (when > now) { + /* It's a bad idea to believe info in the future: you can wind + * up with timeouts that aren't allowed to happen for years. */ + continue; + } + if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) { + /* ignore failure */ + (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try); + } + if (!strcasecmp(line->key, "EntryGuardDownSince")) { + node->unreachable_since = when; + node->last_attempted = last_try; + } else { + node->bad_since = when; + } + } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) { + char d[DIGEST_LEN]; + /* format is digest version date */ + if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) { + log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough."); + continue; + } + if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 || + line->value[HEX_DIGEST_LEN] != ' ') { + log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with " + "hex digest", escaped(line->value)); + continue; + } + digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1)); + } else if (!strcasecmp(line->key, "EntryGuardPathBias")) { + const or_options_t *options = get_options(); + unsigned hop_cnt, success_cnt; + + if (!node) { + *msg = tor_strdup("Unable to parse entry nodes: " + "EntryGuardPathBias without EntryGuard"); + break; + } + + if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) { + log_warn(LD_GENERAL, "Unable to parse guard path bias info: " + "Misformated EntryGuardPathBias %s", escaped(line->value)); + continue; + } + + node->first_hops = hop_cnt; + node->circuit_successes = success_cnt; + log_info(LD_GENERAL, "Read %u/%u path bias for node %s", + node->circuit_successes, node->first_hops, node->nickname); + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (node->circuit_successes/((double)node->first_hops) + < pathbias_get_disable_rate(options)) { + node->path_bias_disabled = 1; + log_info(LD_GENERAL, + "Path bias is too high (%u/%u); disabling node %s", + node->circuit_successes, node->first_hops, node->nickname); + } + + } else { + log_warn(LD_BUG, "Unexpected key %s", line->key); + } + } + + SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) { + char *sp; + char *val = digestmap_get(added_by, e->identity); + if (val && (sp = strchr(val, ' '))) { + time_t when; + *sp++ = '\0'; + if (parse_iso_time(sp, &when)<0) { + log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp); + } else { + e->chosen_by_version = tor_strdup(val); + e->chosen_on_date = when; + } + } else { + if (state_version) { + e->chosen_by_version = tor_strdup(state_version); + e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); + } + } + if (e->path_bias_disabled && !e->bad_since) + e->bad_since = time(NULL); + } + SMARTLIST_FOREACH_END(e); + + if (*msg || !set) { + SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e, + entry_guard_free(e)); + smartlist_free(new_entry_guards); + } else { /* !err && set */ + if (entry_guards) { + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, + entry_guard_free(e)); + smartlist_free(entry_guards); + } + entry_guards = new_entry_guards; + entry_guards_dirty = 0; + /* XXX024 hand new_entry_guards to this func, and move it up a + * few lines, so we don't have to re-dirty it */ + if (remove_obsolete_entry_guards(now)) + entry_guards_dirty = 1; + } + digestmap_free(added_by, tor_free_); + return *msg ? -1 : 0; +} + +/** Our list of entry guards has changed, or some element of one + * of our entry guards has changed. Write the changes to disk within + * the next few minutes. + */ +void +entry_guards_changed(void) +{ + time_t when; + entry_guards_dirty = 1; + + /* or_state_save() will call entry_guards_update_state(). */ + when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600; + or_state_mark_dirty(get_or_state(), when); +} + +/** If the entry guard info has not changed, do nothing and return. + * Otherwise, free the EntryGuards piece of <b>state</b> and create + * a new one out of the global entry_guards list, and then mark + * <b>state</b> dirty so it will get saved to disk. + */ +void +entry_guards_update_state(or_state_t *state) +{ + config_line_t **next, *line; + if (! entry_guards_dirty) + return; + + config_free_lines(state->EntryGuards); + next = &state->EntryGuards; + *next = NULL; + if (!entry_guards) + entry_guards = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + char dbuf[HEX_DIGEST_LEN+1]; + if (!e->made_contact) + continue; /* don't write this one to disk */ + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuard"); + base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN); + tor_asprintf(&line->value, "%s %s", e->nickname, dbuf); + next = &(line->next); + if (e->unreachable_since) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardDownSince"); + line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1); + format_iso_time(line->value, e->unreachable_since); + if (e->last_attempted) { + line->value[ISO_TIME_LEN] = ' '; + format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted); + } + next = &(line->next); + } + if (e->bad_since) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardUnlistedSince"); + line->value = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(line->value, e->bad_since); + next = &(line->next); + } + if (e->chosen_on_date && e->chosen_by_version && + !strchr(e->chosen_by_version, ' ')) { + char d[HEX_DIGEST_LEN+1]; + char t[ISO_TIME_LEN+1]; + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardAddedBy"); + base16_encode(d, sizeof(d), e->identity, DIGEST_LEN); + format_iso_time(t, e->chosen_on_date); + tor_asprintf(&line->value, "%s %s %s", + d, e->chosen_by_version, t); + next = &(line->next); + } + if (e->first_hops) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardPathBias"); + tor_asprintf(&line->value, "%u %u", + e->circuit_successes, e->first_hops); + next = &(line->next); + } + + } SMARTLIST_FOREACH_END(e); + if (!get_options()->AvoidDiskWrites) + or_state_mark_dirty(get_or_state(), 0); + entry_guards_dirty = 0; +} + +/** If <b>question</b> is the string "entry-guards", then dump + * to *<b>answer</b> a newly allocated string describing all of + * the nodes in the global entry_guards list. See control-spec.txt + * for details. + * For backward compatibility, we also handle the string "helper-nodes". + * */ +int +getinfo_helper_entry_guards(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) conn; + (void) errmsg; + + if (!strcmp(question,"entry-guards") || + !strcmp(question,"helper-nodes")) { + smartlist_t *sl = smartlist_new(); + char tbuf[ISO_TIME_LEN+1]; + char nbuf[MAX_VERBOSE_NICKNAME_LEN+1]; + if (!entry_guards) + entry_guards = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + const char *status = NULL; + time_t when = 0; + const node_t *node; + + if (!e->made_contact) { + status = "never-connected"; + } else if (e->bad_since) { + when = e->bad_since; + status = "unusable"; + } else { + status = "up"; + } + + node = node_get_by_id(e->identity); + if (node) { + node_get_verbose_nickname(node, nbuf); + } else { + nbuf[0] = '$'; + base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN); + /* e->nickname field is not very reliable if we don't know about + * this router any longer; don't include it. */ + } + + if (when) { + format_iso_time(tbuf, when); + smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf); + } else { + smartlist_add_asprintf(sl, "%s %s\n", nbuf, status); + } + } SMARTLIST_FOREACH_END(e); + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } + return 0; +} + +/** A list of configured bridges. Whenever we actually get a descriptor + * for one, we add it as an entry guard. Note that the order of bridges + * in this list does not necessarily correspond to the order of bridges + * in the torrc. */ +static smartlist_t *bridge_list = NULL; + +/** Mark every entry of the bridge list to be removed on our next call to + * sweep_bridge_list unless it has first been un-marked. */ +void +mark_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, + b->marked_for_removal = 1); +} + +/** Remove every entry of the bridge list that was marked with + * mark_bridge_list if it has not subsequently been un-marked. */ +void +sweep_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { + if (b->marked_for_removal) { + SMARTLIST_DEL_CURRENT(bridge_list, b); + bridge_free(b); + } + } SMARTLIST_FOREACH_END(b); +} + +/** Initialize the bridge list to empty, creating it if needed. */ +static void +clear_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b)); + smartlist_clear(bridge_list); +} + +/** Free the bridge <b>bridge</b>. */ +static void +bridge_free(bridge_info_t *bridge) +{ + if (!bridge) + return; + + tor_free(bridge->transport_name); + tor_free(bridge); +} + +/** If we have a bridge configured whose digest matches <b>digest</b>, or a + * bridge with no known digest whose address matches any of the + * tor_addr_port_t's in <b>orports</b>, return that bridge. Else return + * NULL. */ +static bridge_info_t * +get_configured_bridge_by_orports_digest(const char *digest, + const smartlist_t *orports) +{ + if (!bridge_list) + return NULL; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (tor_digest_is_zero(bridge->identity)) { + SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, ap) + { + if (tor_addr_compare(&bridge->addr, &ap->addr, CMP_EXACT) == 0 && + bridge->port == ap->port) + return bridge; + } + SMARTLIST_FOREACH_END(ap); + } + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + } + SMARTLIST_FOREACH_END(bridge); + return NULL; +} + +/** If we have a bridge configured whose digest matches <b>digest</b>, or a + * bridge with no known digest whose address matches <b>addr</b>:<b>/port</b>, + * return that bridge. Else return NULL. */ +static bridge_info_t * +get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr, + uint16_t port, + const char *digest) +{ + if (!bridge_list) + return NULL; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (tor_digest_is_zero(bridge->identity) && + !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) && + bridge->port == port) + return bridge; + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + } + SMARTLIST_FOREACH_END(bridge); + return NULL; +} + +/** Wrapper around get_configured_bridge_by_addr_port_digest() to look + * it up via router descriptor <b>ri</b>. */ +static bridge_info_t * +get_configured_bridge_by_routerinfo(const routerinfo_t *ri) +{ + bridge_info_t *bi = NULL; + smartlist_t *orports = router_get_all_orports(ri); + bi = get_configured_bridge_by_orports_digest(ri->cache_info.identity_digest, + orports); + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + return bi; +} + +/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */ +int +routerinfo_is_a_configured_bridge(const routerinfo_t *ri) +{ + return get_configured_bridge_by_routerinfo(ri) ? 1 : 0; +} + +/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */ +int +node_is_a_configured_bridge(const node_t *node) +{ + int retval = 0; + smartlist_t *orports = node_get_all_orports(node); + retval = get_configured_bridge_by_orports_digest(node->identity, + orports) != NULL; + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + return retval; +} + +/** We made a connection to a router at <b>addr</b>:<b>port</b> + * without knowing its digest. Its digest turned out to be <b>digest</b>. + * If it was a bridge, and we still don't know its digest, record it. + */ +void +learned_router_identity(const tor_addr_t *addr, uint16_t port, + const char *digest) +{ + bridge_info_t *bridge = + get_configured_bridge_by_addr_port_digest(addr, port, digest); + if (bridge && tor_digest_is_zero(bridge->identity)) { + memcpy(bridge->identity, digest, DIGEST_LEN); + log_notice(LD_DIR, "Learned fingerprint %s for bridge %s", + hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port)); + } +} + +/** Return true if <b>bridge</b> has the same identity digest as + * <b>digest</b>. If <b>digest</b> is NULL, it matches + * bridges with unspecified identity digests. */ +static int +bridge_has_digest(const bridge_info_t *bridge, const char *digest) +{ + if (digest) + return tor_memeq(digest, bridge->identity, DIGEST_LEN); + else + return tor_digest_is_zero(bridge->identity); +} + +/** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional + * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously + * existing bridge with the same address and port, and warn the user as + * appropriate. + */ +static void +bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port, + const char *digest, const char *transport_name) +{ + /* Iterate the already-registered bridge list: + + If you find a bridge with the same adress and port, mark it for + removal. It doesn't make sense to have two active bridges with + the same IP:PORT. If the bridge in question has a different + digest or transport than <b>digest</b>/<b>transport_name</b>, + it's probably a misconfiguration and we should warn the user. + */ + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) { + if (bridge->marked_for_removal) + continue; + + if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) { + + bridge->marked_for_removal = 1; + + if (!bridge_has_digest(bridge, digest) || + strcmp_opt(bridge->transport_name, transport_name)) { + /* warn the user */ + char *bridge_description_new, *bridge_description_old; + tor_asprintf(&bridge_description_new, "%s:%s:%s", + fmt_addrport(addr, port), + digest ? hex_str(digest, DIGEST_LEN) : "", + transport_name ? transport_name : ""); + tor_asprintf(&bridge_description_old, "%s:%s:%s", + fmt_addrport(&bridge->addr, bridge->port), + tor_digest_is_zero(bridge->identity) ? + "" : hex_str(bridge->identity,DIGEST_LEN), + bridge->transport_name ? bridge->transport_name : ""); + + log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict" + " with the already registered bridge '%s'. We will discard" + " the old bridge and keep '%s'. If this is not what you" + " wanted, please change your configuration file accordingly.", + bridge_description_new, bridge_description_old, + bridge_description_new); + + tor_free(bridge_description_new); + tor_free(bridge_description_old); + } + } + } SMARTLIST_FOREACH_END(bridge); +} + +/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b> + * is set, it tells us the identity key too. If we already had the + * bridge in our list, unmark it, and don't actually add anything new. + * If <b>transport_name</b> is non-NULL - the bridge is associated with a + * pluggable transport - we assign the transport to the bridge. */ +void +bridge_add_from_config(const tor_addr_t *addr, uint16_t port, + const char *digest, const char *transport_name) +{ + bridge_info_t *b; + + bridge_resolve_conflicts(addr, port, digest, transport_name); + + b = tor_malloc_zero(sizeof(bridge_info_t)); + tor_addr_copy(&b->addr, addr); + b->port = port; + if (digest) + memcpy(b->identity, digest, DIGEST_LEN); + if (transport_name) + b->transport_name = tor_strdup(transport_name); + b->fetch_status.schedule = DL_SCHED_BRIDGE; + if (!bridge_list) + bridge_list = smartlist_new(); + + smartlist_add(bridge_list, b); +} + +/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */ +static int +routerset_contains_bridge(const routerset_t *routerset, + const bridge_info_t *bridge) +{ + int result; + extend_info_t *extinfo; + tor_assert(bridge); + if (!routerset) + return 0; + + extinfo = extend_info_new( + NULL, bridge->identity, NULL, &bridge->addr, bridge->port); + result = routerset_contains_extendinfo(routerset, extinfo); + extend_info_free(extinfo); + return result; +} + +/** If <b>digest</b> is one of our known bridges, return it. */ +static bridge_info_t * +find_bridge_by_digest(const char *digest) +{ + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge, + { + if (tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + }); + return NULL; +} + +/* DOCDOC find_transport_name_by_bridge_addrport */ +const char * +find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) +{ + if (!bridge_list) + return NULL; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (tor_addr_eq(&bridge->addr, addr) && + (bridge->port == port)) + return bridge->transport_name; + } SMARTLIST_FOREACH_END(bridge); + + return NULL; +} + +/** If <b>addr</b> and <b>port</b> match the address and port of a + * bridge of ours that uses pluggable transports, place its transport + * in <b>transport</b>. + * + * Return 0 on success (found a transport, or found a bridge with no + * transport, or found no bridge); return -1 if we should be using a + * transport, but the transport could not be found. + */ +int +find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, + const transport_t **transport) +{ + *transport = NULL; + if (!bridge_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (tor_addr_eq(&bridge->addr, addr) && + (bridge->port == port)) { /* bridge matched */ + if (bridge->transport_name) { /* it also uses pluggable transports */ + *transport = transport_get_by_name(bridge->transport_name); + if (*transport == NULL) { /* it uses pluggable transports, but + the transport could not be found! */ + return -1; + } + return 0; + } else { /* bridge matched, but it doesn't use transports. */ + break; + } + } + } SMARTLIST_FOREACH_END(bridge); + + *transport = NULL; + return 0; +} + +/** We need to ask <b>bridge</b> for its server descriptor. */ +static void +launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) +{ + char *address; + const or_options_t *options = get_options(); + + if (connection_get_by_type_addr_port_purpose( + CONN_TYPE_DIR, &bridge->addr, bridge->port, + DIR_PURPOSE_FETCH_SERVERDESC)) + return; /* it's already on the way */ + + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", + safe_str_client(fmt_and_decorate_addr(&bridge->addr))); + return; + } + + address = tor_dup_addr(&bridge->addr); + + directory_initiate_command(address, &bridge->addr, + bridge->port, 0/*no dirport*/, + bridge->identity, + DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, + DIRIND_ONEHOP, "authority.z", NULL, 0, 0); + tor_free(address); +} + +/** Fetching the bridge descriptor from the bridge authority returned a + * "not found". Fall back to trying a direct fetch. */ +void +retry_bridge_descriptor_fetch_directly(const char *digest) +{ + bridge_info_t *bridge = find_bridge_by_digest(digest); + if (!bridge) + return; /* not found? oh well. */ + + launch_direct_bridge_descriptor_fetch(bridge); +} + +/** For each bridge in our list for which we don't currently have a + * descriptor, fetch a new copy of its descriptor -- either directly + * from the bridge or via a bridge authority. */ +void +fetch_bridge_descriptors(const or_options_t *options, time_t now) +{ + int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO); + int ask_bridge_directly; + int can_use_bridge_authority; + + if (!bridge_list) + return; + + /* If we still have unconfigured managed proxies, don't go and + connect to a bridge. */ + if (pt_proxies_configuration_pending()) + return; + + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (!download_status_is_ready(&bridge->fetch_status, now, + IMPOSSIBLE_TO_DOWNLOAD)) + continue; /* don't bother, no need to retry yet */ + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", + safe_str_client(fmt_and_decorate_addr(&bridge->addr))); + continue; + } + + /* schedule another fetch as if this one will fail, in case it does */ + download_status_failed(&bridge->fetch_status, 0); + + can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) && + num_bridge_auths; + ask_bridge_directly = !can_use_bridge_authority || + !options->UpdateBridgesFromAuthority; + log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)", + ask_bridge_directly, tor_digest_is_zero(bridge->identity), + !options->UpdateBridgesFromAuthority, !num_bridge_auths); + + if (ask_bridge_directly && + !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) { + log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our " + "firewall policy. %s.", + fmt_addrport(&bridge->addr, bridge->port), + can_use_bridge_authority ? + "Asking bridge authority instead" : "Skipping"); + if (can_use_bridge_authority) + ask_bridge_directly = 0; + else + continue; + } + + if (ask_bridge_directly) { + /* we need to ask the bridge itself for its descriptor. */ + launch_direct_bridge_descriptor_fetch(bridge); + } else { + /* We have a digest and we want to ask an authority. We could + * combine all the requests into one, but that may give more + * hints to the bridge authority than we want to give. */ + char resource[10 + HEX_DIGEST_LEN]; + memcpy(resource, "fp/", 3); + base16_encode(resource+3, HEX_DIGEST_LEN+1, + bridge->identity, DIGEST_LEN); + memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3); + log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.", + resource); + directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, resource, 0); + } + } + SMARTLIST_FOREACH_END(bridge); +} + +/** If our <b>bridge</b> is configured to be a different address than + * the bridge gives in <b>node</b>, rewrite the routerinfo + * we received to use the address we meant to use. Now we handle + * multihomed bridges better. + */ +static void +rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) +{ + /* XXXX move this function. */ + /* XXXX overridden addresses should really live in the node_t, so that the + * routerinfo_t and the microdesc_t can be immutable. But we can only + * do that safely if we know that no function that connects to an OR + * does so through an address from any source other than node_get_addr(). + */ + tor_addr_t addr; + + if (node->ri) { + routerinfo_t *ri = node->ri; + tor_addr_from_ipv4h(&addr, ri->addr); + + if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == ri->or_port) || + (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) && + bridge->port == ri->ipv6_orport)) { + /* they match, so no need to do anything */ + } else { + if (tor_addr_family(&bridge->addr) == AF_INET) { + ri->addr = tor_addr_to_ipv4h(&bridge->addr); + tor_free(ri->address); + ri->address = tor_dup_ip(ri->addr); + ri->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerinfo for '%s' to match configured " + "address %s:%d.", + ri->nickname, ri->address, ri->or_port); + } else if (tor_addr_family(&bridge->addr) == AF_INET6) { + tor_addr_copy(&ri->ipv6_addr, &bridge->addr); + ri->ipv6_orport = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerinfo for '%s' to match configured " + "address %s.", + ri->nickname, fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); + } else { + log_err(LD_BUG, "Address family not supported: %d.", + tor_addr_family(&bridge->addr)); + return; + } + } + + /* Mark which address to use based on which bridge_t we got. */ + node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && + !tor_addr_is_null(&node->ri->ipv6_addr)); + + /* XXXipv6 we lack support for falling back to another address for + the same relay, warn the user */ + if (!tor_addr_is_null(&ri->ipv6_addr)) { + tor_addr_port_t ap; + node_get_pref_orport(node, &ap); + log_notice(LD_CONFIG, + "Bridge '%s' has both an IPv4 and an IPv6 address. " + "Will prefer using its %s address (%s).", + ri->nickname, + tor_addr_family(&ap.addr) == AF_INET6 ? "IPv6" : "IPv4", + fmt_addrport(&ap.addr, ap.port)); + } + } + if (node->rs) { + routerstatus_t *rs = node->rs; + tor_addr_from_ipv4h(&addr, rs->addr); + + if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == rs->or_port) { + /* they match, so no need to do anything */ + } else { + rs->addr = tor_addr_to_ipv4h(&bridge->addr); + rs->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerstatus for '%s' to match " + "configured address %s.", + rs->nickname, fmt_addrport(&bridge->addr, rs->or_port)); + } + } +} + +/** We just learned a descriptor for a bridge. See if that + * digest is in our entry guard list, and add it if not. */ +void +learned_bridge_descriptor(routerinfo_t *ri, int from_cache) +{ + tor_assert(ri); + tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE); + if (get_options()->UseBridges) { + int first = !any_bridge_descriptors_known(); + bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri); + time_t now = time(NULL); + router_set_status(ri->cache_info.identity_digest, 1); + + if (bridge) { /* if we actually want to use this one */ + node_t *node; + /* it's here; schedule its re-fetch for a long time from now. */ + if (!from_cache) + download_status_reset(&bridge->fetch_status); + + node = node_get_mutable_by_id(ri->cache_info.identity_digest); + tor_assert(node); + rewrite_node_address_for_bridge(bridge, node); + add_an_entry_guard(node, 1, 1); + + log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, + from_cache ? "cached" : "fresh", router_describe(ri)); + /* set entry->made_contact so if it goes down we don't drop it from + * our entry node list */ + entry_guard_register_connect_status(ri->cache_info.identity_digest, + 1, 0, now); + if (first) + routerlist_retry_directory_downloads(now); + } + } +} + +/** Return 1 if any of our entry guards have descriptors that + * are marked with purpose 'bridge' and are running. Else return 0. + * + * We use this function to decide if we're ready to start building + * circuits through our bridges, or if we need to wait until the + * directory "server/authority" requests finish. */ +int +any_bridge_descriptors_known(void) +{ + tor_assert(get_options()->UseBridges); + return choose_random_entry(NULL)!=NULL ? 1 : 0; +} + +/** Return 1 if there are any directory conns fetching bridge descriptors + * that aren't marked for close. We use this to guess if we should tell + * the controller that we have a problem. */ +int +any_pending_bridge_descriptor_fetches(void) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->type == CONN_TYPE_DIR && + conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC && + TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE && + !conn->marked_for_close && + conn->linked && + conn->linked_conn && !conn->linked_conn->marked_for_close) { + log_debug(LD_DIR, "found one: %s", conn->address); + return 1; + } + } SMARTLIST_FOREACH_END(conn); + return 0; +} + +/** Return 1 if we have at least one descriptor for an entry guard + * (bridge or member of EntryNodes) and all descriptors we know are + * down. Else return 0. If <b>act</b> is 1, then mark the down guards + * up; else just observe and report. */ +static int +entries_retry_helper(const or_options_t *options, int act) +{ + const node_t *node; + int any_known = 0; + int any_running = 0; + int need_bridges = options->UseBridges != 0; + if (!entry_guards) + entry_guards = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + node = node_get_by_id(e->identity); + if (node && node_has_descriptor(node) && + node_is_bridge(node) == need_bridges) { + any_known = 1; + if (node->is_running) + any_running = 1; /* some entry is both known and running */ + else if (act) { + /* Mark all current connections to this OR as unhealthy, since + * otherwise there could be one that started 30 seconds + * ago, and in 30 seconds it will time out, causing us to mark + * the node down and undermine the retry attempt. We mark even + * the established conns, since if the network just came back + * we'll want to attach circuits to fresh conns. */ + connection_or_set_bad_connections(node->identity, 1); + + /* mark this entry node for retry */ + router_set_status(node->identity, 1); + e->can_retry = 1; + e->bad_since = 0; + } + } + } SMARTLIST_FOREACH_END(e); + log_debug(LD_DIR, "%d: any_known %d, any_running %d", + act, any_known, any_running); + return any_known && !any_running; +} + +/** Do we know any descriptors for our bridges / entrynodes, and are + * all the ones we have descriptors for down? */ +int +entries_known_but_down(const or_options_t *options) +{ + tor_assert(entry_list_is_constrained(options)); + return entries_retry_helper(options, 0); +} + +/** Mark all down known bridges / entrynodes up. */ +void +entries_retry_all(const or_options_t *options) +{ + tor_assert(entry_list_is_constrained(options)); + entries_retry_helper(options, 1); +} + +/** Return true if we've ever had a bridge running a Tor version that can't + * provide microdescriptors to us. In that case fall back to asking for + * full descriptors. Eventually all bridges will support microdescriptors + * and we can take this check out; see bug 4013. */ +int +any_bridges_dont_support_microdescriptors(void) +{ + const node_t *node; + static int ever_answered_yes = 0; + if (!get_options()->UseBridges || !entry_guards) + return 0; + if (ever_answered_yes) + return 1; /* if we ever answer 'yes', always answer 'yes' */ + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + node = node_get_by_id(e->identity); + if (node && node->ri && + node_is_bridge(node) && node_is_a_configured_bridge(node) && + !tor_version_supports_microdescriptors(node->ri->platform)) { + /* This is one of our current bridges, and we know enough about + * it to know that it won't be able to answer our microdescriptor + * questions. */ + ever_answered_yes = 1; + return 1; + } + } SMARTLIST_FOREACH_END(e); + return 0; +} + +/** Release all storage held by the list of entry guards and related + * memory structs. */ +void +entry_guards_free_all(void) +{ + if (entry_guards) { + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, + entry_guard_free(e)); + smartlist_free(entry_guards); + entry_guards = NULL; + } + clear_bridge_list(); + smartlist_free(bridge_list); + bridge_list = NULL; + circuit_build_times_free_timeouts(&circ_times); +} + diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h new file mode 100644 index 0000000000..1a12cf4bc3 --- /dev/null +++ b/src/or/entrynodes.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2012, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file guardnodes.h + * \brief Header file for circuitbuild.c. + **/ + +#ifndef TOR_ENTRYNODES_H +#define TOR_ENTRYNODES_H + +#if 1 +/* XXXX NM I would prefer that all of this stuff be private to + * entrynodes.c. */ + +/** An entry_guard_t represents our information about a chosen long-term + * first hop, known as a "helper" node in the literature. We can't just + * use a node_t, since we want to remember these even when we + * don't have any directory info. */ +typedef struct entry_guard_t { + char nickname[MAX_NICKNAME_LEN+1]; + char identity[DIGEST_LEN]; + time_t chosen_on_date; /**< Approximately when was this guard added? + * "0" if we don't know. */ + char *chosen_by_version; /**< What tor version added this guard? NULL + * if we don't know. */ + unsigned int made_contact : 1; /**< 0 if we have never connected to this + * router, 1 if we have. */ + unsigned int can_retry : 1; /**< Should we retry connecting to this entry, + * in spite of having it marked as unreachable?*/ + unsigned int path_bias_notice : 1; /**< Did we alert the user about path bias + * for this node already? */ + unsigned int path_bias_disabled : 1; /**< Have we disabled this node because + * of path bias issues? */ + time_t bad_since; /**< 0 if this guard is currently usable, or the time at + * which it was observed to become (according to the + * directory or the user configuration) unusable. */ + time_t unreachable_since; /**< 0 if we can connect to this guard, or the + * time at which we first noticed we couldn't + * connect to it. */ + time_t last_attempted; /**< 0 if we can connect to this guard, or the time + * at which we last failed to connect to it. */ + + unsigned first_hops; /**< Number of first hops this guard has completed */ + unsigned circuit_successes; /**< Number of successfully built circuits using + * this guard as first hop. */ +} entry_guard_t; + +entry_guard_t *entry_guard_get_by_id_digest(const char *digest); +void entry_guards_changed(void); +const smartlist_t *get_entry_guards(void); + +#endif + +void entry_guards_compute_status(const or_options_t *options, time_t now); +int entry_guard_register_connect_status(const char *digest, int succeeded, + int mark_relay_status, time_t now); +void entry_nodes_should_be_added(void); +int entry_list_is_constrained(const or_options_t *options); +const node_t *choose_random_entry(cpath_build_state_t *state); +int entry_guards_parse_state(or_state_t *state, int set, char **msg); +void entry_guards_update_state(or_state_t *state); +int getinfo_helper_entry_guards(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg); + +void mark_bridge_list(void); +void sweep_bridge_list(void); + +int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); +int node_is_a_configured_bridge(const node_t *node); +void learned_router_identity(const tor_addr_t *addr, uint16_t port, + const char *digest); +void bridge_add_from_config(const tor_addr_t *addr, uint16_t port, + const char *digest, + const char *transport_name); +void retry_bridge_descriptor_fetch_directly(const char *digest); +void fetch_bridge_descriptors(const or_options_t *options, time_t now); +void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); +int any_bridge_descriptors_known(void); +int any_pending_bridge_descriptor_fetches(void); +int entries_known_but_down(const or_options_t *options); +void entries_retry_all(const or_options_t *options); + +int any_bridges_dont_support_microdescriptors(void); + +void entry_guards_free_all(void); + +const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, + uint16_t port); +struct transport_t; +int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, + const struct transport_t **transport); + +int validate_pluggable_transports_config(void); + +#endif + diff --git a/src/or/eventdns_tor.h b/src/or/eventdns_tor.h index 4c40b3524b..0775643b5c 100644 --- a/src/or/eventdns_tor.h +++ b/src/or/eventdns_tor.h @@ -1,6 +1,9 @@ /* Copyright (c) 2007-2012, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#ifndef TOR_EVENTDNS_TOR_H +#define TOR_EVENTDNS_TOR_H + #include "orconfig.h" #define DNS_USE_OPENSSL_FOR_ID #ifndef HAVE_UINT @@ -18,3 +21,5 @@ typedef unsigned char u_char; #include "util.h" #include "compat.h" +#endif + diff --git a/src/or/geoip.c b/src/or/geoip.c index 9aba3c98bd..3036ee2b16 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -347,8 +347,8 @@ geoip_load_file(sa_family_t family, const char *filename) * store in node->country. */ refresh_all_country_info(); crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN); - } - else { /* AF_INET6 */ + } else { + /* AF_INET6 */ smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_); crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN); } @@ -631,7 +631,7 @@ geoip_note_client_seen(geoip_client_action_t action, /** HT_FOREACH helper: remove a clientmap_entry_t from the hashtable if it's * older than a certain time. */ static int -_remove_old_client_helper(struct clientmap_entry_t *ent, void *_cutoff) +remove_old_client_helper_(struct clientmap_entry_t *ent, void *_cutoff) { time_t cutoff = *(time_t*)_cutoff / 60; if (ent->last_seen_in_minutes < cutoff) { @@ -647,7 +647,7 @@ void geoip_remove_old_clients(time_t cutoff) { clientmap_HT_FOREACH_FN(&client_history, - _remove_old_client_helper, + remove_old_client_helper_, &cutoff); } @@ -704,7 +704,7 @@ typedef struct c_hist_t { * geoip_ipv4_entry_t. Sort in descending order of total, and then by country * code. */ static int -_c_hist_compare(const void **_a, const void **_b) +c_hist_compare_(const void **_a, const void **_b) { const c_hist_t *a = *_a, *b = *_b; if (a->total > b->total) @@ -773,7 +773,7 @@ HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, * <b>type</b> and <b>dirreq_id</b> as key parts. If there is * already an entry for that key, print out a BUG warning and return. */ static void -_dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type, +dirreq_map_put_(dirreq_map_entry_t *entry, dirreq_type_t type, uint64_t dirreq_id) { dirreq_map_entry_t *old_ent; @@ -795,7 +795,7 @@ _dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type, * using <b>type</b> and <b>dirreq_id</b> as key parts. If there * is no such entry, return NULL. */ static dirreq_map_entry_t * -_dirreq_map_get(dirreq_type_t type, uint64_t dirreq_id) +dirreq_map_get_(dirreq_type_t type, uint64_t dirreq_id) { dirreq_map_entry_t lookup; lookup.type = type; @@ -820,7 +820,7 @@ geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, ent->response_size = response_size; ent->action = action; ent->type = type; - _dirreq_map_put(ent, type, dirreq_id); + dirreq_map_put_(ent, type, dirreq_id); } /** Change the state of the either direct or tunneled (see <b>type</b>) @@ -836,7 +836,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type, dirreq_map_entry_t *ent; if (!get_options()->DirReqStatistics) return; - ent = _dirreq_map_get(type, dirreq_id); + ent = dirreq_map_get_(type, dirreq_id); if (!ent) return; if (new_state == DIRREQ_IS_FOR_NETWORK_STATUS) @@ -1042,7 +1042,7 @@ geoip_get_client_history(geoip_client_action_t action, } /* Sort entries. Note that we must do this _AFTER_ rounding, or else * the sort order could leak info. */ - smartlist_sort(entries, _c_hist_compare); + smartlist_sort(entries, c_hist_compare_); if (country_str) { smartlist_t *chunks = smartlist_new(); @@ -1090,7 +1090,7 @@ geoip_get_request_history(geoip_client_action_t action) ent->total = round_to_next_multiple_of(tot, granularity); smartlist_add(entries, ent); } SMARTLIST_FOREACH_END(c); - smartlist_sort(entries, _c_hist_compare); + smartlist_sort(entries, c_hist_compare_); strings = smartlist_new(); SMARTLIST_FOREACH(entries, c_hist_t *, ent, { diff --git a/src/or/geoip.h b/src/or/geoip.h index 5a17bc2e43..2272486477 100644 --- a/src/or/geoip.h +++ b/src/or/geoip.h @@ -9,8 +9,8 @@ * \brief Header file for geoip.c. **/ -#ifndef _TOR_GEOIP_H -#define _TOR_GEOIP_H +#ifndef TOR_GEOIP_H +#define TOR_GEOIP_H #ifdef GEOIP_PRIVATE int geoip_parse_entry(const char *line, sa_family_t family); diff --git a/src/or/hibernate.h b/src/or/hibernate.h index 9aa026b7b0..5f99cde015 100644 --- a/src/or/hibernate.h +++ b/src/or/hibernate.h @@ -9,8 +9,8 @@ * \brief Header file for hibernate.c. **/ -#ifndef _TOR_HIBERNATE_H -#define _TOR_HIBERNATE_H +#ifndef TOR_HIBERNATE_H +#define TOR_HIBERNATE_H int accounting_parse_options(const or_options_t *options, int validate_only); int accounting_is_enabled(const or_options_t *options); diff --git a/src/or/include.am b/src/or/include.am index 749206151a..01f4784d08 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -23,6 +23,7 @@ src_or_libtor_a_SOURCES = \ src/or/circuitlist.c \ src/or/circuitmux.c \ src/or/circuitmux_ewma.c \ + src/or/circuitstats.c \ src/or/circuituse.c \ src/or/command.c \ src/or/config.c \ @@ -38,6 +39,7 @@ src_or_libtor_a_SOURCES = \ src/or/dns.c \ src/or/dnsserv.c \ src/or/geoip.c \ + src/or/entrynodes.c \ src/or/hibernate.c \ src/or/main.c \ src/or/microdesc.c \ @@ -96,6 +98,7 @@ ORHEADERS = \ src/or/circuitlist.h \ src/or/circuitmux.h \ src/or/circuitmux_ewma.h \ + src/or/circuitstats.h \ src/or/circuituse.h \ src/or/command.h \ src/or/config.h \ @@ -112,6 +115,7 @@ ORHEADERS = \ src/or/dnsserv.h \ src/or/eventdns_tor.h \ src/or/geoip.h \ + src/or/entrynodes.h \ src/or/hibernate.h \ src/or/main.h \ src/or/microdesc.h \ diff --git a/src/or/main.c b/src/or/main.c index 79fe06eea7..0ba28db05e 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -30,6 +30,7 @@ #include "dirvote.h" #include "dns.h" #include "dnsserv.h" +#include "entrynodes.h" #include "geoip.h" #include "hibernate.h" #include "main.h" @@ -2677,7 +2678,7 @@ tor_main(int argc, char *argv[]) { /* Instruct OpenSSL to use our internal wrappers for malloc, realloc and free. */ - int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc, _tor_free); + int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); tor_assert(r); } #endif diff --git a/src/or/main.h b/src/or/main.h index f843b6f9fc..da2bcfd493 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -9,8 +9,8 @@ * \brief Header file for main.c. **/ -#ifndef _TOR_MAIN_H -#define _TOR_MAIN_H +#ifndef TOR_MAIN_H +#define TOR_MAIN_H extern int can_complete_circuit; diff --git a/src/or/microdesc.c b/src/or/microdesc.c index 3bda9cbfaf..42a35f0676 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -6,6 +6,7 @@ #include "config.h" #include "directory.h" #include "dirserv.h" +#include "entrynodes.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" @@ -42,7 +43,7 @@ struct microdesc_cache_t { /** Helper: computes a hash of <b>md</b> to place it in a hash table. */ static INLINE unsigned int -_microdesc_hash(microdesc_t *md) +microdesc_hash_(microdesc_t *md) { unsigned *d = (unsigned*)md->digest; #if SIZEOF_INT == 4 @@ -54,15 +55,15 @@ _microdesc_hash(microdesc_t *md) /** Helper: compares <b>a</b> and </b> for equality for hash-table purposes. */ static INLINE int -_microdesc_eq(microdesc_t *a, microdesc_t *b) +microdesc_eq_(microdesc_t *a, microdesc_t *b) { return tor_memeq(a->digest, b->digest, DIGEST256_LEN); } HT_PROTOTYPE(microdesc_map, microdesc_t, node, - _microdesc_hash, _microdesc_eq); + microdesc_hash_, microdesc_eq_); HT_GENERATE(microdesc_map, microdesc_t, node, - _microdesc_hash, _microdesc_eq, 0.6, + microdesc_hash_, microdesc_eq_, 0.6, malloc, realloc, free); /** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations. diff --git a/src/or/microdesc.h b/src/or/microdesc.h index 5646fc7a85..4b18caaae0 100644 --- a/src/or/microdesc.h +++ b/src/or/microdesc.h @@ -9,8 +9,8 @@ * \brief Header file for microdesc.c. **/ -#ifndef _TOR_MICRODESC_H -#define _TOR_MICRODESC_H +#ifndef TOR_MICRODESC_H +#define TOR_MICRODESC_H microdesc_cache_t *get_microdesc_cache(void); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 91720b5835..89afb5a5c1 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -12,9 +12,9 @@ #include "or.h" #include "channel.h" -#include "circuitbuild.h" #include "circuitmux.h" #include "circuitmux_ewma.h" +#include "circuitstats.h" #include "config.h" #include "connection.h" #include "connection_or.h" @@ -22,6 +22,7 @@ #include "directory.h" #include "dirserv.h" #include "dirvote.h" +#include "entrynodes.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" @@ -670,7 +671,7 @@ networkstatus_get_cache_filename(const char *identity_digest) /** Helper for smartlist_sort: Compare two networkstatus objects by * publication date. */ static int -_compare_networkstatus_v2_published_on(const void **_a, const void **_b) +compare_networkstatus_v2_published_on_(const void **_a, const void **_b) { const networkstatus_v2_t *a = *_a, *b = *_b; if (a->published_on < b->published_on) @@ -904,7 +905,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at, networkstatus_v2_list_has_changed = 1; smartlist_sort(networkstatus_v2_list, - _compare_networkstatus_v2_published_on); + compare_networkstatus_v2_published_on_); if (!skewed) add_networkstatus_to_cache(s, source, ns); @@ -2005,7 +2006,7 @@ download_status_map_update_from_v2_networkstatus(void) digestmap_set(dl_status, d, s); } SMARTLIST_FOREACH_END(rs); } SMARTLIST_FOREACH_END(ns); - digestmap_free(v2_download_status_map, _tor_free); + digestmap_free(v2_download_status_map, tor_free_); v2_download_status_map = dl_status; networkstatus_v2_list_has_changed = 0; } @@ -2018,7 +2019,7 @@ routerstatus_list_update_named_server_map(void) if (!current_consensus) return; - strmap_free(named_server_map, _tor_free); + strmap_free(named_server_map, tor_free_); named_server_map = strmap_new(); strmap_free(unnamed_server_map, NULL); unnamed_server_map = strmap_new(); @@ -2405,7 +2406,7 @@ networkstatus_free_all(void) networkstatus_v2_list = NULL; } - digestmap_free(v2_download_status_map, _tor_free); + digestmap_free(v2_download_status_map, tor_free_); v2_download_status_map = NULL; networkstatus_vote_free(current_ns_consensus); networkstatus_vote_free(current_md_consensus); @@ -2420,7 +2421,7 @@ networkstatus_free_all(void) tor_free(waiting->body); } - strmap_free(named_server_map, _tor_free); + strmap_free(named_server_map, tor_free_); strmap_free(unnamed_server_map, NULL); } diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index dcd58f8898..fe16f33918 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -9,8 +9,8 @@ * \brief Header file for networkstatus.c. **/ -#ifndef _TOR_NETWORKSTATUS_H -#define _TOR_NETWORKSTATUS_H +#ifndef TOR_NETWORKSTATUS_H +#define TOR_NETWORKSTATUS_H /** How old do we allow a v2 network-status to get before removing it * completely? */ diff --git a/src/or/nodelist.c b/src/or/nodelist.c index f3863032a1..5a726377ec 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -1113,7 +1113,7 @@ router_find_exact_exit_enclave(const char *address, uint16_t port) node->is_running && compare_tor_addr_to_node_policy(&a, port, node) == ADDR_POLICY_ACCEPTED && - !routerset_contains_node(options->_ExcludeExitNodesUnion, node)) + !routerset_contains_node(options->ExcludeExitNodesUnion_, node)) return node; }); return NULL; diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 2e978f1782..13a3847414 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -9,8 +9,8 @@ * \brief Header file for nodelist.c. **/ -#ifndef _TOR_NODELIST_H -#define _TOR_NODELIST_H +#ifndef TOR_NODELIST_H +#define TOR_NODELIST_H #define node_assert_ok(n) STMT_BEGIN { \ tor_assert((n)->ri || (n)->rs); \ diff --git a/src/or/ntmain.h b/src/or/ntmain.h index 07fdcf466b..95a835a42e 100644 --- a/src/or/ntmain.h +++ b/src/or/ntmain.h @@ -9,8 +9,8 @@ * \brief Header file for ntmain.c. **/ -#ifndef _TOR_NTMAIN_H -#define _TOR_NTMAIN_H +#ifndef TOR_NTMAIN_H +#define TOR_NTMAIN_H #ifdef _WIN32 #if !defined (WINCE) diff --git a/src/or/onion.h b/src/or/onion.h index 7e0f873c73..e7626f9709 100644 --- a/src/or/onion.h +++ b/src/or/onion.h @@ -9,8 +9,8 @@ * \brief Header file for onion.c. **/ -#ifndef _TOR_ONION_H -#define _TOR_ONION_H +#ifndef TOR_ONION_H +#define TOR_ONION_H int onion_pending_add(or_circuit_t *circ, char *onionskin); or_circuit_t *onion_next_task(char **onionskin_out); diff --git a/src/or/or.h b/src/or/or.h index 5c6e998081..6510725f69 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -9,8 +9,8 @@ * \brief Master header file for Tor-specific functionality. **/ -#ifndef _TOR_OR_H -#define _TOR_OR_H +#ifndef TOR_OR_H +#define TOR_OR_H #include "orconfig.h" @@ -198,7 +198,7 @@ typedef enum { CIRC_ID_TYPE_NEITHER=2 } circ_id_type_t; -#define _CONN_TYPE_MIN 3 +#define CONN_TYPE_MIN_ 3 /** Type for sockets listening for OR connections. */ #define CONN_TYPE_OR_LISTENER 3 /** A bidirectional TLS connection transmitting a sequence of cells. @@ -229,8 +229,8 @@ typedef enum { #define CONN_TYPE_AP_NATD_LISTENER 14 /** Type for sockets listening for DNS requests. */ #define CONN_TYPE_AP_DNS_LISTENER 15 -#define _CONN_TYPE_MAX 15 -/* !!!! If _CONN_TYPE_MAX is ever over 15, we must grow the type field in +#define CONN_TYPE_MAX_ 15 +/* !!!! If CONN_TYPE_MAX_ is ever over 15, we must grow the type field in * connection_t. */ /* Proxy client types */ @@ -270,17 +270,17 @@ typedef enum { /** State for any listener connection. */ #define LISTENER_STATE_READY 0 -#define _CPUWORKER_STATE_MIN 1 +#define CPUWORKER_STATE_MIN_ 1 /** State for a connection to a cpuworker process that's idle. */ #define CPUWORKER_STATE_IDLE 1 /** State for a connection to a cpuworker process that's processing a * handshake. */ #define CPUWORKER_STATE_BUSY_ONION 2 -#define _CPUWORKER_STATE_MAX 2 +#define CPUWORKER_STATE_MAX_ 2 #define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION -#define _OR_CONN_STATE_MIN 1 +#define OR_CONN_STATE_MIN_ 1 /** State for a connection to an OR: waiting for connect() to finish. */ #define OR_CONN_STATE_CONNECTING 1 /** State for a connection to an OR: waiting for proxy handshake to complete */ @@ -305,9 +305,9 @@ typedef enum { #define OR_CONN_STATE_OR_HANDSHAKING_V3 7 /** State for an OR connection: Ready to send/receive cells. */ #define OR_CONN_STATE_OPEN 8 -#define _OR_CONN_STATE_MAX 8 +#define OR_CONN_STATE_MAX_ 8 -#define _EXIT_CONN_STATE_MIN 1 +#define EXIT_CONN_STATE_MIN_ 1 /** State for an exit connection: waiting for response from DNS farm. */ #define EXIT_CONN_STATE_RESOLVING 1 /** State for an exit connection: waiting for connect() to finish. */ @@ -316,10 +316,10 @@ typedef enum { #define EXIT_CONN_STATE_OPEN 3 /** State for an exit connection: waiting to be removed. */ #define EXIT_CONN_STATE_RESOLVEFAILED 4 -#define _EXIT_CONN_STATE_MAX 4 +#define EXIT_CONN_STATE_MAX_ 4 /* The AP state values must be disjoint from the EXIT state values. */ -#define _AP_CONN_STATE_MIN 5 +#define AP_CONN_STATE_MIN_ 5 /** State for a SOCKS connection: waiting for SOCKS request. */ #define AP_CONN_STATE_SOCKS_WAIT 5 /** State for a SOCKS connection: got a y.onion URL; waiting to receive @@ -339,14 +339,14 @@ typedef enum { /** State for a transparent natd connection: waiting for original * destination. */ #define AP_CONN_STATE_NATD_WAIT 12 -#define _AP_CONN_STATE_MAX 12 +#define AP_CONN_STATE_MAX_ 12 /** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding * edge connection is not attached to any circuit. */ #define AP_CONN_STATE_IS_UNATTACHED(s) \ ((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT) -#define _DIR_CONN_STATE_MIN 1 +#define DIR_CONN_STATE_MIN_ 1 /** State for connection to directory server: waiting for connect(). */ #define DIR_CONN_STATE_CONNECTING 1 /** State for connection to directory server: sending HTTP request. */ @@ -359,21 +359,21 @@ typedef enum { #define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5 /** State for connection at directory server: sending HTTP response. */ #define DIR_CONN_STATE_SERVER_WRITING 6 -#define _DIR_CONN_STATE_MAX 6 +#define DIR_CONN_STATE_MAX_ 6 /** True iff the purpose of <b>conn</b> means that it's a server-side * directory connection. */ #define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER) -#define _CONTROL_CONN_STATE_MIN 1 +#define CONTROL_CONN_STATE_MIN_ 1 /** State for a control connection: Authenticated and accepting v1 commands. */ #define CONTROL_CONN_STATE_OPEN 1 /** State for a control connection: Waiting for authentication; speaking * protocol v1. */ #define CONTROL_CONN_STATE_NEEDAUTH 2 -#define _CONTROL_CONN_STATE_MAX 2 +#define CONTROL_CONN_STATE_MAX_ 2 -#define _DIR_PURPOSE_MIN 3 +#define DIR_PURPOSE_MIN_ 3 /** A connection to a directory server: download a rendezvous * descriptor. */ #define DIR_PURPOSE_FETCH_RENDDESC 3 @@ -421,7 +421,7 @@ typedef enum { #define DIR_PURPOSE_FETCH_RENDDESC_V2 18 /** A connection to a directory server: download a microdescriptor. */ #define DIR_PURPOSE_FETCH_MICRODESC 19 -#define _DIR_PURPOSE_MAX 19 +#define DIR_PURPOSE_MAX_ 19 /** True iff <b>p</b> is a purpose corresponding to uploading data to a * directory server. */ @@ -431,12 +431,12 @@ typedef enum { (p)==DIR_PURPOSE_UPLOAD_VOTE || \ (p)==DIR_PURPOSE_UPLOAD_SIGNATURES) -#define _EXIT_PURPOSE_MIN 1 +#define EXIT_PURPOSE_MIN_ 1 /** This exit stream wants to do an ordinary connect. */ #define EXIT_PURPOSE_CONNECT 1 /** This exit stream wants to do a resolve (either normal or reverse). */ #define EXIT_PURPOSE_RESOLVE 2 -#define _EXIT_PURPOSE_MAX 2 +#define EXIT_PURPOSE_MAX_ 2 /* !!!! If any connection purpose is ever over 31, we must grow the type * field in connection_t. */ @@ -451,10 +451,10 @@ typedef enum { /** Circuit state: onionskin(s) processed, ready to send/receive cells. */ #define CIRCUIT_STATE_OPEN 3 -#define _CIRCUIT_PURPOSE_MIN 1 +#define CIRCUIT_PURPOSE_MIN_ 1 /* these circuits were initiated elsewhere */ -#define _CIRCUIT_PURPOSE_OR_MIN 1 +#define CIRCUIT_PURPOSE_OR_MIN_ 1 /** OR-side circuit purpose: normal circuit, at OR. */ #define CIRCUIT_PURPOSE_OR 1 /** OR-side circuit purpose: At OR, from Bob, waiting for intro from Alices. */ @@ -463,7 +463,7 @@ typedef enum { #define CIRCUIT_PURPOSE_REND_POINT_WAITING 3 /** OR-side circuit purpose: At OR, both circuits have this purpose. */ #define CIRCUIT_PURPOSE_REND_ESTABLISHED 4 -#define _CIRCUIT_PURPOSE_OR_MAX 4 +#define CIRCUIT_PURPOSE_OR_MAX_ 4 /* these circuits originate at this node */ @@ -506,7 +506,7 @@ typedef enum { #define CIRCUIT_PURPOSE_C_REND_JOINED 12 /** This circuit is used for build time measurement only */ #define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 13 -#define _CIRCUIT_PURPOSE_C_MAX 13 +#define CIRCUIT_PURPOSE_C_MAX_ 13 /** Hidden-service-side circuit purpose: at Bob, waiting for introductions. */ #define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 14 /** Hidden-service-side circuit purpose: at Bob, successfully established @@ -520,19 +520,19 @@ typedef enum { #define CIRCUIT_PURPOSE_TESTING 18 /** A controller made this circuit and Tor should not use it. */ #define CIRCUIT_PURPOSE_CONTROLLER 19 -#define _CIRCUIT_PURPOSE_MAX 19 +#define CIRCUIT_PURPOSE_MAX_ 19 /** A catch-all for unrecognized purposes. Currently we don't expect * to make or see any circuits with this purpose. */ #define CIRCUIT_PURPOSE_UNKNOWN 255 /** True iff the circuit purpose <b>p</b> is for a circuit that * originated at this node. */ -#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>_CIRCUIT_PURPOSE_OR_MAX) +#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_) /** True iff the circuit purpose <b>p</b> is for a circuit that originated * here to serve as a client. (Hidden services don't count here.) */ #define CIRCUIT_PURPOSE_IS_CLIENT(p) \ - ((p)> _CIRCUIT_PURPOSE_OR_MAX && \ - (p)<=_CIRCUIT_PURPOSE_C_MAX) + ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \ + (p)<=CIRCUIT_PURPOSE_C_MAX_) /** True iff the circuit_t <b>c</b> is actually an origin_circuit_t. */ #define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose)) /** True iff the circuit purpose <b>p</b> is for an established rendezvous @@ -665,7 +665,7 @@ typedef enum { /* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt for * documentation of these. */ -#define _END_CIRC_REASON_MIN 0 +#define END_CIRC_REASON_MIN_ 0 #define END_CIRC_REASON_NONE 0 #define END_CIRC_REASON_TORPROTOCOL 1 #define END_CIRC_REASON_INTERNAL 2 @@ -679,7 +679,7 @@ typedef enum { #define END_CIRC_REASON_TIMEOUT 10 #define END_CIRC_REASON_DESTROYED 11 #define END_CIRC_REASON_NOSUCHSERVICE 12 -#define _END_CIRC_REASON_MAX 12 +#define END_CIRC_REASON_MAX_ 12 /** Bitwise-OR this with the argument to circuit_mark_for_close() or * control_event_circuit_status() to indicate that the reason was @@ -1206,7 +1206,7 @@ typedef struct connection_t { /** Subtype of connection_t; used for a listener socket. */ typedef struct listener_connection_t { - connection_t _base; + connection_t base_; /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points * to the evdns_server_port it uses to listen to and answer connections. */ @@ -1329,7 +1329,7 @@ typedef struct or_handshake_state_t { /** Subtype of connection_t for an "OR connection" -- that is, one that speaks * cells over TLS. */ typedef struct or_connection_t { - connection_t _base; + connection_t base_; /** Hash of the public RSA key for the other side's identity key, or zeroes * if the other side hasn't shown us a valid identity key. */ @@ -1394,7 +1394,7 @@ typedef struct or_connection_t { /** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) * connection, or an exit. */ typedef struct edge_connection_t { - connection_t _base; + connection_t base_; struct edge_connection_t *next_stream; /**< Points to the next stream at this * edge, if any */ @@ -1447,7 +1447,7 @@ typedef struct edge_connection_t { /** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS * connection, a DNS request, a TransPort connection or a NATD connection */ typedef struct entry_connection_t { - edge_connection_t _edge; + edge_connection_t edge_; /** Nickname of planned exit node -- used with .exit support. */ char *chosen_exit_name; @@ -1525,7 +1525,7 @@ typedef struct entry_connection_t { /** Subtype of connection_t for an "directory connection" -- that is, an HTTP * connection to retrieve or serve directory material. */ typedef struct dir_connection_t { - connection_t _base; + connection_t base_; /** Which 'resource' did we ask the directory for? This is typically the part * of the URL string that defines, relative to the directory conn purpose, @@ -1572,7 +1572,7 @@ typedef struct dir_connection_t { /** Subtype of connection_t for an connection to a controller. */ typedef struct control_connection_t { - connection_t _base; + connection_t base_; uint32_t event_mask; /**< Bitfield: which events does this controller * care about? */ @@ -1599,12 +1599,12 @@ typedef struct control_connection_t { } control_connection_t; /** Cast a connection_t subtype pointer to a connection_t **/ -#define TO_CONN(c) (&(((c)->_base))) -/** Helper macro: Given a pointer to to._base, of type from*, return &to. */ -#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, _base)) +#define TO_CONN(c) (&(((c)->base_))) +/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */ +#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_)) /** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ -#define ENTRY_TO_EDGE_CONN(c) (&(((c))->_edge)) +#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) /** Cast a entry_connection_t subtype pointer to a connection_t **/ #define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c))) @@ -1649,12 +1649,12 @@ static INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c) static INLINE entry_connection_t *TO_ENTRY_CONN(connection_t *c) { tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); - return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, _edge._base); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); } static INLINE entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c) { - tor_assert(c->_base.magic == ENTRY_CONNECTION_MAGIC); - return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, _edge); + tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); } static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c) { @@ -2726,7 +2726,7 @@ typedef enum { /** An origin_circuit_t holds data necessary to build and use a circuit. */ typedef struct origin_circuit_t { - circuit_t _base; + circuit_t base_; /** Linked list of AP streams (or EXIT streams if hidden service) * associated with this circuit. */ @@ -2859,7 +2859,7 @@ typedef struct origin_circuit_t { /** An or_circuit_t holds information needed to implement a circuit at an * OR. */ typedef struct or_circuit_t { - circuit_t _base; + circuit_t base_; /** Next circuit in the doubly-linked ring of circuits waiting to add * cells to p_chan. NULL if we have no cells pending, or if we're not @@ -2940,7 +2940,7 @@ typedef struct or_circuit_t { } or_circuit_t; /** Convert a circuit subtype to a circuit_t. */ -#define TO_CIRCUIT(x) (&((x)->_base)) +#define TO_CIRCUIT(x) (&((x)->base_)) /** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert * if the cast is impossible. */ @@ -3063,7 +3063,7 @@ typedef struct routerset_t routerset_t; /** Configuration options for a Tor process. */ typedef struct { - uint32_t _magic; + uint32_t magic_; /** What should the tor process actually do? */ enum { @@ -3105,7 +3105,7 @@ typedef struct { * ORs not to consider as exits. */ /** Union of ExcludeNodes and ExcludeExitNodes */ - routerset_t *_ExcludeExitNodesUnion; + routerset_t *ExcludeExitNodesUnion_; int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our * process for all current and future memory. */ @@ -3113,7 +3113,7 @@ typedef struct { /** List of "entry", "middle", "exit", "introduction", "rendezvous". */ smartlist_t *AllowInvalidNodes; /** Bitmask; derived from AllowInvalidNodes. */ - invalid_router_usage_t _AllowInvalid; + invalid_router_usage_t AllowInvalid_; config_line_t *ExitPolicy; /**< Lists of exit policy components. */ int ExitPolicyRejectPrivate; /**< Should we not exit to local addresses? */ config_line_t *SocksPolicy; /**< Lists of socks policy components */ @@ -3136,9 +3136,9 @@ typedef struct { /** Local address to bind outbound sockets */ config_line_t *OutboundBindAddress; /** IPv4 address derived from OutboundBindAddress. */ - tor_addr_t _OutboundBindAddressIPv4; + tor_addr_t OutboundBindAddressIPv4_; /** IPv6 address derived from OutboundBindAddress. */ - tor_addr_t _OutboundBindAddressIPv6; + tor_addr_t OutboundBindAddressIPv6_; /** Directory server only: which versions of * Tor should we tell users to run? */ config_line_t *RecommendedVersions; @@ -3207,7 +3207,7 @@ typedef struct { char *BridgePassword; /** If BridgePassword is set, this is a SHA256 digest of the basic http * authenticator for it. Used so we can do a time-independent comparison. */ - char *_BridgePassword_AuthDigest; + char *BridgePassword_AuthDigest_; int UseBridges; /**< Boolean: should we start all circuits with a bridge? */ config_line_t *Bridges; /**< List of bootstrap bridge addresses. */ @@ -3233,7 +3233,7 @@ typedef struct { * "v1", "v2", "v3", "bridge", or "". */ smartlist_t *PublishServerDescriptor; /** A bitfield of authority types, derived from PublishServerDescriptor. */ - dirinfo_type_t _PublishServerDescriptor; + dirinfo_type_t PublishServerDescriptor_; /** Boolean: do we publish hidden service descriptors to the HS auths? */ int PublishHidServDescriptors; int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */ @@ -3266,7 +3266,7 @@ typedef struct { int CloseHSServiceRendCircuitsImmediatelyOnTimeout; int ConnLimit; /**< Demanded minimum number of simultaneous connections. */ - int _ConnLimit; /**< Maximum allowed number of simultaneous connections. */ + int ConnLimit_; /**< Maximum allowed number of simultaneous connections. */ int RunAsDaemon; /**< If true, run in the background. (Unix only) */ int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */ smartlist_t *FirewallPorts; /**< Which ports our firewall allows @@ -3470,7 +3470,7 @@ typedef struct { /* Derived from SafeLogging */ enum { SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE - } _SafeLogging; + } SafeLogging_; int SafeSocks; /**< Boolean: should we outright refuse application * connections that use socks4 or socks5-with-local-dns? */ @@ -3689,7 +3689,7 @@ typedef struct { /** Set to true if the TestingTorNetwork configuration option is set. * This is used so that options_validate() has a chance to realize that * the defaults have changed. */ - int _UsingTestNetworkDefaults; + int UsingTestNetworkDefaults_; /** If 1, we try to use microdescriptors to build circuits. If 0, we don't. * If -1, Tor decides. */ @@ -3733,7 +3733,7 @@ typedef struct { /** Persistent state for an onion router, as saved to disk. */ typedef struct { - uint32_t _magic; + uint32_t magic_; /** The time at which we next plan to write the state to the disk. Equal to * TIME_MAX if there are no savable changes, 0 if there are changes that * should be saved right away. */ @@ -4506,7 +4506,7 @@ typedef struct trusted_dir_server_t { #define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3) #define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4) -#define _PDS_PREFER_TUNNELED_DIR_CONNS (1<<16) +#define PDS_PREFER_TUNNELED_DIR_CONNS_ (1<<16) /** Possible ways to weight routers when choosing one randomly. See * routerlist_sl_choose_by_bandwidth() for more information.*/ diff --git a/src/or/policies.c b/src/or/policies.c index ecf1f683d4..09ba10bbe7 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -1351,8 +1351,10 @@ parse_short_policy(const char *summary) unsigned low, high; char dummy; char ent_buf[32]; + size_t len; next = comma ? comma+1 : strchr(summary, '\0'); + len = comma ? (size_t)(comma - summary) : strlen(summary); if (n_entries == MAX_EXITPOLICY_SUMMARY_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Impossibly long policy summary %s", @@ -1360,20 +1362,22 @@ parse_short_policy(const char *summary) return NULL; } - if (! TOR_ISDIGIT(*summary) || next-summary > (int)(sizeof(ent_buf)-1)) { + if (! TOR_ISDIGIT(*summary) || len > (sizeof(ent_buf)-1)) { /* unrecognized entry format. skip it. */ continue; } - if (next-summary < 2) { + if (len < 1) { /* empty; skip it. */ + /* XXX This happens to be unreachable, since if len==0, then *summary is + * ',' or '\0', and the TOR_ISDIGIT test above would have failed. */ continue; } - memcpy(ent_buf, summary, next-summary-1); - ent_buf[next-summary-1] = '\0'; + memcpy(ent_buf, summary, len); + ent_buf[len] = '\0'; if (tor_sscanf(ent_buf, "%u-%u%c", &low, &high, &dummy) == 2) { - if (low<1 || low>65535 || high<1 || high>65535) { + if (low<1 || low>65535 || high<1 || high>65535 || low>high) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Found bad entry in policy summary %s", escaped(orig_summary)); return NULL; @@ -1416,6 +1420,33 @@ parse_short_policy(const char *summary) return result; } +/** Write <b>policy</b> back out into a string. Used only for unit tests + * currently. */ +char * +write_short_policy(const short_policy_t *policy) +{ + int i; + char *answer; + smartlist_t *sl = smartlist_new(); + + smartlist_add_asprintf(sl, "%s", policy->is_accept ? "accept " : "reject "); + + for (i=0; i < policy->n_entries; i++) { + const short_policy_entry_t *e = &policy->entries[i]; + if (e->min_port == e->max_port) { + smartlist_add_asprintf(sl, "%d", e->min_port); + } else { + smartlist_add_asprintf(sl, "%d-%d", e->min_port, e->max_port); + } + if (i < policy->n_entries-1) + smartlist_add(sl, tor_strdup(",")); + } + answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, a, tor_free(a)); + smartlist_free(sl); + return answer; +} + /** Release all storage held in <b>policy</b>. */ void short_policy_free(short_policy_t *policy) @@ -1434,15 +1465,14 @@ compare_tor_addr_to_short_policy(const tor_addr_t *addr, uint16_t port, int i; int found_match = 0; int accept; - (void)addr; tor_assert(port != 0); if (addr && tor_addr_is_null(addr)) addr = NULL; /* Unspec means 'no address at all,' in this context. */ - if (addr && (tor_addr_is_internal(addr, 0) || - tor_addr_is_loopback(addr))) + if (addr && get_options()->ClientRejectInternalAddresses && + (tor_addr_is_internal(addr, 0) || tor_addr_is_loopback(addr))) return ADDR_POLICY_REJECTED; for (i=0; i < policy->n_entries; ++i) { @@ -1490,7 +1520,7 @@ short_policy_is_reject_star(const short_policy_t *policy) policy->entries[0].max_port == 65535); } -/** Decides whether addr:port is probably or definitely accepted or rejcted by +/** Decides whether addr:port is probably or definitely accepted or rejected by * <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port * interpretation. */ addr_policy_result_t diff --git a/src/or/policies.h b/src/or/policies.h index 31f3f06c7d..431e69eb0d 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -9,8 +9,8 @@ * \brief Header file for policies.c. **/ -#ifndef _TOR_POLICIES_H -#define _TOR_POLICIES_H +#ifndef TOR_POLICIES_H +#define TOR_POLICIES_H /* (length of "accept 255.255.255.255/255.255.255.255:65535-65535\n" plus a * NUL.) @@ -61,6 +61,7 @@ void policies_free_all(void); char *policy_summarize(smartlist_t *policy); short_policy_t *parse_short_policy(const char *summary); +char *write_short_policy(const short_policy_t *policy); void short_policy_free(short_policy_t *policy); int short_policy_is_reject_star(const short_policy_t *policy); addr_policy_result_t compare_tor_addr_to_short_policy( diff --git a/src/or/reasons.c b/src/or/reasons.c index a04cd869a2..874a86774b 100644 --- a/src/or/reasons.c +++ b/src/or/reasons.c @@ -300,8 +300,13 @@ errno_to_orconn_end_reason(int e) const char * circuit_end_reason_to_control_string(int reason) { - if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE) + int is_remote = 0; + + if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE) { reason &= ~END_CIRC_REASON_FLAG_REMOTE; + is_remote = 1; + } + switch (reason) { case END_CIRC_AT_ORIGIN: /* This shouldn't get passed here; it's a catch-all reason. */ @@ -338,7 +343,18 @@ circuit_end_reason_to_control_string(int reason) case END_CIRC_REASON_MEASUREMENT_EXPIRED: return "MEASUREMENT_EXPIRED"; default: - log_warn(LD_BUG, "Unrecognized reason code %d", (int)reason); + if (is_remote) { + /* + * If it's remote, it's not a bug *here*, so don't use LD_BUG, but + * do note that the someone we're talking to is speaking the Tor + * protocol with a weird accent. + */ + log_warn(LD_PROTOCOL, + "Remote server sent bogus reason code %d", reason); + } else { + log_warn(LD_BUG, + "Unrecognized reason code %d", reason); + } return NULL; } } diff --git a/src/or/reasons.h b/src/or/reasons.h index 377b61b113..0dbf5aa693 100644 --- a/src/or/reasons.h +++ b/src/or/reasons.h @@ -9,8 +9,8 @@ * \brief Header file for reasons.c. **/ -#ifndef _TOR_REASONS_H -#define _TOR_REASONS_H +#ifndef TOR_REASONS_H +#define TOR_REASONS_H const char *stream_end_reason_to_control_string(int reason); const char *stream_end_reason_to_string(int reason); diff --git a/src/or/relay.c b/src/or/relay.c index 7c81273a0a..bd99d91dca 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -230,7 +230,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, cell_direction == CELL_DIRECTION_OUT) { or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice; tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); - tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + tor_assert(splice->base_.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); cell->circ_id = splice->p_circ_id; cell->command = CELL_RELAY; /* can't be relay_early anyway */ if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice), @@ -422,7 +422,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && - !tmpconn->_base.marked_for_close && + !tmpconn->base_.marked_for_close && tmpconn->cpath_layer == layer_hint) { log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); return tmpconn; @@ -432,7 +432,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && - !tmpconn->_base.marked_for_close) { + !tmpconn->base_.marked_for_close) { log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); if (cell_direction == CELL_DIRECTION_OUT || connection_edge_is_rendezvous_stream(tmpconn)) @@ -442,7 +442,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && - !tmpconn->_base.marked_for_close) { + !tmpconn->base_.marked_for_close) { log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); return tmpconn; } @@ -631,16 +631,16 @@ connection_edge_send_command(edge_connection_t *fromconn, tor_assert(fromconn); circ = fromconn->on_circuit; - if (fromconn->_base.marked_for_close) { + if (fromconn->base_.marked_for_close) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", - fromconn->_base.marked_for_close_file, - fromconn->_base.marked_for_close); + fromconn->base_.marked_for_close_file, + fromconn->base_.marked_for_close); return 0; } if (!circ) { - if (fromconn->_base.type == CONN_TYPE_AP) { + if (fromconn->base_.type == CONN_TYPE_AP) { log_info(LD_APP,"no circ. Closing conn."); connection_mark_unattached_ap(EDGE_TO_ENTRY_CONN(fromconn), END_STREAM_REASON_INTERNAL); @@ -777,8 +777,8 @@ connection_ap_process_end_not_open( circuit_log_path(LOG_INFO,LD_APP,circ); /* Mark this circuit "unusable for new streams". */ /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->_base.timestamp_dirty); - circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + tor_assert(circ->base_.timestamp_dirty); + circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness; if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ @@ -854,7 +854,7 @@ connection_edge_process_relay_cell_not_open( edge_connection_t *conn, crypt_path_t *layer_hint) { if (rh->command == RELAY_COMMAND_END) { - if (CIRCUIT_IS_ORIGIN(circ) && conn->_base.type == CONN_TYPE_AP) { + if (CIRCUIT_IS_ORIGIN(circ) && conn->base_.type == CONN_TYPE_AP) { return connection_ap_process_end_not_open(rh, cell, TO_ORIGIN_CIRCUIT(circ), EDGE_TO_ENTRY_CONN(conn), @@ -869,18 +869,18 @@ connection_edge_process_relay_cell_not_open( } } - if (conn->_base.type == CONN_TYPE_AP && + if (conn->base_.type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); tor_assert(CIRCUIT_IS_ORIGIN(circ)); - if (conn->_base.state != AP_CONN_STATE_CONNECT_WAIT) { + if (conn->base_.state != AP_CONN_STATE_CONNECT_WAIT) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got 'connected' while not in state connect_wait. Dropping."); return 0; } - conn->_base.state = AP_CONN_STATE_OPEN; + conn->base_.state = AP_CONN_STATE_OPEN; log_info(LD_APP,"'connected' received after %d seconds.", - (int)(time(NULL) - conn->_base.timestamp_lastread)); + (int)(time(NULL) - conn->base_.timestamp_lastread)); if (rh->length >= 4) { uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE)); int ttl; @@ -944,13 +944,13 @@ connection_edge_process_relay_cell_not_open( } return 0; } - if (conn->_base.type == CONN_TYPE_AP && + if (conn->base_.type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) { int ttl; int answer_len; uint8_t answer_type; entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); - if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) { + if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a 'resolved' cell while " "not in state resolve_wait. Dropping."); return 0; @@ -1001,8 +1001,8 @@ connection_edge_process_relay_cell_not_open( log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got an unexpected relay command %d, in state %d (%s). Dropping.", - rh->command, conn->_base.state, - conn_state_to_string(conn->_base.type, conn->_base.state)); + rh->command, conn->base_.state, + conn_state_to_string(conn->base_.type, conn->base_.state)); return 0; /* for forward compatibility, don't kill the circuit */ // connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); // connection_mark_for_close(conn); @@ -1050,9 +1050,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, * conn points to the recognized stream. */ if (conn && !connection_state_is_open(TO_CONN(conn))) { - if (conn->_base.type == CONN_TYPE_EXIT && - (conn->_base.state == EXIT_CONN_STATE_CONNECTING || - conn->_base.state == EXIT_CONN_STATE_RESOLVING) && + if (conn->base_.type == CONN_TYPE_EXIT && + (conn->base_.state == EXIT_CONN_STATE_CONNECTING || + conn->base_.state == EXIT_CONN_STATE_RESOLVING) && rh.command == RELAY_COMMAND_DATA) { /* Allow DATA cells to be delivered to an exit node in state * EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING. @@ -1152,10 +1152,10 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } /* XXX add to this log_fn the exit node's nickname? */ log_info(domain,"%d: end cell (%s) for stream %d. Removing stream.", - conn->_base.s, + conn->base_.s, stream_end_reason_to_string(reason), conn->stream_id); - if (conn->_base.type == CONN_TYPE_AP) { + if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); if (entry_conn->socks_request && !entry_conn->socks_request->has_finished) @@ -1166,7 +1166,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, conn->edge_has_sent_end = 1; if (!conn->end_reason) conn->end_reason = reason | END_STREAM_REASON_FLAG_REMOTE; - if (!conn->_base.marked_for_close) { + if (!conn->base_.marked_for_close) { /* only mark it if not already marked. it's possible to * get the 'end' right around when the client hangs up on us. */ connection_mark_and_flush(TO_CONN(conn)); @@ -1392,21 +1392,21 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, size_t bytes_to_process, length; char payload[CELL_PAYLOAD_SIZE]; circuit_t *circ; - const unsigned domain = conn->_base.type == CONN_TYPE_AP ? LD_APP : LD_EXIT; + const unsigned domain = conn->base_.type == CONN_TYPE_AP ? LD_APP : LD_EXIT; int sending_from_optimistic = 0; const int sending_optimistically = - conn->_base.type == CONN_TYPE_AP && - conn->_base.state != AP_CONN_STATE_OPEN; + conn->base_.type == CONN_TYPE_AP && + conn->base_.state != AP_CONN_STATE_OPEN; entry_connection_t *entry_conn = - conn->_base.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL; + conn->base_.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL; crypt_path_t *cpath_layer = conn->cpath_layer; tor_assert(conn); - if (conn->_base.marked_for_close) { + if (conn->base_.marked_for_close) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", - conn->_base.marked_for_close_file, conn->_base.marked_for_close); + conn->base_.marked_for_close_file, conn->base_.marked_for_close); return 0; } @@ -1473,7 +1473,7 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, connection_fetch_from_buf(payload, length, TO_CONN(conn)); } - log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s, + log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->base_.s, (int)length, (int)connection_get_inbuf_len(TO_CONN(conn))); if (sending_optimistically && !sending_from_optimistic) { @@ -1539,9 +1539,9 @@ connection_edge_consider_sending_sendme(edge_connection_t *conn) } while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) { - log_debug(conn->_base.type == CONN_TYPE_AP ?LD_APP:LD_EXIT, + log_debug(conn->base_.type == CONN_TYPE_AP ?LD_APP:LD_EXIT, "Outbuf %d, Queuing stream sendme.", - (int)conn->_base.outbuf_flushlen); + (int)conn->base_.outbuf_flushlen); conn->deliver_window += STREAMWINDOW_INCREMENT; if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME, NULL, 0) < 0) { @@ -1630,7 +1630,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, /* Activate reading starting from the chosen stream */ for (conn=chosen_stream; conn; conn = conn->next_stream) { /* Start reading for the streams starting from here */ - if (conn->_base.marked_for_close || conn->package_window <= 0) + if (conn->base_.marked_for_close || conn->package_window <= 0) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); @@ -1641,7 +1641,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, } /* Go back and do the ones we skipped, circular-style */ for (conn = first_conn; conn != chosen_stream; conn = conn->next_stream) { - if (conn->_base.marked_for_close || conn->package_window <= 0) + if (conn->base_.marked_for_close || conn->package_window <= 0) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); @@ -1667,7 +1667,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, * package. */ for (conn=first_conn; conn; conn=conn->next_stream) { - if (conn->_base.marked_for_close || conn->package_window <= 0) + if (conn->base_.marked_for_close || conn->package_window <= 0) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { int n = cells_per_conn, r; @@ -1857,7 +1857,7 @@ dump_cell_pool_usage(int severity) circuit_t *c; int n_circs = 0; int n_cells = 0; - for (c = _circuit_get_global_list(); c; c = c->next) { + for (c = circuit_get_global_list_(); c; c = c->next) { n_cells += c->n_chan_cells.n; if (!CIRCUIT_IS_ORIGIN(c)) n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n; diff --git a/src/or/relay.h b/src/or/relay.h index 5759c51801..3906d6bf85 100644 --- a/src/or/relay.h +++ b/src/or/relay.h @@ -9,8 +9,8 @@ * \brief Header file for relay.c. **/ -#ifndef _TOR_RELAY_H -#define _TOR_RELAY_H +#ifndef TOR_RELAY_H +#define TOR_RELAY_H extern uint64_t stats_n_relay_cells_relayed; extern uint64_t stats_n_relay_cells_delivered; diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 2104a5b3d4..915a41a0c3 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -44,7 +44,7 @@ rend_client_purge_state(void) void rend_client_introcirc_has_opened(origin_circuit_t *circ) { - tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); tor_assert(circ->cpath); log_info(LD_REND,"introcirc is open"); @@ -57,7 +57,7 @@ rend_client_introcirc_has_opened(origin_circuit_t *circ) static int rend_client_send_establish_rendezvous(origin_circuit_t *circ) { - tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); tor_assert(circ->rend_data); log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell"); @@ -103,13 +103,13 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ) if (circ->remaining_relay_early_cells) { log_info(LD_REND, "Re-extending circ %d, this time to %s.", - circ->_base.n_circ_id, + circ->base_.n_circ_id, safe_str_client(extend_info_describe(extend_info))); result = circuit_extend_to_new_exit(circ, extend_info); } else { log_info(LD_REND, "Closing intro circ %d (out of RELAY_EARLY cells).", - circ->_base.n_circ_id); + circ->base_.n_circ_id); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); /* connection_ap_handshake_attach_circuit will launch a new intro circ. */ result = 0; @@ -135,8 +135,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc, crypto_pk_t *intro_key = NULL; int status = 0; - tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY); + tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY); tor_assert(introcirc->rend_data); tor_assert(rendcirc->rend_data); tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address, @@ -308,12 +308,12 @@ rend_client_send_introduction(origin_circuit_t *introcirc, /* Set timestamp_dirty, because circuit_expire_building expects it * to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT * state. */ - introcirc->_base.timestamp_dirty = time(NULL); + introcirc->base_.timestamp_dirty = time(NULL); goto cleanup; perm_err: - if (!introcirc->_base.marked_for_close) + if (!introcirc->base_.marked_for_close) circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL); circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL); cleanup: @@ -328,7 +328,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, void rend_client_rendcirc_has_opened(origin_circuit_t *circ) { - tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); log_info(LD_REND,"rendcirc is open"); @@ -347,10 +347,10 @@ rend_client_introduction_acked(origin_circuit_t *circ, origin_circuit_t *rendcirc; (void) request; // XXXX Use this. - if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { log_warn(LD_PROTOCOL, "Received REND_INTRODUCE_ACK on unexpected circuit %d.", - circ->_base.n_circ_id); + circ->base_.n_circ_id); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); return -1; } @@ -377,7 +377,7 @@ rend_client_introduction_acked(origin_circuit_t *circ, /* Set timestamp_dirty, because circuit_expire_building expects * it to specify when a circuit entered the * _C_REND_READY_INTRO_ACKED state. */ - rendcirc->_base.timestamp_dirty = time(NULL); + rendcirc->base_.timestamp_dirty = time(NULL); } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } @@ -541,7 +541,7 @@ rend_client_purge_last_hid_serv_requests(void) if (old_last_hid_serv_requests != NULL) { log_info(LD_REND, "Purging client last-HS-desc-request-time table"); - strmap_free(old_last_hid_serv_requests, _tor_free); + strmap_free(old_last_hid_serv_requests, tor_free_); } } @@ -846,7 +846,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request, (void) request; (void) request_len; /* we just got an ack for our establish-rendezvous. switch purposes. */ - if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) { log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. " "Closing circ."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); @@ -857,7 +857,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request, circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_READY); /* Set timestamp_dirty, because circuit_expire_building expects it * to specify when a circuit entered the _C_REND_READY state. */ - circ->_base.timestamp_dirty = time(NULL); + circ->base_.timestamp_dirty = time(NULL); /* XXXX This is a pretty brute-force approach. It'd be better to * attach only the connections that are waiting on this circuit, rather * than trying to attach them all. See comments bug 743. */ @@ -875,8 +875,8 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, crypt_path_t *hop; char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; - if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY && - circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) + if ((circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY && + circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || !circ->build_state->pending_final_cpath) { log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not " "expecting it. Closing."); diff --git a/src/or/rendclient.h b/src/or/rendclient.h index 393b556e32..b71fe48be3 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -9,8 +9,8 @@ * \brief Header file for rendclient.c. **/ -#ifndef _TOR_RENDCLIENT_H -#define _TOR_RENDCLIENT_H +#ifndef TOR_RENDCLIENT_H +#define TOR_RENDCLIENT_H void rend_client_purge_state(void); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index f6b1bf9f65..9e306bdf73 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -800,7 +800,7 @@ rend_cache_entry_free(rend_cache_entry_t *e) /** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which * requires a function pointer whose argument is void*). */ static void -_rend_cache_entry_free(void *p) +rend_cache_entry_free_(void *p) { rend_cache_entry_free(p); } @@ -809,8 +809,8 @@ _rend_cache_entry_free(void *p) void rend_cache_free_all(void) { - strmap_free(rend_cache, _rend_cache_entry_free); - digestmap_free(rend_cache_v2_dir, _rend_cache_entry_free); + strmap_free(rend_cache, rend_cache_entry_free_); + digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_); rend_cache = NULL; rend_cache_v2_dir = NULL; } @@ -844,7 +844,7 @@ rend_cache_purge(void) { if (rend_cache) { log_info(LD_REND, "Purging client/v0-HS-authority HS descriptor cache"); - strmap_free(rend_cache, _rend_cache_entry_free); + strmap_free(rend_cache, rend_cache_entry_free_); } rend_cache = strmap_new(); } diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index be6bd13d2c..fe574b152f 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -9,8 +9,8 @@ * \brief Header file for rendcommon.c. **/ -#ifndef _TOR_RENDCOMMON_H -#define _TOR_RENDCOMMON_H +#ifndef TOR_RENDCOMMON_H +#define TOR_RENDCOMMON_H /** Free all storage associated with <b>data</b> */ static INLINE void diff --git a/src/or/rendmid.c b/src/or/rendmid.c index 00bbd28fa6..dc2dc1d9e7 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -35,7 +35,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, "Received an ESTABLISH_INTRO request on circuit %d", circ->p_circ_id); - if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_chan) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit."); reason = END_CIRC_REASON_TORPROTOCOL; @@ -142,7 +142,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request, log_info(LD_REND, "Received an INTRODUCE1 request on circuit %d", circ->p_circ_id); - if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_chan) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { log_warn(LD_PROTOCOL, "Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.", circ->p_circ_id); @@ -224,7 +224,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %d", circ->p_circ_id); - if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_chan) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { log_warn(LD_PROTOCOL, "Tried to establish rendezvous on non-OR or non-edge circuit."); goto err; @@ -277,7 +277,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, char hexid[9]; int reason = END_CIRC_REASON_INTERNAL; - if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_chan) { + if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { log_info(LD_REND, "Tried to complete rendezvous on non-OR or non-edge circuit %d.", circ->p_circ_id); diff --git a/src/or/rendmid.h b/src/or/rendmid.h index 0af6436dea..74ba16b316 100644 --- a/src/or/rendmid.h +++ b/src/or/rendmid.h @@ -9,8 +9,8 @@ * \brief Header file for rendmid.c. **/ -#ifndef _TOR_RENDMID_H -#define _TOR_RENDMID_H +#ifndef TOR_RENDMID_H +#define TOR_RENDMID_H int rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, size_t request_len); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index a1d4ac6f48..fe0333ef40 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -543,7 +543,7 @@ rend_config_services(const or_options_t *options, int validate_only) /* XXXX it would be nicer if we had a nicer abstraction to use here, * so we could just iterate over the list of services to close, but * once again, this isn't critical-path code. */ - for (circ = _circuit_get_global_list(); circ; circ = circ->next) { + for (circ = circuit_get_global_list_(); circ; circ = circ->next) { if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN && (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || @@ -610,7 +610,7 @@ rend_service_update_descriptor(rend_service_t *service) } circ = find_intro_circuit(intro_svc, service->pk_digest); - if (!circ || circ->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) { + if (!circ || circ->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) { /* This intro point's circuit isn't finished yet. Don't list it. */ continue; } @@ -1128,10 +1128,10 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, int replay; /* Do some initial validation and logging before we parse the cell */ - if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) { + if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) { log_warn(LD_PROTOCOL, "Got an INTRODUCE2 over a non-introduction circuit %d.", - circuit->_base.n_circ_id); + circuit->base_.n_circ_id); goto err; } @@ -1166,7 +1166,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, } log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.", - escaped(serviceid), circuit->_base.n_circ_id); + escaped(serviceid), circuit->base_.n_circ_id); /* use intro key instead of service key. */ intro_key = circuit->intro_key; @@ -1181,7 +1181,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, if (!parsed_req) { goto log_error; } else if (err_msg) { - log_info(LD_REND, "%s on circ %d.", err_msg, circuit->_base.n_circ_id); + log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id); tor_free(err_msg); } @@ -1191,7 +1191,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, if (result < 0) { goto log_error; } else if (err_msg) { - log_info(LD_REND, "%s on circ %d.", err_msg, circuit->_base.n_circ_id); + log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id); tor_free(err_msg); } @@ -1227,7 +1227,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, if (result < 0) { goto log_error; } else if (err_msg) { - log_info(LD_REND, "%s on circ %d.", err_msg, circuit->_base.n_circ_id); + log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id); tor_free(err_msg); } @@ -1237,7 +1237,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, if (result < 0) { goto log_error; } else if (err_msg) { - log_info(LD_REND, "%s on circ %d.", err_msg, circuit->_base.n_circ_id); + log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id); tor_free(err_msg); } @@ -1247,7 +1247,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, if (result < 0) { goto log_error; } else if (err_msg) { - log_info(LD_REND, "%s on circ %d.", err_msg, circuit->_base.n_circ_id); + log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id); tor_free(err_msg); } stage_descr = NULL; @@ -1396,7 +1396,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, } } - log_warn(LD_REND, "%s on circ %d", err_msg, circuit->_base.n_circ_id); + log_warn(LD_REND, "%s on circ %d", err_msg, circuit->base_.n_circ_id); err: status = -1; if (dh) crypto_dh_free(dh); @@ -2264,7 +2264,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) origin_circuit_t *newcirc; cpath_build_state_t *newstate, *oldstate; - tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); + tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); /* Don't relaunch the same rend circ twice. */ if (oldcirc->hs_service_side_rend_circ_has_been_relaunched) { @@ -2369,7 +2369,7 @@ rend_service_launch_establish_intro(rend_service_t *service, sizeof(launched->rend_data->onion_address)); memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN); launched->intro_key = crypto_pk_dup_key(intro->intro_key); - if (launched->_base.state == CIRCUIT_STATE_OPEN) + if (launched->base_.state == CIRCUIT_STATE_OPEN) rend_service_intro_has_opened(launched); return 0; } @@ -2381,7 +2381,7 @@ count_established_intro_points(const char *query) { int num_ipos = 0; circuit_t *circ; - for (circ = _circuit_get_global_list(); circ; circ = circ->next) { + for (circ = circuit_get_global_list_(); circ; circ = circ->next) { if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN && (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || @@ -2410,7 +2410,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) int reason = END_CIRC_REASON_TORPROTOCOL; crypto_pk_t *intro_key; - tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); + tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(!(circuit->build_state->onehop_tunnel)); #endif @@ -2424,7 +2424,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) circuit->rend_data->rend_pk_digest); if (!service) { log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.", - serviceid, circuit->_base.n_circ_id); + serviceid, circuit->base_.n_circ_id); reason = END_CIRC_REASON_NOSUCHSERVICE; goto err; } @@ -2468,7 +2468,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) log_info(LD_REND, "Established circuit %d as introduction point for service %s", - circuit->_base.n_circ_id, serviceid); + circuit->base_.n_circ_id, serviceid); /* Use the intro key instead of the service key in ESTABLISH_INTRO. */ intro_key = circuit->intro_key; @@ -2503,7 +2503,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) buf, len, circuit->cpath->prev)<0) { log_info(LD_GENERAL, "Couldn't send introduction request for service %s on circuit %d", - serviceid, circuit->_base.n_circ_id); + serviceid, circuit->base_.n_circ_id); reason = END_CIRC_REASON_INTERNAL; goto err; } @@ -2533,7 +2533,7 @@ rend_service_intro_established(origin_circuit_t *circuit, (void) request; (void) request_len; - if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { + if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { log_warn(LD_PROTOCOL, "received INTRO_ESTABLISHED cell on non-intro circuit."); goto err; @@ -2543,7 +2543,7 @@ rend_service_intro_established(origin_circuit_t *circuit, circuit->rend_data->rend_pk_digest); if (!service) { log_warn(LD_REND, "Unknown service on introduction circuit %d.", - circuit->_base.n_circ_id); + circuit->base_.n_circ_id); goto err; } service->desc_is_dirty = time(NULL); @@ -2553,7 +2553,7 @@ rend_service_intro_established(origin_circuit_t *circuit, circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN); log_info(LD_REND, "Received INTRO_ESTABLISHED cell on circuit %d for service %s", - circuit->_base.n_circ_id, serviceid); + circuit->base_.n_circ_id, serviceid); return 0; err: @@ -2574,7 +2574,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) char hexcookie[9]; int reason; - tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); + tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); tor_assert(circuit->cpath); tor_assert(circuit->build_state); #ifndef NON_ANONYMOUS_MODE_ENABLED @@ -2590,7 +2590,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) log_info(LD_REND, "Done building circuit %d to rendezvous with " "cookie %s for service %s", - circuit->_base.n_circ_id, hexcookie, serviceid); + circuit->base_.n_circ_id, hexcookie, serviceid); /* Clear the 'in-progress HS circ has timed out' flag for * consistency with what happens on the client side; this line has @@ -3150,7 +3150,7 @@ rend_services_introduce(void) j < (int)n_intro_points_to_open; ++j) { /* XXXX remove casts */ router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC; - if (get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION) + if (get_options()->AllowInvalid_ & ALLOW_INVALID_INTRODUCTION) flags |= CRN_ALLOW_INVALID; node = router_choose_random_node(intro_nodes, options->ExcludeNodes, flags); @@ -3300,7 +3300,7 @@ rend_service_dump_stats(int severity) continue; } log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s", - j, safe_name, circuit_state_to_string(circ->_base.state)); + j, safe_name, circuit_state_to_string(circ->base_.state)); } } } @@ -3319,7 +3319,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, smartlist_t *matching_ports; rend_service_port_config_t *chosen_port; - tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); tor_assert(circ->rend_data); log_debug(LD_REND,"beginning to hunt for addr/port"); base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, @@ -3329,25 +3329,25 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, if (!service) { log_warn(LD_REND, "Couldn't find any service associated with pk %s on " "rendezvous circuit %d; closing.", - serviceid, circ->_base.n_circ_id); + serviceid, circ->base_.n_circ_id); return -1; } matching_ports = smartlist_new(); SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, { - if (conn->_base.port == p->virtual_port) { + if (conn->base_.port == p->virtual_port) { smartlist_add(matching_ports, p); } }); chosen_port = smartlist_choose(matching_ports); smartlist_free(matching_ports); if (chosen_port) { - tor_addr_copy(&conn->_base.addr, &chosen_port->real_addr); - conn->_base.port = chosen_port->real_port; + tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr); + conn->base_.port = chosen_port->real_port; return 0; } log_info(LD_REND, "No virtual port mapping exists for port %d on service %s", - conn->_base.port,serviceid); + conn->base_.port,serviceid); return -1; } diff --git a/src/or/rendservice.h b/src/or/rendservice.h index 0d6eddaee6..1671602348 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -9,8 +9,8 @@ * \brief Header file for rendservice.c. **/ -#ifndef _TOR_RENDSERVICE_H -#define _TOR_RENDSERVICE_H +#ifndef TOR_RENDSERVICE_H +#define TOR_RENDSERVICE_H #include "or.h" diff --git a/src/or/rephist.c b/src/or/rephist.c index b9e7be1fca..e61e599d7e 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -160,7 +160,7 @@ get_link_history(const char *from_id, const char *to_id) /** Helper: free storage held by a single link history entry. */ static void -_free_link_history(void *val) +free_link_history_(void *val) { rephist_total_alloc -= sizeof(link_history_t); tor_free(val); @@ -171,7 +171,7 @@ static void free_or_history(void *_hist) { or_history_t *hist = _hist; - digestmap_free(hist->link_history_map, _free_link_history); + digestmap_free(hist->link_history_map, free_link_history_); rephist_total_alloc -= sizeof(or_history_t); rephist_total_num--; tor_free(hist); @@ -2131,7 +2131,7 @@ rep_hist_exit_stats_term(void) * but works fine for sorting an array of port numbers, which is what we use * it for. */ static int -_compare_int(const void *x, const void *y) +compare_int_(const void *x, const void *y) { return (*(int*)x - *(int*)y); } @@ -2218,7 +2218,7 @@ rep_hist_format_exit_stats(time_t now) other_streams = total_streams; /* Sort the ports; this puts them out of sync with top_bytes, but we * won't be using top_bytes again anyway */ - qsort(top_ports, top_elements, sizeof(int), _compare_int); + qsort(top_ports, top_elements, sizeof(int), compare_int_); for (j = 0; j < top_elements; j++) { cur_port = top_ports[j]; if (exit_bytes_written[cur_port] > 0) { @@ -2440,7 +2440,7 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval) /** Sorting helper: return -1, 1, or 0 based on comparison of two * circ_buffer_stats_t */ static int -_buffer_stats_compare_entries(const void **_a, const void **_b) +buffer_stats_compare_entries_(const void **_a, const void **_b) { const circ_buffer_stats_t *a = *_a, *b = *_b; if (a->processed_cells < b->processed_cells) @@ -2505,7 +2505,7 @@ rep_hist_format_buffer_stats(time_t now) number_of_circuits = smartlist_len(circuits_for_buffer_stats); if (number_of_circuits > 0) { smartlist_sort(circuits_for_buffer_stats, - _buffer_stats_compare_entries); + buffer_stats_compare_entries_); i = 0; SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats, circ_buffer_stats_t *, stat) @@ -2590,7 +2590,7 @@ rep_hist_buffer_stats_write(time_t now) goto done; /* Not ready to write */ /* Add open circuits to the history. */ - for (circ = _circuit_get_global_list(); circ; circ = circ->next) { + for (circ = circuit_get_global_list_(); circ; circ = circ->next) { rep_hist_buffer_stats_add_circ(circ, now); } diff --git a/src/or/rephist.h b/src/or/rephist.h index d47724edb5..28dec8f902 100644 --- a/src/or/rephist.h +++ b/src/or/rephist.h @@ -9,8 +9,8 @@ * \brief Header file for rephist.c. **/ -#ifndef _TOR_REPHIST_H -#define _TOR_REPHIST_H +#ifndef TOR_REPHIST_H +#define TOR_REPHIST_H void rep_hist_init(void); void rep_hist_note_connect_failed(const char* nickname, time_t when); diff --git a/src/or/replaycache.c b/src/or/replaycache.c index 09104a9373..868b21c9b0 100644 --- a/src/or/replaycache.c +++ b/src/or/replaycache.c @@ -23,7 +23,7 @@ replaycache_free(replaycache_t *r) return; } - if (r->digests_seen) digestmap_free(r->digests_seen, _tor_free); + if (r->digests_seen) digestmap_free(r->digests_seen, tor_free_); tor_free(r); } diff --git a/src/or/replaycache.h b/src/or/replaycache.h index 9f3107c513..757102b960 100644 --- a/src/or/replaycache.h +++ b/src/or/replaycache.h @@ -6,8 +6,8 @@ * \brief Header file for replaycache.c. **/ -#ifndef _TOR_REPLAYCACHE_H -#define _TOR_REPLAYCACHE_H +#ifndef TOR_REPLAYCACHE_H +#define TOR_REPLAYCACHE_H typedef struct replaycache_s replaycache_t; diff --git a/src/or/router.c b/src/or/router.c index 926bf26c18..1cac63a3ae 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -970,7 +970,7 @@ router_orport_found_reachable(void) if (!can_reach_or_port && me) { log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from " "the outside. Excellent.%s", - get_options()->_PublishServerDescriptor != NO_DIRINFO ? + get_options()->PublishServerDescriptor_ != NO_DIRINFO ? " Publishing server descriptor." : ""); can_reach_or_port = 1; mark_my_descriptor_dirty("ORPort found reachable"); @@ -1013,9 +1013,9 @@ router_perform_bandwidth_test(int num_circs, time_t now) CIRCUIT_PURPOSE_TESTING))) { /* dump cells_per_circuit drop cells onto this circ */ int i = cells_per_circuit; - if (circ->_base.state != CIRCUIT_STATE_OPEN) + if (circ->base_.state != CIRCUIT_STATE_OPEN) continue; - circ->_base.timestamp_dirty = now; + circ->base_.timestamp_dirty = now; while (i-- > 0) { if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_DROP, @@ -1209,7 +1209,7 @@ decide_if_publishable_server(void) if (options->ClientOnly) return 0; - if (options->_PublishServerDescriptor == NO_DIRINFO) + if (options->PublishServerDescriptor_ == NO_DIRINFO) return 0; if (!server_mode(options)) return 0; @@ -1330,7 +1330,7 @@ router_upload_dir_desc_to_dirservers(int force) extrainfo_t *ei; char *msg; size_t desc_len, extra_len = 0, total_len; - dirinfo_type_t auth = get_options()->_PublishServerDescriptor; + dirinfo_type_t auth = get_options()->PublishServerDescriptor_; ri = router_get_my_routerinfo(); if (!ri) { @@ -1377,14 +1377,14 @@ router_compare_to_my_exit_policy(edge_connection_t *conn) /* make sure it's resolved to something. this way we can't get a 'maybe' below. */ - if (tor_addr_is_null(&conn->_base.addr)) + if (tor_addr_is_null(&conn->base_.addr)) return -1; /* XXXX IPv6 */ - if (tor_addr_family(&conn->_base.addr) != AF_INET) + if (tor_addr_family(&conn->base_.addr) != AF_INET) return -1; - return compare_tor_addr_to_addr_policy(&conn->_base.addr, conn->_base.port, + return compare_tor_addr_to_addr_policy(&conn->base_.addr, conn->base_.port, desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED; } @@ -1796,7 +1796,7 @@ void mark_my_descriptor_dirty(const char *reason) { const or_options_t *options = get_options(); - if (server_mode(options) && options->_PublishServerDescriptor) + if (server_mode(options) && options->PublishServerDescriptor_) log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason); desc_clean_since = 0; if (!desc_dirty_reason) @@ -1928,7 +1928,7 @@ router_new_address_suggestion(const char *suggestion, /* Don't believe anybody who says our IP is, say, 127.0.0.1. */ return; } - if (tor_addr_eq(&d_conn->_base.addr, &addr)) { + if (tor_addr_eq(&d_conn->base_.addr, &addr)) { /* Don't believe anybody who says our IP is their IP. */ log_debug(LD_DIR, "A directory server told us our IP address is %s, " "but he's just reporting his own IP address. Ignoring.", @@ -1944,7 +1944,7 @@ router_new_address_suggestion(const char *suggestion, "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV", suggestion); log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr, - d_conn->_base.address); + d_conn->base_.address); ip_address_changed(0); tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor() will fetch it */ diff --git a/src/or/router.h b/src/or/router.h index 39640855e0..7ab057706d 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -9,8 +9,8 @@ * \brief Header file for router.c. **/ -#ifndef _TOR_ROUTER_H -#define _TOR_ROUTER_H +#ifndef TOR_ROUTER_H +#define TOR_ROUTER_H crypto_pk_t *get_onion_key(void); time_t get_onion_key_set_at(void); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 9537331c64..1cefef9891 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -13,13 +13,14 @@ #define ROUTERLIST_PRIVATE #include "or.h" -#include "circuitbuild.h" +#include "circuitstats.h" #include "config.h" #include "connection.h" #include "control.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" +#include "entrynodes.h" #include "geoip.h" #include "hibernate.h" #include "main.h" @@ -654,7 +655,7 @@ signed_desc_append_to_journal(signed_descriptor_t *desc, * signed_descriptor_t* in *<b>a</b> is older, the same age as, or newer than * the signed_descriptor_t* in *<b>b</b>. */ static int -_compare_signed_descriptors_by_age(const void **_a, const void **_b) +compare_signed_descriptors_by_age_(const void **_a, const void **_b) { const signed_descriptor_t *r1 = *_a, *r2 = *_b; return (int)(r1->published_on - r2->published_on); @@ -727,7 +728,7 @@ router_rebuild_store(int flags, desc_store_t *store) smartlist_add(signed_descriptors, &ri->cache_info)); } - smartlist_sort(signed_descriptors, _compare_signed_descriptors_by_age); + smartlist_sort(signed_descriptors, compare_signed_descriptors_by_age_); /* Now, add the appropriate members to chunk_list */ SMARTLIST_FOREACH_BEGIN(signed_descriptors, signed_descriptor_t *, sd) { @@ -946,7 +947,7 @@ router_pick_directory_server(dirinfo_type_t type, int flags) { const routerstatus_t *choice; if (get_options()->PreferTunneledDirConns) - flags |= _PDS_PREFER_TUNNELED_DIR_CONNS; + flags |= PDS_PREFER_TUNNELED_DIR_CONNS_; if (!routerlist) return NULL; @@ -1053,7 +1054,7 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags) const routerstatus_t *choice; int busy = 0; if (get_options()->PreferTunneledDirConns) - flags |= _PDS_PREFER_TUNNELED_DIR_CONNS; + flags |= PDS_PREFER_TUNNELED_DIR_CONNS_; choice = router_pick_trusteddirserver_impl(type, flags, &busy); if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS)) @@ -1080,7 +1081,7 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags) * routerlist. Arguments are as for router_pick_directory_server(), except * that RETRY_IF_NO_SERVERS is ignored, and: * - * If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers + * If the PDS_PREFER_TUNNELED_DIR_CONNS_ flag is set, prefer directory servers * that we can use with BEGINDIR. */ static const routerstatus_t * @@ -1095,7 +1096,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags) const networkstatus_t *consensus = networkstatus_get_latest_consensus(); int requireother = ! (flags & PDS_ALLOW_SELF); int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL); - int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS); + int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_); int try_excluding = 1, n_excluded = 0; if (!consensus) @@ -1210,7 +1211,7 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags, time_t now = time(NULL); const int requireother = ! (flags & PDS_ALLOW_SELF); const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL); - const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS); + const int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_); const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH); const int no_microdesc_fetching =(flags & PDS_NO_EXISTING_MICRODESC_FETCH); int n_busy = 0; @@ -2451,7 +2452,7 @@ signed_descriptor_from_routerinfo(routerinfo_t *ri) /** Helper: free the storage held by the extrainfo_t in <b>e</b>. */ static void -_extrainfo_free(void *e) +extrainfo_free_(void *e) { extrainfo_free(e); } @@ -2465,7 +2466,7 @@ routerlist_free(routerlist_t *rl) rimap_free(rl->identity_map, NULL); sdmap_free(rl->desc_digest_map, NULL); sdmap_free(rl->desc_by_eid_map, NULL); - eimap_free(rl->extra_info_map, _extrainfo_free); + eimap_free(rl->extra_info_map, extrainfo_free_); SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, routerinfo_free(r)); SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd, @@ -2507,7 +2508,7 @@ dump_routerlist_mem_usage(int severity) * <b>ri</b>. Return the index of <b>ri</b> in <b>sl</b>, or -1 if <b>ri</b> * is not in <b>sl</b>. */ static INLINE int -_routerlist_find_elt(smartlist_t *sl, void *ri, int idx) +routerlist_find_elt_(smartlist_t *sl, void *ri, int idx) { if (idx < 0) { idx = -1; @@ -2804,7 +2805,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, ri_old->cache_info.routerlist_index = -1; ri_new->cache_info.routerlist_index = idx; /* Check that ri_old is not in rl->routers anymore: */ - tor_assert( _routerlist_find_elt(rl->routers, ri_old, -1) == -1 ); + tor_assert( routerlist_find_elt_(rl->routers, ri_old, -1) == -1 ); } else { log_warn(LD_BUG, "Appending entry from routerlist_replace."); routerlist_insert(rl, ri_new); @@ -3166,7 +3167,7 @@ router_add_extrainfo_to_routerlist(extrainfo_t *ei, const char **msg, * signed_descriptor_t* in *<b>a</b> has an identity digest preceding, equal * to, or later than that of *<b>b</b>. */ static int -_compare_old_routers_by_identity(const void **_a, const void **_b) +compare_old_routers_by_identity_(const void **_a, const void **_b) { int i; const signed_descriptor_t *r1 = *_a, *r2 = *_b; @@ -3186,7 +3187,7 @@ struct duration_idx_t { /** Sorting helper: compare two duration_idx_t by their duration. */ static int -_compare_duration_idx(const void *_d1, const void *_d2) +compare_duration_idx_(const void *_d1, const void *_d2) { const struct duration_idx_t *d1 = _d1; const struct duration_idx_t *d2 = _d2; @@ -3263,7 +3264,7 @@ routerlist_remove_old_cached_routers_with_id(time_t now, * the duration of liveness, and remove the ones we're not already going to * remove based on how long they were alive. **/ - qsort(lifespans, n, sizeof(struct duration_idx_t), _compare_duration_idx); + qsort(lifespans, n, sizeof(struct duration_idx_t), compare_duration_idx_); for (i = 0; i < n && n_rmv < n_extra; ++i) { if (!must_keep[lifespans[i].idx-lo] && !lifespans[i].old) { rmv[lifespans[i].idx-lo] = 1; @@ -3417,7 +3418,7 @@ routerlist_remove_old_routers(void) goto done; /* Sort by identity, then fix indices. */ - smartlist_sort(routerlist->old_routers, _compare_old_routers_by_identity); + smartlist_sort(routerlist->old_routers, compare_old_routers_by_identity_); /* Fix indices. */ for (i = 0; i < smartlist_len(routerlist->old_routers); ++i) { signed_descriptor_t *r = smartlist_get(routerlist->old_routers, i); @@ -4775,7 +4776,7 @@ esc_router_info(const routerinfo_t *router) /** Helper for sorting: compare two routerinfos by their identity * digest. */ static int -_compare_routerinfo_by_id_digest(const void **a, const void **b) +compare_routerinfo_by_id_digest_(const void **a, const void **b) { routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; return fast_memcmp(first->cache_info.identity_digest, @@ -4787,7 +4788,7 @@ _compare_routerinfo_by_id_digest(const void **a, const void **b) void routers_sort_by_identity(smartlist_t *routers) { - smartlist_sort(routers, _compare_routerinfo_by_id_digest); + smartlist_sort(routers, compare_routerinfo_by_id_digest_); } /** Called when we change a node set, or when we reload the geoip IPv4 list: @@ -4806,8 +4807,8 @@ refresh_all_country_info(void) routerset_refresh_countries(options->ExcludeNodes); if (options->ExcludeExitNodes) routerset_refresh_countries(options->ExcludeExitNodes); - if (options->_ExcludeExitNodesUnion) - routerset_refresh_countries(options->_ExcludeExitNodesUnion); + if (options->ExcludeExitNodesUnion_) + routerset_refresh_countries(options->ExcludeExitNodesUnion_); nodelist_refresh_countries(); } diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 58143010b3..c8381996d2 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -8,8 +8,8 @@ * \brief Header file for routerlist.c. **/ -#ifndef _TOR_ROUTERLIST_H -#define _TOR_ROUTERLIST_H +#ifndef TOR_ROUTERLIST_H +#define TOR_ROUTERLIST_H int get_n_authorities(dirinfo_type_t type); int trusted_dirs_reload_certs(void); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 8502ff2bf6..8d6cd1c7fa 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -11,7 +11,7 @@ #include "or.h" #include "config.h" -#include "circuitbuild.h" +#include "circuitstats.h" #include "dirserv.h" #include "dirvote.h" #include "policies.h" @@ -29,8 +29,8 @@ /****************************************************************************/ /** Enumeration of possible token types. The ones starting with K_ correspond - * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF - * is an end-of-file marker, and _NIL is used to encode not-a-token. + * to directory 'keywords'. ERR_ is an error in the tokenizing process, EOF_ + * is an end-of-file marker, and NIL_ is used to encode not-a-token. */ typedef enum { K_ACCEPT = 0, @@ -131,7 +131,7 @@ typedef enum { A_PURPOSE, A_LAST_LISTED, - _A_UNKNOWN, + A_UNKNOWN_, R_RENDEZVOUS_SERVICE_DESCRIPTOR, R_VERSION, @@ -152,13 +152,13 @@ typedef enum { C_DESCRIPTOR_COOKIE, C_CLIENT_KEY, - _ERR, - _EOF, - _NIL + ERR_, + EOF_, + NIL_ } directory_keyword; #define MIN_ANNOTATION A_PURPOSE -#define MAX_ANNOTATION _A_UNKNOWN +#define MAX_ANNOTATION A_UNKNOWN_ /** Structure to hold a single directory token. * @@ -181,7 +181,7 @@ typedef struct directory_token_t { crypto_pk_t *key; /**< For public keys only. Heap-allocated. */ - char *error; /**< For _ERR tokens only. */ + char *error; /**< For ERR_ tokens only. */ } directory_token_t; /* ********************************************************************** */ @@ -235,7 +235,7 @@ typedef struct token_rule_t { */ /** Appears to indicate the end of a table. */ -#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 } +#define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 } /** An item with no restrictions: used for obsolete document types */ #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 } /** An item with no restrictions on multiplicity or location. */ @@ -549,10 +549,10 @@ static int router_get_hashes_impl(const char *s, size_t s_len, static void token_clear(directory_token_t *tok); static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k); static smartlist_t *find_all_exitpolicy(smartlist_t *s); -static directory_token_t *_find_by_keyword(smartlist_t *s, +static directory_token_t *find_by_keyword_(smartlist_t *s, directory_keyword keyword, const char *keyword_str); -#define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword) +#define find_by_keyword(s, keyword) find_by_keyword_((s), (keyword), #keyword) static directory_token_t *find_opt_by_keyword(smartlist_t *s, directory_keyword keyword); @@ -2263,7 +2263,7 @@ compare_routerstatus_entries(const void **_a, const void **_b) /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */ static void -_free_duplicate_routerstatus_entry(void *e) +free_duplicate_routerstatus_entry_(void *e) { log_warn(LD_DIR, "Network-status has two entries for the same router. " @@ -2404,7 +2404,7 @@ networkstatus_v2_parse_from_string(const char *s) } smartlist_sort(ns->entries, compare_routerstatus_entries); smartlist_uniq(ns->entries, compare_routerstatus_entries, - _free_duplicate_routerstatus_entry); + free_duplicate_routerstatus_entry_); if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) { log_warn(LD_DIR, "Error tokenizing network-status footer."); @@ -3661,7 +3661,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action) eos = cp + strlen(cp); area = memarea_new(); tok = get_next_token(area, &cp, eos, routerdesc_token_table); - if (tok->tp == _ERR) { + if (tok->tp == ERR_) { log_warn(LD_DIR, "Error reading address policy: %s", tok->error); goto err; } @@ -3814,14 +3814,14 @@ token_clear(directory_token_t *tok) STMT_BEGIN \ if (tok) token_clear(tok); \ tok = ALLOC_ZERO(sizeof(directory_token_t)); \ - tok->tp = _ERR; \ + tok->tp = ERR_; \ tok->error = STRDUP(msg); \ goto done_tokenizing; \ STMT_END /** Helper: make sure that the token <b>tok</b> with keyword <b>kwd</b> obeys * the object syntax of <b>o_syn</b>. Allocate all storage in <b>area</b>. - * Return <b>tok</b> on success, or a new _ERR token if the token didn't + * Return <b>tok</b> on success, or a new ERR_ token if the token didn't * conform to the syntax we wanted. **/ static INLINE directory_token_t * @@ -3940,7 +3940,7 @@ get_next_token(memarea_t *area, tor_assert(area); tok = ALLOC_ZERO(sizeof(directory_token_t)); - tok->tp = _ERR; + tok->tp = ERR_; /* Set *s to first token, eol to end-of-line, next to after first token */ *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */ @@ -3997,10 +3997,10 @@ get_next_token(memarea_t *area, } } - if (tok->tp == _ERR) { + if (tok->tp == ERR_) { /* No keyword matched; call it an "K_opt" or "A_unrecognized" */ if (**s == '@') - tok->tp = _A_UNKNOWN; + tok->tp = A_UNKNOWN_; else tok->tp = K_OPT; tok->args = ALLOC(sizeof(char*)); @@ -4090,7 +4090,7 @@ tokenize_string(memarea_t *area, { const char **s; directory_token_t *tok = NULL; - int counts[_NIL]; + int counts[NIL_]; int i; int first_nonannotation; int prev_len = smartlist_len(out); @@ -4099,14 +4099,14 @@ tokenize_string(memarea_t *area, s = &start; if (!end) end = start+strlen(start); - for (i = 0; i < _NIL; ++i) + for (i = 0; i < NIL_; ++i) counts[i] = 0; SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]); - while (*s < end && (!tok || tok->tp != _EOF)) { + while (*s < end && (!tok || tok->tp != EOF_)) { tok = get_next_token(area, s, end, table); - if (tok->tp == _ERR) { + if (tok->tp == ERR_) { log_warn(LD_DIR, "parse error: %s", tok->error); token_clear(tok); return -1; @@ -4196,7 +4196,7 @@ find_opt_by_keyword(smartlist_t *s, directory_keyword keyword) * with an assert if no such keyword is found. */ static directory_token_t * -_find_by_keyword(smartlist_t *s, directory_keyword keyword, +find_by_keyword_(smartlist_t *s, directory_keyword keyword, const char *keyword_as_string) { directory_token_t *tok = find_opt_by_keyword(s, keyword); @@ -4695,7 +4695,7 @@ tor_version_same_series(tor_version_t *a, tor_version_t *b) * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent. * Used to sort a list of versions. */ static int -_compare_tor_version_str_ptr(const void **_a, const void **_b) +compare_tor_version_str_ptr_(const void **_a, const void **_b) { const char *a = *_a, *b = *_b; int ca, cb; @@ -4719,10 +4719,10 @@ _compare_tor_version_str_ptr(const void **_a, const void **_b) void sort_version_list(smartlist_t *versions, int remove_duplicates) { - smartlist_sort(versions, _compare_tor_version_str_ptr); + smartlist_sort(versions, compare_tor_version_str_ptr_); if (remove_duplicates) - smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free); + smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_); } /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>, diff --git a/src/or/routerparse.h b/src/or/routerparse.h index c6382a7f6b..6cf94c1c2f 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -9,8 +9,8 @@ * \brief Header file for routerparse.c. **/ -#ifndef _TOR_ROUTERPARSE_H -#define _TOR_ROUTERPARSE_H +#ifndef TOR_ROUTERPARSE_H +#define TOR_ROUTERPARSE_H int router_get_router_hash(const char *s, size_t s_len, char *digest); int router_get_dir_hash(const char *s, char *digest); diff --git a/src/or/statefile.c b/src/or/statefile.c index 001c4c3c4b..beb9cf81ba 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -5,16 +5,17 @@ /* See LICENSE for licensing information */ #include "or.h" -#include "circuitbuild.h" +#include "circuitstats.h" #include "config.h" #include "confparse.h" +#include "entrynodes.h" #include "hibernate.h" #include "rephist.h" #include "router.h" #include "statefile.h" /** A list of state-file "abbreviations," for compatibility. */ -static config_abbrev_t _state_abbrevs[] = { +static config_abbrev_t state_abbrevs_[] = { { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 }, { "HelperNode", "EntryGuard", 0, 0 }, { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 }, @@ -34,7 +35,7 @@ static config_abbrev_t _state_abbrevs[] = { VAR(#member, conftype, member, initvalue) /** Array of "state" variables saved to the ~/.tor/state file. */ -static config_var_t _state_vars[] = { +static config_var_t state_vars_[] = { /* Remember to document these in state-contents.txt ! */ V(AccountingBytesReadInInterval, MEMUNIT, NULL), @@ -104,9 +105,9 @@ static config_var_t state_extra_var = { static const config_format_t state_format = { sizeof(or_state_t), OR_STATE_MAGIC, - STRUCT_OFFSET(or_state_t, _magic), - _state_abbrevs, - _state_vars, + STRUCT_OFFSET(or_state_t, magic_), + state_abbrevs_, + state_vars_, (validate_fn_t)or_state_validate, &state_extra_var, }; @@ -302,7 +303,7 @@ or_state_load(void) goto done; } new_state = tor_malloc_zero(sizeof(or_state_t)); - new_state->_magic = OR_STATE_MAGIC; + new_state->magic_ = OR_STATE_MAGIC; config_init(&state_format, new_state); if (contents) { config_line_t *lines=NULL; @@ -339,7 +340,7 @@ or_state_load(void) config_free(&state_format, new_state); new_state = tor_malloc_zero(sizeof(or_state_t)); - new_state->_magic = OR_STATE_MAGIC; + new_state->magic_ = OR_STATE_MAGIC; config_init(&state_format, new_state); } else if (contents) { log_info(LD_GENERAL, "Loaded state from \"%s\"", fname); diff --git a/src/or/status.c b/src/or/status.c index 04cd96eed5..fc01d0a242 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -21,7 +21,7 @@ count_circuits(void) circuit_t *circ; int nr=0; - for (circ = _circuit_get_global_list(); circ; circ = circ->next) + for (circ = circuit_get_global_list_(); circ; circ = circ->next) nr++; return nr; diff --git a/src/or/status.h b/src/or/status.h index 189ac789e1..de49d751c3 100644 --- a/src/or/status.h +++ b/src/or/status.h @@ -1,8 +1,8 @@ /* Copyright (c) 2010-2012, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#ifndef _TOR_STATUS_H -#define _TOR_STATUS_H +#ifndef TOR_STATUS_H +#define TOR_STATUS_H int log_heartbeat(time_t now); diff --git a/src/or/transports.c b/src/or/transports.c index 1586213367..e1ed24dbf4 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -1188,7 +1188,7 @@ create_managed_proxy_environment(const managed_proxy_t *mp) SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) { set_environment_variable_in_smartlist(merged_env_vars, env_var, - _tor_free, 1); + tor_free_, 1); } SMARTLIST_FOREACH_END(env_var); env = process_environment_make(merged_env_vars); @@ -1292,7 +1292,7 @@ free_execve_args(char **arg) char **tmp = arg; while (*tmp) /* use the fact that the last element of the array is a NULL pointer to know when to stop freeing */ - _tor_free(*tmp++); + tor_free_(*tmp++); tor_free(arg); } |