This file is indexed.

/usr/include/libkres/impl.h is in libkres-dev 2.1.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

/** @file
 * Header internal for cache implementation(s).
 * Only LMDB works for now.
 */
#pragma once

#include <stdbool.h>
#include <stdint.h>

#include <libknot/consts.h>
#include <libknot/db/db.h>
#include <libknot/dname.h>

#include "contrib/cleanup.h"
#include "lib/cache/cdb_api.h"
#include "lib/resolve.h"

/** Cache entry header
 *
 * 'E' entry (exact hit):
 *	- ktype == NS: multiple chained entry_h, based on has_* : 1 flags;
 *		TODO: NSEC3 chain descriptors (iff nsec3_cnt > 0)
 *	- is_packet: uint16_t length, otherwise opaque and handled by ./entry_pkt.c
 *	- otherwise RRset + its RRSIG set (possibly empty).
 * '1' entry (NSEC1)
 *	- contents is the same as for exact hit for NSEC
 *	- flags don't make sense there
 * */
struct entry_h {
	uint32_t time;	/**< The time of inception. */
	uint32_t ttl;	/**< TTL at inception moment.  Assuming it fits into int32_t ATM. */
	uint8_t  rank;	/**< See enum kr_rank */

	bool is_packet : 1;	/**< Negative-answer packet for insecure/bogus name. */

	unsigned nsec1_pos : 2;	/**< Only used for NS ktype. */
	unsigned nsec3_cnt : 2;	/**< Only used for NS ktype. */
	bool has_ns : 1;	/**< Only used for NS ktype. */
	bool has_cname : 1;	/**< Only used for NS ktype. */
	bool has_dname : 1;	/**< Only used for NS ktype. */
	bool has_optout : 1;	/**< Only for packets with NSEC3. */
	/* ENTRY_H_FLAGS */

	uint8_t data[];
};


/** Check basic consistency of entry_h for 'E' entries, not looking into ->data.
 * (for is_packet the length of data is checked)
 */
struct entry_h * entry_h_consistent(knot_db_val_t data, uint16_t type);


// TODO
#define KR_CACHE_KEY_MAXLEN (KNOT_DNAME_MAXLEN + 100)

struct key {
	const knot_dname_t *zname; /**< current zone name (points within qry->sname) */
	uint8_t zlf_len; /**< length of current zone's lookup format */

	/** Corresponding key type; e.g. NS for CNAME.
	 * Note: NSEC type is ambiguous (exact and range key). */
	uint16_t type;
	/** The key data start at buf+1, and buf[0] contains some length.
	 * For details see key_exact* and key_NSEC* functions. */
	uint8_t buf[KR_CACHE_KEY_MAXLEN];
};

static inline size_t key_nwz_off(const struct key *k)
{
	/* CACHE_KEY_DEF: zone name lf + 0 '1' + name within zone */
	return k->zlf_len + 2;
}

/** Finish constructing string key for for exact search.
 * It's assumed that kr_dname_lf(k->buf, owner, *) had been ran.
 */
knot_db_val_t key_exact_type_maypkt(struct key *k, uint16_t type);


/* entry_h chaining; implementation in ./entry_list.c */

/** There may be multiple entries within, so rewind `val` to the one we want.
 *
 * ATM there are multiple types only for the NS ktype - it also accommodates xNAMEs.
 * \note `val->len` represents the bound of the whole list, not of a single entry.
 * \note in case of ENOENT, `val` is still rewound to the beginning of the next entry.
 * \return error code
 */
int entry_h_seek(knot_db_val_t *val, uint16_t type);

/** Prepare space to insert an entry.
 *
 * Some checks are performed (rank, TTL), the current entry in cache is copied
 * with a hole ready for the new entry (old one of the same type is cut out).
 *
 * \param val_new_entry The only changing parameter; ->len is read, ->data written.
 * Beware: the entry_h in *val_new_entry->data is zeroed, and in some cases it has
 * some flags set - and in those cases you can't just overwrite those flags.
 * All flags except is_packet are sensitive in this way.
 * \return error code
 */
int entry_h_splice(
	knot_db_val_t *val_new_entry, uint8_t rank,
	const knot_db_val_t key, const uint16_t ktype, const uint16_t type,
	const knot_dname_t *owner/*log only*/,
	const struct kr_query *qry, struct kr_cache *cache);


/* Packet caching; implementation in ./entry_pkt.c */

/** Stash the packet into cache (if suitable, etc.) */
void stash_pkt(const knot_pkt_t *pkt, const struct kr_query *qry,
		const struct kr_request *req);

/** Try answering from packet cache, given an entry_h.
 *
 * This assumes the TTL is OK and entry_h_consistent, but it may still return error.
 * On success it handles all the rest, incl. qry->flags.
 */
