config.c 45.3 KB
Newer Older
1
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2
3
4
/* See LICENSE for licensing information */
/* $Id$ */

Nick Mathewson's avatar
Nick Mathewson committed
5
6
7
8
9
10
11
/**
 * /file config.c
 *
 * /brief Code to parse and interpret configuration files.
 *
 **/

Roger Dingledine's avatar
Roger Dingledine committed
12
#include "or.h"
13
14
15
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
Roger Dingledine's avatar
Roger Dingledine committed
16

Nick Mathewson's avatar
Nick Mathewson committed
17
18
/** Enumeration of types which option values can take */
typedef enum config_type_t {
19
20
21
22
23
24
25
  CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
  CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
  CONFIG_TYPE_DOUBLE,       /**< A floating-point value */
  CONFIG_TYPE_BOOL,         /**< A boolean value, expressed as 0 or 1. */
  CONFIG_TYPE_CSV,          /**< A list of strings, separated by commas and optional
                              * whitespace. */
  CONFIG_TYPE_LINELIST,     /**< Uninterpreted config lines */
26
27
28
29
30
  CONFIG_TYPE_LINELIST_S,   /**< Uninterpreted, context-sensitive config lines,
                             * mixed with other keywords. */
  CONFIG_TYPE_LINELIST_V,   /**< Catch-all "virtual" option to summarize
                             * context-sensitive config lines when fetching.
                             */
31
  CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
Nick Mathewson's avatar
Nick Mathewson committed
32
} config_type_t;
33

Nick Mathewson's avatar
Nick Mathewson committed
34
/* An abbreviation for a configuration option allowed on the command line */
35
typedef struct config_abbrev_t {
36
37
  const char *abbreviated;
  const char *full;
38
  int commandline_only;
39
40
} config_abbrev_t;

41
42
43
44
/* Handy macro for declaring "In the config file or on the command line,
 * you can abbreviate <b>tok</b>s as <b>tok</b>". */
#define PLURAL(tok) { #tok, #tok "s", 0 }

Nick Mathewson's avatar
Nick Mathewson committed
45
/* A list of command-line abbreviations. */
46
static config_abbrev_t config_abbrevs[] = {
47
48
49
50
51
52
53
54
  PLURAL(ExitNode),
  PLURAL(EntryNodes),
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
55
56
57
  { "l", "LogLevel", 1},
  { "BandwidthRate", "BandwidthRateBytes", 1},
  { "BandwidthBurst", "BandwidthBurstBytes", 1},
58
  { NULL, NULL , 0},
59
};
60
#undef PLURAL
61

62
/** A variable allowed in the configuration file or on the command line. */
63
typedef struct config_var_t {
64
65
66
67
  const char *name; /**< The full keyword (case insensitive). */
  config_type_t type; /**< How to interpret the type and turn it into a value. */
  off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
  const char *initvalue; /**< String (or null) describing initial value. */
68
69
} config_var_t;

Nick Mathewson's avatar
Nick Mathewson committed
70
/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
Nick Mathewson's avatar
Nick Mathewson committed
71
#define STRUCT_OFFSET(tp, member) ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
Nick Mathewson's avatar
Nick Mathewson committed
72
73
74
75
/** An entry for config_vars: "The option <b>name</b> has type
 * CONFIG_TYPE_<b>conftype</b>, and corresponds to
 * or_options_t.<b>member</b>"
 */
76
77
#define VAR(name,conftype,member,initvalue) \
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), initvalue }
Nick Mathewson's avatar
Nick Mathewson committed
78
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
79
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
80

Nick Mathewson's avatar
Nick Mathewson committed
81
82
83
84
/** Array of configuration options.  Until we disallow nonstandard
 * abbreviations, order is significant, since the first matching option will
 * be chosen first.
 */
