rendservice.c 92.4 KB
Newer Older
1
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2
 * Copyright (c) 2007-2012, The Tor Project, Inc. */
Nick Mathewson's avatar
Nick Mathewson committed
3
4
/* See LICENSE for licensing information */

Roger Dingledine's avatar
Roger Dingledine committed
5
6
7
8
/**
 * \file rendservice.c
 * \brief The hidden-service side of rendezvous functionality.
 **/
Nick Mathewson's avatar
Nick Mathewson committed
9
10

#include "or.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
11
#include "circuitbuild.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
12
#include "circuitlist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
13
#include "circuituse.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
14
#include "config.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
15
#include "directory.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
16
#include "networkstatus.h"
17
#include "nodelist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
18
#include "rendclient.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
19
#include "rendcommon.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
20
#include "rendservice.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
21
#include "router.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
22
#include "relay.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
23
#include "rephist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
24
#include "routerlist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
25
#include "routerparse.h"
Nick Mathewson's avatar
Nick Mathewson committed
26

27
static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
28
                                            const char *pk_digest);
29
static rend_intro_point_t *find_intro_point(origin_circuit_t *circ);
30

31
static int intro_point_accepted_intro_count(rend_intro_point_t *intro);
32
33
static int intro_point_should_expire_now(rend_intro_point_t *intro,
                                         time_t now);
34

Roger Dingledine's avatar
Roger Dingledine committed
35
/** Represents the mapping from a virtual port of a rendezvous service to
Nick Mathewson's avatar
Nick Mathewson committed
36
37
38
39
40
 * a real port on some IP.
 */
typedef struct rend_service_port_config_t {
  uint16_t virtual_port;
  uint16_t real_port;
41
  tor_addr_t real_addr;
Nick Mathewson's avatar
Nick Mathewson committed
42
43
} rend_service_port_config_t;

44
45
46
47
/** Try to maintain this many intro points per service by default. */
#define NUM_INTRO_POINTS_DEFAULT 3
/** Maintain no more than this many intro points per hidden service. */
#define NUM_INTRO_POINTS_MAX 10
Nick Mathewson's avatar
Nick Mathewson committed
48

49
/** If we can't build our intro circuits, don't retry for this long. */
50
#define INTRO_CIRC_RETRY_PERIOD (60*5)
51
52
/** Don't try to build more than this many circuits before giving up
 * for a while.*/
53
#define MAX_INTRO_CIRCS_PER_PERIOD 10
54
55
/** How many times will a hidden service operator attempt to connect to
 * a requested rendezvous point before giving up? */
56
57
58
59
#define MAX_REND_FAILURES 30
/** How many seconds should we spend trying to connect to a requested
 * rendezvous point before giving up? */
#define MAX_REND_TIMEOUT 30
60

61
62
63
64
/** How many seconds should we wait for new HS descriptors to reach
 * our clients before we close an expiring intro point? */
#define INTRO_POINT_EXPIRATION_GRACE_PERIOD 5*60

Roger Dingledine's avatar
Roger Dingledine committed
65
/** Represents a single hidden service running at this OP. */
Nick Mathewson's avatar
Nick Mathewson committed
66
typedef struct rend_service_t {
67
  /* Fields specified in config file */
Roger Dingledine's avatar
Roger Dingledine committed
68
69
  char *directory; /**< where in the filesystem it stores it */
  smartlist_t *ports; /**< List of rend_service_port_config_t */
70
71
72
  rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client
                               * authorization is performed. */
  smartlist_t *clients; /**< List of rend_authorized_client_t's of
Nick Mathewson's avatar
Nick Mathewson committed
73
                         * clients that may access our service. Can be NULL
Nick Mathewson's avatar
Nick Mathewson committed
74
                         * if no client authorization is performed. */
Nick Mathewson's avatar
Nick Mathewson committed
75
  /* Other fields */
76
  crypto_pk_t *private_key; /**< Permanent hidden-service key. */
77
78
79
  char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without
                                                  * '.onion' */
  char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */
80
  smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have,
81
                             * or are trying to establish. */
82
83
  time_t intro_period_started; /**< Start of the current period to build
                                * introduction points. */
84
  int n_intro_circuits_launched; /**< Count of intro circuits we have
85
                                  * established in this period. */
86
87
  unsigned int n_intro_points_wanted; /**< Number of intro points this
                                       * service wants to have open. */
88
89
90
91
92
93
  rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */
  time_t desc_is_dirty; /**< Time at which changes to the hidden service
                         * descriptor content occurred, or 0 if it's
                         * up-to-date. */
  time_t next_upload_time; /**< Scheduled next hidden service descriptor
                            * upload time. */
94
95
96
97
98
99
  /** Map from digests of Diffie-Hellman values INTRODUCE2 to time_t
   * of when they were received.  Clients may send INTRODUCE1 cells
   * for the same rendezvous point through two or more different
   * introduction points; when they do, this digestmap keeps us from
   * launching multiple simultaneous attempts to connect to the same
   * rend point. */
Robert Ransom's avatar
Robert Ransom committed
100
101
102
103
  digestmap_t *accepted_intro_dh_parts;
  /** Time at which we last removed expired values from
   * accepted_intro_dh_parts. */
  time_t last_cleaned_accepted_intro_dh_parts;
Nick Mathewson's avatar
Nick Mathewson committed
104
105
} rend_service_t;

