Tor 0.4.9.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"
27#include "lib/time/tvdiff.h"
28
29static size_t predicted_ports_total_alloc = 0;
30
31static 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. */
36typedef 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? */
46static time_t prediction_timeout=0;
47/** When was the last time we added a prediction entry (HS or port) */
49
50/**
51 * How much time left until we stop predicting circuits?
52 */
53int
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 */
86static void
87add_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 */
114void
115rep_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 */
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 */
169void
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 */
191void
193{
195}
196
197/** The last time at which we needed an internal circ. */
198static 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>. */
205void
206rep_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. */
228int
229rep_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. */
252int
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. */
263int
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 */
285static void
287{
289}
290
291void
292predicted_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 */
301void
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 bitarray_t * bitarray_init_zero(unsigned int n_bits)
Definition: bitarray.h:33
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
int channelpadding_get_circuits_available_timeout(void)
int circuit_enough_testing_circs(void)
Definition: circuituse.c:1597
Header file for circuituse.c.
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
#define LD_CIRC
Definition: log.h:82
#define tor_free(p)
Definition: malloc.h:56
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)
smartlist_t * rep_hist_get_predicted_ports(time_t now)
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)
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:103