aboutsummaryrefslogtreecommitdiff
path: root/src/feature/relay/relay_periodic.c
blob: bfe12cd0b0db8b9d7086da676e45f942f27117a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * @file relay_periodic.c
 * @brief Periodic functions for the relay subsytem
 **/

#include "orconfig.h"
#include "core/or/or.h"

#include "core/mainloop/periodic.h"
#include "core/mainloop/cpuworker.h" // XXXX use a pubsub event.
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
#include "core/or/circuituse.h" // XXXX move have_performed_bandwidth_test

#include "feature/relay/dns.h"
#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "feature/stats/predict_ports.h"

#include "lib/crypt_ops/crypto_rand.h"

#include "feature/nodelist/routerinfo_st.h"
#include "feature/control/control_events.h"

#ifndef COCCI
#define DECLARE_EVENT(name, roles, flags)         \
  static periodic_event_item_t name ## _event =   \
    PERIODIC_EVENT(name,                          \
                   PERIODIC_EVENT_ROLE_##roles,   \
                   flags)
#endif /* !defined(COCCI) */

#define FL(name) (PERIODIC_EVENT_FLAG_##name)

/**
 * Periodic callback: If we're a server and initializing dns failed, retry.
 */
static int
retry_dns_callback(time_t now, const or_options_t *options)
{
  (void)now;
#define RETRY_DNS_INTERVAL (10*60)
  if (server_mode(options) && has_dns_init_failed())
    dns_init();
  return RETRY_DNS_INTERVAL;
}

DECLARE_EVENT(retry_dns, ROUTER, 0);

static int dns_honesty_first_time = 1;

/**
 * Periodic event: if we're an exit, see if our DNS server is telling us
 * obvious lies.
 */
static int
check_dns_honesty_callback(time_t now, const or_options_t *options)
{
  (void)now;
  /* 9. and if we're an exit node, check whether our DNS is telling stories
   * to us. */
  if (net_is_disabled() ||
      ! public_server_mode(options) ||
      router_my_exit_policy_is_reject_star())
    return PERIODIC_EVENT_NO_UPDATE;

  if (dns_honesty_first_time) {
    /* Don't launch right when we start */
    dns_honesty_first_time = 0;
    return crypto_rand_int_range(60, 180);
  }

  dns_launch_correctness_checks();
  return 12*3600 + crypto_rand_int(12*3600);
}

DECLARE_EVENT(check_dns_honesty, RELAY, FL(NEED_NET));

/* Periodic callback: rotate the onion keys after the period defined by the
 * "onion-key-rotation-days" consensus parameter, shut down and restart all
 * cpuworkers, and update our descriptor if necessary.
 */
static int
rotate_onion_key_callback(time_t now, const or_options_t *options)
{
  if (server_mode(options)) {
    int onion_key_lifetime = get_onion_key_lifetime();
    time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime;
    if (rotation_time > now) {
      return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
    }

    log_info(LD_GENERAL,"Rotating onion key.");
    rotate_onion_key();
    cpuworkers_rotate_keyinfo();
    if (router_rebuild_descriptor(1)<0) {
      log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
    }
    if (advertised_server_mode() && !net_is_disabled())
      router_upload_dir_desc_to_dirservers(0);
    return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
  }
  return PERIODIC_EVENT_NO_UPDATE;
}

DECLARE_EVENT(rotate_onion_key, ROUTER, 0);

/** Periodic callback: consider rebuilding or and re-uploading our descriptor
 * (if we've passed our internal checks). */
static int
check_descriptor_callback(time_t now, const or_options_t *options)
{
/** How often do we check whether part of our router info has changed in a
 * way that would require an upload? That includes checking whether our IP
 * address has changed. */
#define CHECK_DESCRIPTOR_INTERVAL (60)

  (void)options;

  /* 2b. Once per minute, regenerate and upload the descriptor if the old
   * one is inaccurate. */
  if (!net_is_disabled()) {
    check_descriptor_bandwidth_changed(now);
    check_descriptor_ipaddress_changed(now);
    mark_my_descriptor_dirty_if_too_old(now);
    consider_publishable_server(0);
  }

  return CHECK_DESCRIPTOR_INTERVAL;
}

DECLARE_EVENT(check_descriptor, ROUTER, FL(NEED_NET));

static int dirport_reachability_count = 0;

/**
 * Periodic callback: check whether we're reachable (as a relay), and
 * whether our bandwidth has changed enough that we need to
 * publish a new descriptor.
 */