Roger Dingledine's avatar
Roger Dingledine committed
106
/** A list of rend_service_t's for services run on this OP.
Nick Mathewson's avatar
Nick Mathewson committed
107
108
109
 */
static smartlist_t *rend_service_list = NULL;

110
/** Return the number of rendezvous services we have configured. */
111
112
113
int
num_rend_services(void)
{
114
115
116
117
118
  if (!rend_service_list)
    return 0;
  return smartlist_len(rend_service_list);
}

119
120
121
122
123
124
125
126
127
128
129
/** Return a string identifying <b>service</b>, suitable for use in a
 * log message.  The result does not need to be freed, but may be
 * overwritten by the next call to this function. */
static const char *
rend_service_describe_for_log(rend_service_t *service)
{
  /* XXX024 Use this function throughout rendservice.c. */
  /* XXX024 Return a more useful description? */
  return safe_str_client(service->service_id);
}

130
131
132
133
/** Helper: free storage held by a single service authorized client entry. */
static void
rend_authorized_client_free(rend_authorized_client_t *client)
{
134
135
  if (!client)
    return;
136
  if (client->client_key)
137
    crypto_pk_free(client->client_key);
138
139
140
141
142
143
144
145
146
147
148
  tor_free(client->client_name);
  tor_free(client);
}

/** Helper for strmap_free. */
static void
rend_authorized_client_strmap_item_free(void *authorized_client)
{
  rend_authorized_client_free(authorized_client);
}

Nick Mathewson's avatar
Nick Mathewson committed
149
/** Release the storage held by <b>service</b>.
150
 */
151
152
static void
rend_service_free(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
153
{
154
155
156
  if (!service)
    return;

157
158
159
160
  tor_free(service->directory);
  SMARTLIST_FOREACH(service->ports, void*, p, tor_free(p));
  smartlist_free(service->ports);
  if (service->private_key)
161
    crypto_pk_free(service->private_key);
162
163
164
165
166
  if (service->intro_nodes) {
    SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro,
      rend_intro_point_free(intro););
    smartlist_free(service->intro_nodes);
  }
167
168

  rend_service_descriptor_free(service->desc);
169
170
171
172
173
  if (service->clients) {
    SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, c,
      rend_authorized_client_free(c););
    smartlist_free(service->clients);
  }
Robert Ransom's avatar
Robert Ransom committed
174
  digestmap_free(service->accepted_intro_dh_parts, _tor_free);
175
  tor_free(service);
Nick Mathewson's avatar
Nick Mathewson committed
176
177
}

Roger Dingledine's avatar
Roger Dingledine committed
178
/** Release all the storage held in rend_service_list.
179
 */
180
181
void
rend_service_free_all(void)
Nick Mathewson's avatar
Nick Mathewson committed
182
{
183
  if (!rend_service_list)
Nick Mathewson's avatar
Nick Mathewson committed
184
    return;
185

Nick Mathewson's avatar
Nick Mathewson committed
186
187
  SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
                    rend_service_free(ptr));
Nick Mathewson's avatar
Nick Mathewson committed
188
  smartlist_free(rend_service_list);
189
  rend_service_list = NULL;
Nick Mathewson's avatar
Nick Mathewson committed
190
191
}

Nick Mathewson's avatar
Nick Mathewson committed
192
/** Validate <b>service</b> and add it to rend_service_list if possible.
193
 */
194
static void
Roger Dingledine's avatar
Roger Dingledine committed
195
rend_add_service(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
196
197
198
199
{
  int i;
  rend_service_port_config_t *p;

200
  service->intro_nodes = smartlist_new();
Nick Mathewson's avatar
Nick Mathewson committed
201

Nick Mathewson's avatar
Nick Mathewson committed
202
203
  if (service->auth_type != REND_NO_AUTH &&
      smartlist_len(service->clients) == 0) {
204
205
    log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but no "
                        "clients; ignoring.",
206
             escaped(service->directory));
207
208
209
210
    rend_service_free(service);
    return;
  }

Nick Mathewson's avatar
Nick Mathewson committed
211
  if (!smartlist_len(service->ports)) {
212
213
    log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured; "
             "ignoring.",
214
             escaped(service->directory));
Nick Mathewson's avatar
Nick Mathewson committed
215
216
    rend_service_free(service);
  } else {
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
    int dupe = 0;
    /* XXX This duplicate check has two problems:
     *
     * a) It's O(n^2), but the same comment from the bottom of
     *    rend_config_services() should apply.
     *
     * b) We only compare directory paths as strings, so we can't
     *    detect two distinct paths that specify the same directory
     *    (which can arise from symlinks, case-insensitivity, bind
     *    mounts, etc.).
     *
     * It also can't detect that two separate Tor instances are trying
     * to use the same HiddenServiceDir; for that, we would need a
     * lock file.  But this is enough to detect a simple mistake that
     * at least one person has actually made.
     */
    SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
                      dupe = dupe ||
                             !strcmp(ptr->directory, service->directory));
    if (dupe) {
      log_warn(LD_REND, "Another hidden service is already configured for "
               "directory %s, ignoring.", service->directory);
      rend_service_free(service);
      return;
    }
