Пример #1
0
/**
 * Update serial.
 *
 */
ods_status
zone_update_serial(zone_type* zone)
{
    ods_status status = ODS_STATUS_OK;
    rrset_type* rrset = NULL;
    rr_type* soa = NULL;
    ldns_rr* rr = NULL;
    ldns_rdf* soa_rdata = NULL;

    ods_log_assert(zone);
    ods_log_assert(zone->apex);
    ods_log_assert(zone->name);
    ods_log_assert(zone->db);
    ods_log_assert(zone->signconf);

    if (zone->db->serial_updated) {
        /* already done, unmark and return ok */
        ods_log_debug("[%s] zone %s soa serial already up to date",
            zone_str, zone->name);
        zone->db->serial_updated = 0;
        return ODS_STATUS_OK;
    }
    rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
    ods_log_assert(rrset);
    ods_log_assert(rrset->rrs);
    ods_log_assert(rrset->rrs[0].rr);
    rr = ldns_rr_clone(rrset->rrs[0].rr);
    if (!rr) {
        ods_log_error("[%s] unable to update zone %s soa serial: failed to "
            "clone soa rr", zone_str, zone->name);
        return ODS_STATUS_ERR;
    }
    status = namedb_update_serial(zone->db, zone->signconf->soa_serial,
        zone->db->inbserial);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to update zone %s soa serial: %s",
            zone_str, zone->name, ods_status2str(status));
        ldns_rr_free(rr);
        return status;
    }
    ods_log_verbose("[%s] zone %s set soa serial to %u", zone_str,
        zone->name, zone->db->intserial);
    soa_rdata = ldns_rr_set_rdf(rr,
        ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
        zone->db->intserial), SE_SOA_RDATA_SERIAL);
    if (soa_rdata) {
        ldns_rdf_deep_free(soa_rdata);
        soa_rdata = NULL;
    } else {
        ods_log_error("[%s] unable to update zone %s soa serial: failed to "
            "replace soa serial rdata", zone_str, zone->name);
        ldns_rr_free(rr);
        return ODS_STATUS_ERR;
    }
    soa = rrset_add_rr(rrset, rr);
    ods_log_assert(soa);
    rrset_diff(rrset, 0, 0);
    zone->db->serial_updated = 0;
    return ODS_STATUS_OK;
}
Пример #2
0
/**
 * Merge zones.
 *
 */
void
zone_merge(zone_type* z1, zone_type* z2)
{
    const char* str;
    adapter_type* adtmp = NULL;

    if (!z1 || !z2) {
        return;
    }
    /* policy name */
    if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) {
        if (z2->policy_name) {
            str = strdup(z2->policy_name);
            if (!str) {
                ods_log_error("[%s] failed to merge policy %s name to zone "
                    "%s", zone_str, z2->policy_name, z1->name);
            } else {
                free((void*)z1->policy_name);
                z1->policy_name = str;
                z1->zl_status = ZONE_ZL_UPDATED;
            }
        } else {
            free((void*)z1->policy_name);
            z1->policy_name = NULL;
            z1->zl_status = ZONE_ZL_UPDATED;
        }
    }
    /* signconf filename */
    if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
        if (z2->signconf_filename) {
            str = strdup(z2->signconf_filename);
            if (!str) {
                ods_log_error("[%s] failed to merge signconf filename %s to "
                    "zone %s", zone_str, z2->policy_name, z1->name);
            } else {
                free((void*)z1->signconf_filename);
                z1->signconf_filename = str;
                z1->zl_status = ZONE_ZL_UPDATED;
            }
        } else {
            free((void*)z1->signconf_filename);
            z1->signconf_filename = NULL;
            z1->zl_status = ZONE_ZL_UPDATED;
        }
    }
    /* adapters */
    if (adapter_compare(z2->adinbound, z1->adinbound) != 0) {
        adtmp = z2->adinbound;
        z2->adinbound = z1->adinbound;
        z1->adinbound = adtmp;
        adtmp = NULL;
    }
    if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) {
        adtmp = z2->adoutbound;
        z2->adoutbound = z1->adoutbound;
        z1->adoutbound = adtmp;
        adtmp = NULL;
    }
    return;
}
Пример #3
0
/**
 * Publish the NSEC3 parameters as indicated by the signer configuration.
 *
 */
ods_status
zone_publish_nsec3param(zone_type* zone)
{
    rrset_type* rrset = NULL;
    rr_type* n3prr = NULL;
    ldns_rr* rr = NULL;
    ods_status status = ODS_STATUS_OK;

    if (!zone || !zone->name || !zone->db || !zone->signconf) {
        return ODS_STATUS_ASSERT_ERR;
    }
    if (!zone->signconf->nsec3params) {
        /* NSEC */
        ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC);
        return ODS_STATUS_OK;
    }

    if (!zone->signconf->nsec3params->rr) {
        rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
        if (!rr) {
            ods_log_error("[%s] unable to publish nsec3params for zone %s: "
                "error creating rr (%s)", zone_str, zone->name,
                ods_status2str(status));
            return ODS_STATUS_MALLOC_ERR;
        }
        ldns_rr_set_class(rr, zone->klass);
        ldns_rr_set_ttl(rr, 0);
        ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex));
        ldns_nsec3_add_param_rdfs(rr,
            zone->signconf->nsec3params->algorithm, 0,
            zone->signconf->nsec3params->iterations,
            zone->signconf->nsec3params->salt_len,
            zone->signconf->nsec3params->salt_data);
        /**
         * Always set bit 7 of the flags to zero,
         * according to rfc5155 section 11
         */
        ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0);
        zone->signconf->nsec3params->rr = rr;
    }
    ods_log_assert(zone->signconf->nsec3params->rr);
    status = zone_add_rr(zone, zone->signconf->nsec3params->rr, 0);
    if (status == ODS_STATUS_UNCHANGED) {
        /* rr already exists, adjust pointer */
        rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
        ods_log_assert(rrset);
        n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
        ods_log_assert(n3prr);
        if (n3prr->rr != zone->signconf->nsec3params->rr) {
            ldns_rr_free(zone->signconf->nsec3params->rr);
        }
        zone->signconf->nsec3params->rr = n3prr->rr;
        status = ODS_STATUS_OK;
    } else if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to publish nsec3params for zone %s: "
            "error adding nsec3params (%s)", zone_str,
            zone->name, ods_status2str(status));
    }
    return status;
}
/**
 * Create new NSEC3 parameters.
 *
 */
