LCOV - code coverage report
Current view: top level - feature/relay - onion_queue.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 69 117 59.0 %
Date: 2021-11-24 03:28:48 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /* Copyright (c) 2001 Matej Pfajfar.
       2             :  * Copyright (c) 2001-2004, Roger Dingledine.
       3             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       4             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       5             : /* See LICENSE for licensing information */
       6             : 
       7             : /**
       8             :  * \file onion_queue.c
       9             :  * \brief Functions to queue create cells for processing.
      10             :  *
      11             :  * Relays invoke these functions when they receive a CREATE or EXTEND
      12             :  * cell in command.c or relay.c, in order to queue the pending request.
      13             :  * They also invoke them from cpuworker.c, which handles dispatching
      14             :  * onionskin requests to different worker threads.
      15             :  *
      16             :  * <br>
      17             :  *
      18             :  * This module also handles:
      19             :  *  <ul>
      20             :  *  <li> Queueing incoming onionskins on the relay side before passing
      21             :  *      them to worker threads.
      22             :  *   <li>Expiring onionskins on the relay side if they have waited for
      23             :  *     too long.
      24             :  * </ul>
      25             :  **/
      26             : 
      27             : #include "core/or/or.h"
      28             : 
      29             : #include "feature/relay/onion_queue.h"
      30             : 
      31             : #include "app/config/config.h"
      32             : #include "core/mainloop/cpuworker.h"
      33             : #include "core/or/circuitlist.h"
      34             : #include "core/or/onion.h"
      35             : #include "feature/nodelist/networkstatus.h"
      36             : #include "feature/stats/rephist.h"
      37             : 
      38             : #include "core/or/or_circuit_st.h"
      39             : 
      40             : /** Type for a linked list of circuits that are waiting for a free CPU worker
      41             :  * to process a waiting onion handshake. */
      42             : typedef struct onion_queue_t {
      43             :   TOR_TAILQ_ENTRY(onion_queue_t) next;
      44             :   or_circuit_t *circ;
      45             :   uint16_t handshake_type;
      46             :   create_cell_t *onionskin;
      47             :   time_t when_added;
      48             : } onion_queue_t;
      49             : 
      50             : /** 5 seconds on the onion queue til we just send back a destroy */
      51             : #define ONIONQUEUE_WAIT_CUTOFF 5
      52             : 
      53             : TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t);
      54             : typedef struct onion_queue_head_t onion_queue_head_t;
      55             : 
      56             : /** Array of queues of circuits waiting for CPU workers. An element is NULL
      57             :  * if that queue is empty.*/
      58             : static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
      59             : { TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
      60             :   TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
      61             :   TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
      62             : };
      63             : 
      64             : /** Number of entries of each type currently in each element of ol_list[]. */
      65             : static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
      66             : 
      67             : static int num_ntors_per_tap(void);
      68             : static void onion_queue_entry_remove(onion_queue_t *victim);
      69             : 
      70             : /* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN.
      71             :  *
      72             :  * (By which I think I meant, "make sure that no
      73             :  * X_ONIONSKIN_CHALLENGE/REPLY_LEN is greater than
      74             :  * MAX_ONIONSKIN_CHALLENGE/REPLY_LEN."  Also, make sure that we can pass
      75             :  * over-large values via EXTEND2/EXTENDED2, for future-compatibility.*/
      76             : 
      77             : /** Return true iff we have room to queue another onionskin of type
      78             :  * <b>type</b>. */
      79             : static int
      80           2 : have_room_for_onionskin(uint16_t type)
      81             : {
      82           2 :   const or_options_t *options = get_options();
      83           2 :   int num_cpus;
      84           2 :   uint64_t tap_usec, ntor_usec;
      85           2 :   uint64_t ntor_during_tap_usec, tap_during_ntor_usec;
      86             : 
      87             :   /* If we've got fewer than 50 entries, we always have room for one more. */
      88           2 :   if (ol_entries[type] < 50)
      89             :     return 1;
      90           0 :   num_cpus = get_num_cpus(options);
      91             :   /* Compute how many microseconds we'd expect to need to clear all
      92             :    * onionskins in various combinations of the queues. */
      93             : 
      94             :   /* How long would it take to process all the TAP cells in the queue? */
      95           0 :   tap_usec  = estimated_usec_for_onionskins(
      96           0 :                                     ol_entries[ONION_HANDSHAKE_TYPE_TAP],
      97           0 :                                     ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
      98             : 
      99             :   /* How long would it take to process all the NTor cells in the queue? */
     100           0 :   ntor_usec = estimated_usec_for_onionskins(
     101           0 :                                     ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
     102             :                                     ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
     103             : 
     104             :   /* How long would it take to process the tap cells that we expect to
     105             :    * process while draining the ntor queue? */
     106           0 :   tap_during_ntor_usec  = estimated_usec_for_onionskins(
     107           0 :     MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
     108             :         ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()),
     109             :                                     ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
     110             : 
     111             :   /* How long would it take to process the ntor cells that we expect to
     112             :    * process while draining the tap queue? */
     113           0 :   ntor_during_tap_usec  = estimated_usec_for_onionskins(
     114           0 :     MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
     115             :         ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()),
     116             :                                     ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
     117             : 
     118             :   /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
     119             :    * this. */
     120           0 :   if (type == ONION_HANDSHAKE_TYPE_NTOR &&
     121           0 :       (ntor_usec + tap_during_ntor_usec) / 1000 >
     122           0 :        (uint64_t)options->MaxOnionQueueDelay)
     123             :     return 0;
     124             : 
     125           0 :   if (type == ONION_HANDSHAKE_TYPE_TAP &&
     126           0 :       (tap_usec + ntor_during_tap_usec) / 1000 >
     127           0 :        (uint64_t)options->MaxOnionQueueDelay)
     128             :     return 0;
     129             : 
     130             :   /* If we support the ntor handshake, then don't let TAP handshakes use
     131             :    * more than 2/3 of the space on the queue. */
     132           0 :   if (type == ONION_HANDSHAKE_TYPE_TAP &&
     133           0 :       tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3)
     134           0 :     return 0;
     135             : 
     136             :   return 1;
     137             : }
     138             : 
     139             : /** Add <b>circ</b> to the end of ol_list and return 0, except
     140             :  * if ol_list is too long, in which case do nothing and return -1.
     141             :  */
     142             : int
     143           2 : onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
     144             : {
     145           2 :   onion_queue_t *tmp;
     146           2 :   time_t now = time(NULL);
     147             : 
     148           2 :   if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
     149             :     /* LCOV_EXCL_START
     150             :      * We should have rejected this far before this point */
     151             :     log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
     152             :              onionskin->handshake_type);
     153             :     return -1;
     154             :     /* LCOV_EXCL_STOP */
     155             :   }
     156             : 
     157           2 :   tmp = tor_malloc_zero(sizeof(onion_queue_t));
     158           2 :   tmp->circ = circ;
     159           2 :   tmp->handshake_type = onionskin->handshake_type;
     160           2 :   tmp->onionskin = onionskin;
     161           2 :   tmp->when_added = now;
     162             : 
     163           2 :   if (!have_room_for_onionskin(onionskin->handshake_type)) {
     164             : #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60)
     165           0 :     static ratelim_t last_warned =
     166             :       RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
     167           0 :     rep_hist_note_circuit_handshake_dropped(onionskin->handshake_type);
     168           0 :     if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
     169           0 :       char *m;
     170             :       /* Note this ntor onionskin drop as an overload */
     171           0 :       rep_hist_note_overload(OVERLOAD_GENERAL);
     172           0 :       if ((m = rate_limit_log(&last_warned, approx_time()))) {
     173           0 :         log_warn(LD_GENERAL,
     174             :                  "Your computer is too slow to handle this many circuit "
     175             :                  "creation requests! Please consider using the "
     176             :                  "MaxAdvertisedBandwidth config option or choosing a more "
     177             :                  "restricted exit policy.%s",
     178             :                  m);
     179           0 :         tor_free(m);
     180             :       }
     181             :     }
     182           0 :     tor_free(tmp);
     183           0 :     return -1;
     184             :   }
     185             : 
     186           2 :   ++ol_entries[onionskin->handshake_type];
     187           3 :   log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.",
     188             :     onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
     189             :     ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
     190             :     ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
     191             : 
     192           2 :   circ->onionqueue_entry = tmp;
     193           2 :   TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
     194             : 
     195             :   /* cull elderly requests. */
     196           2 :   while (1) {
     197           2 :     onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
     198           2 :     if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
     199             :       break;
     200             : 
     201           0 :     circ = head->circ;
     202           0 :     circ->onionqueue_entry = NULL;
     203           0 :     onion_queue_entry_remove(head);
     204           0 :     log_info(LD_CIRC,
     205             :              "Circuit create request is too old; canceling due to overload.");
     206           0 :     if (! TO_CIRCUIT(circ)->marked_for_close) {
     207           0 :       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
     208             :     }
     209             :   }
     210             :   return 0;
     211             : }
     212             : 
     213             : /** Return a fairness parameter, to prefer processing NTOR style
     214             :  * handshakes but still slowly drain the TAP queue so we don't starve
     215             :  * it entirely. */
     216             : static int
     217           1 : num_ntors_per_tap(void)
     218             : {
     219             : #define DEFAULT_NUM_NTORS_PER_TAP 10
     220             : #define MIN_NUM_NTORS_PER_TAP 1
     221             : #define MAX_NUM_NTORS_PER_TAP 100000
     222             : 
     223           1 :   int result = networkstatus_get_param(NULL, "NumNTorsPerTAP",
     224             :                                        DEFAULT_NUM_NTORS_PER_TAP,
     225             :                                        MIN_NUM_NTORS_PER_TAP,
     226             :                                        MAX_NUM_NTORS_PER_TAP);
     227           1 :   tor_assert(result > 0);
     228           1 :   return result;
     229             : }
     230             : 
     231             : /** Choose which onion queue we'll pull from next. If one is empty choose
     232             :  * the other; if they both have elements, load balance across them but
     233             :  * favoring NTOR. */
     234             : static uint16_t
     235           1 : decide_next_handshake_type(void)
     236             : {
     237             :   /* The number of times we've chosen ntor lately when both were available. */
     238           1 :   static int recently_chosen_ntors = 0;
     239             : 
     240           1 :   if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR])
     241             :     return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */
     242             : 
     243           1 :   if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) {
     244             : 
     245             :     /* Nick wants us to prioritize new tap requests when there aren't
     246             :      * any in the queue and we've processed k ntor cells since the last
     247             :      * tap cell. This strategy is maybe a good idea, since it starves tap
     248             :      * less in the case where tap is rare, or maybe a poor idea, since it
     249             :      * makes the new tap cell unfairly jump in front of ntor cells that
     250             :      * got here first. In any case this edge case will only become relevant
     251             :      * once tap is rare. We should reevaluate whether we like this decision
     252             :      * once tap gets more rare. */
     253           0 :     if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
     254           0 :         recently_chosen_ntors <= num_ntors_per_tap())
     255           0 :       ++recently_chosen_ntors;
     256             : 
     257           0 :     return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */
     258             :   }
     259             : 
     260             :   /* They both have something queued. Pick ntor if we haven't done that
     261             :    * too much lately. */
     262           1 :   if (++recently_chosen_ntors <= num_ntors_per_tap()) {
     263             :     return ONION_HANDSHAKE_TYPE_NTOR;
     264             :   }
     265             : 
     266             :   /* Else, it's time to let tap have its turn. */
     267           0 :   recently_chosen_ntors = 0;
     268           0 :   return ONION_HANDSHAKE_TYPE_TAP;
     269             : }
     270             : 
     271             : /** Remove the highest priority item from ol_list[] and return it, or
     272             :  * return NULL if the lists are empty.
     273             :  */
     274             : or_circuit_t *
     275           1 : onion_next_task(create_cell_t **onionskin_out)
     276             : {
     277           1 :   or_circuit_t *circ;
     278           1 :   uint16_t handshake_to_choose = decide_next_handshake_type();
     279           1 :   onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[handshake_to_choose]);
     280             : 
     281           1 :   if (!head)
     282             :     return NULL; /* no onions pending, we're done */
     283             : 
     284           1 :   tor_assert(head->circ);
     285           1 :   tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE);
     286             : //  tor_assert(head->circ->p_chan); /* make sure it's still valid */
     287             : /* XXX I only commented out the above line to make the unit tests
     288             :  * more manageable. That's probably not good long-term. -RD */
     289           1 :   circ = head->circ;
     290           1 :   if (head->onionskin)
     291           1 :     --ol_entries[head->handshake_type];
     292           1 :   log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.",
     293             :     head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
     294             :     ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
     295             :     ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
     296             : 
     297           1 :   *onionskin_out = head->onionskin;
     298           1 :   head->onionskin = NULL; /* prevent free. */
     299           1 :   circ->onionqueue_entry = NULL;
     300           1 :   onion_queue_entry_remove(head);
     301           1 :   return circ;
     302             : }
     303             : 
     304             : /** Return the number of <b>handshake_type</b>-style create requests pending.
     305             :  */
     306             : int
     307           8 : onion_num_pending(uint16_t handshake_type)
     308             : {
     309           8 :   return ol_entries[handshake_type];
     310             : }
     311             : 
     312             : /** Go through ol_list, find the onion_queue_t element which points to
     313             :  * circ, remove and free that element. Leave circ itself alone.
     314             :  */
     315             : void
     316           0 : onion_pending_remove(or_circuit_t *circ)
     317             : {
     318           0 :   onion_queue_t *victim;
     319             : 
     320           0 :   if (!circ)
     321             :     return;
     322             : 
     323           0 :   victim = circ->onionqueue_entry;
     324           0 :   if (victim)
     325           0 :     onion_queue_entry_remove(victim);
     326             : 
     327           0 :   cpuworker_cancel_circ_handshake(circ);
     328             : }
     329             : 
     330             : /** Remove a queue entry <b>victim</b> from the queue, unlinking it from
     331             :  * its circuit and freeing it and any structures it owns.*/
     332             : static void
     333           2 : onion_queue_entry_remove(onion_queue_t *victim)
     334             : {
     335           2 :   if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
     336             :     /* LCOV_EXCL_START
     337             :      * We should have rejected this far before this point */
     338             :     log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
     339             :              victim->handshake_type);
     340             :     /* XXX leaks */
     341             :     return;
     342             :     /* LCOV_EXCL_STOP */
     343             :   }
     344             : 
     345           2 :   TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
     346             : 
     347           2 :   if (victim->circ)
     348           2 :     victim->circ->onionqueue_entry = NULL;
     349             : 
     350           2 :   if (victim->onionskin)
     351           1 :     --ol_entries[victim->handshake_type];
     352             : 
     353           2 :   tor_free(victim->onionskin);
     354           2 :   tor_free(victim);
     355             : }
     356             : 
     357             : /** Remove all circuits from the pending list.  Called from tor_free_all. */
     358             : void
     359         236 : clear_pending_onions(void)
     360             : {
     361         236 :   onion_queue_t *victim, *next;
     362         236 :   int i;
     363         944 :   for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
     364         709 :     for (victim = TOR_TAILQ_FIRST(&ol_list[i]); victim; victim = next) {
     365           1 :       next = TOR_TAILQ_NEXT(victim,next);
     366           1 :       onion_queue_entry_remove(victim);
     367             :     }
     368         708 :     tor_assert(TOR_TAILQ_EMPTY(&ol_list[i]));
     369             :   }
     370         236 :   memset(ol_entries, 0, sizeof(ol_entries));
     371         236 : }

Generated by: LCOV version 1.14