]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-transaction.c
util-lib: split out globbing related calls into glob-util.[ch]
[thirdparty/systemd.git] / src / resolve / resolved-dns-transaction.c
CommitLineData
ec2c5e43
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include "af-list.h"
f52e61da 23#include "dns-domain.h"
3ffd4af2
LP
24#include "fd-util.h"
25#include "random-util.h"
26#include "resolved-dns-transaction.h"
27#include "resolved-llmnr.h"
8b43440b 28#include "string-table.h"
ec2c5e43
LP
29
30DnsTransaction* dns_transaction_free(DnsTransaction *t) {
31 DnsQuery *q;
32 DnsZoneItem *i;
33
34 if (!t)
35 return NULL;
36
37 sd_event_source_unref(t->timeout_event_source);
38
ec2c5e43
LP
39 dns_packet_unref(t->sent);
40 dns_packet_unref(t->received);
41 dns_answer_unref(t->cached);
42
4667e00a
LP
43 sd_event_source_unref(t->dns_udp_event_source);
44 safe_close(t->dns_udp_fd);
d20b1667 45
8300ba21 46 dns_server_unref(t->server);
ec2c5e43
LP
47 dns_stream_free(t->stream);
48
49 if (t->scope) {
da0c630e 50 hashmap_remove(t->scope->transactions, t->key);
ec2c5e43
LP
51
52 if (t->id != 0)
53 hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
54 }
55
da0c630e
LP
56 dns_resource_key_unref(t->key);
57
ec2c5e43
LP
58 while ((q = set_steal_first(t->queries)))
59 set_remove(q->transactions, t);
60 set_free(t->queries);
61
62 while ((i = set_steal_first(t->zone_items)))
63 i->probe_transaction = NULL;
64 set_free(t->zone_items);
65
66 free(t);
67 return NULL;
68}
69
70DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free);
71
72void dns_transaction_gc(DnsTransaction *t) {
73 assert(t);
74
75 if (t->block_gc > 0)
76 return;
77
78 if (set_isempty(t->queries) && set_isempty(t->zone_items))
79 dns_transaction_free(t);
80}
81
f52e61da 82int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) {
ec2c5e43
LP
83 _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
84 int r;
85
86 assert(ret);
87 assert(s);
f52e61da 88 assert(key);
ec2c5e43 89
d5099efc 90 r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL);
ec2c5e43
LP
91 if (r < 0)
92 return r;
93
da0c630e
LP
94 r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops);
95 if (r < 0)
96 return r;
97
ec2c5e43
LP
98 t = new0(DnsTransaction, 1);
99 if (!t)
100 return -ENOMEM;
101
4667e00a 102 t->dns_udp_fd = -1;
f52e61da 103 t->key = dns_resource_key_ref(key);
ec2c5e43 104
da0c630e 105 /* Find a fresh, unused transaction id */
ec2c5e43
LP
106 do
107 random_bytes(&t->id, sizeof(t->id));
108 while (t->id == 0 ||
109 hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id)));
110
111 r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t);
112 if (r < 0) {
113 t->id = 0;
114 return r;
115 }
116
da0c630e
LP
117 r = hashmap_put(s->transactions, t->key, t);
118 if (r < 0) {
119 hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id));
120 return r;
121 }
122
ec2c5e43
LP
123 t->scope = s;
124
125 if (ret)
126 *ret = t;
127
128 t = NULL;
129
130 return 0;
131}
132
133static void dns_transaction_stop(DnsTransaction *t) {
134 assert(t);
135
136 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
137 t->stream = dns_stream_free(t->stream);
138}
139
140static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
2fb3034c 141 _cleanup_free_ char *pretty = NULL;
ec2c5e43 142 DnsZoneItem *z;
ec2c5e43
LP
143
144 assert(t);
145 assert(p);
146
147 if (manager_our_packet(t->scope->manager, p) != 0)
148 return;
149
2fb3034c
LP
150 in_addr_to_string(p->family, &p->sender, &pretty);
151
152 log_debug("Transaction on scope %s on %s/%s got tentative packet from %s",
ec2c5e43
LP
153 dns_protocol_to_string(t->scope->protocol),
154 t->scope->link ? t->scope->link->name : "*",
2fb3034c
LP
155 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
156 pretty);
ec2c5e43 157
a4076574
LP
158 /* RFC 4795, Section 4.1 says that the peer with the
159 * lexicographically smaller IP address loses */
4d91eec4
LP
160 if (memcmp(&p->sender, &p->destination, FAMILY_ADDRESS_SIZE(p->family)) >= 0) {
161 log_debug("Peer has lexicographically larger IP address and thus lost in the conflict.");
a4076574
LP
162 return;
163 }
164
4d91eec4 165 log_debug("We have the lexicographically larger IP address and thus lost in the conflict.");
a4076574 166
ec2c5e43 167 t->block_gc++;
3ef64445
LP
168 while ((z = set_first(t->zone_items))) {
169 /* First, make sure the zone item drops the reference
170 * to us */
171 dns_zone_item_probe_stop(z);
172
173 /* Secondly, report this as conflict, so that we might
174 * look for a different hostname */
ec2c5e43 175 dns_zone_item_conflict(z);
3ef64445 176 }
ec2c5e43
LP
177 t->block_gc--;
178
179 dns_transaction_gc(t);
180}
181
182void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
183 DnsQuery *q;
184 DnsZoneItem *z;
185 Iterator i;
186
187 assert(t);
188 assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
e56187ca 189
ec2c5e43
LP
190 /* Note that this call might invalidate the query. Callers
191 * should hence not attempt to access the query or transaction
192 * after calling this function. */
193
194 log_debug("Transaction on scope %s on %s/%s now complete with <%s>",
195 dns_protocol_to_string(t->scope->protocol),
196 t->scope->link ? t->scope->link->name : "*",
197 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
198 dns_transaction_state_to_string(state));
199
200 t->state = state;
201
202 dns_transaction_stop(t);
203
204 /* Notify all queries that are interested, but make sure the
205 * transaction isn't freed while we are still looking at it */
206 t->block_gc++;
207 SET_FOREACH(q, t->queries, i)
208 dns_query_ready(q);
209 SET_FOREACH(z, t->zone_items, i)
210 dns_zone_item_ready(z);
211 t->block_gc--;
212
213 dns_transaction_gc(t);
214}
215
216static int on_stream_complete(DnsStream *s, int error) {
217 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
218 DnsTransaction *t;
219
220 assert(s);
221 assert(s->transaction);
222
223 /* Copy the data we care about out of the stream before we
224 * destroy it. */
225 t = s->transaction;
226 p = dns_packet_ref(s->read_packet);
227
228 t->stream = dns_stream_free(t->stream);
229
230 if (error != 0) {
231 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
232 return 0;
233 }
234
a4076574
LP
235 if (dns_packet_validate_reply(p) <= 0) {
236 log_debug("Invalid LLMNR TCP packet.");
237 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
238 return 0;
239 }
240
241 dns_scope_check_conflicts(t->scope, p);
242
ec2c5e43
LP
243 t->block_gc++;
244 dns_transaction_process_reply(t, p);
245 t->block_gc--;
246
247 /* If the response wasn't useful, then complete the transition now */
248 if (t->state == DNS_TRANSACTION_PENDING)
249 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
250
251 return 0;
252}
253
254static int dns_transaction_open_tcp(DnsTransaction *t) {
088480fa 255 DnsServer *server = NULL;
ec2c5e43
LP
256 _cleanup_close_ int fd = -1;
257 int r;
258
259 assert(t);
260
261 if (t->stream)
262 return 0;
263
106784eb
DM
264 switch (t->scope->protocol) {
265 case DNS_PROTOCOL_DNS:
8300ba21 266 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
106784eb 267 break;
ec2c5e43 268
106784eb 269 case DNS_PROTOCOL_LLMNR:
a8f6397f 270 /* When we already received a reply to this (but it was truncated), send to its sender address */
ec2c5e43 271 if (t->received)
8300ba21 272 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
ec2c5e43
LP
273 else {
274 union in_addr_union address;
a7f7d1bd 275 int family = AF_UNSPEC;
ec2c5e43
LP
276
277 /* Otherwise, try to talk to the owner of a
278 * the IP address, in case this is a reverse
279 * PTR lookup */
f52e61da
LP
280
281 r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address);
ec2c5e43
LP
282 if (r < 0)
283 return r;
284 if (r == 0)
285 return -EINVAL;
9e08a6e0 286 if (family != t->scope->family)
9318cdd3 287 return -ESRCH;
ec2c5e43 288
8300ba21 289 fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
ec2c5e43 290 }
106784eb
DM
291
292 break;
293
294 default:
ec2c5e43 295 return -EAFNOSUPPORT;
106784eb 296 }
ec2c5e43
LP
297
298 if (fd < 0)
299 return fd;
300
301 r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
302 if (r < 0)
303 return r;
304
305 fd = -1;
306
307 r = dns_stream_write_packet(t->stream, t->sent);
308 if (r < 0) {
309 t->stream = dns_stream_free(t->stream);
310 return r;
311 }
312
8300ba21
TG
313 dns_server_unref(t->server);
314 t->server = dns_server_ref(server);
ec2c5e43
LP
315 t->received = dns_packet_unref(t->received);
316 t->stream->complete = on_stream_complete;
317 t->stream->transaction = t;
318
319 /* The interface index is difficult to determine if we are
320 * connecting to the local host, hence fill this in right away
321 * instead of determining it from the socket */
322 if (t->scope->link)
323 t->stream->ifindex = t->scope->link->ifindex;
324
325 return 0;
326}
327
647f6aa8
TG
328static void dns_transaction_next_dns_server(DnsTransaction *t) {
329 assert(t);
330
331 t->server = dns_server_unref(t->server);
4667e00a
LP
332 t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source);
333 t->dns_udp_fd = safe_close(t->dns_udp_fd);
647f6aa8
TG
334
335 dns_scope_next_dns_server(t->scope);
336}
337
ec2c5e43 338void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
9df3ba6c 339 usec_t ts;
ec2c5e43
LP
340 int r;
341
342 assert(t);
343 assert(p);
344 assert(t->state == DNS_TRANSACTION_PENDING);
9df3ba6c
TG
345 assert(t->scope);
346 assert(t->scope->manager);
ec2c5e43
LP
347
348 /* Note that this call might invalidate the query. Callers
349 * should hence not attempt to access the query or transaction
350 * after calling this function. */
351
106784eb
DM
352 switch (t->scope->protocol) {
353 case DNS_PROTOCOL_LLMNR:
ec2c5e43
LP
354 assert(t->scope->link);
355
356 /* For LLMNR we will not accept any packets from other
357 * interfaces */
358
359 if (p->ifindex != t->scope->link->ifindex)
360 return;
361
362 if (p->family != t->scope->family)
363 return;
364
365 /* Tentative packets are not full responses but still
366 * useful for identifying uniqueness conflicts during
367 * probing. */
8b757a38 368 if (DNS_PACKET_LLMNR_T(p)) {
ec2c5e43
LP
369 dns_transaction_tentative(t, p);
370 return;
371 }
106784eb
DM
372
373 break;
374
375 case DNS_PROTOCOL_DNS:
376 break;
377
378 default:
9c56a6f3 379 assert_not_reached("Invalid DNS protocol.");
ec2c5e43
LP
380 }
381
ec2c5e43
LP
382 if (t->received != p) {
383 dns_packet_unref(t->received);
384 t->received = dns_packet_ref(p);
385 }
386
387 if (p->ipproto == IPPROTO_TCP) {
388 if (DNS_PACKET_TC(p)) {
389 /* Truncated via TCP? Somebody must be fucking with us */
390 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
391 return;
392 }
393
394 if (DNS_PACKET_ID(p) != t->id) {
395 /* Not the reply to our query? Somebody must be fucking with us */
396 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
397 return;
398 }
399 }
400
38a03f06 401 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
9df3ba6c
TG
402
403 switch (t->scope->protocol) {
404 case DNS_PROTOCOL_DNS:
405 assert(t->server);
406
407 dns_server_packet_received(t->server, ts - t->start_usec);
408
409 break;
410 case DNS_PROTOCOL_LLMNR:
411 case DNS_PROTOCOL_MDNS:
412 dns_scope_packet_received(t->scope, ts - t->start_usec);
413
414 break;
415 default:
9c56a6f3 416 break;
9df3ba6c
TG
417 }
418
ec2c5e43
LP
419 if (DNS_PACKET_TC(p)) {
420 /* Response was truncated, let's try again with good old TCP */
421 r = dns_transaction_open_tcp(t);
422 if (r == -ESRCH) {
423 /* No servers found? Damn! */
424 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
425 return;
426 }
427 if (r < 0) {
428 /* On LLMNR, if we cannot connect to the host,
429 * we immediately give up */
430 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
431 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
432 return;
433 }
434
435 /* On DNS, couldn't send? Try immediately again, with a new server */
647f6aa8 436 dns_transaction_next_dns_server(t);
ec2c5e43
LP
437
438 r = dns_transaction_go(t);
439 if (r < 0) {
440 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
441 return;
442 }
443
444 return;
445 }
446 }
447
448 /* Parse and update the cache */
449 r = dns_packet_extract(p);
450 if (r < 0) {
451 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
452 return;
453 }
454
29815b6c 455 /* Only consider responses with equivalent query section to the request */
f52e61da 456 if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) {
29815b6c 457 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
6709eb94
TG
458 return;
459 }
29815b6c 460
ec2c5e43 461 /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
8e427d9b 462 dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
ec2c5e43
LP
463
464 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
465 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
466 else
467 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
468}
469
c19ffd9f
TG
470static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
471 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
472 DnsTransaction *t = userdata;
473 int r;
474
475 assert(t);
476 assert(t->scope);
477
478 r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
479 if (r <= 0)
480 return r;
481
482 if (dns_packet_validate_reply(p) > 0 &&
9df3ba6c 483 DNS_PACKET_ID(p) == t->id)
c19ffd9f 484 dns_transaction_process_reply(t, p);
9df3ba6c 485 else
c19ffd9f
TG
486 log_debug("Invalid DNS packet.");
487
488 return 0;
489}
490
471d40d9 491static int dns_transaction_emit(DnsTransaction *t) {
c19ffd9f
TG
492 int r;
493
494 assert(t);
c19ffd9f 495
471d40d9
TG
496 if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) {
497 DnsServer *server = NULL;
498 _cleanup_close_ int fd = -1;
c19ffd9f 499
471d40d9
TG
500 fd = dns_scope_udp_dns_socket(t->scope, &server);
501 if (fd < 0)
502 return fd;
c19ffd9f 503
4667e00a 504 r = sd_event_add_io(t->scope->manager->event, &t->dns_udp_event_source, fd, EPOLLIN, on_dns_packet, t);
471d40d9
TG
505 if (r < 0)
506 return r;
c19ffd9f 507
4667e00a 508 t->dns_udp_fd = fd;
471d40d9
TG
509 fd = -1;
510 t->server = dns_server_ref(server);
511 }
c19ffd9f 512
4667e00a 513 r = dns_scope_emit(t->scope, t->dns_udp_fd, t->sent);
471d40d9
TG
514 if (r < 0)
515 return r;
c19ffd9f 516
471d40d9 517 return 0;
c19ffd9f
TG
518}
519
ec2c5e43
LP
520static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
521 DnsTransaction *t = userdata;
522 int r;
523
524 assert(s);
525 assert(t);
526
527 /* Timeout reached? Try again, with a new server */
647f6aa8 528 dns_transaction_next_dns_server(t);
ec2c5e43 529
9df3ba6c
TG
530 /* ... and possibly increased timeout */
531 if (t->server)
532 dns_server_packet_lost(t->server, usec - t->start_usec);
533 else
534 dns_scope_packet_lost(t->scope, usec - t->start_usec);
535
ec2c5e43
LP
536 r = dns_transaction_go(t);
537 if (r < 0)
538 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
539
540 return 0;
541}
542
543static int dns_transaction_make_packet(DnsTransaction *t) {
544 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
ec2c5e43
LP
545 int r;
546
547 assert(t);
548
549 if (t->sent)
550 return 0;
551
552 r = dns_packet_new_query(&p, t->scope->protocol, 0);
553 if (r < 0)
554 return r;
555
f52e61da
LP
556 r = dns_scope_good_key(t->scope, t->key);
557 if (r < 0)
558 return r;
559 if (r == 0)
ec2c5e43
LP
560 return -EDOM;
561
f52e61da
LP
562 r = dns_packet_append_key(p, t->key, NULL);
563 if (r < 0)
564 return r;
565
566 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
ec2c5e43
LP
567 DNS_PACKET_HEADER(p)->id = t->id;
568
569 t->sent = p;
570 p = NULL;
571
572 return 0;
573}
574
9df3ba6c
TG
575static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
576 assert(t);
577 assert(t->scope);
578
579 switch (t->scope->protocol) {
580 case DNS_PROTOCOL_DNS:
581 assert(t->server);
582
583 return t->server->resend_timeout;
584 case DNS_PROTOCOL_LLMNR:
585 case DNS_PROTOCOL_MDNS:
586 return t->scope->resend_timeout;
587 default:
588 assert_not_reached("Invalid DNS protocol.");
589 }
590}
591
ec2c5e43
LP
592int dns_transaction_go(DnsTransaction *t) {
593 bool had_stream;
9df3ba6c 594 usec_t ts;
ec2c5e43
LP
595 int r;
596
597 assert(t);
598
599 had_stream = !!t->stream;
600
601 dns_transaction_stop(t);
602
e56187ca 603 log_debug("Excercising transaction on scope %s on %s/%s",
ec2c5e43
LP
604 dns_protocol_to_string(t->scope->protocol),
605 t->scope->link ? t->scope->link->name : "*",
606 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
607
608 if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
609 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
610 return 0;
611 }
612
613 if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) {
614 /* If we already tried via a stream, then we don't
615 * retry on LLMNR. See RFC 4795, Section 2.7. */
616 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
617 return 0;
618 }
619
38a03f06 620 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
9df3ba6c 621
ec2c5e43 622 t->n_attempts++;
9df3ba6c 623 t->start_usec = ts;
ec2c5e43
LP
624 t->received = dns_packet_unref(t->received);
625 t->cached = dns_answer_unref(t->cached);
626 t->cached_rcode = 0;
627
4d926a69
LP
628 /* Check the cache, but only if this transaction is not used
629 * for probing or verifying a zone item. */
630 if (set_isempty(t->zone_items)) {
2c27fbca 631
4d926a69
LP
632 /* Before trying the cache, let's make sure we figured out a
633 * server to use. Should this cause a change of server this
634 * might flush the cache. */
635 dns_scope_get_dns_server(t->scope);
2c27fbca 636
4d926a69
LP
637 /* Let's then prune all outdated entries */
638 dns_cache_prune(&t->scope->cache);
639
f52e61da 640 r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached);
4d926a69
LP
641 if (r < 0)
642 return r;
643 if (r > 0) {
4d926a69
LP
644 if (t->cached_rcode == DNS_RCODE_SUCCESS)
645 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
646 else
647 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
648 return 0;
649 }
ec2c5e43
LP
650 }
651
6e068472
LP
652 if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) {
653 usec_t jitter;
654
655 /* RFC 4795 Section 2.7 suggests all queries should be
656 * delayed by a random time from 0 to JITTER_INTERVAL. */
657
658 t->initial_jitter = true;
659
660 random_bytes(&jitter, sizeof(jitter));
661 jitter %= LLMNR_JITTER_INTERVAL_USEC;
662
663 r = sd_event_add_time(
664 t->scope->manager->event,
665 &t->timeout_event_source,
666 clock_boottime_or_monotonic(),
9df3ba6c 667 ts + jitter,
a4076574 668 LLMNR_JITTER_INTERVAL_USEC,
6e068472
LP
669 on_transaction_timeout, t);
670 if (r < 0)
671 return r;
672
673 t->n_attempts = 0;
674 t->state = DNS_TRANSACTION_PENDING;
675
676 log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter);
677 return 0;
678 }
679
ec2c5e43
LP
680 /* Otherwise, we need to ask the network */
681 r = dns_transaction_make_packet(t);
682 if (r == -EDOM) {
683 /* Not the right request to make on this network?
684 * (i.e. an A request made on IPv6 or an AAAA request
685 * made on IPv4, on LLMNR or mDNS.) */
686 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
687 return 0;
688 }
689 if (r < 0)
690 return r;
691
692 if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
f52e61da
LP
693 (dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "in-addr.arpa") > 0 ||
694 dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "ip6.arpa") > 0)) {
ec2c5e43
LP
695
696 /* RFC 4795, Section 2.4. says reverse lookups shall
697 * always be made via TCP on LLMNR */
698 r = dns_transaction_open_tcp(t);
699 } else {
700 /* Try via UDP, and if that fails due to large size try via TCP */
471d40d9
TG
701 r = dns_transaction_emit(t);
702 if (r == -EMSGSIZE)
ec2c5e43
LP
703 r = dns_transaction_open_tcp(t);
704 }
705 if (r == -ESRCH) {
706 /* No servers to send this to? */
707 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
708 return 0;
8300ba21 709 } else if (r < 0) {
13b551ac
LP
710 if (t->scope->protocol != DNS_PROTOCOL_DNS) {
711 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
712 return 0;
713 }
714
ec2c5e43 715 /* Couldn't send? Try immediately again, with a new server */
647f6aa8 716 dns_transaction_next_dns_server(t);
ec2c5e43
LP
717
718 return dns_transaction_go(t);
719 }
720
9a015429
LP
721 r = sd_event_add_time(
722 t->scope->manager->event,
723 &t->timeout_event_source,
724 clock_boottime_or_monotonic(),
9df3ba6c 725 ts + transaction_get_resend_timeout(t), 0,
9a015429 726 on_transaction_timeout, t);
ec2c5e43
LP
727 if (r < 0)
728 return r;
729
730 t->state = DNS_TRANSACTION_PENDING;
731 return 1;
732}
733
734static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
735 [DNS_TRANSACTION_NULL] = "null",
736 [DNS_TRANSACTION_PENDING] = "pending",
737 [DNS_TRANSACTION_FAILURE] = "failure",
738 [DNS_TRANSACTION_SUCCESS] = "success",
739 [DNS_TRANSACTION_NO_SERVERS] = "no-servers",
740 [DNS_TRANSACTION_TIMEOUT] = "timeout",
741 [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached",
742 [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply",
743 [DNS_TRANSACTION_RESOURCES] = "resources",
744 [DNS_TRANSACTION_ABORTED] = "aborted",
745};
746DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);