Commit 92ce24a7 authored by Štěpán Balážik's avatar Štěpán Balážik

random with cache

parent ab8c6bf3
Pipeline #64073 failed with stages
in 17 seconds
modules.unload('ta_update')
modules.unload('ta_signal_query')
modules.unload('priming')
modules.unload('detect_time_skew')
modules.unload('detect_time_jump')
modules.unload('ta_sentinel')
modules.unload('edns_keepalive')
modules.unload('refuse_nord')
modules.unload('watchdog')
policy.add(policy.all(policy.QTRACE))
......@@ -5,6 +5,10 @@
#include "lib/generic/pack.h"
#include "lib/generic/trie.h"
#include "lib/rplan.h"
#include "lib/cache/api.h"
#include "lib/resolve.h"
// Old code
/** @internal Macro to set address structure. */
#define ADDR_SET(sa, family, addr, len, port) do {\
......@@ -13,52 +17,187 @@
sa ## _port = htons(port); \
} while (0)
int kr_nsrep_elect(struct kr_query *qry)
#define PREFIX 'S'
void *prefix_key(const void *ip, size_t len) {
void *key = malloc(len+1);
*(char*) key = PREFIX;
memcpy(key+1, ip, len);
return key;
}
#undef PREFIX
int32_t get_score(const void *ip, size_t len, struct kr_cache *cache) {
int32_t score;
knot_db_val_t value;
knot_db_t *db = cache->db;
struct kr_cdb_stats *stats = &cache->stats;
void *prefixed_ip = prefix_key(ip, len);
knot_db_val_t key = {.len = len + 1, .data = prefixed_ip};
if(cache->api->read(db, stats, &key, &value, 1)) {
score = -1;
} else {
assert(value.len == sizeof(int32_t));
score = *(int32_t*)value.data;
}
free(prefixed_ip);
return score;
}
int update_score(const void *ip, size_t len, int32_t score, struct kr_cache *cache) {
knot_db_t *db = cache->db;
struct kr_cdb_stats *stats = &cache->stats;
void *prefixed_ip = prefix_key(ip, len);
knot_db_val_t key = {.len = len + 1, .data = prefixed_ip};
knot_db_val_t value = {.len = sizeof(int32_t), .data = &score};
int ret = cache->api->write(db, stats, &key, &value, 1);
free(prefixed_ip);
return ret;
}
struct server {
knot_dname_t *name;
const void* ip;
size_t ip_len;
int32_t score;
};
int cmp_servers(const void* a, const void* b) {
const struct server *a_ = (struct server*) a;
const struct server *b_ = (struct server*) b;
return a_->score - b_->score;
}
struct server *choose(struct server *choice, size_t len) {
qsort(choice, len, sizeof(struct server), &cmp_servers);
return choice;
}
int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx)
{
// Unpack available servers
const int nsset_len = trie_weight(qry->zone_cut.nsset);
struct {
const knot_dname_t *name;
const pack_t *addrs;
knot_dname_t *name;
const pack_t *addr_set;
} nsset[nsset_len];
trie_it_t *it;
printf("hi\n");
int i = 0;
for (it = trie_it_begin(qry->zone_cut.nsset); !trie_it_finished(it);
trie_it_next(it), ++i) {
int name_count = 0;
int addr_count = 0;
printf("Available names: \n");
for(it = trie_it_begin(qry->zone_cut.nsset); !trie_it_finished(it);
trie_it_next(it), ++name_count) {
/* we trust it's a correct dname */
nsset[i].name = (const knot_dname_t *)trie_it_key(it, NULL);
nsset[i].addrs = (const pack_t *)*trie_it_val(it);
nsset[name_count].name = (knot_dname_t *)trie_it_key(it, NULL);
char dname[1024];
knot_dname_to_str(dname, nsset[name_count].name, 1023);
printf("%s\n", dname);
nsset[name_count].addr_set = (const pack_t *)*trie_it_val(it);
for(uint8_t *jt = pack_head(*nsset[name_count].addr_set); jt != pack_tail(*nsset[name_count].addr_set);
jt = pack_obj_next(jt)) {
addr_count++;
}
}
printf("\n");
trie_it_free(it);
assert(i == nsset_len);
assert(name_count == nsset_len);
if(!addr_count) {
// All the NSes are glueless, let's resolve them and try again
// If there are some glued ones, with don't do this at all
printf("No name with address, we will plan to resolve them now.\n");
for(int i = 0; i < name_count; i++) {
char dname[256];
knot_dname_to_str(dname, nsset[0].name, 255);
printf("NS name: %s\n", dname);
char dname[1024];
knot_dname_to_str(dname, nsset[name_count].name, 1023);
printf("%s\n", dname);
if (!pack_obj_len(nsset[0].addrs)) {
printf("fuck, there is no address in cache, fuck\n");
qry->ns.addr[0].ip.sa_family = AF_UNSPEC;
return kr_error(1);
kr_ns_resolve_addr(qry, qry->request);
}
return KR_STATE_PRODUCE; // Retry!
}
uint8_t *head = pack_head(*nsset[0].addrs);
// Flatten the structure
struct server server_set[addr_count];
int c = 0;
for(int i = 0; i < name_count; i++) {
for(uint8_t *obj = pack_head(*nsset[i].addr_set); obj != pack_tail(*nsset[i].addr_set);
obj = pack_obj_next(obj)) {
server_set[c].name = nsset[i].name;
server_set[c].ip = pack_obj_val(obj);
server_set[c].ip_len = pack_obj_len(obj);
c++;
}
}
assert(c == addr_count);
void *val = pack_obj_val(head);
size_t len = pack_obj_len(head);
// Retrieve current scores
struct kr_cache *cache = &ctx->cache;
for(int i = 0; i < addr_count; i++) {
struct server *cur = &server_set[i];
// Currently no feedback, but we set random values
update_score(cur->ip, cur->ip_len, kr_rand_bytes(1), cache);
printf("ip %u\n", *(unsigned *)val);
// printf("ip? %s\n", kr_straddr(kr_inaddr(ip)));
cur->score = get_score(cur->ip, cur->ip_len, cache);
}
// This prints the IP addresses (kinda :P):
printf("Names with addresses:\n");
for(int i = 0; i < addr_count; i++) {
char dname[1024];
knot_dname_to_str(dname, server_set[i].name, 1023);
printf("%s ", dname);
size_t len = server_set[i].ip_len;
const uint8_t *ptr = server_set[i].ip;
for(int j = 0; j < len; j++) {
uint8_t b = *(ptr+j);
printf("%02hx", b);
}
printf(" %d", server_set[i].score);
printf("\n");
}
printf("Total addr_count %d\n", c);
// Choose the _best_ server
struct server *choice = choose(server_set, addr_count);
///
printf("Chose ");
char dname[1024];
knot_dname_to_str(dname, choice->name, 1023);
printf("%s ", dname);
size_t len = choice->ip_len;
const uint8_t *ptr = choice->ip;
for(int j = 0; j < len; j++) {
uint8_t b = *(ptr+j);
printf("%02hx", b);
}
printf("\n");
///
qry->ns.name = nsset[0].name;
if (len == sizeof(struct in_addr)) {
ADDR_SET(qry->ns.addr[0].ip4.sin, AF_INET, val, len, KR_DNS_PORT);
// Set it as next server
qry->ns.name = choice->name;
if (choice->ip_len == sizeof(struct in_addr)) {
ADDR_SET(qry->ns.addr[0].ip4.sin, AF_INET, choice->ip, choice->ip_len, KR_DNS_PORT);
}
if (len == sizeof(struct in6_addr)) {
ADDR_SET(qry->ns.addr[0].ip6.sin6, AF_INET6, val, len, KR_DNS_PORT);
if (choice->ip_len == sizeof(struct in6_addr)) {
ADDR_SET(qry->ns.addr[0].ip6.sin6, AF_INET6, choice->ip, choice->ip_len, KR_DNS_PORT);
}
return kr_ok();
}
\ No newline at end of file
}
......@@ -27,4 +27,4 @@ typedef struct kr_nsrep_rtt_lru_entry {
} kr_nsrep_rtt_lru_entry_t;
KR_EXPORT
int kr_nsrep_elect(struct kr_query *qry);
int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx);
......@@ -147,24 +147,6 @@ static void randomized_qname_case(knot_dname_t * restrict qname, uint32_t secret
}
}
/** Invalidate current NS/addr pair. */
// NS_REP
// static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
// {
// if (qry->ns.addr[0].ip.sa_family != AF_UNSPEC) {
// const char *addr = kr_inaddr(&qry->ns.addr[0].ip);
// int addr_len = kr_inaddr_len(&qry->ns.addr[0].ip);
// int ret = kr_zonecut_del(&qry->zone_cut, qry->ns.name, addr, addr_len);
// /* Also remove it from the qry->ns.addr array.
// * That's useful at least for STUB and FORWARD modes. */
// memmove(qry->ns.addr, qry->ns.addr + 1,
// sizeof(qry->ns.addr[0]) * (KR_NSREP_MAXADDR - 1));
// return ret;
// } else {
// return kr_zonecut_del_all(&qry->zone_cut, qry->ns.name);
// }
// }
/** This turns of QNAME minimisation if there is a non-terminal between current zone cut, and name target.
* It save several minimization steps, as the zone cut is likely final one.
*/
......@@ -301,70 +283,6 @@ static int ns_fetch_cut(struct kr_query *qry, const knot_dname_t *requested_name
return KR_STATE_PRODUCE;
}
static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
{
struct kr_rplan *rplan = &param->rplan;
struct kr_context *ctx = param->ctx;
/* Start NS queries from root, to avoid certain cases
* where a NS drops out of cache and the rest is unavailable,
* this would lead to dependency loop in current zone cut.
* Prefer IPv6 and continue with IPv4 if not available.
*/
uint16_t next_type = 0;
if (!(qry->flags.AWAIT_IPV6) &&
!(ctx->options.NO_IPV6)) {
next_type = KNOT_RRTYPE_AAAA;
qry->flags.AWAIT_IPV6 = true;
} else if (!(qry->flags.AWAIT_IPV4) &&
!(ctx->options.NO_IPV4)) {
next_type = KNOT_RRTYPE_A;
qry->flags.AWAIT_IPV4 = true;
/* Hmm, no useable IPv6 then. */
// NS_REP
// qry->ns.reputation |= KR_NS_NOIP6;
// kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
}
/* Bail out if the query is already pending or dependency loop. */
if (!next_type || kr_rplan_satisfies(qry->parent, qry->ns.name, KNOT_CLASS_IN, next_type)) {
/* Fall back to SBELT if root server query fails. */
if (!next_type && qry->zone_cut.name[0] == '\0') {
VERBOSE_MSG(qry, "=> fallback to root hints\n");
kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
qry->flags.NO_THROTTLE = true; /* Pick even bad SBELT servers */
return kr_error(EAGAIN);
}
/* No IPv4 nor IPv6, flag server as unusable. */
VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out\n");
// NS_REP: qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
// NS_REP: kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
// NS_REP: invalidate_ns(rplan, qry);
return kr_error(EHOSTUNREACH);
}
/* Push new query to the resolution plan */
struct kr_query *next =
kr_rplan_push(rplan, qry, qry->ns.name, KNOT_CLASS_IN, next_type);
if (!next) {
return kr_error(ENOMEM);
}
next->flags.NONAUTH = true;
/* At the root level with no NS addresses, add SBELT subrequest. */
int ret = 0;
if (qry->zone_cut.name[0] == '\0') {
ret = kr_zonecut_set_sbelt(ctx, &next->zone_cut);
if (ret == 0) { /* Copy TA and key since it's the same cut to avoid lookup. */
kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
kr_zonecut_set_sbelt(ctx, &qry->zone_cut); /* Add SBELT to parent in case query fails. */
qry->flags.NO_THROTTLE = true; /* Pick even bad SBELT servers */
}
} else {
next->flags.AWAIT_CUT = true;
}
return ret;
}
static int edns_put(knot_pkt_t *pkt, bool reclaim)
{
if (!pkt->opt_rr) {
......@@ -382,6 +300,8 @@ static int edns_put(knot_pkt_t *pkt, bool reclaim)
return knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
}
/** Removes last EDNS OPT RR written to the packet. */
static int edns_erase_and_reserve(knot_pkt_t *pkt)
{
......@@ -1310,20 +1230,94 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot
return trust_chain_check(request, qry);
}
/** @internal Macro to set address structure. */
#define ADDR_SET(sa, family, addr, len, port) do {\
memcpy(&sa ## _addr, (addr), (len)); \
sa ## _family = (family); \
sa ## _port = htons(port); \
} while (0)
/** Invalidate current NS/addr pair. */
static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
{
if (qry->ns.addr[0].ip.sa_family != AF_UNSPEC) {
const char *addr = kr_inaddr(&qry->ns.addr[0].ip);
int addr_len = kr_inaddr_len(&qry->ns.addr[0].ip);
int ret = kr_zonecut_del(&qry->zone_cut, qry->ns.name, addr, addr_len);
/* Also remove it from the qry->ns.addr array.
* That's useful at least for STUB and FORWARD modes. */
// NS_REP
// memmove(qry->ns.addr, qry->ns.addr + 1,
// sizeof(qry->ns.addr[0]) * (KR_NSREP_MAXADDR - 1));
return ret;
} else {
return kr_zonecut_del_all(&qry->zone_cut, qry->ns.name);
}
}
int kr_ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
{
struct kr_rplan *rplan = &param->rplan;
struct kr_context *ctx = param->ctx;
uint32_t A_ROOT_IP = 167772161; // This is 1.0.0.10 used in maze tests
knot_dname_t a_root[255];
/* Start NS queries from root, to avoid certain cases
* where a NS drops out of cache and the rest is unavailable,
* this would lead to dependency loop in current zone cut.
* Prefer IPv6 and continue with IPv4 if not available.
*/
uint16_t next_type = 0;
if (!(qry->flags.AWAIT_IPV6) &&
!(ctx->options.NO_IPV6)) {
next_type = KNOT_RRTYPE_AAAA;
qry->flags.AWAIT_IPV6 = true;
} else if (!(qry->flags.AWAIT_IPV4) &&
!(ctx->options.NO_IPV4)) {
next_type = KNOT_RRTYPE_A;
qry->flags.AWAIT_IPV4 = true;
/* Hmm, no useable IPv6 then. */
// NS_REP
// qry->ns.reputation |= KR_NS_NOIP6;
// kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
}
/* Bail out if the query is already pending or dependency loop. */
if (!next_type || kr_rplan_satisfies(qry->parent, qry->ns.name, KNOT_CLASS_IN, next_type)) {
/* Fall back to SBELT if root server query fails. */
if (!next_type && qry->zone_cut.name[0] == '\0') {
VERBOSE_MSG(qry, "=> fallback to root hints\n");
kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
qry->flags.NO_THROTTLE = true; /* Pick even bad SBELT servers */
return kr_error(EAGAIN);
}
/* No IPv4 nor IPv6, flag server as unusable. */
VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out\n");
// NS_REP: qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
// NS_REP: kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
invalidate_ns(rplan, qry);
return kr_error(EHOSTUNREACH);
}
/* Push new query to the resolution plan */
struct kr_query *next =
kr_rplan_push(rplan, qry, qry->ns.name, KNOT_CLASS_IN, next_type);
if (!next) {
return kr_error(ENOMEM);
}
next->flags.NONAUTH = true;
/* At the root level with no NS addresses, add SBELT subrequest. */
int ret = 0;
if (qry->zone_cut.name[0] == '\0') {
ret = kr_zonecut_set_sbelt(ctx, &next->zone_cut);
if (ret == 0) { /* Copy TA and key since it's the same cut to avoid lookup. */
kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
kr_zonecut_set_sbelt(ctx, &qry->zone_cut); /* Add SBELT to parent in case query fails. */
qry->flags.NO_THROTTLE = true; /* Pick even bad SBELT servers */
}
} else {
next->flags.AWAIT_CUT = true;
}
if(!ret) {
ITERATE_LAYERS(param, qry, reset);
}
return ret;
}
int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *type, knot_pkt_t *packet)
{
struct kr_rplan *rplan = &request->rplan;
unsigned ns_election_iter = 0;
/* No query left for resolution */
if (kr_rplan_empty(rplan)) {
......@@ -1430,24 +1424,10 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
}
}
qry->ns.name = knot_dname_from_str(a_root, "a.root-server.net", 255);
ADDR_SET(qry->ns.addr[0].ip4.sin, AF_INET, &A_ROOT_IP, 4, KR_DNS_PORT);
if(kr_nsrep_elect(qry, request->ctx) == KR_STATE_PRODUCE) {
return KR_STATE_PRODUCE;
}
/* Resolve address records */
// if (kr_nsrep_elect(qry)) {
// int ret = ns_resolve_addr(qry, request);
// if (ret != 0) {
// qry->flags.AWAIT_IPV6 = false;
// qry->flags.AWAIT_IPV4 = false;
// qry->flags.TCP = false;
// qry->ns.name = NULL;
// }
// ITERATE_LAYERS(request, qry, reset);
// return KR_STATE_PRODUCE;
// }
/* Randomize query case (if not in safe mode or turned off) */
qry->secret = (qry->flags.SAFEMODE || qry->flags.NO_0X20)
......
......@@ -254,7 +254,7 @@ int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pk
* Consume input packet (may be either first query or answer to query originated from kr_resolve_produce())
*
* @note If the I/O fails, provide an empty or NULL packet, this will make iterator recognize nameserver failure.
*
*
* @param request request state (awaiting input)
* @param src [in] packet source address
* @param packet [in] input packet
......@@ -269,7 +269,7 @@ int kr_resolve_consume(struct kr_request *request, const struct sockaddr *src, k
* If the CONSUME is returned then dst, type and packet will be filled with
* appropriate values and caller is responsible to send them and receive answer.
* If it returns any other state, then content of the variables is undefined.
*
*
* @param request request state (in PRODUCE state)
* @param dst [out] possible address of the next nameserver
* @param type [out] possible used socket type (SOCK_STREAM, SOCK_DGRAM)
......@@ -308,6 +308,9 @@ int kr_resolve_checkout(struct kr_request *request, const struct sockaddr *src,
KR_EXPORT
int kr_resolve_finish(struct kr_request *request, int state);
KR_EXPORT
int kr_ns_resolve_addr(struct kr_query *qry, struct kr_request *param);
/**
* Return resolution plan.
* @param request request state
......@@ -323,4 +326,3 @@ struct kr_rplan *kr_resolve_plan(struct kr_request *request);
*/
KR_EXPORT KR_PURE
knot_mm_t *kr_resolve_pool(struct kr_request *request);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment