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