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