Tor  0.4.7.0-alpha-dev
predict_ports.c
Go to the documentation of this file.
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2  * Copyright (c) 2007-2021, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
4 
5 /**
6  * \file predict_ports.c
7  * \brief Remember what ports we've needed so we can have circuits ready.
8  *
9  * Predicted ports are used by clients to remember how long it's been
10  * since they opened an exit connection to each given target
11  * port. Clients use this information in order to try to keep circuits
12  * open to exit nodes that can connect to the ports that they care
13  * about. (The predicted ports mechanism also handles predicted circuit
14  * usage that _isn't_ port-specific, such as resolves, internal circuits,
15  * and so on.)
16  **/
17 
18 #include "core/or/or.h"
19 
20 #include "app/config/config.h"
21 #include "core/or/channelpadding.h"
22 #include "core/or/circuituse.h"
24 #include "feature/relay/selftest.h"
26 #include "lib/container/bitarray.h"
27 #include "lib/time/tvdiff.h"
28 
29 static size_t predicted_ports_total_alloc = 0;
30 
31 static void predicted_ports_alloc(void);
32 
33 /** A single predicted port: used to remember which ports we've made
34  * connections to, so that we can try to keep making circuits that can handle
35  * those ports. */
36 typedef struct predicted_port_t {
37  /** The port we connected to */
38  uint16_t port;
39  /** The time at which we last used it */
40  time_t time;
42 
43 /** A list of port numbers that have been used recently. */
45 /** How long do we keep predicting circuits? */
46 static time_t prediction_timeout=0;
47 /** When was the last time we added a prediction entry (HS or port) */
48 static time_t last_prediction_add_time=0;
49 
50 /**
51  * How much time left until we stop predicting circuits?
52  */
53 int
55 {
56  time_t seconds_waited;
57  time_t seconds_left;
58 
59  /* Protect against overflow of return value. This can happen if the clock
60  * jumps backwards in time. Update the last prediction time (aka last
61  * active time) to prevent it. This update is preferable to using monotonic
62  * time because it prevents clock jumps into the past from simply causing
63  * very long idle timeouts while the monotonic time stands still. */
64  seconds_waited = time_diff(last_prediction_add_time, now);
65  if (seconds_waited == TIME_MAX) {
67  seconds_waited = 0;
68  }
69 
70  /* Protect against underflow of the return value. This can happen for very
71  * large periods of inactivity/system sleep. */
72  if (seconds_waited > prediction_timeout)
73  return 0;
74 
75  seconds_left = time_diff(seconds_waited, prediction_timeout);
76  if (BUG(seconds_left == TIME_MAX))
77  return INT_MAX;
78 
79  return (int)(seconds_left);
80 }
81 
82 /** We just got an application request for a connection with
83  * port <b>port</b>. Remember it for the future, so we can keep
84  * some circuits open that will exit to this port.
85  */
86 static void
87 add_predicted_port(time_t now, uint16_t port)
88 {
89  predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t));
90 
91  // If the list is empty, re-randomize predicted ports lifetime
92  if (!any_predicted_circuits(now)) {
95  }
96 
98 
99  log_info(LD_CIRC,
100  "New port prediction added. Will continue predictive circ building "
101  "for %d more seconds.",
103 
104  pp->port = port;
105  pp->time = now;
106  predicted_ports_total_alloc += sizeof(*pp);
108 }
109 
110 /** Remember that <b>port</b> has been asked for as of time <b>now</b>.
111  * This is used for predicting what sorts of streams we'll make in the
112  * future and making exit circuits to anticipate that.
113  */
114 void
115 rep_hist_note_used_port(time_t now, uint16_t port)
116 {
118 
119  if (!port) /* record nothing */
120  return;
121 
123  if (pp->port == port) {
124  pp->time = now;
125 
127  log_info(LD_CIRC,
128  "New port prediction added. Will continue predictive circ "
129  "building for %d more seconds.",
131  return;
132  }
133  } SMARTLIST_FOREACH_END(pp);
134  /* it's not there yet; we need to add it */
135  add_predicted_port(now, port);
136 }
137 
138 /** Return a newly allocated pointer to a list of uint16_t * for ports that
139  * are likely to be asked for in the near future.
140  */
141 smartlist_t *
143 {
144  int predicted_circs_relevance_time;
145  smartlist_t *out = smartlist_new();
147 
148  predicted_circs_relevance_time = (int)prediction_timeout;
149 
150  /* clean out obsolete entries */
152  if (pp->time + predicted_circs_relevance_time < now) {
153  log_debug(LD_CIRC, "Expiring predicted port %d", pp->port);
154 
155  predicted_ports_total_alloc -= sizeof(predicted_port_t);
156  tor_free(pp);
158  } else {
159  smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t)));
160  }
161  } SMARTLIST_FOREACH_END(pp);
162  return out;
163 }
164 
165 /**
166  * Take a list of uint16_t *, and remove every port in the list from the
167  * current list of predicted ports.
168  */
169 void
171 {
172  /* Let's do this on O(N), not O(N^2). */
173  bitarray_t *remove_ports = bitarray_init_zero(UINT16_MAX);
174  SMARTLIST_FOREACH(rmv_ports, const uint16_t *, p,
175  bitarray_set(remove_ports, *p));
177  if (bitarray_is_set(remove_ports, pp->port)) {
178  tor_free(pp);
179  predicted_ports_total_alloc -= sizeof(*pp);
181  }
182  } SMARTLIST_FOREACH_END(pp);
183  bitarray_free(remove_ports);
184 }
185 
186 /** The user asked us to do a resolve. Rather than keeping track of
187  * timings and such of resolves, we fake it for now by treating
188  * it the same way as a connection to port 80. This way we will continue
189  * to have circuits lying around if the user only uses Tor for resolves.
190  */
191 void
193 {
194  rep_hist_note_used_port(now, 80);
195 }
196 
197 /** The last time at which we needed an internal circ. */
198 static time_t predicted_internal_time = 0;
199 /** The last time we needed an internal circ with good uptime. */
201 /** The last time we needed an internal circ with good capacity. */
203 
204 /** Remember that we used an internal circ at time <b>now</b>. */
205 void
206 rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
207 {
208  // If the list is empty, re-randomize predicted ports lifetime
209  if (!any_predicted_circuits(now)) {
211  }
212 
214 
215  log_info(LD_CIRC,
216  "New port prediction added. Will continue predictive circ building "
217  "for %d more seconds.",
219 
221  if (need_uptime)
223  if (need_capacity)
225 }
226 
227 /** Return 1 if we've used an internal circ recently; else return 0. */
228 int
229 rep_hist_get_predicted_internal(time_t now, int *need_uptime,
230  int *need_capacity)
231 {
232  int predicted_circs_relevance_time;
233 
234  predicted_circs_relevance_time = (int)prediction_timeout;
235 
236  if (!predicted_internal_time) { /* initialize it */
240  }
241  if (predicted_internal_time + predicted_circs_relevance_time < now)
242  return 0; /* too long ago */
243  if (predicted_internal_uptime_time + predicted_circs_relevance_time >= now)
244  *need_uptime = 1;
245  // Always predict that we need capacity.
246  *need_capacity = 1;
247  return 1;
248 }
249 
250 /** Any ports used lately? These are pre-seeded if we just started
251  * up or if we're running a hidden service. */
252 int
254 {
255  int predicted_circs_relevance_time;
256  predicted_circs_relevance_time = (int)prediction_timeout;
257 
258  return smartlist_len(predicted_ports_list) ||
259  predicted_internal_time + predicted_circs_relevance_time >= now;
260 }
261 
262 /** Return 1 if we have no need for circuits currently, else return 0. */
263 int
265 {
266  const or_options_t *options = get_options();
267 
268  if (any_predicted_circuits(now))
269  return 0;
270 
271  /* see if we'll still need to build testing circuits */
272  if (server_mode(options) &&
273  (!router_all_orports_seem_reachable(options) ||
275  return 0;
276 
277  return 1;
278 }
279 
280 /**
281  * Allocate whatever memory and structs are needed for predicting
282  * which ports will be used. Also seed it with port 80, so we'll build
283  * circuits on start-up.
284  */
285 static void
287 {
289 }
290 
291 void
292 predicted_ports_init(void)
293 {
295  add_predicted_port(time(NULL), 443); // Add a port to get us started
296 }
297 
298 /** Free whatever memory is needed for predicting which ports will
299  * be used.
300  */
301 void
303 {
305  return;
306  predicted_ports_total_alloc -=
307  smartlist_len(predicted_ports_list)*sizeof(predicted_port_t);
309  pp, tor_free(pp));
310  smartlist_free(predicted_ports_list);
311 }
Implements a variable-sized (but non-resizeable) bit-array.
unsigned int bitarray_t
Definition: bitarray.h:30
static void bitarray_set(bitarray_t *b, int bit)
Definition: bitarray.h:68
static unsigned int bitarray_is_set(bitarray_t *b, int bit)
Definition: bitarray.h:81
static bitarray_t * bitarray_init_zero(unsigned int n_bits)
Definition: bitarray.h:33
int channelpadding_get_circuits_available_timeout(void)
int circuit_enough_testing_circs(void)
Definition: circuituse.c:1613
Header file for circuituse.c.
const or_options_t * get_options(void)
Definition: config.c:919
Header file for config.c.
#define LD_CIRC
Definition: log.h:82
#define tor_free(p)
Definition: malloc.h:52
Master header file for Tor-specific functionality.
void rep_hist_note_used_port(time_t now, uint16_t port)
void rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports)
static void predicted_ports_alloc(void)
int rep_hist_circbuilding_dormant(time_t now)
void rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
void rep_hist_note_used_resolve(time_t now)
int predicted_ports_prediction_time_remaining(time_t now)
Definition: predict_ports.c:54
static void add_predicted_port(time_t now, uint16_t port)
Definition: predict_ports.c:87
static time_t predicted_internal_uptime_time
static time_t last_prediction_add_time
Definition: predict_ports.c:48
static smartlist_t * predicted_ports_list
Definition: predict_ports.c:44
static time_t predicted_internal_time
static time_t prediction_timeout
Definition: predict_ports.c:46
int rep_hist_get_predicted_internal(time_t now, int *need_uptime, int *need_capacity)
int any_predicted_circuits(time_t now)
smartlist_t * rep_hist_get_predicted_ports(time_t now)
static time_t predicted_internal_capacity_time
void predicted_ports_free_all(void)
Header file for predict_ports.c.
int server_mode(const or_options_t *options)
Definition: routermode.c:34
Header file for routermode.c.
Header file for selftest.c.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
#define SMARTLIST_DEL_CURRENT(sl, var)
time_t time_diff(const time_t t1, const time_t t2)
Definition: tvdiff.c:181
Header for tvdiff.c.
#define tor_assert(expr)
Definition: util_bug.h:102