Nick Mathewson's avatar
Nick Mathewson committed
242
    smartlist_add(rend_service_list, service);
243
244
    log_debug(LD_REND,"Configuring service with directory \"%s\"",
              service->directory);
Nick Mathewson's avatar
Nick Mathewson committed
245
246
    for (i = 0; i < smartlist_len(service->ports); ++i) {
      p = smartlist_get(service->ports, i);
247
      log_debug(LD_REND,"Service maps port %d to %s:%d",
248
                p->virtual_port, fmt_addr(&p->real_addr), p->real_port);
Nick Mathewson's avatar
Nick Mathewson committed
249
250
251
252
    }
  }
}

Roger Dingledine's avatar
Roger Dingledine committed
253
/** Parses a real-port to virtual-port mapping and returns a new
254
255
256
 * rend_service_port_config_t.
 *
 * The format is: VirtualPort (IP|RealPort|IP:RealPort)?
Nick Mathewson's avatar
Nick Mathewson committed
257
258
 *
 * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
Nick Mathewson's avatar
Nick Mathewson committed
259
 */
260
261
static rend_service_port_config_t *
parse_port_config(const char *string)
Nick Mathewson's avatar
Nick Mathewson committed
262
{
263
  smartlist_t *sl;
264
  int virtport;
265
266
  int realport;
  uint16_t p;
267
  tor_addr_t addr;
268
269
270
  const char *addrport;
  rend_service_port_config_t *result = NULL;

271
  sl = smartlist_new();
272
273
  smartlist_split_string(sl, string, " ",
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
274
  if (smartlist_len(sl) < 1 || smartlist_len(sl) > 2) {
275
    log_warn(LD_CONFIG, "Bad syntax in hidden service port configuration.");
276
    goto err;
Nick Mathewson's avatar
Nick Mathewson committed
277
  }
278

279
280
281
282
  virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
  if (!virtport) {
    log_warn(LD_CONFIG, "Missing or invalid port %s in hidden service port "
             "configuration", escaped(smartlist_get(sl,0)));
283
    goto err;
Nick Mathewson's avatar
Nick Mathewson committed
284
  }
285
286

  if (smartlist_len(sl) == 1) {
Nick Mathewson's avatar
Nick Mathewson committed
287
288
    /* No addr:port part; use default. */
    realport = virtport;
289
    tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
290
  } else {
291
292
    addrport = smartlist_get(sl,1);
    if (strchr(addrport, ':') || strchr(addrport, '.')) {
293
      if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
294
295
        log_warn(LD_CONFIG,"Unparseable address in hidden service port "
                 "configuration.");
296
297
298
299
300
        goto err;
      }
      realport = p?p:virtport;
    } else {
      /* No addr:port, no addr -- must be port. */
301
302
303
304
      realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL);
      if (!realport) {
        log_warn(LD_CONFIG,"Unparseable or out-of-range port %s in hidden "
                 "service port configuration.", escaped(addrport));
305
        goto err;
306
      }
307
      tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
308
    }
Nick Mathewson's avatar
Nick Mathewson committed
309
310
311
312
313
  }

  result = tor_malloc(sizeof(rend_service_port_config_t));
  result->virtual_port = virtport;
  result->real_port = realport;
314
  tor_addr_copy(&result->real_addr, &addr);
315
316
317
 err:
  SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
  smartlist_free(sl);
Nick Mathewson's avatar
Nick Mathewson committed
318
319
320
  return result;
}

Roger Dingledine's avatar
Roger Dingledine committed
321
/** Set up rend_service_list, based on the values of HiddenServiceDir and
Nick Mathewson's avatar
Nick Mathewson committed
322
 * HiddenServicePort in <b>options</b>.  Return 0 on success and -1 on
323
324
 * failure.  (If <b>validate_only</b> is set, parse, warn and return as
 * normal, but don't actually change the configured services.)
Nick Mathewson's avatar
Nick Mathewson committed
325
 */
326
int
327
rend_config_services(const or_options_t *options, int validate_only)
Nick Mathewson's avatar
Nick Mathewson committed
328
{
329
  config_line_t *line;
Nick Mathewson's avatar
Nick Mathewson committed
330
331
  rend_service_t *service = NULL;
  rend_service_port_config_t *portcfg;
332
  smartlist_t *old_service_list = NULL;
333

334
  if (!validate_only) {
335
    old_service_list = rend_service_list;
336
    rend_service_list = smartlist_new();
337
  }
Nick Mathewson's avatar
Nick Mathewson committed
338
339
340

  for (line = options->RendConfigLines; line; line = line->next) {
    if (!strcasecmp(line->key, "HiddenServiceDir")) {
341
      if (service) { /* register the one we just finished parsing */
342
343
344
        if (validate_only)
          rend_service_free(service);
        else
Roger Dingledine's avatar
Roger Dingledine committed
345
          rend_add_service(service);
346
      }
Nick Mathewson's avatar
Nick Mathewson committed
347
348
      service = tor_malloc_zero(sizeof(rend_service_t));
      service->directory = tor_strdup(line->value);
349
      service->ports = smartlist_new();
350
      service->intro_period_started = time(NULL);
351
      service->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
352
353
354
      continue;
    }
    if (!service) {
355
356
      log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
               line->key);
357
358
359
360
      rend_service_free(service);
      return -1;
    }
    if (!strcasecmp(line->key, "HiddenServicePort")) {
Nick Mathewson's avatar
Nick Mathewson committed
361
362
      portcfg = parse_port_config(line->value);
      if (!portcfg) {
Roger Dingledine's avatar
tabs    
Roger Dingledine committed
363
364
        rend_service_free(service);
        return -1;
Nick Mathewson's avatar
Nick Mathewson committed
365
366
      }
      smartlist_add(service->ports, portcfg);
367
368
369
370
371
372
    } else if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
      /* Parse auth type and comma-separated list of client names and add a
       * rend_authorized_client_t for each client to the service's list
       * of authorized clients. */
      smartlist_t *type_names_split, *clients;
      const char *authname;
Nick Mathewson's avatar
Nick Mathewson committed
373
374
      int num_clients;
      if (service->auth_type != REND_NO_AUTH) {
375
376
377
378
379
        log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient "
                 "lines for a single service.");
        rend_service_free(service);
        return -1;
      }