nsec3params_type*
nsec3params_create(void* sc, uint8_t algo, uint8_t flags, uint16_t iter,
    const char* salt)
{
    nsec3params_type* nsec3params = NULL;
    signconf_type* signconf = (signconf_type*) sc;
    uint8_t salt_len; /* calculate salt len */
    uint8_t* salt_data; /* calculate salt data */

    if (!sc) {
        return NULL;
    }
    nsec3params = (nsec3params_type*) allocator_alloc(signconf->allocator,
        sizeof(nsec3params_type));
    if (!nsec3params) {
        ods_log_error("[%s] unable to create: allocator_alloc() failed",
            nsec3_str);
        return NULL;
    }
    nsec3params->sc = sc;
    nsec3params->algorithm = algo;
    nsec3params->flags = flags;
    nsec3params->iterations = iter;
    /* construct the salt from the string */
    if (nsec3params_create_salt(salt, &salt_len, &salt_data) != 0) {
        ods_log_error("[%s] unable to create: create salt failed", nsec3_str);
        allocator_deallocate(signconf->allocator, (void*)nsec3params);
        return NULL;
    }
    nsec3params->salt_len = salt_len;
    nsec3params->salt_data = salt_data;
    nsec3params->rr = NULL;
    return nsec3params;
}
Пример #5
0
/**
 * Create new schedule.
 *
 */
schedule_type*
schedule_create(allocator_type* allocator)
{
    schedule_type* schedule;
    if (!allocator) {
        return NULL;
    }
    schedule = (schedule_type*) allocator_alloc(allocator,
        sizeof(schedule_type));
    if (!schedule) {
        ods_log_error("[%s] unable to create schedule: allocator_alloc() "
            "failed", schedule_str);
        return NULL;
    }
    schedule->allocator = allocator;
    schedule->loading = 0;
    schedule->flushcount = 0;
    schedule->tasks = ldns_rbtree_create(task_compare);
    if (!schedule->tasks) {
        ods_log_error("[%s] unable to create schedule: ldns_rbtree_create() "
            "failed", schedule_str);
        allocator_deallocate(allocator, (void*) schedule);
        return NULL;
    }
    lock_basic_init(&schedule->schedule_lock);
    return schedule;
}
/**
 * Convert salt to string.
 *
 */
const char*
nsec3params_salt2str(nsec3params_type* nsec3params)
{
    uint8_t *data;
    uint8_t salt_length = 0;
    uint8_t salt_pos = 0;
    int written = 0;
    char* str = NULL;
    ldns_buffer* buffer = NULL;

    salt_length = nsec3params->salt_len;
    data = nsec3params->salt_data;
    /* from now there are variable length entries so remember pos */
    if (salt_length == 0) {
        buffer = ldns_buffer_new(2);
        written = ldns_buffer_printf(buffer, "-");
    } else {
        buffer = ldns_buffer_new(salt_pos+1);
        for (salt_pos = 0; salt_pos < salt_length; salt_pos++) {
            written = ldns_buffer_printf(buffer, "%02x", data[salt_pos]);
        }
    }
    if (ldns_buffer_status(buffer) == LDNS_STATUS_OK) {
        str = ldns_buffer2str(buffer);
    } else if (written) {
        ods_log_error("[%s] unable to convert nsec3 salt to string: %s",
            nsec3_str, ldns_get_errorstr_by_id(ldns_buffer_status(buffer)));
    } else {
        ods_log_error("[%s] unable to convert nsec3 salt to string: zero "
            "bytes written", nsec3_str);
    }
    ldns_buffer_free(buffer);
    return (const char*) str;
}
Пример #7
0
/**
 * Check configuration.
 *
 */
ods_status
engine_config_check(engineconfig_type* config)
{
    if (!config) {
        ods_log_error("[%s] check failed: config does not exist", conf_str);
        return ODS_STATUS_CFG_ERR;
    }
    if (!config->policy_filename) {
        ods_log_error("[%s] check failed: no policy filename", conf_str);
        return ODS_STATUS_CFG_ERR;
    }
    if (!config->zonelist_filename) {
        ods_log_error("[%s] check failed: no zonelist filename", conf_str);
        return ODS_STATUS_CFG_ERR;
    }
    if (!config->clisock_filename) {
        ods_log_error("[%s] check failed: no socket filename", conf_str);
        return ODS_STATUS_CFG_ERR;
    }
    if (!config->datastore) {
        ods_log_error("[%s] check failed: no datastore", conf_str);
        return ODS_STATUS_CFG_ERR;
    }

    /*  [TODO] room for more checks here */

    return ODS_STATUS_OK;
}
Пример #8
0
/**
 * Make sure that no appointed jobs have failed.
 *
 */
