Knot Resolver library

Requirements

  • libknot 2.0 (Knot DNS high-performance DNS library.)

For users

The library as described provides basic services for name resolution, which should cover the usage,examples are in theresolve API documentation.

Tip

If you’re migrating fromgetaddrinfo(), see“synchronous” API, but the library offers iterative API as well to plug it into your event loop for example.

For developers

The resolution process starts with the functions inresolve.c, they are responsible for:

  • reacting to state machine state (i.e. calling consume layers if we have an answer ready)
  • interacting with the library user (i.e. asking caller for I/O, accepting queries)
  • fetching assets needed by layers (i.e. zone cut)

This is thedriver. The driver is not meant to know“how” the query resolves, but rather“when” to execute“what”.

_images/resolution.png

On the other side arelayers. They are responsible for dissecting the packets and informing the driver about the results. For example, aproduce layer generates query, aconsume layer validates answer.

Tip

Layers are executed asynchronously by the driver. If you need some asset beforehand, you can signalize the driver using returning state or current query flags. For example, setting a flagAWAIT_CUT forces driver to fetch zone cut information before the packet is consumed; setting aRESOLVED flag makes it pop a query after the current set of layers is finished; returningFAIL state makes it fail current query.

Layers can also change course of resolution, for example by appending additional queries.

consume=function(state,req,answer)ifanswer:qtype()==kres.type.NSthenlocalqry=req:push(answer:qname(),kres.type.SOA,kres.class.IN)qry.flags.AWAIT_CUT=trueendreturnstateend

Thisdoesn’t block currently processed query, and the newly created sub-request will start as soon as driver finishes processing current. In some cases you might need to issue sub-request and process itbefore continuing with the current, i.e. validator may need a DNSKEY before it can validate signatures. In this case, layers can yield and resume afterwards.

consume=function(state,req,answer)ifstate==kres.YIELDthenprint('continuing yielded layer')returnkres.DONEelseifanswer:qtype()==kres.type.NSthenlocalqry=req:push(answer:qname(),kres.type.SOA,kres.class.IN)qry.flags.AWAIT_CUT=trueprint('planned SOA query, yielding')returnkres.YIELDendreturnstateendend

TheYIELD state is a bit special. When a layer returns it, it interrupts current walk through the layers. When the layer receives it,it means that it yielded before and now it is resumed. This is useful in a situation where you need a sub-request to determine whether current answer is valid or not.

Writing layers

Warning

FIXME: this dev-docs section is outdated! Better see comments in files instead, for now.

The resolverlibrary leverages the processing API from the libknot to separate packet processing code into layers.

Note

This is only crash-course in the library internals, see the resolverlibrary documentation for the complete overview of the services.

The library offers following services:

  • Cache - MVCC cache interface for retrieving/storing resource records.
  • Resolution plan - Query resolution plan, a list of partial queries (with hierarchy) sent in order to satisfy original query. This contains information about the queries, nameserver choice, timing information, answer and its class.
  • Nameservers - Reputation database of nameservers, this serves as an aid for nameserver choice.

A processing layer is going to be called by the query resolution driver for each query,so you’re going to work withstruct kr_request as your per-query context.This structure contains pointers to resolution context, resolution plan and also the final answer.

intconsume(kr_layer_t*ctx,knot_pkt_t*pkt){structkr_request*req=ctx->req;structkr_query*qry=req->current_query;}

This is only passive processing of the incoming answer. If you want to change the course of resolution, say satisfy a query from a local cache before the library issues a query to the nameserver, you can use states (see theStatic hints for example).

intproduce(kr_layer_t*ctx,knot_pkt_t*pkt){structkr_request*req=ctx->req;structkr_query*qry=req->current_query;/* Query can be satisfied locally. */if(can_satisfy(qry)){/* This flag makes the resolver move the query                 * to the "resolved" list. */qry->flags.RESOLVED=true;returnKR_STATE_DONE;}/* Pass-through. */returnctx->state;}

It is possible to not only act during the query resolution, but also to view the complete resolution plan afterwards. This is useful for analysis-type tasks, or“per answer” hooks.

intfinish(kr_layer_t*ctx){structkr_request*req=ctx->req;structkr_rplan*rplan=req->rplan;/* Print the query sequence with start time. */charqname_str[KNOT_DNAME_MAXLEN];structkr_query*qry=NULLWALK_LIST(qry,rplan->resolved){knot_dname_to_str(qname_str,qry->sname,sizeof(qname_str));printf("%s at %u\n",qname_str,qry->timestamp);}returnctx->state;}

APIs in Lua

The APIs in Lua world try to mirror the C APIs using LuaJIT FFI, with several differences and enhancements.There is not comprehensive guide on the API yet, but you can have a look at thebindings file.

Elementary types and constants

  • States are directly inkres table, e.g.kres.YIELD,kres.CONSUME,kres.PRODUCE,kres.DONE,kres.FAIL.
  • DNS classes are inkres.class table, e.g.kres.class.IN for Internet class.
  • DNS types are inkres.type table, e.g.kres.type.AAAA for AAAA type.
  • DNS rcodes types are inkres.rcode table, e.g.kres.rcode.NOERROR.
  • Packet sections (QUESTION, ANSWER, AUTHORITY, ADDITIONAL) are in thekres.section table.

Working with domain names

The internal API usually works with domain names in label format, you can convert between text and wire freely.

localdname=kres.str2dname('business.se')localstrname=kres.dname2str(dname)

Working with resource records

Resource records are stored as tables.

localrr={owner=kres.str2dname('owner'),ttl=0,class=kres.class.IN,type=kres.type.CNAME,rdata=kres.str2dname('someplace')}print(kres.rr2str(rr))

RRSets in packet can be accessed using FFI, you can easily fetch single records.

localrrset={...}localrr=rrset:get(0)-- Return first RRprint(kres.dname2str(rr:owner()))print(rr:ttl())print(kres.rr2str(rr))

Working with packets

Packet is the data structure that you’re going to see in layers very often. They consists of a header, and four sections: QUESTION, ANSWER, AUTHORITY, ADDITIONAL. The first section is special, as it contains the query name, type, and class; the rest of the sections contain RRSets.

First you need to convert it to a type known to FFI and check basic properties. Let’s start with a snippet of aconsume layer.

consume=function(state,req,pkt)print('rcode:',pkt:rcode())print('query:',kres.dname2str(pkt:qname()),pkt:qclass(),pkt:qtype())ifpkt:rcode()~=kres.rcode.NOERRORthenprint('error response')endend

You can enumerate records in the sections.

localrecords=pkt:section(kres.section.ANSWER)fori=1,#recordsdolocalrr=records[i]ifrr.type==kres.type.AAAAthenprint(kres.rr2str(rr))endend

Duringproduce orbegin, you might want to want to write to packet. Keep in mind that you have to write packet sections in sequence,e.g. you can’t write to ANSWER after writing AUTHORITY, it’s like stages where you can’t go back.

pkt:rcode(kres.rcode.NXDOMAIN)-- Clear answer and write QUESTIONpkt:recycle()pkt:question('\7blocked',kres.class.IN,kres.type.SOA)-- Start writing datapkt:begin(kres.section.ANSWER)-- Nothing in answerpkt:begin(kres.section.AUTHORITY)localsoa={owner='\7blocked',ttl=900,class=kres.class.IN,type=kres.type.SOA,rdata='...'}pkt:put(soa.owner,soa.ttl,soa.class,soa.type,soa.rdata)

Working with requests

The request holds information about currently processed query, enabled options, cache, and other extra data.You primarily need to retrieve currently processed query.

consume=function(state,req,pkt)print(req.options)print(req.state)-- Print information about current querylocalcurrent=req:current()print(kres.dname2str(current.owner))print(current.stype,current.sclass,current.id,current.flags)end

In layers that either begin or finalize, you can walk the list of resolved queries.

locallast=req:resolved()print(last.stype)

As described in the layers, you can not only retrieve information about current query, but also push new ones or pop old ones.

-- Push new querylocalqry=req:push(pkt:qname(),kres.type.SOA,kres.class.IN)qry.flags.AWAIT_CUT=true-- Pop the query, this will erase it from resolution planreq:pop(qry)

Significant Lua API changes

Incompatible changes since 3.0.0

In the mainkres.* lua binding, there was only change in struct knot_rrset_t:

  • constructor now accepts TTL as additional parameter (defaulting to zero)
  • add_rdata() doesn’t accept TTL anymore (and will throw an error if passed)

In case you used knot_* functions and structures bound to lua:

  • knot_dname_is_sub(a, b): knot_dname_in_bailiwick(a, b) > 0
  • knot_rdata_rdlen(): knot_rdataset_at().len
  • knot_rdata_data(): knot_rdataset_at().data
  • knot_rdata_array_size(): offsetof(struct knot_data_t, data) + knot_rdataset_at().len
  • struct knot_rdataset: field names were renamed to .count and .rdata
  • some functions got inlined from headers, but you can use their kr_* clones:kr_rrsig_sig_inception(), kr_rrsig_sig_expiration(), kr_rrsig_type_covered().Note that these functions now accept knot_rdata_t* instead of a pairknot_rdataset_t* and size_t - you can use knot_rdataset_at() for that.
  • knot_rrset_add_rdata() doesn’t take TTL parameter anymore
  • knot_rrset_init_empty() was inlined, but in lua you can use the constructor
  • knot_rrset_ttl() was inlined, but in lua you can use :ttl() method instead
  • knot_pkt_qname(), _qtype(), _qclass(), _rr(), _section() were inlined,but in lua you can use methods instead, e.g. myPacket:qname()
  • knot_pkt_free() takes knot_pkt_t* instead of knot_pkt_t**, but from luayou probably didn’t want to use that; constructor ensures garbage collection.

