summaryrefslogtreecommitdiff
path: root/src/feature/relay/relay_find_addr.c
blob: 33a50ce3c35761a48637c1eb4b0dc3edfdc53253 (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
/* Copyright (c) 2001-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file relay_find_addr.c
 * \brief Implement mechanism for a relay to find its address.
 **/

#include "core/or/or.h"

#include "app/config/config.h"
#include "app/config/resolve_addr.h"

#include "core/mainloop/mainloop.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/extendinfo.h"

#include "feature/control/control_events.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/node_select.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerstatus_st.h"
#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"

/** Consider the address suggestion suggested_addr as a possible one to use as
 * our address.
 *
 * This is called when a valid NETINFO cell is received containing a candidate
 * for our address or when a directory sends us back the X-Your-Address-Is
 * header.
 *
 * The suggested address is ignored if it does NOT come from a trusted source.
 * At the moment, we only look a trusted directory authorities.
 *
 * The suggested address is ignored if it is internal or it is the same as the
 * given peer_addr which is the address from the endpoint that sent the
 * NETINFO cell.
 *
 * The identity_digest is NULL if this is an address suggested by a directory
 * since this is a plaintext connection.
 *
 * The suggested address is set in our suggested address cache if everything
 * passes. */
void
relay_address_new_suggestion(const tor_addr_t *suggested_addr,
                             const tor_addr_t *peer_addr,
                             const char *identity_digest)
{
  const or_options_t *options = get_options();

  tor_assert(suggested_addr);
  tor_assert(peer_addr);

  /* Non server should just ignore this suggestion. Clients don't need to
   * learn their address let alone cache it. */
  if (!server_mode(options)) {
    return;
  }

  /* Is the peer a trusted source? Ignore anything coming from non trusted
   * source. In this case, we only look at trusted directory authorities. */
  if (!router_addr_is_trusted_dir(peer_addr) ||
      (identity_digest && !router_digest_is_trusted_dir(identity_digest))) {
    return;
  }

  /* Ignore a suggestion that is an internal address or the same as the one
   * the peer address. */
  if (tor_addr_is_internal(suggested_addr, 0)) {
    /* Do not believe anyone who says our address is internal. */
    return;
  }
  if (tor_addr_eq(suggested_addr, peer_addr)) {
    /* Do not believe anyone who says our address is their address. */
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "A relay endpoint %s is telling us that their address is ours.",
           fmt_addr(peer_addr));
    return;
  }

  /* Save the suggestion in our cache. */
  resolved_addr_set_suggested(suggested_addr);
}

/** Find our address to be published in our descriptor. Three places are
 * looked at:
 *
 *    1. Resolved cache. Populated by find_my_address() during the relay
 *       periodic event that attempts to learn if our address has changed.
 *
 *    2. If flags is set with RELAY_FIND_ADDR_CACHE_ONLY, only the resolved
 *       and suggested cache are looked at. No address discovery will be done.
 *
 *    3. Finally, if all fails, use the suggested address cache which is
 *       populated by the NETINFO cell content or HTTP header from a
 *       directory.
 *
 * The AddressDisableIPv6 is checked here for IPv6 address discovery and if
 * set, false is returned and addr_out is UNSPEC.
 *
 * Before doing any discovery, the configuration is checked for an ORPort of
 * the given family. If none can be found, false is returned and addr_out is
 * UNSPEC.
 *
 * Return true on success and addr_out contains the address to use for the
 * given family. On failure to find the address, false is returned and
 * addr_out is set to an AF_UNSPEC address. */