static ods_status
worker_check_jobs(worker_type* worker, task_type* task) {
    ods_log_assert(worker);
    ods_log_assert(task);
    lock_basic_lock(&worker->worker_lock);
    if (worker->jobs_failed) {
        ods_log_error("[%s[%i]] sign zone %s failed: %u RRsets failed",
            worker2str(worker->type), worker->thread_num,
            task_who2str(task), worker->jobs_failed);
        lock_basic_unlock(&worker->worker_lock);
        return ODS_STATUS_ERR;
    } else if (worker->jobs_completed != worker->jobs_appointed) {
        ods_log_error("[%s[%i]] sign zone %s failed: processed %u of %u "
            "RRsets", worker2str(worker->type), worker->thread_num,
            task_who2str(task), worker->jobs_completed,
            worker->jobs_appointed);
        lock_basic_unlock(&worker->worker_lock);
        return ODS_STATUS_ERR;
    } else if (worker->need_to_exit) {
        ods_log_debug("[%s[%i]] sign zone %s failed: worker needs to exit",
            worker2str(worker->type), worker->thread_num, task_who2str(task));
        lock_basic_unlock(&worker->worker_lock);
        return ODS_STATUS_ERR;
    } else {
        ods_log_debug("[%s[%i]] sign zone %s ok: %u of %u RRsets "
            "succeeded", worker2str(worker->type), worker->thread_num,
            task_who2str(task), worker->jobs_completed,
            worker->jobs_appointed);
        ods_log_assert(worker->jobs_appointed == worker->jobs_completed);
    }
    lock_basic_unlock(&worker->worker_lock);
    return ODS_STATUS_OK;
}
Пример #9
0
/**
 * Create a new task.
 *
 */
task_type*
task_create(task_id what, time_t when, void* zone)
{
    allocator_type* allocator = NULL;
    task_type* task = NULL;

    if (!zone) {
        return NULL;
    }
    allocator = allocator_create(malloc, free);
    if (!allocator) {
        ods_log_error("[%s] unable to create task: allocator_create() failed",
            task_str);
        return NULL;
    }
    task = (task_type*) allocator_alloc(allocator, sizeof(task_type));
    if (!task) {
        ods_log_error("[%s] unable to create task: allocator_alloc() failed",
            task_str);
        allocator_cleanup(allocator);
        return NULL;
    }
    task->allocator = allocator;
    task->what = what;
    task->interrupt = TASK_NONE;
    task->halted = TASK_NONE;
    task->when = when;
    task->halted_when = 0;
    task->backoff = 0;
    task->flush = 0;
    task->zone = zone;
    return task;
}
Пример #10
0
/**
 * Set udp socket to non-blocking and bind.
 *
 */
static ods_status
sock_fcntl_and_bind(sock_type* sock, const char* node, const char* port,
    const char* stype, const char* fam)
{
    ods_log_assert(sock);
    ods_log_assert(port);
    ods_log_assert(stype);
    ods_log_assert(fam);
    if (fcntl(sock->s, F_SETFL, O_NONBLOCK) == -1) {
        ods_log_error("[%s] unable to set %s/%s socket '%s:%s' to "
            "non-blocking: fcntl() failed (%s)", sock_str, stype, fam,
            node?node:"localhost", port, strerror(errno));
        return ODS_STATUS_SOCK_FCNTL_NONBLOCK;
    }
    ods_log_debug("[%s] bind %s/%s socket '%s:%s'", sock_str, stype, fam,
        node?node:"localhost", port, strerror(errno));
    if (bind(sock->s, (struct sockaddr *) sock->addr->ai_addr,
        sock->addr->ai_addrlen) != 0) {
        ods_log_error("[%s] unable to bind %s/%s socket '%s:%s': bind() "
            "failed (%s)", sock_str, stype, fam, node?node:"localhost",
            port, strerror(errno));
        return ODS_STATUS_SOCK_BIND;
    }
    return ODS_STATUS_OK;
}
Пример #11
0
/**
 * Update DNS output adapter.
 *
 */
ods_status
dnsout_update(dnsout_type** addns, const char* filename, time_t* last_mod)
{
    dnsout_type* new_addns = NULL;
    time_t st_mtime = 0;
    ods_status status = ODS_STATUS_OK;

    if (!filename || !addns || !last_mod) {
        return ODS_STATUS_UNCHANGED;
    }
    /* read the new signer configuration */
    new_addns = dnsout_create();
    if (!new_addns) {
        ods_log_error("[%s] unable to update dnsout: dnsout_create() "
                      "failed", adapter_str);
        return ODS_STATUS_ERR;
    }
    status = dnsout_read(new_addns, filename);
    if (status == ODS_STATUS_OK) {
        *addns = new_addns;
        *last_mod = st_mtime;
    } else {
        ods_log_error("[%s] unable to update dnsout: dnsout_read(%s) "
                      "failed (%s)", adapter_str, filename, ods_status2str(status));
        dnsout_cleanup(new_addns);
    }
    return status;
}
Пример #12
0
/**
 * Read DNS output adapter.
 *
 */