API reference

Name resolution

The API provides an API providing a “consumer-producer”-like interface to enable user to plug it into existing event loop or I/O code.

Example usage of the iterative API:

// Create request and its memory poolstructkr_requestreq={.pool={.ctx=mp_new(4096),.alloc=(mm_alloc_t)mp_alloc}};// Setup and provide input queryintstate=kr_resolve_begin(&req,ctx,final_answer);state=kr_resolve_consume(&req,query);// Generate answerwhile(state==KR_STATE_PRODUCE){// Additional query generate, do the I/O and pass back answerstate=kr_resolve_produce(&req,&addr,&type,query);while(state==KR_STATE_CONSUME){intret=sendrecv(addr,proto,query,resp);// If I/O fails, make "resp" emptystate=kr_resolve_consume(&request,addr,resp);knot_pkt_clear(resp);}knot_pkt_clear(query);}// "state" is either DONE or FAILkr_resolve_finish(&request,state);

Defines

kr_request_selected(req)

Initializer for an array of *_selected.

Enums

kr_rank

RRset rank - for cache and ranked_rr_*.

The rank meaning consists of one independent flag - KR_RANK_AUTH, and the rest have meaning of values where only one can hold at any time. You can use one of the enums as a safe initial value, optionally | KR_RANK_AUTH; otherwise it’s best to manipulate ranks via the kr_rank_* functions.

See also:

https://tools.ietf.org/html/rfc2181#section-5.4.1https://tools.ietf.org/html/rfc4035#section-4.3
Note
The representation is complicated by restrictions on integer comparison:
  • AUTH must be > than !AUTH
  • AUTH INSECURE must be > than AUTH (because it attempted validation)
  • !AUTH SECURE must be > than AUTH (because it’s valid)

Values:

0

Did not attempt to validate.

It’s assumed compulsory to validate (or prove insecure).

KR_RANK_OMIT

Do not attempt to validate.

(And don’t consider it a validation failure.)

KR_RANK_TRY

Attempt to validate, but failures are non-fatal.

4

Unable to determine whether it should be secure.

KR_RANK_BOGUS

Ought to be secure but isn’t.

KR_RANK_MISMATCH
KR_RANK_MISSING

Unable to obtain a good signature.

8

Proven to be insecure, i.e.

we have a chain of trust from TAs that cryptographically denies the possibility of existence of a positive chain of trust from the TAs to the record.

16

Authoritative data flag; the chain of authority was “verified”.

Even if not set, only in-bailiwick stuff is acceptable, i.e. almost authoritative (example: mandatory glue and its NS RR).

32

Verified whole chain of trust from the closest TA.

Functions

boolkr_rank_check(uint8_t rank)

Check that a rank value is valid.

Meant for assertions.

static boolkr_rank_test(uint8_t rank, uint8_t kr_flag)

Test the presence of any flag/state in a rank, i.e.

including KR_RANK_AUTH.

static voidkr_rank_set(uint8_t * rank, uint8_t kr_flag)

Set the rank state.

The _AUTH flag is kept as it was.

KR_EXPORT intkr_resolve_begin(structkr_request * request, structkr_context * ctx, knot_pkt_t * answer)

Begin name resolution.

Note
Expects a request to have an initialized mempool, the “answer” packet will be kept during the resolution and will contain the final answer at the end.
Return
CONSUME (expecting query)
Parameters
  • request: request state with initialized mempool
  • ctx: resolution context
  • answer: allocated packet for final answer

KR_EXPORT intkr_resolve_consume(structkr_request * request, const struct sockaddr * src, knot_pkt_t * packet)

Consume input packet (may be either first query or answer to query originated fromkr_resolve_produce())

Note
If the I/O fails, provide an empty or NULL packet, this will make iterator recognize nameserver failure.
Return
any state
Parameters
  • request: request state (awaiting input)
  • src: [in] packet source address
  • packet: [in] input packet

KR_EXPORT intkr_resolve_produce(structkr_request * request, struct sockaddr ** dst, int * type, knot_pkt_t * packet)

Produce either next additional query or finish.

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.

Return
any state
Parameters
  • request: request state (in PRODUCE state)
  • dst: [out] possible address of the next nameserver
  • type: [out] possible used socket type (SOCK_STREAM, SOCK_DGRAM)
  • packet: [out] packet to be filled with additional query

KR_EXPORT intkr_resolve_checkout(structkr_request * request, const struct sockaddr * src, struct sockaddr * dst, int type, knot_pkt_t * packet)

Finalises the outbound query packet with the knowledge of the IP addresses.

Note
The function must be called before actual sending of the request packet.
Return
kr_ok() or error code
Parameters
  • request: request state (in PRODUCE state)
  • src: address from which the query is going to be sent
  • dst: address of the name server
  • type: used socket type (SOCK_STREAM, SOCK_DGRAM)
  • packet: [in,out] query packet to be finalised

KR_EXPORT intkr_resolve_finish(structkr_request * request, int state)

Finish resolution and commit results if the state is DONE.

Note
The structures will be deinitialized, but the assigned memory pool is not going to be destroyed, as it’s owned by caller.
Return
DONE
Parameters
  • request: request state
  • state: either DONE or FAIL state (to be assigned to request->state)

KR_EXPORTKR_PURE structkr_rplan*kr_resolve_plan(structkr_request * request)

Return resolution plan.

Return
pointer to rplan
Parameters
  • request: request state

KR_EXPORTKR_PURE knot_mm_t*kr_resolve_pool(structkr_request * request)

Return memory pool associated with request.

Return
mempool
Parameters
  • request: request state

structkr_context
#include <resolve.h>

Name resolution context.

Resolution context provides basic services like cache, configuration and options.

Note
This structure is persistent between name resolutions and may be shared between threads.

Public Members

structkr_qflagsoptions
knot_rrset_t*opt_rr
map_ttrust_anchors
map_tnegative_anchors
structkr_zonecutroot_hints
structkr_cachecache
kr_nsrep_rtt_lru_t*cache_rtt
unsignedcache_rtt_tout_retry_interval
kr_nsrep_lru_t*cache_rep
module_array_t*modules
struct kr_cookie_ctxcookie_ctx
kr_cookie_lru_t*cache_cookie
int32_ttls_padding

See net.tls_padding in ../daemon/README.rst -1 is “true” (default policy), 0 is “false” (no padding)

knot_mm_t*pool
structkr_request_qsource_flags

Public Members

boolkr_request_qsource_flags::tcp :1

true if the request is on TCP (or TLS); only meaningful if (dst_addr).

boolkr_request_qsource_flags::tls :1

true if the request is on TLS (or HTTPS); only meaningful if (dst_addr).

boolkr_request_qsource_flags::http :1

true if the request is on HTTP; only meaningful if (dst_addr).

structkr_request
#include <resolve.h>

Name resolution request.

Keeps information about current query processing between calls to processing APIs, i.e. current resolved query, resolution plan, … Use this instead of the simple interface if you want to implement multiplexing or custom I/O.

Note
All data for this request must be allocated from the given pool.

Public Members

structkr_context*ctx
knot_pkt_t*answer
structkr_query*current_query

Current evaluated query.

const struct sockaddr*addr

Address that originated the request.

Current upstream address.

NULL for internal origin.

const struct sockaddr*dst_addr

Address that accepted the request.

NULL for internal origin. Beware: in case of UDP on wildcard address it will be wildcard; closely related: issue #173.

const knot_pkt_t*packet
structkr_request_qsource_flagsflags

See definition above.

size_tsize

query packet size

structkr_request::@6qsource
unsignedrtt

Current upstream RTT.

structkr_request::@7upstream

Upstream information, valid only in consume() phase.

structkr_qflagsoptions
intstate
ranked_rr_array_tansw_selected
ranked_rr_array_tauth_selected
ranked_rr_array_tadd_selected
boolansw_validated

internal to validator; beware of caching, etc.

boolauth_validated

see answ_validated ^^ ; TODO

uint8_trank

Overall rank for the request.

Values from kr_rank, currently just KR_RANK_SECURE and _INITIAL. Only read this in finish phase and after validator, please. Meaning of _SECURE: all RRs in answer+authority are _SECURE, including any negative results implied (NXDOMAIN, NODATA).

structkr_rplanrplan
trace_log_ftrace_log

Logging tracepoint.

trace_callback_ftrace_finish

Request finish tracepoint.

intvars_ref

Reference to per-request variable table.

LUA_NOREF if not set.

knot_mm_tpool
unsigned intuid

Typedefs

typedefint32_t(* kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type, const structkr_query *qry)

Callback for serve-stale decisions.

Return
the adjusted TTL (typically 1) or < 0.
Parameters
  • ttl: the expired TTL (i.e. it’s < 0)

Functions

KR_EXPORT voidkr_qflags_set(structkr_qflags * fl1, structkr_qflags fl2)

Combine flags together.

This means set union for simple flags.

KR_EXPORT voidkr_qflags_clear(structkr_qflags * fl1, structkr_qflags fl2)

Remove flags.

This means set-theoretic difference.

KR_EXPORT intkr_rplan_init(structkr_rplan * rplan, structkr_request * request, knot_mm_t * pool)

Initialize resolution plan (empty).

Parameters
  • rplan: plan instance
  • request: resolution request
  • pool: ephemeral memory pool for whole resolution

KR_EXPORT voidkr_rplan_deinit(structkr_rplan * rplan)

