Exemplo n.º 1
0
Arquivo: paths.c Projeto: hungld/gdnsd
vscf_data_t* gdnsd_initialize(const char* config_dir, const bool check_create_dirs) {
    static bool has_run = false;
    if(has_run)
        log_fatal("BUG: gdnsd_initialize() should only be called once!");
    else
        has_run = true;

    // Initialize other areas of libgdnsd
    gdnsd_init_net();
    gdnsd_rand_meta_init();

    // set up config dir
    if(!config_dir)
        config_dir = GDNSD_DEFPATH_CONFIG;
    gdnsd_dirs[CFG] = gdnsd_realdir(config_dir, "config", false, 0);

    // parse config file
    char* cfg_file = gdnsd_resolve_path_cfg("config", NULL);
    vscf_data_t* cfg_root = conf_load_vscf(cfg_file);
    free(cfg_file);

#ifndef NDEBUG
    // in developer debug builds, exercise clone+destroy
    if(cfg_root) {
        vscf_data_t* temp_cfg = vscf_clone(cfg_root, false);
        vscf_destroy(cfg_root);
        cfg_root = temp_cfg;
    }
#endif

    // find run/state paths, possibly using config input
    const char* run_dir = GDNSD_DEFPATH_RUN;
    const char* state_dir = GDNSD_DEFPATH_STATE;
    if(cfg_root) {
        vscf_data_t* options = vscf_hash_get_data_byconstkey(cfg_root, "options", true);
        if(options) {
            if(!vscf_is_hash(options))
                log_fatal("Config key 'options': wrong type (must be hash)");
            CFG_DIR(options, run_dir);
            CFG_DIR(options, state_dir);
        }
    }

    // set them up
    if(check_create_dirs) {
        gdnsd_dirs[RUN] = gdnsd_realdir(run_dir, "run", true, 0750);
        gdnsd_dirs[STATE] = gdnsd_realdir(state_dir, "state", true, 0755);
    }
    else {
        gdnsd_dirs[RUN] = strdup(run_dir);
        gdnsd_dirs[STATE] = strdup(state_dir);
    }

    // This is just fixed at compiletime, period
    gdnsd_dirs[LIBEXEC] = GDNSD_DEFPATH_LIBEXEC;

    return cfg_root;
}
Exemplo n.º 2
0
gdmaps_t* gdmaps_test_load(const char* cfg_data) {
    vscf_data_t* maps_cfg = vscf_scan_buf(strlen(cfg_data), cfg_data, "(test maps)", false);
    if(!maps_cfg)
        log_fatal("Test config load failed");
    if(!vscf_is_hash(maps_cfg))
        log_fatal("Geoip plugin config for 'maps' must be a hash");
    gdmaps_t* rv = gdmaps_new(maps_cfg);
    vscf_destroy(maps_cfg);

    gdmaps_load_databases(rv);

    return rv;
}
Exemplo n.º 3
0
gdmaps_t* gdmaps_test_init(const char* input_cfgdir) {

    dmn_init1(false, true, true, false, "gdmaps_test");

    const vscf_data_t* cfg_root = conf_load_vscf(input_cfgdir);
    const vscf_data_t* maps_cfg = conf_get_maps(cfg_root);
    gdmaps_t* gdmaps = gdmaps_new(maps_cfg);
    vscf_destroy(cfg_root);

    gdmaps_load_databases(gdmaps);
    gdmaps_setup_watchers(gdmaps);

    return gdmaps;
}
Exemplo n.º 4
0
gdmaps_t* gdmaps_test_init(const char* config_path) {

    dmn_init_log();

    dmn_assert(config_path);

    const vscf_data_t* cfg_root = conf_load(config_path);
    conf_options(cfg_root);
    gdnsd_set_cfdir(config_path);

    const vscf_data_t* maps_cfg = conf_get_maps(cfg_root);
    gdmaps_t* gdmaps = gdmaps_new(maps_cfg);
    vscf_destroy(cfg_root);

    gdmaps_load_geoip_databases(gdmaps);
    gdmaps_setup_geoip_watcher_paths(gdmaps);
    gdmaps_setup_geoip_watchers(gdmaps);

    return gdmaps;
}
Exemplo n.º 5
0
F_NONNULL
static void config_cnameset(const char* res_name, const char* stanza, cnset_t* cnset, const vscf_data_t* cfg) {
    dmn_assert(res_name); dmn_assert(stanza); dmn_assert(cnset); dmn_assert(cfg);

    if(!vscf_is_hash(cfg))
        log_fatal("plugin_weighted: resource '%s' stanza '%s' value must be a hash", res_name, stanza);

    cnset->count = vscf_hash_get_len(cfg);

    if(cnset->count > MAX_ITEMS_PER_SET)
        log_fatal("plugin_weighted: resource '%s' (%s): number of cnames cannot be more than %u", res_name, stanza, MAX_ITEMS_PER_SET);
    if(!cnset->count)
        log_fatal("plugin_weighted: resource '%s' (%s): empty cname sets not allowed", res_name, stanza);

    cnset->items = calloc(cnset->count, sizeof(res_citem_t));
    cname_iter_data_t cid = {
        .cnset = cnset,
        .res_name = res_name,
        .stanza = stanza,
        .item_idx = 0,
    };
    vscf_hash_iterate(cfg, true, config_item_cname, &cid);

    cnset->weight = 0;
    for(unsigned i = 0; i < cnset->count; i++) {
        const unsigned cwt = cnset->items[i].weight;
        dmn_assert(cwt);
        cnset->weight += cwt;
    }

    dmn_assert(cnset->weight);
}

