[ldns-users] suggestion for a parse-rrs callback method

Jelte Jansen jelte.jansen at sidn.nl
Mon May 27 10:05:14 UTC 2013


I just posted a blog article about a possible extension i'd like to see
in ldns (in dutch):

http://www.sidnlabs.nl/laatste-berichten/nieuwsdetail/article/dns-resource-record-handling/

lemme quickly summarize it in english here:

I often find (like in the recent case of the 3597 translation), that
I simply need to read a bunch of resource records from either
dig/drill output or a zone file, and do something with them.

Since I'd like to focus on that 'something' and not on the zone
parsing itself  this usually only works with a pretty specific
'flattened' input format (generally the output of ldns-read-zone),
and not with the full flexibility a zone parser gives you.

So what would be very useful is a general construct to define a
function that is called for every RR in a given file stream, e.g. a
callback that gets an RR and probably a callback-specific void*
'state' object. Said construct would keep track of the state
involved in 'real' parsing so that I don't have to repeat the same
code over and over again.

Ideally, the calling program would then just have to define its
callback, open the file, and call the ldns parser code, and be done
with it, e.g. in the case of ldns I'd want something like:

// Callback to print the RR, no state.
int printer(ldns_rr* rr, void* state) {
	ldns_rr_print(stdout, rr);
	return 0;
}

in = fopen("my.zone", "r");
if (in != NULL) {
	ldns_parse_rr_stream(in, printer, NULL);
	fclose(in);
}

So no more keeping ldns_rr's around (unless you need them later), no
more tracking of origin, ttl, etc.

Some details need to be hashed out (e.g. is ownership of the rr
transfered, should there be an initial origin/default ttl, etc.)

But in general, I think this would be a reasonably simple but highly
useful addition.

This is an initial stab at an implementation, it's really not that much
right now (but I expect it to grow a little bit):

ldns_status
ldns_parse_rr_stream(FILE* in, int (*callback)(ldns_rr*, void*),
                     void* callback_state) {
    ldns_rdf* origin = NULL;
    uint32_t ttl = 3600;
    ldns_rdf* prev = NULL;

    ldns_rr* cur_rr = NULL;
    ldns_status status;
    while (!feof(in)) {
        status = ldns_rr_new_frm_fp(&cur_rr, in, &ttl, &origin, &prev);
        if (!callback(cur_rr, callback_state)) {
            return LDNS_STATUS_ERR;
        }
        ldns_rr_free(cur_rr);
        cur_rr = NULL;

        switch (status) {
        case LDNS_STATUS_OK:
        case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */
        case LDNS_STATUS_SYNTAX_TTL: /* the function set the ttl */
        case LDNS_STATUS_SYNTAX_ORIGIN: /* the function set the origin */
            break;
        default:
            if (prev != NULL) {
                ldns_rdf_deep_free(prev);
            }
            return status;
        }
    }
    if (prev != NULL) {
        ldns_rdf_deep_free(prev);
    }
    return LDNS_STATUS_OK;
}



More information about the ldns-users mailing list