85
static config_var_t config_vars[] = {
86
  VAR("Address",             STRING,   Address,              NULL),
87
  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
88
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
89
90
  VAR("BandwidthRateBytes",  UINT,     BandwidthRateBytes,   "800000"),
  VAR("BandwidthBurstBytes", UINT,     BandwidthBurstBytes,  "50000000"),
91
92
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
93
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
  VAR("DirPort",             UINT,     DirPort,              "0"),
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
  VAR("DirFetchPostPeriod",  UINT,     DirFetchPostPeriod,   "600"),
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
108
  VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
109
110
111
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
  VAR("Group",               STRING,   Group,                NULL),
112
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
113
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
114
115
116
117
118
  VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines,    NULL),
  VAR("HiddenServiceDir",    LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServicePort",   LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServiceNodes",  LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
119
120
  VAR("IgnoreVersion",       BOOL,     IgnoreVersion,        "0"),
  VAR("KeepalivePeriod",     UINT,     KeepalivePeriod,      "300"),
121
122
123
  VAR("LogOptions",          LINELIST_V, LogOptions,         NULL),
  VAR("LogLevel",            LINELIST_S, LogOptions,         NULL),
  VAR("LogFile",             LINELIST_S, LogOptions,         NULL),
124
  OBSOLETE("LinkPadding"),
125
126
127
128
129
130
131
132
133
134
135
136
137
  VAR("MaxConn",             UINT,     MaxConn,              "1024"),
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
  VAR("MonthlyAccountingStart",UINT,   AccountingStart,      "0"),
  VAR("AccountingMaxKB",     UINT,     AccountingMaxKB,      "0"),
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NewCircuitPeriod",    UINT,     NewCircuitPeriod,     "30"),
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
  VAR("ORPort",              UINT,     ORPort,               "0"),
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PidFile",             STRING,   PidFile,              NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
138
  OBSOLETE("RouterFile"),
139
140
141
142
143
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
144
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
145
146
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
147
  VAR("SysLog",              LINELIST_S, LogOptions,         NULL),
148
  OBSOLETE("TrafficShaping"),
149
150
  VAR("User",                STRING,   User,                 NULL),
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
151
152
153
154
};
#undef VAR
#undef OBSOLETE

Nick Mathewson's avatar
Nick Mathewson committed
155
/** Largest allowed config line */
156
#define CONFIG_LINE_T_MAXLEN 4096
157

158
static struct config_line_t *config_get_commandlines(int argc, char **argv);
159
static int config_get_lines(FILE *f, struct config_line_t **result);
160
static void config_free_lines(struct config_line_t *front);
161
162
163
164
static int config_assign_line(or_options_t *options, struct config_line_t *c,
                              int reset);
static int config_assign(or_options_t *options, struct config_line_t *list,
                         int reset);
165
static int parse_dir_server_line(const char *line);
Roger Dingledine's avatar
Roger Dingledine committed
166
167
static int parse_redirect_line(or_options_t *options,
                               struct config_line_t *line);
168
static const char *expand_abbrev(const char *option, int commandline_only);
169
static config_var_t *config_find_option(const char *key);
170
static void reset_option(or_options_t *options, config_var_t *var);
171

Nick Mathewson's avatar
Nick Mathewson committed
172
/** If <b>option</b> is an official abbreviation for a longer option,
173
174
175
 * return the longer option.  Otherwise return <b>option</b>.
 * If <b>command_line</b> is set, apply all abbreviations.  Otherwise, only
 * apply abbreviations that work for the config file and the command line. */
176
static const char *
177
expand_abbrev(const char *option, int command_line)
178
179
180
181
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
182
183
    if (!strcmp(option,config_abbrevs[i].abbreviated) &&
        (command_line || !config_abbrevs[i].commandline_only)) {
184
      return config_abbrevs[i].full;
185
    }
186
187
188
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
189

Nick Mathewson's avatar
Nick Mathewson committed
190
/** Helper: Read a list of configuration options from the command line. */
191
192
193
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
194
195
  struct config_line_t *new;
  struct config_line_t *front = NULL;