F_NONNULL
static void config_auto(resource_t* res, const vscf_data_t* res_cfg) {
    dmn_assert(res); dmn_assert(res_cfg); dmn_assert(vscf_is_hash(res_cfg));

    // mark all possible parameter-keys
    vscf_hash_get_data_byconstkey(res_cfg, "service_types", true);
    vscf_hash_get_data_byconstkey(res_cfg, "multi", true);
    vscf_hash_get_data_byconstkey(res_cfg, "up_thresh", true);

    // make a copy that contains no parameters, only item-name keys
    vscf_data_t* res_cfg_noparams = vscf_clone(res_cfg, true);

    if(!vscf_hash_get_len(res_cfg_noparams))
        log_fatal("plugin_weighted: resource '%s' (direct) contains no weighted items", res->name);

    const char* first_name = vscf_hash_get_key_byindex(res_cfg_noparams, 0, NULL);
    const vscf_data_t* first_cfg = vscf_hash_get_data_byindex(res_cfg_noparams, 0);
    if(vscf_is_hash(first_cfg)) { // grouped address mode...
        if(!vscf_hash_get_len(first_cfg))
            log_fatal("plugin_weighted: resource '%s' (direct): group '%s': contains no addresses", res->name, first_name);
        const char* lb_name = vscf_hash_get_key_byindex(first_cfg, 0, NULL);
        const vscf_data_t* lb_cfg = vscf_hash_get_data_byindex(first_cfg, 0);
        if(!vscf_is_array(lb_cfg) || !vscf_array_get_len(lb_cfg) || !vscf_is_simple(vscf_array_get_data(lb_cfg, 0)))
            log_fatal("plugin_weighted: resource '%s' (direct): group '%s': item '%s': value must be an array of [ IP, weight ]", res->name, first_name, lb_name);
        const char* first_addr_txt = vscf_simple_get_data(vscf_array_get_data(lb_cfg, 0));
        anysin_t temp_sin;
        int addr_err = gdnsd_anysin_getaddrinfo(first_addr_txt, NULL, &temp_sin);
        if(addr_err)
            log_fatal("plugin_weighted: resource '%s' (direct): group '%s': item '%s': could not parse '%s' as an IP address: %s", res->name, first_name, lb_name, first_addr_txt, gai_strerror(addr_err));
        if(temp_sin.sa.sa_family == AF_INET6) {
            res->addrs_v6 = calloc(1, sizeof(addrset_t));
            config_addrset(res->name, "direct", true, res->addrs_v6, res_cfg);
        }
        else {
            dmn_assert(temp_sin.sa.sa_family == AF_INET);
            res->addrs_v4 = calloc(1, sizeof(addrset_t));
            config_addrset(res->name, "direct", false, res->addrs_v4, res_cfg);
        }
    }
    else if(vscf_is_array(first_cfg)) { // ungrouped address, or cnames
        const vscf_data_t* first_ac = vscf_array_get_data(first_cfg, 0);
        if(!first_ac || !vscf_is_simple(first_ac))
            log_fatal("plugin_weighted: resource '%s' (direct): item '%s': first element of array should be an IP address or CNAME string", res->name, first_name);
        anysin_t temp_sin;
        if(gdnsd_anysin_getaddrinfo(vscf_simple_get_data(first_ac), NULL, &temp_sin)) {
            // was not a valid address, try cnames mode
            res->cnames = calloc(1, sizeof(cnset_t));
            config_cnameset(res->name, "direct", res->cnames, res_cfg_noparams);
        }
        else {
            // was a valid address, try addrset mode
            if(temp_sin.sa.sa_family == AF_INET6) {
                res->addrs_v6 = calloc(1, sizeof(addrset_t));
                config_addrset(res->name, "direct", true, res->addrs_v6, res_cfg);
            }
            else {
                dmn_assert(temp_sin.sa.sa_family == AF_INET);
                res->addrs_v4 = calloc(1, sizeof(addrset_t));
                config_addrset(res->name, "direct", false, res->addrs_v4, res_cfg);
            }
        }
    }
    else {
        log_fatal("plugin_weighted: resource '%s' (direct): item '%s': resource type not detectable (should be array of [ IP, weight ], array of [ CNAME, weight ], or hashed address group ...)", res->name, first_name);
    }

    vscf_destroy(res_cfg_noparams);
}
Exemplo n.º 6
0
F_NONNULL
static void inject_child_plugin_config(dc_t* this_dc, const char* resname, vscf_data_t* cfg) {
    dmn_assert(this_dc); dmn_assert(resname); dmn_assert(cfg);

    char* child_resname = make_synth_resname(resname, this_dc->dc_name);
    this_dc->res_name = child_resname;

    // Move up 2 layers: dcX -> dcmap -> resX
    vscf_data_t* res_cfg = (vscf_data_t*)cfg;
    for(unsigned i = 0; i < 2; i++) {
        res_cfg = (vscf_data_t*)vscf_get_parent(res_cfg);
        dmn_assert(res_cfg);
    }

    // Move up 3 more layers:
    //   resX -> resources -> metafo|geoip -> plugins
    vscf_data_t* plugins_top = res_cfg;
    for(unsigned i = 0; i < 3; i++) {
        plugins_top = (vscf_data_t*)vscf_get_parent(plugins_top);
        dmn_assert(plugins_top);
    }

    // synth multifo stanza for: dc1 => 192.0.2.1, or dc1 => [ 192.0.2.1, ... ]
    bool cfg_synthed = false;
    if(!vscf_is_hash(cfg)) { // synthesize a hash for multifo for single/array
        vscf_data_t* newhash = vscf_hash_new();
        vscf_data_t* plugname_cfg = vscf_simple_new("multifo", 7);
        vscf_hash_add_val("plugin", 6, newhash, plugname_cfg);
        const unsigned alen = vscf_array_get_len(cfg);
        for(unsigned i = 0; i < alen; i++) {
            const vscf_data_t* this_addr_cfg = vscf_array_get_data(cfg, i);
            if(!vscf_is_simple(this_addr_cfg))
                log_fatal("plugin_" PNSTR ": resource '%s': datacenter '%s': if defined as an array, array values must all be address strings", resname, this_dc->dc_name);
            const unsigned lnum = i + 1;
            char lbuf[12];
            snprintf(lbuf, 12, "%u", lnum);
            vscf_hash_add_val(lbuf, strlen(lbuf), newhash, vscf_clone(this_addr_cfg, false));
        }
        cfg_synthed = true;
        cfg = newhash;
    }

    // inherit resource-level stuff down to dc-level
    vscf_hash_inherit_all(res_cfg, cfg, true);

    this_dc->plugin_name = get_defaulted_plugname(cfg, resname, this_dc->dc_name);
    if(!strcmp(this_dc->plugin_name, PNSTR))
        log_fatal("plugin_" PNSTR ": resource '%s': datacenter '%s': plugin_" PNSTR " cannot synthesize config for itself...", resname, this_dc->dc_name);

    // Create top-level plugins => { foo => {} } if necc
    vscf_data_t* plug_cfg = (vscf_data_t*)vscf_hash_get_data_bystringkey(plugins_top, this_dc->plugin_name, false);
    if(!plug_cfg) {
        plug_cfg = vscf_hash_new();
        vscf_hash_add_val(this_dc->plugin_name, strlen(this_dc->plugin_name), plugins_top, plug_cfg);
    }

    // special-case for geoip -> metafo synthesis, use resources sub-stanza
    if(!strcmp(this_dc->plugin_name, "metafo")) {
        vscf_data_t* synth_res_cfg = (vscf_data_t*)vscf_hash_get_data_byconstkey(plug_cfg, "resources", false);
        if(!synth_res_cfg) {
            synth_res_cfg = vscf_hash_new();
            vscf_hash_add_val("resources", strlen("resources"), plug_cfg, synth_res_cfg);
        }
        plug_cfg = synth_res_cfg; // for below
    }

    // Check if resource already exists
    if(vscf_hash_get_data_bystringkey(plug_cfg, child_resname, false))
        log_fatal("plugin_" PNSTR ": resource '%s': datacenter '%s': synthesis of resource '%s' for plugin '%s' failed (resource name already exists)", resname, this_dc->dc_name, child_resname, this_dc->plugin_name);

    // Add it, using clone() to skip marked key "plugin"
    vscf_hash_add_val(child_resname, strlen(child_resname), plug_cfg, vscf_clone(cfg, true));

    // destroy clone source if synthesized and disconnected from real config tree
    if(cfg_synthed) vscf_destroy(cfg);
}
Exemplo n.º 7
0
F_NONNULL
static void config_cnameset(const char* res_name, const char* stanza, cnset_t* cnset, const vscf_data_t* cfg) {
    dmn_assert(res_name); dmn_assert(stanza); dmn_assert(cnset); dmn_assert(cfg);

    if(!vscf_is_hash(cfg))
        log_fatal("plugin_weighted: resource '%s' stanza '%s' value must be a hash", res_name, stanza);

    cnset->count = vscf_hash_get_len(cfg);

    // service_types
    cnset->num_svcs = 0;
    const vscf_data_t* res_stypes = vscf_hash_get_data_byconstkey(cfg, "service_types", true);
    if (res_stypes) {
        cnset->count--; // minus one for service_types entry
        cnset->num_svcs = vscf_array_get_len(res_stypes);
        if(cnset->num_svcs) {
            cnset->svc_names = malloc(cnset->num_svcs * sizeof(char*));
            for(unsigned i = 0; i < cnset->num_svcs; i++) {
                const vscf_data_t* this_svc_cfg = vscf_array_get_data(res_stypes, i);
                if(!vscf_is_simple(this_svc_cfg))
                    log_fatal("plugin_weighted: resource '%s' (%s): service_types values must be strings", res_name, stanza);
                cnset->svc_names[i] = strdup(vscf_simple_get_data(this_svc_cfg));
            }
        }
    }
    else {
        cnset->num_svcs = 1;
        cnset->svc_names = malloc(sizeof(char*));
        cnset->svc_names[0] = strdup(DEFAULT_SVCNAME);
    }

    // up threshold as double
    double up_thresh = 0.5;
    const vscf_data_t* thresh_cfg = vscf_hash_get_data_byconstkey(cfg, "up_thresh", true);
    if(thresh_cfg) {
        cnset->count--; // minus one for up_thresh entry
        if(!vscf_is_simple(thresh_cfg) || !vscf_simple_get_as_double(thresh_cfg, &up_thresh)
           || up_thresh <= 0.0 || up_thresh > 1.0)
            log_fatal("plugin_weighted: resource '%s' (%s): 'up_thresh' must be a floating point value in the range (0.0 - 1.0]", res_name, stanza);
    }

    // multi option is processed for count-correctness, but ignored (it's not legal
    //   here, but may be present due to inheritance of defaults!)
    if(vscf_hash_get_data_byconstkey(cfg, "multi", true))
        cnset->count--;

    if(cnset->count > MAX_ITEMS_PER_SET)
        log_fatal("plugin_weighted: resource '%s' (%s): number of cnames cannot be more than %u", res_name, stanza, MAX_ITEMS_PER_SET);
    if(!cnset->count)
        log_fatal("plugin_weighted: resource '%s' (%s): empty cname sets not allowed", res_name, stanza);

    cnset->items = calloc(cnset->count, sizeof(res_citem_t));
    cname_iter_data_t cid = {
        .cnset = cnset,
        .res_name = res_name,
        .stanza = stanza,
        .item_idx = 0,
    };
    vscf_hash_iterate(cfg, true, config_item_cname, &cid);

    cnset->weight = 0;
    for(unsigned i = 0; i < cnset->count; i++) {
        const unsigned cwt = cnset->items[i].weight;
        dmn_assert(cwt);
        cnset->weight += cwt;
    }

    dmn_assert(cnset->weight);

    cnset->up_weight = ceil(up_thresh * cnset->weight);
}