380
      type_names_split = smartlist_new();
Nick Mathewson's avatar
Nick Mathewson committed
381
      smartlist_split_string(type_names_split, line->value, " ", 0, 2);
382
383
384
385
386
387
388
389
390
      if (smartlist_len(type_names_split) < 1) {
        log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This "
                         "should have been prevented when parsing the "
                         "configuration.");
        smartlist_free(type_names_split);
        rend_service_free(service);
        return -1;
      }
      authname = smartlist_get(type_names_split, 0);
Nick Mathewson's avatar
Nick Mathewson committed
391
      if (!strcasecmp(authname, "basic")) {
392
        service->auth_type = REND_BASIC_AUTH;
Nick Mathewson's avatar
Nick Mathewson committed
393
      } else if (!strcasecmp(authname, "stealth")) {
394
395
396
        service->auth_type = REND_STEALTH_AUTH;
      } else {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
Nick Mathewson's avatar
Nick Mathewson committed
397
398
                 "unrecognized auth-type '%s'. Only 'basic' or 'stealth' "
                 "are recognized.",
399
400
401
402
403
404
                 (char *) smartlist_get(type_names_split, 0));
        SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
        smartlist_free(type_names_split);
        rend_service_free(service);
        return -1;
      }
405
      service->clients = smartlist_new();
406
407
      if (smartlist_len(type_names_split) < 2) {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
Nick Mathewson's avatar
Nick Mathewson committed
408
                            "auth-type '%s', but no client names.",
409
                 service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
410
411
412
413
        SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
        smartlist_free(type_names_split);
        continue;
      }
414
      clients = smartlist_new();
415
      smartlist_split_string(clients, smartlist_get(type_names_split, 1),
Nick Mathewson's avatar
Nick Mathewson committed
416
                             ",", SPLIT_SKIP_SPACE, 0);
417
418
      SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
      smartlist_free(type_names_split);
Nick Mathewson's avatar
Nick Mathewson committed
419
420
421
422
423
424
425
426
427
428
      /* Remove duplicate client names. */
      num_clients = smartlist_len(clients);
      smartlist_sort_strings(clients);
      smartlist_uniq_strings(clients);
      if (smartlist_len(clients) < num_clients) {
        log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
                            "duplicate client name(s); removing.",
                 num_clients - smartlist_len(clients));
        num_clients = smartlist_len(clients);
      }
429
430
431
432
      SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name)
      {
        rend_authorized_client_t *client;
        size_t len = strlen(client_name);
Nick Mathewson's avatar
Nick Mathewson committed
433
        if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) {
434
435
          log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
                              "illegal client name: '%s'. Length must be "
Nick Mathewson's avatar
Nick Mathewson committed
436
437
                              "between 1 and %d characters.",
                   client_name, REND_CLIENTNAME_MAX_LEN);
438
439
440
441
442
443
444
445
          SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
          smartlist_free(clients);
          rend_service_free(service);
          return -1;
        }
        if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
          log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
                              "illegal client name: '%s'. Valid "
Robert Ransom's avatar
Robert Ransom committed
446
                              "characters are [A-Za-z0-9+_-].",
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
                   client_name);
          SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
          smartlist_free(clients);
          rend_service_free(service);
          return -1;
        }
        client = tor_malloc_zero(sizeof(rend_authorized_client_t));
        client->client_name = tor_strdup(client_name);
        smartlist_add(service->clients, client);
        log_debug(LD_REND, "Adding client name '%s'", client_name);
      }
      SMARTLIST_FOREACH_END(client_name);
      SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
      smartlist_free(clients);
      /* Ensure maximum number of clients. */
      if ((service->auth_type == REND_BASIC_AUTH &&
            smartlist_len(service->clients) > 512) ||
          (service->auth_type == REND_STEALTH_AUTH &&
            smartlist_len(service->clients) > 16)) {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
                            "client authorization entries, but only a "
                            "maximum of %d entries is allowed for "
Nick Mathewson's avatar
Nick Mathewson committed
469
                            "authorization type '%s'.",
470
471
                 smartlist_len(service->clients),
                 service->auth_type == REND_BASIC_AUTH ? 512 : 16,
472
                 service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
473
474
475
        rend_service_free(service);
        return -1;
      }