Deinitialize resolution plan, aborting any uncommited transactions.

Parameters
  • rplan: plan instance

KR_EXPORTKR_PURE boolkr_rplan_empty(structkr_rplan * rplan)

Return true if the resolution plan is empty (i.e.

finished or initialized)

Return
true or false
Parameters
  • rplan: plan instance

KR_EXPORT structkr_query*kr_rplan_push_empty(structkr_rplan * rplan, structkr_query * parent)

Push empty query to the top of the resolution plan.

Note
This query serves as a cookie query only.
Return
query instance or NULL
Parameters
  • rplan: plan instance
  • parent: query parent (or NULL)

KR_EXPORT structkr_query*kr_rplan_push(structkr_rplan * rplan, structkr_query * parent, const knot_dname_t * name, uint16_t cls, uint16_t type)

Push a query to the top of the resolution plan.

Note
This means that this query takes precedence before all pending queries.
Return
query instance or NULL
Parameters
  • rplan: plan instance
  • parent: query parent (or NULL)
  • name: resolved name
  • cls: resolved class
  • type: resolved type

KR_EXPORT intkr_rplan_pop(structkr_rplan * rplan, structkr_query * qry)

Pop existing query from the resolution plan.

Note
Popped queries are not discarded, but moved to the resolved list.
Return
0 or an error
Parameters
  • rplan: plan instance
  • qry: resolved query

KR_EXPORTKR_PURE boolkr_rplan_satisfies(structkr_query * closure, const knot_dname_t * name, uint16_t cls, uint16_t type)

Return true if resolution chain satisfies given query.

KR_EXPORTKR_PURE structkr_query*kr_rplan_resolved(structkr_rplan * rplan)

Return last resolved query.

KR_EXPORTKR_PURE structkr_query*kr_rplan_last(structkr_rplan * rplan)

Return last query (either currently being solved or last resolved).

This is necessary to retrieve the last query in case of resolution failures (e.g. time limit reached).

KR_EXPORTKR_PURE structkr_query*kr_rplan_find_resolved(structkr_rplan * rplan, structkr_query * parent, const knot_dname_t * name, uint16_t cls, uint16_t type)

Check if a given query already resolved.

Return
query instance or NULL
Parameters
  • rplan: plan instance
  • parent: query parent (or NULL)
  • name: resolved name
  • cls: resolved class
  • type: resolved type

structkr_qflags
#include <rplan.h>

Query flags.

Public Members

boolkr_qflags::NO_MINIMIZE :1

Don’t minimize QNAME.

boolkr_qflags::NO_THROTTLE :1

No query/slow NS throttling.

boolkr_qflags::NO_IPV6 :1

Disable IPv6.

boolkr_qflags::NO_IPV4 :1

Disable IPv4.

boolkr_qflags::TCP :1

Use TCP for this query.

boolkr_qflags::RESOLVED :1

Query is resolved.

Note thatkr_query gets RESOLVED before following a CNAME chain; see .CNAME.

boolkr_qflags::AWAIT_IPV4 :1

Query is waiting for A address.

boolkr_qflags::AWAIT_IPV6 :1

Query is waiting for AAAA address.

boolkr_qflags::AWAIT_CUT :1

Query is waiting for zone cut lookup.

boolkr_qflags::SAFEMODE :1

Don’t use fancy stuff (EDNS, 0x20, …)

boolkr_qflags::CACHED :1

Query response is cached.

boolkr_qflags::NO_CACHE :1

No cache for lookup; exception: finding NSs and subqueries.

boolkr_qflags::EXPIRING :1

Query response is cached, but expiring.

boolkr_qflags::ALLOW_LOCAL :1

Allow queries to local or private address ranges.

boolkr_qflags::DNSSEC_WANT :1

Want DNSSEC secured answer; exception: +cd, i.e.

knot_wire_set_cd(request->answer->wire).

boolkr_qflags::DNSSEC_BOGUS :1

Query response is DNSSEC bogus.

boolkr_qflags::DNSSEC_INSECURE :1

Query response is DNSSEC insecure.

boolkr_qflags::DNSSEC_CD :1

Instruction to set CD bit in request.

boolkr_qflags::STUB :1

Stub resolution, accept received answer as solved.

boolkr_qflags::ALWAYS_CUT :1

Always recover zone cut (even if cached).

boolkr_qflags::DNSSEC_WEXPAND :1

Query response has wildcard expansion.

boolkr_qflags::PERMISSIVE :1

Permissive resolver mode.

boolkr_qflags::STRICT :1

Strict resolver mode.

boolkr_qflags::BADCOOKIE_AGAIN :1

Query again because bad cookie returned.

boolkr_qflags::CNAME :1

Query response contains CNAME in answer section.

boolkr_qflags::REORDER_RR :1

Reorder cached RRs.

boolkr_qflags::TRACE :1

Also log answers if verbose.

boolkr_qflags::NO_0X20 :1

Disable query case randomization .

boolkr_qflags::DNSSEC_NODS :1

DS non-existance is proven.

boolkr_qflags::DNSSEC_OPTOUT :1

Closest encloser proof has optout.

boolkr_qflags::NONAUTH :1

Non-authoritative in-bailiwick records are enough.

TODO: utilize this also outside cache.

boolkr_qflags::FORWARD :1

Forward all queries to upstream; validate answers.

boolkr_qflags::DNS64_MARK :1

Internal mark for dns64 module.

boolkr_qflags::CACHE_TRIED :1

Internal to cache module.

boolkr_qflags::NO_NS_FOUND :1

No valid NS found during last PRODUCE stage.

boolkr_qflags::PKT_IS_SANE :1

Set by iterator in consume phase to indicate whether some basic aspects of the packet are OK, e.g.

QNAME.

structkr_query
#include <rplan.h>

Single query representation.

Public Members

structkr_query*parent
knot_dname_t*sname

The name to resolve - lower-cased, uncompressed.

uint16_tstype
uint16_tsclass
uint16_tid
uint16_treorder

Seed to reorder (cached) RRs in answer or zero.

structkr_qflags flagsforward_flags
uint32_tsecret
uint32_tuid

Query iteration number, unique within thekr_rplan.

uint64_tcreation_time_mono
uint64_ttimestamp_mono

Time of query created or time of query to upstream resolver (milliseconds).

struct timevaltimestamp

Real time for TTL+DNSSEC checks (.tv_sec only).

structkr_zonecutzone_cut
structkr_layer_pickle*deferred
int8_tcname_depth

Current xNAME depth, set by iterator.

0 = uninitialized, 1 = no CNAME, … See also KR_CNAME_CHAIN_LIMIT.

structkr_query*cname_parent

Pointer to the query that originated this one because of following a CNAME (or NULL).

structkr_request*request

Parent resolution request.

kr_stale_cbstale_cb

See the type.

structkr_nsrepns
structkr_rplan
#include <rplan.h>

Query resolution plan structure.

The structure most importantly holds the original query, answer and the list of pending queries required to resolve the original query. It also keeps a notion of current zone cut.

Public Members

kr_qarray_tpending

List of pending queries.

Beware: order is significant ATM, as the last is the next one to solve, and they may be inter-dependent.

kr_qarray_tresolved

List of resolved queries.

structkr_request*request

Parent resolution request.

knot_mm_t*pool

Temporary memory pool.

uint32_tnext_uid

Next value forkr_query::uid (incremental).

Cache

Functions

intcache_peek(kr_layer_t * ctx, knot_pkt_t * pkt)
intcache_stash(kr_layer_t * ctx, knot_pkt_t * pkt)
KR_EXPORT intkr_cache_open(structkr_cache * cache, const struct kr_cdb_api * api, struct kr_cdb_opts * opts, knot_mm_t * mm)

Open/create cache with provided storage options.

Return
0 or an error code
Parameters
  • cache: cache structure to be initialized
  • api: storage engine API
  • opts: storage-specific options (may be NULL for default)
  • mm: memory context.

KR_EXPORT voidkr_cache_close(structkr_cache * cache)

Close persistent cache.

Note
This doesn’t clear the data, just closes the connection to the database.
Parameters
  • cache: structure

KR_EXPORT intkr_cache_commit(structkr_cache * cache)

Run after a row of operations to release transaction/lock if needed.

static boolkr_cache_is_open(structkr_cache * cache)

Return true if cache is open and enabled.

static voidkr_cache_make_checkpoint(structkr_cache * cache)

(Re)set the time pair to the current values.

KR_EXPORT intkr_cache_insert_rr(structkr_cache * cache, const knot_rrset_t * rr, const knot_rrset_t * rrsig, uint8_t rank,uint32_t timestamp)

Insert RRSet into cache, replacing any existing data.

Return
0 or an errcode
Parameters
  • cache: cache structure
  • rr: inserted RRSet
  • rrsig: RRSIG for inserted RRSet (optional)
  • rank: rank of the data
  • timestamp: current time

KR_EXPORT intkr_cache_clear(structkr_cache * cache)

Clear all items from the cache.

Return
0 or an errcode
Parameters
  • cache: cache structure

KR_EXPORT intkr_cache_peek_exact(structkr_cache * cache, const knot_dname_t * name, uint16_t type, structkr_cache_p * peek)
KR_EXPORT int32_tkr_cache_ttl(const structkr_cache_p * peek, const structkr_query * qry, const knot_dname_t * name, uint16_t type)
KR_EXPORT intkr_cache_materialize(knot_rdataset_t * dst, const structkr_cache_p * ref, knot_mm_t * pool)
KR_EXPORT intkr_cache_remove(structkr_cache * cache, const knot_dname_t * name, uint16_t type)

