Bug Summary

File:build-scan/../src/resolve/resolved-dns-answer.c
Warning:line 577, column 40
Potential leak of memory pointed to by 'copy'

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-answer.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 pic -pic-level 2 -fhalf-no-semantic-interposition -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 src/resolve/libsystemd-resolve-core.a.p -I src/resolve -I ../src/resolve -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/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 . -I .. -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-answer.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "alloc-util.h"
4#include "dns-domain.h"
5#include "resolved-dns-answer.h"
6#include "resolved-dns-dnssec.h"
7#include "string-util.h"
8
9DnsAnswer *dns_answer_new(size_t n) {
10 DnsAnswer *a;
11
12 a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n)(calloc(1, (__builtin_offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem
) * n)))
;
29
Memory is allocated
13 if (!a)
30
Assuming 'a' is non-null
31
Taking false branch
14 return NULL((void*)0);
15
16 a->n_ref = 1;
17 a->n_allocated = n;
18
19 return a;
20}
21
22DnsAnswer *dns_answer_ref(DnsAnswer *a) {
23 if (!a)
24 return NULL((void*)0);
25
26 assert(a->n_ref > 0)do { if ((__builtin_expect(!!(!(a->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a->n_ref > 0"), "../src/resolve/resolved-dns-answer.c"
, 26, __PRETTY_FUNCTION__); } while (0)
;
27 a->n_ref++;
28 return a;
29}
30
31static void dns_answer_flush(DnsAnswer *a) {
32 DnsResourceRecord *rr;
33
34 if (!a)
35 return;
36
37 DNS_ANSWER_FOREACH(rr, a)for (size_t __unique_prefix_i37 = ({ (rr) = ((a) && (
a)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); 0; }
); (a) && (__unique_prefix_i37 < (a)->n_rrs); __unique_prefix_i37
++, (rr) = (__unique_prefix_i37 < (a)->n_rrs ? (a)->
items[__unique_prefix_i37].rr : ((void*)0)))
38 dns_resource_record_unref(rr);
39
40 a->n_rrs = 0;
41}
42
43DnsAnswer *dns_answer_unref(DnsAnswer *a) {
44 if (!a)
45 return NULL((void*)0);
46
47 assert(a->n_ref > 0)do { if ((__builtin_expect(!!(!(a->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a->n_ref > 0"), "../src/resolve/resolved-dns-answer.c"
, 47, __PRETTY_FUNCTION__); } while (0)
;
48
49 if (a->n_ref == 1) {
50 dns_answer_flush(a);
51 free(a);
52 } else
53 a->n_ref--;
54
55 return NULL((void*)0);
56}
57
58static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
59 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-answer.c"
, 59, __PRETTY_FUNCTION__); } while (0)
;
60
61 if (!a)
62 return -ENOSPC28;
63
64 if (a->n_rrs >= a->n_allocated)
65 return -ENOSPC28;
66
67 a->items[a->n_rrs++] = (DnsAnswerItem) {
68 .rr = dns_resource_record_ref(rr),
69 .ifindex = ifindex,
70 .flags = flags,
71 };
72
73 return 1;
74}
75
76static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) {
77 DnsResourceRecord *rr;
78 DnsAnswerFlags flags;
79 int ifindex, r;
80
81 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, source)for (size_t __unique_prefix_i38 = ({ (rr) = ((source) &&
(source)->n_rrs > 0) ? (source)->items[0].rr : ((void
*)0); (ifindex) = ((source) && (source)->n_rrs >
0) ? (source)->items[0].ifindex : 0; (flags) = ((source) &&
(source)->n_rrs > 0) ? (source)->items[0].flags : 0
; 0; }); (source) && (__unique_prefix_i38 < (source
)->n_rrs); __unique_prefix_i38++, (rr) = ((__unique_prefix_i38
< (source)->n_rrs) ? (source)->items[__unique_prefix_i38
].rr : ((void*)0)), (ifindex) = ((__unique_prefix_i38 < (source
)->n_rrs) ? (source)->items[__unique_prefix_i38].ifindex
: 0), (flags) = ((__unique_prefix_i38 < (source)->n_rrs
) ? (source)->items[__unique_prefix_i38].flags : 0))
{
82 r = dns_answer_add_raw(a, rr, ifindex, flags);
83 if (r < 0)
84 return r;
85 }
86
87 return 0;
88}
89
90int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
91 size_t i;
92 int r;
93
94 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-answer.c"
, 94, __PRETTY_FUNCTION__); } while (0)
;
95
96 if (!a)
97 return -ENOSPC28;
98 if (a->n_ref > 1)
99 return -EBUSY16;
100
101 for (i = 0; i < a->n_rrs; i++) {
102 if (a->items[i].ifindex != ifindex)
103 continue;
104
105 r = dns_resource_record_equal(a->items[i].rr, rr);
106 if (r < 0)
107 return r;
108 if (r > 0) {
109 /* Don't mix contradicting TTLs (see below) */
110 if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0))
111 return -EINVAL22;
112
113 /* Entry already exists, keep the entry with
114 * the higher RR. */
115 if (rr->ttl > a->items[i].rr->ttl) {
116 dns_resource_record_ref(rr);
117 dns_resource_record_unref(a->items[i].rr);
118 a->items[i].rr = rr;
119 }
120
121 a->items[i].flags |= flags;
122 return 0;
123 }
124
125 r = dns_resource_key_equal(a->items[i].rr->key, rr->key);
126 if (r < 0)
127 return r;
128 if (r > 0) {
129 /* There's already an RR of the same RRset in
130 * place! Let's see if the TTLs more or less
131 * match. We don't really care if they match
132 * precisely, but we do care whether one is 0
133 * and the other is not. See RFC 2181, Section
134 * 5.2. */
135
136 if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0))
137 return -EINVAL22;
138 }
139 }
140
141 return dns_answer_add_raw(a, rr, ifindex, flags);
142}
143
144static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
145 DnsResourceRecord *rr;
146 DnsAnswerFlags flags;
147 int ifindex, r;
148
149 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, b)for (size_t __unique_prefix_i39 = ({ (rr) = ((b) && (
b)->n_rrs > 0) ? (b)->items[0].rr : ((void*)0); (ifindex
) = ((b) && (b)->n_rrs > 0) ? (b)->items[0].
ifindex : 0; (flags) = ((b) && (b)->n_rrs > 0) ?
(b)->items[0].flags : 0; 0; }); (b) && (__unique_prefix_i39
< (b)->n_rrs); __unique_prefix_i39++, (rr) = ((__unique_prefix_i39
< (b)->n_rrs) ? (b)->items[__unique_prefix_i39].rr :
((void*)0)), (ifindex) = ((__unique_prefix_i39 < (b)->
n_rrs) ? (b)->items[__unique_prefix_i39].ifindex : 0), (flags
) = ((__unique_prefix_i39 < (b)->n_rrs) ? (b)->items
[__unique_prefix_i39].flags : 0))
{
150 r = dns_answer_add(a, rr, ifindex, flags);
151 if (r < 0)
152 return r;
153 }
154
155 return 0;
156}
157
158int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
159 int r;
160
161 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 161, __PRETTY_FUNCTION__); } while (0)
;
162 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-answer.c"
, 162, __PRETTY_FUNCTION__); } while (0)
;
163
164 r = dns_answer_reserve_or_clone(a, 1);
165 if (r < 0)
166 return r;
167
168 return dns_answer_add(*a, rr, ifindex, flags);
169}
170
171int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) {
172 _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *soa = NULL((void*)0);
173
174 soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name);
175 if (!soa)
176 return -ENOMEM12;
177
178 soa->ttl = ttl;
179
180 soa->soa.mname = strdup(name);
181 if (!soa->soa.mname)
182 return -ENOMEM12;
183
184 soa->soa.rname = strappend("root.", name);
185 if (!soa->soa.rname)
186 return -ENOMEM12;
187
188 soa->soa.serial = 1;
189 soa->soa.refresh = 1;
190 soa->soa.retry = 1;
191 soa->soa.expire = 1;
192 soa->soa.minimum = ttl;
193
194 return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED);
195}
196
197int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
198 DnsAnswerFlags flags = 0, i_flags;
199 DnsResourceRecord *i;
200 bool_Bool found = false0;
201 int r;
202
203 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 203, __PRETTY_FUNCTION__); } while (0)
;
204
205 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a)for (size_t __unique_prefix_i40 = ({ (i) = ((a) && (a
)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); (i_flags
) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].
flags : 0; 0; }); (a) && (__unique_prefix_i40 < (a
)->n_rrs); __unique_prefix_i40++, (i) = ((__unique_prefix_i40
< (a)->n_rrs) ? (a)->items[__unique_prefix_i40].rr :
((void*)0)), (i_flags) = ((__unique_prefix_i40 < (a)->
n_rrs) ? (a)->items[__unique_prefix_i40].flags : 0))
{
206 r = dns_resource_key_match_rr(key, i, NULL((void*)0));
207 if (r < 0)
208 return r;
209 if (r == 0)
210 continue;
211
212 if (!ret_flags)
213 return 1;
214
215 if (found)
216 flags &= i_flags;
217 else {
218 flags = i_flags;
219 found = true1;
220 }
221 }
222
223 if (ret_flags)
224 *ret_flags = flags;
225
226 return found;
227}
228
229int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *ret_flags) {
230 DnsAnswerFlags flags = 0, i_flags;
231 DnsResourceRecord *i;
232 bool_Bool found = false0;
233 int r;
234
235 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-answer.c"
, 235, __PRETTY_FUNCTION__); } while (0)
;
236
237 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a)for (size_t __unique_prefix_i41 = ({ (i) = ((a) && (a
)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); (i_flags
) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].
flags : 0; 0; }); (a) && (__unique_prefix_i41 < (a
)->n_rrs); __unique_prefix_i41++, (i) = ((__unique_prefix_i41
< (a)->n_rrs) ? (a)->items[__unique_prefix_i41].rr :
((void*)0)), (i_flags) = ((__unique_prefix_i41 < (a)->
n_rrs) ? (a)->items[__unique_prefix_i41].flags : 0))
{
238 r = dns_resource_record_equal(i, rr);
239 if (r < 0)
240 return r;
241 if (r == 0)
242 continue;
243
244 if (!ret_flags)
245 return 1;
246
247 if (found)
248 flags &= i_flags;
249 else {
250 flags = i_flags;
251 found = true1;
252 }
253 }
254
255 if (ret_flags)
256 *ret_flags = flags;
257
258 return found;
259}
260
261int dns_answer_contains_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
262 DnsAnswerFlags flags = 0, i_flags;
263 DnsResourceRecord *i;
264 bool_Bool found = false0;
265 int r;
266
267 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 267, __PRETTY_FUNCTION__); } while (0)
;
268
269 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a)for (size_t __unique_prefix_i42 = ({ (i) = ((a) && (a
)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); (i_flags
) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].
flags : 0; 0; }); (a) && (__unique_prefix_i42 < (a
)->n_rrs); __unique_prefix_i42++, (i) = ((__unique_prefix_i42
< (a)->n_rrs) ? (a)->items[__unique_prefix_i42].rr :
((void*)0)), (i_flags) = ((__unique_prefix_i42 < (a)->
n_rrs) ? (a)->items[__unique_prefix_i42].flags : 0))
{
270 r = dns_resource_key_equal(i->key, key);
271 if (r < 0)
272 return r;
273 if (r == 0)
274 continue;
275
276 if (!ret_flags)
277 return true1;
278
279 if (found)
280 flags &= i_flags;
281 else {
282 flags = i_flags;
283 found = true1;
284 }
285 }
286
287 if (ret_flags)
288 *ret_flags = flags;
289
290 return found;
291}
292
293int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
294 DnsResourceRecord *i;
295
296 DNS_ANSWER_FOREACH(i, a)for (size_t __unique_prefix_i43 = ({ (i) = ((a) && (a
)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); 0; })
; (a) && (__unique_prefix_i43 < (a)->n_rrs); __unique_prefix_i43
++, (i) = (__unique_prefix_i43 < (a)->n_rrs ? (a)->items
[__unique_prefix_i43].rr : ((void*)0)))
{
297 if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TYPE_NSEC, DNS_TYPE_NSEC3})/sizeof(int
)]; switch(i->key->type) { case DNS_TYPE_NSEC: case DNS_TYPE_NSEC3
: _found = 1; break; default: break; } _found; })
)
298 return true1;
299 }
300
301 return false0;
302}
303
304int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
305 DnsResourceRecord *rr;
306 int r;
307
308 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
309
310 DNS_ANSWER_FOREACH(rr, answer)for (size_t __unique_prefix_i44 = ({ (rr) = ((answer) &&
(answer)->n_rrs > 0) ? (answer)->items[0].rr : ((void
*)0); 0; }); (answer) && (__unique_prefix_i44 < (answer
)->n_rrs); __unique_prefix_i44++, (rr) = (__unique_prefix_i44
< (answer)->n_rrs ? (answer)->items[__unique_prefix_i44
].rr : ((void*)0)))
{
311 const char *p;
312
313 if (rr->key->type != DNS_TYPE_NSEC3)
314 continue;
315
316 p = dns_resource_key_name(rr->key);
317 r = dns_name_parent(&p);
318 if (r < 0)
319 return r;
320 if (r == 0)
321 continue;
322
323 r = dns_name_equal(p, zone);
324 if (r != 0)
325 return r;
326 }
327
328 return false0;
329}
330
331int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
332 DnsResourceRecord *rr, *soa = NULL((void*)0);
333 DnsAnswerFlags rr_flags, soa_flags = 0;
334 int r;
335
336 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 336, __PRETTY_FUNCTION__); } while (0)
;
337
338 /* For a SOA record we can never find a matching SOA record */
339 if (key->type == DNS_TYPE_SOA)
340 return 0;
341
342 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a)for (size_t __unique_prefix_i45 = ({ (rr) = ((a) && (
a)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); (rr_flags
) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].
flags : 0; 0; }); (a) && (__unique_prefix_i45 < (a
)->n_rrs); __unique_prefix_i45++, (rr) = ((__unique_prefix_i45
< (a)->n_rrs) ? (a)->items[__unique_prefix_i45].rr :
((void*)0)), (rr_flags) = ((__unique_prefix_i45 < (a)->
n_rrs) ? (a)->items[__unique_prefix_i45].flags : 0))
{
343 r = dns_resource_key_match_soa(key, rr->key);
344 if (r < 0)
345 return r;
346 if (r > 0) {
347
348 if (soa) {
349 r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key));
350 if (r < 0)
351 return r;
352 if (r > 0)
353 continue;
354 }
355
356 soa = rr;
357 soa_flags = rr_flags;
358 }
359 }
360
361 if (!soa)
362 return 0;
363
364 if (ret)
365 *ret = soa;
366 if (flags)
367 *flags = soa_flags;
368
369 return 1;
370}
371
372int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
373 DnsResourceRecord *rr;
374 DnsAnswerFlags rr_flags;
375 int r;
376
377 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 377, __PRETTY_FUNCTION__); } while (0)
;
378
379 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
380 if (!dns_type_may_redirect(key->type))
381 return 0;
382
383 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a)for (size_t __unique_prefix_i46 = ({ (rr) = ((a) && (
a)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); (rr_flags
) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].
flags : 0; 0; }); (a) && (__unique_prefix_i46 < (a
)->n_rrs); __unique_prefix_i46++, (rr) = ((__unique_prefix_i46
< (a)->n_rrs) ? (a)->items[__unique_prefix_i46].rr :
((void*)0)), (rr_flags) = ((__unique_prefix_i46 < (a)->
n_rrs) ? (a)->items[__unique_prefix_i46].flags : 0))
{
384 r = dns_resource_key_match_cname_or_dname(key, rr->key, NULL((void*)0));
385 if (r < 0)
386 return r;
387 if (r > 0) {
388 if (ret)
389 *ret = rr;
390 if (flags)
391 *flags = rr_flags;
392 return 1;
393 }
394 }
395
396 return 0;
397}
398
399int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) {
400 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *k = NULL((void*)0);
401 int r;
402
403 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-answer.c"
, 403, __PRETTY_FUNCTION__); } while (0)
;
404
405 if (dns_answer_size(a) <= 0) {
406 *ret = dns_answer_ref(b);
407 return 0;
408 }
409
410 if (dns_answer_size(b) <= 0) {
411 *ret = dns_answer_ref(a);
412 return 0;
413 }
414
415 k = dns_answer_new(a->n_rrs + b->n_rrs);
416 if (!k)
417 return -ENOMEM12;
418
419 r = dns_answer_add_raw_all(k, a);
420 if (r < 0)
421 return r;
422
423 r = dns_answer_add_all(k, b);
424 if (r < 0)
425 return r;
426
427 *ret = TAKE_PTR(k)({ typeof(k) _ptr_ = (k); (k) = ((void*)0); _ptr_; });
428
429 return 0;
430}
431
432int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) {
433 DnsAnswer *merged;
434 int r;
435
436 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 436, __PRETTY_FUNCTION__); } while (0)
;
437
438 r = dns_answer_merge(*a, b, &merged);
439 if (r < 0)
440 return r;
441
442 dns_answer_unref(*a);
443 *a = merged;
444
445 return 0;
446}
447
448int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
449 bool_Bool found = false0, other = false0;
450 DnsResourceRecord *rr;
451 size_t i;
452 int r;
453
454 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 454, __PRETTY_FUNCTION__); } while (0)
;
455 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 455, __PRETTY_FUNCTION__); } while (0)
;
456
457 /* Remove all entries matching the specified key from *a */
458
459 DNS_ANSWER_FOREACH(rr, *a)for (size_t __unique_prefix_i47 = ({ (rr) = ((*a) && (
*a)->n_rrs > 0) ? (*a)->items[0].rr : ((void*)0); 0;
}); (*a) && (__unique_prefix_i47 < (*a)->n_rrs
); __unique_prefix_i47++, (rr) = (__unique_prefix_i47 < (*
a)->n_rrs ? (*a)->items[__unique_prefix_i47].rr : ((void
*)0)))
{
460 r = dns_resource_key_equal(rr->key, key);
461 if (r < 0)
462 return r;
463 if (r > 0)
464 found = true1;
465 else
466 other = true1;
467
468 if (found && other)
469 break;
470 }
471
472 if (!found)
473 return 0;
474
475 if (!other) {
476 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
477 return 1;
478 }
479
480 if ((*a)->n_ref > 1) {
481 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *copy = NULL((void*)0);
482 DnsAnswerFlags flags;
483 int ifindex;
484
485 copy = dns_answer_new((*a)->n_rrs);
486 if (!copy)
487 return -ENOMEM12;
488
489 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a)for (size_t __unique_prefix_i48 = ({ (rr) = ((*a) && (
*a)->n_rrs > 0) ? (*a)->items[0].rr : ((void*)0); (ifindex
) = ((*a) && (*a)->n_rrs > 0) ? (*a)->items[
0].ifindex : 0; (flags) = ((*a) && (*a)->n_rrs >
0) ? (*a)->items[0].flags : 0; 0; }); (*a) && (__unique_prefix_i48
< (*a)->n_rrs); __unique_prefix_i48++, (rr) = ((__unique_prefix_i48
< (*a)->n_rrs) ? (*a)->items[__unique_prefix_i48].rr
: ((void*)0)), (ifindex) = ((__unique_prefix_i48 < (*a)->
n_rrs) ? (*a)->items[__unique_prefix_i48].ifindex : 0), (flags
) = ((__unique_prefix_i48 < (*a)->n_rrs) ? (*a)->items
[__unique_prefix_i48].flags : 0))
{
490 r = dns_resource_key_equal(rr->key, key);
491 if (r < 0)
492 return r;
493 if (r > 0)
494 continue;
495
496 r = dns_answer_add_raw(copy, rr, ifindex, flags);
497 if (r < 0)
498 return r;
499 }
500
501 dns_answer_unref(*a);
502 *a = TAKE_PTR(copy)({ typeof(copy) _ptr_ = (copy); (copy) = ((void*)0); _ptr_; }
)
;
503
504 return 1;
505 }
506
507 /* Only a single reference, edit in-place */
508
509 i = 0;
510 for (;;) {
511 if (i >= (*a)->n_rrs)
512 break;
513
514 r = dns_resource_key_equal((*a)->items[i].rr->key, key);
515 if (r < 0)
516 return r;
517 if (r > 0) {
518 /* Kill this entry */
519
520 dns_resource_record_unref((*a)->items[i].rr);
521 memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
522 (*a)->n_rrs--;
523 continue;
524
525 } else
526 /* Keep this entry */
527 i++;
528 }
529
530 return 1;
531}
532
533int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
534 bool_Bool found = false0, other = false0;
535 DnsResourceRecord *rr;
536 size_t i;
537 int r;
538
539 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 539, __PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'a' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
540 assert(rm)do { if ((__builtin_expect(!!(!(rm)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rm"), "../src/resolve/resolved-dns-answer.c"
, 540, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'rm' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
541
542 /* Remove all entries matching the specified RR from *a */
543
544 DNS_ANSWER_FOREACH(rr, *a)for (size_t __unique_prefix_i49 = ({ (rr) = ((*a) && (
*a)->n_rrs > 0) ? (*a)->items[0].rr : ((void*)0); 0;
}); (*a) && (__unique_prefix_i49 < (*a)->n_rrs
); __unique_prefix_i49++, (rr) = (__unique_prefix_i49 < (*
a)->n_rrs ? (*a)->items[__unique_prefix_i49].rr : ((void
*)0)))
{
7
Assuming the condition is true
8
Assuming field 'n_rrs' is > 0
9
'?' condition is true
10
Loop condition is true. Entering loop body
15
Assuming '__unique_prefix_i15' is < field 'n_rrs'
16
'?' condition is true
17
Loop condition is true. Entering loop body
545 r = dns_resource_record_equal(rr, rm);
546 if (r < 0)
11
Assuming 'r' is >= 0
12
Taking false branch
18
Assuming 'r' is >= 0
19
Taking false branch
547 return r;
548 if (r > 0)
13
Assuming 'r' is <= 0
14
Taking false branch
20
Assuming 'r' is > 0
21
Taking true branch
549 found = true1;
550 else
551 other = true1;
552
553 if (found
14.1
'found' is false
21.1
'found' is true
&& other
21.2
'other' is true
)
22
Taking true branch
554 break;
23
Execution continues on line 557
555 }
556
557 if (!found
23.1
'found' is true
)
24
Taking false branch
558 return 0;
559
560 if (!other
24.1
'other' is true
) {
25
Taking false branch
561 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
562 return 1;
563 }
564
565 if ((*a)->n_ref > 1) {
26
Assuming field 'n_ref' is > 1
27
Taking true branch
566 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *copy = NULL((void*)0);
567 DnsAnswerFlags flags;
568 int ifindex;
569
570 copy = dns_answer_new((*a)->n_rrs);
28
Calling 'dns_answer_new'
32
Returned allocated memory
571 if (!copy
32.1
'copy' is non-null
)
33
Taking false branch
572 return -ENOMEM12;
573
574 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a)for (size_t __unique_prefix_i50 = ({ (rr) = ((*a) && (
*a)->n_rrs > 0) ? (*a)->items[0].rr : ((void*)0); (ifindex
) = ((*a) && (*a)->n_rrs > 0) ? (*a)->items[
0].ifindex : 0; (flags) = ((*a) && (*a)->n_rrs >
0) ? (*a)->items[0].flags : 0; 0; }); (*a) && (__unique_prefix_i50
< (*a)->n_rrs); __unique_prefix_i50++, (rr) = ((__unique_prefix_i50
< (*a)->n_rrs) ? (*a)->items[__unique_prefix_i50].rr
: ((void*)0)), (ifindex) = ((__unique_prefix_i50 < (*a)->
n_rrs) ? (*a)->items[__unique_prefix_i50].ifindex : 0), (flags
) = ((__unique_prefix_i50 < (*a)->n_rrs) ? (*a)->items
[__unique_prefix_i50].flags : 0))
{
34
'?' condition is true
35
'?' condition is true
36
'?' condition is true
37
Loop condition is true. Entering loop body
575 r = dns_resource_record_equal(rr, rm);
576 if (r < 0)
38
Assuming 'r' is < 0
39
Taking true branch
577 return r;
40
Potential leak of memory pointed to by 'copy'
578 if (r > 0)
579 continue;
580
581 r = dns_answer_add_raw(copy, rr, ifindex, flags);
582 if (r < 0)
583 return r;
584 }
585
586 dns_answer_unref(*a);
587 *a = TAKE_PTR(copy)({ typeof(copy) _ptr_ = (copy); (copy) = ((void*)0); _ptr_; }
)
;
588
589 return 1;
590 }
591
592 /* Only a single reference, edit in-place */
593
594 i = 0;
595 for (;;) {
596 if (i >= (*a)->n_rrs)
597 break;
598
599 r = dns_resource_record_equal((*a)->items[i].rr, rm);
600 if (r < 0)
601 return r;
602 if (r > 0) {
603 /* Kill this entry */
604
605 dns_resource_record_unref((*a)->items[i].rr);
606 memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
607 (*a)->n_rrs--;
608 continue;
609
610 } else
611 /* Keep this entry */
612 i++;
613 }
614
615 return 1;
616}
617
618int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
619 DnsResourceRecord *rr_source;
620 int ifindex_source, r;
621 DnsAnswerFlags flags_source;
622
623 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 623, __PRETTY_FUNCTION__); } while (0)
;
624 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 624, __PRETTY_FUNCTION__); } while (0)
;
625
626 /* Copy all RRs matching the specified key from source into *a */
627
628 DNS_ANSWER_FOREACH_FULL(rr_source, ifindex_source, flags_source, source)for (size_t __unique_prefix_i51 = ({ (rr_source) = ((source) &&
(source)->n_rrs > 0) ? (source)->items[0].rr : ((void
*)0); (ifindex_source) = ((source) && (source)->n_rrs
> 0) ? (source)->items[0].ifindex : 0; (flags_source) =
((source) && (source)->n_rrs > 0) ? (source)->
items[0].flags : 0; 0; }); (source) && (__unique_prefix_i51
< (source)->n_rrs); __unique_prefix_i51++, (rr_source)
= ((__unique_prefix_i51 < (source)->n_rrs) ? (source)->
items[__unique_prefix_i51].rr : ((void*)0)), (ifindex_source)
= ((__unique_prefix_i51 < (source)->n_rrs) ? (source)->
items[__unique_prefix_i51].ifindex : 0), (flags_source) = ((__unique_prefix_i51
< (source)->n_rrs) ? (source)->items[__unique_prefix_i51
].flags : 0))
{
629
630 r = dns_resource_key_equal(rr_source->key, key);
631 if (r < 0)
632 return r;
633 if (r == 0)
634 continue;
635
636 /* Make space for at least one entry */
637 r = dns_answer_reserve_or_clone(a, 1);
638 if (r < 0)
639 return r;
640
641 r = dns_answer_add(*a, rr_source, ifindex_source, flags_source|or_flags);
642 if (r < 0)
643 return r;
644 }
645
646 return 0;
647}
648
649int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
650 int r;
651
652 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/resolve/resolved-dns-answer.c"
, 652, __PRETTY_FUNCTION__); } while (0)
;
653 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/resolve/resolved-dns-answer.c"
, 653, __PRETTY_FUNCTION__); } while (0)
;
654 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-answer.c"
, 654, __PRETTY_FUNCTION__); } while (0)
;
655
656 r = dns_answer_copy_by_key(to, *from, key, or_flags);
657 if (r < 0)
658 return r;
659
660 return dns_answer_remove_by_key(from, key);
661}
662
663void dns_answer_order_by_scope(DnsAnswer *a, bool_Bool prefer_link_local) {
664 DnsAnswerItem *items;
665 size_t i, start, end;
666
667 if (!a)
668 return;
669
670 if (a->n_rrs <= 1)
671 return;
672
673 start = 0;
674 end = a->n_rrs-1;
675
676 /* RFC 4795, Section 2.6 suggests we should order entries
677 * depending on whether the sender is a link-local address. */
678
679 items = newa(DnsAnswerItem, a->n_rrs)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(DnsAnswerItem), a->n_rrs))),0))) log_assert_failed_realm(
LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(DnsAnswerItem), a->n_rrs)"
), "../src/resolve/resolved-dns-answer.c", 679, __PRETTY_FUNCTION__
); } while (0); (DnsAnswerItem*) __builtin_alloca (sizeof(DnsAnswerItem
)*(a->n_rrs)); })
;
680 for (i = 0; i < a->n_rrs; i++) {
681
682 if (a->items[i].rr->key->class == DNS_CLASS_IN &&
683 ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET2, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) ||
684 (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET610, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local)))
685 /* Order address records that are not preferred to the end of the array */
686 items[end--] = a->items[i];
687 else
688 /* Order all other records to the beginning of the array */
689 items[start++] = a->items[i];
690 }
691
692 assert(start == end+1)do { if ((__builtin_expect(!!(!(start == end+1)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("start == end+1"), "../src/resolve/resolved-dns-answer.c"
, 692, __PRETTY_FUNCTION__); } while (0)
;
693 memcpy(a->items, items, sizeof(DnsAnswerItem) * a->n_rrs);
694}
695
696int dns_answer_reserve(DnsAnswer **a, size_t n_free) {
697 DnsAnswer *n;
698
699 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 699, __PRETTY_FUNCTION__); } while (0)
;
700
701 if (n_free <= 0)
702 return 0;
703
704 if (*a) {
705 size_t ns;
706
707 if ((*a)->n_ref > 1)
708 return -EBUSY16;
709
710 ns = (*a)->n_rrs + n_free;
711
712 if ((*a)->n_allocated >= ns)
713 return 0;
714
715 /* Allocate more than we need */
716 ns *= 2;
717
718 n = realloc(*a, offsetof(DnsAnswer, items)__builtin_offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns);
719 if (!n)
720 return -ENOMEM12;
721
722 n->n_allocated = ns;
723 } else {
724 n = dns_answer_new(n_free);
725 if (!n)
726 return -ENOMEM12;
727 }
728
729 *a = n;
730 return 0;
731}
732
733int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) {
734 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *n = NULL((void*)0);
735 int r;
736
737 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-answer.c"
, 737, __PRETTY_FUNCTION__); } while (0)
;
738
739 /* Tries to extend the DnsAnswer object. And if that's not
740 * possible, since we are not the sole owner, then allocate a
741 * new, appropriately sized one. Either way, after this call
742 * the object will only have a single reference, and has room
743 * for at least the specified number of RRs. */
744
745 r = dns_answer_reserve(a, n_free);
746 if (r != -EBUSY16)
747 return r;
748
749 assert(*a)do { if ((__builtin_expect(!!(!(*a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("*a"), "../src/resolve/resolved-dns-answer.c"
, 749, __PRETTY_FUNCTION__); } while (0)
;
750
751 n = dns_answer_new(((*a)->n_rrs + n_free) * 2);
752 if (!n)
753 return -ENOMEM12;
754
755 r = dns_answer_add_raw_all(n, *a);
756 if (r < 0)
757 return r;
758
759 dns_answer_unref(*a);
760 *a = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; });
761
762 return 0;
763}
764
765void dns_answer_dump(DnsAnswer *answer, FILE *f) {
766 DnsResourceRecord *rr;
767 DnsAnswerFlags flags;
768 int ifindex;
769
770 if (!f)
771 f = stdoutstdout;
772
773 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer)for (size_t __unique_prefix_i52 = ({ (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_i52 < (answer
)->n_rrs); __unique_prefix_i52++, (rr) = ((__unique_prefix_i52
< (answer)->n_rrs) ? (answer)->items[__unique_prefix_i52
].rr : ((void*)0)), (ifindex) = ((__unique_prefix_i52 < (answer
)->n_rrs) ? (answer)->items[__unique_prefix_i52].ifindex
: 0), (flags) = ((__unique_prefix_i52 < (answer)->n_rrs
) ? (answer)->items[__unique_prefix_i52].flags : 0))
{
774 const char *t;
775
776 fputc('\t', f);
777
778 t = dns_resource_record_to_string(rr);
779 if (!t) {
780 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/resolve/resolved-dns-answer.c"
, 780, __func__)
;
781 continue;
782 }
783
784 fputs(t, f);
785
786 if (ifindex != 0 || flags & (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE|DNS_ANSWER_SHARED_OWNER))
787 fputs("\t;", f);
788
789 if (ifindex != 0)
790 printf(" ifindex=%i", ifindex);
791 if (flags & DNS_ANSWER_AUTHENTICATED)
792 fputs(" authenticated", f);
793 if (flags & DNS_ANSWER_CACHEABLE)
794 fputs(" cachable", f);
795 if (flags & DNS_ANSWER_SHARED_OWNER)
796 fputs(" shared-owner", f);
797
798 fputc('\n', f);
799 }
800}
801
802bool_Bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
803 DnsResourceRecord *rr;
804 int r;
805
806 assert(cname)do { if ((__builtin_expect(!!(!(cname)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("cname"), "../src/resolve/resolved-dns-answer.c"
, 806, __PRETTY_FUNCTION__); } while (0)
;
807
808 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
809 * synthesized from it */
810
811 if (cname->key->type != DNS_TYPE_CNAME)
812 return 0;
813
814 DNS_ANSWER_FOREACH(rr, a)for (size_t __unique_prefix_i53 = ({ (rr) = ((a) && (
a)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); 0; }
); (a) && (__unique_prefix_i53 < (a)->n_rrs); __unique_prefix_i53
++, (rr) = (__unique_prefix_i53 < (a)->n_rrs ? (a)->
items[__unique_prefix_i53].rr : ((void*)0)))
{
815 _cleanup_free___attribute__((cleanup(freep))) char *n = NULL((void*)0);
816
817 if (rr->key->type != DNS_TYPE_DNAME)
818 continue;
819 if (rr->key->class != cname->key->class)
820 continue;
821
822 r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n);
823 if (r < 0)
824 return r;
825 if (r == 0)
826 continue;
827
828 r = dns_name_equal(n, dns_resource_key_name(cname->key));
829 if (r < 0)
830 return r;
831 if (r > 0)
832 return 1;
833
834 }
835
836 return 0;
837}