static ods_status
dnsout_read(dnsout_type* addns, const char* filename)
{
    const char* rngfile = ODS_SE_RNGDIR "/addns.rng";
    ods_status status = ODS_STATUS_OK;
    FILE* fd = NULL;
    if (!filename || !addns) {
        return ODS_STATUS_ASSERT_ERR;
    }
    ods_log_debug("[%s] read dnsout file %s", adapter_str, filename);
    status = parse_file_check(filename, rngfile);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to read dnsout: parse error in "
                      "file %s (%s)", adapter_str, filename, ods_status2str(status));
        return status;
    }
    fd = ods_fopen(filename, NULL, "r");
    if (fd) {
        addns->tsig = parse_addns_tsig(addns->allocator, filename);
        addns->provide_xfr = parse_addns_provide_xfr(addns->allocator,
                             filename, addns->tsig);
        addns->do_notify = parse_addns_do_notify(addns->allocator, filename,
                           addns->tsig);
        ods_fclose(fd);
        return ODS_STATUS_OK;
    }
    ods_log_error("[%s] unable to read dnsout: failed to open file %s",
                  adapter_str, filename);
    return ODS_STATUS_ERR;
}
Пример #13
0
/**
 * Create a new 'instant' duration.
 *
 */
duration_type*
duration_create(void)
{
    duration_type* duration;
    allocator_type* allocator = allocator_create(malloc, free);
    if (!allocator) {
        ods_log_error("[%s] cannot create: no allocator available",
            duration_str);
        return NULL;
    }

    duration = (duration_type*) allocator_alloc(allocator,
        sizeof(duration_type));
    if (!duration) {
        ods_log_error("[%s] cannot create: allocator failed", duration_str);
        allocator_cleanup(allocator);
        return NULL;
    }
    duration->allocator = allocator;
    duration->years = 0;
    duration->months = 0;
    duration->weeks = 0;
    duration->days = 0;
    duration->hours = 0;
    duration->minutes = 0;
    duration->seconds = 0;
    return duration;
}
Пример #14
0
/**
 * copycode: This code is based on the EXAMPLE in the strftime manual.
 *
 */
uint32_t
time_datestamp(time_t tt, const char* format, char** str)
{
    time_t t;
    struct tm *tmp;
    uint32_t ut = 0;
    char outstr[32];

    if (tt) {
        t = tt;
    } else {
        t = time_now();
    }

    tmp = localtime(&t);
    if (tmp == NULL) {
        ods_log_error("[%s] time_datestamp: localtime() failed", duration_str);
        return 0;
    }

    if (strftime(outstr, sizeof(outstr), format, tmp) == 0) {
        ods_log_error("[%s] time_datestamp: strftime() failed", duration_str);
        return 0;
    }

    ut = (uint32_t) strtoul(outstr, NULL, 10);
    if (str) {
        *str = strdup(outstr);
    }
    return ut;
}
Пример #15
0
/**
 * Self pipe trick (see Unix Network Programming).
 *
 */
static int
self_pipe_trick(engine_type* engine)
{
    int sockfd, ret;
    struct sockaddr_un servaddr;
    const char* servsock_filename = ODS_SE_SOCKFILE;
    ods_log_assert(engine);
    ods_log_assert(engine->cmdhandler);
    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd < 0) {
        ods_log_error("[%s] unable to connect to command handler: "
            "socket() failed (%s)", engine_str, strerror(errno));
        return 1;
    } else {
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sun_family = AF_UNIX;
        strncpy(servaddr.sun_path, servsock_filename,
            sizeof(servaddr.sun_path) - 1);
        ret = connect(sockfd, (const struct sockaddr*) &servaddr,
            sizeof(servaddr));
        if (ret != 0) {
            ods_log_error("[%s] unable to connect to command handler: "
                "connect() failed (%s)", engine_str, strerror(errno));
            close(sockfd);
            return 1;
        } else {
            /* self-pipe trick */
            ods_writen(sockfd, "", 1);
            close(sockfd);
        }
    }
    return 0;
}
Пример #16
0
/**
 * IXFR.
 *
 */
static query_state
query_process_ixfr(query_type* q)
{
    uint16_t count = 0;
    ods_log_assert(q);
    ods_log_assert(q->buffer);
    ods_log_assert(buffer_pkt_qdcount(q->buffer) == 1);
    /* skip header and question section */
    buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE);
    if (!buffer_skip_rr(q->buffer, 1)) {
        ods_log_error("[%s] dropped packet: zone %s received bad ixfr "
            "request (bad question section)", query_str, q->zone->name);
        return QUERY_DISCARDED;
    }
    /* answer section is empty */
    ods_log_assert(buffer_pkt_ancount(q->buffer) == 0);
    /* examine auth section */
    q->startpos = buffer_position(q->buffer);
    count = buffer_pkt_nscount(q->buffer);
    if (count) {
        if (!buffer_skip_dname(q->buffer) ||
            !query_parse_soa(q->buffer, &(q->serial))) {
            ods_log_error("[%s] dropped packet: zone %s received bad ixfr "
                "request (bad soa in auth section)", query_str, q->zone->name);
            return QUERY_DISCARDED;
        }
        ods_log_debug("[%s] found ixfr request zone %s serial=%u", query_str,
            q->zone->name, q->serial);
        return QUERY_PROCESSED;
    }
    ods_log_debug("[%s] ixfr request zone %s has no auth section", query_str,
        q->zone->name);
    q->serial = 0;
    return QUERY_PROCESSED;
}
Пример #17
0
/**
 * (Create) and change ownership of directories
 *
 */