Remove an entry from cache.

Return
number of deleted records, or negative error code
Note
only “exact hits” are considered ATM, and some other information may be removed alongside.
Parameters
  • cache: cache structure
  • name: dname
  • type: rr type

KR_EXPORT intkr_cache_match(structkr_cache * cache, const knot_dname_t * name, bool exact_name, knot_db_val_t keyval[][2], int maxcount)

Get keys matching a dname lf prefix.

Return
result count or an errcode
Note
the cache keys are matched by prefix, i.e. it very much depends on their structure; CACHE_KEY_DEF.
Parameters
  • cache: cache structure
  • name: dname
  • exact_name: whether to only consider exact name matches
  • keyval: matched key-value pairs
  • maxcount: limit on the number of returned key-value pairs

KR_EXPORT intkr_cache_remove_subtree(structkr_cache * cache, const knot_dname_t * name, bool exact_name, int maxcount)

Remove a subtree in cache.

It’s like _match but removing them instead of returning.

Return
number of deleted entries or an errcode

KR_EXPORT intkr_cache_closest_apex(structkr_cache * cache, const knot_dname_t * name, bool is_DS, knot_dname_t ** apex)

Find the closest cached zone apex for a name (in cache).

Return
the number of labels to remove from the name, or negative error code
Note
timestamp is found by a syscall, and stale-serving is not considered
Parameters
  • is_DS: start searching one name higher

KR_EXPORT intkr_unpack_cache_key(knot_db_val_t key, knot_dname_t * buf, uint16_t * type)

Unpack dname and type from db key.

Return
length of dname or an errcode
Note
only “exact hits” are considered ATM, moreover xNAME records are “hidden” as NS. (see comments in struct entry_h)
Parameters
  • key: db key representation
  • buf: output buffer of domain name in dname format
  • type: output for type

Variables

const size_t PKT_SIZE_NOWIRE = -1

When knot_pkt is passed from cache without ->wire, this is the ->size.

KR_EXPORT const char*kr_cache_emergency_file_to_remove

Path to cache file to remove on critical out-of-space error.

(do NOT modify it)

structkr_cache
#include <api.h>

Cache structure, keeps API, instance and metadata.

Public Members

knot_db_t*db

Storage instance.

const struct kr_cdb_api*api

Storage engine.

struct kr_cdb_statsstats
uint32_tttl_min
uint32_tttl_max

TTL limits.

struct timevalcheckpoint_walltime

Wall time on the last check-point.

uint64_tcheckpoint_monotime

Monotonic milliseconds on the last check-point.

structkr_cache_p

Public Members

uint32_ttime

The time of inception.

uint32_tttl

TTL at inception moment.

Assuming it fits into int32_t ATM.

uint8_trank

See enum kr_rank.

void*raw_data
void *raw_bound
structkr_cache_p::@0kr_cache_p::@1

Nameservers

Defines

KR_NS_DEAD

See kr_nsrep_update_rtt()

KR_NS_FWD_DEAD
KR_NS_TIMEOUT_RETRY_INTERVAL

If once NS was marked as “timeouted”, it won’t participate in NS elections at least KR_NS_TIMEOUT_RETRY_INTERVAL milliseconds (now: one second).

KR_NSREP_MAXADDR

Typedefs

typedefstructkr_nsrep_rtt_lru_entrykr_nsrep_rtt_lru_entry_t

Enums

kr_ns_score

NS RTT score (special values).

Note
RTT is measured in milliseconds.

Values:

KR_CONN_RTT_MAX
2
100
10
kr_ns_rep

NS QoS flags.

Values:

0

NS has no IPv4.

1

NS has no IPv6.

2

NS has no EDNS support.

kr_ns_update_mode

NS RTT update modes.

First update is always KR_NS_RESET unless KR_NS_UPDATE_NORESET mode had choosen.

Values:

0

Update as smooth over last two measurements.

KR_NS_UPDATE_NORESET

Same as KR_NS_UPDATE, but disable fallback to KR_NS_RESET on newly added entries.

Zero is used as initial value.

KR_NS_RESET

Set to given value.

KR_NS_ADD

Increment current value.

KR_NS_MAX

Set to maximum of current/proposed value.

Functions

typedeflru_t(kr_nsrep_rtt_lru_entry_t)

NS QoS tracking.

typedeflru_t(unsigned)

NS reputation tracking.

KR_EXPORT intkr_nsrep_set(structkr_query * qry, size_t index, const struct sockaddr * sock)

Set given NS address.

(Very low-level access to the list.)

Return
0 or an error code, in particular kr_error(ENOENT) for net.ipvX
Parameters
  • qry: updated query
  • index: index of the updated target
  • sock: socket address to use (sockaddr_in or sockaddr_in6 or NULL)

KR_EXPORT intkr_nsrep_elect(structkr_query * qry, structkr_context * ctx)

Elect best nameserver/address pair from the nsset.

Return
0 or an error code
Parameters
  • qry: updated query
  • ctx: resolution context

KR_EXPORT intkr_nsrep_elect_addr(structkr_query * qry, structkr_context * ctx)

Elect best nameserver/address pair from the nsset.

Return
0 or an error code
Parameters
  • qry: updated query
  • ctx: resolution context

KR_EXPORT intkr_nsrep_update_rtt(structkr_nsrep * ns, const struct sockaddr * addr, unsigned score, kr_nsrep_rtt_lru_t * cache, int umode)

Update NS address RTT information.

In KR_NS_UPDATE mode reputation is smoothed over last N measurements.

Return
0 on success, error code on failure
Parameters
  • ns: updated NS representation
  • addr: chosen address (NULL for first)
  • score: new score (i.e. RTT), see enum kr_ns_score
  • cache: RTT LRU cache
  • umode: update mode (KR_NS_UPDATE or KR_NS_RESET or KR_NS_ADD)

KR_EXPORT intkr_nsrep_update_rep(structkr_nsrep * ns, unsigned reputation, kr_nsrep_lru_t * cache)

Update NSSET reputation information.

Return
0 on success, error code on failure
Parameters
  • ns: updated NS representation
  • reputation: combined reputation flags, see enum kr_ns_rep
  • cache: LRU cache

intkr_nsrep_copy_set(structkr_nsrep * dst, const structkr_nsrep * src)

Copy NSSET reputation information and resets score.

Return
0 on success, error code on failure
Parameters
  • dst: updated NS representation
  • src: source NS representation

KR_EXPORT intkr_nsrep_sort(structkr_nsrep * ns, structkr_context * ctx)

Sort addresses in the query nsrep list by cached RTT.

if RTT is greater then KR_NS_TIMEOUT, address will placed at the beginning of the nsrep list once in cache.ns_tout() milliseconds. Otherwise it will be sorted as if it has cached RTT equal to KR_NS_MAX_SCORE + 1.

Return
0 or an error code
Note
ns reputation is zeroed and score is set to KR_NS_MAX_SCORE + 1.
Parameters
  • ns: updatedkr_nsrep
  • ctx: name resolution context.

structkr_nsrep_rtt_lru_entry

Public Members

unsignedscore
uint64_ttout_timestamp
structkr_nsrep
#include <nsrep.h>

Name server representation.

Contains extra information about the name server, e.g. score or other metadata.

Public Members

unsignedscore

NS score.

unsignedreputation

NS reputation.

const knot_dname_t*name

NS name.

structkr_context*ctx

Resolution context.

union inaddr kr_nsrep::addr[KR_NSREP_MAXADDR]

NS address(es)

Functions

KR_EXPORT intkr_zonecut_init(structkr_zonecut * cut, const knot_dname_t * name, knot_mm_t * pool)

Populate root zone cut with SBELT.

Return
0 or error code
Parameters
  • cut: zone cut
  • name:
  • pool:

KR_EXPORT voidkr_zonecut_deinit(structkr_zonecut * cut)

Clear the structure and free the address set.

Parameters
  • cut: zone cut

KR_EXPORT voidkr_zonecut_move(structkr_zonecut * to, const structkr_zonecut * from)

Move a zonecut, transferring ownership of any pointed-to memory.

Parameters
  • to: the target - it gets deinit-ed
  • from: the source - not modified, but shouldn’t be used afterward

KR_EXPORT voidkr_zonecut_set(structkr_zonecut * cut, const knot_dname_t * name)

Reset zone cut to given name and clear address list.

Note
This clears the address list even if the name doesn’t change. TA and DNSKEY don’t change.
Parameters
  • cut: zone cut to be set
  • name: new zone cut name

KR_EXPORT intkr_zonecut_copy(structkr_zonecut * dst, const structkr_zonecut * src)

Copy zone cut, including all data.

Does not copy keys and trust anchor.

Return
0 or an error code; If it fails with kr_error(ENOMEM), it may be in a half-filled state, but it’s safe to deinit…
Note
addresses for names insrc get replaced and others are left as they were.
Parameters
  • dst: destination zone cut
  • src: source zone cut

KR_EXPORT intkr_zonecut_copy_trust(structkr_zonecut * dst, const structkr_zonecut * src)

Copy zone trust anchor and keys.

Return
0 or an error code
Parameters
  • dst: destination zone cut
  • src: source zone cut

KR_EXPORT intkr_zonecut_add(structkr_zonecut * cut, const knot_dname_t * ns, const void * data, int len)

Add address record to the zone cut.

The record will be merged with existing data, it may be either A/AAAA type.

Return
0 or error code
Parameters
  • cut: zone cut to be populated
  • ns: nameserver name
  • data: typically knot_rdata_t::data
  • len: typically knot_rdata_t::len

