Esempio n. 1
0
void plugin_extfile_add_svctype(const char* name, vscf_data_t* svc_cfg, const unsigned interval, const unsigned timeout) {
    dmn_assert(name); dmn_assert(svc_cfg);

    service_types = xrealloc(service_types, (num_svcs + 1) * sizeof(extf_svc_t));
    extf_svc_t* svc = &service_types[num_svcs++];

    svc->name = strdup(name);
    svc->timeout = timeout;
    svc->interval = interval;

    vscf_data_t* path_cfg = vscf_hash_get_data_byconstkey(svc_cfg, "file", true);
    if(!path_cfg || !vscf_is_simple(path_cfg))
        log_fatal("plugin_extfile: service_type '%s': the 'file' option is required and must be a string filename", name);
    svc->path = gdnsd_resolve_path_state(vscf_simple_get_data(path_cfg), "extfile");

    svc->direct = false;
    svc->def_sttl = GDNSD_STTL_TTL_MAX;
    SVC_OPT_BOOL(svc_cfg, name, direct, svc->direct);
    SVC_OPT_UINT(svc_cfg, name, def_ttl, svc->def_sttl, 1LU, (unsigned long)GDNSD_STTL_TTL_MAX);
    bool def_down = false;
    SVC_OPT_BOOL(svc_cfg, name, def_down, def_down);
    if(def_down)
        svc->def_sttl |= GDNSD_STTL_DOWN;

    svc->num_mons = 0;
    svc->mons = NULL;
}
Esempio n. 2
0
static void mon_child_cb(struct ev_loop* loop, ev_child* w, int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_CHILD);

    ev_child_stop(loop, w); // always single-shot

    mon_t* this_mon = w->data;
    ev_timer_stop(loop, this_mon->cmd_timeout);
    this_mon->cmd_pid = 0;

    bool failed = true;
    int status = w->rstatus;
    if(WIFEXITED(status)) {
        if(!WEXITSTATUS(status))
           failed = false;
    }
    else {
        if(WIFSIGNALED(status))
            dmn_log_warn("Monitor child process for '%s' terminated by signal %u", this_mon->cmd->desc, WTERMSIG(status));
        else
            dmn_log_warn("Monitor child process for '%s' terminated abnormally...", this_mon->cmd->desc);
    }

    // If timeout already sent a failure, don't double-send
    //   here when we reap the SIGKILL'd child
    if(this_mon->result_pending) {
        if(!killed_by) {
            sendq_enq(emc_encode_mon(this_mon->cmd->idx, failed));
            ev_io_start(loop, plugin_write_watcher);
        }
        if (num_proc > 0) {
            num_proc--;
        }
        this_mon->result_pending = false;
    }
}
Esempio n. 3
0
File: ntree.c Progetto: fabled/gdnsd
F_NONNULL
static unsigned ntree_lookup_inner(const ntree_t* tree, const anysin_t* client_addr, unsigned* scope_mask) {
    dmn_assert(tree); dmn_assert(client_addr); dmn_assert(scope_mask);

    unsigned rv;

    if(client_addr->sa.sa_family == AF_INET) {
        rv = ntree_lookup_v4(tree, ntohl(client_addr->sin.sin_addr.s_addr), scope_mask);
    }
    else {
        dmn_assert(client_addr->sa.sa_family == AF_INET6);
        unsigned mask_adj = 0; // for v4-like conversions...
        const uint32_t ipv4 = v6_v4fixup(client_addr->sin6.sin6_addr.s6_addr, &mask_adj);
        if(mask_adj) {
            unsigned temp_mask;
            rv = ntree_lookup_v4(tree, ipv4, &temp_mask);
            *scope_mask = temp_mask + mask_adj;
        }
        else {
            rv = ntree_lookup_v6(tree, client_addr->sin6.sin6_addr.s6_addr, scope_mask);
        }
    }

    return rv;
}
Esempio n. 4
0
F_NONNULL
static unsigned res_get_mapnum(const vscf_data_t* res_cfg, const char* res_name) {
    dmn_assert(res_cfg); dmn_assert(res_name);

    // Get 'dclist' name, convert, store, return 0-based dclist index
    const vscf_data_t* dc_cfg = vscf_hash_get_data_byconstkey(res_cfg, "datacenters", true);
    if(!dc_cfg)
        log_fatal("plugin_metafo: resource '%s': required key 'datacenters' is missing", res_name);
    dclist_t* dcl = malloc(sizeof(dclist_t));
    if(vscf_is_hash(dc_cfg) || !(dcl->num_dcs = vscf_array_get_len(dc_cfg)))
        log_fatal("plugin_metafo: resource '%s': 'datacenters' must be an array of one or more datacenter name strings", res_name);

    uint8_t* dclptr = dcl->dc_list = malloc(dcl->num_dcs + 1);
    dcl->dc_names = malloc((dcl->num_dcs + 1) * sizeof(char*));
    dcl->dc_names[0] = NULL; // index zero is invalid
    for(unsigned i = 0; i < dcl->num_dcs; i++) {
        const vscf_data_t* dcname_cfg = vscf_array_get_data(dc_cfg, i);
        if(!dcname_cfg || !vscf_is_simple(dcname_cfg))
            log_fatal("plugin_metafo: resource '%s': 'datacenters' must be an array of one or more datacenter name strings", res_name);
        const unsigned dcidx = i + 1;
        *dclptr++ = dcidx;
        dcl->dc_names[dcidx] = strdup(vscf_simple_get_data(dcname_cfg));
    }
    *dclptr = 0;

    const unsigned rv_idx = num_dclists++;
    dclists = realloc(dclists, num_dclists * sizeof(dclist_t*));
    dclists[rv_idx] = dcl;
    return rv_idx;
}
Esempio n. 5
0
F_NONNULL
static uint32_t geoip2_get_dclist_cached(geoip2_t* db, const uint32_t offset) {
    dmn_assert(db);

    // In GeoIP2, an offset of zero means not found in the DB, so default it.
    // (even if it works in geoip2_get_dclist(), the offset cache can't handle
    // an offset of zero efficiently anyways).
    if(!offset)
        return 0;

    unsigned bucket_size = 0;
    const unsigned ndx = offset % OFFSET_CACHE_SIZE;

    if(db->offset_cache[ndx]) {
        for(bucket_size = 0; db->offset_cache[ndx][bucket_size].offset; bucket_size++)
            if(db->offset_cache[ndx][bucket_size].offset == offset)
                return db->offset_cache[ndx][bucket_size].dclist;
    }

    const uint32_t dclist = geoip2_get_dclist(db, offset);
    db->offset_cache[ndx] = xrealloc(db->offset_cache[ndx], sizeof(offset_cache_item_t) * (bucket_size + 2));
    dmn_assert(db->offset_cache[ndx]);
    db->offset_cache[ndx][bucket_size].offset = offset;
    db->offset_cache[ndx][bucket_size].dclist = dclist;
    db->offset_cache[ndx][bucket_size + 1].offset = 0;
    dmn_assert(dclist <= DCLIST_MAX); // auto not allowed here, should have been resolved earlier
    return dclist;
}
Esempio n. 6
0
F_NONNULL
static void die_gracefully(struct ev_loop* loop) {
    dmn_assert(loop);

    dmn_assert(killed_by);
    static bool done_once = false;
    if(!done_once) { // avoid repetition
        done_once = true;
        // send friendly death message to plugin
        sendq_enq(emc_encode_exit());
        ev_io_start(loop, plugin_write_watcher);
        // kill interval timers for future invocations
        //   and immediately clamp the remaining timeout
        //   for any running commands to 2.0s.
        for(unsigned i = 0; i < num_mons; i++) {
            ev_timer_stop(loop, mons[i].interval_timer);
            if(ev_is_active(mons[i].cmd_timeout)) {
                if(ev_timer_remaining(loop, mons[i].cmd_timeout) > 2.0) {
                    ev_timer_stop(loop, mons[i].cmd_timeout);
                    ev_timer_set(mons[i].cmd_timeout, 2.0, 0.);
                    ev_timer_start(loop, mons[i].cmd_timeout);
                }
            }
        }
    }
}
Esempio n. 7
0
static plugin_t* gdnsd_plugin_load(const char* pname) {
    dmn_assert(pname); dmn_assert(psearch);

    plugin_t* plug = plugin_allocate(pname);
    void* pptr = plugin_dlopen(pname);
    const gdnsd_apiv_cb_t apiv = (gdnsd_apiv_cb_t)plugin_dlsym(pptr, pname, "get_api_version");
    if(!apiv)
        log_fatal("Plugin '%s' does not appear to be a valid gdnsd plugin", pname);

    // The raw number for the API version is now split into two 16-bit chunks:
    //    the bottom 16 bits are still a regular version number
    //    the top 16 bits are build option flags that affect binary compatibility
    //      (these come from <gdnsd/bopt.h> for 3rd party plugins)
    const uint32_t this_version = apiv();
    if(this_version != GDNSD_PLUGIN_API_VERSION) {
        unsigned apiv_vers = GDNSD_PLUGIN_API_VERSION & 0xFFFF;
        unsigned apiv_bopt = GDNSD_PLUGIN_API_VERSION >> 16;
        unsigned this_vers = this_version & 0xFFFF;
        unsigned this_bopt = this_version >> 16;
        if(apiv_vers != this_vers)
            log_fatal("Plugin '%s' needs to be recompiled! (wanted API version %u, got %u)",
                pname, apiv_vers, this_vers);
        else
            log_fatal("Plugin '%s' needs to be recompiled! (wanted build options %x, got %x)",
                pname, apiv_bopt, this_bopt);
    }
Esempio n. 8
0
void gdmaps_test_lookup_check(const gdmaps_t* gdmaps, const char* map_name, const char* addr_txt, const char* dclist_cmp, const unsigned scope_cmp) {
    dmn_assert(gdmaps);
    dmn_assert(map_name);
    dmn_assert(addr_txt);
    dmn_assert(dclist_cmp);

    const int rv = gdmaps_name2idx(gdmaps, map_name);
    if(rv < 0)
        log_fatal("Map name '%s' not found in configuration", map_name);

    const unsigned map_idx = (unsigned)rv;

    client_info_t cinfo;
    cinfo.edns_client_mask = 128U;
    unsigned scope = 175U;

    const int addr_err = gdnsd_anysin_getaddrinfo(addr_txt, NULL, &cinfo.edns_client);
    if(addr_err)
        log_fatal("Cannot parse address '%s': %s", addr_txt, gai_strerror(addr_err));

    const uint8_t* dclist = gdmaps_lookup(gdmaps, map_idx, &cinfo, &scope);

    ok(!strcmp((const char*)dclist, dclist_cmp),
        "gdmaps_lookup(%s, %s) returns dclist %s (got %s)",
            map_name, addr_txt,
            gdmaps_logf_dclist(gdmaps, map_idx, (const uint8_t*)dclist_cmp),
            gdmaps_logf_dclist(gdmaps, map_idx, dclist));

    ok(scope == scope_cmp,
        "gdmaps_lookup(%s, %s) returns scope %u (got %u)",
            map_name, addr_txt, scope_cmp, scope);
}
Esempio n. 9
0
// grow a dnhash_t's hashtable size by doubling
F_NONNULL
static void dnhash_grow(dnhash_t* dnhash) {
    dmn_assert(dnhash); dmn_assert(dnhash->count);
    // assert that dnhash->mask is still 2^n-1 and >0
    dmn_assert(dnhash->mask); dmn_assert(!((dnhash->mask + 1U) & dnhash->mask));

    const uint8_t** old_table = dnhash->table;
    const unsigned old_mask = dnhash->mask;
    const unsigned new_mask = (old_mask << 1U) | 1U;
    const uint8_t** new_table = xcalloc(new_mask + 1U, sizeof(uint8_t*));
    for(unsigned i = 0; i <= old_mask; i++) {
        const uint8_t* item = old_table[i];
        if(item) {
            unsigned jmpby = 1U;
            unsigned new_slot = dname_hash(item) & new_mask;
            while(new_table[new_slot]) {
                new_slot += jmpby++;
                new_slot &= new_mask;
            }
            new_table[new_slot] = item;
        }
    }

    free(dnhash->table);
    dnhash->table = new_table;
    dnhash->mask = new_mask;
}
Esempio n. 10
0
static void plugin_write_cb(struct ev_loop* loop, ev_io* w, int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_WRITE);

    while(!sendq_empty()) {
        const uint32_t data = sendq_deq_peek();
        int rv = write(plugin_write_fd, &data, 4);
        if(rv != 4) {
            if(rv < 0) {
                if(errno == EAGAIN)
                    return; // pipe full, wait for more libev notification of write-ready
                else if(errno == EINTR)
                    continue; // try this write again immediately
                else {
                    ev_break(loop, EVBREAK_ALL);
                    return;
                }
            }
            else if(rv == 0) {
                ev_break(loop, EVBREAK_ALL);
                return;
            }
            else {
                log_fatal("BUG: atomic pipe write of 4 bytes was not atomic, retval was %u", rv);
            }
        }
        sendq_deq_commit();
    }
    ev_io_stop(loop, w); // queue now empty
}
Esempio n. 11
0
static void plugin_write_cb(struct ev_loop* loop, ev_io* w, int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_WRITE);

    dmn_assert(plugin_write_fd > -1);
    while(!sendq_empty()) {
        const uint32_t data = sendq_deq_peek();
        ssize_t write_rv = write(plugin_write_fd, &data, 4);
        if(write_rv != 4) {
            if(write_rv < 0) {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                    return; // pipe full, wait for more libev notification of write-ready
                else if(errno == EINTR)
                    continue; // try this write again immediately
                else {
                    ev_break(loop, EVBREAK_ALL);
                    return;
                }
            }
            else if(write_rv == 0) {
                ev_break(loop, EVBREAK_ALL);
                return;
            }
            else {
                log_fatal("BUG: atomic pipe write of 4 bytes was not atomic, retval was %zi", write_rv);
            }
        }
        sendq_deq_commit();
    }
    ev_io_stop(loop, w); // queue now empty

    if(killed_by) { // we've sent our final message, close
        close(plugin_write_fd);
        plugin_write_fd = -1;
    }
}
Esempio n. 12
0
F_NONNULL
static void make_resource(resource_t* res, const char* res_name, const vscf_data_t* res_cfg) {
    dmn_assert(res);
    dmn_assert(res_name);
    dmn_assert(res_cfg);

    res->name = strdup(res_name);

    if(!vscf_is_hash(res_cfg))
        log_fatal("plugin_" PNSTR ": the value of resource '%s' must be a hash", res_name);

    res->map = res_get_mapnum(res_cfg, res_name);
    unsigned dc_count = map_get_len(res->map);
    dmn_assert(dc_count); // empty lists not allowed!

    // the core item: dcmap (dc -> result map)
    const vscf_data_t* dcs_cfg = vscf_hash_get_data_byconstkey(res_cfg, "dcmap", true);
    if(!dcs_cfg)
        log_fatal("plugin_" PNSTR ": resource '%s': missing required stanza 'dcmap'", res_name);

    // Get/check datacenter count
    res->num_dcs = vscf_hash_get_len(dcs_cfg);

    if(res->num_dcs != dc_count)
        log_fatal("plugin_" PNSTR ": resource '%s': the dcmap does not match the datacenters list", res_name);

    res->dcs = config_res_perdc(res->map, dcs_cfg, res_name);
}
Esempio n. 13
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;
}
Esempio n. 14
0
F_NONNULL
static void dnhash_destroy(dnhash_t* dnhash) {
    dmn_assert(dnhash);
    dmn_assert(dnhash->table);
    dmn_assert(dnhash->mask);
    free(dnhash->table);
    free(dnhash);
}
Esempio n. 15
0
File: main.c Progetto: fabled/gdnsd
F_NONNULL
static void terminal_signal(struct ev_loop* loop, struct ev_signal *w, const int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(w);
    dmn_assert(revents == EV_SIGNAL);
    dmn_assert(w->signum == SIGTERM || w->signum == SIGINT);

    log_info("Received terminating signal %i, exiting", w->signum);
    ev_break(loop, EVBREAK_ALL);
}
Esempio n. 16
0
void plugin_http_status_init_monitors(struct ev_loop* mon_loop) {
    dmn_assert(mon_loop);

    for(unsigned int i = 0; i < num_mons; i++) {
        ev_timer* ival_watcher = mons[i]->interval_watcher;
        dmn_assert(mons[i]->sock == -1);
        ev_timer_set(ival_watcher, 0, 0);
        ev_timer_start(mon_loop, ival_watcher);
    }
}
Esempio n. 17
0
F_MALLOC F_WUNUSED
static dnhash_t* dnhash_new(void) {
    dmn_assert(INIT_DNHASH_MASK);
    dmn_assert(!((INIT_DNHASH_MASK + 1U) & INIT_DNHASH_MASK)); // 2^n-1

    dnhash_t* rv = xmalloc(sizeof(dnhash_t));
    rv->count = 0;
    rv->mask = INIT_DNHASH_MASK;
    rv->table = xcalloc(INIT_DNHASH_MASK + 1U, sizeof(uint8_t*));
    return rv;
}
Esempio n. 18
0
F_NONNULL
static gen_func_ptr plugin_dlsym(void* handle, const char* pname, const char* sym_suffix) {
    dmn_assert(handle); dmn_assert(pname); dmn_assert(sym_suffix);

    // If you see an aliasing warning here, it's ok to ignore it
    char* symname = gdnsd_str_combine_n(4, "plugin_", pname, "_", sym_suffix);
    gen_func_ptr rval;
    *(void**)(&rval) = dlsym(handle, symname);
    free(symname);
    return rval;
}
Esempio n. 19
0
F_NONNULL
static void statio_fill_outbuf_csv(struct iovec* outbufs) {
    dmn_assert(outbufs);
    populate_stats();

    dmn_assert(pop_statio_time >= start_time);

    outbufs[1].iov_len = snprintf(outbufs[1].iov_base, data_buffer_size, csv_fixed, (uint64_t)pop_statio_time - start_time, statio.dns_noerror, statio.dns_refused, statio.dns_nxdomain, statio.dns_notimp, statio.dns_badvers, statio.dns_formerr, statio.dns_dropped, statio.dns_v6, statio.dns_edns, statio.dns_edns_clientsub, statio.udp_reqs, statio.udp_recvfail, statio.udp_sendfail, statio.udp_tc, statio.udp_edns_big, statio.udp_edns_tc, statio.tcp_reqs, statio.tcp_recvfail, statio.tcp_sendfail);

    outbufs[1].iov_len += monio_stats_out_csv(ADDVOID(outbufs[1].iov_base, outbufs[1].iov_len));
    outbufs[0].iov_len = snprintf(outbufs[0].iov_base, hdr_buffer_size, http_headers, "text/plain", (unsigned)outbufs[1].iov_len);
}
Esempio n. 20
0
F_NONNULL
static unsigned map_get_dcidx(const unsigned mapnum, const char* dcname) {
    dmn_assert(dcname);
    dmn_assert(mapnum < num_dclists);

    dclist_t* this_map = dclists[mapnum];
    for(unsigned i = 1; i <= this_map->num_dcs; i++)
        if(!strcmp(dcname, this_map->dc_names[i]))
            return i;

    return 0;
}
Esempio n. 21
0
F_NONNULL
static void do_lookup(const gdmaps_t* gdmaps, const char* map_name, const char* ip_arg) {
    dmn_assert(gdmaps); dmn_assert(map_name); dmn_assert(ip_arg);

    int map_idx = gdmaps_name2idx(gdmaps, map_name);
    if(map_idx < 0) {
        log_err("Mapping name '%s' not found in configuration", map_name);
        return;
    }

    client_info_t cinfo;

    // mostly ignored, but needs to be nonzero, and 150 is interesting in that
    //  it easily differentiates source -> scope copies from actual database scope netmasks,
    //  since it's larger than any legal netmask in the database.
    cinfo.edns_client_mask = 150U;

    const int addr_err = gdnsd_anysin_getaddrinfo(ip_arg, NULL, &cinfo.edns_client);
    if(addr_err) {
        log_err("Could not parse address '%s': %s", ip_arg, gai_strerror(addr_err));
        return;
    }

    // To void gdmaps fallback pitfalls
    memcpy(&cinfo.dns_source, &cinfo.edns_client, sizeof(dmn_anysin_t));

    // w/ edns_client_mask set, scope_mask should *always* be set by gdmaps_lookup();
    // (and regardless, dclist should also always be set and contain something)
    unsigned scope_mask = 175U;
    const uint8_t* dclist = gdmaps_lookup(gdmaps, map_idx, &cinfo, &scope_mask);
    dmn_assert(scope_mask != 175U);
    dmn_assert(dclist);

    // Scope was set to Source.  Since we always query as edns, this implies
    //  the database was V4-only and the address input was a non-v4-compat v6 address,
    //  and the lookup code fell back to the default dclist (1).
    if(scope_mask == 150U) {
        printf(
            "%s => %s => %s\n",
            map_name, dmn_logf_anysin_noport(&cinfo.edns_client),
            gdmaps_logf_dclist(gdmaps, map_idx, dclist)
        );
    }
    else {
        printf(
            "%s => %s/%u => %s\n",
            map_name, dmn_logf_anysin_noport(&cinfo.edns_client), scope_mask,
            gdmaps_logf_dclist(gdmaps, map_idx, dclist)
        );
    }

    dmn_fmtbuf_reset();
}
Esempio n. 22
0
File: ntree.c Progetto: fabled/gdnsd
unsigned ntree_add_node(ntree_t* tree) {
    dmn_assert(tree);
    dmn_assert(tree->alloc);
    if(tree->count == tree->alloc) {
        tree->alloc <<= 1;
        tree->store = realloc(tree->store, tree->alloc * sizeof(nnode_t));
    }
    const unsigned rv = tree->count;
    dmn_assert(rv < (1U << 24));
    tree->count++;
    return rv;
}
Esempio n. 23
0
F_NONNULL
static bool config_addr_group_addr(const char* lb_name, const unsigned lb_name_len, const vscf_data_t* lb_data, void* iaga_asvoid) {
    dmn_assert(lb_name); dmn_assert(lb_name_len); dmn_assert(lb_data); dmn_assert(iaga_asvoid);

    iaga_t* iaga = (iaga_t*)iaga_asvoid;

    addrset_t* addrset = iaga->addrset;
    res_aitem_t* res_item = iaga->res_item;
    unsigned lb_idx = iaga->lb_idx++;
    const char* res_name = iaga->res_name;
    const char* stanza = iaga->stanza;
    const char* item_name = iaga->item_name;
    const bool ipv6 = iaga->ipv6;
    const unsigned res_name_len = strlen(res_name);
    const unsigned item_name_len = strlen(item_name);

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

    res_item->as[lb_idx].states = calloc(addrset->num_svcs, sizeof(mon_state_t));
    res_item->as[lb_idx].weight = lb_weight;

    const char* addr_txt = vscf_simple_get_data(vscf_array_get_data(lb_data, 0));
    int addr_err = gdnsd_anysin_getaddrinfo(addr_txt, NULL, &res_item->as[lb_idx].addr);
    if(addr_err)
        log_fatal("plugin_weighted: resource '%s', group '%s', addr '%s': parsing '%s' as an IP address failed: %s", res_name, item_name, lb_name, addr_txt, gai_strerror(addr_err));
    if(ipv6 && res_item->as[lb_idx].addr.sa.sa_family != AF_INET6)
        log_fatal("plugin_weighted: resource '%s' (%s): item '%s': '%s' is IPv4, was expecting IPv6", res_name, stanza, item_name, addr_txt);
    else if(!ipv6 && res_item->as[lb_idx].addr.sa.sa_family != AF_INET)
        log_fatal("plugin_weighted: resource '%s' (%s): item '%s': '%s' is IPv6, was expecting IPv4", res_name, stanza, item_name, addr_txt);

    for(unsigned i = 0; i < addrset->num_svcs; i++) {
        const unsigned svc_name_len = strlen(addrset->svc_names[i]);
        char *complete_desc = malloc(res_name_len + 1 + 4 + 1 + item_name_len + 1 + lb_name_len + 1 + svc_name_len + 1);
        sprintf(complete_desc, "%s/%s/%s/%s/%s", res_name, ipv6 ? "ipv6" : "ipv4", item_name, lb_name, addrset->svc_names[i]);
        mon_list.info = realloc(mon_list.info, sizeof(mon_info_t) * (mon_list.count + 1));
        mon_info_t* m = &mon_list.info[mon_list.count++];
        m->svctype = addrset->svc_names[i];
        m->desc = complete_desc;
        m->addr = addr_txt;
        m->state_ptr = &res_item->as[lb_idx].states[i];
    }

    log_debug("plugin_weighted: resource '%s' (%s), item '%s', address %s added with weight %u", res_name, stanza, item_name, addr_txt, res_item->as[lb_idx].weight);

    return true;
}
Esempio n. 24
0
F_NONNULL
static const vscf_data_t* conf_load(const char* cfg_file) {
    dmn_assert(cfg_file);

    char* vscf_err;
    const vscf_data_t* cfg_root = vscf_scan_filename(cfg_file, &vscf_err);
    if(!cfg_root)
        log_fatal("Configuration load failed: %s", vscf_err);

    dmn_assert(vscf_is_hash(cfg_root));
    return cfg_root;
}
Esempio n. 25
0
File: ntree.c Progetto: fabled/gdnsd
// returns either a node offset for the true ipv4 root
//   node at exactly ::/96, or a terminal dclist
//   for a wholly enclosing supernet.  This is cached
//   for the tree to make various ipv4-related lookups
//   faster and simpler.
F_NONNULL
static unsigned ntree_find_v4root(const ntree_t* tree) {
    dmn_assert(tree);

    unsigned offset = 0;
    unsigned mask_depth = 96;
    do {
        dmn_assert(offset < tree->count);
        offset = tree->store[offset].zero;
    } while(--mask_depth && !NN_IS_DCLIST(offset));

    return offset;
}
Esempio n. 26
0
void plugin_http_status_start_monitors(struct ev_loop* mon_loop) {
    dmn_assert(mon_loop);

    for(unsigned int i = 0; i < num_mons; i++) {
        http_events_t* mon = mons[i];
        dmn_assert(mon->sock == -1);
        const unsigned ival = mon->http_svc->interval;
        const double stagger = (((double)i) / ((double)num_mons)) * ((double)ival);
        ev_timer* ival_watcher = mon->interval_watcher;
        ev_timer_set(ival_watcher, stagger, ival);
        ev_timer_start(mon_loop, ival_watcher);
    }
}
Esempio n. 27
0
F_NONNULL F_NOINLINE
static void isolate_jmp(geoip2_t* db, nlist_t** nl) {
    dmn_assert(db); dmn_assert(nl);

    *nl = nlist_new(db->map_name, true);
    if(!sigsetjmp(db->jbuf, 0)) {
        geoip2_list_xlate(db, *nl);
        nlist_finish(*nl);
    }
    else {
        nlist_destroy(*nl);
        *nl = NULL;
    }
}
Esempio n. 28
0
File: misc.c Progetto: adibshh/gdnsd
char* gdnsd_str_combine(const char* s1, const char* s2, const char** s2_offs) {
    dmn_assert(s1); dmn_assert(s2);
    const unsigned s1_len = strlen(s1);
    const unsigned s2_len = strlen(s2);
    char* out = xmalloc(s1_len + s2_len + 1);
    char* work = out;
    memcpy(work, s1, s1_len);
    work += s1_len;
    memcpy(work, s2, s2_len);
    work[s2_len] = 0;
    if(s2_offs)
        *s2_offs = work;
    return out;
}
Esempio n. 29
0
F_NONNULL
static void mon_read_cb(struct ev_loop* loop, struct ev_io* io, const int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(io);
    dmn_assert(revents == EV_READ);

    http_events_t* md = (http_events_t*)io->data;

    dmn_assert(md);
    dmn_assert(md->hstate == HTTP_STATE_READING);
    dmn_assert(ev_is_active(md->read_watcher));
    dmn_assert(!ev_is_active(md->write_watcher));
    dmn_assert(md->sock > -1);

    bool final_status = false;
    const int to_recv = 13 - md->done;
    const int recvd = recv(md->sock, md->res_buf + md->done, to_recv, 0);
    if(unlikely(recvd == -1)) {
        switch(errno) {
            case EAGAIN:
            case EINTR:
                return;
            case ETIMEDOUT:
            case ENOTCONN:
            case ECONNRESET:
            case EPIPE:
                break;
            default:
                log_err("plugin_http_status: read() from monitoring socket failed, possible local problem: %s", logf_errno());
        }
    }
    else if(recvd < to_recv) {
        md->done += recvd;
        return;
    }
    else {
        md->res_buf[13] = '\0';
        char code_str[4] = { 0 };
        if(1 == sscanf(md->res_buf, "HTTP/1.%*1[01]%*1[ ]%3c%*1[ ]", code_str)) {
            unsigned long lcode = strtoul(code_str, NULL, 10);
            for(unsigned i = 0; i < md->http_svc->num_ok_codes; i++) {
                if(lcode == md->http_svc->ok_codes[i]) {
                    final_status = true;
                    break;
                }
            }
        }
    }

    // I don't believe we actually need to read the rest of the response before
    //   shutdown/close in order to avoid bad TCP behavior, but I could be wrong.

    log_debug("plugin_http_status: State poll of %s %s", md->smgr->desc, final_status ? "succeeded" : "failed");
    shutdown(md->sock, SHUT_RDWR);
    close(md->sock);
    md->sock = -1;
    ev_io_stop(loop, md->read_watcher);
    ev_timer_stop(loop, md->timeout_watcher);
    md->hstate = HTTP_STATE_WAITING;
    gdnsd_mon_state_updater(md->smgr, final_status);
}
Esempio n. 30
0
static void make_req_data(http_svc_t* s, const char* url_path, const char* vhost) {
    dmn_assert(s); dmn_assert(url_path);
    const unsigned url_len = strlen(url_path);
    if(vhost) {
        s->req_data_len = 25 + url_len + strlen(vhost);
        s->req_data = malloc(s->req_data_len + 1);
        snprintf(s->req_data, s->req_data_len + 1, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", url_path, vhost);
    }
    else {
        s->req_data_len = 17 + url_len;
        s->req_data = malloc(s->req_data_len + 1);
        snprintf(s->req_data, s->req_data_len + 1, "GET %s HTTP/1.0\r\n\r\n", url_path);
    }
}