void
ods_chown(const char* file, uid_t uid, gid_t gid, int getdir)
{
    char* dir = NULL;

    if (!file) {
        ods_log_warning("[%s] no filename given for chown()", file_str);
        return;
    }

    if (!getdir) {
        ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
           file_str, file, (signed long) uid, (signed long) gid);
        if (chown(file, uid, gid) != 0) {
            ods_log_error("[%s] chown() %s failed: %s", file_str, file,
                strerror(errno));
        }
    } else if ((dir = ods_dir_name(file)) != NULL) {
        ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
            file_str, dir, (signed long) uid, (signed long) gid);
        if (chown(dir, uid, gid) != 0) {
            ods_log_error("[%s] chown() %s failed: %s", file_str,
                dir, strerror(errno));
        }
        free((void*) dir);
    } else {
        ods_log_warning("[%s] use of relative path: %s", file_str, file);
    }
}
Пример #18
0
/**
 * Write zonefile.
 *
 */
ods_status
adfile_write(void* zone, const char* filename)
{
    FILE* fd = NULL;
    char* tmpname = NULL;
    zone_type* adzone = (zone_type*) zone;
    ods_status status = ODS_STATUS_OK;

    /* [start] sanity parameter checking */
    if (!adzone || !adzone->adoutbound) {
        ods_log_error("[%s] unable to write file: no output adapter",
            adapter_str);
        return ODS_STATUS_ASSERT_ERR;
    }
    if (!filename) {
        ods_log_error("[%s] unable to write file: no filename given",
            adapter_str);
        return ODS_STATUS_ASSERT_ERR;
    }
    /* [end] sanity parameter checking */

    /* [start] write zone */
    tmpname = ods_build_path(filename, ".tmp", 0, 0);
    if (!tmpname) {
        return ODS_STATUS_MALLOC_ERR;
    }
    fd = ods_fopen(tmpname, NULL, "w");
    if (fd) {
        status = adapi_printzone(fd, adzone);
        ods_fclose(fd);
        if (status == ODS_STATUS_OK) {
            if (adzone->adoutbound->error) {
                ods_log_error("[%s] unable to write zone %s file %s: one or "
                    "more RR print failed", adapter_str, adzone->name,
                    filename);
                /* clear error */
                adzone->adoutbound->error = 0;
                status = ODS_STATUS_FWRITE_ERR;
            }
        }
    } else {
        status = ODS_STATUS_FOPEN_ERR;
    }

    if (status == ODS_STATUS_OK) {
        if (rename((const char*) tmpname, filename) != 0) {
            ods_log_error("[%s] unable to write file: failed to rename %s "
                "to %s (%s)", adapter_str, tmpname, filename, strerror(errno));
            status = ODS_STATUS_RENAME_ERR;
        }
    }
    free(tmpname);
    /* [end] write zone */
    return status;
}
Пример #19
0
/**
 * Update zone list.
 *
 */
ods_status
zonelist_update(zonelist_type* zl, const char* zlfile)
{
    zonelist_type* new_zlist = NULL;
    allocator_type* tmp_alloc = NULL;
    time_t st_mtime = 0;
    ods_status status = ODS_STATUS_OK;
    char* datestamp = NULL;

    ods_log_debug("[%s] update zone list", zl_str);
    if (!zl|| !zl->zones || !zlfile) {
        return ODS_STATUS_ASSERT_ERR;
    }
    /* is the file updated? */
    st_mtime = ods_file_lastmodified(zlfile);
    if (st_mtime <= zl->last_modified) {
        (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
        ods_log_debug("[%s] zonelist file %s is unchanged since %s",
                      zl_str, zlfile, datestamp?datestamp:"Unknown");
        free((void*)datestamp);
        return ODS_STATUS_UNCHANGED;
    }
    /* create new zonelist */
    tmp_alloc = allocator_create(malloc, free);
    if (!tmp_alloc) {
        return ODS_STATUS_MALLOC_ERR;
    }
    new_zlist = zonelist_create(tmp_alloc);
    if (!new_zlist) {
        ods_log_error("[%s] unable to update zonelist: zonelist_create() "
                      "failed", zl_str);
        allocator_cleanup(tmp_alloc);
        return ODS_STATUS_ERR;
    }
    /* read zonelist */
    status = zonelist_read(new_zlist, zlfile);
    if (status == ODS_STATUS_OK) {
        zl->just_removed = 0;
        zl->just_added = 0;
        zl->just_updated = 0;
        new_zlist->last_modified = st_mtime;
        zonelist_merge(zl, new_zlist);
        (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
        ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
                      datestamp?datestamp:"Unknown");
        free((void*)datestamp);
    } else {
        ods_log_error("[%s] unable to update zonelist: read file %s failed "
                      "(%s)", zl_str, zlfile, ods_status2str(status));
    }
    zonelist_free(new_zlist);
    allocator_cleanup(tmp_alloc);
    return status;
}
Пример #20
0
/**
 * Parse elements from the configuration file.
 *
 */
const char*
parse_conf_string(const char* cfgfile, const char* expr, int required)
{
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr xpathCtx = NULL;
    xmlXPathObjectPtr xpathObj = NULL;
    xmlChar *xexpr = NULL;
    const char* string = NULL;

    ods_log_assert(expr);
    ods_log_assert(cfgfile);

    /* Load XML document */
    doc = xmlParseFile(cfgfile);
    if (doc == NULL) {
        return NULL;
    }
    /* Create xpath evaluation context */
    xpathCtx = xmlXPathNewContext(doc);
    if (xpathCtx == NULL) {
        ods_log_error("[%s] unable to create new XPath context for cfgile "
            "%s expr %s", parser_str, cfgfile, (char*) expr);
        xmlFreeDoc(doc);
        return NULL;
    }
    /* Get string */
    xexpr = (unsigned char*) expr;
    xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
    if (xpathObj == NULL || xpathObj->nodesetval == NULL ||
        xpathObj->nodesetval->nodeNr <= 0) {
        if (required) {
            ods_log_error("[%s] unable to evaluate required element %s in "
                "cfgfile %s", parser_str, (char*) xexpr, cfgfile);
        }
        xmlXPathFreeContext(xpathCtx);
        if (xpathObj) {
            xmlXPathFreeObject(xpathObj);
        }
        xmlFreeDoc(doc);
        return NULL;
    }
    if (xpathObj->nodesetval != NULL &&
        xpathObj->nodesetval->nodeNr > 0) {
        string = (const char*) xmlXPathCastToString(xpathObj);
        xmlXPathFreeContext(xpathCtx);
        xmlXPathFreeObject(xpathObj);
        xmlFreeDoc(doc);
        return string;
    }
    xmlXPathFreeContext(xpathCtx);
    xmlXPathFreeObject(xpathObj);
    xmlFreeDoc(doc);
    return NULL;
}
Пример #21
0
/**
 * Create engine.
 *
 */
static engine_type*
engine_create(void)
{
    engine_type* engine;
    allocator_type* allocator = allocator_create(malloc, free);
    if (!allocator) {
        ods_log_error("[%s] unable to create engine: allocator_create() "
            "failed", engine_str);
        return NULL;
    }
    engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type));
    if (!engine) {
        ods_log_error("[%s] unable to create engine: allocator_alloc() "
            "failed", engine_str);
        allocator_cleanup(allocator);
        return NULL;
    }
    engine->allocator = allocator;
    engine->config = NULL;
    engine->workers = NULL;
    engine->drudgers = NULL;
    engine->cmdhandler = NULL;
    engine->cmdhandler_done = 0;
    engine->dnshandler = NULL;
    engine->xfrhandler = NULL;
    engine->pid = -1;
    engine->uid = -1;
    engine->gid = -1;
    engine->daemonize = 0;
    engine->need_to_exit = 0;
    engine->need_to_reload = 0;
    lock_basic_init(&engine->signal_lock);
    lock_basic_set(&engine->signal_cond);
    lock_basic_lock(&engine->signal_lock);
    engine->signal = SIGNAL_INIT;
    lock_basic_unlock(&engine->signal_lock);
    engine->zonelist = zonelist_create(engine->allocator);
    if (!engine->zonelist) {
        engine_cleanup(engine);
        return NULL;
    }
    engine->taskq = schedule_create(engine->allocator);
    if (!engine->taskq) {
        engine_cleanup(engine);
        return NULL;
    }
    engine->signq = fifoq_create(engine->allocator);
    if (!engine->signq) {
        engine_cleanup(engine);
        return NULL;
    }
    return engine;
}
Пример #22
0
/**
 * Push an interface to the listener.
 *
 */