KR_EXPORT intkr_zonecut_del(structkr_zonecut * cut, const knot_dname_t * ns, const void * data, int len)

Delete nameserver/address pair from the zone cut.

Return
0 or error code
Parameters
  • cut:
  • ns: name server name
  • data: typically knot_rdata_t::data
  • len: typically knot_rdata_t::len

KR_EXPORT intkr_zonecut_del_all(structkr_zonecut * cut, const knot_dname_t * ns)

Delete all addresses associated with the given name.

Return
0 or error code
Parameters
  • cut:
  • ns: name server name

KR_EXPORTKR_PURE pack_t*kr_zonecut_find(structkr_zonecut * cut, const knot_dname_t * ns)

Find nameserver address list in the zone cut.

Note
This can be used for membership test, a non-null pack is returned if the nameserver name exists.
Return
pack of addresses or NULL
Parameters
  • cut:
  • ns: name server name

KR_EXPORT intkr_zonecut_set_sbelt(structkr_context * ctx, structkr_zonecut * cut)

Populate zone cut with a root zone using SBELT :rfc:1034

Return
0 or error code
Parameters
  • ctx: resolution context (to fetch root hints)
  • cut: zone cut to be populated

KR_EXPORT intkr_zonecut_find_cached(structkr_context * ctx, structkr_zonecut * cut, const knot_dname_t * name, const structkr_query * qry, bool *restrict secured)

Populate zone cut address set from cache.

Return
0 or error code (ENOENT if it doesn’t find anything)
Parameters
  • ctx: resolution context (to fetch data from LRU caches)
  • cut: zone cut to be populated
  • name: QNAME to start finding zone cut for
  • qry: query for timestamp and stale-serving decisions
  • secured: set to true if want secured zone cut, will return false if it is provably insecure

KR_EXPORT boolkr_zonecut_is_empty(structkr_zonecut * cut)

Check if any address is present in the zone cut.

Return
true/false
Parameters
  • cut: zone cut to check

structkr_zonecut
#include <zonecut.h>

Current zone cut representation.

Public Members

knot_dname_t*name

Zone cut name.

knot_rrset_t*key

Zone cut DNSKEY.

knot_rrset_t*trust_anchor

Current trust anchor.

structkr_zonecut*parent

Parent zone cut.

trie_t*nsset

Map of nameserver => address_set (pack_t).

knot_mm_t*pool

Memory pool.

Modules

Module API definition and functions for (un)loading modules.

Defines

KR_MODULE_EXPORT(module)

Export module API version (place this at the end of your module).

Parameters
  • module: module name (e.g. policy)

KR_MODULE_API

Typedefs

typedefuint32_t() module_api_cb(void)
typedefchar*() kr_prop_cb(void *env, struct kr_module *self, const char *input)

Module property callback.

Input and output is passed via a JSON encoded in a string.

Return
a free-form JSON output (malloc-ated)
Note
see modules_create_table_for_c() implementation for details about the input/output conversion.
Parameters
  • env: pointer to the lua engine, i.e. struct engine *env (TODO: explicit type)
  • input: parameter (NULL if missing/nil on lua level)

typedefint(* kr_module_init_cb)(structkr_module *)

Functions

KR_EXPORT intkr_module_load(structkr_module * module, const char * name, const char * path)

Load a C module instance into memory.

And call its init().

Return
0 or an error
Parameters
  • module: module structure. Will be overwritten except for ->data on success.
  • name: module name
  • path: module search path

KR_EXPORT voidkr_module_unload(structkr_module * module)

Unload module instance.

Note
currently used even for lua modules
Parameters
  • module: module structure

KR_EXPORTkr_module_init_cbkr_module_get_embedded(const char * name)

Get embedded module’s init function by name (or NULL).

structkr_module
#include <module.h>

Module representation.

The five symbols (init, …) may be defined by the module as name_init(), etc; all are optional and missing symbols are represented as NULLs;

Public Members

char*name
intinit)(structkr_module *self)

Constructor.

Called after loading the module.

Return
error code. Lua modules: not populated, called via lua directly.

intdeinit)(structkr_module *self)

Destructor.

Called before unloading the module.

Return
error code.

intconfig)(structkr_module *self, const char *input)

Configure with encoded JSON (NULL if missing).

Return
error code. Lua modules: not used and not useful from C. When called from lua, input is JSON, like for kr_prop_cb.

constkr_layer_api_t*layer

Packet processing API specs.

May be NULL. See docs on that type. Owned by the module code.

const structkr_prop*props

List of properties.

May be NULL. Terminated by { NULL, NULL, NULL }. Lua modules: not used and not useful.

void*lib

dlopen() handle; RTLD_DEFAULT for embedded modules; NULL for lua modules.

void*data

Custom data context.

structkr_prop
#include <module.h>

Module property (named callable).

Public Members

kr_prop_cb*cb
const char*name
const char*info

Defines

QRVERBOSE(_query, _cls, ...)

Print a debug message related to resolution.

Parameters
  • _query: associatedkr_query, may be NULL
  • _cls: identifying string, typically of length exactly four (padded)
  • ...: printf-compatible list of parameters

Typedefs

typedefstructkr_layerkr_layer_t

Packet processing context.

typedefstructkr_layer_apikr_layer_api_t

Enums

kr_layer_state

Layer processing states.

Only one value at a time (but see TODO).

Each state represents the state machine transition, and determines readiness for the next action. See structkr_layer_api for the actions.

TODO: the cookie module sometimes sets (_FAIL | _DONE) on purpose (!)

Values:

0

Consume data.

1

Produce data.

2

Finished successfully or a special case: in CONSUME phase this can be used (by iterator) to do a transition to PRODUCE phase again, in which case the packet wasn’t accepted for some reason.

3

Error.

4

Paused, waiting for a sub-query.

Functions

static boolkr_state_consistent(enumkr_layer_state s)

Check that a kr_layer_state makes sense.

We’re not very strict ATM.

structkr_layer
#include <layer.h>

Packet processing context.

Public Members

intstate

The current state; bitmap of enum kr_layer_state.

structkr_request*req

The corresponding request.

const structkr_layer_api*api
knot_pkt_t*pkt

In glue for luakr_layer_api it’s used to pass the parameter.

struct sockaddr*dst

In glue for checkout layer it’s used to pass the parameter.

boolis_stream

In glue for checkout layer it’s used to pass the parameter.

structkr_layer_api
#include <layer.h>

Packet processing module API.

All functions return the new kr_layer_state.

Lua modules are allowed to return nil/nothing, meaning the state shall not change.

Public Members

intbegin)(kr_layer_t *ctx)

Start of processing the DNS request.

intreset)(kr_layer_t *ctx)
intfinish)(kr_layer_t *ctx)

Paired to begin, called both on successes and failures.

intconsume)(kr_layer_t *ctx, knot_pkt_t *pkt)

Process an answer from upstream or from cache.

Lua API: call is omitted iff (state & KR_STATE_FAIL).

intproduce)(kr_layer_t *ctx, knot_pkt_t *pkt)

Produce either an answer to the request or a query for upstream (or fail).

Lua API: call is omitted iff (state & KR_STATE_FAIL).

intcheckout)(kr_layer_t *ctx, knot_pkt_t *packet, struct sockaddr *dst, int type)

Finalises the outbound query packet with the knowledge of the IP addresses.

The checkout layer doesn’t persist the state, so canceled subrequests don’t affect the resolution or rest of the processing. Lua API: call is omitted iff (state & KR_STATE_FAIL).

intanswer_finalize)(kr_layer_t *ctx)

Finalises the answer.

Last chance to affect what will get into the answer, including EDNS.

void*data

The C module can store anything in here.

int kr_layer_api::cb_slots[]

Internal to .

/daemon/ffimodule.c.

structkr_layer_pickle
#include <layer.h>

Pickled layer state (api, input, state).

Public Members

structkr_layer_pickle*next
const structkr_layer_api*api
knot_pkt_t*pkt
unsignedstate

Utilities

Defines

kr_log_info
kr_log_error(...)
kr_log_deprecate(...)
kr_log_trace_enabled(query)

Return true if the query has request log handler installed.

VERBOSE_STATUS

Block run in verbose mode; optimized when not run.

WITH_VERBOSE(query)
kr_log_verbose
KR_DNAME_GET_STR(dname_str, dname)
KR_RRTYPE_GET_STR(rrtype_str, rrtype)
static_assert(cond, msg)
KR_RRKEY_LEN
SWAP(x, y)

Swap two places.

Note: the parameters need to be without side effects.

Typedefs

typedefvoid(* trace_callback_f)(structkr_request *request)

Callback for request events.

typedefvoid(* trace_log_f)(const structkr_query *query, const char *source, const char *msg)

Callback for request logging handler.

Functions

KR_EXPORT boolkr_verbose_set(bool status)

Set verbose mode.

Not available if compiled with -DNOVERBOSELOG.

KR_EXPORTKR_PRINTF(1)

Log a message if in verbose mode.

KR_EXPORTKR_PRINTF(3)

Utility for QRVERBOSE - use that instead.

Log a message through the request log handler.

Return
true if the message was logged
Parameters
  • query: current query
  • source: message source
  • fmt: message format

static intstrcmp_p(const void * p1, const void * p2)

A strcmp() variant directly usable for qsort() on an array of strings.

static longtime_diff(struct timeval * begin, struct timeval * end)

Return time difference in miliseconds.

Note
based on the _BSD_SOURCE timersub() macro

static voidget_workdir(char * out, size_t len)

Get current working directory with fallback value.

KR_EXPORT char*kr_strcatdup(unsigned n, ...)