476
477
    } else {
      tor_assert(!strcasecmp(line->key, "HiddenServiceVersion"));
478
479
480
481
482
      if (strcmp(line->value, "2")) {
        log_warn(LD_CONFIG,
                 "The only supported HiddenServiceVersion is 2.");
        rend_service_free(service);
        return -1;
483
      }
Nick Mathewson's avatar
Nick Mathewson committed
484
485
    }
  }
486
487
488
489
  if (service) {
    if (validate_only)
      rend_service_free(service);
    else
Roger Dingledine's avatar
Roger Dingledine committed
490
      rend_add_service(service);
491
  }
Nick Mathewson's avatar
Nick Mathewson committed
492

493
494
495
496
  /* If this is a reload and there were hidden services configured before,
   * keep the introduction points that are still needed and close the
   * other ones. */
  if (old_service_list && !validate_only) {
497
    smartlist_t *surviving_services = smartlist_new();
498
499
500
501
502
    circuit_t *circ;

    /* Copy introduction points to new services. */
    /* XXXX This is O(n^2), but it's only called on reconfigure, so it's
     * probably ok? */
503
504
    SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, new) {
      SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
505
        if (!strcmp(old->directory, new->directory)) {
506
507
508
509
510
          smartlist_add_all(new->intro_nodes, old->intro_nodes);
          smartlist_clear(old->intro_nodes);
          smartlist_add(surviving_services, old);
          break;
        }
511
512
      } SMARTLIST_FOREACH_END(old);
    } SMARTLIST_FOREACH_END(new);
513
514
515
516
517
518
519
520
521
522
523
524
525
526

    /* Close introduction circuits of services we don't serve anymore. */
    /* XXXX it would be nicer if we had a nicer abstraction to use here,
     * so we could just iterate over the list of services to close, but
     * once again, this isn't critical-path code. */
    for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
      if (!circ->marked_for_close &&
          circ->state == CIRCUIT_STATE_OPEN &&
          (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
           circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
        origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
        int keep_it = 0;
        tor_assert(oc->rend_data);
        SMARTLIST_FOREACH(surviving_services, rend_service_t *, ptr, {
527
          if (tor_memeq(ptr->pk_digest, oc->rend_data->rend_pk_digest,
528
                      DIGEST_LEN)) {
529
530
531
532
533
534
            keep_it = 1;
            break;
          }
        });
        if (keep_it)
          continue;
535
        log_info(LD_REND, "Closing intro point %s for service %s.",
536
537
                 safe_str_client(extend_info_describe(
                                            oc->build_state->chosen_exit)),
538
                 oc->rend_data->onion_address);
539
540
541
542
543
544
545
546
547
548
        circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
        /* XXXX Is there another reason we should use here? */
      }
    }
    smartlist_free(surviving_services);
    SMARTLIST_FOREACH(old_service_list, rend_service_t *, ptr,
                      rend_service_free(ptr));
    smartlist_free(old_service_list);
  }

Nick Mathewson's avatar
Nick Mathewson committed
549
550
551
  return 0;
}

Nick Mathewson's avatar
Nick Mathewson committed
552
/** Replace the old value of <b>service</b>-\>desc with one that reflects
Nick Mathewson's avatar
Nick Mathewson committed
553
 * the other fields in service.
Nick Mathewson's avatar
Nick Mathewson committed
554
 */
555
556
static void
rend_service_update_descriptor(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
557
558
{
  rend_service_descriptor_t *d;
559
  origin_circuit_t *circ;
560
  int i;
561
562
563
564

  rend_service_descriptor_free(service->desc);
  service->desc = NULL;

565
  d = service->desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
Nick Mathewson's avatar
Nick Mathewson committed
566
567
  d->pk = crypto_pk_dup_key(service->private_key);
  d->timestamp = time(NULL);
568
  d->intro_nodes = smartlist_new();
569
570
  /* Support intro protocols 2 and 3. */
  d->protocols = (1 << 2) + (1 << 3);
571

572
573
574
  for (i = 0; i < smartlist_len(service->intro_nodes); ++i) {
    rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i);
    rend_intro_point_t *intro_desc;
575
576
577
578

    /* This intro point won't be listed in the descriptor... */
    intro_svc->listed_in_last_desc = 0;

579
580
581
582
583
    if (intro_svc->time_expiring != -1) {
      /* This intro point is expiring.  Don't list it. */
      continue;
    }

584
    circ = find_intro_circuit(intro_svc, service->pk_digest);
585
586
    if (!circ || circ->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
      /* This intro point's circuit isn't finished yet.  Don't list it. */
587
      continue;
588
    }
589

590
591
    /* ...unless this intro point is listed in the descriptor. */
    intro_svc->listed_in_last_desc = 1;
592

Robert Ransom's avatar
Robert Ransom committed
593
594
    /* We have an entirely established intro circuit.  Publish it in
     * our descriptor. */
595
596
597
598
599
    intro_desc = tor_malloc_zero(sizeof(rend_intro_point_t));
    intro_desc->extend_info = extend_info_dup(intro_svc->extend_info);
    if (intro_svc->intro_key)
      intro_desc->intro_key = crypto_pk_dup_key(intro_svc->intro_key);
    smartlist_add(d->intro_nodes, intro_desc);
600
601
602
603
604
605
606

    if (intro_svc->time_published == -1) {
      /* We are publishing this intro point in a descriptor for the
       * first time -- note the current time in the service's copy of
       * the intro point. */
      intro_svc->time_published = time(NULL);
    }
Nick Mathewson's avatar
Nick Mathewson committed
607
608
609
  }
}