F_NONNULL
static void config_auto(resource_t* res, const vscf_data_t* res_cfg) {
    dmn_assert(res); dmn_assert(res_cfg); dmn_assert(vscf_is_hash(res_cfg));

    // mark all possible parameter-keys
    vscf_hash_get_data_byconstkey(res_cfg, "service_types", true);
    vscf_hash_get_data_byconstkey(res_cfg, "multi", true);
    vscf_hash_get_data_byconstkey(res_cfg, "up_thresh", true);

    // make a copy that contains no parameters, only item-name keys
    vscf_data_t* res_cfg_noparams = vscf_clone(res_cfg, true);

    if(!vscf_hash_get_len(res_cfg_noparams))
        log_fatal("plugin_weighted: resource '%s' (direct) contains no weighted items", res->name);

    const char* first_name = vscf_hash_get_key_byindex(res_cfg_noparams, 0, NULL);
    const vscf_data_t* first_cfg = vscf_hash_get_data_byindex(res_cfg_noparams, 0);
    if(vscf_is_hash(first_cfg)) { // grouped address mode...
        if(!vscf_hash_get_len(first_cfg))
            log_fatal("plugin_weighted: resource '%s' (direct): group '%s': contains no addresses", res->name, first_name);
        const char* lb_name = vscf_hash_get_key_byindex(first_cfg, 0, NULL);
        const vscf_data_t* lb_cfg = vscf_hash_get_data_byindex(first_cfg, 0);
        if(!vscf_is_array(lb_cfg) || !vscf_array_get_len(lb_cfg) || !vscf_is_simple(vscf_array_get_data(lb_cfg, 0)))
            log_fatal("plugin_weighted: resource '%s' (direct): group '%s': item '%s': value must be an array of [ IP, weight ]", res->name, first_name, lb_name);
        const char* first_addr_txt = vscf_simple_get_data(vscf_array_get_data(lb_cfg, 0));
        dmn_anysin_t temp_sin;
        int addr_err = gdnsd_anysin_getaddrinfo(first_addr_txt, NULL, &temp_sin);
        if(addr_err)
            log_fatal("plugin_weighted: resource '%s' (direct): group '%s': item '%s': could not parse '%s' as an IP address: %s", res->name, first_name, lb_name, first_addr_txt, gai_strerror(addr_err));
        if(temp_sin.sa.sa_family == AF_INET6) {
            res->addrs_v6 = calloc(1, sizeof(addrset_t));
            config_addrset(res->name, "direct", true, res->addrs_v6, res_cfg);
        }
        else {
            dmn_assert(temp_sin.sa.sa_family == AF_INET);
            res->addrs_v4 = calloc(1, sizeof(addrset_t));
            config_addrset(res->name, "direct", false, res->addrs_v4, res_cfg);
        }
    }
    else if(vscf_is_array(first_cfg)) { // ungrouped address, or cnames
        const vscf_data_t* first_ac = vscf_array_get_data(first_cfg, 0);
        if(!first_ac || !vscf_is_simple(first_ac))
            log_fatal("plugin_weighted: resource '%s' (direct): item '%s': first element of array should be an IP address or CNAME string", res->name, first_name);
        dmn_anysin_t temp_sin;
        if(gdnsd_anysin_getaddrinfo(vscf_simple_get_data(first_ac), NULL, &temp_sin)) {
            // was not a valid address, try cnames mode
            res->cnames = calloc(1, sizeof(cnset_t));
            config_cnameset(res->name, "direct", res->cnames, res_cfg);
        }
        else {
            // was a valid address, try addrset mode
            if(temp_sin.sa.sa_family == AF_INET6) {
                res->addrs_v6 = calloc(1, sizeof(addrset_t));
                config_addrset(res->name, "direct", true, res->addrs_v6, res_cfg);
            }
            else {
                dmn_assert(temp_sin.sa.sa_family == AF_INET);
                res->addrs_v4 = calloc(1, sizeof(addrset_t));
                config_addrset(res->name, "direct", false, res->addrs_v4, res_cfg);
            }
        }
    }
    else {
        log_fatal("plugin_weighted: resource '%s' (direct): item '%s': resource type not detectable (should be array of [ IP, weight ], array of [ CNAME, weight ], or hashed address group ...)", res->name, first_name);
    }

    vscf_destroy(res_cfg_noparams);
}