diff --git a/lib/layer/validate.c b/lib/layer/validate.c index 11ac4d220d7c61eac6fd0acb725030d063802794..56e07c5f16bf76cf702499becf90cbbfb3719095 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -14,8 +14,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <assert.h> #include <ctype.h> #include <sys/time.h> +#include <string.h> #include <libknot/descriptor.h> #include <libknot/rrtype/rdname.h> @@ -30,6 +32,267 @@ #define DEBUG_MSG(fmt...) QRDEBUG(qry, "vldr", fmt) +static int dname_parse(knot_dname_t **dname, const char *dname_str, mm_ctx_t *pool) +{ + if (!dname) { + return kr_error(EINVAL); + } + + knot_dname_t *owner = mm_alloc(pool, KNOT_DNAME_MAXLEN); + if (owner == NULL) { + return kr_error(ENOMEM); + } + knot_dname_t *aux = knot_dname_from_str(owner, dname_str, KNOT_DNAME_MAXLEN); + if (aux == NULL) { + mm_free(pool, owner); + return kr_error(ENOMEM); + } + + assert(!*dname); + *dname = owner; + return 0; +} + +static int uint_parse(const char *str, unsigned *u) +{ + char *err_pos; + long num = strtol(str, &err_pos, 10); + if ((*err_pos != '\0') || (num < 0)) { + return kr_error(EINVAL); + } + *u = (unsigned) num; + return 0; +} + +static int strcicmp(char const *a, char const *b) +{ + if (!a && !b) { + return 0; + } + if (!a) { + return -1; + } + if (!b) { + return 1; + } + for ( ; ; ++a, ++b) { + int d = tolower(*a) - tolower(*b); + if ((d != 0) || (*a == '\0')) { + return d; + } + } +} + +static int algorithm_parse(const char *str, unsigned *u) +{ + int ret = uint_parse(str, u); + if (ret == 0) { + return 0; + } + + const lookup_table_t *item = knot_dnssec_alg_names; + while (item->id) { + if (strcicmp(str, item->name) == 0) { + break; + } + ++item; + } + + if (!item->id) { + return kr_error(ENOENT); + } + + *u = (unsigned) item->id; + return 0; +} + +static int hex2value(const char hex) +{ + if ((hex >= '0') && (hex <= '9')) { + return hex - '0'; + } else if ((hex >= 'a') && (hex <= 'f')) { + return hex - 'a' + 10; + } else if ((hex >= 'A') && (hex <= 'F')) { + return hex - 'A' + 10; + } else { + return -1; + } +} + +static int hex2byte(const char hex[2], uint8_t *u) +{ + int d0, d1; + d0 = hex2value(hex[0]); + d1 = hex2value(hex[1]); + + if ((d0 == -1) || (d1 == -1)) { + return kr_error(EINVAL); + } + + *u = ((d0 & 0x0f) << 4) | (d1 & 0x0f); + return 0; +} + +int kr_ta_parse(knot_rrset_t **rr, const char *ds_str, mm_ctx_t *pool) +{ +#define SEPARATORS " \t\n\r" +#define RDATA_MAXSIZE 640 + int ret = 0; + unsigned aux; + + if (!rr || !ds_str || !pool) { + ret = kr_error(EINVAL); + goto fail; + } + + size_t ds_len = strlen(ds_str) + 1; + char *ds_cpy = mm_alloc(pool, ds_len); + if (!ds_cpy) { + ret = kr_error(ENOMEM); + goto fail; + } + memcpy(ds_cpy, ds_str, ds_len); + char *saveptr = NULL, *token; + + /* Owner name. */ + knot_dname_t *owner = NULL; + token = strtok_r(ds_cpy, SEPARATORS, &saveptr); + if (!token) { + ret = kr_error(EINVAL); + goto fail; + } + ret = dname_parse(&owner, token, pool); + if (ret != 0) { + goto fail; + } + + /* Class. */ + uint16_t class; + token = strtok_r(NULL, SEPARATORS, &saveptr); + if (!token) { + ret = kr_error(EINVAL); + goto fail; + } + ret = knot_rrclass_from_string(token, &class); + if (ret != 0) { + ret = kr_error(EINVAL); + goto fail; + } + + /* Type. */ + uint16_t type; + token = strtok_r(NULL, SEPARATORS, &saveptr); + if (!token) { + ret = kr_error(EINVAL); + goto fail; + } + ret = knot_rrtype_from_string(token, &type); + if ((ret != 0) || (type != KNOT_RRTYPE_DS)) { + ret = kr_error(EINVAL); + goto fail; + } + + /* Key tag. */ + token = strtok_r(NULL, SEPARATORS, &saveptr); + if (!token) { + ret = kr_error(EINVAL); + goto fail; + } + ret = uint_parse(token, &aux); + if (ret != 0) { + goto fail; + } + uint16_t key_tag = aux; + + /* Algorithm. */ + token = strtok_r(NULL, SEPARATORS, &saveptr); + if (!token) { + ret = kr_error(EINVAL); + goto fail; + } + ret = algorithm_parse(token, &aux); + if (ret != 0) { + goto fail; + } + uint8_t algorithm = aux; + + /* Digest type. */ + token = strtok_r(NULL, SEPARATORS, &saveptr); + if (!token) { + ret = kr_error(EINVAL); + goto fail; + } + ret = uint_parse(token, &aux); + if (ret != 0) { + goto fail; + } + uint8_t digest_type = aux; + + /* Construct RDATA. */ + knot_rdata_t *rdata = mm_alloc(pool, RDATA_MAXSIZE); + if (!rdata) { + ret = kr_error(ENOMEM); + goto fail; + } + size_t rd_pos = 0; + uint8_t *rd = rdata; + + * (uint16_t *) (rd + rd_pos) = htons(key_tag); rd_pos += 2; + *(rd + rd_pos++) = algorithm; + *(rd + rd_pos++) = digest_type; + + char hexbuf[2]; + int i = 0; + while ((token = strtok_r(NULL, SEPARATORS, &saveptr)) != NULL) { + for (int j = 0; j < strlen(token); ++j) { + hexbuf[i++] = token[j]; + if (i == 2) { + uint8_t byte; + ret = hex2byte(hexbuf, &byte); + if (ret != 0) { + goto fail; + } + i = 0; + + if (rd_pos < RDATA_MAXSIZE) { + *(rd + rd_pos++) = byte; + } else { + ret = kr_error(ENOMEM); + goto fail; + } + } + } + } + + if (i != 0) { + ret = kr_error(EINVAL); + goto fail; + } + + knot_rrset_t *ds_set = knot_rrset_new(owner, type, class, pool); + if (!ds_set) { + ret = kr_error(ENOMEM); + goto fail; + } + + ret = knot_rrset_add_rdata(ds_set, rdata, rd_pos, 0, pool); + if (ret != 0) { + goto fail; + } + + *rr = ds_set; + ds_set = NULL; + +fail: + knot_rrset_free(&ds_set, pool); + mm_free(pool, rdata); + knot_dname_free(&owner, pool); + mm_free(pool, ds_cpy); + return ret; +#undef RDATA_MAXSIZE +#undef SEPARATORS +} + /* Set resolution context and parameters. */ static int begin(knot_layer_t *ctx, void *module_param) { diff --git a/lib/zonecut.c b/lib/zonecut.c index 3532fc844ef1e55ae7db01d55f8d39f0788eb785..12b535924e858005d75b3cdf8de1944eba5eea50 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -24,6 +24,7 @@ #include "lib/rplan.h" #include "lib/defines.h" #include "lib/layer.h" +#include "lib/layer/validate.h" // kr_ta_parse() #include "lib/generic/pack.h" /* Root hint descriptor. */ @@ -71,6 +72,7 @@ int kr_zonecut_init(struct kr_zonecut *cut, const knot_dname_t *name, mm_ctx_t * cut->name = knot_dname_copy(name, pool); cut->pool = pool; cut->key = NULL; + cut->trust_anchor = NULL; cut->nsset = map_make(); cut->nsset.malloc = (map_alloc_f) mm_alloc; cut->nsset.free = (map_free_f) mm_free; @@ -95,6 +97,7 @@ void kr_zonecut_deinit(struct kr_zonecut *cut) map_walk(&cut->nsset, free_addr_set, cut->pool); map_clear(&cut->nsset); knot_rrset_free(&cut->key, cut->pool); + knot_rrset_free(&cut->trust_anchor, cut->pool); } void kr_zonecut_set(struct kr_zonecut *cut, const knot_dname_t *name) @@ -265,7 +268,12 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut) } } -#warning TODO: set root trust anchor from config, or hardcode for now +#warning TODO: set root trust anchor from config + /* Set trust achor. */ + int ret = kr_ta_parse(&cut->trust_anchor, ROOT_TA, cut->pool); + if (ret != 0) { + return ret; + } return kr_ok(); }