196
197
198
  char *s;
  int i = 1;

199
  while (i < argc-1) {
200
201
202
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
203
      continue;
204
205
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
206
      continue;
207
208
    }

209
    new = tor_malloc(sizeof(struct config_line_t));
210
    s = argv[i];
211

212
213
    while(*s == '-')
      s++;
214

215
    new->key = tor_strdup(expand_abbrev(s, 1));
216
    new->value = tor_strdup(argv[i+1]);
217
218

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
219
        new->key, new->value);
220
221
222
223
224
225
226
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
227
228
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
229
struct config_line_t *
230
231
232
233
234
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
235

236
237
238
239
240
241
242
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

243
/** Helper: parse the config file and strdup into key/value
244
245
246
 * strings. Set *result to the list, or NULL if parsing the file
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
247
248
249
static int
config_get_lines(FILE *f, struct config_line_t **result)
{
250
251
  struct config_line_t *front = NULL;
  char line[CONFIG_LINE_T_MAXLEN];
252
  int r;
253
  char *key, *value;
254

255
  while ((r = parse_line_from_file(line, sizeof(line), f, &key, &value)) > 0) {
256
    front = config_line_prepend(front, key, value);
Roger Dingledine's avatar
Roger Dingledine committed
257
  }
258
259

  if (r < 0) {
260
261
262
    *result = NULL;
    return -1;
  }
263
264
  *result = front;
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
265
266
}

Nick Mathewson's avatar
Nick Mathewson committed
267
268
269
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
270
271
272
static void
config_free_lines(struct config_line_t *front)
{
273
  struct config_line_t *tmp;
274

275
  while (front) {
276
277
278
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
279
280
281
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
282
283
284
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
285
286
287
288
/** If <b>key</b> is a configuration option, return the corresponding
 * config_var_t.  Otherwise, if <b>key</b> is a non-standard abbreviation,
 * warn, and return the corresponding config_var_t.  Otherwise return NULL.
 */
289
290
291
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
292
  /* First, check for an exact (case-insensitive) match */
293
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
294
    if (!strcasecmp(key, config_vars[i].name))
295
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
296
297
298
299
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
300
301
302
303
304
305
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
          "Tell Nick and Roger to make it official, or just use '%s' instead",
             key, config_vars[i].name);
      return &config_vars[i];
    }
  }
Nick Mathewson's avatar
Nick Mathewson committed
306
  /* Okay, unrecogized options */
307
308
309
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
310
/** If <b>c</b> is a syntactically valid configuration line, update
311
312
313
314
315
 * <b>options</b> with its value and return 0.  Otherwise return -1.
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
316
static int
317
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
318
{
319
  int i, ok;
320
321
  config_var_t *var;
  void *lvalue;
322

323
324
325
326
327
328
329
  var = config_find_option(c->key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", c->key);
    return -1;
  }
  /* Put keyword into canonical case. */
  if (strcmp(var->name, c->key)) {
330
    tor_free(c->key);
331
    c->key = tor_strdup(var->name);
332
333
  }

334
335
336
337
338
  if (reset && !strlen(c->value)) {
    reset_option(options, var);
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
339
  lvalue = ((char*)options) + var->var_offset;
340
  switch(var->type) {
341

342
343
344
345
346
347
348
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds. Skipping.",
          c->key,c->value);
      return 0;
    }
349
    *(int *)lvalue = i;
350
351
352
353
354
355
356
357
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key);
      return 0;
    }
358
    *(int *)lvalue = i;
359
360
361
    break;

  case CONFIG_TYPE_STRING:
362
363
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
364
365
366
    break;

  case CONFIG_TYPE_DOUBLE:
367
    *(double *)lvalue = atof(c->value);
368
369
370
    break;

  case CONFIG_TYPE_CSV:
371
372
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
373

374
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
375
376
377
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

