Bug Summary

File:build-scan/../src/resolve/resolved-dns-query.c
Warning:line 367, column 17
Use of memory after it is freed

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-query.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-query.c

../src/resolve/resolved-dns-query.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "alloc-util.h"
4#include "dns-domain.h"
5#include "dns-type.h"
6#include "hostname-util.h"
7#include "local-addresses.h"
8#include "resolved-dns-query.h"
9#include "resolved-dns-synthesize.h"
10#include "resolved-etc-hosts.h"
11#include "string-util.h"
12
13#define CNAME_MAX8 8
14#define QUERIES_MAX2048 2048
15#define AUXILIARY_QUERIES_MAX64 64
16
17static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
18 DnsQueryCandidate *c;
19
20 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-query.c"
, 20, __PRETTY_FUNCTION__); } while (0)
;
21 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 21, __PRETTY_FUNCTION__); } while (0)
;
22 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-query.c"
, 22, __PRETTY_FUNCTION__); } while (0)
;
23
24 c = new0(DnsQueryCandidate, 1)((DnsQueryCandidate*) calloc((1), sizeof(DnsQueryCandidate)));
25 if (!c)
26 return -ENOMEM12;
27
28 c->query = q;
29 c->scope = s;
30
31 LIST_PREPEND(candidates_by_query, q->candidates, c)do { typeof(*(q->candidates)) **_head = &(q->candidates
), *_item = (c); do { if ((__builtin_expect(!!(!(_item)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-query.c"
, 31, __PRETTY_FUNCTION__); } while (0); if ((_item->candidates_by_query_next
= *_head)) _item->candidates_by_query_next->candidates_by_query_prev
= _item; _item->candidates_by_query_prev = ((void*)0); *_head
= _item; } while (0)
;
32 LIST_PREPEND(candidates_by_scope, s->query_candidates, c)do { typeof(*(s->query_candidates)) **_head = &(s->
query_candidates), *_item = (c); do { if ((__builtin_expect(!
!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, (
"_item"), "../src/resolve/resolved-dns-query.c", 32, __PRETTY_FUNCTION__
); } while (0); if ((_item->candidates_by_scope_next = *_head
)) _item->candidates_by_scope_next->candidates_by_scope_prev
= _item; _item->candidates_by_scope_prev = ((void*)0); *_head
= _item; } while (0)
;
33
34 *ret = c;
35 return 0;
36}
37
38static void dns_query_candidate_stop(DnsQueryCandidate *c) {
39 DnsTransaction *t;
40
41 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 41, __PRETTY_FUNCTION__); } while (0)
;
42
43 while ((t = set_steal_first(c->transactions))) {
44 set_remove(t->notify_query_candidates, c);
45 set_remove(t->notify_query_candidates_done, c);
46 dns_transaction_gc(t);
47 }
48}
49
50DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
51
52 if (!c)
53 return NULL((void*)0);
54
55 dns_query_candidate_stop(c);
56
57 set_free(c->transactions);
58 dns_search_domain_unref(c->search_domain);
59
60 if (c->query)
61 LIST_REMOVE(candidates_by_query, c->query->candidates, c)do { typeof(*(c->query->candidates)) **_head = &(c->
query->candidates), *_item = (c); do { if ((__builtin_expect
(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD,
("_item"), "../src/resolve/resolved-dns-query.c", 61, __PRETTY_FUNCTION__
); } while (0); if (_item->candidates_by_query_next) _item
->candidates_by_query_next->candidates_by_query_prev = _item
->candidates_by_query_prev; if (_item->candidates_by_query_prev
) _item->candidates_by_query_prev->candidates_by_query_next
= _item->candidates_by_query_next; else { do { if ((__builtin_expect
(!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("*_head == _item"), "../src/resolve/resolved-dns-query.c",
61, __PRETTY_FUNCTION__); } while (0); *_head = _item->candidates_by_query_next
; } _item->candidates_by_query_next = _item->candidates_by_query_prev
= ((void*)0); } while (0)
;
62
63 if (c->scope)
64 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c)do { typeof(*(c->scope->query_candidates)) **_head = &
(c->scope->query_candidates), *_item = (c); do { if ((__builtin_expect
(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD,
("_item"), "../src/resolve/resolved-dns-query.c", 64, __PRETTY_FUNCTION__
); } while (0); if (_item->candidates_by_scope_next) _item
->candidates_by_scope_next->candidates_by_scope_prev = _item
->candidates_by_scope_prev; if (_item->candidates_by_scope_prev
) _item->candidates_by_scope_prev->candidates_by_scope_next
= _item->candidates_by_scope_next; else { do { if ((__builtin_expect
(!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("*_head == _item"), "../src/resolve/resolved-dns-query.c",
64, __PRETTY_FUNCTION__); } while (0); *_head = _item->candidates_by_scope_next
; } _item->candidates_by_scope_next = _item->candidates_by_scope_prev
= ((void*)0); } while (0)
;
65
66 return mfree(c);
67}
68
69static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
70 DnsSearchDomain *next = NULL((void*)0);
71
72 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 72, __PRETTY_FUNCTION__); } while (0)
;
73
74 if (c->search_domain && c->search_domain->linked)
75 next = c->search_domain->domains_next;
76 else
77 next = dns_scope_get_search_domains(c->scope);
78
79 for (;;) {
80 if (!next) /* We hit the end of the list */
81 return 0;
82
83 if (!next->route_only)
84 break;
85
86 /* Skip over route-only domains */
87 next = next->domains_next;
88 }
89
90 dns_search_domain_unref(c->search_domain);
91 c->search_domain = dns_search_domain_ref(next);
92
93 return 1;
94}
95
96static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
97 DnsTransaction *t;
98 int r;
99
100 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 100, __PRETTY_FUNCTION__); } while (0)
;
101 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-query.c"
, 101, __PRETTY_FUNCTION__); } while (0)
;
102
103 t = dns_scope_find_transaction(c->scope, key, true1);
104 if (!t) {
105 r = dns_transaction_new(&t, c->scope, key);
106 if (r < 0)
107 return r;
108 } else {
109 if (set_contains(c->transactions, t))
110 return 0;
111 }
112
113 r = set_ensure_allocated(&c->transactions, NULL)internal_set_ensure_allocated(&c->transactions, ((void
*)0) )
;
114 if (r < 0)
115 goto gc;
116
117 r = set_ensure_allocated(&t->notify_query_candidates, NULL)internal_set_ensure_allocated(&t->notify_query_candidates
, ((void*)0) )
;
118 if (r < 0)
119 goto gc;
120
121 r = set_ensure_allocated(&t->notify_query_candidates_done, NULL)internal_set_ensure_allocated(&t->notify_query_candidates_done
, ((void*)0) )
;
122 if (r < 0)
123 goto gc;
124
125 r = set_put(t->notify_query_candidates, c);
126 if (r < 0)
127 goto gc;
128
129 r = set_put(c->transactions, t);
130 if (r < 0) {
131 (void) set_remove(t->notify_query_candidates, c);
132 goto gc;
133 }
134
135 t->clamp_ttl = c->query->clamp_ttl;
136 return 1;
137
138gc:
139 dns_transaction_gc(t);
140 return r;
141}
142
143static int dns_query_candidate_go(DnsQueryCandidate *c) {
144 DnsTransaction *t;
145 Iterator i;
146 int r;
147 unsigned n = 0;
148
149 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 149, __PRETTY_FUNCTION__); } while (0)
;
150
151 /* Start the transactions that are not started yet */
152 SET_FOREACH(t, c->transactions, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); set_iterate((c->transactions), &
(i), (void**)&(t)); )
{
153 if (t->state != DNS_TRANSACTION_NULL)
154 continue;
155
156 r = dns_transaction_go(t);
157 if (r < 0)
158 return r;
159
160 n++;
161 }
162
163 /* If there was nothing to start, then let's proceed immediately */
164 if (n == 0)
165 dns_query_candidate_notify(c);
166
167 return 0;
168}
169
170static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
171 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
172 DnsTransaction *t;
173 Iterator i;
174
175 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 175, __PRETTY_FUNCTION__); } while (0)
;
176
177 if (c->error_code != 0)
178 return DNS_TRANSACTION_ERRNO;
179
180 SET_FOREACH(t, c->transactions, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); set_iterate((c->transactions), &
(i), (void**)&(t)); )
{
181
182 switch (t->state) {
183
184 case DNS_TRANSACTION_NULL:
185 /* If there's a NULL transaction pending, then
186 * this means not all transactions where
187 * started yet, and we were called from within
188 * the stackframe that is supposed to start
189 * remaining transactions. In this case,
190 * simply claim the candidate is pending. */
191
192 case DNS_TRANSACTION_PENDING:
193 case DNS_TRANSACTION_VALIDATING:
194 /* If there's one transaction currently in
195 * VALIDATING state, then this means there's
196 * also one in PENDING state, hence we can
197 * return PENDING immediately. */
198 return DNS_TRANSACTION_PENDING;
199
200 case DNS_TRANSACTION_SUCCESS:
201 state = t->state;
202 break;
203
204 default:
205 if (state != DNS_TRANSACTION_SUCCESS)
206 state = t->state;
207
208 break;
209 }
210 }
211
212 return state;
213}
214
215static bool_Bool dns_query_candidate_is_routable(DnsQueryCandidate *c, uint16_t type) {
216 int family;
217
218 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 218, __PRETTY_FUNCTION__); } while (0)
;
219
220 /* Checks whether the specified RR type matches an address family that is routable on the link(s) the scope of
221 * this candidate belongs to. Specifically, whether there's a routable IPv4 address on it if we query an A RR,
222 * or a routable IPv6 address if we query an AAAA RR. */
223
224 if (!c->query->suppress_unroutable_family)
225 return true1;
226
227 if (c->scope->protocol != DNS_PROTOCOL_DNS)
228 return true1;
229
230 family = dns_type_to_af(type);
231 if (family < 0)
232 return true1;
233
234 if (c->scope->link)
235 return link_relevant(c->scope->link, family, false0);
236 else
237 return manager_routable(c->scope->manager, family);
238}
239
240static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
241 DnsQuestion *question;
242 DnsResourceKey *key;
243 int n = 0, r;
244
245 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 245, __PRETTY_FUNCTION__); } while (0)
;
246
247 dns_query_candidate_stop(c);
248
249 question = dns_query_question_for_protocol(c->query, c->scope->protocol);
250
251 /* Create one transaction per question key */
252 DNS_QUESTION_FOREACH(key, question)for (size_t __unique_prefix_i13 = ({ (key) = ((question) &&
(question)->n_keys > 0) ? (question)->keys[0] : ((void
*)0); 0; }); (question) && (__unique_prefix_i13 < (
question)->n_keys); __unique_prefix_i13++, (key) = (__unique_prefix_i13
< (question)->n_keys ? (question)->keys[__unique_prefix_i13
] : ((void*)0)))
{
253 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *new_key = NULL((void*)0);
254 DnsResourceKey *qkey;
255
256 if (!dns_query_candidate_is_routable(c, key->type))
257 continue;
258
259 if (c->search_domain) {
260 r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
261 if (r < 0)
262 goto fail;
263
264 qkey = new_key;
265 } else
266 qkey = key;
267
268 if (!dns_scope_good_key(c->scope, qkey))
269 continue;
270
271 r = dns_query_candidate_add_transaction(c, qkey);
272 if (r < 0)
273 goto fail;
274
275 n++;
276 }
277
278 return n;
279
280fail:
281 dns_query_candidate_stop(c);
282 return r;
283}
284
285void dns_query_candidate_notify(DnsQueryCandidate *c) {
286 DnsTransactionState state;
287 int r;
288
289 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/resolve/resolved-dns-query.c"
, 289, __PRETTY_FUNCTION__); } while (0)
;
290
291 state = dns_query_candidate_state(c);
292
293 if (DNS_TRANSACTION_IS_LIVE(state)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING
, DNS_TRANSACTION_VALIDATING})/sizeof(int)]; switch((state)) {
case DNS_TRANSACTION_NULL: case DNS_TRANSACTION_PENDING: case
DNS_TRANSACTION_VALIDATING: _found = 1; break; default: break
; } _found; })
)
294 return;
295
296 if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
297
298 r = dns_query_candidate_next_search_domain(c);
299 if (r < 0)
300 goto fail;
301
302 if (r > 0) {
303 /* OK, there's another search domain to try, let's do so. */
304
305 r = dns_query_candidate_setup_transactions(c);
306 if (r < 0)
307 goto fail;
308
309 if (r > 0) {
310 /* New transactions where queued. Start them and wait */
311
312 r = dns_query_candidate_go(c);
313 if (r < 0)
314 goto fail;
315
316 return;
317 }
318 }
319
320 }
321
322 dns_query_ready(c->query);
323 return;
324
325fail:
326 log_warning_errno(r, "Failed to follow search domains: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-query.c", 326, __func__, "Failed to follow search domains: %m"
) : -abs(_e); })
;
327 c->error_code = r;
328 dns_query_ready(c->query);
329}
330
331static void dns_query_stop(DnsQuery *q) {
332 DnsQueryCandidate *c;
333
334 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 334, __PRETTY_FUNCTION__); } while (0)
;
335
336 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
337
338 LIST_FOREACH(candidates_by_query, c, q->candidates)for ((c) = (q->candidates); (c); (c) = (c)->candidates_by_query_next
)
339 dns_query_candidate_stop(c);
340}
341
342static void dns_query_free_candidates(DnsQuery *q) {
343 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 343, __PRETTY_FUNCTION__); } while (0)
;
344
345 while (q->candidates)
346 dns_query_candidate_free(q->candidates);
347}
348
349static void dns_query_reset_answer(DnsQuery *q) {
350 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 350, __PRETTY_FUNCTION__); } while (0)
;
351
352 q->answer = dns_answer_unref(q->answer);
353 q->answer_rcode = 0;
354 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
355 q->answer_errno = 0;
356 q->answer_authenticated = false0;
357 q->answer_protocol = _DNS_PROTOCOL_INVALID;
358 q->answer_family = AF_UNSPEC0;
359 q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
360}
361
362DnsQuery *dns_query_free(DnsQuery *q) {
363 if (!q
4.1
'q' is non-null
7.1
'q' is non-null
10.1
'q' is non-null
13.1
'q' is non-null
4.1
'q' is non-null
7.1
'q' is non-null
10.1
'q' is non-null
13.1
'q' is non-null
)
1
Assuming 'q' is non-null
2
Taking false branch
5
Taking false branch
8
Taking false branch
11
Taking false branch
14
Taking false branch
364 return NULL((void*)0);
365
366 while (q->auxiliary_queries)
3
Loop condition is true. Entering loop body
6
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
12
Loop condition is true. Entering loop body
15
Loop condition is false. Execution continues on line 369
26
Loop condition is true. Entering loop body
367 dns_query_free(q->auxiliary_queries);
4
Calling 'dns_query_free'
7
Calling 'dns_query_free'
10
Calling 'dns_query_free'
13
Calling 'dns_query_free'
25
Returning; memory was released via 1st parameter
27
Use of memory after it is freed
368
369 if (q->auxiliary_for) {
16
Assuming field 'auxiliary_for' is null
17
Taking false branch
370 assert(q->auxiliary_for->n_auxiliary_queries > 0)do { if ((__builtin_expect(!!(!(q->auxiliary_for->n_auxiliary_queries
> 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("q->auxiliary_for->n_auxiliary_queries > 0"
), "../src/resolve/resolved-dns-query.c", 370, __PRETTY_FUNCTION__
); } while (0)
;
371 q->auxiliary_for->n_auxiliary_queries--;
372 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q)do { typeof(*(q->auxiliary_for->auxiliary_queries)) **_head
= &(q->auxiliary_for->auxiliary_queries), *_item =
(q); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-query.c"
, 372, __PRETTY_FUNCTION__); } while (0); if (_item->auxiliary_queries_next
) _item->auxiliary_queries_next->auxiliary_queries_prev
= _item->auxiliary_queries_prev; if (_item->auxiliary_queries_prev
) _item->auxiliary_queries_prev->auxiliary_queries_next
= _item->auxiliary_queries_next; else { do { if ((__builtin_expect
(!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("*_head == _item"), "../src/resolve/resolved-dns-query.c",
372, __PRETTY_FUNCTION__); } while (0); *_head = _item->auxiliary_queries_next
; } _item->auxiliary_queries_next = _item->auxiliary_queries_prev
= ((void*)0); } while (0)
;
373 }
374
375 dns_query_free_candidates(q);
376
377 dns_question_unref(q->question_idna);
378 dns_question_unref(q->question_utf8);
379
380 dns_query_reset_answer(q);
381
382 sd_bus_message_unref(q->request);
383 sd_bus_track_unref(q->bus_track);
384
385 dns_packet_unref(q->request_dns_packet);
386 dns_packet_unref(q->reply_dns_packet);
387
388 if (q->request_dns_stream) {
18
Assuming field 'request_dns_stream' is null
19
Taking false branch
389 /* Detach the stream from our query, in case something else keeps a reference to it. */
390 q->request_dns_stream->complete = NULL((void*)0);
391 q->request_dns_stream->on_packet = NULL((void*)0);
392 q->request_dns_stream->query = NULL((void*)0);
393 dns_stream_unref(q->request_dns_stream);
394 }
395
396 free(q->request_address_string);
397
398 if (q->manager) {
20
Assuming field 'manager' is null
21
Taking false branch
399 LIST_REMOVE(queries, q->manager->dns_queries, q)do { typeof(*(q->manager->dns_queries)) **_head = &
(q->manager->dns_queries), *_item = (q); do { if ((__builtin_expect
(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD,
("_item"), "../src/resolve/resolved-dns-query.c", 399, __PRETTY_FUNCTION__
); } while (0); if (_item->queries_next) _item->queries_next
->queries_prev = _item->queries_prev; if (_item->queries_prev
) _item->queries_prev->queries_next = _item->queries_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/resolve/resolved-dns-query.c", 399, __PRETTY_FUNCTION__
); } while (0); *_head = _item->queries_next; } _item->
queries_next = _item->queries_prev = ((void*)0); } while (
0)
;
400 q->manager->n_dns_queries--;
401 }
402
403 return mfree(q);
22
Calling 'mfree'
24
Returning; memory was released via 1st parameter
404}
405
406int dns_query_new(
407 Manager *m,
408 DnsQuery **ret,
409 DnsQuestion *question_utf8,
410 DnsQuestion *question_idna,
411 int ifindex,
412 uint64_t flags) {
413
414 _cleanup_(dns_query_freep)__attribute__((cleanup(dns_query_freep))) DnsQuery *q = NULL((void*)0);
415 DnsResourceKey *key;
416 bool_Bool good = false0;
417 int r;
418 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)
];
419
420 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-dns-query.c"
, 420, __PRETTY_FUNCTION__); } while (0)
;
421
422 if (dns_question_size(question_utf8) > 0) {
423 r = dns_question_is_valid_for_query(question_utf8);
424 if (r < 0)
425 return r;
426 if (r == 0)
427 return -EINVAL22;
428
429 good = true1;
430 }
431
432 /* If the IDNA and UTF8 questions are the same, merge their references */
433 r = dns_question_is_equal(question_idna, question_utf8);
434 if (r < 0)
435 return r;
436 if (r > 0)
437 question_idna = question_utf8;
438 else {
439 if (dns_question_size(question_idna) > 0) {
440 r = dns_question_is_valid_for_query(question_idna);
441 if (r < 0)
442 return r;
443 if (r == 0)
444 return -EINVAL22;
445
446 good = true1;
447 }
448 }
449
450 if (!good) /* don't allow empty queries */
451 return -EINVAL22;
452
453 if (m->n_dns_queries >= QUERIES_MAX2048)
454 return -EBUSY16;
455
456 q = new0(DnsQuery, 1)((DnsQuery*) calloc((1), sizeof(DnsQuery)));
457 if (!q)
458 return -ENOMEM12;
459
460 q->question_utf8 = dns_question_ref(question_utf8);
461 q->question_idna = dns_question_ref(question_idna);
462 q->ifindex = ifindex;
463 q->flags = flags;
464 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
465 q->answer_protocol = _DNS_PROTOCOL_INVALID;
466 q->answer_family = AF_UNSPEC0;
467
468 /* First dump UTF8 question */
469 DNS_QUESTION_FOREACH(key, question_utf8)for (size_t __unique_prefix_i14 = ({ (key) = ((question_utf8)
&& (question_utf8)->n_keys > 0) ? (question_utf8
)->keys[0] : ((void*)0); 0; }); (question_utf8) &&
(__unique_prefix_i14 < (question_utf8)->n_keys); __unique_prefix_i14
++, (key) = (__unique_prefix_i14 < (question_utf8)->n_keys
? (question_utf8)->keys[__unique_prefix_i14] : ((void*)0)
))
470 log_debug("Looking up RR 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-query.c", 471, __func__, "Looking up RR for %s."
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
471 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-query.c", 471, __func__, "Looking up RR for %s."
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
472
473 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
474 DNS_QUESTION_FOREACH(key, question_idna)for (size_t __unique_prefix_i15 = ({ (key) = ((question_idna)
&& (question_idna)->n_keys > 0) ? (question_idna
)->keys[0] : ((void*)0); 0; }); (question_idna) &&
(__unique_prefix_i15 < (question_idna)->n_keys); __unique_prefix_i15
++, (key) = (__unique_prefix_i15 < (question_idna)->n_keys
? (question_idna)->keys[__unique_prefix_i15] : ((void*)0)
))
{
475 r = dns_question_contains(question_utf8, key);
476 if (r < 0)
477 return r;
478 if (r > 0)
479 continue;
480
481 log_debug("Looking up IDNA RR 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-query.c", 482, __func__, "Looking up IDNA RR for %s."
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
482 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-query.c", 482, __func__, "Looking up IDNA RR for %s."
, dns_resource_key_to_string(key, key_str, sizeof key_str)) :
-abs(_e); })
;
483 }
484
485 LIST_PREPEND(queries, m->dns_queries, q)do { typeof(*(m->dns_queries)) **_head = &(m->dns_queries
), *_item = (q); do { if ((__builtin_expect(!!(!(_item)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-query.c"
, 485, __PRETTY_FUNCTION__); } while (0); if ((_item->queries_next
= *_head)) _item->queries_next->queries_prev = _item; _item
->queries_prev = ((void*)0); *_head = _item; } while (0)
;
486 m->n_dns_queries++;
487 q->manager = m;
488
489 if (ret)
490 *ret = q;
491 q = NULL((void*)0);
492
493 return 0;
494}
495
496int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
497 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 497, __PRETTY_FUNCTION__); } while (0)
;
498 assert(auxiliary_for)do { if ((__builtin_expect(!!(!(auxiliary_for)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("auxiliary_for"), "../src/resolve/resolved-dns-query.c"
, 498, __PRETTY_FUNCTION__); } while (0)
;
499
500 /* Ensure that the query is not auxiliary yet, and
501 * nothing else is auxiliary to it either */
502 assert(!q->auxiliary_for)do { if ((__builtin_expect(!!(!(!q->auxiliary_for)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("!q->auxiliary_for"), "../src/resolve/resolved-dns-query.c"
, 502, __PRETTY_FUNCTION__); } while (0)
;
503 assert(!q->auxiliary_queries)do { if ((__builtin_expect(!!(!(!q->auxiliary_queries)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!q->auxiliary_queries"
), "../src/resolve/resolved-dns-query.c", 503, __PRETTY_FUNCTION__
); } while (0)
;
504
505 /* Ensure that the unit we shall be made auxiliary for isn't
506 * auxiliary itself */
507 assert(!auxiliary_for->auxiliary_for)do { if ((__builtin_expect(!!(!(!auxiliary_for->auxiliary_for
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!auxiliary_for->auxiliary_for"
), "../src/resolve/resolved-dns-query.c", 507, __PRETTY_FUNCTION__
); } while (0)
;
508
509 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX64)
510 return -EAGAIN11;
511
512 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q)do { typeof(*(auxiliary_for->auxiliary_queries)) **_head =
&(auxiliary_for->auxiliary_queries), *_item = (q); do
{ if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-query.c"
, 512, __PRETTY_FUNCTION__); } while (0); if ((_item->auxiliary_queries_next
= *_head)) _item->auxiliary_queries_next->auxiliary_queries_prev
= _item; _item->auxiliary_queries_prev = ((void*)0); *_head
= _item; } while (0)
;
513 q->auxiliary_for = auxiliary_for;
514
515 auxiliary_for->n_auxiliary_queries++;
516 return 0;
517}
518
519static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
520 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 520, __PRETTY_FUNCTION__); } while (0)
;
521 assert(!DNS_TRANSACTION_IS_LIVE(state))do { if ((__builtin_expect(!!(!(!({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING
, DNS_TRANSACTION_VALIDATING})/sizeof(int)]; switch((state)) {
case DNS_TRANSACTION_NULL: case DNS_TRANSACTION_PENDING: case
DNS_TRANSACTION_VALIDATING: _found = 1; break; default: break
; } _found; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!DNS_TRANSACTION_IS_LIVE(state)"), "../src/resolve/resolved-dns-query.c"
, 521, __PRETTY_FUNCTION__); } while (0)
;
522 assert(DNS_TRANSACTION_IS_LIVE(q->state))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING
, DNS_TRANSACTION_VALIDATING})/sizeof(int)]; switch((q->state
)) { case DNS_TRANSACTION_NULL: case DNS_TRANSACTION_PENDING:
case DNS_TRANSACTION_VALIDATING: _found = 1; break; default:
break; } _found; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("DNS_TRANSACTION_IS_LIVE(q->state)"), "../src/resolve/resolved-dns-query.c"
, 522, __PRETTY_FUNCTION__); } while (0)
;
523
524 /* Note that this call might invalidate the query. Callers
525 * should hence not attempt to access the query or transaction
526 * after calling this function. */
527
528 q->state = state;
529
530 dns_query_stop(q);
531 if (q->complete)
532 q->complete(q);
533}
534
535static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
536 DnsQuery *q = userdata;
537
538 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-query.c"
, 538, __PRETTY_FUNCTION__); } while (0)
;
539 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 539, __PRETTY_FUNCTION__); } while (0)
;
540
541 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
542 return 0;
543}
544
545static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
546 DnsQueryCandidate *c;
547 int r;
548
549 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 549, __PRETTY_FUNCTION__); } while (0)
;
550 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-query.c"
, 550, __PRETTY_FUNCTION__); } while (0)
;
551
552 r = dns_query_candidate_new(&c, q, s);
553 if (r < 0)
554 return r;
555
556 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
557 if ((q->flags & SD_RESOLVED_NO_SEARCH(1UL << 8)) == 0) {
558 r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna));
559 if (r < 0)
560 goto fail;
561 if (r > 0) {
562 /* OK, we need a search domain now. Let's find one for this scope */
563
564 r = dns_query_candidate_next_search_domain(c);
565 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
566 goto fail;
567 }
568 }
569
570 r = dns_query_candidate_setup_transactions(c);
571 if (r < 0)
572 goto fail;
573
574 return 0;
575
576fail:
577 dns_query_candidate_free(c);
578 return r;
579}
580
581static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
582 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *answer = NULL((void*)0);
583 int r;
584
585 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 585, __PRETTY_FUNCTION__); } while (0)
;
586 assert(state)do { if ((__builtin_expect(!!(!(state)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("state"), "../src/resolve/resolved-dns-query.c"
, 586, __PRETTY_FUNCTION__); } while (0)
;
587
588 /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
589 * the normal lookup finished. The data from the network hence takes precedence over the data we
590 * synthesize. (But note that many scopes refuse to resolve certain domain names) */
591
592 if (!IN_SET(*state,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
593 DNS_TRANSACTION_RCODE_FAILURE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
594 DNS_TRANSACTION_NO_SERVERS,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
595 DNS_TRANSACTION_TIMEOUT,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
596 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
597 DNS_TRANSACTION_NETWORK_DOWN,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
598 DNS_TRANSACTION_NOT_FOUND)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS
, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND})/sizeof
(int)]; switch(*state) { case DNS_TRANSACTION_RCODE_FAILURE: case
DNS_TRANSACTION_NO_SERVERS: case DNS_TRANSACTION_TIMEOUT: case
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: case DNS_TRANSACTION_NETWORK_DOWN
: case DNS_TRANSACTION_NOT_FOUND: _found = 1; break; default:
break; } _found; })
)
599 return 0;
600
601 r = dns_synthesize_answer(
602 q->manager,
603 q->question_utf8,
604 q->ifindex,
605 &answer);
606 if (r == -ENXIO6) {
607 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
608
609 dns_query_reset_answer(q);
610 q->answer_rcode = DNS_RCODE_NXDOMAIN;
611 q->answer_protocol = dns_synthesize_protocol(q->flags);
612 q->answer_family = dns_synthesize_family(q->flags);
613 q->answer_authenticated = true1;
614 *state = DNS_TRANSACTION_RCODE_FAILURE;
615
616 return 0;
617 }
618 if (r <= 0)
619 return r;
620
621 dns_query_reset_answer(q);
622
623 q->answer = TAKE_PTR(answer)({ typeof(answer) _ptr_ = (answer); (answer) = ((void*)0); _ptr_
; })
;
624 q->answer_rcode = DNS_RCODE_SUCCESS;
625 q->answer_protocol = dns_synthesize_protocol(q->flags);
626 q->answer_family = dns_synthesize_family(q->flags);
627 q->answer_authenticated = true1;
628
629 *state = DNS_TRANSACTION_SUCCESS;
630
631 return 1;
632}
633
634static int dns_query_try_etc_hosts(DnsQuery *q) {
635 _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *answer = NULL((void*)0);
636 int r;
637
638 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 638, __PRETTY_FUNCTION__); } while (0)
;
639
640 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
641 * data from /etc/hosts hence takes precedence over the network. */
642
643 r = manager_etc_hosts_lookup(
644 q->manager,
645 q->question_utf8,
646 &answer);
647 if (r <= 0)
648 return r;
649
650 dns_query_reset_answer(q);
651
652 q->answer = TAKE_PTR(answer)({ typeof(answer) _ptr_ = (answer); (answer) = ((void*)0); _ptr_
; })
;
653 q->answer_rcode = DNS_RCODE_SUCCESS;
654 q->answer_protocol = dns_synthesize_protocol(q->flags);
655 q->answer_family = dns_synthesize_family(q->flags);
656 q->answer_authenticated = true1;
657
658 return 1;
659}
660
661int dns_query_go(DnsQuery *q) {
662 DnsScopeMatch found = DNS_SCOPE_NO;
663 DnsScope *s, *first = NULL((void*)0);
664 DnsQueryCandidate *c;
665 int r;
666
667 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 667, __PRETTY_FUNCTION__); } while (0)
;
668
669 if (q->state != DNS_TRANSACTION_NULL)
670 return 0;
671
672 r = dns_query_try_etc_hosts(q);
673 if (r < 0)
674 return r;
675 if (r > 0) {
676 dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
677 return 1;
678 }
679
680 LIST_FOREACH(scopes, s, q->manager->dns_scopes)for ((s) = (q->manager->dns_scopes); (s); (s) = (s)->
scopes_next)
{
681 DnsScopeMatch match;
682 const char *name;
683
684 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
685 if (!name)
686 continue;
687
688 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
689 if (match < 0)
690 return match;
691
692 if (match == DNS_SCOPE_NO)
693 continue;
694
695 found = match;
696
697 if (match == DNS_SCOPE_YES) {
698 first = s;
699 break;
700 } else {
701 assert(match == DNS_SCOPE_MAYBE)do { if ((__builtin_expect(!!(!(match == DNS_SCOPE_MAYBE)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("match == DNS_SCOPE_MAYBE"
), "../src/resolve/resolved-dns-query.c", 701, __PRETTY_FUNCTION__
); } while (0)
;
702
703 if (!first)
704 first = s;
705 }
706 }
707
708 if (found == DNS_SCOPE_NO) {
709 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
710
711 r = dns_query_synthesize_reply(q, &state);
712 if (r < 0)
713 return r;
714
715 dns_query_complete(q, state);
716 return 1;
717 }
718
719 r = dns_query_add_candidate(q, first);
720 if (r < 0)
721 goto fail;
722
723 LIST_FOREACH(scopes, s, first->scopes_next)for ((s) = (first->scopes_next); (s); (s) = (s)->scopes_next
)
{
724 DnsScopeMatch match;
725 const char *name;
726
727 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
728 if (!name)
729 continue;
730
731 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
732 if (match < 0)
733 goto fail;
734
735 if (match != found)
736 continue;
737
738 r = dns_query_add_candidate(q, s);
739 if (r < 0)
740 goto fail;
741 }
742
743 dns_query_reset_answer(q);
744
745 r = sd_event_add_time(
746 q->manager->event,
747 &q->timeout_event_source,
748 clock_boottime_or_monotonic(),
749 now(clock_boottime_or_monotonic()) + SD_RESOLVED_QUERY_TIMEOUT_USEC(120 * ((usec_t) 1000000ULL)),
750 0, on_query_timeout, q);
751 if (r < 0)
752 goto fail;
753
754 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
755
756 q->state = DNS_TRANSACTION_PENDING;
757 q->block_ready++;
758
759 /* Start the transactions */
760 LIST_FOREACH(candidates_by_query, c, q->candidates)for ((c) = (q->candidates); (c); (c) = (c)->candidates_by_query_next
)
{
761 r = dns_query_candidate_go(c);
762 if (r < 0) {
763 q->block_ready--;
764 goto fail;
765 }
766 }
767
768 q->block_ready--;
769 dns_query_ready(q);
770
771 return 1;
772
773fail:
774 dns_query_stop(q);
775 return r;
776}
777
778static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
779 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
780 bool_Bool has_authenticated = false0, has_non_authenticated = false0;
781 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
782 DnsTransaction *t;
783 Iterator i;
784 int r;
785
786 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 786, __PRETTY_FUNCTION__); } while (0)
;
787
788 if (!c) {
789 r = dns_query_synthesize_reply(q, &state);
790 if (r < 0)
791 goto fail;
792
793 dns_query_complete(q, state);
794 return;
795 }
796
797 if (c->error_code != 0) {
798 /* If the candidate had an error condition of its own, start with that. */
799 state = DNS_TRANSACTION_ERRNO;
800 q->answer = dns_answer_unref(q->answer);
801 q->answer_rcode = 0;
802 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
803 q->answer_authenticated = false0;
804 q->answer_errno = c->error_code;
805 }
806
807 SET_FOREACH(t, c->transactions, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); set_iterate((c->transactions), &
(i), (void**)&(t)); )
{
808
809 switch (t->state) {
810
811 case DNS_TRANSACTION_SUCCESS: {
812 /* We found a successfully reply, merge it into the answer */
813 r = dns_answer_extend(&q->answer, t->answer);
814 if (r < 0)
815 goto fail;
816
817 q->answer_rcode = t->answer_rcode;
818 q->answer_errno = 0;
819
820 if (t->answer_authenticated) {
821 has_authenticated = true1;
822 dnssec_result_authenticated = t->answer_dnssec_result;
823 } else {
824 has_non_authenticated = true1;
825 dnssec_result_non_authenticated = t->answer_dnssec_result;
826 }
827
828 state = DNS_TRANSACTION_SUCCESS;
829 break;
830 }
831
832 case DNS_TRANSACTION_NULL:
833 case DNS_TRANSACTION_PENDING:
834 case DNS_TRANSACTION_VALIDATING:
835 case DNS_TRANSACTION_ABORTED:
836 /* Ignore transactions that didn't complete */
837 continue;
838
839 default:
840 /* Any kind of failure? Store the data away, if there's nothing stored yet. */
841 if (state == DNS_TRANSACTION_SUCCESS)
842 continue;
843
844 /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
845 if (q->answer_authenticated && !t->answer_authenticated)
846 continue;
847
848 q->answer = dns_answer_unref(q->answer);
849 q->answer_rcode = t->answer_rcode;
850 q->answer_dnssec_result = t->answer_dnssec_result;
851 q->answer_authenticated = t->answer_authenticated;
852 q->answer_errno = t->answer_errno;
853
854 state = t->state;
855 break;
856 }
857 }
858
859 if (state == DNS_TRANSACTION_SUCCESS) {
860 q->answer_authenticated = has_authenticated && !has_non_authenticated;
861 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
862 }
863
864 q->answer_protocol = c->scope->protocol;
865 q->answer_family = c->scope->family;
866
867 dns_search_domain_unref(q->answer_search_domain);
868 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
869
870 r = dns_query_synthesize_reply(q, &state);
871 if (r < 0)
872 goto fail;
873
874 dns_query_complete(q, state);
875 return;
876
877fail:
878 q->answer_errno = -r;
879 dns_query_complete(q, DNS_TRANSACTION_ERRNO);
880}
881
882void dns_query_ready(DnsQuery *q) {
883
884 DnsQueryCandidate *bad = NULL((void*)0), *c;
885 bool_Bool pending = false0;
886
887 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 887, __PRETTY_FUNCTION__); } while (0)
;
888 assert(DNS_TRANSACTION_IS_LIVE(q->state))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING
, DNS_TRANSACTION_VALIDATING})/sizeof(int)]; switch((q->state
)) { case DNS_TRANSACTION_NULL: case DNS_TRANSACTION_PENDING:
case DNS_TRANSACTION_VALIDATING: _found = 1; break; default:
break; } _found; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("DNS_TRANSACTION_IS_LIVE(q->state)"), "../src/resolve/resolved-dns-query.c"
, 888, __PRETTY_FUNCTION__); } while (0)
;
889
890 /* Note that this call might invalidate the query. Callers
891 * should hence not attempt to access the query or transaction
892 * after calling this function, unless the block_ready
893 * counter was explicitly bumped before doing so. */
894
895 if (q->block_ready > 0)
896 return;
897
898 LIST_FOREACH(candidates_by_query, c, q->candidates)for ((c) = (q->candidates); (c); (c) = (c)->candidates_by_query_next
)
{
899 DnsTransactionState state;
900
901 state = dns_query_candidate_state(c);
902 switch (state) {
903
904 case DNS_TRANSACTION_SUCCESS:
905 /* One of the candidates is successful,
906 * let's use it, and copy its data out */
907 dns_query_accept(q, c);
908 return;
909
910 case DNS_TRANSACTION_NULL:
911 case DNS_TRANSACTION_PENDING:
912 case DNS_TRANSACTION_VALIDATING:
913 /* One of the candidates is still going on,
914 * let's maybe wait for it */
915 pending = true1;
916 break;
917
918 default:
919 /* Any kind of failure */
920 bad = c;
921 break;
922 }
923 }
924
925 if (pending)
926 return;
927
928 dns_query_accept(q, bad);
929}
930
931static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
932 _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *nq_idna = NULL((void*)0), *nq_utf8 = NULL((void*)0);
933 int r, k;
934
935 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 935, __PRETTY_FUNCTION__); } while (0)
;
936
937 q->n_cname_redirects++;
938 if (q->n_cname_redirects > CNAME_MAX8)
939 return -ELOOP40;
940
941 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
942 if (r < 0)
943 return r;
944 else if (r > 0)
945 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna))({ 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-query.c", 945, __func__, "Following CNAME/DNAME %s → %s."
, dns_question_first_name(q->question_idna), dns_question_first_name
(nq_idna)) : -abs(_e); })
;
946
947 k = dns_question_is_equal(q->question_idna, q->question_utf8);
948 if (k < 0)
949 return r;
950 if (k > 0) {
951 /* Same question? Shortcut new question generation */
952 nq_utf8 = dns_question_ref(nq_idna);
953 k = r;
954 } else {
955 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
956 if (k < 0)
957 return k;
958 else if (k > 0)
959 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8))({ 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-query.c", 959, __func__, "Following UTF8 CNAME/DNAME %s → %s."
, dns_question_first_name(q->question_utf8), dns_question_first_name
(nq_utf8)) : -abs(_e); })
;
960 }
961
962 if (r == 0 && k == 0) /* No actual cname happened? */
963 return -ELOOP40;
964
965 if (q->answer_protocol == DNS_PROTOCOL_DNS) {
966 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
967 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
968 * ones. */
969
970 q->flags &= ~(SD_RESOLVED_LLMNR((1UL << 1)|(1UL << 2))|SD_RESOLVED_MDNS((1UL << 3)|(1UL << 4))); /* mask away the local protocols */
971 }
972
973 /* Turn off searching for the new name */
974 q->flags |= SD_RESOLVED_NO_SEARCH(1UL << 8);
975
976 dns_question_unref(q->question_idna);
977 q->question_idna = TAKE_PTR(nq_idna)({ typeof(nq_idna) _ptr_ = (nq_idna); (nq_idna) = ((void*)0);
_ptr_; })
;
978
979 dns_question_unref(q->question_utf8);
980 q->question_utf8 = TAKE_PTR(nq_utf8)({ typeof(nq_utf8) _ptr_ = (nq_utf8); (nq_utf8) = ((void*)0);
_ptr_; })
;
981
982 dns_query_free_candidates(q);
983 dns_query_reset_answer(q);
984
985 q->state = DNS_TRANSACTION_NULL;
986
987 return 0;
988}
989
990int dns_query_process_cname(DnsQuery *q) {
991 _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *cname = NULL((void*)0);
992 DnsQuestion *question;
993 DnsResourceRecord *rr;
994 int r;
995
996 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 996, __PRETTY_FUNCTION__); } while (0)
;
997
998 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL
})/sizeof(int)]; switch(q->state) { case DNS_TRANSACTION_SUCCESS
: case DNS_TRANSACTION_NULL: _found = 1; break; default: break
; } _found; })
)
999 return DNS_QUERY_NOMATCH;
1000
1001 question = dns_query_question_for_protocol(q, q->answer_protocol);
1002
1003 DNS_ANSWER_FOREACH(rr, q->answer)for (size_t __unique_prefix_i16 = ({ (rr) = ((q->answer) &&
(q->answer)->n_rrs > 0) ? (q->answer)->items[
0].rr : ((void*)0); 0; }); (q->answer) && (__unique_prefix_i16
< (q->answer)->n_rrs); __unique_prefix_i16++, (rr) =
(__unique_prefix_i16 < (q->answer)->n_rrs ? (q->
answer)->items[__unique_prefix_i16].rr : ((void*)0)))
{
1004 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1005 if (r < 0)
1006 return r;
1007 if (r > 0)
1008 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
1009
1010 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1011 if (r < 0)
1012 return r;
1013 if (r > 0 && !cname)
1014 cname = dns_resource_record_ref(rr);
1015 }
1016
1017 if (!cname)
1018 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
1019
1020 if (q->flags & SD_RESOLVED_NO_CNAME(1UL << 5))
1021 return -ELOOP40;
1022
1023 if (!q->answer_authenticated)
1024 q->previous_redirect_unauthenticated = true1;
1025
1026 /* OK, let's actually follow the CNAME */
1027 r = dns_query_cname_redirect(q, cname);
1028 if (r < 0)
1029 return r;
1030
1031 /* Let's see if the answer can already answer the new
1032 * redirected question */
1033 r = dns_query_process_cname(q);
1034 if (r != DNS_QUERY_NOMATCH)
1035 return r;
1036
1037 /* OK, it cannot, let's begin with the new query */
1038 r = dns_query_go(q);
1039 if (r < 0)
1040 return r;
1041
1042 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
1043}
1044
1045static int on_bus_track(sd_bus_track *t, void *userdata) {
1046 DnsQuery *q = userdata;
1047
1048 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/resolve/resolved-dns-query.c"
, 1048, __PRETTY_FUNCTION__); } while (0)
;
1049 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 1049, __PRETTY_FUNCTION__); } while (0)
;
1050
1051 log_debug("Client of active query vanished, aborting query.")({ 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-query.c", 1051, __func__, "Client of active query vanished, aborting query."
) : -abs(_e); })
;
1052 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1053 return 0;
1054}
1055
1056int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
1057 int r;
1058
1059 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 1059, __PRETTY_FUNCTION__); } while (0)
;
1060 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-dns-query.c"
, 1060, __PRETTY_FUNCTION__); } while (0)
;
1061
1062 if (!q->bus_track) {
1063 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
1064 if (r < 0)
1065 return r;
1066 }
1067
1068 r = sd_bus_track_add_sender(q->bus_track, m);
1069 if (r < 0)
1070 return r;
1071
1072 return 0;
1073}
1074
1075DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1076 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 1076, __PRETTY_FUNCTION__); } while (0)
;
1077
1078 switch (protocol) {
1079
1080 case DNS_PROTOCOL_DNS:
1081 return q->question_idna;
1082
1083 case DNS_PROTOCOL_MDNS:
1084 case DNS_PROTOCOL_LLMNR:
1085 return q->question_utf8;
1086
1087 default:
1088 return NULL((void*)0);
1089 }
1090}
1091
1092const char *dns_query_string(DnsQuery *q) {
1093 const char *name;
1094 int r;
1095
1096 /* Returns a somewhat useful human-readable lookup key string for this query */
1097
1098 if (q->request_address_string)
1099 return q->request_address_string;
1100
1101 if (q->request_address_valid) {
1102 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1103 if (r >= 0)
1104 return q->request_address_string;
1105 }
1106
1107 name = dns_question_first_name(q->question_utf8);
1108 if (name)
1109 return name;
1110
1111 return dns_question_first_name(q->question_idna);
1112}
1113
1114bool_Bool dns_query_fully_authenticated(DnsQuery *q) {
1115 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/resolve/resolved-dns-query.c"
, 1115, __PRETTY_FUNCTION__); } while (0)
;
1116
1117 return q->answer_authenticated && !q->previous_redirect_unauthenticated;
1118}