Concatenate N strings.

KR_EXPORT voidkr_rnd_buffered(void * data, unsigned int size)

You probably want kr_rand_* convenience functions instead.

This is a buffered version of gnutls_rnd(GNUTLS_RND_NONCE, ..)

static uint64_tkr_rand_bytes(unsigned int size)

Return a few random bytes.

static boolkr_rand_coin(unsigned int nomin, unsigned int denomin)

Throw a pseudo-random coin, succeeding approximately with probability nomin/denomin.

  • low precision, only one byte of randomness (or none with extreme parameters)
  • tip: use !kr_rand_coin() to get the complementary probability

KR_EXPORT intkr_memreserve(void * baton, char ** mem, size_t elm_size, size_t want, size_t * have)

Memory reservation routine for knot_mm_t.

KR_EXPORT intkr_pkt_recycle(knot_pkt_t * pkt)
KR_EXPORT intkr_pkt_clear_payload(knot_pkt_t * pkt)
KR_EXPORT intkr_pkt_put(knot_pkt_t * pkt, const knot_dname_t * name,uint32_t ttl, uint16_t rclass, uint16_t rtype, const uint8_t * rdata, uint16_t rdlen)

Construct and put record to packet.

KR_EXPORT voidkr_pkt_make_auth_header(knot_pkt_t * pkt)

Set packet header suitable for authoritative answer.

(for policy module)

KR_EXPORTKR_PURE const char*kr_inaddr(const struct sockaddr * addr)

Address bytes for given family.

KR_EXPORTKR_PURE intkr_inaddr_family(const struct sockaddr * addr)

Address family.

KR_EXPORTKR_PURE intkr_inaddr_len(const struct sockaddr * addr)

Address length for given family, i.e.

sizeof(struct in*_addr).

KR_EXPORTKR_PURE intkr_sockaddr_len(const struct sockaddr * addr)

Sockaddr length for given family, i.e.

sizeof(struct sockaddr_in*).

KR_EXPORTKR_PURE intkr_sockaddr_cmp(const struct sockaddr * left, const struct sockaddr * right)

Compare two given sockaddr.

return 0 - addresses are equal, error code otherwise.

KR_EXPORTKR_PURE uint16_tkr_inaddr_port(const struct sockaddr * addr)

Port.

KR_EXPORT voidkr_inaddr_set_port(struct sockaddr * addr, uint16_t port)

Set port.

KR_EXPORT intkr_inaddr_str(const struct sockaddr * addr, char * buf, size_t * buflen)

Write string representation for given address as “<addr>#<port>”.

Parameters
  • [in]addr: the raw address
  • [out]buf: the buffer for output string
  • [inout]buflen: the available(in) and utilized(out) length, including \0

KR_EXPORT intkr_ntop_str(int family, const void * src, uint16_t port, char * buf, size_t * buflen)

Write string representation for given address as “<addr>#<port>”.

It’s the same as kr_inaddr_str(), but the input address is input in native format like for inet_ntop() (4 or 16 bytes) and port must be separate parameter.

static char*kr_straddr(const struct sockaddr * addr)
KR_EXPORTKR_PURE intkr_straddr_family(const char * addr)

Return address type for string.

KR_EXPORTKR_CONST intkr_family_len(int family)

Return address length in given family (struct in*_addr).

KR_EXPORT struct sockaddr*kr_straddr_socket(const char * addr, int port, knot_mm_t * pool)

Create a sockaddr* from string+port representation.

Also accepts IPv6 link-local and AF_UNIX starting with “/” (ignoring port)

KR_EXPORT intkr_straddr_subnet(void * dst, const char * addr)

Parse address and return subnet length (bits).

Warning
’dst’ must be at leastsizeof(structin6_addr) long.

KR_EXPORT intkr_straddr_split(const char * instr, char ipaddr[static restrict(INET6_ADDRSTRLEN+1)], uint16_t * port)

Splits ip address specified as “addr@port” or “addr#port” into addr and port.

Return
error code
Note
Typically you follow this by kr_straddr_socket().
Note
Only internet addresses are supported, i.e. no AF_UNIX sockets.
Parameters
  • instr[in]: zero-terminated input, e.g. “192.0.2.1#12345\0”
  • ipaddr[out]: working buffer for the port-less prefix of instr; length >= INET6_ADDRSTRLEN + 1.
  • port[out]: written in case it’s specified in instr

KR_EXPORT intkr_straddr_join(const char * addr, uint16_t port, char * buf, size_t * buflen)

Formats ip address and port in “addr#port” format.

and performs validation.

Note
Port always formatted as five-character string with leading zeros.
Return
kr_error(EINVAL) - addr or buf is NULL or buflen is 0 or addr doesn’t contain a valid ip address kr_error(ENOSP) - buflen is too small

KR_EXPORTKR_PURE intkr_bitcmp(const char * a, const char * b, int bits)

Compare memory bitwise.

The semantics is “the same” as for memcmp(). The partial byte is considered with more-significant bits first, so this is e.g. suitable for comparing IP prefixes.

static uint8_tKEY_FLAG_RANK(const char * key)
static boolKEY_COVERING_RRSIG(const char * key)
KR_EXPORT intkr_rrkey(char * key, uint16_t class, const knot_dname_t * owner, uint16_t type, uint16_t additional)

Create unique null-terminated string key for RR.

Return
key length if successful or an error
Parameters
  • key: Destination buffer for key size, MUST be KR_RRKEY_LEN or larger.
  • class: RR class.
  • owner: RR owner name.
  • type: RR type.
  • additional: flags (for instance can be used for storing covered type when RR type is RRSIG).

KR_EXPORT intkr_ranked_rrarray_add(ranked_rr_array_t * array, const knot_rrset_t * rr, uint8_t rank, bool to_wire,uint32_t qry_uid, knot_mm_t * pool)

Add RRSet copy to a ranked RR array.

To convert to standard RRs inside, you need to call _finalize() afterwards, and the memory of rr->rrs.rdata has to remain until then.

KR_EXPORT intkr_ranked_rrarray_finalize(ranked_rr_array_t * array,uint32_t qry_uid, knot_mm_t * pool)

Finalize in_progress sets - all with matching qry_uid.

intkr_ranked_rrarray_set_wire(ranked_rr_array_t * array, bool to_wire,uint32_t qry_uid, bool check_dups, bool(*extraCheck)(const ranked_rr_array_entry_t *))
KR_EXPORT char*kr_pkt_text(const knot_pkt_t * pkt)

Return
Newly allocated string representation of packet. Caller has to free() returned string.

KR_PURE char*kr_rrset_text(const knot_rrset_t * rr)
staticKR_PURE char*kr_dname_text(const knot_dname_t * name)
staticKR_CONST char*kr_rrtype_text(const uint16_t rrtype)
KR_EXPORT char*kr_module_call(structkr_context * ctx, const char * module, const char * prop, const char * input)

Call module property.

static uint16_tkr_rrset_type_maysig(const knot_rrset_t * rr)

Return the (covered) type of an nonempty RRset.

KR_EXPORT uint64_tkr_now()

The current time in monotonic milliseconds.

Note
it may be outdated in case of long callbacks; see uv_now().

KR_EXPORT voidkr_uv_free_cb(uv_handle_t * handle)

Call free(handle->data); it’s useful e.g.

as a callback in uv_close().

intknot_dname_lf2wire(knot_dname_t * dst, uint8_t len, const uint8_t * lf)

Convert name from lookup format to wire.

See knot_dname_lf

Note
len bytes are read and len+1 are written withnormal LF, but it’s also allowed that the final zero byte is omitted in LF.
Return
the number of bytes written (>0) or error code (<0)

static intkr_dname_lf(uint8_t * dst, const knot_dname_t * src, bool add_wildcard)

Patched knot_dname_lf.

LF for “.” has length zero instead of one, for consistency. (TODO: consistency?)

Note
packet is always NULL
Parameters
  • add_wildcard: append the wildcard label

KR_EXPORT const char*kr_strptime_diff(const char * format, const char * time1_str, const char * time0_str, double * diff)

Difference between two calendar times specified as strings.

Parameters
  • format[in]: format for strptime
  • diff[out]: result from C difftime(time1, time0)

KR_EXPORT voidkr_rrset_init(knot_rrset_t * rrset, knot_dname_t * owner, uint16_t type, uint16_t rclass,uint32_t ttl)
KR_EXPORT uint16_tkr_pkt_has_dnssec(const knot_pkt_t * pkt)
KR_EXPORT uint16_tkr_pkt_qclass(const knot_pkt_t * pkt)
KR_EXPORT uint16_tkr_pkt_qtype(const knot_pkt_t * pkt)
KR_EXPORTuint32_tkr_rrsig_sig_inception(const knot_rdata_t * rdata)
KR_EXPORTuint32_tkr_rrsig_sig_expiration(const knot_rdata_t * rdata)
KR_EXPORT uint16_tkr_rrsig_type_covered(const knot_rdata_t * rdata)
KR_EXPORT time_tkr_file_mtime(const char * fname)
KR_EXPORT long longkr_fssize(const char * path)

Return filesystem size in bytes.

Variables

KR_EXPORT boolkr_verbose_status

Whether in verbose mode.

Only use this for reading.

KR_EXPORTKR_EXPORT const char*cls
KR_EXPORT const char const char *fmt
KR_EXPORT const char*source
const uint8_t KEY_FLAG_RRSIG =0x02
unioninaddr
#include <utils.h>

Simple storage for IPx address or AF_UNSPEC.

Public Members

