1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
6 * \file predict_ports.c
7 * \brief Remember what ports we've needed so we can have circuits ready.
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,
18 #include "core/or/or.h"
20 #include "app/config/config.h"
21 #include "core/or/channelpadding.h"
22 #include "core/or/circuituse.h"
23 #include "feature/relay/routermode.h"
24 #include "feature/relay/selftest.h"
25 #include "feature/stats/predict_ports.h"
26 #include "lib/container/bitarray.h"
27 #include "lib/time/tvdiff.h"
29 static size_t predicted_ports_total_alloc
= 0;
31 static void predicted_ports_alloc(void);
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
36 typedef struct predicted_port_t
{
37 /** The port we connected to */
39 /** The time at which we last used it */
43 /** A list of port numbers that have been used recently. */
44 static smartlist_t
*predicted_ports_list
=NULL
;
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;
51 * How much time left until we stop predicting circuits?
54 predicted_ports_prediction_time_remaining(time_t now
)
56 time_t seconds_waited
;
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
) {
66 last_prediction_add_time
= now
;
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
)
75 seconds_left
= time_diff(seconds_waited
, prediction_timeout
);
76 if (BUG(seconds_left
== TIME_MAX
))
79 return (int)(seconds_left
);
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.
87 add_predicted_port(time_t now
, uint16_t port
)
89 predicted_port_t
*pp
= tor_malloc(sizeof(predicted_port_t
));
91 // If the list is empty, re-randomize predicted ports lifetime
92 if (!any_predicted_circuits(now
)) {
94 (time_t)channelpadding_get_circuits_available_timeout();
97 last_prediction_add_time
= now
;
100 "New port prediction added. Will continue predictive circ building "
101 "for %d more seconds.",
102 predicted_ports_prediction_time_remaining(now
));
106 predicted_ports_total_alloc
+= sizeof(*pp
);
107 smartlist_add(predicted_ports_list
, pp
);
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.
115 rep_hist_note_used_port(time_t now
, uint16_t port
)
117 tor_assert(predicted_ports_list
);
119 if (!port
) /* record nothing */
122 SMARTLIST_FOREACH_BEGIN(predicted_ports_list
, predicted_port_t
*, pp
) {
123 if (pp
->port
== port
) {
126 last_prediction_add_time
= now
;
128 "New port prediction added. Will continue predictive circ "
129 "building for %d more seconds.",
130 predicted_ports_prediction_time_remaining(now
));
133 } SMARTLIST_FOREACH_END(pp
);
134 /* it's not there yet; we need to add it */
135 add_predicted_port(now
, port
);
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.
142 rep_hist_get_predicted_ports(time_t now
)
144 int predicted_circs_relevance_time
;
145 smartlist_t
*out
= smartlist_new();
146 tor_assert(predicted_ports_list
);
148 predicted_circs_relevance_time
= (int)prediction_timeout
;
150 /* clean out obsolete entries */
151 SMARTLIST_FOREACH_BEGIN(predicted_ports_list
, predicted_port_t
*, pp
) {
152 if (pp
->time
+ predicted_circs_relevance_time
< now
) {
153 log_debug(LD_CIRC
, "Expiring predicted port %d", pp
->port
);
155 predicted_ports_total_alloc
-= sizeof(predicted_port_t
);
157 SMARTLIST_DEL_CURRENT(predicted_ports_list
, pp
);
159 smartlist_add(out
, tor_memdup(&pp
->port
, sizeof(uint16_t)));
161 } SMARTLIST_FOREACH_END(pp
);
166 * Take a list of uint16_t *, and remove every port in the list from the
167 * current list of predicted ports.
170 rep_hist_remove_predicted_ports(const smartlist_t
*rmv_ports
)
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
));
176 SMARTLIST_FOREACH_BEGIN(predicted_ports_list
, predicted_port_t
*, pp
) {
177 if (bitarray_is_set(remove_ports
, pp
->port
)) {
179 predicted_ports_total_alloc
-= sizeof(*pp
);
180 SMARTLIST_DEL_CURRENT(predicted_ports_list
, pp
);
182 } SMARTLIST_FOREACH_END(pp
);
183 bitarray_free(remove_ports
);
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.
192 rep_hist_note_used_resolve(time_t now
)
194 rep_hist_note_used_port(now
, 80);
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. */
200 static time_t predicted_internal_uptime_time
= 0;
201 /** The last time we needed an internal circ with good capacity. */
202 static time_t predicted_internal_capacity_time
= 0;
204 /** Remember that we used an internal circ at time <b>now</b>. */
206 rep_hist_note_used_internal(time_t now
, int need_uptime
, int need_capacity
)
208 // If the list is empty, re-randomize predicted ports lifetime
209 if (!any_predicted_circuits(now
)) {
210 prediction_timeout
= channelpadding_get_circuits_available_timeout();
213 last_prediction_add_time
= now
;
216 "New port prediction added. Will continue predictive circ building "
217 "for %d more seconds.",
218 predicted_ports_prediction_time_remaining(now
));
220 predicted_internal_time
= now
;
222 predicted_internal_uptime_time
= now
;
224 predicted_internal_capacity_time
= now
;
227 /** Return 1 if we've used an internal circ recently; else return 0. */
229 rep_hist_get_predicted_internal(time_t now
, int *need_uptime
,
232 int predicted_circs_relevance_time
;
234 predicted_circs_relevance_time
= (int)prediction_timeout
;
236 if (!predicted_internal_time
) { /* initialize it */
237 predicted_internal_time
= now
;
238 predicted_internal_uptime_time
= now
;
239 predicted_internal_capacity_time
= now
;
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
)
245 // Always predict that we need capacity.
250 /** Any ports used lately? These are pre-seeded if we just started
251 * up or if we're running a hidden service. */
253 any_predicted_circuits(time_t now
)
255 int predicted_circs_relevance_time
;
256 predicted_circs_relevance_time
= (int)prediction_timeout
;
258 return smartlist_len(predicted_ports_list
) ||
259 predicted_internal_time
+ predicted_circs_relevance_time
>= now
;
262 /** Return 1 if we have no need for circuits currently, else return 0. */
264 rep_hist_circbuilding_dormant(time_t now
)
266 const or_options_t
*options
= get_options();
268 if (any_predicted_circuits(now
))
271 /* see if we'll still need to build testing circuits */
272 if (server_mode(options
) &&
273 (!router_all_orports_seem_reachable(options
) ||
274 !circuit_enough_testing_circs()))
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.
286 predicted_ports_alloc(void)
288 predicted_ports_list
= smartlist_new();
292 predicted_ports_init(void)
294 predicted_ports_alloc();
295 add_predicted_port(time(NULL
), 443); // Add a port to get us started
298 /** Free whatever memory is needed for predicting which ports will
302 predicted_ports_free_all(void)
304 if (!predicted_ports_list
)
306 predicted_ports_total_alloc
-=
307 smartlist_len(predicted_ports_list
)*sizeof(predicted_port_t
);
308 SMARTLIST_FOREACH(predicted_ports_list
, predicted_port_t
*,
310 smartlist_free(predicted_ports_list
);