Bug Summary

File:build-scan/../src/resolve/resolved-dns-cache.c
Warning:line 270, column 17
Value stored to 'k' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name resolved-dns-cache.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-resolved.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I /usr/include/p11-kit-1 -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/resolve/resolved-dns-cache.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <net/if.h>
4
5#include "af-list.h"
6#include "alloc-util.h"
7#include "dns-domain.h"
8#include "resolved-dns-answer.h"
9#include "resolved-dns-cache.h"
10#include "resolved-dns-packet.h"
11#include "string-util.h"
12
13/* Never cache more than 4K entries. RFC 1536, Section 5 suggests to
14 * leave DNS caches unbounded, but that's crazy. */
15#define CACHE_MAX4096 4096
16
17/* We never keep any item longer than 2h in our cache */
18#define CACHE_TTL_MAX_USEC(2 * ((usec_t) (60ULL*((usec_t) (60ULL*((usec_t) 1000000ULL))
))))
(2 * USEC_PER_HOUR((usec_t) (60ULL*((usec_t) (60ULL*((usec_t) 1000000ULL))))))
19
20/* How long to cache strange rcodes, i.e. rcodes != SUCCESS and != NXDOMAIN (specifically: that's only SERVFAIL for
21 * now) */
22#define CACHE_TTL_STRANGE_RCODE_USEC(30 * ((usec_t) 1000000ULL)) (30 * USEC_PER_SEC((usec_t) 1000000ULL))
23
24typedef enum DnsCacheItemType DnsCacheItemType;
25typedef struct DnsCacheItem DnsCacheItem;
26
27enum DnsCacheItemType {
28 DNS_CACHE_POSITIVE,
29 DNS_CACHE_NODATA,
30 DNS_CACHE_NXDOMAIN,
31 DNS_CACHE_RCODE, /* "strange" RCODE (effective only SERVFAIL for now) */
32};
33
34struct DnsCacheItem {
35 DnsCacheItemType type;
36 DnsResourceKey *key;
37 DnsResourceRecord *rr;
38 int rcode;
39
40 usec_t until;
41 bool_Bool authenticated:1;
42 bool_Bool shared_owner:1;
43
44 int ifindex;
45 int owner_family;
46 union in_addr_union owner_address;
47
48 unsigned prioq_idx;
49 LIST_FIELDS(DnsCacheItem, by_key)DnsCacheItem *by_key_next, *by_key_prev;
50};
51
52static const char *dns_cache_item_type_to_string(DnsCacheItem *item) {
53 assert(item)do { if ((__builtin_expect(!!(!(item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("item"), "../src/resolve/resolved-dns-cache.c"
, 53, __PRETTY_FUNCTION__); } while (0)
;
54
55 switch (item->type) {
56
57 case DNS_CACHE_POSITIVE:
58 return "POSITIVE";
59
60 case DNS_CACHE_NODATA:
61 return "NODATA";
62
63 case DNS_CACHE_NXDOMAIN:
64 return "NXDOMAIN";
65
66 case DNS_CACHE_RCODE:
67 return dns_rcode_to_string(item->rcode);
68 }
69
70 return NULL((void*)0);
71}
72
73static void dns_cache_item_free(DnsCacheItem *i) {
74 if (!i)
75 return;
76
77 dns_resource_record_unref(i->rr);
78 dns_resource_key_unref(i->key);
79 free(i);
80}
81
82DEFINE_TRIVIAL_CLEANUP_FUNC(DnsCacheItem*, dns_cache_item_free)static inline void dns_cache_item_freep(DnsCacheItem* *p) { if
(*p) dns_cache_item_free(*p); }
;
83
84static void dns_cache_item_unlink_and_free(DnsCache *c, DnsCacheItem *i) {
85 DnsCacheItem *first;
86
87 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 87, __PRETTY_FUNCTION__); } while (0)
;
88
89 if (!i)
90 return;
91
92 first = hashmap_get(c->by_key, i->key);
93 LIST_REMOVE(by_key, first, i)do { typeof(*(first)) **_head = &(first), *_item = (i); do
{ if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-cache.c"
, 93, __PRETTY_FUNCTION__); } while (0); if (_item->by_key_next
) _item->by_key_next->by_key_prev = _item->by_key_prev
; if (_item->by_key_prev) _item->by_key_prev->by_key_next
= _item->by_key_next; else { do { if ((__builtin_expect(!
!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("*_head == _item"), "../src/resolve/resolved-dns-cache.c",
93, __PRETTY_FUNCTION__); } while (0); *_head = _item->by_key_next
; } _item->by_key_next = _item->by_key_prev = ((void*)0
); } while (0)
;
94
95 if (first)
96 assert_se(hashmap_replace(c->by_key, first->key, first) >= 0)do { if ((__builtin_expect(!!(!(hashmap_replace(c->by_key,
first->key, first) >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("hashmap_replace(c->by_key, first->key, first) >= 0"
), "../src/resolve/resolved-dns-cache.c", 96, __PRETTY_FUNCTION__
); } while (0)
;
97 else
98 hashmap_remove(c->by_key, i->key);
99
100 prioq_remove(c->by_expiry, i, &i->prioq_idx);
101
102 dns_cache_item_free(i);
103}
104
105static bool_Bool dns_cache_remove_by_rr(DnsCache *c, DnsResourceRecord *rr) {
106 DnsCacheItem *first, *i;
107 int r;
108
109 first = hashmap_get(c->by_key, rr->key);
110 LIST_FOREACH(by_key, i, first)for ((i) = (first); (i); (i) = (i)->by_key_next) {
111 r = dns_resource_record_equal(i->rr, rr);
112 if (r < 0)
113 return r;
114 if (r > 0) {
115 dns_cache_item_unlink_and_free(c, i);
116 return true1;
117 }
118 }
119
120 return false0;
121}
122
123static bool_Bool dns_cache_remove_by_key(DnsCache *c, DnsResourceKey *key) {
124 DnsCacheItem *first, *i, *n;
125
126 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 126, __PRETTY_FUNCTION__); } while (0)
;
127 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-cache.c"
, 127, __PRETTY_FUNCTION__); } while (0)
;
128
129 first = hashmap_remove(c->by_key, key);
130 if (!first)
131 return false0;
132
133 LIST_FOREACH_SAFE(by_key, i, n, first)for ((i) = (first); (i) && (((n) = (i)->by_key_next
), 1); (i) = (n))
{
134 prioq_remove(c->by_expiry, i, &i->prioq_idx);
135 dns_cache_item_free(i);
136 }
137
138 return true1;
139}
140
141void dns_cache_flush(DnsCache *c) {
142 DnsResourceKey *key;
143
144 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 144, __PRETTY_FUNCTION__); } while (0)
;
145
146 while ((key = hashmap_first_key(c->by_key)))
147 dns_cache_remove_by_key(c, key);
148
149 assert(hashmap_size(c->by_key) == 0)do { if ((__builtin_expect(!!(!(hashmap_size(c->by_key) ==
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("hashmap_size(c->by_key) == 0"
), "../src/resolve/resolved-dns-cache.c", 149, __PRETTY_FUNCTION__
); } while (0)
;
150 assert(prioq_size(c->by_expiry) == 0)do { if ((__builtin_expect(!!(!(prioq_size(c->by_expiry) ==
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("prioq_size(c->by_expiry) == 0"
), "../src/resolve/resolved-dns-cache.c", 150, __PRETTY_FUNCTION__
); } while (0)
;
151
152 c->by_key = hashmap_free(c->by_key);
153 c->by_expiry = prioq_free(c->by_expiry);
154}
155
156static void dns_cache_make_space(DnsCache *c, unsigned add) {
157 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 157, __PRETTY_FUNCTION__); } while (0)
;
158
159 if (add <= 0)
160 return;
161
162 /* Makes space for n new entries. Note that we actually allow
163 * the cache to grow beyond CACHE_MAX, but only when we shall
164 * add more RRs to the cache than CACHE_MAX at once. In that
165 * case the cache will be emptied completely otherwise. */
166
167 for (;;) {
168 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0);
169 DnsCacheItem *i;
170
171 if (prioq_size(c->by_expiry) <= 0)
172 break;
173
174 if (prioq_size(c->by_expiry) + add < CACHE_MAX4096)
175 break;
176
177 i = prioq_peek(c->by_expiry);
178 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/resolve/resolved-dns-cache.c"
, 178, __PRETTY_FUNCTION__); } while (0)
;
179
180 /* Take an extra reference to the key so that it
181 * doesn't go away in the middle of the remove call */
182 key = dns_resource_key_ref(i->key);
183 dns_cache_remove_by_key(c, key);
184 }
185}
186
187void dns_cache_prune(DnsCache *c) {
188 usec_t t = 0;
189
190 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 190, __PRETTY_FUNCTION__); } while (0)
;
191
192 /* Remove all entries that are past their TTL */
193
194 for (;;) {
195 DnsCacheItem *i;
196 char key_str[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(
uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof
(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) >
8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3
: sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10
: sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t
) > 8)])))) + 253 + 1)
];
197
198 i = prioq_peek(c->by_expiry);
199 if (!i)
200 break;
201
202 if (t <= 0)
203 t = now(clock_boottime_or_monotonic());
204
205 if (i->until > t)
206 break;
207
208 /* Depending whether this is an mDNS shared entry
209 * either remove only this one RR or the whole RRset */
210 log_debug("Removing %scache entry for %s (expired "USEC_FMT"s ago)",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 213, __func__, "Removing %scache entry for %s (expired "
"%" "l" "u""s ago)", i->shared_owner ? "shared " : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (t - i->until) / ((usec_t
) 1000000ULL)) : -abs(_e); })
211 i->shared_owner ? "shared " : "",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 213, __func__, "Removing %scache entry for %s (expired "
"%" "l" "u""s ago)", i->shared_owner ? "shared " : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (t - i->until) / ((usec_t
) 1000000ULL)) : -abs(_e); })
212 dns_resource_key_to_string(i->key, key_str, sizeof key_str),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 213, __func__, "Removing %scache entry for %s (expired "
"%" "l" "u""s ago)", i->shared_owner ? "shared " : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (t - i->until) / ((usec_t
) 1000000ULL)) : -abs(_e); })
213 (t - i->until) / USEC_PER_SEC)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 213, __func__, "Removing %scache entry for %s (expired "
"%" "l" "u""s ago)", i->shared_owner ? "shared " : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (t - i->until) / ((usec_t
) 1000000ULL)) : -abs(_e); })
;
214
215 if (i->shared_owner)
216 dns_cache_item_unlink_and_free(c, i);
217 else {
218 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0);
219
220 /* Take an extra reference to the key so that it
221 * doesn't go away in the middle of the remove call */
222 key = dns_resource_key_ref(i->key);
223 dns_cache_remove_by_key(c, key);
224 }
225 }
226}
227
228static int dns_cache_item_prioq_compare_func(const void *a, const void *b) {
229 const DnsCacheItem *x = a, *y = b;
230
231 if (x->until < y->until)
232 return -1;
233 if (x->until > y->until)
234 return 1;
235 return 0;
236}
237
238static int dns_cache_init(DnsCache *c) {
239 int r;
240
241 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 241, __PRETTY_FUNCTION__); } while (0)
;
242
243 r = prioq_ensure_allocated(&c->by_expiry, dns_cache_item_prioq_compare_func);
244 if (r < 0)
245 return r;
246
247 r = hashmap_ensure_allocated(&c->by_key, &dns_resource_key_hash_ops)internal_hashmap_ensure_allocated(&c->by_key, &dns_resource_key_hash_ops
)
;
248 if (r < 0)
249 return r;
250
251 return r;
252}
253
254static int dns_cache_link_item(DnsCache *c, DnsCacheItem *i) {
255 DnsCacheItem *first;
256 int r;
257
258 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 258, __PRETTY_FUNCTION__); } while (0)
;
259 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/resolve/resolved-dns-cache.c"
, 259, __PRETTY_FUNCTION__); } while (0)
;
260
261 r = prioq_put(c->by_expiry, i, &i->prioq_idx);
262 if (r < 0)
263 return r;
264
265 first = hashmap_get(c->by_key, i->key);
266 if (first) {
267 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *k = NULL((void*)0);
268
269 /* Keep a reference to the original key, while we manipulate the list. */
270 k = dns_resource_key_ref(first->key);
Value stored to 'k' is never read
271
272 /* Now, try to reduce the number of keys we keep */
273 dns_resource_key_reduce(&first->key, &i->key);
274
275 if (first->rr)
276 dns_resource_key_reduce(&first->rr->key, &i->key);
277 if (i->rr)
278 dns_resource_key_reduce(&i->rr->key, &i->key);
279
280 LIST_PREPEND(by_key, first, i)do { typeof(*(first)) **_head = &(first), *_item = (i); do
{ if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-cache.c"
, 280, __PRETTY_FUNCTION__); } while (0); if ((_item->by_key_next
= *_head)) _item->by_key_next->by_key_prev = _item; _item
->by_key_prev = ((void*)0); *_head = _item; } while (0)
;
281 assert_se(hashmap_replace(c->by_key, first->key, first) >= 0)do { if ((__builtin_expect(!!(!(hashmap_replace(c->by_key,
first->key, first) >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("hashmap_replace(c->by_key, first->key, first) >= 0"
), "../src/resolve/resolved-dns-cache.c", 281, __PRETTY_FUNCTION__
); } while (0)
;
282 } else {
283 r = hashmap_put(c->by_key, i->key, i);
284 if (r < 0) {
285 prioq_remove(c->by_expiry, i, &i->prioq_idx);
286 return r;
287 }
288 }
289
290 return 0;
291}
292
293static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {
294 DnsCacheItem *i;
295
296 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 296, __PRETTY_FUNCTION__); } while (0)
;
297 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-cache.c"
, 297, __PRETTY_FUNCTION__); } while (0)
;
298
299 LIST_FOREACH(by_key, i, hashmap_get(c->by_key, rr->key))for ((i) = (hashmap_get(c->by_key, rr->key)); (i); (i) =
(i)->by_key_next)
300 if (i->rr && dns_resource_record_equal(i->rr, rr) > 0)
301 return i;
302
303 return NULL((void*)0);
304}
305
306static usec_t calculate_until(DnsResourceRecord *rr, uint32_t nsec_ttl, usec_t timestamp, bool_Bool use_soa_minimum) {
307 uint32_t ttl;
308 usec_t u;
309
310 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-cache.c"
, 310, __PRETTY_FUNCTION__); } while (0)
;
311
312 ttl = MIN(rr->ttl, nsec_ttl)__extension__ ({ const typeof((rr->ttl)) __unique_prefix_A14
= ((rr->ttl)); const typeof((nsec_ttl)) __unique_prefix_B15
= ((nsec_ttl)); __unique_prefix_A14 < __unique_prefix_B15
? __unique_prefix_A14 : __unique_prefix_B15; })
;
313 if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) {
314 /* If this is a SOA RR, and it is requested, clamp to
315 * the SOA's minimum field. This is used when we do
316 * negative caching, to determine the TTL for the
317 * negative caching entry. See RFC 2308, Section
318 * 5. */
319
320 if (ttl > rr->soa.minimum)
321 ttl = rr->soa.minimum;
322 }
323
324 u = ttl * USEC_PER_SEC((usec_t) 1000000ULL);
325 if (u > CACHE_TTL_MAX_USEC(2 * ((usec_t) (60ULL*((usec_t) (60ULL*((usec_t) 1000000ULL))
))))
)
326 u = CACHE_TTL_MAX_USEC(2 * ((usec_t) (60ULL*((usec_t) (60ULL*((usec_t) 1000000ULL))
))))
;
327
328 if (rr->expiry != USEC_INFINITY((usec_t) -1)) {
329 usec_t left;
330
331 /* Make use of the DNSSEC RRSIG expiry info, if we
332 * have it */
333
334 left = LESS_BY(rr->expiry, now(CLOCK_REALTIME))__extension__ ({ const typeof((rr->expiry)) __unique_prefix_A16
= ((rr->expiry)); const typeof((now(0))) __unique_prefix_B17
= ((now(0))); __unique_prefix_A16 > __unique_prefix_B17 ?
__unique_prefix_A16 - __unique_prefix_B17 : 0; })
;
335 if (u > left)
336 u = left;
337 }
338
339 return timestamp + u;
340}
341
342static void dns_cache_item_update_positive(
343 DnsCache *c,
344 DnsCacheItem *i,
345 DnsResourceRecord *rr,
346 bool_Bool authenticated,
347 bool_Bool shared_owner,
348 usec_t timestamp,
349 int ifindex,
350 int owner_family,
351 const union in_addr_union *owner_address) {
352
353 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 353, __PRETTY_FUNCTION__); } while (0)
;
354 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/resolve/resolved-dns-cache.c"
, 354, __PRETTY_FUNCTION__); } while (0)
;
355 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-cache.c"
, 355, __PRETTY_FUNCTION__); } while (0)
;
356 assert(owner_address)do { if ((__builtin_expect(!!(!(owner_address)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("owner_address"), "../src/resolve/resolved-dns-cache.c"
, 356, __PRETTY_FUNCTION__); } while (0)
;
357
358 i->type = DNS_CACHE_POSITIVE;
359
360 if (!i->by_key_prev)
361 /* We are the first item in the list, we need to
362 * update the key used in the hashmap */
363
364 assert_se(hashmap_replace(c->by_key, rr->key, i) >= 0)do { if ((__builtin_expect(!!(!(hashmap_replace(c->by_key,
rr->key, i) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("hashmap_replace(c->by_key, rr->key, i) >= 0"), "../src/resolve/resolved-dns-cache.c"
, 364, __PRETTY_FUNCTION__); } while (0)
;
365
366 dns_resource_record_ref(rr);
367 dns_resource_record_unref(i->rr);
368 i->rr = rr;
369
370 dns_resource_key_unref(i->key);
371 i->key = dns_resource_key_ref(rr->key);
372
373 i->until = calculate_until(rr, (uint32_t) -1, timestamp, false0);
374 i->authenticated = authenticated;
375 i->shared_owner = shared_owner;
376
377 i->ifindex = ifindex;
378
379 i->owner_family = owner_family;
380 i->owner_address = *owner_address;
381
382 prioq_reshuffle(c->by_expiry, i, &i->prioq_idx);
383}
384
385static int dns_cache_put_positive(
386 DnsCache *c,
387 DnsResourceRecord *rr,
388 bool_Bool authenticated,
389 bool_Bool shared_owner,
390 usec_t timestamp,
391 int ifindex,
392 int owner_family,
393 const union in_addr_union *owner_address) {
394
395 _cleanup_(dns_cache_item_freep)__attribute__((cleanup(dns_cache_item_freep))) DnsCacheItem *i = NULL((void*)0);
396 DnsCacheItem *existing;
397 char key_str[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(
uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof
(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) >
8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3
: sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10
: sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t
) > 8)])))) + 253 + 1)
], ifname[IF_NAMESIZE16];
398 int r, k;
399
400 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 400, __PRETTY_FUNCTION__); } while (0)
;
401 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-cache.c"
, 401, __PRETTY_FUNCTION__); } while (0)
;
402 assert(owner_address)do { if ((__builtin_expect(!!(!(owner_address)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("owner_address"), "../src/resolve/resolved-dns-cache.c"
, 402, __PRETTY_FUNCTION__); } while (0)
;
403
404 /* Never cache pseudo RRs */
405 if (dns_class_is_pseudo(rr->key->class))
406 return 0;
407 if (dns_type_is_pseudo(rr->key->type))
408 return 0;
409
410 /* New TTL is 0? Delete this specific entry... */
411 if (rr->ttl <= 0) {
412 k = dns_cache_remove_by_rr(c, rr);
413 log_debug("%s: %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 415, __func__, "%s: %s"
, k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry"
, dns_resource_key_to_string(rr->key, key_str, sizeof key_str
)) : -abs(_e); })
414 k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 415, __func__, "%s: %s"
, k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry"
, dns_resource_key_to_string(rr->key, key_str, sizeof key_str
)) : -abs(_e); })
415 dns_resource_key_to_string(rr->key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 415, __func__, "%s: %s"
, k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry"
, dns_resource_key_to_string(rr->key, key_str, sizeof key_str
)) : -abs(_e); })
;
416 return 0;
417 }
418
419 /* Entry exists already? Update TTL, timestamp and owner */
420 existing = dns_cache_get(c, rr);
421 if (existing) {
422 dns_cache_item_update_positive(
423 c,
424 existing,
425 rr,
426 authenticated,
427 shared_owner,
428 timestamp,
429 ifindex,
430 owner_family,
431 owner_address);
432 return 0;
433 }
434
435 /* Otherwise, add the new RR */
436 r = dns_cache_init(c);
437 if (r < 0)
438 return r;
439
440 dns_cache_make_space(c, 1);
441
442 i = new0(DnsCacheItem, 1)((DnsCacheItem*) calloc((1), sizeof(DnsCacheItem)));
443 if (!i)
444 return -ENOMEM12;
445
446 i->type = DNS_CACHE_POSITIVE;
447 i->key = dns_resource_key_ref(rr->key);
448 i->rr = dns_resource_record_ref(rr);
449 i->until = calculate_until(rr, (uint32_t) -1, timestamp, false0);
450 i->authenticated = authenticated;
451 i->shared_owner = shared_owner;
452 i->ifindex = ifindex;
453 i->owner_family = owner_family;
454 i->owner_address = *owner_address;
455 i->prioq_idx = PRIOQ_IDX_NULL((unsigned) -1);
456
457 r = dns_cache_link_item(c, i);
458 if (r < 0)
459 return r;
460
461 if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= 7),0))
) {
462 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0);
463
464 (void) in_addr_to_string(i->owner_family, &i->owner_address, &t);
465
466 log_debug("Added positive %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
467 i->authenticated ? "authenticated" : "unauthenticated",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
468 i->shared_owner ? " shared" : "",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
469 dns_resource_key_to_string(i->key, key_str, sizeof key_str),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
470 (i->until - timestamp) / USEC_PER_SEC,({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
471 i->ifindex == 0 ? "*" : strna(if_indextoname(i->ifindex, ifname)),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
472 af_to_name_short(i->owner_family),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
473 strna(t))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 473, __func__, "Added positive %s%s cache entry for %s "
"%" "l" "u""s on %s/%s/%s", i->authenticated ? "authenticated"
: "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL), i->ifindex == 0 ? "*" : strna(if_indextoname
(i->ifindex, ifname)), af_to_name_short(i->owner_family
), strna(t)) : -abs(_e); })
;
474 }
475
476 i = NULL((void*)0);
477 return 0;
478}
479
480static int dns_cache_put_negative(
481 DnsCache *c,
482 DnsResourceKey *key,
483 int rcode,
484 bool_Bool authenticated,
485 uint32_t nsec_ttl,
486 usec_t timestamp,
487 DnsResourceRecord *soa,
488 int owner_family,
489 const union in_addr_union *owner_address) {
490
491 _cleanup_(dns_cache_item_freep)__attribute__((cleanup(dns_cache_item_freep))) DnsCacheItem *i = NULL((void*)0);
492 char key_str[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(
uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof
(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) >
8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3
: sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10
: sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t
) > 8)])))) + 253 + 1)
];
493 int r;
494
495 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 495, __PRETTY_FUNCTION__); } while (0)
;
496 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-cache.c"
, 496, __PRETTY_FUNCTION__); } while (0)
;
497 assert(owner_address)do { if ((__builtin_expect(!!(!(owner_address)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("owner_address"), "../src/resolve/resolved-dns-cache.c"
, 497, __PRETTY_FUNCTION__); } while (0)
;
498
499 /* Never cache pseudo RR keys. DNS_TYPE_ANY is particularly
500 * important to filter out as we use this as a pseudo-type for
501 * NXDOMAIN entries */
502 if (dns_class_is_pseudo(key->class))
503 return 0;
504 if (dns_type_is_pseudo(key->type))
505 return 0;
506
507 if (IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN})/
sizeof(int)]; switch(rcode) { case DNS_RCODE_SUCCESS: case DNS_RCODE_NXDOMAIN
: _found = 1; break; default: break; } _found; })
) {
508 if (!soa)
509 return 0;
510
511 /* For negative replies, check if we have a TTL of a SOA */
512 if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) {
513 log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 514, __func__, "Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
514 dns_resource_key_to_string(key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 514, __func__, "Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
515 return 0;
516 }
517 } else if (rcode != DNS_RCODE_SERVFAIL)
518 return 0;
519
520 r = dns_cache_init(c);
521 if (r < 0)
522 return r;
523
524 dns_cache_make_space(c, 1);
525
526 i = new0(DnsCacheItem, 1)((DnsCacheItem*) calloc((1), sizeof(DnsCacheItem)));
527 if (!i)
528 return -ENOMEM12;
529
530 i->type =
531 rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA :
532 rcode == DNS_RCODE_NXDOMAIN ? DNS_CACHE_NXDOMAIN : DNS_CACHE_RCODE;
533 i->until =
534 i->type == DNS_CACHE_RCODE ? timestamp + CACHE_TTL_STRANGE_RCODE_USEC(30 * ((usec_t) 1000000ULL)) :
535 calculate_until(soa, nsec_ttl, timestamp, true1);
536 i->authenticated = authenticated;
537 i->owner_family = owner_family;
538 i->owner_address = *owner_address;
539 i->prioq_idx = PRIOQ_IDX_NULL((unsigned) -1);
540 i->rcode = rcode;
541
542 if (i->type == DNS_CACHE_NXDOMAIN) {
543 /* NXDOMAIN entries should apply equally to all types, so we use ANY as
544 * a pseudo type for this purpose here. */
545 i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, dns_resource_key_name(key));
546 if (!i->key)
547 return -ENOMEM12;
548
549 /* Make sure to remove any previous entry for this
550 * specific ANY key. (For non-ANY keys the cache data
551 * is already cleared by the caller.) Note that we
552 * don't bother removing positive or NODATA cache
553 * items in this case, because it would either be slow
554 * or require explicit indexing by name */
555 dns_cache_remove_by_key(c, key);
556 } else
557 i->key = dns_resource_key_ref(key);
558
559 r = dns_cache_link_item(c, i);
560 if (r < 0)
561 return r;
562
563 log_debug("Added %s cache entry for %s "USEC_FMT"s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 566, __func__, "Added %s cache entry for %s "
"%" "l" "u""s", dns_cache_item_type_to_string(i), dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL)) : -abs(_e); })
564 dns_cache_item_type_to_string(i),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 566, __func__, "Added %s cache entry for %s "
"%" "l" "u""s", dns_cache_item_type_to_string(i), dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL)) : -abs(_e); })
565 dns_resource_key_to_string(i->key, key_str, sizeof key_str),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 566, __func__, "Added %s cache entry for %s "
"%" "l" "u""s", dns_cache_item_type_to_string(i), dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL)) : -abs(_e); })
566 (i->until - timestamp) / USEC_PER_SEC)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 566, __func__, "Added %s cache entry for %s "
"%" "l" "u""s", dns_cache_item_type_to_string(i), dns_resource_key_to_string
(i->key, key_str, sizeof key_str), (i->until - timestamp
) / ((usec_t) 1000000ULL)) : -abs(_e); })
;
567
568 i = NULL((void*)0);
569 return 0;
570}
571
572static void dns_cache_remove_previous(
573 DnsCache *c,
574 DnsResourceKey *key,
575 DnsAnswer *answer) {
576
577 DnsResourceRecord *rr;
578 DnsAnswerFlags flags;
579
580 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 580, __PRETTY_FUNCTION__); } while (0)
;
581
582 /* First, if we were passed a key (i.e. on LLMNR/DNS, but
583 * not on mDNS), delete all matching old RRs, so that we only
584 * keep complete by_key in place. */
585 if (key)
586 dns_cache_remove_by_key(c, key);
587
588 /* Second, flush all entries matching the answer, unless this
589 * is an RR that is explicitly marked to be "shared" between
590 * peers (i.e. mDNS RRs without the flush-cache bit set). */
591 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer)for (size_t __unique_prefix_i18 = ({ (rr) = ((answer) &&
(answer)->n_rrs > 0) ? (answer)->items[0].rr : ((void
*)0); (flags) = ((answer) && (answer)->n_rrs > 0
) ? (answer)->items[0].flags : 0; 0; }); (answer) &&
(__unique_prefix_i18 < (answer)->n_rrs); __unique_prefix_i18
++, (rr) = ((__unique_prefix_i18 < (answer)->n_rrs) ? (
answer)->items[__unique_prefix_i18].rr : ((void*)0)), (flags
) = ((__unique_prefix_i18 < (answer)->n_rrs) ? (answer)
->items[__unique_prefix_i18].flags : 0))
{
592 if ((flags & DNS_ANSWER_CACHEABLE) == 0)
593 continue;
594
595 if (flags & DNS_ANSWER_SHARED_OWNER)
596 continue;
597
598 dns_cache_remove_by_key(c, rr->key);
599 }
600}
601
602static bool_Bool rr_eligible(DnsResourceRecord *rr) {
603 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-cache.c"
, 603, __PRETTY_FUNCTION__); } while (0)
;
604
605 /* When we see an NSEC/NSEC3 RR, we'll only cache it if it is from the lower zone, not the upper zone, since
606 * that's where the interesting bits are (with exception of DS RRs). Of course, this way we cannot derive DS
607 * existence from any cached NSEC/NSEC3, but that should be fine. */
608
609 switch (rr->key->type) {
610
611 case DNS_TYPE_NSEC:
612 return !bitmap_isset(rr->nsec.types, DNS_TYPE_NS) ||
613 bitmap_isset(rr->nsec.types, DNS_TYPE_SOA);
614
615 case DNS_TYPE_NSEC3:
616 return !bitmap_isset(rr->nsec3.types, DNS_TYPE_NS) ||
617 bitmap_isset(rr->nsec3.types, DNS_TYPE_SOA);
618
619 default:
620 return true1;
621 }
622}
623
624int dns_cache_put(
625 DnsCache *c,
626 DnsResourceKey *key,
627 int rcode,
628 DnsAnswer *answer,
629 bool_Bool authenticated,
630 uint32_t nsec_ttl,
631 usec_t timestamp,
632 int owner_family,
633 const union in_addr_union *owner_address) {
634
635 DnsResourceRecord *soa = NULL((void*)0), *rr;
636 bool_Bool weird_rcode = false0;
637 DnsAnswerFlags flags;
638 unsigned cache_keys;
639 int r, ifindex;
640
641 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 641, __PRETTY_FUNCTION__); } while (0)
;
642 assert(owner_address)do { if ((__builtin_expect(!!(!(owner_address)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("owner_address"), "../src/resolve/resolved-dns-cache.c"
, 642, __PRETTY_FUNCTION__); } while (0)
;
643
644 dns_cache_remove_previous(c, key, answer);
645
646 /* We only care for positive replies and NXDOMAINs, on all other replies we will simply flush the respective
647 * entries, and that's it. (Well, with one further exception: since some DNS zones (akamai!) return SERVFAIL
648 * consistently for some lookups, and forwarders tend to propagate that we'll cache that too, but only for a
649 * short time.) */
650
651 if (IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN})/
sizeof(int)]; switch(rcode) { case DNS_RCODE_SUCCESS: case DNS_RCODE_NXDOMAIN
: _found = 1; break; default: break; } _found; })
) {
652 if (dns_answer_size(answer) <= 0) {
653 if (key) {
654 char key_str[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(
uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof
(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) >
8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3
: sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10
: sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t
) > 8)])))) + 253 + 1)
];
655
656 log_debug("Not caching negative entry without a SOA record: %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 657, __func__, "Not caching negative entry without a SOA record: %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
657 dns_resource_key_to_string(key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 657, __func__, "Not caching negative entry without a SOA record: %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
658 }
659 return 0;
660 }
661
662 } else {
663 /* Only cache SERVFAIL as "weird" rcode for now. We can add more later, should that turn out to be
664 * beneficial. */
665 if (rcode != DNS_RCODE_SERVFAIL)
666 return 0;
667
668 weird_rcode = true1;
669 }
670
671 cache_keys = dns_answer_size(answer);
672 if (key)
673 cache_keys++;
674
675 /* Make some space for our new entries */
676 dns_cache_make_space(c, cache_keys);
677
678 if (timestamp <= 0)
679 timestamp = now(clock_boottime_or_monotonic());
680
681 /* Second, add in positive entries for all contained RRs */
682 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer)for (size_t __unique_prefix_i19 = ({ (rr) = ((answer) &&
(answer)->n_rrs > 0) ? (answer)->items[0].rr : ((void
*)0); (ifindex) = ((answer) && (answer)->n_rrs >
0) ? (answer)->items[0].ifindex : 0; (flags) = ((answer) &&
(answer)->n_rrs > 0) ? (answer)->items[0].flags : 0
; 0; }); (answer) && (__unique_prefix_i19 < (answer
)->n_rrs); __unique_prefix_i19++, (rr) = ((__unique_prefix_i19
< (answer)->n_rrs) ? (answer)->items[__unique_prefix_i19
].rr : ((void*)0)), (ifindex) = ((__unique_prefix_i19 < (answer
)->n_rrs) ? (answer)->items[__unique_prefix_i19].ifindex
: 0), (flags) = ((__unique_prefix_i19 < (answer)->n_rrs
) ? (answer)->items[__unique_prefix_i19].flags : 0))
{
683 if ((flags & DNS_ANSWER_CACHEABLE) == 0)
684 continue;
685
686 r = rr_eligible(rr);
687 if (r < 0)
688 return r;
689 if (r == 0)
690 continue;
691
692 r = dns_cache_put_positive(
693 c,
694 rr,
695 flags & DNS_ANSWER_AUTHENTICATED,
696 flags & DNS_ANSWER_SHARED_OWNER,
697 timestamp,
698 ifindex,
699 owner_family, owner_address);
700 if (r < 0)
701 goto fail;
702 }
703
704 if (!key) /* mDNS doesn't know negative caching, really */
705 return 0;
706
707 /* Third, add in negative entries if the key has no RR */
708 r = dns_answer_match_key(answer, key, NULL((void*)0));
709 if (r < 0)
710 goto fail;
711 if (r > 0)
712 return 0;
713
714 /* But not if it has a matching CNAME/DNAME (the negative
715 * caching will be done on the canonical name, not on the
716 * alias) */
717 r = dns_answer_find_cname_or_dname(answer, key, NULL((void*)0), NULL((void*)0));
718 if (r < 0)
719 goto fail;
720 if (r > 0)
721 return 0;
722
723 /* See https://tools.ietf.org/html/rfc2308, which say that a matching SOA record in the packet is used to
724 * enable negative caching. We apply one exception though: if we are about to cache a weird rcode we do so
725 * regardless of a SOA. */
726 r = dns_answer_find_soa(answer, key, &soa, &flags);
727 if (r < 0)
728 goto fail;
729 if (r == 0 && !weird_rcode)
730 return 0;
731 if (r > 0) {
732 /* Refuse using the SOA data if it is unsigned, but the key is
733 * signed */
734 if (authenticated && (flags & DNS_ANSWER_AUTHENTICATED) == 0)
735 return 0;
736 }
737
738 r = dns_cache_put_negative(
739 c,
740 key,
741 rcode,
742 authenticated,
743 nsec_ttl,
744 timestamp,
745 soa,
746 owner_family, owner_address);
747 if (r < 0)
748 goto fail;
749
750 return 0;
751
752fail:
753 /* Adding all RRs failed. Let's clean up what we already
754 * added, just in case */
755
756 if (key)
757 dns_cache_remove_by_key(c, key);
758
759 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer)for (size_t __unique_prefix_i20 = ({ (rr) = ((answer) &&
(answer)->n_rrs > 0) ? (answer)->items[0].rr : ((void
*)0); (flags) = ((answer) && (answer)->n_rrs > 0
) ? (answer)->items[0].flags : 0; 0; }); (answer) &&
(__unique_prefix_i20 < (answer)->n_rrs); __unique_prefix_i20
++, (rr) = ((__unique_prefix_i20 < (answer)->n_rrs) ? (
answer)->items[__unique_prefix_i20].rr : ((void*)0)), (flags
) = ((__unique_prefix_i20 < (answer)->n_rrs) ? (answer)
->items[__unique_prefix_i20].flags : 0))
{
760 if ((flags & DNS_ANSWER_CACHEABLE) == 0)
761 continue;
762
763 dns_cache_remove_by_key(c, rr->key);
764 }
765
766 return r;
767}
768
769static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, DnsResourceKey *k) {
770 DnsCacheItem *i;
771 const char *n;
772 int r;
773
774 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 774, __PRETTY_FUNCTION__); } while (0)
;
775 assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("k"), "../src/resolve/resolved-dns-cache.c"
, 775, __PRETTY_FUNCTION__); } while (0)
;
776
777 /* If we hit some OOM error, or suchlike, we don't care too
778 * much, after all this is just a cache */
779
780 i = hashmap_get(c->by_key, k);
781 if (i)
782 return i;
783
784 n = dns_resource_key_name(k);
785
786 /* Check if we have an NXDOMAIN cache item for the name, notice that we use
787 * the pseudo-type ANY for NXDOMAIN cache items. */
788 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_ANY, n)((DnsResourceKey) { .n_ref = (unsigned) -1, .class = k->class
, .type = DNS_TYPE_ANY, ._name = (char*) n, })
);
789 if (i && i->type == DNS_CACHE_NXDOMAIN)
790 return i;
791
792 if (dns_type_may_redirect(k->type)) {
793 /* Check if we have a CNAME record instead */
794 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_CNAME, n)((DnsResourceKey) { .n_ref = (unsigned) -1, .class = k->class
, .type = DNS_TYPE_CNAME, ._name = (char*) n, })
);
795 if (i)
796 return i;
797
798 /* OK, let's look for cached DNAME records. */
799 for (;;) {
800 if (isempty(n))
801 return NULL((void*)0);
802
803 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_DNAME, n)((DnsResourceKey) { .n_ref = (unsigned) -1, .class = k->class
, .type = DNS_TYPE_DNAME, ._name = (char*) n, })
);
804 if (i)
805 return i;
806
807 /* Jump one label ahead */
808 r = dns_name_parent(&n);
809 if (r <= 0)
810 return NULL((void*)0);
811 }
812 }
813
814 if (k->type != DNS_TYPE_NSEC) {
815 /* Check if we have an NSEC record instead for the name. */
816 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_NSEC, n)((DnsResourceKey) { .n_ref = (unsigned) -1, .class = k->class
, .type = DNS_TYPE_NSEC, ._name = (char*) n, })
);
817 if (i)
818 return i;
819 }
820
821 return NULL((void*)0);
822}
823
824int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool_Bool clamp_ttl, int *rcode, DnsAnswer **ret, bool_Bool *authenticated) {
825 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *answer = NULL((void*)0);
826 char key_str[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(
uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof
(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) >
8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3
: sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10
: sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t
) > 8)])))) + 253 + 1)
];
827 unsigned n = 0;
828 int r;
829 bool_Bool nxdomain = false0;
830 DnsCacheItem *j, *first, *nsec = NULL((void*)0);
831 bool_Bool have_authenticated = false0, have_non_authenticated = false0;
832 usec_t current;
833 int found_rcode = -1;
834
835 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-cache.c"
, 835, __PRETTY_FUNCTION__); } while (0)
;
836 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-cache.c"
, 836, __PRETTY_FUNCTION__); } while (0)
;
837 assert(rcode)do { if ((__builtin_expect(!!(!(rcode)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rcode"), "../src/resolve/resolved-dns-cache.c"
, 837, __PRETTY_FUNCTION__); } while (0)
;
838 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-cache.c"
, 838, __PRETTY_FUNCTION__); } while (0)
;
839 assert(authenticated)do { if ((__builtin_expect(!!(!(authenticated)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("authenticated"), "../src/resolve/resolved-dns-cache.c"
, 839, __PRETTY_FUNCTION__); } while (0)
;
840
841 if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
842 /* If we have ANY lookups we don't use the cache, so
843 * that the caller refreshes via the network. */
844
845 log_debug("Ignoring cache for ANY lookup: %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 846, __func__, "Ignoring cache for ANY lookup: %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
846 dns_resource_key_to_string(key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 846, __func__, "Ignoring cache for ANY lookup: %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
847
848 c->n_miss++;
849
850 *ret = NULL((void*)0);
851 *rcode = DNS_RCODE_SUCCESS;
852 *authenticated = false0;
853
854 return 0;
855 }
856
857 first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key);
858 if (!first) {
859 /* If one question cannot be answered we need to refresh */
860
861 log_debug("Cache miss for %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 862, __func__, "Cache miss for %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
862 dns_resource_key_to_string(key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 862, __func__, "Cache miss for %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
863
864 c->n_miss++;
865
866 *ret = NULL((void*)0);
867 *rcode = DNS_RCODE_SUCCESS;
868 *authenticated = false0;
869
870 return 0;
871 }
872
873 LIST_FOREACH(by_key, j, first)for ((j) = (first); (j); (j) = (j)->by_key_next) {
874 if (j->rr) {
875 if (j->rr->key->type == DNS_TYPE_NSEC)
876 nsec = j;
877
878 n++;
879 } else if (j->type == DNS_CACHE_NXDOMAIN)
880 nxdomain = true1;
881 else if (j->type == DNS_CACHE_RCODE)
882 found_rcode = j->rcode;
883
884 if (j->authenticated)
885 have_authenticated = true1;
886 else
887 have_non_authenticated = true1;
888 }
889
890 if (found_rcode >= 0) {
891 log_debug("RCODE %s cache hit for %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 893, __func__, "RCODE %s cache hit for %s"
, dns_rcode_to_string(found_rcode), dns_resource_key_to_string
(key, key_str, sizeof(key_str))) : -abs(_e); })
892 dns_rcode_to_string(found_rcode),({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 893, __func__, "RCODE %s cache hit for %s"
, dns_rcode_to_string(found_rcode), dns_resource_key_to_string
(key, key_str, sizeof(key_str))) : -abs(_e); })
893 dns_resource_key_to_string(key, key_str, sizeof(key_str)))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 893, __func__, "RCODE %s cache hit for %s"
, dns_rcode_to_string(found_rcode), dns_resource_key_to_string
(key, key_str, sizeof(key_str))) : -abs(_e); })
;
894
895 *ret = NULL((void*)0);
896 *rcode = found_rcode;
897 *authenticated = false0;
898
899 c->n_hit++;
900 return 1;
901 }
902
903 if (nsec && !IN_SET(key->type, DNS_TYPE_NSEC, DNS_TYPE_DS)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TYPE_NSEC, DNS_TYPE_DS})/sizeof(int)
]; switch(key->type) { case DNS_TYPE_NSEC: case DNS_TYPE_DS
: _found = 1; break; default: break; } _found; })
) {
904 /* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from
905 * the lower-zone of a zone cut, but the DS RRs are on the upper zone. */
906
907 log_debug("NSEC NODATA cache hit for %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 908, __func__, "NSEC NODATA cache hit for %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
908 dns_resource_key_to_string(key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 908, __func__, "NSEC NODATA cache hit for %s"
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
909
910 /* We only found an NSEC record that matches our name.
911 * If it says the type doesn't exist report
912 * NODATA. Otherwise report a cache miss. */
913
914 *ret = NULL((void*)0);
915 *rcode = DNS_RCODE_SUCCESS;
916 *authenticated = nsec->authenticated;
917
918 if (!bitmap_isset(nsec->rr->nsec.types, key->type) &&
919 !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) &&
920 !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_DNAME)) {
921 c->n_hit++;
922 return 1;
923 }
924
925 c->n_miss++;
926 return 0;
927 }
928
929 log_debug("%s cache hit for %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 932, __func__, "%s cache hit for %s"
, n > 0 ? "Positive" : nxdomain ? "NXDOMAIN" : "NODATA", dns_resource_key_to_string
(key, key_str, sizeof key_str)) : -abs(_e); })
930 n > 0 ? "Positive" :({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 932, __func__, "%s cache hit for %s"
, n > 0 ? "Positive" : nxdomain ? "NXDOMAIN" : "NODATA", dns_resource_key_to_string
(key, key_str, sizeof key_str)) : -abs(_e); })
931 nxdomain ? "NXDOMAIN" : "NODATA",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 932, __func__, "%s cache hit for %s"
, n > 0 ? "Positive" : nxdomain ? "NXDOMAIN" : "NODATA", dns_resource_key_to_string
(key, key_str, sizeof key_str)) : -abs(_e); })
932 dns_resource_key_to_string(key, key_str, sizeof key_str))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-cache.c", 932, __func__, "%s cache hit for %s"
, n > 0 ? "Positive" : nxdomain ? "NXDOMAIN" : "NODATA", dns_resource_key_to_string
(key, key_str, sizeof key_str)) : -abs(_e); })
;
933
934 if (n <= 0) {
935 c->n_hit++;
936
937 *ret = NULL((void*)0);
938 *rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS;
939 *authenticated = have_authenticated && !have_non_authenticated;
940 return 1;
941 }
942
943 answer = dns_answer_new(n);
944 if (!answer)
945 return -ENOMEM12;
946
947 if (clamp_ttl)
948 current = now(clock_boottime_or_monotonic());
949
950 LIST_FOREACH(by_key, j, first)for ((j) = (first); (j); (j) = (j)->by_key_next) {
951 _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *rr = NULL((void*)0);
952
953 if (!j->rr)
954 continue;
955
956 if (clamp_ttl) {
957 rr = dns_resource_record_ref(j->rr);
958
959 r = dns_resource_record_clamp_ttl(&rr, LESS_BY(j->until, current)__extension__ ({ const typeof((j->until)) __unique_prefix_A21
= ((j->until)); const typeof((current)) __unique_prefix_B22
= ((current)); __unique_prefix_A21 > __unique_prefix_B22 ?
__unique_prefix_A21 - __unique_prefix_B22 : 0; })
/ USEC_PER_SEC((usec_t) 1000000ULL));
960 if (r < 0)
961 return r;
962 }
963
964 r = dns_answer_add(answer, rr ?: j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0);
965 if (r < 0)
966 return r;
967 }
968
969 c->n_hit++;
970
971 *ret = answer;
972 *rcode = DNS_RCODE_SUCCESS;
973 *authenticated = have_authenticated && !have_non_authenticated;
974 answer = NULL((void*)0);
975
976 return n;
977}
978
979int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address) {
980 DnsCacheItem *i, *first;
981 bool_Bool same_owner = true1;
982
983 assert(cache)do { if ((__builtin_expect(!!(!(cache)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("cache"), "../src/resolve/resolved-dns-cache.c"
, 983, __PRETTY_FUNCTION__); } while (0)
;
984 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-cache.c"
, 984, __PRETTY_FUNCTION__); } while (0)
;
985
986 dns_cache_prune(cache);
987
988 /* See if there's a cache entry for the same key. If there
989 * isn't there's no conflict */
990 first = hashmap_get(cache->by_key, rr->key);
991 if (!first)
992 return 0;
993
994 /* See if the RR key is owned by the same owner, if so, there
995 * isn't a conflict either */
996 LIST_FOREACH(by_key, i, first)for ((i) = (first); (i); (i) = (i)->by_key_next) {
997 if (i->owner_family != owner_family ||
998 !in_addr_equal(owner_family, &i->owner_address, owner_address)) {
999 same_owner = false0;
1000 break;
1001 }
1002 }
1003 if (same_owner)
1004 return 0;
1005
1006 /* See if there's the exact same RR in the cache. If yes, then
1007 * there's no conflict. */
1008 if (dns_cache_get(cache, rr))
1009 return 0;
1010
1011 /* There's a conflict */
1012 return 1;
1013}
1014
1015int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
1016 unsigned ancount = 0;
1017 Iterator iterator;
1018 DnsCacheItem *i;
1019 int r;
1020
1021 assert(cache)do { if ((__builtin_expect(!!(!(cache)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("cache"), "../src/resolve/resolved-dns-cache.c"
, 1021, __PRETTY_FUNCTION__); } while (0)
;
1022 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-cache.c"
, 1022, __PRETTY_FUNCTION__); } while (0)
;
1023
1024 HASHMAP_FOREACH(i, cache->by_key, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); hashmap_iterate((cache->by_key
), &(iterator), (void**)&(i), ((void*)0)); )
{
1025 DnsCacheItem *j;
1026
1027 LIST_FOREACH(by_key, j, i)for ((j) = (i); (j); (j) = (j)->by_key_next) {
1028 if (!j->rr)
1029 continue;
1030
1031 if (!j->shared_owner)
1032 continue;
1033
1034 r = dns_packet_append_rr(p, j->rr, 0, NULL((void*)0), NULL((void*)0));
1035 if (r == -EMSGSIZE90 && p->protocol == DNS_PROTOCOL_MDNS) {
1036 /* For mDNS, if we're unable to stuff all known answers into the given packet,
1037 * allocate a new one, push the RR into that one and link it to the current one.
1038 */
1039
1040 DNS_PACKET_HEADER(p)((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount = htobe16(ancount);
1041 ancount = 0;
1042
1043 r = dns_packet_new_query(&p->more, p->protocol, 0, true1);
1044 if (r < 0)
1045 return r;
1046
1047 /* continue with new packet */
1048 p = p->more;
1049 r = dns_packet_append_rr(p, j->rr, 0, NULL((void*)0), NULL((void*)0));
1050 }
1051
1052 if (r < 0)
1053 return r;
1054
1055 ancount++;
1056 }
1057 }
1058
1059 DNS_PACKET_HEADER(p)((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount = htobe16(ancount);
1060
1061 return 0;
1062}
1063
1064void dns_cache_dump(DnsCache *cache, FILE *f) {
1065 Iterator iterator;
1066 DnsCacheItem *i;
1067
1068 if (!cache)
1069 return;
1070
1071 if (!f)
1072 f = stdoutstdout;
1073
1074 HASHMAP_FOREACH(i, cache->by_key, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); hashmap_iterate((cache->by_key
), &(iterator), (void**)&(i), ((void*)0)); )
{
1075 DnsCacheItem *j;
1076
1077 LIST_FOREACH(by_key, j, i)for ((j) = (i); (j); (j) = (j)->by_key_next) {
1078
1079 fputc('\t', f);
1080
1081 if (j->rr) {
1082 const char *t;
1083 t = dns_resource_record_to_string(j->rr);
1084 if (!t) {
1085 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/resolve/resolved-dns-cache.c"
, 1085, __func__)
;
1086 continue;
1087 }
1088
1089 fputs(t, f);
1090 fputc('\n', f);
1091 } else {
1092 char key_str[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(
uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof
(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) >
8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3
: sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10
: sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t
) > 8)])))) + 253 + 1)
];
1093
1094 fputs(dns_resource_key_to_string(j->key, key_str, sizeof key_str), f);
1095 fputs(" -- ", f);
1096 fputs(dns_cache_item_type_to_string(j), f);
1097 fputc('\n', f);
1098 }
1099 }
1100 }
1101}
1102
1103bool_Bool dns_cache_is_empty(DnsCache *cache) {
1104 if (!cache)
1105 return true1;
1106
1107 return hashmap_isempty(cache->by_key);
1108}
1109
1110unsigned dns_cache_size(DnsCache *cache) {
1111 if (!cache)
1112 return 0;
1113
1114 return hashmap_size(cache->by_key);
1115}