378
379
380
381
382
383
384
385
386

  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
    /* Note: this reverses the order that the lines appear in.  That's
     * just fine, since we build up the list of lines reversed in the
     * first place. */
    *(struct config_line_t**)lvalue =
      config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
    break;
387
388
389
390

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
391
392
393
394
395
396
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
    return -1;
  default:
    tor_assert(0);
    break;
397
  }
398

399
  return 0;
400
401
}

402
403
404
405
406
407
408
409
410
411
412
413
414
/** restore the option named <b>key</b> in options to its default value. */
static void
config_reset_line(or_options_t *options, const char *key)
{
  config_var_t *var;

  var = config_find_option(key);
  if (!var)
    return; /* give error on next pass. */

  reset_option(options, var);
}

415
416
417
418
419
420
421
422
423
424
425
426
427
428
/** Return a canonicalized list of the options assigned for key.
 */
struct config_line_t *
config_get_assigned_option(or_options_t *options, const char *key)
{
  config_var_t *var;
  const void *value;
  char buf[32];
  struct config_line_t *result;

  var = config_find_option(key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
429
430
431
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
432
433
434
  }
  value = ((char*)options) + var->var_offset;

435
436
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
    /* Linelist requires special handling: we just copy and return it. */
    const struct config_line_t *next_in = value;
    struct config_line_t **next_out = &result;
    while (next_in) {
      *next_out = tor_malloc(sizeof(struct config_line_t));
      (*next_out)->key = tor_strdup(next_in->key);
      (*next_out)->value = tor_strdup(next_in->value);
      next_in = next_in->next;
      next_out = &((*next_out)->next);
    }
    (*next_out) = NULL;
    return result;
  }

  result = tor_malloc_zero(sizeof(struct config_line_t));
  result->key = tor_strdup(var->name);
  switch(var->type)
    {
    case CONFIG_TYPE_STRING:
      result->value = tor_strdup(value ? (char*)value : "");
      break;
    case CONFIG_TYPE_UINT:
      tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
      result->value = tor_strdup(buf);
      break;
    case CONFIG_TYPE_DOUBLE:
      tor_snprintf(buf, sizeof(buf), "%f", *(double*)value);
      result->value = tor_strdup(buf);
      break;
    case CONFIG_TYPE_BOOL:
      result->value = tor_strdup(*(int*)value ? "1" : "0");
      break;
    case CONFIG_TYPE_CSV:
      if (value)
        result->value = smartlist_join_strings((smartlist_t*)value,",",0,NULL);
      else
        result->value = tor_strdup("");
      break;
    default:
      tor_free(result->key);
      tor_free(result);
478
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
479
480
481
482
483
484
      return NULL;
    }

  return result;
}

485
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
486
 * For each item, convert as appropriate and assign to <b>options</b>.
487
 * If an item is unrecognized, return -1 immediately,
488
489
490
491
492
493
 * else return 0 for success.
 *
 * If <b>reset</b>, then interpret empty lines as meaning "restore to
 * default value", and interpret LINELIST* options as replacing (not
 * extending) their previous values.
 */
494
static int
495
config_assign(or_options_t *options, struct config_line_t *list, int reset)
496
{
497
498
499
500
501
502
503
504
  struct config_line_t *p;

  /* pass 1: normalize keys */
  for (p = list; p; p = p->next) {
    const char *full = expand_abbrev(p->key, 0);
    if (strcmp(full,p->key)) {
      tor_free(p->key);
      p->key = tor_strdup(full);
505
    }
506
507
508
509
510
511
512
513
  }

  /* pass 2: if we're reading from a resetting souurce, clear all mentioned
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
514

515
516
517
  /* pass 3: assign. */
  while (list) {
    if (config_assign_line(options, list, reset))
518
      return -1;
519
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
520
  }
521
  return 0;
522
523
}