../src/basic/alloc-util.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <alloca.h>
5#include <stddef.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "macro.h"
10
11#define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n)))
12
13#define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t)))
14
15#define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while
(0); (t*) __builtin_alloca (sizeof(t)*(n)); })
\
16 ({ \
17 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while
(0)
; \
18 (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \
19 })
20
21#define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while
(0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_
= __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_)
; }); })
\
22 ({ \
23 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while
(0)
; \
24 (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca
(_len_); (void *) memset(_new_, 0, _len_); })
; \
25 })
26
27#define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n)))
28
29#define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
30
31#define malloc0(n)(calloc(1, (n))) (calloc(1, (n)))
32
33static inline void *mfree(void *memory) {
34 free(memory);
23
Memory is released
35 return NULL((void*)0);
36}
37
38#define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \
39 ({ \
40 free(a); \
41 (a) = (b); \
42 (b) = NULL((void*)0); \
43 0; \
44 })
45
46void* memdup(const void *p, size_t l) _alloc_(2);
47void* memdup_suffix0(const void *p, size_t l) _alloc_(2);
48
49static inline void freep(void *p) {
50 free(*(void**) p);
51}
52
53#define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep)))
54
55static inline bool_Bool size_multiply_overflow(size_t size, size_t need) {
56 return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL
) / need)),0))
;
57}
58
59_malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
60 if (size_multiply_overflow(size, need))
61 return NULL((void*)0);
62
63 return malloc(size * need);
64}
65
66#if !HAVE_REALLOCARRAY1
67_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
68 if (size_multiply_overflow(size, need))
69 return NULL((void*)0);
70
71 return realloc(p, size * need);
72}
73#endif
74
75_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
76 if (size_multiply_overflow(size, need))
77 return NULL((void*)0);
78
79 return memdup(p, size * need);
80}
81
82_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
83 if (size_multiply_overflow(size, need))
84 return NULL((void*)0);
85
86 return memdup_suffix0(p, size * need);
87}
88
89void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
90void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
91
92#define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
93 greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
94
95#define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
96 greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
97
98#define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_
); (void *) memset(_new_, 0, _len_); })
\
99 ({ \
100 char *_new_; \
101 size_t _len_ = n; \
102 _new_ = alloca(_len_)__builtin_alloca (_len_); \
103 (void *) memset(_new_, 0, _len_); \
104 })
105
106/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
107#define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca
((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
\
108 ({ \
109 void *_ptr_; \
110 size_t _mask_ = (align) - 1; \
111 _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \
112 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
113 })
114
115#define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_
; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_
) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_
); }); (void*)memset(_new_, 0, _size_); })
\
116 ({ \
117 void *_new_; \
118 size_t _size_ = (size); \
119 _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca
((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
; \
120 (void*)memset(_new_, 0, _size_); \
121 })
122
123/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
124 * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
125#define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \
126 ({ \
127 typeof(ptr) _ptr_ = (ptr); \
128 (ptr) = NULL((void*)0); \
129 _ptr_; \
130 })