static int
check_for_reachability_bw_callback(time_t now, const or_options_t *options)
{
  /* XXXX This whole thing was stuck in the middle of what is now
   * XXXX check_descriptor_callback.  I'm not sure it's right. */
  /** How often should we consider launching reachability tests in our first
   * TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT seconds? */
#define EARLY_CHECK_REACHABILITY_INTERVAL (60)

  /* also, check religiously for reachability, if it's within the first
   * 20 minutes of our uptime. */
  if (server_mode(options) &&
      (have_completed_a_circuit() || !any_predicted_circuits(now)) &&
      !net_is_disabled()) {
    if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
      router_do_reachability_checks(1, dirport_reachability_count==0);
      if (++dirport_reachability_count > 5)
        dirport_reachability_count = 0;
      return EARLY_CHECK_REACHABILITY_INTERVAL;
    } else {
      /* If we haven't checked for 12 hours and our bandwidth estimate is
       * low, do another bandwidth test. This is especially important for
       * bridges, since they might go long periods without much use. */
      const routerinfo_t *me = router_get_my_routerinfo();
      static int first_time = 1;
      if (!first_time && me &&
          me->bandwidthcapacity < me->bandwidthrate &&
          me->bandwidthcapacity < 51200) {
        reset_bandwidth_test();
      }
      first_time = 0;
#define BANDWIDTH_RECHECK_INTERVAL (12*60*60)
      return BANDWIDTH_RECHECK_INTERVAL;
    }
  }
  return CHECK_DESCRIPTOR_INTERVAL;
}

DECLARE_EVENT(check_for_reachability_bw, ROUTER, FL(NEED_NET));

/**
 * Callback: Send warnings if Tor doesn't find its ports reachable.
 */
static int
reachability_warnings_callback(time_t now, const or_options_t *options)
{
  (void) now;

  if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
    return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime());
  }

  if (server_mode(options) &&
      !net_is_disabled() &&
      have_completed_a_circuit()) {
    /* every 20 minutes, check and complain if necessary */
    const routerinfo_t *me = router_get_my_routerinfo();
    if (me && !check_whether_orport_reachable(options)) {
      char *address = tor_dup_ip(me->addr);
      if (address) {
        log_warn(LD_CONFIG,
                 "Your server (%s:%d) has not managed to confirm that "
                 "its ORPort is reachable. Relays do not publish descriptors "
                 "until their ORPort and DirPort are reachable. Please check "
                 "your firewalls, ports, address, /etc/hosts file, etc.",
                 address, me->or_port);
        control_event_server_status(LOG_WARN,
                                    "REACHABILITY_FAILED ORADDRESS=%s:%d",
                                    address, me->or_port);
        tor_free(address);
      }
    }

    if (me && !check_whether_dirport_reachable(options)) {
      char *address = tor_dup_ip(me->addr);
      if (address) {
        log_warn(LD_CONFIG,
                 "Your server (%s:%d) has not managed to confirm that its "
                 "DirPort is reachable. Relays do not publish descriptors "
                 "until their ORPort and DirPort are reachable. Please check "
                 "your firewalls, ports, address, /etc/hosts file, etc.",
                 address, me->dir_port);
        control_event_server_status(LOG_WARN,
                                    "REACHABILITY_FAILED DIRADDRESS=%s:%d",
                                    address, me->dir_port);
        tor_free(address);
      }
    }
  }

  return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT;
}

DECLARE_EVENT(reachability_warnings, ROUTER, FL(NEED_NET));

/* Periodic callback: Every 30 seconds, check whether it's time to make new
 * Ed25519 subkeys.
 */
static int
check_ed_keys_callback(time_t now, const or_options_t *options)
{
  if (server_mode(options)) {
    if (should_make_new_ed_keys(options, now)) {
      int new_signing_key = load_ed_keys(options, now);
      if (new_signing_key < 0 ||
          generate_ed_link_cert(options, now, new_signing_key > 0)) {
        log_err(LD_OR, "Unable to update Ed25519 keys!  Exiting.");
        tor_shutdown_event_loop_and_exit(1);
      }
    }
    return 30;
  }
  return PERIODIC_EVENT_NO_UPDATE;
}

DECLARE_EVENT(check_ed_keys, ROUTER, 0);

/* Period callback: Check if our old onion keys are still valid after the
 * period of time defined by the consensus parameter
 * "onion-key-grace-period-days", otherwise expire them by setting them to
 * NULL.
 */
static int
check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options)
{
  if (server_mode(options)) {
    int onion_key_grace_period = get_onion_key_grace_period();
    time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period;
    if (expiry_time > now) {
      return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
    }

    log_info(LD_GENERAL, "Expiring old onion keys.");
    expire_old_onion_keys();
    cpuworkers_rotate_keyinfo();
    return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
  }

  return PERIODIC_EVENT_NO_UPDATE;
}

DECLARE_EVENT(check_onion_keys_expiry_time, ROUTER, 0);

void
relay_register_periodic_events(void)
{
  periodic_events_register(&retry_dns_event);
  periodic_events_register(&check_dns_honesty_event);
  periodic_events_register(&rotate_onion_key_event);
  periodic_events_register(&check_descriptor_event);
  periodic_events_register(&check_for_reachability_bw_event);
  periodic_events_register(&reachability_warnings_event);
  periodic_events_register(&check_ed_keys_event);
  periodic_events_register(&check_onion_keys_expiry_time_event);

  dns_honesty_first_time = 1;
  dirport_reachability_count = 0;
}

/**
 * Update our schedule so that we'll check whether we need to update our
 * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL
 * seconds.
 */
void
reschedule_descriptor_update_check(void)
{
  periodic_event_reschedule(&check_descriptor_event);
}