/*! \file */
+#include <isc/lex.h>
+#include <isc/log.h>
+
+#include <dns/callbacks.h>
+#include <dns/fixedname.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
#include <dns/skr.h>
+#include <dns/time.h>
+#include <dns/ttl.h>
+
+#define CHECK(op) \
+ do { \
+ result = (op); \
+ if (result != ISC_R_SUCCESS) \
+ goto failure; \
+ } while (0)
+
+#define READLINE(lex, opt, token)
+
+#define NEXTTOKEN(lex, opt, token) \
+ { \
+ ret = isc_lex_gettoken(lex, opt, token); \
+ if (ret != ISC_R_SUCCESS) \
+ goto cleanup; \
+ }
-void
-dns_skrbundle_create(isc_mem_t *mctx, dns_name_t *name,
- dns_rdataclass_t rdclass, isc_stdtime_t inception,
- dns_skrbundle_t **bp) {
+#define BADTOKEN() \
+ { \
+ ret = ISC_R_UNEXPECTEDTOKEN; \
+ goto cleanup; \
+ }
+
+#define TOKENSIZ (8 * 1024)
+#define STR(t) ((t).value.as_textregion.base)
+
+static isc_result_t
+parse_rr(isc_lex_t *lex, isc_mem_t *mctx, char *owner, dns_name_t *origin,
+ dns_rdataclass_t rdclass, isc_buffer_t *buf, dns_ttl_t *ttl,
+ dns_rdatatype_t *rdtype, dns_rdata_t **rdata) {
+ dns_rdatacallbacks_t callbacks;
+ dns_fixedname_t dfname;
+ dns_name_t *dname = NULL;
+ dns_rdataclass_t clas;
+ isc_buffer_t b;
+ isc_token_t token;
+ unsigned int opt = ISC_LEXOPT_EOL;
+ isc_result_t ret = ISC_R_SUCCESS;
+
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+
+ /* Read the domain name */
+ if (!strcmp(owner, "@")) {
+ BADTOKEN();
+ }
+ dname = dns_fixedname_initname(&dfname);
+ isc_buffer_init(&b, owner, strlen(owner));
+ isc_buffer_add(&b, strlen(owner));
+ ret = dns_name_fromtext(dname, &b, dns_rootname, 0, NULL);
+ if (ret != ISC_R_SUCCESS) {
+ return (ret);
+ }
+ if (dns_name_compare(dname, origin) != 0) {
+ return (DNS_R_BADOWNERNAME);
+ }
+ isc_buffer_clear(&b);
+
+ /* Read the next word: either TTL, class, or type */
+ NEXTTOKEN(lex, opt, &token);
+ if (token.type != isc_tokentype_string) {
+ BADTOKEN();
+ }
+
+ /* If it's a TTL, read the next one */
+ ret = dns_ttl_fromtext(&token.value.as_textregion, ttl);
+ if (ret == ISC_R_SUCCESS) {
+ NEXTTOKEN(lex, opt, &token);
+ }
+ if (token.type != isc_tokentype_string) {
+ BADTOKEN();
+ }
+
+ /* If it's a class, read the next one */
+ ret = dns_rdataclass_fromtext(&clas, &token.value.as_textregion);
+ if (ret == ISC_R_SUCCESS) {
+ if (clas != rdclass) {
+ BADTOKEN();
+ }
+ NEXTTOKEN(lex, opt, &token);
+ }
+ if (token.type != isc_tokentype_string) {
+ BADTOKEN();
+ }
+
+ /* Must be the record type */
+ ret = dns_rdatatype_fromtext(rdtype, &token.value.as_textregion);
+ if (ret != ISC_R_SUCCESS) {
+ BADTOKEN();
+ }
+ switch (*rdtype) {
+ case dns_rdatatype_dnskey:
+ case dns_rdatatype_cdnskey:
+ case dns_rdatatype_cds:
+ case dns_rdatatype_rrsig:
+ /* Allowed record types */
+ break;
+ default:
+ BADTOKEN();
+ }
+
+ dns_rdatacallbacks_init(&callbacks);
+ ret = dns_rdata_fromtext(*rdata, rdclass, *rdtype, lex, dname, 0, mctx,
+ buf, &callbacks);
+cleanup:
+ isc_lex_setcomments(lex, 0);
+ return (ret);
+}
+
+static void
+skrbundle_create(isc_mem_t *mctx, isc_stdtime_t inception,
+ dns_skrbundle_t **bp) {
dns_skrbundle_t *b;
REQUIRE(bp != NULL && *bp == NULL);
- UNUSED(name);
- UNUSED(rdclass);
-
b = isc_mem_get(mctx, sizeof(*b));
b->magic = DNS_SKRBUNDLE_MAGIC;
b->inception = inception;
*bp = b;
}
-void
-dns_skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple) {
+static void
+skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple) {
REQUIRE(DNS_DIFFTUPLE_VALID(*tuple));
REQUIRE(DNS_SKRBUNDLE_VALID(bundle));
REQUIRE(DNS_DIFF_VALID(&bundle->diff));
*skrp = skr;
}
-void
-dns_skr_addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep) {
+static void
+addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep) {
REQUIRE(DNS_SKR_VALID(skr));
REQUIRE(DNS_SKRBUNDLE_VALID(*bundlep));
*bundlep = NULL;
}
+isc_result_t
+dns_skr_read(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
+ dns_rdataclass_t rdclass, dns_ttl_t dnskeyttl, dns_skr_t **skrp) {
+ isc_result_t result;
+ dns_skrbundle_t *bundle = NULL;
+ char bundlebuf[1024];
+ uint32_t bundle_id;
+ isc_lex_t *lex = NULL;
+ isc_lexspecials_t specials;
+ isc_token_t token;
+ unsigned int opt = ISC_LEXOPT_EOL;
+
+ REQUIRE(DNS_SKR_VALID(*skrp));
+
+ isc_lex_create(mctx, TOKENSIZ, &lex);
+ memset(specials, 0, sizeof(specials));
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+ result = isc_lex_openfile(lex, filename);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+ ISC_LOG_ERROR, "unable to open ksr file %s: %s",
+ filename, isc_result_totext(result));
+ isc_lex_destroy(&lex);
+ return (result);
+ }
+
+ for (result = isc_lex_gettoken(lex, opt, &token);
+ result == ISC_R_SUCCESS;
+ result = isc_lex_gettoken(lex, opt, &token))
+ {
+ if (token.type == isc_tokentype_eol) {
+ continue;
+ }
+
+ if (token.type != isc_tokentype_string) {
+ CHECK(DNS_R_SYNTAX);
+ }
+
+ if (strcmp(STR(token), ";;") == 0) {
+ /* New bundle */
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ if (token.type != isc_tokentype_string ||
+ strcmp(STR(token), "SignedKeyResponse") != 0)
+ {
+ CHECK(DNS_R_SYNTAX);
+ }
+
+ /* Version */
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ if (token.type != isc_tokentype_string ||
+ strcmp(STR(token), "1.0") != 0)
+ {
+ CHECK(DNS_R_SYNTAX);
+ }
+
+ /* Date and time of bundle */
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ if (token.type != isc_tokentype_string) {
+ CHECK(DNS_R_SYNTAX);
+ }
+ if (strcmp(STR(token), "generated") == 0) {
+ /* Final bundle */
+ goto readline;
+ }
+ if (token.type != isc_tokentype_string) {
+ CHECK(DNS_R_SYNTAX);
+ }
+
+ /* Add previous bundle */
+ if (bundle != NULL) {
+ addbundle(*skrp, &bundle);
+ }
+
+ /* Create new bundle */
+ sscanf(STR(token), "%s", bundlebuf);
+ CHECK(dns_time32_fromtext(bundlebuf, &bundle_id));
+ bundle = NULL;
+ skrbundle_create(mctx, (isc_stdtime_t)bundle_id,
+ &bundle);
+
+ readline:
+ /* Read remainder of header line */
+ do {
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ } while (token.type != isc_tokentype_eol);
+ } else {
+ isc_buffer_t buf;
+ dns_rdata_t *rdata = NULL;
+ u_char rdatabuf[DST_KEY_MAXSIZE];
+ dns_rdatatype_t rdtype;
+
+ /* Parse record */
+ rdata = isc_mem_get(mctx, sizeof(*rdata));
+ dns_rdata_init(rdata);
+ isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
+ result = parse_rr(lex, mctx, STR(token), origin,
+ rdclass, &buf, &dnskeyttl, &rdtype,
+ &rdata);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(
+ DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(1),
+ "read skr file %s(%lu) parse rr "
+ "failed: %s",
+ filename, isc_lex_getsourceline(lex),
+ isc_result_totext(result));
+ isc_mem_put(mctx, rdata, sizeof(*rdata));
+ goto failure;
+ }
+
+ /* Create new diff tuple */
+ dns_diffop_t op = (rdtype == dns_rdatatype_rrsig)
+ ? DNS_DIFFOP_ADDRESIGN
+ : DNS_DIFFOP_ADD;
+ dns_difftuple_t *tuple = NULL;
+
+ dns_difftuple_create((*skrp)->mctx, op, origin,
+ dnskeyttl, rdata, &tuple);
+
+ skrbundle_addtuple(bundle, &tuple);
+ INSIST(tuple == NULL);
+
+ isc_mem_put(mctx, rdata, sizeof(*rdata));
+ }
+ }
+
+ if (result != ISC_R_EOF) {
+ CHECK(DNS_R_SYNTAX);
+ }
+ result = ISC_R_SUCCESS;
+
+ /* Add final bundle */
+ if (bundle != NULL) {
+ addbundle(*skrp, &bundle);
+ }
+
+failure:
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+ ISC_LOG_DEBUG(1),
+ "read skr file %s(%lu) failed: %s", filename,
+ isc_lex_getsourceline(lex),
+ isc_result_totext(result));
+ }
+
+ /* Clean up */
+ isc_lex_destroy(&lex);
+ return (result);
+}
+
dns_skrbundle_t *
dns_skr_lookup(dns_skr_t *skr, isc_stdtime_t time, uint32_t sigval) {
dns_skrbundle_t *b, *next;