610
611
612
/** Load and/or generate private keys for all hidden services, possibly
 * including keys for client authorization.  Return 0 on success, -1 on
 * failure.
Nick Mathewson's avatar
Nick Mathewson committed
613
 */
614
615
int
rend_service_load_keys(void)
Nick Mathewson's avatar
Nick Mathewson committed
616
{
617
  int r = 0;
Nick Mathewson's avatar
Nick Mathewson committed
618
  char fname[512];
619
  char buf[1500];
Nick Mathewson's avatar
Nick Mathewson committed
620

621
  SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) {
Nick Mathewson's avatar
Nick Mathewson committed
622
623
    if (s->private_key)
      continue;
624
625
    log_info(LD_REND, "Loading hidden-service keys from \"%s\"",
             s->directory);
Nick Mathewson's avatar
Nick Mathewson committed
626

Nick Mathewson's avatar
Nick Mathewson committed
627
    /* Check/create directory */
628
    if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
Nick Mathewson's avatar
Nick Mathewson committed
629
630
631
      return -1;

    /* Load key */
632
    if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
633
634
        strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname))
                                                  >= sizeof(fname)) {
635
636
      log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
               s->directory);
Nick Mathewson's avatar
Nick Mathewson committed
637
638
      return -1;
    }
639
    s->private_key = init_key_from_file(fname, 1, LOG_ERR);
Nick Mathewson's avatar
Nick Mathewson committed
640
641
642
643
644
    if (!s->private_key)
      return -1;

    /* Create service file */
    if (rend_get_service_id(s->private_key, s->service_id)<0) {
645
      log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
Nick Mathewson's avatar
Nick Mathewson committed
646
647
      return -1;
    }
648
    if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
649
      log_warn(LD_BUG, "Couldn't compute hash of public key.");
650
651
      return -1;
    }
652
    if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
653
654
        strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname))
                                                  >= sizeof(fname)) {
655
656
      log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
               " \"%s\".", s->directory);
Nick Mathewson's avatar
Nick Mathewson committed
657
658
      return -1;
    }
659
    tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
660
661
    if (write_str_to_file(fname,buf,0)<0) {
      log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
Nick Mathewson's avatar
Nick Mathewson committed
662
      return -1;
663
664
665
    }

    /* If client authorization is configured, load or generate keys. */
Nick Mathewson's avatar
Nick Mathewson committed
666
    if (s->auth_type != REND_NO_AUTH) {
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
      char *client_keys_str = NULL;
      strmap_t *parsed_clients = strmap_new();
      char cfname[512];
      FILE *cfile, *hfile;
      open_file_t *open_cfile = NULL, *open_hfile = NULL;

      /* Load client keys and descriptor cookies, if available. */
      if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys",
                       s->directory)<0) {
        log_warn(LD_CONFIG, "Directory name too long to store client keys "
                 "file: \"%s\".", s->directory);
        goto err;
      }
      client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
      if (client_keys_str) {
        if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
          log_warn(LD_CONFIG, "Previously stored client_keys file could not "
                              "be parsed.");
          goto err;
        } else {
          log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
                   strmap_size(parsed_clients));
          tor_free(client_keys_str);
        }
      }

      /* Prepare client_keys and hostname files. */
694
695
      if (!(cfile = start_writing_to_stdio_file(cfname,
                                                OPEN_FLAGS_REPLACE | O_TEXT,
696
697
698
699
700
                                                0600, &open_cfile))) {
        log_warn(LD_CONFIG, "Could not open client_keys file %s",
                 escaped(cfname));
        goto err;
      }