524
525
526
static void
add_default_trusted_dirservers(void)
{
Nick Mathewson's avatar
Nick Mathewson committed
527
528
529
530
  /* moria1 */
  parse_dir_server_line("18.244.0.188:9031 "
                        "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
  /* moria2 */
531
  parse_dir_server_line("18.244.0.114:80 "
Nick Mathewson's avatar
Nick Mathewson committed
532
533
534
535
                        "719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
  /* tor26 */
  parse_dir_server_line("62.116.124.106:9030 "
                        "847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
536
537
}

Nick Mathewson's avatar
Nick Mathewson committed
538
/** Print a usage message for tor. */
539
540
541
static void
print_usage(void)
{
542
  printf("tor -f <torrc> [args]\n"
543
544
         "See man page for more options. This -h is obsolete.\n");
#if 0
545
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
546
         "-d <file>\t\tDebug file\n"
547
548
549
550
         "-l <level>\t\tLog level\n"
         "-r <file>\t\tList of known routers\n");
  printf("\nClient options:\n"
         "-e \"nick1 nick2 ...\"\t\tExit nodes\n"
551
         "-s <IP>\t\t\tPort to bind to for Socks\n");
552
553
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
554
         "-o <port>\t\tOR port to bind to\n"
555
         "-p <file>\t\tPID file\n");
556
#endif
557
558
}

Nick Mathewson's avatar
Nick Mathewson committed
559
/**
560
561
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
562
 */
563
564
565
int
resolve_my_address(const char *address, uint32_t *addr)
{
566
567
  struct in_addr in;
  struct hostent *rent;
568
  char hostname[256];
569
  int explicit_ip=1;
570

571
572
  tor_assert(addr);

573
574
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
575
  } else { /* then we need to guess our address */
576
    explicit_ip = 0; /* it's implicit */
577

578
    if (gethostname(hostname, sizeof(hostname)) < 0) {
579
580
581
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
582
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
583
584
  }

585
  /* now we know hostname. resolve it and keep only the IP */
586

587
  if (tor_inet_aton(hostname, &in) == 0) {
588
589
    /* then we have to resolve it */
    explicit_ip = 0;
590
    rent = (struct hostent *)gethostbyname(hostname);
591
    if (!rent) {
592
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
593
594
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
595
    tor_assert(rent->h_length == 4);
596
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
597
  }
598
599

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
600
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
601
           "Please set the Address config option to be the IP you want to use.",
602
           hostname, inet_ntoa(in));
603
604
    return -1;
  }
605
606

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
607
  *addr = ntohl(in.s_addr);
608
609
610
  return 0;
}