struct sockaddrip
struct sockaddr_inip4
struct sockaddr_in6ip6

Defines

KR_EXPORT
KR_CONST
KR_PURE
KR_NORETURN
KR_COLD
KR_PRINTF(n)
uint
kr_ok
kr_strerror(x)

Typedefs

typedefunsigned intuint

Functions

static intKR_COLDkr_error(int x)

Generics library

This small collection of “generics” was born out of frustration that I couldn’t find nosuch thing for C. It’s either bloated, has poor interface, null-checking is absent ordoesn’t allow custom allocation scheme. BSD-licensed (or compatible) code is allowed here,as long as it comes with a test case intests/test_generics.c.

  • array - a set of simple macros to make working with dynamic arrays easier.
  • queue - a FIFO + LIFO queue.
  • map - aCrit-bit tree key-value map implementation (public domain) that comes with tests.
  • set - set abstraction implemented on top ofmap (unused now).
  • pack - length-prefixed list of objects (i.e. array-list).
  • lru - LRU-like hash table
  • trie - a trie-based key-value map, taken from knot-dns

array

A set of simple macros to make working with dynamic arrays easier.

MIN(array_push(arr,val),other)
Note
The C has no generics, so it is implemented mostly using macros. Be aware of that, as direct usage of the macros in the evaluating macros may lead to different expectations:

May evaluate the code twice, leading to unexpected behaviour. This is a price to pay for the absence of proper generics.

Example usage:

array_t(constchar*)arr;array_init(arr);// Reserve memory in advanceif(array_reserve(arr,2)<0){returnENOMEM;}// Already reserved, cannot failarray_push(arr,"princess");array_push(arr,"leia");// Not reserved, may failif(array_push(arr,"han")<0){returnENOMEM;}// It does not hide what it really isfor(size_ti=0;i<arr.len;++i){printf("%s\n",arr.at[i]);}// Random deletearray_del(arr,0);

Defines

array_t(type)

Declare an array structure.

array_init(array)

Zero-initialize the array.

array_clear(array)

Free and zero-initialize the array (plain malloc/free).

array_clear_mm(array, free, baton)

Make the array empty and free pointed-to memory.

Mempool usage: pass mm_free and a knot_mm_t* .

array_reserve(array, n)

Reserve capacity for at least n elements.

Return
0 if success, <0 on failure

array_reserve_mm(array, n, reserve, baton)

Reserve capacity for at least n elements.

Mempool usage: pass kr_memreserve and a knot_mm_t* .

Return
0 if success, <0 on failure

array_push_mm(array, val, reserve, baton)

Push value at the end of the array, resize it if necessary.

Mempool usage: pass kr_memreserve and a knot_mm_t* .

Note
May fail if the capacity is not reserved.
Return
element index on success, <0 on failure

array_push(array, val)

Push value at the end of the array, resize it if necessary (plain malloc/free).

Note
May fail if the capacity is not reserved.
Return
element index on success, <0 on failure

array_pop(array)

Pop value from the end of the array.

array_del(array, i)

Remove value at given index.

Return
0 on success, <0 on failure

array_tail(array)

Return last element of the array.

Warning
Undefined if the array is empty.

Functions

static size_tarray_next_count(size_t want)

Simplified Qt containers growth strategy.

static intarray_std_reserve(void * baton, char ** mem, size_t elm_size, size_t want, size_t * have)
static voidarray_std_free(void * baton, void * p)

queue

A queue, usable for FIFO and LIFO simultaneously.

Both the head and tail of the queue can be accessed and pushed to, but only the head can be popped from.

Example usage:

// define new queue type, and init a new queue instancetypedefqueue_t(int)queue_int_t;queue_int_tq;queue_init(q);// do some operationsqueue_push(q,1);queue_push(q,2);queue_push(q,3);queue_push(q,4);queue_pop(q);assert(queue_head(q)==2);assert(queue_tail(q)==4);// you may iteratetypedefqueue_it_t(int)queue_it_int_t;for(queue_it_int_tit=queue_it_begin(q);!queue_it_finished(it);queue_it_next(it)){++queue_it_val(it);}assert(queue_tail(q)==5);queue_push_head(q,0);++queue_tail(q);assert(queue_tail(q)==6);// free it upqueue_deinit(q);// you may use dynamic allocation for the type itselfqueue_int_t*qm=malloc(sizeof(queue_int_t));queue_init(*qm);queue_deinit(*qm);free(qm);
Note
The implementation uses a singly linked list of blocks where each block stores an array of values (for better efficiency).

Defines

queue_t(type)

The type for queue, parametrized by value type.

queue_init(q)

Initialize a queue.

You can malloc() it the usual way.

queue_deinit(q)

De-initialize a queue: make it invalid and free any inner allocations.

queue_push(q, data)

Push data to queue’s tail.

(Type-safe version; use _impl() otherwise.)

queue_push_head(q, data)

Push data to queue’s head.

(Type-safe version; use _impl() otherwise.)

queue_pop(q)

Remove the element at the head.

The queue must not be empty.

queue_head(q)

Return a “reference” to the element at the head (it’s an L-value).

The queue must not be empty.

queue_tail(q)

Return a “reference” to the element at the tail (it’s an L-value).

The queue must not be empty.

queue_len(q)

Return the number of elements in the queue (very efficient).

queue_it_t(type)

Type for queue iterator, parametrized by value type.

It’s a simple structure that owns no other resources. You may NOT use it after doing any push or pop (without _begin again).

queue_it_begin(q)

Initialize a queue iterator at the head of the queue.

If you use this in assignment (instead of initialization), you will unfortunately need to add corresponding type-cast in front. Beware: there’s no type-check between queue and iterator!

queue_it_val(it)

Return a “reference” to the current element (it’s an L-value) .

queue_it_finished(it)

Test if the iterator has gone past the last element.

If it has, you may not use _val or _next.

queue_it_next(it)

Advance the iterator to the next element.

map

A Crit-bit tree key-value map implementation.

Example usage:

Warning
If the user provides a custom allocator, it must return addresses aligned to 2B boundary.

map_tmap=map_make(NULL);// Custom allocator (optional)map.malloc=&mymalloc;map.baton=&mymalloc_context;// Insert k-v pairsintvalues={42,53,64};if(map_set(&map,"princess",&values[0])!=0||map_set(&map,"prince",&values[1])!=0||map_set(&map,"leia",&values[2])!=0){fail();}// Test membershipif(map_contains(&map,"leia")){success();}// Prefix searchinti=0;intcount(constchar*k,void*v,void*ext){(*(int*)ext)++;return0;}if(map_walk_prefixed(map,"princ",count,&i)==0){printf("%d matches\n",i);}// Deleteif(map_del(&map,"badkey")!=0){fail();// No such key}// Clear the mapmap_clear(&map);

Defines

map_walk(map, callback, baton)

Functions

staticmap_tmap_make(struct knot_mm * pool)

Creates an new empty critbit map.

Pass NULL for malloc+free.

intmap_contains(map_t * map, const char * str)

Returns non-zero if map contains str.

void*map_get(map_t * map, const char * str)

Returns value if map contains str.

Note: NULL may mean two different things.

intmap_set(map_t * map, const char * str, void * val)

Inserts str into map.

Returns 0 if new, 1 if replaced, or ENOMEM.

intmap_del(map_t * map, const char * str)

Deletes str from the map, returns 0 on suceess.

voidmap_clear(map_t * map)

Clears the given map.

intmap_walk_prefixed(map_t * map, const char * prefix, int(*callback)(const char *, void *, void *), void * baton)

Calls callback for all strings in map with the given prefix.

Returns value immediately if a callback returns nonzero.

Parameters
  • map:
  • prefix: required string prefix (empty => all strings)
  • callback: callback parameters are (key, value, baton)
  • baton: passed uservalue

structmap_t
#include <map.h>

Main data structure.

Public Members

void*root
struct knot_mm*pool

set

A set abstraction implemented on top of map.

Example usage:

Note
The API is based on map.h, see it for more examples.

set_tset=set_make(NULL);// Insert keysif(set_add(&set,"princess")!=0||set_add(&set,"prince")!=0||set_add(&set,"leia")!=0){fail();}// Test membershipif(set_contains(&set,"leia")){success();}// Prefix searchinti=0;intcount(constchar*s,void*n){(*(int*)n)++;return0;}if(set_walk_prefixed(set,"princ",count,&i)==0){printf("%d matches\n",i);}// Deleteif(set_del(&set,"badkey")!=0){fail();// No such key}// Clear the setset_clear(&set);

Defines

set_make

Creates an new, empty critbit set

set_contains(set, str)

Returns non-zero if set contains str

set_add(set, str)

Inserts str into set. Returns 0 if new, 1 if already present, or ENOMEM.

set_del(set, str)

Deletes str from the set, returns 0 on suceess

set_clear(set)

Clears the given set

set_walk(set, callback, baton)

Calls callback for all strings in map

set_walk_prefixed(set, prefix, callback, baton)

Calls callback for all strings in set with the given prefix

Typedefs

typedefmap_tset_t
typedefint() set_walk_cb(const char *, void *)

pack

A length-prefixed list of objects, also an array list.

Each object is prefixed by item length, unlike array this structure permits variable-length data. It is also equivallent to forward-only list backed by an array.

Example usage:

Note
Maximum object size is 2^16 bytes, seepack_objlen_t If some mistake happens somewhere, the access may end up in an infinite loop. (equality comparison on pointers)

