Commit 34f3fcef authored by David Goulet's avatar David Goulet 🐼
Browse files

Merge branch 'tor-github/pr/1290'

parents 46a38206 4bcfa286
Loading
Loading
Loading
Loading

changes/ticket31240

0 → 100644
+5 −0
Original line number Diff line number Diff line
  o Minor features (configuration):
    - The configuration code has been extended to allow splitting
      configuration data across multiple objects. Previously, all
      configuration data needed to be kept in a single object, which
      tended to become bloated.  Closes ticket 31240.
+75 −82
Original line number Diff line number Diff line
@@ -843,15 +843,15 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
static int options_validate_cb(void *old_options, void *options,
                               void *default_options,
                               int from_setconf, char **msg);
static void options_free_cb(void *options);
static void cleanup_protocol_warning_severity_level(void);
static void set_protocol_warning_severity_level(int warning_severity);
static void options_clear_cb(const config_mgr_t *mgr, void *opts);

/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909

/** Configuration format for or_options_t. */
STATIC const config_format_t options_format = {
static const config_format_t options_format = {
  sizeof(or_options_t),
  {
   "or_options_t",
@@ -862,8 +862,9 @@ STATIC const config_format_t options_format = {
  option_deprecation_notes_,
  option_vars_,
  options_validate_cb,
  options_free_cb,
  NULL
  options_clear_cb,
  NULL,
  offsetof(or_options_t, subconfigs_),
};

/*
@@ -895,6 +896,20 @@ static int in_option_validation = 0;
/* True iff we've initialized libevent */
static int libevent_initialized = 0;

/* A global configuration manager to handle all configuration objects. */
static config_mgr_t *options_mgr = NULL;

/** Return the global configuration manager object for torrc options. */
STATIC const config_mgr_t *
get_options_mgr(void)
{
  if (PREDICT_UNLIKELY(options_mgr == NULL)) {
    options_mgr = config_mgr_new(&options_format);
    config_mgr_freeze(options_mgr);
  }
  return options_mgr;
}

/** Return the contents of our frontpage string, or NULL if not configured. */
MOCK_IMPL(const char*,
get_dirportfrontpage, (void))
@@ -951,9 +966,6 @@ get_options_defaults(void)
int
set_options(or_options_t *new_val, char **msg)
{
  int i;
  smartlist_t *elements;
  config_line_t *line;
  or_options_t *old_options = global_options;
  global_options = new_val;
  /* Note that we pass the *old* options below, for comparison. It
@@ -975,35 +987,16 @@ set_options(or_options_t *new_val, char **msg)
  /* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
   * just starting up then the old_options will be undefined. */
  if (old_options && old_options != global_options) {
    elements = smartlist_new();
    for (i=0; options_format.vars[i].member.name; ++i) {
      const config_var_t *var = &options_format.vars[i];
      const char *var_name = var->member.name;
      if (config_var_is_contained(var)) {
        /* something else will check this var, or it doesn't need checking */
        continue;
      }
      if (!config_is_same(&options_format, new_val, old_options, var_name)) {
        line = config_get_assigned_option(&options_format, new_val,
                                          var_name, 1);

        if (line) {
          config_line_t *next;
          for (; line; line = next) {
            next = line->next;
    smartlist_t *elements = smartlist_new();
    config_line_t *changes =
      config_get_changes(get_options_mgr(), old_options, new_val);
    for (config_line_t *line = changes; line; line = line->next) {
      smartlist_add(elements, line->key);
      smartlist_add(elements, line->value);
            tor_free(line);
          }
        } else {
          smartlist_add_strdup(elements, options_format.vars[i].member.name);
          smartlist_add(elements, NULL);
        }
      }
    }
    control_event_conf_changed(elements);
    SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
    smartlist_free(elements);
    config_free_lines(changes);
  }

  if (old_options != global_options) {
@@ -1019,11 +1012,11 @@ set_options(or_options_t *new_val, char **msg)

/** Release additional memory allocated in options
 */
STATIC void
or_options_free_(or_options_t *options)
static void
options_clear_cb(const config_mgr_t *mgr, void *opts)
{
  if (!options)
    return;
  (void)mgr;
  or_options_t *options = opts;

  routerset_free(options->ExcludeExitNodesUnion_);
  if (options->NodeFamilySets) {
@@ -1046,7 +1039,14 @@ or_options_free_(or_options_t *options)
  tor_free(options->command_arg);
  tor_free(options->master_key_fname);
  config_free_lines(options->MyFamily);
  config_free(&options_format, options);
}

/** Release all memory allocated in options
 */
STATIC void
or_options_free_(or_options_t *options)
{
  config_free(get_options_mgr(), options);
}

/** Release all memory and resources held by global configuration structures.
@@ -1080,6 +1080,8 @@ config_free_all(void)

  have_parsed_cmdline = 0;
  libevent_initialized = 0;

  config_mgr_free(options_mgr);
}

/** Make <b>address</b> -- a piece of information related to our operation as
@@ -2547,7 +2549,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,

    param = tor_malloc_zero(sizeof(config_line_t));
    param->key = is_cmdline ? tor_strdup(argv[i]) :
                   tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
                 tor_strdup(config_expand_abbrev(get_options_mgr(), s, 1, 1));
    param->value = arg;
    param->command = command;
    param->next = NULL;
@@ -2573,8 +2575,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
int
option_is_recognized(const char *key)
{
  const config_var_t *var = config_find_option(&options_format, key);
  return (var != NULL);
  return config_find_option_name(get_options_mgr(), key) != NULL;
}

/** Return the canonical name of a configuration option, or NULL
@@ -2582,8 +2583,7 @@ option_is_recognized(const char *key)
const char *
option_get_canonical_name(const char *key)
{
  const config_var_t *var = config_find_option(&options_format, key);
  return var ? var->member.name : NULL;
  return config_find_option_name(get_options_mgr(), key);
}

/** Return a canonical list of the options assigned for key.
@@ -2591,7 +2591,7 @@ option_get_canonical_name(const char *key)
config_line_t *
option_get_assignment(const or_options_t *options, const char *key)
{
  return config_get_assigned_option(&options_format, options, key, 1);
  return config_get_assigned_option(get_options_mgr(), options, key, 1);
}

/** Try assigning <b>list</b> to the global options. You do this by duping
@@ -2607,9 +2607,9 @@ setopt_err_t
options_trial_assign(config_line_t *list, unsigned flags, char **msg)
{
  int r;
  or_options_t *trial_options = config_dup(&options_format, get_options());
  or_options_t *trial_options = config_dup(get_options_mgr(), get_options());

  if ((r=config_assign(&options_format, trial_options,
  if ((r=config_assign(get_options_mgr(), trial_options,
                       list, flags, msg)) < 0) {
    or_options_free(trial_options);
    return r;
@@ -2664,25 +2664,25 @@ print_usage(void)
static void
list_torrc_options(void)
{
  int i;
  for (i = 0; option_vars_[i].member.name; ++i) {
    const config_var_t *var = &option_vars_[i];
  smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
  SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
    if (! config_var_is_settable(var)) {
      /* This variable cannot be set, or cannot be set by this name. */
      continue;
    }
    printf("%s\n", var->member.name);
  }
  } SMARTLIST_FOREACH_END(var);
  smartlist_free(vars);
}

/** Print all deprecated but non-obsolete torrc options. */
static void
list_deprecated_options(void)
{
  const config_deprecation_t *d;
  for (d = option_deprecation_notes_; d->name; ++d) {
    printf("%s\n", d->name);
  }
  smartlist_t *deps = config_mgr_list_deprecated_vars(get_options_mgr());
  SMARTLIST_FOREACH(deps, const char *, name,
                    printf("%s\n", name));
  smartlist_free(deps);
}

/** Print all compile-time modules and their enabled/disabled status. */
@@ -2992,7 +2992,7 @@ is_local_addr, (const tor_addr_t *addr))
or_options_t *
options_new(void)
{
  return config_new(&options_format);
  return config_new(get_options_mgr());
}

/** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3000,10 +3000,10 @@ options_new(void)
void
options_init(or_options_t *options)
{
  config_init(&options_format, options);
  config_init(get_options_mgr(), options);
  config_line_t *dflts = get_options_defaults();
  char *msg=NULL;
  if (config_assign(&options_format, options, dflts,
  if (config_assign(get_options_mgr(), options, dflts,
                    CAL_WARN_DEPRECATIONS, &msg)<0) {
    log_err(LD_BUG, "Unable to set default options: %s", msg);
    tor_free(msg);
@@ -3040,7 +3040,7 @@ options_dump(const or_options_t *options, int how_to_dump)
      return NULL;
  }

  return config_dump(&options_format, use_defaults, options, minimal, 0);
  return config_dump(get_options_mgr(), use_defaults, options, minimal, 0);
}

/** Return 0 if every element of sl is a string holding a decimal
@@ -3172,13 +3172,6 @@ options_validate_cb(void *old_options, void *options, void *default_options,
  return rv;
}

/** Callback to free an or_options_t */
static void
options_free_cb(void *options)
{
  or_options_free_(options);
}

#define REJECT(arg) \
  STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
#if defined(__GNUC__) && __GNUC__ <= 3
@@ -4435,7 +4428,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
  STMT_BEGIN                                                            \
    if (!options->TestingTorNetwork &&                                  \
        !options->UsingTestNetworkDefaults_ &&                          \
        !config_is_same(&options_format,options,                        \
        !config_is_same(get_options_mgr(),options,                        \
                        default_options,#arg)) {                        \
      REJECT(#arg " may only be changed in testing Tor "                \
             "networks!");                                              \
@@ -5411,8 +5404,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
  oldoptions = global_options; /* get_options unfortunately asserts if
                                  this is the first time we run*/

  newoptions = tor_malloc_zero(sizeof(or_options_t));
  newoptions->magic_ = OR_OPTIONS_MAGIC;
  newoptions = options_new();
  options_init(newoptions);
  newoptions->command = command;
  newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
@@ -5431,7 +5423,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
      err = SETOPT_ERR_PARSE;
      goto err;
    }
    retval = config_assign(&options_format, newoptions, cl,
    retval = config_assign(get_options_mgr(), newoptions, cl,
                           CAL_WARN_DEPRECATIONS, msg);
    config_free_lines(cl);
    if (retval < 0) {
@@ -5439,15 +5431,15 @@ options_init_from_string(const char *cf_defaults, const char *cf,
      goto err;
    }
    if (i==0)
      newdefaultoptions = config_dup(&options_format, newoptions);
      newdefaultoptions = config_dup(get_options_mgr(), newoptions);
  }

  if (newdefaultoptions == NULL) {
    newdefaultoptions = config_dup(&options_format, global_default_options);
    newdefaultoptions = config_dup(get_options_mgr(), global_default_options);
  }

  /* Go through command-line variables too */
  retval = config_assign(&options_format, newoptions,
  retval = config_assign(get_options_mgr(), newoptions,
                         global_cmdline_options, CAL_WARN_DEPRECATIONS, msg);
  if (retval < 0) {
    err = SETOPT_ERR_PARSE;
@@ -8133,9 +8125,8 @@ getinfo_helper_config(control_connection_t *conn,
  (void) errmsg;
  if (!strcmp(question, "config/names")) {
    smartlist_t *sl = smartlist_new();
    int i;
    for (i = 0; option_vars_[i].member.name; ++i) {
      const config_var_t *var = &option_vars_[i];
    smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
    SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
      /* don't tell controller about invisible options */
      if (config_var_is_invisible(var))
        continue;
@@ -8143,26 +8134,27 @@ getinfo_helper_config(control_connection_t *conn,
      if (!type)
        continue;
      smartlist_add_asprintf(sl, "%s %s\n",var->member.name,type);
    }
    } SMARTLIST_FOREACH_END(var);
    *answer = smartlist_join_strings(sl, "", 0, NULL);
    SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
    smartlist_free(sl);
    smartlist_free(vars);
  } else if (!strcmp(question, "config/defaults")) {
    smartlist_t *sl = smartlist_new();
    int dirauth_lines_seen = 0, fallback_lines_seen = 0;
    for (int i = 0; option_vars_[i].member.name; ++i) {
      const config_var_t *var = &option_vars_[i];
    smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
    SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
      if (var->initvalue != NULL) {
        if (strcmp(option_vars_[i].member.name, "DirAuthority") == 0) {
        if (strcmp(var->member.name, "DirAuthority") == 0) {
          /*
           * Count dirauth lines we have a default for; we'll use the
           * count later to decide whether to add the defaults manually
           */
          ++dirauth_lines_seen;
        }
        if (strcmp(option_vars_[i].member.name, "FallbackDir") == 0) {
        if (strcmp(var->member.name, "FallbackDir") == 0) {
          /*
           * Similarly count fallback lines, so that we can decided later
           * Similarly count fallback lines, so that we can decide later
           * to add the defaults manually.
           */
          ++fallback_lines_seen;
@@ -8171,7 +8163,8 @@ getinfo_helper_config(control_connection_t *conn,
        smartlist_add_asprintf(sl, "%s %s\n",var->member.name,val);
        tor_free(val);
      }
    }
    } SMARTLIST_FOREACH_END(var);
    smartlist_free(vars);

    if (dirauth_lines_seen == 0) {
      /*
+2 −3
Original line number Diff line number Diff line
@@ -247,9 +247,8 @@ int options_any_client_port_set(const or_options_t *options);
#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)

STATIC int options_act(const or_options_t *old_options);
#ifdef TOR_UNIT_TESTS
extern const struct config_format_t options_format;
#endif
struct config_mgr_t;
STATIC const struct config_mgr_t *get_options_mgr(void);

STATIC port_cfg_t *port_cfg_new(size_t namelen);
#define port_cfg_free(port) \
+589 −157

File changed.

Preview size limit exceeded, changes collapsed.

+60 −26
Original line number Diff line number Diff line
@@ -39,8 +39,19 @@ typedef struct config_deprecation_t {
 * of arguments. */
typedef int (*validate_fn_t)(void*,void*,void*,int,char**);

/** Callback to free a configuration object. */
typedef void (*free_cfg_fn_t)(void*);
struct config_mgr_t;

/**
 * Callback to clear all non-managed fields of a configuration object.
 *
 * <b>obj</b> is the configuration object whose non-managed fields should be
 * cleared.
 *
 * (Regular fields get cleared by config_reset(), but you might have fields
 * in the object that do not correspond to configuration variables.  If those
 * fields need to be cleared or freed, this is where to do it.)
 */
typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj);

/** Information on the keys, value types, key-to-struct-member mappings,
 * variable descriptions, validation functions, and abbreviations for a
@@ -55,51 +66,70 @@ typedef struct config_format_t {
                             * values, and where we stick them in the
                             * structure. */
  validate_fn_t validate_fn; /**< Function to validate config. */
  free_cfg_fn_t free_fn; /**< Function to free the configuration. */
  clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */
  /** If present, extra denotes a LINELIST variable for unrecognized
   * lines.  Otherwise, unrecognized lines are an error. */
  const struct_member_t *extra;
  /** The position of a config_suite_t pointer within the toplevel object,
   * or -1 if there is no such pointer. */
  int config_suite_offset;
} config_format_t;

/** Macro: assert that <b>cfg</b> has the right magic field for format
 * <b>fmt</b>. */
#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN                               \
    tor_assert(fmt);                                                    \
    struct_check_magic((cfg), &fmt->magic);                             \
  STMT_END
/**
 * A collection of config_format_t objects to describe several objects
 * that are all configured with the same configuration file.
 *
 * (NOTE: for now, this only handles a single config_format_t.)
 **/
typedef struct config_mgr_t config_mgr_t;

config_mgr_t *config_mgr_new(const config_format_t *toplevel_fmt);
void config_mgr_free_(config_mgr_t *mgr);
int config_mgr_add_format(config_mgr_t *mgr,
                          const config_format_t *fmt);
void config_mgr_freeze(config_mgr_t *mgr);
#define config_mgr_free(mgr) \
  FREE_AND_NULL(config_mgr_t, config_mgr_free_, (mgr))
struct smartlist_t *config_mgr_list_vars(const config_mgr_t *mgr);
struct smartlist_t *config_mgr_list_deprecated_vars(const config_mgr_t *mgr);

/** A collection of managed configuration objects. */
typedef struct config_suite_t config_suite_t;

#define CAL_USE_DEFAULTS      (1u<<0)
#define CAL_CLEAR_FIRST       (1u<<1)
#define CAL_WARN_DEPRECATIONS (1u<<2)

void *config_new(const config_format_t *fmt);
void config_free_(const config_format_t *fmt, void *options);
#define config_free(fmt, options) do {                \
    config_free_((fmt), (options));                   \
void *config_new(const config_mgr_t *fmt);
void config_free_(const config_mgr_t *fmt, void *options);
#define config_free(mgr, options) do {                \
    config_free_((mgr), (options));                   \
    (options) = NULL;                                 \
  } while (0)

struct config_line_t *config_get_assigned_option(const config_format_t *fmt,
struct config_line_t *config_get_assigned_option(const config_mgr_t *mgr,
                                          const void *options, const char *key,
                                          int escape_val);
int config_is_same(const config_format_t *fmt,
int config_is_same(const config_mgr_t *fmt,
                   const void *o1, const void *o2,
                   const char *name);
void config_init(const config_format_t *fmt, void *options);
void *config_dup(const config_format_t *fmt, const void *old);
char *config_dump(const config_format_t *fmt, const void *default_options,
struct config_line_t *config_get_changes(const config_mgr_t *mgr,
                                  const void *options1, const void *options2);
void config_init(const config_mgr_t *mgr, void *options);
void *config_dup(const config_mgr_t *mgr, const void *old);
char *config_dump(const config_mgr_t *mgr, const void *default_options,
                  const void *options, int minimal,
                  int comment_defaults);
bool config_check_ok(const config_format_t *fmt, const void *options,
bool config_check_ok(const config_mgr_t *mgr, const void *options,
                     int severity);
int config_assign(const config_format_t *fmt, void *options,
int config_assign(const config_mgr_t *mgr, void *options,
                  struct config_line_t *list,
                  unsigned flags, char **msg);
const char *config_find_deprecation(const config_format_t *fmt,
const char *config_find_deprecation(const config_mgr_t *mgr,
                                    const char *key);
const config_var_t *config_find_option(const config_format_t *fmt,
const char *config_find_option_name(const config_mgr_t *mgr,
                                    const char *key);
const char *config_expand_abbrev(const config_format_t *fmt,
const char *config_expand_abbrev(const config_mgr_t *mgr,
                                 const char *option,
                                 int command_line, int warn_obsolete);
void warn_deprecated_option(const char *what, const char *why);
@@ -119,8 +149,12 @@ bool config_var_is_dumpable(const config_var_t *var);
#define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt)

#ifdef CONFPARSE_PRIVATE
STATIC void config_reset_line(const config_format_t *fmt, void *options,
STATIC void config_reset_line(const config_mgr_t *mgr, void *options,
                              const char *key, int use_defaults);
STATIC void *config_mgr_get_obj_mutable(const config_mgr_t *mgr,
                                        void *toplevel, int idx);
STATIC const void *config_mgr_get_obj(const config_mgr_t *mgr,
                                       const void *toplevel, int idx);
#endif

#endif /* !defined(TOR_CONFPARSE_H) */
Loading