611
612
static char *
get_default_nickname(void)
613
614
615
616
{
  char localhostname[256];
  char *cp, *out, *outp;

617
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
618
619
620
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
621

622
  /* Put it in lowercase; stop at the first dot. */
623
  for (cp = localhostname; *cp; ++cp) {
624
625
626
627
628
629
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
630

631
632
  /* Strip invalid characters. */
  cp = localhostname;
633
  out = outp = tor_malloc(strlen(localhostname) + 1);
634
635
636
637
638
639
640
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
641

642
643
644
645
646
647
648
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
649
/** Release storage held by <b>options</b> */
650
651
652
static void
free_options(or_options_t *options)
{
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  int i;
  void *lvalue;

  for (i=0; config_vars[i].name; ++i) {
    lvalue = ((char*)options) + config_vars[i].var_offset;
    switch(config_vars[i].type) {
      case CONFIG_TYPE_UINT:
      case CONFIG_TYPE_BOOL:
      case CONFIG_TYPE_DOUBLE:
      case CONFIG_TYPE_OBSOLETE:
        break; /* nothing to free for these config types */
      case CONFIG_TYPE_STRING:
        tor_free(*(char **)lvalue);
        break;
      case CONFIG_TYPE_LINELIST:
668
      case CONFIG_TYPE_LINELIST_V:
669
670
671
672
673
674
675
676
677
678
        config_free_lines(*(struct config_line_t**)lvalue);
        *(struct config_line_t**)lvalue = NULL;
        break;
      case CONFIG_TYPE_CSV:
        if (*(smartlist_t**)lvalue) {
          SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
          smartlist_free(*(smartlist_t**)lvalue);
          *(smartlist_t**)lvalue = NULL;
        }
        break;
679
680
681
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
682
683
684
    }
  }
  /* XXX this last part is an exception. can we make it not needed? */
685
  if (options->RedirectExitList) {
Nick Mathewson's avatar
Nick Mathewson committed
686
687
    SMARTLIST_FOREACH(options->RedirectExitList,
                      exit_redirect_t *, p, tor_free(p));
Roger Dingledine's avatar
Roger Dingledine committed
688
    smartlist_free(options->RedirectExitList);
689
    options->RedirectExitList = NULL;
690
  }
691
}
692

693
694
695
696
697
698
699
700
701
702
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
737
738
739
/** Replace the option indexed by <b>var</b> in <b>options</b> with its
 * default value. */
static void
reset_option(or_options_t *options, config_var_t *var)
{
  struct config_line_t *c;
  void *lvalue;

  lvalue = ((char*)options) + var->var_offset;
  switch (var->type) {
    case CONFIG_TYPE_STRING:
      tor_free(*(char**)lvalue);
      break;
    case CONFIG_TYPE_DOUBLE:
      *(double*)lvalue = 0.0;
      break;
    case CONFIG_TYPE_UINT:
    case CONFIG_TYPE_BOOL:
      *(int*)lvalue = 0;
      break;
    case CONFIG_TYPE_CSV:
      if (*(smartlist_t**)lvalue) {
        SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
        smartlist_free(*(smartlist_t **)lvalue);
        *(smartlist_t **)lvalue = NULL;
      }
      break;
    case CONFIG_TYPE_LINELIST:
    case CONFIG_TYPE_LINELIST_S:
      config_free_lines(*(struct config_line_t **)lvalue);
      *(struct config_line_t **)lvalue = NULL;
      break;
    case CONFIG_TYPE_LINELIST_V:
      /* handled by linelist_s. */
      break;
    case CONFIG_TYPE_OBSOLETE:
      break;
  }
  if (var->initvalue) {
    c = tor_malloc(sizeof(struct config_line_t));
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

740
741
742
743
744
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
static void
init_options(or_options_t *options)
{
745
746
747
  int i;
  config_var_t *var;

748
  memset(options,0,sizeof(or_options_t));
749
750
751
752
  for (i=0; config_vars[i].name; ++i) {
    var = &config_vars[i];
    if(!var->initvalue)
      continue; /* defaults to NULL or 0 */
753
    reset_option(options, var);
754
  }
755
756
}

757
#ifdef MS_WINDOWS
758
759
760
761
762
static char *get_windows_conf_root(void)
{
  static int is_set = 0;
  static char path[MAX_PATH+1];

763
764
765
  LPITEMIDLIST idl;
  IMalloc *m;
  HRESULT result;
766
767
768

  if (is_set)
    return path;
769

770
771
772
773
774
  /* Find X:\documents and settings\username\applicatation data\ .
   * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
   */
  if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA,
                                            &idl))) {
775
776
777
778
    GetCurrentDirectory(MAX_PATH, path);
    is_set = 1;
    log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path);
    return path;
779
780
781
782
783
784
785
786
787
788
  }
  /* Convert the path from an "ID List" (whatever that is!) to a path. */
  result = SHGetPathFromIDList(idl, path);
  /* Now we need to free the */
  SHGetMalloc(&m);
  if (m) {
    m->lpVtbl->Free(m, idl);
    m->lpVtbl->Release(m);
  }
  if (!SUCCEEDED(result)) {
Nick Mathewson's avatar
Nick Mathewson committed
789
    return NULL;
790
  }
791
  strlcat(path,"\\tor",MAX_PATH);
792
793
794
795
796
797
798
799
800
801
802
  is_set = 1;
  return path;
}
#endif