pack_tpack;pack_init(pack);// Reserve 2 objects, 6 bytes totalpack_reserve(pack,2,4+2);// Push 2 objectspack_obj_push(pack,U8("jedi"),4)pack_obj_push(pack,U8("\xbe\xef"),2);// Iterate length-value pairsuint8_t*it=pack_head(pack);while(it!=pack_tail(pack)){uint8_t*val=pack_obj_val(it);it=pack_obj_next(it);}// Remove objectpack_obj_del(pack,U8("jedi"),4);pack_clear(pack);

Defines

pack_init(pack)

Zero-initialize the pack.

pack_clear(pack)

Make the pack empty and free pointed-to memory (plain malloc/free).

pack_clear_mm(pack, free, baton)

Make the pack empty and free pointed-to memory.

Mempool usage: pass mm_free and a knot_mm_t* .

pack_reserve(pack, objs_count, objs_len)

Reserve space foradditional objects in the pack (plain malloc/free).

Return
0 if success, <0 on failure

pack_reserve_mm(pack, objs_count, objs_len, reserve, baton)

Reserve space foradditional objects in the pack.

Mempool usage: pass kr_memreserve and a knot_mm_t* .

Return
0 if success, <0 on failure

pack_head(pack)

Return pointer to first packed object.

Recommended way to iterate: for (uint8_t *it =pack_head(pack); it !=pack_tail(pack); it = pack_obj_next(it))

pack_tail(pack)

Return pack end pointer.

Typedefs

typedefuint16_tpack_objlen_t

Packed object length type.

Functions

typedefarray_t(uint8_t)

Pack is defined as an array of bytes.

staticpack_objlen_tpack_obj_len(uint8_t * it)

Return packed object length.

static uint8_t*pack_obj_val(uint8_t * it)

Return packed object value.

static uint8_t*pack_obj_next(uint8_t * it)

Return pointer to next packed object.

static uint8_t*pack_last(pack_t pack)

Return pointer to the last packed object.

static intpack_obj_push(pack_t * pack, const uint8_t * obj,pack_objlen_t len)

Push object to the end of the pack.

Return
0 on success, negative number on failure

static uint8_t*pack_obj_find(pack_t * pack, const uint8_t * obj,pack_objlen_t len)

Returns a pointer to packed object.

Return
pointer to packed object or NULL

static intpack_obj_del(pack_t * pack, const uint8_t * obj,pack_objlen_t len)

Delete object from the pack.

Return
0 on success, negative number on failure

static intpack_clone(pack_t ** dst, const pack_t * src, knot_mm_t * pool)

Clone a pack, replacing destination pack; (*dst == NULL) is valid input.

Return
kr_error(ENOMEM) on allocation failure.

lru

A lossy cache.

Example usage:

// Define new LRU typetypedeflru_t(int)lru_int_t;// Create LRUlru_int_t*lru;lru_create(&lru,5,NULL,NULL);// Insert some valuesint*pi=lru_get_new(lru,"luke",strlen("luke"),NULL);if(pi)*pi=42;pi=lru_get_new(lru,"leia",strlen("leia"),NULL);if(pi)*pi=24;// Retrieve valuesint*ret=lru_get_try(lru,"luke",strlen("luke"),NULL);if(!ret)printf("luke dropped out!\n");elseprintf("luke's number is %d\n",*ret);char*enemies[]={"goro","raiden","subzero","scorpion"};for(inti=0;i<4;++i){int*val=lru_get_new(lru,enemies[i],strlen(enemies[i]),NULL);if(val)*val=i;}// We're donelru_free(lru);
Note
The implementation tries to keep frequent keys and avoid others, even if “used recently”, so it may refuse to store it onlru_get_new(). It uses hashing to split the problem pseudo-randomly into smaller groups, and within each it tries to approximate relative usage counts of several most frequent keys/hashes. This tracking is done formore keys than those that are actually stored.

Defines

lru_t(type)

The type for LRU, parametrized by value type.

lru_create(ptable, max_slots, mm_ctx_array, mm_ctx)

Allocate and initialize an LRU with default associativity.

The real limit on the number of slots can be a bit larger but less than double.

Note
The pointers to memory contexts need to remain valid during the whole life of the structure (or be NULL).
Parameters
  • ptable: pointer to a pointer to the LRU
  • max_slots: number of slots
  • mm_ctx_array: memory context to use for the huge array, NULL for default If you pass your own, it needs to produce CACHE_ALIGNED allocations (ubsan).
  • mm_ctx: memory context to use for individual key-value pairs, NULL for default

lru_free(table)

Free an LRU created by lru_create (it can be NULL).

lru_reset(table)

Reset an LRU to the empty state (but preserve any settings).

lru_get_try(table, key_, len_)

Find key in the LRU and return pointer to the corresponding value.

Return
pointer to data or NULL if not found
Parameters
  • table: pointer to LRU
  • key_: lookup key
  • len_: key length

lru_get_new(table, key_, len_, is_new)

Return pointer to value, inserting if needed (zeroed).

Return
pointer to data or NULL (can be even if memory could be allocated!)
Parameters
  • table: pointer to LRU
  • key_: lookup key
  • len_: key lengthkeys
  • is_new: pointer to bool to store result of operation (true if entry is newly added, false otherwise; can be NULL).

lru_apply(table, function, baton)

Apply a function to every item in LRU.

Parameters
  • table: pointer to LRU
  • function: enum lru_apply_do (*function)(const char *key, uint len, val_type *val, void *baton) See enum lru_apply_do for the return type meanings.
  • baton: extra pointer passed to each function invocation

lru_capacity(table)

Return the real capacity - maximum number of keys holdable within.

Parameters
  • table: pointer to LRU

Enums

lru_apply_do

Possible actions to do with an element.

Values:

LRU_APPLY_DO_NOTHING
LRU_APPLY_DO_EVICT

trie

Typedefs

typedefvoid*trie_val_t

Native API of QP-tries:

  • keys are char strings, not necessarily zero-terminated, the structure copies the contents of the passed keys
  • values are void* pointers, typically you get an ephemeral pointer to it
  • key lengths are limited by 2^32-1 ATM

XXX EDITORS: trie.{h,c} are synced fromhttps://gitlab.labs.nic.cz/knot/knot-dns/tree/68352fc969/src/contrib/qp-trie only with tiny adjustments, mostly #includes and KR_EXPORT.

Element value.

typedefstruct trietrie_t

Opaque structure holding a QP-trie.

typedefstruct trie_ittrie_it_t

Opaque type for holding a QP-trie iterator.

Functions

KR_EXPORTtrie_t*trie_create(knot_mm_t * mm)

Create a trie instance. Pass NULL to use malloc+free.

KR_EXPORT voidtrie_free(trie_t * tbl)

Free a trie instance.

KR_EXPORT voidtrie_clear(trie_t * tbl)

Clear a trie instance (make it empty).

KR_EXPORT size_ttrie_weight(consttrie_t * tbl)

Return the number of keys in the trie.

KR_EXPORTtrie_val_t*trie_get_try(trie_t * tbl, const char * key,uint32_t len)

Search the trie, returning NULL on failure.

KR_EXPORTtrie_val_t*trie_get_first(trie_t * tbl, char ** key,uint32_t * len)

Return pointer to the minimum. Optionally with key and its length.

KR_EXPORTtrie_val_t*trie_get_ins(trie_t * tbl, const char * key,uint32_t len)

Search the trie, inserting NULL trie_val_t on failure.

KR_EXPORT inttrie_get_leq(trie_t * tbl, const char * key,uint32_t len,trie_val_t ** val)

Search for less-or-equal element.

Return
KNOT_EOK for exact match, 1 for previous, KNOT_ENOENT for not-found, or KNOT_E*.
Parameters
  • tbl: Trie.
  • key: Searched key.
  • len: Key length.
  • val: Must be valid; it will be set to NULL if not found or errored.

KR_EXPORT inttrie_apply(trie_t * tbl, int(*f)(trie_val_t *, void *), void * d)

Apply a function to every trie_val_t, in order.

Return
First nonzero from f() or zero (i.e. KNOT_EOK).
Parameters
  • d: Parameter passed as the second argument to f().

KR_EXPORT inttrie_del(trie_t * tbl, const char * key,uint32_t len,trie_val_t * val)

Remove an item, returning KNOT_EOK if succeeded or KNOT_ENOENT if not found.

If val!=NULL and deletion succeeded, the deleted value is set.

KR_EXPORT inttrie_del_first(trie_t * tbl, char * key,uint32_t * len,trie_val_t * val)

Remove the first item, returning KNOT_EOK on success.

You may optionally get the key and/or value. The key is copied, so you need to pass sufficient len, otherwise kr_error(ENOSPC) is returned.

KR_EXPORTtrie_it_t*trie_it_begin(trie_t * tbl)

Create a new iterator pointing to the first element (if any).

KR_EXPORT voidtrie_it_next(trie_it_t * it)

Advance the iterator to the next element.

Iteration is in ascending lexicographical order. In particular, the empty string would be considered as the very first.

Note
You may not use this function if the trie’s key-set has been modified during the lifetime of the iterator (modifying values only is OK).

KR_EXPORT booltrie_it_finished(trie_it_t * it)

Test if the iterator has gone past the last element.

KR_EXPORT voidtrie_it_free(trie_it_t * it)

Free any resources of the iterator. It’s OK to call it on NULL.

KR_EXPORT const char*trie_it_key(trie_it_t * it, size_t * len)

Return pointer to the key of the current element.

Note
The optional len is uint32_t internally but size_t is better for our usage, as it is without an additional type conversion.

KR_EXPORTtrie_val_t*trie_it_val(trie_it_t * it)

Return pointer to the value of the current element (writable).