interface_type*
listener_push(listener_type* listener, char* address, int family, char* port)
{
    interface_type* ifs_old = NULL;
    ods_log_assert(listener);
    ods_log_assert(address);
    ifs_old = listener->interfaces;
    listener->interfaces = (interface_type*) allocator_alloc(
        listener->allocator, (listener->count + 1) * sizeof(interface_type));
    if (!listener->interfaces) {
        ods_log_error("[%s] unable to add interface: allocator_alloc() failed",
            listener_str);
        exit(1);
    }
    if (ifs_old) {
        memcpy(listener->interfaces, ifs_old,
           (listener->count) * sizeof(interface_type));
    }
    allocator_deallocate(listener->allocator, (void*) ifs_old);
    listener->count++;
    listener->interfaces[listener->count -1].address =
        allocator_strdup(listener->allocator, address);
    listener->interfaces[listener->count -1].family = family;

    if (port) {
        listener->interfaces[listener->count -1].port =
            allocator_strdup(listener->allocator, port);
    } else{
        listener->interfaces[listener->count -1].port = NULL;
    }
    memset(&listener->interfaces[listener->count -1].addr, 0,
        sizeof(union acl_addr_storage));
    if (listener->interfaces[listener->count -1].family == AF_INET6 &&
        strlen(listener->interfaces[listener->count -1].address) > 0) {
        if (inet_pton(listener->interfaces[listener->count -1].family,
            listener->interfaces[listener->count -1].address,
            &listener->interfaces[listener->count -1].addr.addr6) != 1) {
            ods_log_error("[%s] bad ip address '%s'",
                listener->interfaces[listener->count -1].address);
            return NULL;
        }
    } else if (listener->interfaces[listener->count -1].family == AF_INET &&
        strlen(listener->interfaces[listener->count -1].address) > 0) {
        if (inet_pton(listener->interfaces[listener->count -1].family,
            listener->interfaces[listener->count -1].address,
            &listener->interfaces[listener->count -1].addr.addr) != 1) {
            ods_log_error("[%s] bad ip address '%s'",
                listener->interfaces[listener->count -1].address);
            return NULL;
        }
    }
    return &listener->interfaces[listener->count -1];
}
Пример #23
0
/**
 * File copy.
 *
 */