701
702
      if (!(hfile = start_writing_to_stdio_file(fname,
                                                OPEN_FLAGS_REPLACE | O_TEXT,
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
                                                0600, &open_hfile))) {
        log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(fname));
        goto err;
      }

      /* Either use loaded keys for configured clients or generate new
       * ones if a client is new. */
      SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client)
      {
        char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
        char service_id[16+1];
        rend_authorized_client_t *parsed =
            strmap_get(parsed_clients, client->client_name);
        int written;
        size_t len;
        /* Copy descriptor cookie from parsed entry or create new one. */
        if (parsed) {
          memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
                 REND_DESC_COOKIE_LEN);
        } else {
          crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
        }
        if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
                          client->descriptor_cookie,
                          REND_DESC_COOKIE_LEN) < 0) {
          log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
          strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
          return -1;
        }
        /* Copy client key from parsed entry or create new one if required. */
        if (parsed && parsed->client_key) {
          client->client_key = crypto_pk_dup_key(parsed->client_key);
        } else if (s->auth_type == REND_STEALTH_AUTH) {
          /* Create private key for client. */
737
738
          crypto_pk_t *prkey = NULL;
          if (!(prkey = crypto_pk_new())) {
739
740
741
742
743
            log_warn(LD_BUG,"Error constructing client key");
            goto err;
          }
          if (crypto_pk_generate_key(prkey)) {
            log_warn(LD_BUG,"Error generating client key");
744
            crypto_pk_free(prkey);
745
746
747
748
            goto err;
          }
          if (crypto_pk_check_key(prkey) <= 0) {
            log_warn(LD_BUG,"Generated client key seems invalid");
749
            crypto_pk_free(prkey);
750
751
752
753
754
755
756
757
758
759
760
761
762
763
            goto err;
          }
          client->client_key = prkey;
        }
        /* Add entry to client_keys file. */
        desc_cook_out[strlen(desc_cook_out)-1] = '\0'; /* Remove newline. */
        written = tor_snprintf(buf, sizeof(buf),
                               "client-name %s\ndescriptor-cookie %s\n",
                               client->client_name, desc_cook_out);
        if (written < 0) {
          log_warn(LD_BUG, "Could not write client entry.");
          goto err;
        }
        if (client->client_key) {
764
          char *client_key_out = NULL;
765
766
767
768
          crypto_pk_write_private_key_to_string(client->client_key,
                                                &client_key_out, &len);
          if (rend_get_service_id(client->client_key, service_id)<0) {
            log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
769
            tor_free(client_key_out);
770
771
772
773
            goto err;
          }
          written = tor_snprintf(buf + written, sizeof(buf) - written,
                                 "client-key\n%s", client_key_out);
774
          tor_free(client_key_out);
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
          if (written < 0) {
            log_warn(LD_BUG, "Could not write client entry.");
            goto err;
          }
        }

        if (fputs(buf, cfile) < 0) {
          log_warn(LD_FS, "Could not append client entry to file: %s",
                   strerror(errno));
          goto err;
        }

        /* Add line to hostname file. */
        if (s->auth_type == REND_BASIC_AUTH) {
          /* Remove == signs (newline has been removed above). */
          desc_cook_out[strlen(desc_cook_out)-2] = '\0';
          tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
                       s->service_id, desc_cook_out, client->client_name);
        } else {
          char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
          memcpy(extended_desc_cookie, client->descriptor_cookie,
                 REND_DESC_COOKIE_LEN);
Nick Mathewson's avatar
Nick Mathewson committed
797
798
          extended_desc_cookie[REND_DESC_COOKIE_LEN] =
              ((int)s->auth_type - 1) << 4;
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
          if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
                            extended_desc_cookie,
                            REND_DESC_COOKIE_LEN+1) < 0) {
            log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
            goto err;
          }
          desc_cook_out[strlen(desc_cook_out)-3] = '\0'; /* Remove A= and
                                                            newline. */
          tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
                       service_id, desc_cook_out, client->client_name);
        }

        if (fputs(buf, hfile)<0) {
          log_warn(LD_FS, "Could not append host entry to file: %s",
                   strerror(errno));
          goto err;
        }
      }
      SMARTLIST_FOREACH_END(client);

      goto done;
    err:
      r = -1;
    done:
      tor_free(client_keys_str);
      strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
      if (r<0) {
826
827
828
829
        if (open_cfile)
          abort_writing_to_file(open_cfile);
        if (open_hfile)
          abort_writing_to_file(open_hfile);
830
831
832
833
834
835
836
837
        return r;
      } else {
        finish_writing_to_file(open_cfile);
        finish_writing_to_file(open_hfile);
      }
    }
  } SMARTLIST_FOREACH_END(s);
  return r;
Nick Mathewson's avatar
Nick Mathewson committed
838
}
839

840
841
/** Return the service whose public key has a digest of <b>digest</b>, or
 * NULL if no such service exists.
842
 */
843
static rend_service_t *
844
rend_service_get_by_pk_digest(const char* digest)
845
{
Nick Mathewson's avatar
Nick Mathewson committed
846
  SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s,
847
                    if (tor_memeq(s->pk_digest,digest,DIGEST_LEN))
848
                        return s);
849
850
851
  return NULL;
}

852
853
854
855
/** Return 1 if any virtual port in <b>service</b> wants a circuit
 * to have good uptime. Else return 0.
 */
static int
856
857
rend_service_requires_uptime(rend_service_t *service)
{
858
859
860
861
862
  int i;
  rend_service_port_config_t *p;

  for (i=0; i < smartlist_len(service->ports); ++i) {
    p = smartlist_get(service->ports, i);
863
864
    if (smartlist_string_num_isin(get_options()->LongLivedPorts,
                                  p->virtual_port))
865
866
867
868
869
      return 1;
  }
  return 0;
}

870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
/** Check client authorization of a given <b>descriptor_cookie</b> for
 * <b>service</b>. Return 1 for success and 0 for failure. */
