static void*
scheduler_queue_dnskey_create_thread(void* data_)
{
    scheduler_dnskey_create *data = (scheduler_dnskey_create*)data_;
    ya_result return_value;
    
    log_info("dnssec: key create (%{dnsname} %hd %hhd %hd)", data->zone->origin, data->flags, data->algorithm, data->size);

    char origin[MAX_DOMAIN_LENGTH];

    dnsname_to_cstr(origin, data->zone->origin);

    dnssec_key* key;
    
    if(ISOK(return_value = dnssec_key_createnew(DNSKEY_ALGORITHM_RSASHA1_NSEC3, data->size, data->flags, origin, &key)))
    {
        if(ISOK(return_value = dnssec_key_store_private(key)))
        {
            if(ISOK(return_value = dnssec_key_store_dnskey(key)))
            {
                log_info("dnssec: key created (%{dnsname} %hd %hhd %hd)", data->zone->origin, data->flags, data->algorithm, data->size);    
            }
            else
            {
                log_err("dnssec: key store public (%{dnsname} %hd %hhd %hd): %r", data->zone->origin, data->flags, data->algorithm, data->size, return_value);
            }
        }
        else
        {
            log_err("dnssec: key store private (%{dnsname} %hd %hhd %hd): %r", data->zone->origin, data->flags, data->algorithm, data->size, return_value);
        }
    }
    else
    {
        log_err("dnssec: key create failed (%{dnsname} %hd %hhd %hd): %r", data->zone->origin, data->flags, data->algorithm, data->size, return_value);
    }

    if(ISOK(return_value))
    {
        data->key = key;
    }
    else
    {
        dnssec_key_free(key);
        
        data->key = NULL;
    }
    
    scheduler_schedule_task(scheduler_queue_dnskey_create_callback, data);

    /* WARNING: From this point forward, 'data' cannot be used anymore */

    /*
     * The key is still in the keystore.
     *
     */

    return NULL;
}
Esempio n. 2
0
static asynStatus executeCommand(Port* pport,asynUser* pasynUser)
{
    int i;
    asynStatus sts;

    asynPrint(pasynUser,ASYN_TRACE_FLOW,"drvLove::executeCommand\n");
    pasynUser->timeout = K_COMTMO;

    for( i = 0; i < 3; ++i )
    {
        epicsThreadSleep( K_TUNE );

        sts = sendCommand(pport,pasynUser,i);
        if( ISOK(sts) )
            asynPrint(pasynUser,ASYN_TRACEIO_FILTER,"drvLove::executeCommand write \"%s\"\n",pport->outMsg);
        else
        {
            if( sts == asynTimeout )
            {
                asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::executeCommand write timeout, retrying\n");
                continue;
            }

            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::executeCommand write failure - Sent \"%s\" \n",pport->outMsg);
            return( sts );
        }

        sts = recvReply(pport,pasynUser,pport->inpMsg,sizeof(pport->inpMsg));
        if( ISOK(sts) )
            asynPrint(pasynUser,ASYN_TRACEIO_FILTER,"drvLove::executeCommand read \"%s\"\n",pport->inpMsg);
        else
        {
            if( sts == asynTimeout )
            {
                asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::executeCommand read timeout, retrying\n");
                continue;
            }

            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::executeCommand read failure - Sent \"%s\" Rcvd \"%s\" \n",pport->outMsg,pport->inpMsg);
            return( sts );
        }

        return( asynSuccess );
    }

    asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::executeCommand retries exceeded\n");
    return( asynError );
}
Esempio n. 3
0
ya_result
nsec3_load_add_rrsig(nsec3_load_context *context, const  u8 *digest_label, s32 ttl, const u8 *rdata, u16 rdata_size)
{
    u8 digest_len = BASE32HEX_DECODED_LEN(digest_label[0]);
    u8 digest[digest_len + 1];
    digest[0] = digest_len;
    if(ISOK(base32hex_decode((const char*)&digest_label[1], digest_label[0], &digest[1])))
    {
        zdb_packed_ttlrdata *rrsig;
        ZDB_RECORD_ZALLOC(rrsig,ttl,rdata_size,rdata);
                
        if(context->last_inserted_nsec3 != NULL)
        {
            nsec3_context_record* nsec3_r = (nsec3_context_record*)context->last_inserted_nsec3;
            if(memcmp(nsec3_r->digest_then_rdata, digest, 1 + digest[0]) == 0)
            {
                rrsig->next = nsec3_r->rrsig;
                nsec3_r->rrsig = rrsig;
                
                return SUCCESS;
            }
        }
        
        // the records are not nicely ordered : need to postpone the insertion of this record.
        
        ptr_node *node = ptr_set_avl_insert(&context->postponed_rrsig, digest);
                
        if(node->value == NULL)
        {
            u8 *key;
            ZALLOC_ARRAY_OR_DIE(u8*, key, digest_len + 1, N3LKEYDG_TAG);
            memcpy(key, digest, digest_len + 1);
            node->key = key;
        }
Esempio n. 4
0
static nsec3_context_record*
nsec3_load_context_record_new(const u8 *digest, s32 ttl, const u8 *rdata, u16 rdata_size)
{
    u8 digest_len = BASE32HEX_DECODED_LEN(digest[0]);
 
    nsec3_context_record* record;
        
    ZALLOC_ARRAY_OR_DIE(nsec3_context_record*, record, sizeof(nsec3_context_record) + 1 + digest_len + rdata_size, N3LCTXRR_TAG);
    record->rrsig = NULL;
    record->ttl = ttl;
    record->rdata_size = rdata_size;
    
    //memcpy(&record->digest_then_rdata[0], digest, digest_len);
    record->digest_then_rdata[0] = digest_len;
    
    if(ISOK(base32hex_decode((const char*)&digest[1], digest[0], &record->digest_then_rdata[1])))
    {
        memcpy(&record->digest_then_rdata[digest_len + 1], rdata, rdata_size);    
        return record;
    }
    else
    {
        nsec3_load_context_record_delete(record);
        return NULL;
    }
}
Esempio n. 5
0
nsec3_zone_item*
nsec3_get_nsec3_by_name(zdb_zone* zone, const u8 *nsec3_label, const u8* nsec3_rdata)
{
    nsec3_zone* n3 = zone->nsec.nsec3;

    while(n3 != NULL)
    {
        if(nsec3_zone_rdata_compare(n3->rdata, nsec3_rdata) == 0)
        {
            u8 digest[256];

#ifndef NDEBUG
            memset(digest, 0xd1, sizeof(digest));
#endif

            ya_result digest_len = base32hex_decode((char*)&nsec3_label[1], nsec3_label[0], &digest[1]);

            if(ISOK(digest_len))
            {
                digest[0] = digest_len;

                nsec3_zone_item* item = nsec3_avl_find(&n3->items, digest);

                return item;
            }

            break;
        }

        n3 = n3->next;
    }

    return NULL;
}
Esempio n. 6
0
ya_result
logger_channel_file_open(const char *fullpath, uid_t uid, gid_t gid, u16 mode, bool forceflush,logger_channel* chan)
{
    ya_result return_code;
    
    file_data* sd;
    MALLOC_OR_DIE(file_data*, sd, sizeof (file_data), 0x4d5254534e414843); /* CHANSTRM */

    if(ISOK(return_code = logger_channel_file_append(fullpath, uid, gid, mode, sd)))
    {
        sd->file_name = strdup(fullpath);
        sd->uid = uid;
        sd->gid = gid;
        sd->mode = mode;
        sd->force_flush = forceflush;

        chan->data = sd;
        chan->vtbl = &stream_vtbl;
    }
    else
    {
        free(sd);
    }

    return return_code;
}
Esempio n. 7
0
void
nsec3_remove_rrsig(zdb_zone* zone, zdb_packed_ttlrdata* nsec3param)
{
    nsec3_zone* n3 = zone->nsec.nsec3;

    while(n3 != NULL)
    {
        if(nsec3_zone_rdata_compare(n3->rdata, nsec3param->rdata_start) == 0)
        {
            u8 digest[256];

            ya_result digest_len = base32hex_decode((char*)&nsec3param->rdata_start[1], (u32)nsec3param->rdata_start[0], digest);

            if(ISOK(digest_len))
            {
                digest[0] = digest_len;

                nsec3_zone_item* item = nsec3_avl_find(&n3->items, digest);

                if(item != NULL)
                {
                    nsec3_zone_item_rrsig_delete_all(item);
                }
            }

            break;
        }

        n3 = n3->next;
    }
}
Esempio n. 8
0
static void*
xfr_query_axfr_load_thread(void *data)
{
    axfr_query_axfr_load_param *aqalp = (axfr_query_axfr_load_param*) data;
    ya_result return_value;

    /*
     * Now that the access has been cut, this could be done in background, with the loading
     */


    /*
     * Load the zone again
     * (other thread, with no zone visible until the very end)
     */

    zdb_zone *newzone = NULL;

    log_info("slave: zone %{dnsname} transferred", aqalp->origin);
    
    /**
     * Behaviour change : loading an zone file (axfr file) into memory will now drop (invalidate) the zone before
     * loading it.  Else loading a zone like .com would lead to potentially twice the amount of memory made readily
     * available to yadifa when most of it will remain untouched.
     * 
     * so:
     * 
     * invalidate the zone
     * drop the zone
     * load the zone
     */

    if(ISOK(return_value = zdb_zone_load((zdb*)aqalp->db, &aqalp->zr, &newzone, g_config->xfr_path, aqalp->origin, ZDB_ZONE_DESTROY_JOURNAL|ZDB_ZONE_IS_SLAVE)))
    {
        zassert(newzone != NULL);
        
        log_info("slave: zone %{dnsname} loaded", aqalp->origin);
        
        aqalp->new_zone = newzone;       
    }
    else
    {
        log_err("slave: zone %{dnsname} failed to load: %r", aqalp->origin, return_value);
        
        if(return_value == DNSSEC_ERROR_NSEC3_INVALIDZONESTATE)
        {
            /** @todo don't try for a while */
        }
    }

    zone_reader_close(&aqalp->zr);

    /*
     * At this point, since we are a slave, we need to start the alarm again.
     */

    scheduler_schedule_task(xfr_query_final_callback, aqalp);

    return NULL;
}
Esempio n. 9
0
static void
xfr_query_mark_zone_loaded(zdb* db, const u8 *origin, u32 refreshed_time, u32 retried_time)
{
    zone_data *zone = zone_getbydnsname(origin);
    
    bool refresh = TRUE;
    
    if(zone != NULL)
    {
        zone_setloading(zone, FALSE);
        
        if(refreshed_time != 0)
        {
            zone->refresh.refreshed_time = refreshed_time;
        }
        if(retried_time != 0)
        {
            zone->refresh.retried_time = retried_time;
        }
        
        zdb_zone *dbzone = zdb_zone_find_from_dnsname(db, origin, CLASS_IN);
        
        if(dbzone != NULL)
        {
            soa_rdata soa;
            
            zdb_zone_lock(dbzone, ZDB_ZONE_MUTEX_XFR);
                    
            if(ISOK(zdb_zone_getsoa(dbzone, &soa)))
            {
                u32 now = time(NULL);
                if(zone->refresh.refreshed_time >= now + soa.expire)
                {
                    log_info("slave: zone %{dnsname} has expired", origin);
                    
                    dbzone->apex->flags |= ZDB_RR_LABEL_INVALID_ZONE;
                    
                    refresh = FALSE;
                }
            }
            
            zdb_zone_unlock(dbzone, ZDB_ZONE_MUTEX_XFR);
        }
        
        log_info("slave: zone %{dnsname} load operation done", origin);
    }
    else
    {
        log_err("slave: expected to find zone '%{dnsname}' in the database", origin);
    }
    
    if(refresh)
    {
        database_zone_refresh_maintenance(g_config->database, origin);
    }
}
Esempio n. 10
0
static ya_result
counter_write(output_stream* stream, const u8* counter_, u32 len)
{
    counter_output_stream_data* data = (counter_output_stream_data*)stream->data;

    data->write_count += len;

    if(ISOK(data->result))
    {
        data->result = output_stream_write(data->filtered, counter_, len);

        if(ISOK(data->result))
        {
            data->writed_count += data->result;
        }
    }

    return data->result;
}
Esempio n. 11
0
static ya_result
counter_flush(output_stream* stream)
{
    counter_output_stream_data* data = (counter_output_stream_data*)stream->data;

    if(ISOK(data->result))
    {
        data->result = output_stream_flush(data->filtered);
    }

    return data->result;
}
Esempio n. 12
0
static asynStatus setDefaultEos(Port* plov)
{
    asynStatus sts;
    char inpEos = '\006';
    char outEos = '\003';
    Serport* pser = plov->pserport;

    sts = pser->pasynOctet->setInputEos(pser->pasynOctetPvt,pser->pasynUser,&inpEos,1);
    if( ISOK(sts) )
        printf("drvLove::setDefaultEos Input EOS set to \\0%d\n",inpEos);
    else
        printf("drvLove::setDefaultEos Input EOS set failed to \\0%d\n",inpEos);

    sts = pser->pasynOctet->setOutputEos(pser->pasynOctetPvt,pser->pasynUser,&outEos,1);
    if( ISOK(sts) )
        printf("drvLove::setDefaultEos Output EOS set to \\0%d\n",outEos);
    else
        printf("drvLove::setDefaultEos Output EOS set failed to \\0%d\n",outEos);

    return( sts );
}
Esempio n. 13
0
ya_result
tcp_io_stream_connect_ex(const char *server, u16 port, io_stream *ios, struct sockaddr *bind_from)
{
    input_stream istream;
    output_stream ostream;
    ya_result return_code;

    if(ISOK(return_code = tcp_input_output_stream_connect_ex(server, port, &istream, &ostream, bind_from, 0)))
    {
        io_stream_link(ios, &istream, &ostream);
    }

    return return_code;
}
Esempio n. 14
0
ya_result
tcp_input_output_stream_connect_host_address(const host_address *ha, input_stream *istream_, output_stream *ostream_, u8 to_sec)
{
    socketaddress sa;
    
    ya_result return_code;
    
    if(ISOK(return_code = host_address2sockaddr(&sa, ha)))
    {
        return_code = tcp_input_output_stream_connect_sockaddr(&sa.sa, istream_, ostream_, NULL, to_sec);
    }

    return return_code;
}
Esempio n. 15
0
void
nsec3_add_nsec3_by_name(zdb_zone* zone, const u8 *nsec3_label, const u8* nsec3_rdata, u16 nsec3_rdata_size)
{
    nsec3_zone* n3 = zone->nsec.nsec3;

    while(n3 != NULL)
    {
        if(nsec3_zone_rdata_compare(n3->rdata, nsec3_rdata) == 0)
        {
            u8 digest[256];

#ifndef NDEBUG
            memset(digest, 0xd1, sizeof(digest));
#endif

            ya_result digest_len = base32hex_decode((char*)&nsec3_label[1], nsec3_label[0], &digest[1]);

            if(ISOK(digest_len))
            {
                digest[0] = digest_len;

                nsec3_zone_item* item = nsec3_avl_find(&n3->items, digest);

                if(item == NULL)
                {
                    nsec3_zone_item *self = nsec3_avl_insert(&n3->items, (u8*)digest);
                    
                    self->flags = nsec3_rdata[1];
                    /*
                    self->rc = 0;
                    self->sc = 0;

                    self->type_bit_maps = NULL;
                    self->type_bit_maps_size = 0;
                    */
                    nsec3_zone_item_update_bitmap(self, nsec3_rdata, nsec3_rdata_size);
                }
                else
                {
                    /* exists already */
                    assert(FALSE);
                }
            }

            break;
        }

        n3 = n3->next;
    }
}
Esempio n. 16
0
static int
tcl_cpucount(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
{
    ya_result count = sys_get_cpu_count();

    if(ISOK(count))
    {
	fprintf(stdout, "Detected cpu count : %i\n", count);
    }
    else
    {
	fprintf(stdout, "Assumed cpu count : %i\n", DEFAULT_ASSUMED_CPU_COUNT);
    }

    fflush(stdout);

    return TCL_OK;
}
Esempio n. 17
0
ya_result
tcp_input_output_stream_connect_ex(const char *server, u16 port, input_stream *istream_, output_stream *ostream_, struct sockaddr *bind_from, u8 to_sec)
{
    ya_result return_code;
    socketaddress sa;

    /*
     * If the client interface is specified, then use its family.
     * Else use the unspecified familly to let the algorithm choose the first available one.
     */

    int family = (bind_from != NULL) ? bind_from->sa_family : AF_UNSPEC;

    if(ISOK(return_code = gethostaddr(server, port, &sa.sa, family)))
    {
        return_code = tcp_input_output_stream_connect_sockaddr(&sa.sa, istream_, ostream_, bind_from, to_sec);
    }

    return return_code;
}
Esempio n. 18
0
static asynStatus sendCommand(void* ppvt,asynUser* pasynUser,int retry)
{
    unsigned char cs;
    asynStatus sts;
    int addr;
    size_t len,bytesXfer;
    Port* plov = (Port*)ppvt;
    Serport* pser = plov->pserport;

    asynPrint(pasynUser,ASYN_TRACE_FLOW,"drvLove::sendCommand - retries(%d)\n",retry);

    if( retry == 0 )
    {
        sts = pasynManager->getAddr(pasynUser,&addr);
        if( ISNOTOK(sts) )
            return( sts );

        sprintf(plov->tmpMsg,"%02X%s",addr,plov->outMsg);
        calcChecksum(strlen(plov->tmpMsg),plov->tmpMsg,&cs);
        sprintf(plov->outMsg,"\002L%s%2X",plov->tmpMsg,cs);
    }

    len = strlen(plov->outMsg);
    sts = pser->pasynOctet->write(pser->pasynOctetPvt,pser->pasynUser,plov->outMsg,len,&bytesXfer);
    if( ISOK(sts) )
        asynPrint(pasynUser,ASYN_TRACEIO_FILTER,"drvLove::sendCommand - retries(%d),data \"%s\" \"%s\"\n",retry,plov->outMsg);
    else
    {
        if( sts == asynTimeout )
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::sendCommand - retries(%d) asynTimeout\n",retry);
        else if( sts == asynOverflow )
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::sendCommand - retries(%d) asynOverflow\n",retry);
        else if( sts == asynError )
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::sendCommand - retries(%d) asynError\n",retry);
        else
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::sendCommand - retries(%d) failed - unknown Asyn error\n",retry);
    }

    return( sts );
}
Esempio n. 19
0
/// register the logging configuration
/// note that for this to work, logger_handle_create("handle-name",logger_handle_for_handle_name_ptr_ptr)
/// must be called before the config_read is done
ya_result
config_register_logger(const char *null_or_channels_name, const char *null_or_loggers_name, s32 priority)
{
    //null_or_channels_name = "channels";
    //null_or_loggers_name = "loggers";
    (void)null_or_channels_name;
    (void)null_or_loggers_name;

    if(priority < 0)
    {
        priority = 0;
    }
    
    ya_result return_code;
    
    if(ISOK(return_code = config_register(&config_section_handles_descriptor, priority + 0)))
    {
        return_code = config_register(&config_section_loggers_descriptor, priority + 1);
    }
    
    return return_code;
}
Esempio n. 20
0
static asynStatus readUInt32(void* ppvt,asynUser* pasynUser,epicsUInt32* value,epicsUInt32 mask)
{
    asynStatus sts;
    Port* pport = (Port*)ppvt;
    Inst* pinst = (Inst*)pasynUser->drvUser;

    asynPrint(pasynUser,ASYN_TRACE_FLOW,"drvLove::readUInt32\n");

    if( pinst->pcmd->read )
        sprintf(pport->outMsg,"%s",pinst->pcmd->read);
    else
    {
        epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"%s error %s",pport->name,pport->pasynUser->errorMessage);
        return( asynError );
    }

    lockPort(pport,pasynUser);
    sts = executeCommand(pport,pasynUser);
    unlockPort(pport,pasynUser);

    if( ISNOTOK(sts) )
    {
        epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"%s error %s",pport->name,pport->pasynUser->errorMessage);
        return( sts );
    }

    sts = pinst->read(pinst,(epicsInt32*)value);
    if( ISNOTOK(sts) )
    {
        epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"%s error %s",pport->name,pport->pasynUser->errorMessage);
        return( sts );
    }

    if( ISOK(sts) )
        asynPrint(pasynUser,ASYN_TRACEIO_FILTER,"drvLove::readUInt32 readback from %s is 0x%X,mask=0x%X\n",pport->name,*value,mask);

    return( asynSuccess );
}
Esempio n. 21
0
static ya_result
journal_ix_reopen(journal *jh)
{
    journal_ix *jix = (journal_ix*)jh;
    ya_result ret = SUCCESS;
    journal_ix_writelock(jix);
    if(jix->fd < 0)
    {
        if(ISOK(ret = open_ex(jix->journal_name, O_RDWR)))
        {
            jix->fd = ret;
        }
        else
        {
            ret = ERRNO_ERROR;
            if(ret == MAKE_ERRNO_ERROR(ENOENT))
            {
                ret = ZDB_ERROR_ICMTL_NOTFOUND;
            }
        }        
    }
    journal_ix_writeunlock(jix);
    return ret;
}
Esempio n. 22
0
static asynStatus recvReply(void* ppvt,asynUser* pasynUser,char* data,size_t maxchars)
{
    int eom;
    asynStatus sts;
    size_t bytesXfer;
    Port* plov = (Port*)ppvt;
    Serport* pser = plov->pserport;

    asynPrint(pasynUser,ASYN_TRACE_FLOW,"drvLove::recvReplay\n");

    sts = pser->pasynOctet->read(pser->pasynOctetPvt,pser->pasynUser,data,maxchars,&bytesXfer,&eom);
    if( ISOK(sts) )
    {
        if( eom != ASYN_EOM_EOS )
        {
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::recvReply eos failure\n");
            return( asynError );
        }

        sts = evalMessage(&bytesXfer,plov->inpMsg,pasynUser,data);
        asynPrint(pasynUser,ASYN_TRACEIO_FILTER,"drvLove::recvReply %d \"%s\"\n",bytesXfer,data);
    }
    else
    {
        if( sts == asynTimeout )
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::recvReply asynTimeout\n");
        else if( sts == asynOverflow )
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::recvReply asynOverflow\n");
        else if( sts == asynError )
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::recvReply asynError\n");
        else
            asynPrint(pasynUser,ASYN_TRACE_ERROR,"drvLove::recvReply failed - unknown Asyn error\n");
    }

    return( sts );
}
Esempio n. 23
0
ya_result
config_register_main(s32 priority)
{
    MALLOC_OR_DIE(config_data*, g_config, sizeof(config_data), YGCONFIG_TAG);
    ZEROMEMORY(g_config, sizeof(config_data));
    
    g_config->gid = getgid();
    g_config->uid = getuid();

    const char *section_name = "main";
    
    ya_result return_code = config_register_struct(section_name, config_main_desc, g_config, priority);
    
    if(ISOK(return_code))
    {    
        // hook a new finaliser before the standard one
        
        config_section_descriptor_s *section_desc = config_section_get_descriptor(section_name);
        config_section_descriptor_vtbl_s *vtbl = (config_section_descriptor_vtbl_s*)section_desc->vtbl;
        vtbl->postprocess = config_main_section_postprocess;
    }
    
    return return_code;
}
Esempio n. 24
0
static ya_result
config_section_zone_stop(struct config_section_descriptor_s *csd)
{
#if CONFIG_SETTINGS_DEBUG
    formatln("config: section: zone: stop");
#endif
    
    // NOP
    zone_desc_s *zone_desc = (zone_desc_s*)csd->base;
    ya_result return_code;
    
    // ensure the descriptor is valid
    
    if(ISOK(return_code = zone_complete_settings(zone_desc)))
    {
        zone_setdefaults(zone_desc);
        
        if(logger_is_running())
        {
            log_debug("config: %{dnsname}: zone section parsed", zone_desc->origin);
        }
        
        // load the descriptor (most likely offline)

        if(config_section_zone_filter(zone_desc, config_section_zone_filter_params) == 1)
        {
            if(logger_is_running())
            {
                log_debug("config: %{dnsname}: sending zone to service", zone_desc->origin);
            }
            database_zone_desc_load(zone_desc);
        }
        else
        {
            
            zone_desc_s *current_zone_desc = zone_acquirebydnsname(zone_desc->origin);
            if(current_zone_desc != NULL)
            {
                if(logger_is_running())
                {
                    log_debug("config: %{dnsname}: clearing original zone drop status", zone_desc->origin);
                }
                zone_lock(current_zone_desc, ZONE_LOCK_REPLACE_DESC);
                zone_clear_status(current_zone_desc, ZONE_STATUS_DROP_AFTER_RELOAD);
                zone_unlock(current_zone_desc, ZONE_LOCK_REPLACE_DESC);
                
                zone_release(current_zone_desc);
            }
            
            zone_release(zone_desc);
        }
    }
    else
    {
        zone_release(zone_desc);
    }
        
    csd->base = NULL;
    
    return return_code;
}
Esempio n. 25
0
static ya_result
buffer_input_stream_read(input_stream* stream, u8* buffer, u32 len)
{
    buffer_input_stream_data* data = (buffer_input_stream_data*)stream->data;
    u8* src = data->buffer;

    ya_result ret;

    u32 remaining = data->buffer_size - data->buffer_offset;

    if(len <= remaining)
    {
        MEMCOPY(buffer, &src[data->buffer_offset], len);
        data->buffer_offset += len;

        /* There are still some bytes available */

        return len;
    }

    /* len >= remaining : copy what remains in the buffer */

    MEMCOPY(buffer, &src[data->buffer_offset], remaining);
    len -= remaining;
    buffer += remaining;

    /* NOTE: at this point the internal buffer is empty */

    if(len >= data->buffer_maxsize)
    {
        /* It would be pointless to buffer a read bigger than the buffer */

        data->buffer_offset = data->buffer_size; /* mark the buffer as "empty" */

        if(ISOK(ret = input_stream_read(&data->filtered, buffer, len)))
        {
            return remaining + ret; /* the chunk we've read from the buffer +
				   the chunk we've read from the stream */
        }
        else // 'remaining' bytes may have been copied already, if so, return that before the error
        {
            return (remaining > 0)?remaining:ret;
        }
    }

#ifdef DEBUG
    memset(data->buffer, 0xee, data->buffer_maxsize);
#endif

    // What remains to read is smaller than the buffer max size:
    // read a full buffer

    if((ret = input_stream_read(&data->filtered, data->buffer, data->buffer_maxsize)) <= 0)
    {
        data->buffer_size = 0;
        data->buffer_offset = 0;
        
        // 'remaining' bytes may have been copied already, if so, return that before the error

        return (remaining > 0) ? remaining : ERROR /* eof */;
    }
    
    if(len > ret)
    {
        len = ret;
    }

    MEMCOPY(buffer, data->buffer, len); /* starts at offset 0 */

    data->buffer_size = ret;
    data->buffer_offset = len;

    return remaining + len;
}
Esempio n. 26
0
void
nsec3_remove_nsec3_by_name(zdb_zone* zone, const u8 *nsec3_label, const u8* nsec3_rdata)
{
    nsec3_zone* n3 = zone->nsec.nsec3;

    while(n3 != NULL)
    {
        if(nsec3_zone_rdata_compare(n3->rdata, nsec3_rdata) == 0)
        {
            u8 digest[256];

#ifndef NDEBUG
            memset(digest, 0xd1, sizeof(digest));
#endif

            ya_result digest_len = base32hex_decode((char*)&nsec3_label[1], nsec3_label[0], &digest[1]);
            
            if(ISOK(digest_len))
            {
                digest[0] = digest_len;

                nsec3_zone_item* item = nsec3_avl_find(&n3->items, digest);

                if(item != NULL)
                {
                    int depth;

                    log_debug("nsec3_remove_nsec3_by_name: destroying %{digest32h}", item->digest);

					/*
					GOT IT : AN NSEC3 RECORD IS REMOVED BY IXFR BUT THE LABEL HAS NOT BEEN CHANGED
					I PRESUME IT IS BECAUSE THE AXFR CHAIN IS CHANGED
					I NEED A REPLACE FUNCTION, I NEED TO SORT THE IXFR NSEC(3) OPERATIONS
					*/

                    if(item->sc > 0)
                    {
                        nsec3_zone_item* prev = nsec3_avl_node_mod_prev(item);
                        if(prev != NULL)
                        {
                            nsec3_move_all_star(item, prev);
                        }
                        else
                        {
                            nsec3_remove_all_star(item);
                        }
                    }
                    nsec3_remove_all_owners(item);

                    zassert(item->rc == 0 && item->sc == 0);

                    ZFREE_ARRAY(item->type_bit_maps, item->type_bit_maps_size);

                    item->type_bit_maps = NULL;
                    item->type_bit_maps_size = 0;

                    nsec3_zone_item_rrsig_delete_all(item);

                    nsec3_avl_delete(&n3->items, item->digest);

                }
            }

            break;
        }

        n3 = n3->next;
    }
}
Esempio n. 27
0
static ya_result
journal_ix_get_ixfr_stream_at_serial(journal *jh, u32 serial_from, input_stream *out_input_stream, dns_resource_record *last_soa_rr)
{
    journal_ix *jix = (journal_ix*)jh;
    ya_result return_value = SUCCESS;
    
    journal_ix_readlock(jix);
    
    /*
     * check that serial_from in in the journal range
     * set the file descriptor to the position
     * create a stream that'll stop at the current end of the stream
     */
    
    if(serial_lt(serial_from, jix->first_serial) || serial_ge(serial_from, jix->last_serial) || ((jix->first_serial == 0) && (jix->last_serial == 0)))
    {
        /* out of known range */
        
        journal_ix_readunlock(jix);
        
        if(serial_from == jix->last_serial)
        {
            return SUCCESS;
        }
        else
        {        
            return ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
        }
    }
    
    /*
     * On success, dup() returns a new file descriptor that has the following in common with the original:
     * 
     *  _ Same open file (or pipe)
     *  _ Same file pointer (both file descriptors share one file pointer) <= THIS is a problem
     *  _ Same access mode (read, write, or read/write)
     * 
     * So this is wrong:
     * 
     * cloned_fd = dup(jix->fd);
     */    
    
    int cloned_fd;
    
    while((cloned_fd = open_ex(jix->journal_name, O_RDONLY)) < 0)
    {
        int err = errno;

        if(err == EINTR)
        {
            continue;
        }

        return_value = MAKE_ERRNO_ERROR(err);

#ifdef DEBUG
        log_debug("journal: ix: unable to clone the file descriptor: %r", return_value);
#endif
        journal_ix_readunlock(jix);

        return return_value;
    }
    
    /* 
     * given that I use a clone of the fd and
     * given that only appends are done in the file and
     * given that the limit of the file has already been processed (should be at this point)
     * 
     * THEN
     * 
     * there is no point keeping the lock for reading (on unix systems)
     */
    
    struct stat journal_stat;
    
    s64 last_page_offset = jix->last_page_offset;
    
    if(fstat(cloned_fd, &journal_stat) < 0)
    {
        return_value = ERRNO_ERROR;
        
        log_err("journal: ix: unable to get journal file status", return_value);
        
        close_ex(cloned_fd);

        return return_value;
    }
    
    s64 file_size = journal_stat.st_size;
    
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: the last page starts at position %lld", last_page_offset);
#endif

    journal_ix_readunlock(jix);
    jix = NULL;  
    
    input_stream fis;
    fd_input_stream_attach(&fis, cloned_fd);
    
    if(last_soa_rr != NULL)
    {
        /* seek and store the last SOA print*/
        
        last_soa_rr->tctr.qtype = 0; // clear type
        
        if(lseek(cloned_fd, last_page_offset, SEEK_SET) >= 0)
        {
            /* deleted SOA */
            if((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
            {
                if(last_soa_rr->tctr.qtype == TYPE_SOA)
                {
                    /* DEL records */
                    last_soa_rr->tctr.qtype = 0; // clear type
            
                    /* scan until added SOA found */
                    while((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
                    {
                        if(last_soa_rr->tctr.qtype == TYPE_SOA)
                        {
                            break;
                        }
                    }
                }
            }
            
            // if the SOA has not been found, it's an error (EOF has been reached is covered by this)
            
            
            if(ISOK(return_value))
            {
                if(last_soa_rr->tctr.qtype != TYPE_SOA)
                {
                    return_value = ZDB_JOURNAL_SOA_RECORD_EXPECTED;
                }
            }
        }
        else
        {
            return_value = ERRNO_ERROR;
        }
        
        if(FAIL(return_value))
        {
            input_stream_close(&fis);
            
            return return_value;
        }
    }
    
    /*
     * this format has no indexing so we scan for a page that STARTS with a DELETE of the SOA with serial = serial_from
     */
    
    if(lseek(cloned_fd, 0, SEEK_SET) != 0)  /* the resulting offset MUST be zero */
    {
        return_value = ERRNO_ERROR;
        
        if(ISOK(return_value))
        {
            return_value = ERROR;
        }
        
        input_stream_close(&fis);
            
        return return_value;
    }
    
    input_stream bis;
    dns_resource_record rr;
    dns_resource_record_init(&rr);
    buffer_input_stream_init(&fis, &bis, 512);
    
    s64 offset = 0;

    /* skip until the right serial is found */

    u32 soa_count = 0;

#ifdef DEBUG_JOURNAL
    u32 rr_count = 0;
#endif
    
    for(;;)
    {
        if( (return_value = dns_resource_record_read(&rr, &bis)) <= 0 ) // FAIL or nothing to 
        {
            return_value = ZDB_JOURNAL_ERROR_READING_JOURNAL; /* is the journal file broken ? */
            
            break;
        }

#ifdef DEBUG_JOURNAL
        rr_count++;
#endif
        
        u32 record_size = return_value;
        
        if(rr.tctr.qtype == TYPE_SOA)
        {
            // ((0+1)&1) != 0 => Y N Y N 
            
            if((++soa_count & 1) != 0) // 1 2 3 4
            {
                u8 *p = rr.rdata;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                u32 serial = ntohl(GET_U32_AT(*p));

                if(serial_ge(serial, serial_from))
                {
                    if(serial == serial_from)
                    {
                        /* setup the serial to be from 'offset' up to the current length of the stream */

                        return_value = SUCCESS;
                    }
                    else
                    {
                        /* the serial does not exist in the range */

                        return_value = ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
                    }

                    break;
                }
            }
        }
        
        offset += record_size;
    }
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: serial %08x (%d) is at offset %lld. %d records parsed", serial_from, serial_from, offset, rr_count);
#endif
    
    dns_resource_record_clear(&rr);
    
    /* 
     * detach the file descriptor from the file stream in the buffer stream
     * I do it like this because the streams are not needed anymore but the
     * file descriptor still is (if no error occurred)
     */
    
    fd_input_stream_detach(buffer_input_stream_get_filtered(&bis));
    input_stream_close(&bis);

    if(ISOK(return_value))
    {
        // offset is the start of the page we are looking for
        if(lseek(cloned_fd, offset, SEEK_SET) >= 0)
        {
            fd_input_stream_attach(&fis, cloned_fd);
            limited_input_stream_init(&fis, out_input_stream, file_size - offset);
        }
        else
        {
            return_value = ERRNO_ERROR;
            
            close_ex(cloned_fd);
        }
    }
    else
    {
        close_ex(cloned_fd);
    }
        
    return return_value;
}
Esempio n. 28
0
static ya_result
journal_ix_append_ixfr_stream(journal *jh, input_stream *ixfr_wire_is)
{
    journal_ix *jix = (journal_ix*)jh;
    
    journal_ix_writelock(jix);
    
    /*
     * Move at the end of the file
     * Check that the wire starts with the last soa/serial
     * Append the wire
     * update the last serial
     */
    
    // read the record
    
    ya_result return_value;    
    dns_resource_record rr;
    
    dns_resource_record_init(&rr);
    
    if((return_value = dns_resource_record_read(&rr, ixfr_wire_is)) <= 0)
    {
        /* FAIL or EOF */
        
        dns_resource_record_clear(&rr);
        journal_ix_writeunlock(jix);
        
        log_err("journal: ix: unable to read record: %r", return_value);
        
        return return_value;
    }
    
    /*
     * The first record is an SOA and our starting point (to be deleted)
     */
    
#ifdef DEBUG
    rdata_desc rdatadesc = {rr.tctr.qtype, rr.rdata_size, rr.rdata};
    log_debug("journal: ix: DEL %{dnsname} %{typerdatadesc}", rr.name, &rdatadesc);
#endif
        
    if(rr.tctr.qtype != TYPE_SOA)
    {
        u16 rtype = rr.tctr.qtype;
        dns_resource_record_clear(&rr);
        journal_ix_writeunlock(jix);
        
        log_err("journal: ix: expected SOA record but got %{dnstype} instead", &rtype);
        
        return ZDB_JOURNAL_SOA_RECORD_EXPECTED;
    }
    
    /*
     * check the journal file exists/is defined
     * do it now if not
     * proceed
     */
    
    if(((jix->first_serial == 0) && (jix->last_serial == 0)) || (jix->fd == -1))
    {
        /* the file does not exists yet */
        
        if(FAIL(return_value = rr_soa_get_serial(rr.rdata, rr.rdata_size, &jix->first_serial)))
        {
            dns_resource_record_clear(&rr);
            journal_ix_writeunlock(jix);
            
            log_err("journal: ix: unable to read record: %r", return_value);

            return return_value;
        }
        
        int fd = open_create_ex(jix->journal_name, O_RDWR|O_CREAT, 0644);

        if(fd < 0)
        {
            return_value = ERRNO_ERROR;
            dns_resource_record_clear(&rr);
            journal_ix_writeunlock(jix);
            
            log_err("journal: ix: unable to open journal file '%s': %r", jix->journal_name, return_value);
            
            return return_value;
        }
        
        log_info("journal: ix: journal file created '%s'", jix->journal_name);
        
        jix->fd = fd;
    }
    
    if(FAIL(return_value = journal_ix_ensure_opened(jix)))
    {
        return return_value;
    }
    
    u64 valid_offset = lseek(jix->fd, 0, SEEK_END);
    u64 current_offset = valid_offset;
    
    u32 valid_serial = jix->last_serial;
    u32 potential_serial = valid_serial;
    
    s64 valid_page_offset = jix->last_page_offset;
    s64 potential_page_offset = current_offset;
    
#ifdef DEBUG
    log_debug("journal: ix: ready to append to journal after serial %08x (%d) at offset %lld", valid_serial, valid_serial, valid_offset);
#endif
    
    u8 mode = 0; /* 0: del, 1: add */
    
    output_stream fos;
    output_stream bos;
    fd_output_stream_attach(&fos, jix->fd);
    buffer_output_stream_init(&bos, &fos, 512);
    
    for(;;)
    {
        /* write the first */

        if(FAIL(return_value = dns_resource_record_write(&rr, &bos)))
        {
            /* this is VERY bad */
            
            log_err("journal: ix: error writing a record to the journal: %r", return_value);

            break;
        }
        
        /* update the current offset */
        
        current_offset += return_value;        
        
        if((return_value = dns_resource_record_read(&rr, ixfr_wire_is)) <= 0) /* no bytes read OR error, there is no macro for this */
        {
            /* error or end of stream */
            
            if(return_value == 0)           /* end of stream */
            {
                if(mode != 0)               /* on add mode so everything should be fine */
                {
                    valid_offset = current_offset;
                    valid_serial = potential_serial;
                    valid_page_offset = potential_page_offset;
                }
                else                        /* but on delete mode instead of add mode */
                {
                    log_err("journal: ix: ixfr stream unexpected eof");

                    return_value = UNEXPECTED_EOF;  /* we have an error */
                }
            }

            break;
        }
        
        if(rr.tctr.qtype == TYPE_SOA)
        {
            mode ^= 1;
            
#ifdef DEBUG
            rdata_desc rdatadesc = {rr.tctr.qtype, rr.rdata_size, rr.rdata};
            log_debug("journal: ix: %s %{dnsname} %{typerdatadesc}", (mode!=0)?"add":"del", rr.name, &rdatadesc);
#endif
            
            if(mode == 0)
            {
                /* 
                 * new SOA to delete
                 * 
                 * it's a new "page" (delete -> add)
                 * 
                 * the offset before we write this record is the highest valid one in the file
                 * so the error correcting truncation will be made at that offset
                 */
                
                valid_offset = current_offset;
                
                /*
                 * the serial number that has been added with the previous page
                 */
                
                valid_serial = potential_serial;
                
                /*
                 * the offset of the previous page
                 */
                
                valid_page_offset = potential_page_offset;
                
                /*
                 * the new page starts here : update
                 */
                
                potential_page_offset = current_offset;
            }
            else
            {
                /*
                 * new SOA add
                 * 
                 * this is the second half of the page, we know what serial it is about
                 */
                
                if(FAIL(return_value = rr_soa_get_serial(rr.rdata, rr.rdata_size, &potential_serial)))
                {
                    break;
                }
            }
        }
#ifdef DEBUG
        else
        {
            rdata_desc rdatadesc = {rr.tctr.qtype, rr.rdata_size, rr.rdata};
            log_debug("journal: ix: %s %{dnsname} %{typerdatadesc}", (mode!=0)?"add":"del", rr.name, &rdatadesc);
        }
#endif
    }

    if(FAIL(return_value))
    {
        /*
         * The journal is only valid up to valid_offset with serial ...
         */
        
        log_err("journal: ix: rewinding journal up to last valid point (%lld)", valid_offset);
        
        ftruncate(jix->fd, valid_offset);
    }
    
#ifdef DEBUG
    log_debug("journal: ix: page offset got from %d to %d", jix->last_page_offset, valid_page_offset);
    log_debug("journal: ix: serial got from %d to %d", jix->last_serial, valid_serial);
#endif
    
    jix->last_page_offset = valid_page_offset;    
    jix->last_serial = valid_serial;
    
    /*
     * rename the file
     */
    
    if(ISOK(return_value))
    {
        char new_name[PATH_MAX];
        memcpy(new_name, jix->journal_name, jix->journal_name_len);
        snformat(&new_name[jix->journal_name_len - FIRST_FROM_END], 8 + 1 + 8 + 1 + IX_EXT_STRLEN + 1,
                "%08x-%08x." IX_EXT , jix->first_serial, jix->last_serial);
        if(rename(jix->journal_name, new_name) >= 0)
        {
            memcpy(jix->journal_name, new_name, jix->journal_name_len);
        }
    }
    
    /*
     */

#ifdef DEBUG
    log_debug("journal: ix: fd=%i from=%08x to=%08x soa@%lld file=%s",
            jix->fd, jix->first_serial, jix->last_serial, jix->last_page_offset, (jix->journal_name!=NULL)?jix->journal_name:"NONE-YET");
#endif
    
    output_stream_flush(&bos);
    fd_output_stream_detach(buffer_output_stream_get_filtered(&bos));
    output_stream_close(&bos);
    
    dns_resource_record_clear(&rr);
    
    journal_ix_writeunlock(jix);
    
    if(ISOK(return_value))
    {
#ifdef DEBUG
        log_debug("journal: ix: page added (fd=%i from=%08x to=%08x soa@%lld file=%s): %r",
                jix->fd, jix->first_serial, jix->last_serial, jix->last_page_offset, (jix->journal_name!=NULL)?jix->journal_name:"NONE-YET",
                return_value);
#endif
        return TYPE_IXFR;       /* that's what the caller expects to handle the new journal pages */
    }
    else
    {    
        log_err("journal: ix: failed to add page");
        return return_value;
    }
}
Esempio n. 29
0
static ya_result
config_main_verify_and_update_file(const char *base_path, char **dirp)
{
    if(dirp == NULL)
    {
        return UNEXPECTED_NULL_ARGUMENT_ERROR;
    }
    
    char *p = *dirp;
    
    if(p == NULL)
    {
        return UNEXPECTED_NULL_ARGUMENT_ERROR;
    }
    
    char *e = p + strlen(p) - 1;
    while((*e != '/') && (e > p))
    {
        e--;
    }
    
    if((*e == '/') || (e == p))
    {
        char filename[PATH_MAX];
        
        if(*e == '/')
        {
            *e = '\0';
            e++;
            strncpy(filename, e, sizeof(filename));
            *e = '\0';
        }
        else
        {
            strncpy(filename, e, sizeof(filename));
            *e = '\0';
        }
        
        ya_result ret;
        
        if(ISOK(ret = config_main_verify_and_update_directory(base_path, dirp)))
        {        
            chroot_unmanage_path(dirp);
            int pathlen = strlen(*dirp);
            memmove(&filename[pathlen + 1], filename, strlen(filename) + 1);
            memcpy(filename, *dirp, pathlen);
            filename[pathlen] = '/';
            free(*dirp);
            *dirp = strdup(filename);
            chroot_manage_path(dirp, filename, FALSE);
            
            return SUCCESS;
        }
        else
        {
            return ret;
        }
    }
    
    return SUCCESS;
}
Esempio n. 30
0
static ya_result
xfr_query_callback(void* data)
{
    xfr_query_schedule_param *xqsp = (xfr_query_schedule_param*)data;
    ya_result return_value;
	ya_result scheduler_status;
    u32 refreshed_time = 0;
    u32 retried_time = time(NULL);
    
    /*
     * Zone refresh will be enabled (again) here.
     * 
     * xfr_query_mark_zone_loaded
     * 
     */

    
    if(ISOK(xqsp->return_value))
    {
        /* success but type == 0 => transfer done */
        
        if(xqsp->type != 0)
        {
            log_info("slave: %{dnstype}: proceeding with transfer of %{dnsname}", &xqsp->type, xqsp->origin);
        }
    }
    else
    {
        log_err("slave: %{dnstype}: transfer of %{dnsname} failed: %r", &xqsp->type, xqsp->origin, xqsp->return_value);
        
        /*
         * Here (?) put the invalid zone placeholder if it is not there yet
         */
    }

    switch(xqsp->type)
    {
        case TYPE_AXFR:
        {
            /*
             * Load the axfr
             */
            
            if(ISOK(xqsp->return_value))
            {
                axfr_query_axfr_load_param *aqalp;
                MALLOC_OR_DIE(axfr_query_axfr_load_param*, aqalp, sizeof(axfr_query_axfr_load_param), GENERIC_TAG);
                
                log_info("slave: opening AXFR for %{dnsname} %d", xqsp->origin, xqsp->loaded_serial);

                if(ISOK(return_value = zone_axfr_reader_open_with_serial(g_config->xfr_path, xqsp->origin, xqsp->loaded_serial, &aqalp->zr)))
                {
                    /*
                     * The system is ready to load an AXFR
                     * A zone is already in place (by design), there may be an old zone that is now irrelevant.
                     * At this point ...
                     * 
                     * If the serial are not the same
                     *      MT the old zone must be destroyed (if it exist)
                     *       then
                     *      MT The new zone has to be created (loaded from the AXFR file)
                     * Else
                     *      ST The new zone is actually the old zone, and the old zone is non-existent
                     * EndIf
                     * 
                     * then
                     * 
                     * ST The new zone and the placeholder zone have to be swapped, then the placeholder has to be destroyed
                     * 
                     */
                    
                    zdb_zone *zone = zdb_zone_find_from_dnsname((zdb*)xqsp->db, xqsp->origin, CLASS_IN);

                    if(zone != NULL)
                    {
                        zdb_zone_truncate_invalidate(zone);
                    }                    

                    /**
                     * schedule the axfr load
                     */

                    aqalp->old_zone = NULL; /* old zone */
                    aqalp->new_zone = NULL;
                    aqalp->db = xqsp->db;
                    aqalp->origin = dnsname_dup(xqsp->origin);

                    scheduler_status = SCHEDULER_TASK_PROGRESS;

                    thread_pool_schedule_job(xfr_query_axfr_load_thread, aqalp, NULL, "axfr load");
                    
                    break;
                }
            }
            
            /**
             * @todo If the "old_zone" exists, then ... (destroy ? swap back ? expired ?)
             * 
             */
            
            /*
             * An issue occurred (AXFR transfer, load)
             */
			
            log_err("slave: unable to load the axfr (retry set in %d seconds)", g_config->axfr_retry_delay);

            alarm_event_node *event = alarm_event_alloc();

            event->epoch = time(NULL) + g_config->axfr_retry_delay;

            if(g_config->axfr_retry_jitter > 0)
            {
                random_ctx rndctx = thread_pool_get_random_ctx();
                u32 jitter = random_next(rndctx) % g_config->axfr_retry_jitter;
                event->epoch += jitter;
            }

            event->function = scheduler_axfr_query_alarm;
            event->args = xqsp;
            event->key = ALARM_KEY_ZONE_AXFR_QUERY;
            event->flags = ALARM_DUP_NOP;
            event->text = "scheduler_axfr_query_alarm";

            zdb *db = (zdb*)xqsp->db;
            alarm_set(db->alarm_handle, event);

            /* DO NOT FREE xqsp, SO DO NOT BREAK : return now */
            
            return SCHEDULER_TASK_FINISHED;
        }
        
        case TYPE_IXFR:
        {
            /**
             * Load the ixfr (single thread, zone locked)
             */

			scheduler_status = SCHEDULER_TASK_FINISHED;

            if(ISOK(xqsp->return_value))
            {
                zdb_zone *dbzone = zdb_zone_find_from_dnsname((zdb*)xqsp->db, xqsp->origin, CLASS_IN);

                if(dbzone == NULL)
                {
                    log_err("slave: zone %{dnsname} journal has vanished", xqsp->origin);
                    break;
                }
                
                log_info("slave: opening journal for '%{dnsname}'", xqsp->origin);

                zdb_zone_lock(dbzone, ZDB_ZONE_MUTEX_XFR);
                
                if(ISOK(return_value = zdb_icmtl_replay(dbzone, g_config->xfr_path, xqsp->serial_start_offset, xqsp->loaded_serial, ZDB_ICMTL_REPLAY_SERIAL_OFFSET|ZDB_ICMTL_REPLAY_SERIAL_LIMIT)))
                {
                    log_info("slave: replayed %d records changes", return_value);
                    
                    dbzone->apex->flags &= ~ZDB_RR_LABEL_INVALID_ZONE;
                    
                    refreshed_time = time(NULL);
                }
                else
                {
                    log_err("slave: replay error: %r this is bad: invalidate the zone and ask for an AXFR", return_value);
                    
                    /** @todo INVALIDATE AND AXFR */
                }
                
                /** @todo invalitate if retried_time > expired_time */

                zdb_zone_unlock(dbzone, ZDB_ZONE_MUTEX_XFR);
            }
            
            log_info("slave: journal transfer done");

            xfr_query_mark_zone_loaded((zdb*)g_config->database, xqsp->origin, refreshed_time, retried_time);
            
			scheduler_status = SCHEDULER_TASK_FINISHED;
            break;            
        }
        default:
        {
            refreshed_time = time(NULL);
            
            log_info("slave: transfer done");

            xfr_query_mark_zone_loaded((zdb*)g_config->database, xqsp->origin, refreshed_time, retried_time);
            
			scheduler_status = SCHEDULER_TASK_FINISHED;
            break;
        }
    }   /* switch return_value */