static char *
get_default_conf_file(void)
{
#ifdef MS_WINDOWS
  char *path = tor_malloc(MAX_PATH);
  strlcpy(path, get_windows_conf_root(), MAX_PATH);
803
  strlcat(path,"\\torrc",MAX_PATH);
804
805
  return path;
#else
806
  return tor_strdup(CONFDIR "/torrc");
807
808
809
#endif
}

810
811
812
813
/** Verify whether lst is a string containing valid-looking space-separated
 * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
 */
static int check_nickname_list(const char *lst, const char *name)
814
{
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  int r = 0;
  smartlist_t *sl;

  if (!lst)
    return 0;
  sl = smartlist_create();
  smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  SMARTLIST_FOREACH(sl, const char *, s,
    {
      if (!is_legal_nickname_or_hexdigest(s)) {
        log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name);
        r = -1;
      }
    });
  SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
830
  smartlist_free(sl);
831
832
833
  return r;
}

Roger Dingledine's avatar
Roger Dingledine committed
834
835
836
837
838
839
static int
validate_options(or_options_t *options)
{
  int i;
  int result = 0;
  struct config_line_t *cl;
840

841
842
  if (options->ORPort < 0 || options->ORPort > 65535) {
    log(LOG_WARN, "ORPort option out of bounds.");
843
844
845
    result = -1;
  }

846
  if (options->Nickname == NULL) {
847
    if (server_mode()) {
848
849
850
851
      if (!(options->Nickname = get_default_nickname()))
        return -1;
      log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
    }
852
853
854
855
856
857
  } else {
    if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
        strlen(options->Nickname)) {
      log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
      result = -1;
    }
858
859
860
861
    if (strlen(options->Nickname) == 0) {
      log_fn(LOG_WARN, "Nickname must have at least one character");
      result = -1;
    }
862
863
864
865
    if (strlen(options->Nickname) > MAX_NICKNAME_LEN) {
      log_fn(LOG_WARN, "Nickname '%s' has more than %d characters.",
             options->Nickname, MAX_NICKNAME_LEN);
      result = -1;
866
    }
867
868
  }

869
  if (server_mode()) {
870
871
    /* confirm that our address isn't broken, so we can complain now */
    uint32_t tmp;
872
    if (resolve_my_address(options->Address, &tmp) < 0)
873
      result = -1;
874
875
  }

876
877
  if (options->SocksPort < 0 || options->SocksPort > 65535) {
    log(LOG_WARN, "SocksPort option out of bounds.");
878
879
880
    result = -1;
  }

881
882
  if (options->SocksPort == 0 && options->ORPort == 0) {
    log(LOG_WARN, "SocksPort and ORPort are both undefined? Quitting.");
883
    result = -1;
Roger Dingledine's avatar
Roger Dingledine committed
884
  }
885

886
887
888
889
890
  if (options->ControlPort < 0 || options->ControlPort > 65535) {
    log(LOG_WARN, "ControlPort option out of bounds.");
    result = -1;
  }

891
892
  if (options->DirPort < 0 || options->DirPort > 65535) {
    log(LOG_WARN, "DirPort option out of bounds.");
893
894
895
    result = -1;
  }

896
897
  if (options->StrictExitNodes &&
      (!options->ExitNodes || !strlen(options->ExitNodes))) {
898
    log(LOG_WARN, "StrictExitNodes set, but no ExitNodes listed.");
899
900
  }

901
902
  if (options->StrictEntryNodes &&
      (!options->EntryNodes || !strlen(options->EntryNodes))) {
903
    log(LOG_WARN, "StrictEntryNodes set, but no EntryNodes listed.");
904
905
  }

906
907
  if (options->AuthoritativeDir && options->RecommendedVersions == NULL) {
    log(LOG_WARN, "Directory servers must configure RecommendedVersions.");
908
909
910
    result = -1;
  }