static int
rend_check_authorization(rend_service_t *service,
                         const char *descriptor_cookie)
{
  rend_authorized_client_t *auth_client = NULL;
  tor_assert(service);
  tor_assert(descriptor_cookie);
  if (!service->clients) {
    log_warn(LD_BUG, "Can't check authorization for a service that has no "
                     "authorized clients configured.");
    return 0;
  }

  /* Look up client authorization by descriptor cookie. */
  SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, client, {
887
    if (tor_memeq(client->descriptor_cookie, descriptor_cookie,
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
                REND_DESC_COOKIE_LEN)) {
      auth_client = client;
      break;
    }
  });
  if (!auth_client) {
    char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
    base64_encode(descriptor_cookie_base64, sizeof(descriptor_cookie_base64),
                  descriptor_cookie, REND_DESC_COOKIE_LEN);
    log_info(LD_REND, "No authorization found for descriptor cookie '%s'! "
                      "Dropping cell!",
             descriptor_cookie_base64);
    return 0;
  }

  /* Allow the request. */
  log_debug(LD_REND, "Client %s authorized for service %s.",
            auth_client->client_name, service->service_id);
  return 1;
}

/** Remove elements from <b>service</b>'s replay cache that are old enough to
 * be noticed by timestamp checking. */
static void
Robert Ransom's avatar
Robert Ransom committed
912
clean_accepted_intro_dh_parts(rend_service_t *service, time_t now)
913
914
915
{
  const time_t cutoff = now - REND_REPLAY_TIME_INTERVAL;

Robert Ransom's avatar
Robert Ransom committed
916
917
  service->last_cleaned_accepted_intro_dh_parts = now;
  if (!service->accepted_intro_dh_parts)
918
919
    return;

Robert Ransom's avatar
Robert Ransom committed
920
921
  DIGESTMAP_FOREACH_MODIFY(service->accepted_intro_dh_parts, digest,
                           time_t *, t) {
922
923
924
925
926
927
928
    if (*t < cutoff) {
      tor_free(t);
      MAP_DEL_CURRENT(digest);
    }
  } DIGESTMAP_FOREACH_END;
}

929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
/** Called when <b>intro</b> will soon be removed from
 * <b>service</b>'s list of intro points. */
static void
rend_service_note_removing_intro_point(rend_service_t *service,
                                       rend_intro_point_t *intro)
{
  time_t now = time(NULL);

  /* Don't process an intro point twice here. */
  if (intro->rend_service_note_removing_intro_point_called) {
    return;
  } else {
    intro->rend_service_note_removing_intro_point_called = 1;
  }

  /* Update service->n_intro_points_wanted based on how long intro
   * lasted and how many introductions it handled. */
  if (intro->time_published == -1) {
    /* This intro point was never used.  Don't change
     * n_intro_points_wanted. */
  } else {
    /* We want to increase the number of introduction points service
     * operates if intro was heavily used, or decrease the number of
     * intro points if intro was lightly used.
     *
     * We consider an intro point's target 'usage' to be
     * INTRO_POINT_LIFETIME_INTRODUCTIONS introductions in
     * INTRO_POINT_LIFETIME_MIN_SECONDS seconds.  To calculate intro's
     * fraction of target usage, we divide the fraction of
     * _LIFETIME_INTRODUCTIONS introductions that it has handled by
     * the fraction of _LIFETIME_MIN_SECONDS for which it existed.
     *
961
962
963
964
965
966
967
968
     * Then we multiply that fraction of desired usage by a fudge
     * factor of 1.5, to decide how many new introduction points
     * should ideally replace intro (which is now closed or soon to be
     * closed).  In theory, assuming that introduction load is
     * distributed equally across all intro points and ignoring the
     * fact that different intro points are established and closed at
     * different times, that number of intro points should bring all
     * of our intro points exactly to our target usage.
969
970
971
972
973
974
975
976
     *
     * Then we clamp that number to a number of intro points we might
     * be willing to replace this intro point with and turn it into an
     * integer. then we clamp it again to the number of new intro
     * points we could establish now, then we adjust
     * service->n_intro_points_wanted and let rend_services_introduce
     * create the new intro points we want (if any).
     */
977
978
979
980
981
982
983
984
    const double intro_point_usage =
      intro_point_accepted_intro_count(intro) /
      (double)(now - intro->time_published);
    const double intro_point_target_usage =
      INTRO_POINT_LIFETIME_INTRODUCTIONS /
      (double)INTRO_POINT_LIFETIME_MIN_SECONDS;
    const double fractional_n_intro_points_wanted_to_replace_this_one =
      (1.5 * (intro_point_usage / intro_point_target_usage));
985
986
987
988
989
990
991
992
993
994
995
    unsigned int n_intro_points_wanted_to_replace_this_one;
    unsigned int n_intro_points_wanted_now;
    unsigned int n_intro_points_really_wanted_now;
    int n_intro_points_really_replacing_this_one;

    if (fractional_n_intro_points_wanted_to_replace_this_one >
        NUM_INTRO_POINTS_MAX) {
      n_intro_points_wanted_to_replace_this_one = NUM_INTRO_POINTS_MAX;
    } else if (fractional_n_intro_points_wanted_to_replace_this_one < 0) {
      n_intro_points_wanted_to_replace_this_one = 0;
    } else {
996
      n_intro_points_wanted_to_replace_this_one = (unsigned)
997
998
999
1000
        fractional_n_intro_points_wanted_to_replace_this_one;
    }

    n_intro_points_wanted_now =
For faster browsing, not all history is shown. View entire blame