static void _test_nsec_next(const char *msg, const knot_dname_t *input, const knot_dname_t *apex, const knot_dname_t *expected) { knot_dname_t *next = online_nsec_next(input, apex); ok(next != NULL && knot_dname_cmp(next, expected) == 0, "nsec_next, %s", msg); knot_dname_free(&next, NULL); }
static int ztree_tests_run(int argc, char *argv[]) { ztree_init_data(); /* 1. create test */ knot_zone_tree_t* t = knot_zone_tree_create(); ok(t != NULL, "ztree: created"); /* 2. insert test */ unsigned passed = 1; for (unsigned i = 0; i < NCOUNT; ++i) { if (knot_zone_tree_insert(t, NODE + i) != KNOT_EOK) { passed = 0; break; } } ok(passed, "ztree: insertion"); /* 3. check data test */ passed = 1; const knot_node_t *node = NULL; for (unsigned i = 0; i < NCOUNT; ++i) { int r = knot_zone_tree_find(t, NAME[i], &node); if (r != KNOT_EOK || node != NODE + i) { passed = 0; break; } } ok(passed, "ztree: lookup"); /* heal index for ordered lookup */ hattrie_build_index(t); /* 4. ordered lookup */ passed = 1; node = NULL; const knot_node_t *prev = NULL; knot_dname_t *tmp_dn = knot_dname_new_from_str("z.ac.", 5, NULL); knot_zone_tree_find_less_or_equal(t, tmp_dn, &node, &prev); knot_dname_free(&tmp_dn); ok(prev == NODE + 1, "ztree: ordered lookup"); /* 5. ordered traversal */ struct ztree_iter it = { KNOT_EOK, 0 }; knot_zone_tree_apply_inorder(t, ztree_iter_data, &it); ok (it.ret == KNOT_EOK, "ztree: ordered traversal"); knot_zone_tree_free(&t); ztree_free_data(); return 0; }
static int reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, knot_rrset_t *rr) { /* Synthetize PTR record data. */ knot_dname_t *ptrname = synth_ptrname(addr_str, tpl); if (ptrname == NULL) { return KNOT_ENOMEM; } rr->type = KNOT_RRTYPE_PTR; knot_rrset_add_rdata(rr, ptrname, knot_dname_size(ptrname), tpl->ttl, &pkt->mm); knot_dname_free(&ptrname, NULL); return KNOT_EOK; }
/*----------------------------------------------------------------------------*/ _public_ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) { if (d1 == NULL || d2 == NULL) return NULL; /* This is problem equal to replacing last \x00 from d1 with d2. */ knot_dname_t *ret = knot_dname_replace_suffix(d1, 0, d2); /* Like if we are reallocating d1. */ if (ret != NULL) knot_dname_free(&d1, NULL); return ret; }
static int adjust_nsec3_pointers(zone_node_t **tnode, void *data) { assert(data != NULL); assert(tnode != NULL); zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; zone_node_t *node = *tnode; // Connect to NSEC3 node (only if NSEC3 tree is not empty) zone_node_t *nsec3 = NULL; knot_dname_t *nsec3_name = NULL; int ret = zone_contents_nsec3_name(args->zone, node->owner, &nsec3_name); if (ret == KNOT_EOK) { assert(nsec3_name); zone_tree_get(args->zone->nsec3_nodes, nsec3_name, &nsec3); node->nsec3_node = nsec3; } else if (ret == KNOT_ENSEC3PAR) { node->nsec3_node = NULL; ret = KNOT_EOK; } knot_dname_free(&nsec3_name, NULL); return ret; }
int main(int argc, char *argv[]) { plan(25); /* Create memory pool context. */ int ret = 0; knot_mm_t mm; mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE); /* Create names and data. */ knot_dname_t* dnames[NAMECOUNT] = {0}; knot_rrset_t* rrsets[NAMECOUNT] = {0}; for (unsigned i = 0; i < NAMECOUNT; ++i) { dnames[i] = knot_dname_from_str_alloc(g_names[i]); } uint8_t *edns_str = (uint8_t *)"ab"; /* Create OPT RR. */ knot_rrset_t opt_rr; ret = knot_edns_init(&opt_rr, 1024, 0, 0, &mm); if (ret != KNOT_EOK) { skip_block(25, "Failed to initialize OPT RR."); return 0; } /* Add NSID */ ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_NSID, strlen((char *)edns_str), edns_str, &mm); if (ret != KNOT_EOK) { knot_rrset_clear(&opt_rr, &mm); skip_block(25, "Failed to add NSID to OPT RR."); return 0; } /* * Packet writer tests. */ /* Create packet. */ knot_pkt_t *out = knot_pkt_new(NULL, MM_DEFAULT_BLKSIZE, &mm); ok(out != NULL, "pkt: new"); /* Mark as response (not part of the test). */ knot_wire_set_qr(out->wire); /* Secure packet. */ const char *tsig_secret = "abcd"; knot_tsig_key_t tsig_key; tsig_key.algorithm = DNSSEC_TSIG_HMAC_MD5; tsig_key.name = dnames[0]; tsig_key.secret.data = (uint8_t *)strdup(tsig_secret); tsig_key.secret.size = strlen(tsig_secret); ret = knot_pkt_reserve(out, knot_tsig_wire_maxsize(&tsig_key)); ok(ret == KNOT_EOK, "pkt: set TSIG key"); /* Write question. */ ret = knot_pkt_put_question(out, dnames[0], KNOT_CLASS_IN, KNOT_RRTYPE_A); ok(ret == KNOT_EOK, "pkt: put question"); /* Add OPT to packet (empty NSID). */ ret = knot_pkt_reserve(out, knot_edns_wire_size(&opt_rr)); ok(ret == KNOT_EOK, "pkt: reserve OPT RR"); /* Begin ANSWER section. */ ret = knot_pkt_begin(out, KNOT_ANSWER); ok(ret == KNOT_EOK, "pkt: begin ANSWER"); /* Write ANSWER section. */ rrsets[0] = knot_rrset_new(dnames[0], KNOT_RRTYPE_A, KNOT_CLASS_IN, NULL); knot_dname_free(&dnames[0], NULL); knot_rrset_add_rdata(rrsets[0], RDVAL(0), RDLEN(0), TTL, NULL); ret = knot_pkt_put(out, KNOT_COMPR_HINT_QNAME, rrsets[0], 0); ok(ret == KNOT_EOK, "pkt: write ANSWER"); /* Begin AUTHORITY. */ ret = knot_pkt_begin(out, KNOT_AUTHORITY); ok(ret == KNOT_EOK, "pkt: begin AUTHORITY"); /* Write rest to AUTHORITY. */ ret = KNOT_EOK; for (unsigned i = 1; i < NAMECOUNT; ++i) { rrsets[i] = knot_rrset_new(dnames[i], KNOT_RRTYPE_NS, KNOT_CLASS_IN, NULL); knot_dname_free(&dnames[i], NULL); knot_rrset_add_rdata(rrsets[i], RDVAL(i), RDLEN(i), TTL, NULL); ret |= knot_pkt_put(out, KNOT_COMPR_HINT_NONE, rrsets[i], 0); } ok(ret == KNOT_EOK, "pkt: write AUTHORITY(%u)", NAMECOUNT - 1); /* Begin ADDITIONALS */ ret = knot_pkt_begin(out, KNOT_ADDITIONAL); ok(ret == KNOT_EOK, "pkt: begin ADDITIONALS"); /* Encode OPT RR. */ ret = knot_pkt_put(out, KNOT_COMPR_HINT_NONE, &opt_rr, 0); ok(ret == KNOT_EOK, "pkt: write OPT RR"); /* * Packet reader tests. */ /* Create new packet from query packet. */ knot_pkt_t *in = knot_pkt_new(out->wire, out->size, &out->mm); ok(in != NULL, "pkt: create packet for parsing"); /* Read packet header. */ ret = knot_pkt_parse_question(in); ok(ret == KNOT_EOK, "pkt: read header"); /* Read packet payload. */ ret = knot_pkt_parse_payload(in, 0); ok(ret == KNOT_EOK, "pkt: read payload"); /* Compare parsed packet to written packet. */ packet_match(in, out); /* * Copied packet tests. */ knot_pkt_t *copy = knot_pkt_new(NULL, in->max_size, &in->mm); ret = knot_pkt_copy(copy, in); ok(ret == KNOT_EOK, "pkt: create packet copy"); /* Compare copied packet to original. */ packet_match(in, copy); /* Free packets. */ knot_pkt_free(©); knot_pkt_free(&out); knot_pkt_free(&in); ok(in == NULL && out == NULL && copy == NULL, "pkt: free"); /* Free extra data. */ for (unsigned i = 0; i < NAMECOUNT; ++i) { knot_rrset_free(&rrsets[i], NULL); } free(tsig_key.secret.data); mp_delete((struct mempool *)mm.ctx); return 0; }
int main(int argc, char *argv[]) { plan(10); /* Prepare query. */ knot_pkt_t *query = knot_pkt_new(NULL, 512, NULL); if (query == NULL) { return KNOT_ERROR; /* Fatal */ } knot_dname_t *qname = knot_dname_from_str("beef."); int ret = knot_pkt_put_question(query, qname, KNOT_CLASS_IN, KNOT_RRTYPE_A); knot_dname_free(&qname, NULL); if (ret != KNOT_EOK) { knot_pkt_free(&query); return KNOT_ERROR; /* Fatal */ } /* Prepare response */ uint8_t rbuf[65535]; size_t rlen = sizeof(rbuf); memcpy(rbuf, query->wire, query->size); knot_wire_flags_set_qr(rbuf); rrl_req_t rq; rq.w = rbuf; rq.len = rlen; rq.query = query; rq.flags = 0; /* 1. create rrl table */ rrl_table_t *rrl = rrl_create(RRL_SIZE); ok(rrl != NULL, "rrl: create"); /* 2. set rate limit */ uint32_t rate = 10; rrl_setrate(rrl, rate); is_int(rate, rrl_rate(rrl), "rrl: setrate"); /* 3. setlocks */ ret = rrl_setlocks(rrl, RRL_LOCKS); is_int(KNOT_EOK, ret, "rrl: setlocks"); /* 4. N unlimited requests. */ conf_zone_t *zone_conf = malloc(sizeof(conf_zone_t)); conf_init_zone(zone_conf); zone_conf->name = strdup("rrl."); zone_t *zone = zone_new(zone_conf); struct sockaddr_storage addr; struct sockaddr_storage addr6; sockaddr_set(&addr, AF_INET, "1.2.3.4", 0); sockaddr_set(&addr6, AF_INET6, "1122:3344:5566:7788::aabb", 0); ret = 0; for (unsigned i = 0; i < rate; ++i) { if (rrl_query(rrl, &addr, &rq, zone) != KNOT_EOK || rrl_query(rrl, &addr6, &rq, zone) != KNOT_EOK) { ret = KNOT_ELIMIT; break; } } is_int(0, ret, "rrl: unlimited IPv4/v6 requests"); #ifdef ENABLE_TIMED_TESTS /* 5. limited request */ ret = rrl_query(rrl, &addr, &rq, zone); is_int(0, ret, "rrl: throttled IPv4 request"); /* 6. limited IPv6 request */ ret = rrl_query(rrl, &addr6, &rq, zone); is_int(0, ret, "rrl: throttled IPv6 request"); #else skip_block(2, "Timed tests not enabled"); #endif /* 7. invalid values. */ ret = 0; rrl_create(0); // NULL ret += rrl_setrate(0, 0); // 0 ret += rrl_rate(0); // 0 ret += rrl_setlocks(0,0); // -1 ret += rrl_query(0, 0, 0, 0); // -1 ret += rrl_query(rrl, 0, 0, 0); // -1 ret += rrl_query(rrl, (void*)0x1, 0, 0); // -1 ret += rrl_destroy(0); // -1 is_int(-488, ret, "rrl: not crashed while executing functions on NULL context"); #ifdef ENABLE_TIMED_TESTS /* 8. hopscotch test */ struct runnable_data rd = { 1, rrl, &addr, &rq, zone }; rrl_hopscotch(&rd); ok(rd.passed, "rrl: hashtable is ~ consistent"); /* 9. reseed */ is_int(0, rrl_reseed(rrl), "rrl: reseed"); /* 10. hopscotch after reseed. */ rrl_hopscotch(&rd); ok(rd.passed, "rrl: hashtable is ~ consistent"); #else skip_block(3, "Timed tests not enabled"); #endif zone_free(&zone); knot_pkt_free(&query); rrl_destroy(rrl); return 0; }
int synth_record_load(struct query_plan *plan, struct query_module *self) { /* Parse first token. */ char *saveptr = NULL; char *token = strtok_r(self->param, " ", &saveptr); if (token == NULL) { return KNOT_EFEWDATA; } /* Create synthesis template. */ struct synth_template *tpl = mm_alloc(self->mm, sizeof(struct synth_template)); if (tpl == NULL) { return KNOT_ENOMEM; } /* Save in query module, it takes ownership from now on. */ self->ctx = tpl; /* Supported types: reverse, forward */ if (strcmp(token, "reverse") == 0) { tpl->type = SYNTH_REVERSE; } else if (strcmp(token, "forward") == 0) { tpl->type = SYNTH_FORWARD; } else { MODULE_ERR("invalid type '%s'.\n", token); return KNOT_ENOTSUP; } /* Parse format string. */ tpl->prefix = strtok_r(NULL, " ", &saveptr); if (strchr(tpl->prefix, '.') != NULL) { MODULE_ERR("dots '.' are not allowed in the prefix.\n"); return KNOT_EMALF; } /* Parse zone if generating reverse record. */ if (tpl->type == SYNTH_REVERSE) { tpl->zone = strtok_r(NULL, " ", &saveptr); knot_dname_t *check_name = knot_dname_from_str(tpl->zone); if (check_name == NULL) { MODULE_ERR("invalid zone '%s'.\n", tpl->zone); return KNOT_EMALF; } knot_dname_free(&check_name, NULL); } /* Parse TTL. */ tpl->ttl = strtol(strtok_r(NULL, " ", &saveptr), NULL, 10); /* Parse address. */ token = strtok_r(NULL, " ", &saveptr); char *subnet = strchr(token, '/'); if (subnet) { subnet[0] = '\0'; tpl->subnet.prefix = strtol(subnet + 1, NULL, 10); } /* Estimate family. */ int family = AF_INET; int prefix_max = IPV4_PREFIXLEN; if (strchr(token, ':') != NULL) { family = AF_INET6; prefix_max = IPV6_PREFIXLEN; } /* Check subnet. */ if (tpl->subnet.prefix > prefix_max) { MODULE_ERR("invalid address prefix '%s'.\n", subnet); return KNOT_EMALF; } int ret = sockaddr_set(&tpl->subnet.ss, family, token, 0); if (ret != KNOT_EOK) { MODULE_ERR("invalid address '%s'.\n", token); return KNOT_EMALF; } return query_plan_step(plan, QPLAN_ANSWER, solve_synth_record, tpl); }
static void ztree_free_data() { for (unsigned i = 0; i < NCOUNT; ++i) knot_dname_free(NAME + i); }
/*! Run all scheduled tests for given parameters. */ int main(int argc, char *argv[]) { plan(19); // Test 1: Allocate new config const char *config_fn = "rc:/sample_conf"; conf_t *conf = conf_new(strdup(config_fn)); ok(conf != 0, "config_new()"); // Test 2: Parse config int ret = conf_parse_str(conf, sample_conf_rc); is_int(0, ret, "parsing configuration file %s", config_fn); if (ret != 0) { skip_block(19, "Parse err"); goto skip_all; } // Test 3: Test server version (0-level depth) is_string("Infinitesimal", conf->version, "server version loaded ok"); // Test 4: Test interfaces (1-level depth) ok(!EMPTY_LIST(conf->ifaces), "configured interfaces exist"); // Test 5,6: Interfaces content (2-level depth) struct node *n = HEAD(conf->ifaces); conf_iface_t *iface = (conf_iface_t*)n; struct sockaddr_storage addr_ref; sockaddr_set(&addr_ref, AF_INET, "10.10.1.1", 53531); is_int(0, sockaddr_cmp(&iface->addr, &addr_ref), "interface0 address check"); n = n->next; iface = (conf_iface_t*)n; sockaddr_set(&addr_ref, AF_INET6, "::0", 53); is_int(0, sockaddr_cmp(&iface->addr, &addr_ref), "interface1 address check"); // Test 9,10: Check server key if (EMPTY_LIST(conf->keys)) { ok(0, "TSIG key algorithm check - NO KEY FOUND"); ok(0, "TSIG key secret check - NO KEY FOUND"); } else { knot_tsig_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k; uint8_t decoded_secret[] = { 0x5a }; ok(k->algorithm == KNOT_TSIG_ALG_HMAC_MD5, "TSIG key algorithm check"); ok(k->secret.size == sizeof(decoded_secret) && memcmp(k->secret.data, decoded_secret, sizeof(decoded_secret)) == 0, "TSIG key secret check"); } // Test 11,12,13,14,15,16,17,18: Check logging facilities ok(list_size(&conf->logs) == 4, "log facilites count check"); n = HEAD(conf->logs); ok(!EMPTY_LIST(conf->logs), "log facilities not empty"); conf_log_t *log = (conf_log_t*)n; node_t *nm = HEAD(log->map); conf_log_map_t *m = (conf_log_map_t*)nm; ok(log->type == LOGT_SYSLOG, "log0 is syslog"); if (EMPTY_LIST(log->map)) { skip_block(5, "Empty list"); } else { ok(m->source == LOG_ANY, "syslog first rule is ANY"); int mask = LOG_UPTO(LOG_NOTICE); ok(m->prios == mask, "syslog mask is equal"); nm = nm->next; m = (conf_log_map_t*)nm; ok(m != 0, "syslog has more than 1 rule"); if (m == 0) { skip_block(2, "No mapping"); } else { ok(m->source == LOG_ZONE, "syslog next rule is for zone"); ok(m->prios == LOG_UPTO(LOG_INFO), "rule for zone is: info level"); } } // Test 19,20: File facility checks n = n->next; log = (conf_log_t*)n; ok(n != 0, "log has next facility"); if (n == 0) { skip("No mapping"); } else { is_string("/var/log/knot/server.err", log->file, "log file matches"); } // Test 21: Load key dname const char *sample_str = "key0.example.net"; knot_dname_t *sample = knot_dname_from_str_alloc(sample_str); if (list_size(&conf->keys) > 0) { knot_tsig_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k; ok(knot_dname_cmp(sample, k->name) == 0, "TSIG key dname check"); } else { ok(0, "TSIG key dname check - NO KEY FOUND"); } knot_dname_free(&sample, NULL); skip_all: // Deallocating config conf_free(conf); return 0; }
/*! * \brief Entry point of 'knsec3hash'. */ int main(int argc, char *argv[]) { bool enable_idn = true; struct option options[] = { { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { NULL } }; #ifdef LIBIDN // Set up localization. if (setlocale(LC_CTYPE, "") == NULL) { enable_idn = false; } #endif int opt = 0; int li = 0; while ((opt = getopt_long(argc, argv, "hV", options, &li)) != -1) { switch(opt) { case 'V': printf("%s, version %s\n", PROGRAM_NAME, PACKAGE_VERSION); return 0; case 'h': usage(stdout); return 0; default: usage(stderr); return 1; } } // knsec3hash <salt> <algorithm> <iterations> <domain> if (argc != 5) { usage(stderr); return 1; } atexit(knot_crypto_cleanup); int exit_code = 1; knot_nsec3_params_t nsec3_params = { 0 }; knot_dname_t *dname = NULL; uint8_t *digest = NULL; size_t digest_size = 0; uint8_t *b32_digest = NULL; int32_t b32_length = 0; int result = 0; if (!parse_nsec3_params(&nsec3_params, argv[1], argv[2], argv[3])) { goto fail; } if (enable_idn) { char *ascii_name = name_from_idn(argv[4]); if (ascii_name == NULL) { fprintf(stderr, "Cannot transform IDN domain name.\n"); goto fail; } dname = knot_dname_from_str(ascii_name); free(ascii_name); } else { dname = knot_dname_from_str(argv[4]); } if (dname == NULL) { fprintf(stderr, "Cannot parse domain name.\n"); goto fail; } result = knot_nsec3_hash(&nsec3_params, dname, knot_dname_size(dname), &digest, &digest_size); if (result != KNOT_EOK) { fprintf(stderr, "Cannot compute hash: %s\n", knot_strerror(result)); goto fail; } b32_length = base32hex_encode_alloc(digest, digest_size, &b32_digest); if (b32_length < 0) { fprintf(stderr, "Cannot encode computed hash: %s\n", knot_strerror(b32_length)); goto fail; } exit_code = 0; printf("%.*s (salt=%s, hash=%d, iterations=%d)\n", b32_length, b32_digest, argv[1], nsec3_params.algorithm, nsec3_params.iterations); fail: knot_nsec3param_free(&nsec3_params); knot_dname_free(&dname, NULL); free(digest); free(b32_digest); return exit_code; }
int main(int argc, char *argv[]) { plan(23); // Test with NULL changeset ok(changeset_size(NULL) == 0, "changeset: NULL size"); ok(changeset_empty(NULL), "changeset: NULL empty"); // Test creation. knot_dname_t *d = knot_dname_from_str_alloc("test."); assert(d); changeset_t *ch = changeset_new(d); knot_dname_free(&d, NULL); ok(ch != NULL, "changeset: new"); ok(changeset_empty(ch), "changeset: empty"); ch->soa_to = (knot_rrset_t *)0xdeadbeef; ok(!changeset_empty(ch), "changseset: empty SOA"); ch->soa_to = NULL; ok(changeset_size(ch) == 0, "changeset: empty size"); // Test additions. d = knot_dname_from_str_alloc("non.terminals.test."); assert(d); knot_rrset_t *apex_txt_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, NULL); assert(apex_txt_rr); uint8_t data[8] = "\7teststr"; knot_rrset_add_rdata(apex_txt_rr, data, sizeof(data), 3600, NULL); int ret = changeset_add_rrset(ch, apex_txt_rr); ok(ret == KNOT_EOK, "changeset: add RRSet"); ok(changeset_size(ch) == 1, "changeset: size add"); ret = changeset_rem_rrset(ch, apex_txt_rr); ok(ret == KNOT_EOK, "changeset: rem RRSet"); ok(changeset_size(ch) == 2, "changeset: size remove"); ok(!changeset_empty(ch), "changeset: not empty"); // Add another RR to node. knot_rrset_t *apex_spf_rr = knot_rrset_new(d, KNOT_RRTYPE_SPF, KNOT_CLASS_IN, NULL); assert(apex_spf_rr); knot_rrset_add_rdata(apex_spf_rr, data, sizeof(data), 3600, NULL); ret = changeset_add_rrset(ch, apex_spf_rr); ok(ret == KNOT_EOK, "changeset: add multiple"); // Add another node. knot_dname_free(&d, NULL); d = knot_dname_from_str_alloc("here.come.more.non.terminals.test"); assert(d); knot_rrset_t *other_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, NULL); assert(other_rr); knot_rrset_add_rdata(other_rr, data, sizeof(data), 3600, NULL); ret = changeset_add_rrset(ch, other_rr); ok(ret == KNOT_EOK, "changeset: remove multiple"); // Test add traversal. changeset_iter_t it; ret = changeset_iter_add(&it, ch, true); ok(ret == KNOT_EOK, "changeset: create iter add"); // Order: non.terminals.test. TXT, SPF, here.come.more.non.terminals.test. TXT. knot_rrset_t iter = changeset_iter_next(&it); bool trav_ok = knot_rrset_equal(&iter, apex_txt_rr, KNOT_RRSET_COMPARE_WHOLE); iter = changeset_iter_next(&it); trav_ok = trav_ok && knot_rrset_equal(&iter, apex_spf_rr, KNOT_RRSET_COMPARE_WHOLE); iter = changeset_iter_next(&it); trav_ok = trav_ok && knot_rrset_equal(&iter, other_rr, KNOT_RRSET_COMPARE_WHOLE); ok(trav_ok, "changeset: add traversal"); iter = changeset_iter_next(&it); changeset_iter_clear(&it); ok(knot_rrset_empty(&iter), "changeset: traversal: skip non-terminals"); // Test remove traversal. ret = changeset_iter_rem(&it, ch, false); ok(ret == KNOT_EOK, "changeset: create iter rem"); iter = changeset_iter_next(&it); ok(knot_rrset_equal(&iter, apex_txt_rr, KNOT_RRSET_COMPARE_WHOLE), "changeset: rem traversal"); changeset_iter_clear(&it); // Test all traversal - just count. ret = changeset_iter_all(&it, ch, false); ok(ret == KNOT_EOK, "changest: create iter all"); size_t size = 0; iter = changeset_iter_next(&it); while (!knot_rrset_empty(&iter)) { ++size; iter = changeset_iter_next(&it); } changeset_iter_clear(&it); ok(size == 4, "changeset: iter all"); // Create new changeset. knot_dname_free(&d, NULL); d = knot_dname_from_str_alloc("test."); assert(d); changeset_t *ch2 = changeset_new(d); knot_dname_free(&d, NULL); assert(ch2); // Add something to add section. knot_dname_free(&apex_txt_rr->owner, NULL); apex_txt_rr->owner = knot_dname_from_str_alloc("something.test."); assert(apex_txt_rr->owner); ret = changeset_add_rrset(ch2, apex_txt_rr); assert(ret == KNOT_EOK); // Add something to remove section. knot_dname_free(&apex_txt_rr->owner, NULL); apex_txt_rr->owner = knot_dname_from_str_alloc("and.now.for.something.completely.different.test."); assert(apex_txt_rr->owner); ret = changeset_rem_rrset(ch2, apex_txt_rr); assert(ret == KNOT_EOK); // Test merge. ret = changeset_merge(ch, ch2); ok(ret == KNOT_EOK && changeset_size(ch) == 6, "changeset: merge"); // Test cleanup. changeset_clear(ch); ok(changeset_empty(ch), "changeset: clear"); free(ch); list_t chgs; init_list(&chgs); add_head(&chgs, &ch2->n); changesets_clear(&chgs); ok(changeset_empty(ch2), "changeset: clear list"); free(ch2); knot_rrset_free(&apex_txt_rr, NULL); knot_rrset_free(&apex_spf_rr, NULL); knot_rrset_free(&other_rr, NULL); return 0; }