ods_status
ods_file_copy(const char* file1, const char* file2, long startpos, int append)
{
    char buf[BUFFER_SIZE];
    int fin = 0;
    int fout = 0;
    int read_size = 0;
    if (!file1 || !file2) {
        return ODS_STATUS_ASSERT_ERR;
    }
    if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) {
        return ODS_STATUS_FOPEN_ERR;
    }
    if (append) {
        fout = open(file2, O_WRONLY|O_APPEND|O_CREAT, 0666);
    } else {
        fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666);
}
    if (fout < 0) {
        close(fin);
        return ODS_STATUS_FOPEN_ERR;
    }
    ods_log_debug("[%s] lseek file %s pos %ld", file_str, file1, startpos);
    if (lseek(fin, startpos, SEEK_SET) < 0) {
        close(fin);
        close(fout);
        return ODS_STATUS_FSEEK_ERR;
    }
    while (1) {
        read_size = read(fin, buf, sizeof(buf));
        if (read_size == 0) {
            break;
        }
        if (read_size < 0) {
            ods_log_error("[%s] read file %s error %s", file_str, file1,
                strerror(errno));
            close(fin);
            close(fout);
            return ODS_STATUS_FREAD_ERR;
        }
        if (write(fout, buf, (unsigned int) read_size) < 0) {
            ods_log_error("[%s] write file %s error %s", file_str, file1,
                strerror(errno));
            close(fin);
            close(fout);
            return ODS_STATUS_FWRITE_ERR;
        }
    }
    close(fin);
    close(fout);
    return ODS_STATUS_OK;
}
Пример #24
0
/**
 * Create zone transfer handler.
 *
 */
xfrhandler_type*
xfrhandler_create()
{
    xfrhandler_type* xfrh = NULL;
    CHECKALLOC(xfrh = (xfrhandler_type*) malloc(sizeof(xfrhandler_type)));
    xfrh->engine = NULL;
    xfrh->packet = NULL;
    xfrh->netio = NULL;
    xfrh->tcp_set = NULL;
    xfrh->tcp_waiting_first = NULL;
    xfrh->udp_waiting_first = NULL;
    xfrh->udp_waiting_last = NULL;
    xfrh->udp_use_num = 0;
    xfrh->start_time = 0;
    xfrh->current_time = 0;
    xfrh->got_time = 0;
    xfrh->need_to_exit = 0;
    xfrh->started = 0;
    /* notify */
    xfrh->notify_waiting_first = NULL;
    xfrh->notify_waiting_last = NULL;
    xfrh->notify_udp_num = 0;
    /* setup */
    xfrh->netio = netio_create();
    if (!xfrh->netio) {
        ods_log_error("[%s] unable to create xfrhandler: "
            "netio_create() failed", xfrh_str);
        xfrhandler_cleanup(xfrh);
        return NULL;
    }
    xfrh->packet = buffer_create(PACKET_BUFFER_SIZE);
    if (!xfrh->packet) {
        ods_log_error("[%s] unable to create xfrhandler: "
            "buffer_create() failed", xfrh_str);
        xfrhandler_cleanup(xfrh);
        return NULL;
    }
    xfrh->tcp_set = tcp_set_create();
    if (!xfrh->tcp_set) {
        ods_log_error("[%s] unable to create xfrhandler: "
            "tcp_set_create() failed", xfrh_str);
        xfrhandler_cleanup(xfrh);
        return NULL;
    }
    xfrh->dnshandler.fd = -1;
    xfrh->dnshandler.user_data = (void*) xfrh;
    xfrh->dnshandler.timeout = 0;
    xfrh->dnshandler.event_types = NETIO_EVENT_READ;
    xfrh->dnshandler.event_handler = xfrhandler_handle_dns;
    xfrh->dnshandler.free_handler = 0;
    return xfrh;
}
/**
 * Create dns handler.
 *
 */
dnshandler_type*
dnshandler_create(allocator_type* allocator, listener_type* interfaces)
{
    dnshandler_type* dnsh = NULL;
    if (!allocator || !interfaces || interfaces->count <= 0) {
        return NULL;
    }
    dnsh = (dnshandler_type*) allocator_alloc(allocator,
        sizeof(dnshandler_type));
    if (!dnsh) {
        ods_log_error("[%s] unable to create dnshandler: "
            "allocator_alloc() failed", dnsh_str);
        return NULL;
    }
    dnsh->allocator = allocator;
    dnsh->need_to_exit = 0;
    dnsh->engine = NULL;
    dnsh->interfaces = interfaces;
    dnsh->socklist = NULL;
    dnsh->netio = NULL;
    dnsh->query = NULL;
    /* setup */
    dnsh->socklist = (socklist_type*) allocator_alloc(allocator,
        sizeof(socklist_type));
    if (!dnsh->socklist) {
        ods_log_error("[%s] unable to create socklist: "
            "allocator_alloc() failed", dnsh_str);
        dnshandler_cleanup(dnsh);
        return NULL;
    }
    dnsh->netio = netio_create(allocator);
    if (!dnsh->netio) {
        ods_log_error("[%s] unable to create dnshandler: "
            "netio_create() failed", dnsh_str);
        dnshandler_cleanup(dnsh);
        return NULL;
    }
    dnsh->query = query_create();
    if (!dnsh->query) {
        ods_log_error("[%s] unable to create dnshandler: "
            "query_create() failed", dnsh_str);
        dnshandler_cleanup(dnsh);
        return NULL;
    }
    dnsh->xfrhandler.fd = -1;
    dnsh->xfrhandler.user_data = (void*) dnsh;
    dnsh->xfrhandler.timeout = 0;
    dnsh->xfrhandler.event_types = NETIO_EVENT_READ;
    dnsh->xfrhandler.event_handler = dnshandler_handle_xfr;
    return dnsh;
}
Пример #26
0
/**
 * Get the user identifier from the username.
 *
 */
