static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_lru_t *rttcache, unsigned score, uint8_t *addr[], uint32_t opts) { /* Name server is better candidate if it has address record. */ uint8_t *it = pack_head(*addr_set); while (it != pack_tail(*addr_set)) { void *val = pack_obj_val(it); size_t len = pack_obj_len(it); unsigned favour = 0; bool is_valid = false; /* Check if the address isn't disabled. */ if (len == sizeof(struct in6_addr)) { is_valid = !(opts & QUERY_NO_IPV6); favour = FAVOUR_IPV6; } else { is_valid = !(opts & QUERY_NO_IPV4); } /* Get RTT for this address (if known) */ if (is_valid) { unsigned *cached = rttcache ? lru_get(rttcache, val, len) : NULL; unsigned addr_score = (cached) ? *cached : KR_NS_GLUED; if (addr_score < score + favour) { /* Shake down previous contenders */ for (size_t i = KR_NSREP_MAXADDR - 1; i > 0; --i) addr[i] = addr[i - 1]; addr[0] = it; score = addr_score; } } it = pack_obj_next(it); } return score; }
/** @internal Pack address list into JSON array. */ static JsonNode *pack_addrs(pack_t *pack) { char buf[SOCKADDR_STRLEN]; JsonNode *root = json_mkarray(); uint8_t *addr = pack_head(*pack); while (addr != pack_tail(*pack)) { size_t len = pack_obj_len(addr); int family = len == sizeof(struct in_addr) ? AF_INET : AF_INET6; if (!inet_ntop(family, pack_obj_val(addr), buf, sizeof(buf))) { break; } json_append_element(root, json_mkstring(buf)); addr = pack_obj_next(addr); } return root; }
static int answer_query(knot_pkt_t *pkt, pack_t *addr_set, struct kr_query *qry) { uint16_t rrtype = qry->stype; uint16_t rrclass = qry->sclass; if (rrtype != KNOT_RRTYPE_A && rrtype != KNOT_RRTYPE_AAAA) { return kr_error(ENOENT); } knot_dname_t *qname = knot_dname_copy(qry->sname, &pkt->mm); knot_rrset_t rr; knot_rrset_init(&rr, qname, rrtype, rrclass); int family_len = sizeof(struct in_addr); if (rr.type == KNOT_RRTYPE_AAAA) { family_len = sizeof(struct in6_addr); } /* Append address records from hints */ uint8_t *addr = pack_head(*addr_set); while (addr != pack_tail(*addr_set)) { size_t len = pack_obj_len(addr); void *addr_val = pack_obj_val(addr); if (len == family_len) { knot_rrset_add_rdata(&rr, addr_val, len, 0, &pkt->mm); } addr = pack_obj_next(addr); } int ret = kr_error(ENOENT); if (!knot_rrset_empty(&rr)) { /* Update packet question */ if (!knot_dname_is_equal(knot_pkt_qname(pkt), qname)) { KR_PKT_RECYCLE(pkt); knot_pkt_put_question(pkt, qname, rrclass, rrtype); } /* Append to packet */ ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, &rr, KNOT_PF_FREE); } /* Clear RR if failed */ if (ret != 0) { knot_rrset_clear(&rr, &pkt->mm); } return ret; }
static void test_pack_std(void **state) { int ret = 0; pack_t pack; pack_init(pack); assert_int_equal(pack.len, 0); /* Push/delete without reservation. */ assert_int_not_equal(pack_obj_push(&pack, U8(""), 1), 0); assert_int_not_equal(pack_obj_del(&pack, U8(""), 1), 0); /* Reserve capacity and fill. */ assert_true(pack_reserve(pack, 10, 10 * 2) >= 0); for (unsigned i = 0; i < 10; ++i) { ret = pack_obj_push(&pack, U8("de"), 2); assert_true(ret >= 0); } /* Iterate */ uint8_t *it = pack_head(pack); assert_non_null(it); unsigned count = 0; while (it != pack_tail(pack)) { assert_int_equal(pack_obj_len(it), 2); assert_true(memcmp(pack_obj_val(it), "de", 2) == 0); it = pack_obj_next(it); count += 1; } /* Find */ it = pack_obj_find(&pack, U8("de"), 2); assert_non_null(it); it = pack_obj_find(&pack, U8("ed"), 2); assert_null(it); /* Delete */ assert_int_not_equal(pack_obj_del(&pack, U8("be"), 2), 0); assert_int_equal(pack_obj_del(&pack, U8("de"), 2), 0); assert_int_equal(pack.len, 9*(2+2)); /* 9 objects, length=2 */ pack_clear(pack); }
static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_lru_t *rttcache, unsigned score, uint8_t **addr) { /* Name server is better candidate if it has address record. */ uint8_t *it = pack_head(*addr_set); while (it != pack_tail(*addr_set)) { void *val = pack_obj_val(it); size_t len = pack_obj_len(it); /* Get RTT for this address (if known) */ unsigned *cached = rttcache ? lru_get(rttcache, val, len) : NULL; unsigned addr_score = (cached) ? *cached : KR_NS_GLUED; /* Give v6 a head start */ unsigned favour = (len == sizeof(struct in6_addr)) ? FAVOUR_IPV6 : 0; if (addr_score < score + favour) { *addr = it; score = addr_score; } it = pack_obj_next(it); } return score; }