911
912
  if (options->AuthoritativeDir && !options->DirPort) {
    log(LOG_WARN, "Running as authoritative directory, but no DirPort set.");
913
914
915
    result = -1;
  }

916
917
  if (options->AuthoritativeDir && !options->ORPort) {
    log(LOG_WARN, "Running as authoritative directory, but no ORPort set.");
Roger Dingledine's avatar
Roger Dingledine committed
918
919
    result = -1;
  }
920

921
922
  if (options->AuthoritativeDir && options->ClientOnly) {
    log(LOG_WARN, "Running as authoritative directory, but ClientOnly also set.");
Roger Dingledine's avatar
Roger Dingledine committed
923
924
    result = -1;
  }
925

926
  if (options->FirewallPorts) {
927
    SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp,
928
929
    {
      i = atoi(cp);
930
      if (i < 1 || i > 65535) {
931
932
933
934
935
936
        log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp);
        result=-1;
      }
    });
  }
  options->_AllowUnverified = 0;
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
  if (options->AllowUnverifiedNodes) {
    SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, {
        if (!strcasecmp(cp, "entry"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_ENTRY;
        else if (!strcasecmp(cp, "exit"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_EXIT;
        else if (!strcasecmp(cp, "middle"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_MIDDLE;
        else if (!strcasecmp(cp, "introduction"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_INTRODUCTION;
        else if (!strcasecmp(cp, "rendezvous"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_RENDEZVOUS;
        else {
          log(LOG_WARN, "Unrecognized value '%s' in AllowUnverifiedNodes",
              cp);
          result=-1;
        }
      });
  }

  if (options->SocksPort >= 1 &&
      (options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) {
    log(LOG_WARN, "PathlenCoinWeight option must be >=0.0 and <1.0.");
960
961
962
    result = -1;
  }

963
964
  if (options->MaxConn < 1) {
    log(LOG_WARN, "MaxConn option must be a non-zero positive integer.");
965
966
967
    result = -1;
  }

968
969
  if (options->MaxConn >= MAXCONNECTIONS) {
    log(LOG_WARN, "MaxConn option must be less than %d.", MAXCONNECTIONS);
970
971
972
    result = -1;
  }

973
#define MIN_DIRFETCHPOSTPERIOD 60
974
975
  if (options->DirFetchPostPeriod < MIN_DIRFETCHPOSTPERIOD) {
    log(LOG_WARN, "DirFetchPostPeriod option must be at least %d.", MIN_DIRFETCHPOSTPERIOD);
976
977
    result = -1;
  }
978
979
980
  if (options->DirFetchPostPeriod > MIN_ONION_KEY_LIFETIME / 2) {
    log(LOG_WARN, "DirFetchPostPeriod is too large; clipping.");
    options->DirFetchPostPeriod = MIN_ONION_KEY_LIFETIME / 2;
981
  }
982

983
  if (options->KeepalivePeriod < 1) {
Roger Dingledine's avatar
Roger Dingledine committed
984
    log(LOG_WARN,"KeepalivePeriod option must be positive.");
985
986
987
    result = -1;
  }

988
  if (options->AccountingStart < 0 || options->AccountingStart > 31) {
989
    log(LOG_WARN,"Monthly accounting must start on a day of the month, and no months have %d days.",
990
991
992
993
994
995
996
        options->AccountingStart);
    result = -1;
  } else if (options->AccountingStart > 28) {
    log(LOG_WARN,"Not every month has %d days.",options->AccountingStart);
    result = -1;
  }

997
998
999
  if (options->HttpProxy) { /* parse it now */
    if (parse_addr_port(options->HttpProxy, NULL,
                        &options->HttpProxyAddr, &options->HttpProxyPort) < 0) {
1000
      log(LOG_WARN,"HttpProxy failed to parse or resolve. Please fix.");