int answer_from_pkt(kr_layer_t *ctx, knot_pkt_t *pkt, uint16_t type,
		const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl);


/** Record is expiring if it has less than 1% TTL (or less than 5s) */
static inline bool is_expiring(uint32_t orig_ttl, uint32_t new_ttl)
{
	int64_t nttl = new_ttl; /* avoid potential over/under-flow */
	return 100 * (nttl - 5) < orig_ttl;
}

/** Returns signed result so you can inspect how much stale the RR is.
 *
 * @param owner name for stale-serving decisions.  You may pass NULL to disable stale.
 * FIXME: NSEC uses zone name ATM.
 * @param type for stale-serving.
 */
int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
		    const knot_dname_t *owner, uint16_t type);

/* RRset (de)materialization; implementation in ./entry_rr.c */

/** Compute size of dematerialized rdataset.  NULL is accepted as empty set. */
static inline int rdataset_dematerialize_size(const knot_rdataset_t *rds)
{
	return 1/*sizeof(rr_count)*/ + (rds
		? knot_rdataset_size(rds) - 4 * rds->rr_count /*TTLs*/
		: 0);
}

/** Dematerialize a rdataset. */
int rdataset_dematerialize(const knot_rdataset_t *rds, void * restrict data);

/** Partially constructed answer when gathering RRsets from cache. */
struct answer {
	int rcode;	/**< PKT_NODATA, etc. */
	uint8_t nsec_v;	/**< 1 or 3 */
	knot_mm_t *mm;	/**< Allocator for rrsets */
	struct answer_rrset {
		ranked_rr_array_entry_t set;	/**< set+rank for the main data */
		knot_rdataset_t sig_rds;	/**< RRSIG data, if any */
	} rrsets[1+1+3]; /**< see AR_ANSWER and friends; only required records are filled */
};
enum {
	AR_ANSWER = 0,	/**< Positive answer record.  It might be wildcard-expanded. */
	AR_SOA, 	/**< SOA record. */
	AR_NSEC,	/**< NSEC* covering the SNAME. */
	AR_WILD,	/**< NSEC* covering or matching the source of synthesis. */
	AR_CPE, 	/**< NSEC3 matching the closest provable encloser. */
};

/** Materialize RRset + RRSIGs into ans->rrsets[id].
 * LATER(optim.): it's slightly wasteful that we allocate knot_rrset_t for the packet
 *
 * \return error code.  They are all bad conditions and "guarded" by assert.
 */
int entry2answer(struct answer *ans, int id,
		const struct entry_h *eh, const void *eh_bound,
		const knot_dname_t *owner, uint16_t type, uint32_t new_ttl);


/* Preparing knot_pkt_t for cache answer from RRs; implementation in ./knot_pkt.c */

/** Prepare answer packet to be filled by RRs (without RR data in wire). */
int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type);

/** Append RRset + its RRSIGs into the current section (*shallow* copy), with given rank.
 * \note it works with empty set as well (skipped)
 * \note pkt->wire is not updated in any way
 * \note KNOT_CLASS_IN is assumed
 */
int pkt_append(knot_pkt_t *pkt, const struct answer_rrset *rrset, uint8_t rank);


/* NSEC (1) stuff.  Implementation in ./nsec1.c */


/** Construct a string key for for NSEC (1) predecessor-search.
 * \param add_wildcard Act as if the name was extended by "*."
 * \note k->zlf_len is assumed to have been correctly set */
knot_db_val_t key_NSEC1(struct key *k, const knot_dname_t *name, bool add_wildcard);

/** Closest encloser check for NSEC (1).
 * To understand the interface, see the call point.
 * \param k	space to store key + input: zname and zlf_len
 * \return 0: success;  >0: try other (NSEC3);  <0: exit cache immediately. */
int nsec1_encloser(struct key *k, struct answer *ans,
		   const int sname_labels, int *clencl_labels,
		   knot_db_val_t *cover_low_kwz, knot_db_val_t *cover_hi_kwz,
		   const struct kr_query *qry, struct kr_cache *cache);

/** Source of synthesis (SS) check for NSEC (1).
 * To understand the interface, see the call point.
 * \return 0: continue; <0: exit cache immediately;
 * 	AR_SOA: skip to adding SOA (SS was covered or matched for NODATA). */
int nsec1_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
		    knot_db_val_t cover_low_kwz, knot_db_val_t cover_hi_kwz,
		    const struct kr_query *qry, struct kr_cache *cache);


#define VERBOSE_MSG(qry, fmt...) QRVERBOSE((qry), "cach",  fmt)



/** Shorthand for operations on cache backend */
#define cache_op(cache, op, ...) (cache)->api->op((cache)->db, ## __VA_ARGS__)