Beispiel #1
0
static bool config_res(const char* resname, unsigned resname_len V_UNUSED, vscf_data_t* addr, void* data) {
    unsigned* residx_ptr = data;

    if(vscf_get_type(addr) != VSCF_SIMPLE_T)
        log_fatal("plugin_static: resource %s: must be an IP address or a domainname in string form", resname);

    unsigned res = (*residx_ptr)++;
    resources[res].name = strdup(resname);

    const char* addr_txt = vscf_simple_get_data(addr);
    if(gdnsd_anysin_fromstr(addr_txt, 0, &resources[res].addr)) {
        // Address-parsing failed, treat as domainname for DYNC
        resources[res].is_addr = false;
        resources[res].dname = xmalloc(256);
        dname_status_t status = vscf_simple_get_as_dname(addr, resources[res].dname);
        if(status == DNAME_INVALID)
            log_fatal("plugin_static: resource %s: must be an IPv4 address or a domainname in string form", resname);
        if(status == DNAME_VALID)
            resources[res].dname = dname_trim(resources[res].dname);
    }
    else {
        resources[res].is_addr = true;
    }

    return true;
}
Beispiel #2
0
F_NONNULL
static dc_t* config_res_perdc(const unsigned mapnum, const vscf_data_t* cfg, const char* resname) {
    dmn_assert(cfg); dmn_assert(resname);
    dmn_assert(vscf_is_hash(cfg));

    const unsigned num_dcs = vscf_hash_get_len(cfg);
    dc_t* store = calloc((num_dcs + 1), sizeof(dc_t));
    for(unsigned i = 0; i < num_dcs; i++) {
        const char* dcname = vscf_hash_get_key_byindex(cfg, i, NULL);
        const unsigned dc_idx = map_get_dcidx(mapnum, dcname);
        if(!dc_idx)
            log_fatal("plugin_" PNSTR ": resource '%s': datacenter name '%s' is not valid", resname, dcname);
        dmn_assert(dc_idx <= num_dcs);
        dc_t* this_dc = &store[dc_idx];
        this_dc->dc_name = strdup(dcname);
        const vscf_data_t* plugdata = vscf_hash_get_data_byindex(cfg, i);
        if(vscf_is_simple(plugdata)) {
            const char* textdata = vscf_simple_get_data(plugdata);
            if(*textdata == '%') {
                char* child_plugname = strdup(textdata + 1);
                this_dc->plugin_name = child_plugname;
                char* child_resname = strchr(child_plugname, '!');
                if(child_resname) {
                    *child_resname++ = '\0';
                    this_dc->res_name = strdup(child_resname);
                }
                if(!strcmp(this_dc->plugin_name, PNSTR) && !strcmp(this_dc->res_name, resname))
                    log_fatal("plugin_" PNSTR ": resource '%s': not allowed to reference itself!", resname);
            }
            else if(*textdata == '!') {
                this_dc->res_name = strdup(textdata + 1);
                const vscf_data_t* res_cfg = vscf_get_parent(cfg);
                this_dc->plugin_name = get_defaulted_plugname(res_cfg, resname, dcname);
                if(!strcmp(this_dc->plugin_name, PNSTR) && !strcmp(this_dc->res_name, resname))
                    log_fatal("plugin_" PNSTR ": resource '%s': not allowed to reference itself!", resname);
            }
            else {
                anysin_t tempsin;
                if(gdnsd_anysin_getaddrinfo(textdata, NULL, &tempsin)) {
                    // failed to parse as address, so set up direct CNAME if possible
                    uint8_t* dname = malloc(256);
                    dname_status_t dnstat = vscf_simple_get_as_dname(plugdata, dname);
                    if(dnstat == DNAME_INVALID)
                        log_fatal("plugin_" PNSTR ": resource '%s': CNAME for datacenter '%s' is not a legal domainname", resname, dcname);
                    if(dnstat == DNAME_VALID)
                        dname = dname_trim(dname);
                    this_dc->dname = dname;
                }
                else {
                    inject_child_plugin_config(this_dc, resname, (vscf_data_t*)plugdata);
                }
            }
        }
        else {
            inject_child_plugin_config(this_dc, resname, (vscf_data_t*)plugdata);
        }
    }
    return store;
}
Beispiel #3
0
F_NONNULL
static void config_addrset(const char* res_name, const char* stanza, const bool ipv6, addrset_t* addrset, const vscf_data_t* cfg) {
    dmn_assert(res_name); dmn_assert(stanza); dmn_assert(addrset); dmn_assert(cfg);

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

    const vscf_data_t* parent = vscf_get_parent(cfg);

    // inherit down the applicable res-level parameters
    vscf_hash_inherit(parent, (vscf_data_t*)cfg, "service_types", true);
    vscf_hash_inherit(parent, (vscf_data_t*)cfg, "multi", true);
    vscf_hash_inherit(parent, (vscf_data_t*)cfg, "up_thresh", true);

    // Get a starting assumption of our item count
    addrset->count = vscf_hash_get_len(cfg);

    /////// Process the parameters...

    // service_types
    const vscf_data_t* res_stypes = vscf_hash_get_data_byconstkey(cfg, "service_types", true);
    if (res_stypes) {
        addrset->count--; // minus one for service_types entry
        addrset->num_svcs = vscf_array_get_len(res_stypes);
        if(!addrset->num_svcs)
            log_fatal("plugin_weighted: resource '%s' (%s): service_types cannot be an empty array", res_name, stanza);
        addrset->svc_names = malloc(addrset->num_svcs * sizeof(char*));
        for(unsigned i = 0; i < addrset->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);
            addrset->svc_names[i] = strdup(vscf_simple_get_data(this_svc_cfg));
        }
    }
    else {
        addrset->num_svcs = 1;
        addrset->svc_names = malloc(sizeof(char*));
        addrset->svc_names[0] = strdup("default");
    }

    // multi option
    addrset->multi = false;
    const vscf_data_t* multi_cfg = vscf_hash_get_data_byconstkey(cfg, "multi", true);
    if(multi_cfg) {
        addrset->count--; // minus one for multi entry
        if(!vscf_is_simple(multi_cfg) || !vscf_simple_get_as_bool(multi_cfg, &addrset->multi))
            log_fatal("plugin_weighted: resource '%s' (%s): 'multi' must be a boolean value ('true' or 'false')", res_name, stanza);
    }

    // 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) {
        addrset->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);
    }

    if(addrset->count > MAX_ITEMS_PER_SET)
        log_fatal("plugin_weighted: resource '%s' (%s): number of direct groups or addrs within one family cannot be more than %u", res_name, stanza, MAX_ITEMS_PER_SET);
    if(!addrset->count)
        log_fatal("plugin_weighted: resource '%s' (%s): empty address-family sets not allowed", res_name, stanza);

    // track maximum res-size actually configured
    if(cfg_max_items_per_res < addrset->count)
        cfg_max_items_per_res = addrset->count;

    addrset->items = calloc(addrset->count, sizeof(res_aitem_t));
    addrset->gmode = RES_ASET_UNKNOWN;
    addr_iter_data_t aid = {
        .item_idx = 0,
        .addrset = addrset,
        .res_name = res_name,
        .stanza = stanza,
        .ipv6 = ipv6
    };
    vscf_hash_iterate(cfg, true, config_addrset_item, &aid);

    addrset->weight = 0;
    addrset->max_weight = 0;
    for(unsigned i = 0; i < addrset->count; i++) {
        const unsigned iwt = addrset->items[i].weight;
        dmn_assert(iwt); dmn_assert(addrset->items[i].max_weight);
        addrset->weight += iwt;
        if(addrset->max_weight < iwt)
            addrset->max_weight = iwt;
    }

    dmn_assert(addrset->weight);
    dmn_assert(addrset->max_weight);

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