uid_t
privuid(const char* username)
{
    struct passwd pwd;
    struct passwd* result;
    long bufsize;
    char* buf;
    uid_t uid;
    int s;
    uid = geteuid();
    if (username) {
        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
        if (bufsize == -1) {
            bufsize = 16384; /* should be more than enough */
        }
        buf = (char*) calloc(bufsize, sizeof(char));
        if (!buf) {
            ods_log_crit("[%s] calloc failed: insufficient memory", logstr);
            return -1;
        }
        /* Lookup the user id in /etc/passwd */
        s = getpwnam_r(username, &pwd, buf, bufsize, &result); /* leaks? */
        if (s) {
            ods_log_error("[%s] unable to get user id for %s: %s",
                logstr, username, strerror(s));
        }
        if (result != NULL) {
            uid = pwd.pw_uid;
        }
        free(buf);
    } else {
        uid = -1;
    }
    return uid;
}
Пример #27
0
static int
run(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
{
    db_connection_t* dbconn = getconnectioncontext(context);
    engine_type* engine = getglobalcontext(context);
    (void)cmd;

    if (!engine) {
        return 1;
    }
    if (!engine->config) {
        return 1;
    }
    if (!engine->config->zonelist_filename) {
        return 1;
    }
    if (!dbconn) {
        return 1;
    }

    ods_log_debug("[%s] %s command", module_str, zonelist_export_funcblock.cmdname);

    if (zonelist_export(sockfd, dbconn, engine->config->zonelist_filename, 1) != ZONELIST_EXPORT_OK) {
        ods_log_error("[%s] zonelist exported to %s failed", module_str, engine->config->zonelist_filename);
        client_printf_err(sockfd, "Exported zonelist to %s failed!\n", engine->config->zonelist_filename);
        return 1;
    }

    ods_log_info("[%s] zonelist exported to %s successfully", module_str, engine->config->zonelist_filename);
    client_printf(sockfd, "Exported zonelist to %s successfully\n", engine->config->zonelist_filename);
    return 0;
}
Пример #28
0
/**
 * Sign notify.
 *
 */
static void
notify_tsig_sign(notify_type* notify, buffer_type* buffer)
{
    tsig_algo_type* algo = NULL;
    if (!notify || !notify->tsig_rr || !notify->secondary ||
        !notify->secondary->tsig || !notify->secondary->tsig->key ||
        !buffer) {
        return; /* no tsig configured */
    }
    algo = tsig_lookup_algo(notify->secondary->tsig->algorithm);
    if (!algo) {
        ods_log_error("[%s] unable to sign notify: tsig unknown algorithm "
            "%s", notify_str, notify->secondary->tsig->algorithm);
        return;
    }
    ods_log_assert(algo);
    tsig_rr_reset(notify->tsig_rr, algo, notify->secondary->tsig->key);
    notify->tsig_rr->original_query_id = buffer_pkt_id(buffer);
    notify->tsig_rr->algo_name =
        ldns_rdf_clone(notify->tsig_rr->algo->wf_name);
    notify->tsig_rr->key_name = ldns_rdf_clone(notify->tsig_rr->key->dname);
    log_dname(notify->tsig_rr->key_name, "tsig sign notify with key %s",
        LOG_DEBUG);
    log_dname(notify->tsig_rr->algo_name, "tsig sign notify with algorithm %s",
        LOG_DEBUG);
    tsig_rr_prepare(notify->tsig_rr);
    tsig_rr_update(notify->tsig_rr, buffer, buffer_position(buffer));
    tsig_rr_sign(notify->tsig_rr);
    ods_log_debug("[%s] tsig append rr to notify id=%u", notify_str,
        buffer_pkt_id(buffer));
    tsig_rr_append(notify->tsig_rr, buffer);
    buffer_pkt_set_arcount(buffer, buffer_pkt_arcount(buffer)+1);
    tsig_rr_prepare(notify->tsig_rr);
    return;
}
Пример #29
0
/**
 * Create new schedule. Allocate and initialise scheduler. To clean
 * up schedule_cleanup() should be called.
 */
schedule_type*
schedule_create()
{
    schedule_type* schedule;
    struct sigaction action;

    schedule = (schedule_type*) malloc(sizeof(schedule_type));
    if (!schedule) {
        ods_log_error("[%s] unable to create: malloc failed", schedule_str);
        return NULL;
    }

    schedule->tasks = ldns_rbtree_create(task_compare);
    schedule->tasks_by_name = ldns_rbtree_create(task_compare_name);
    pthread_mutex_init(&schedule->schedule_lock, NULL);
    pthread_cond_init(&schedule->schedule_cond, NULL);
    /* static condition for alarm. Must be accessible from interrupt */
    schedule_cond = &schedule->schedule_cond;

    action.sa_handler = (void (*)(int))&alarm_handler;
    sigfillset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGALRM, &action, NULL);
    
    return schedule;
}
Пример #30
0
/**
 * Start zone transfer handler.
 *
 */
void
xfrhandler_start(xfrhandler_type* xfrhandler)
{
    ods_log_assert(xfrhandler);
    ods_log_assert(xfrhandler->engine);
    ods_log_debug("[%s] start", xfrh_str);
    /* setup */
    xfrhandler->start_time = time_now();
    /* handlers */
    netio_add_handler(xfrhandler->netio, &xfrhandler->dnshandler);
    /* service */
    while (xfrhandler->need_to_exit == 0) {
        /* dispatch may block for a longer period, so current is gone */
        xfrhandler->got_time = 0;
        ods_log_deeebug("[%s] netio dispatch", xfrh_str);
        if (netio_dispatch(xfrhandler->netio, NULL, NULL) == -1) {
            if (errno != EINTR) {
                ods_log_error("[%s] unable to dispatch netio: %s", xfrh_str,
                    strerror(errno));
            }
        }
    }
    /* shutdown */
    ods_log_debug("[%s] shutdown", xfrh_str);
}