MOCK_IMPL(bool,
relay_find_addr_to_publish, (const or_options_t *options, int family,
                             int flags, tor_addr_t *addr_out))
{
  tor_assert(options);
  tor_assert(addr_out);

  tor_addr_make_unspec(addr_out);

  /* If an IPv6 is requested, check if IPv6 address discovery is disabled on
   * this instance. If so, we return a failure. It is done here so we don't
   * query the suggested cache that might be populated with an IPv6. */
  if (family == AF_INET6 && options->AddressDisableIPv6) {
    return false;
  }

  /* There is no point on attempting an address discovery to publish if we
   * don't have an ORPort for this family. */
  if (!routerconf_find_or_port(options, family)) {
    return false;
  }

  /* First, check our resolved address cache. It should contain the address
   * we've discovered from the periodic relay event. */
  resolved_addr_get_last(family, addr_out);
  if (!tor_addr_is_null(addr_out)) {
    goto found;
  }

  /* Second, attempt to find our address. The following can do a DNS resolve
   * thus only do it when the no cache only flag is flipped. */
  if (!(flags & RELAY_FIND_ADDR_CACHE_ONLY)) {
    if (find_my_address(options, family, LOG_INFO, addr_out, NULL, NULL)) {
      goto found;
    }
  }

  /* Third, consider address from our suggestion cache. */
  resolved_addr_get_suggested(family, addr_out);
  if (!tor_addr_is_null(addr_out)) {
    goto found;
  }

  /* No publishable address was found even though we have an ORPort thus
   * print a notice log so operator can notice. We'll do that every hour so
   * it is not too spammy but enough so operators address the issue. */
  static ratelim_t rlim = RATELIM_INIT(3600);
  log_fn_ratelim(&rlim, LOG_NOTICE, LD_CONFIG,
                 "Unable to find %s address for ORPort %u. "
                 "You might want to specify %sOnly to it or set an "
                 "explicit address or set Address.",
                 fmt_af_family(family),
                 routerconf_find_or_port(options, family),
                 (family == AF_INET) ? fmt_af_family(AF_INET6) :
                                       fmt_af_family(AF_INET));

  /* Not found. */
  return false;

 found:
  return true;
}

/** How often should we launch a circuit to an authority to be sure of getting
 * a guess for our IP? */
#define DUMMY_DOWNLOAD_INTERVAL (20*60)

void
relay_addr_learn_from_dirauth(void)
{
  static time_t last_dummy_circuit = 0;
  const or_options_t *options = get_options();
  time_t now = time(NULL);
  bool have_addr;
  tor_addr_t addr_out;

  /* This dummy circuit only matter for relays. */
  if (BUG(!server_mode(options))) {
    return;
  }

  /* Lookup the address cache to learn if we have a good usable address. We
   * still force relays to have an IPv4 so that alone is enough to learn if we
   * need a lookup. In case we don't have one, we might want to attempt a
   * dummy circuit to learn our address as a suggestion from an authority. */
  have_addr = relay_find_addr_to_publish(options, AF_INET,
                                         RELAY_FIND_ADDR_CACHE_ONLY,
                                         &addr_out);

  /* If we're a relay or bridge for which we were unable to discover our
   * public address, we rely on learning our address from a directory
   * authority from the NETINFO cell. */
  if (!have_addr && last_dummy_circuit + DUMMY_DOWNLOAD_INTERVAL < now) {
    last_dummy_circuit = now;

    const routerstatus_t *rs = router_pick_trusteddirserver(V3_DIRINFO, 0);
    if (BUG(!rs)) {
      /* We should really always have trusted directories configured at this
       * stage. They are loaded early either from default list or the one
       * given in the configuration file. */
      return;
    }
    const node_t *node = node_get_by_id(rs->identity_digest);
    if (!node) {
      /* This can happen if we are still in the early starting stage where no
       * descriptors we actually fetched and thus we have the routerstatus_t
       * for the authority but not its descriptor which is needed to build a
       * circuit and thus learn our address. */
      log_info(LD_GENERAL, "Can't build a circuit to an authority. Unable to "
                           "learn for now our address from them.");
      return;
    }
    extend_info_t *ei = extend_info_from_node(node, 1);
    if (BUG(!ei)) {
      return;
    }

    log_debug(LD_GENERAL, "Attempting dummy testing circuit to an authority "
                          "in order to learn our address.");

    /* Launch a one-hop testing circuit to a trusted authority so we can learn
     * our address through the NETINFO cell. */
    circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
                                  CIRCLAUNCH_IS_INTERNAL |
                                  CIRCLAUNCH_ONEHOP_TUNNEL);
    extend_info_free(ei);
  }
}