typedef struct {
    cnset_t* cnset;
    const char* res_name;
    const char* stanza;
    unsigned item_idx;
} cname_iter_data_t;

F_NONNULL
static bool config_item_cname(const char* item_name, unsigned klen V_UNUSED, const vscf_data_t* cfg_data, void* cid_asvoid) {
    dmn_assert(item_name); dmn_assert(cfg_data); dmn_assert(cid_asvoid);
    cname_iter_data_t* cid = (cname_iter_data_t*)cid_asvoid;

    cnset_t* cnset = cid->cnset;
    const char* res_name = cid->res_name;
    const char* stanza = cid->stanza;
    const unsigned item_idx = cid->item_idx++;
    res_citem_t* res_item = &cnset->items[item_idx];

    long wtemp = 0;
    if(!vscf_is_array(cfg_data)
            || (2 != vscf_array_get_len(cfg_data))
            || !vscf_is_simple(vscf_array_get_data(cfg_data, 0))
            || !vscf_is_simple(vscf_array_get_data(cfg_data, 1))
            || !vscf_simple_get_as_long(vscf_array_get_data(cfg_data, 1), &wtemp)
            || wtemp < 1 || wtemp > MAX_WEIGHT )
        log_fatal("plugin_weighted: resource '%s' (%s), item '%s': values in cname mode must be arrays of [ CNAME, WEIGHT ], where weight must be an integer in the range 1 - " MAX_WEIGHT_STR, res_name, stanza, item_name);
    res_item->weight = wtemp;

    uint8_t* dname = malloc(256);
    dname_status_t dnstat = vscf_simple_get_as_dname(vscf_array_get_data(cfg_data, 0), dname);
    if(dnstat == DNAME_INVALID)
        log_fatal("plugin_weighted: resource '%s' (%s), item '%s': '%s' is not a legal domainname", res_name, stanza, item_name, vscf_simple_get_data(vscf_array_get_data(cfg_data, 0)));
    if(dnstat == DNAME_VALID)
        dname = dname_trim(dname);
    res_item->cname = dname;

    log_debug("plugin_weighted: resource '%s' (%s), item '%s', CNAME '%s' added with weight %u", res_name, stanza, item_name, logf_dname(dname), res_item->weight);

    return true;
}