]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-transaction.c
hwdb: Update database of Bluetooth company identifiers
[thirdparty/systemd.git] / src / resolve / resolved-dns-transaction.c
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
24 #include "resolved-llmnr.h"
25 #include "resolved-dns-transaction.h"
26 #include "random-util.h"
27 #include "dns-domain.h"
28
29 DnsTransaction* 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
38 dns_packet_unref(t->sent);
39 dns_packet_unref(t->received);
40 dns_answer_unref(t->cached);
41
42 sd_event_source_unref(t->dns_udp_event_source);
43 safe_close(t->dns_udp_fd);
44
45 dns_server_unref(t->server);
46 dns_stream_free(t->stream);
47
48 if (t->scope) {
49 hashmap_remove(t->scope->transactions, t->key);
50
51 if (t->id != 0)
52 hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
53 }
54
55 dns_resource_key_unref(t->key);
56
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
69 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free);
70
71 void 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
81 int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) {
82 _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
83 int r;
84
85 assert(ret);
86 assert(s);
87 assert(key);
88
89 r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL);
90 if (r < 0)
91 return r;
92
93 r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops);
94 if (r < 0)
95 return r;
96
97 t = new0(DnsTransaction, 1);
98 if (!t)
99 return -ENOMEM;
100
101 t->dns_udp_fd = -1;
102 t->key = dns_resource_key_ref(key);
103
104 /* Find a fresh, unused transaction id */
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
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
122 t->scope = s;
123
124 if (ret)
125 *ret = t;
126
127 t = NULL;
128
129 return 0;
130 }
131
132 static 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
139 static 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
181 void 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
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
215 static 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
253 static int dns_transaction_open_tcp(DnsTransaction *t) {
254 DnsServer *server = NULL;
255 _cleanup_close_ int fd = -1;
256 int r;
257
258 assert(t);
259
260 if (t->stream)
261 return 0;
262
263 switch (t->scope->protocol) {
264 case DNS_PROTOCOL_DNS:
265 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
266 break;
267
268 case DNS_PROTOCOL_LLMNR:
269 /* When we already received a reply to this (but it was truncated), send to its sender address */
270 if (t->received)
271 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
272 else {
273 union in_addr_union address;
274 int family = AF_UNSPEC;
275
276 /* Otherwise, try to talk to the owner of a
277 * the IP address, in case this is a reverse
278 * PTR lookup */
279
280 r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address);
281 if (r < 0)
282 return r;
283 if (r == 0)
284 return -EINVAL;
285 if (family != t->scope->family)
286 return -ESRCH;
287
288 fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
289 }
290
291 break;
292
293 default:
294 return -EAFNOSUPPORT;
295 }
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
312 dns_server_unref(t->server);
313 t->server = dns_server_ref(server);
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
327 static void dns_transaction_next_dns_server(DnsTransaction *t) {
328 assert(t);
329
330 t->server = dns_server_unref(t->server);
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);
333
334 dns_scope_next_dns_server(t->scope);
335 }
336
337 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
338 usec_t ts;
339 int r;
340
341 assert(t);
342 assert(p);
343 assert(t->state == DNS_TRANSACTION_PENDING);
344 assert(t->scope);
345 assert(t->scope->manager);
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
351 switch (t->scope->protocol) {
352 case DNS_PROTOCOL_LLMNR:
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. */
367 if (DNS_PACKET_LLMNR_T(p)) {
368 dns_transaction_tentative(t, p);
369 return;
370 }
371
372 break;
373
374 case DNS_PROTOCOL_DNS:
375 break;
376
377 default:
378 assert_not_reached("Invalid DNS protocol.");
379 }
380
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
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
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 */
435 dns_transaction_next_dns_server(t);
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
454 /* Only consider responses with equivalent query section to the request */
455 if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) {
456 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
457 return;
458 }
459
460 /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
461 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
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
469 static 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 &&
482 DNS_PACKET_ID(p) == t->id)
483 dns_transaction_process_reply(t, p);
484 else
485 log_debug("Invalid DNS packet.");
486
487 return 0;
488 }
489
490 static 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
503 r = sd_event_add_io(t->scope->manager->event, &t->dns_udp_event_source, fd, EPOLLIN, on_dns_packet, t);
504 if (r < 0)
505 return r;
506
507 t->dns_udp_fd = fd;
508 fd = -1;
509 t->server = dns_server_ref(server);
510 }
511
512 r = dns_scope_emit(t->scope, t->dns_udp_fd, t->sent);
513 if (r < 0)
514 return r;
515
516 return 0;
517 }
518
519 static 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 */
527 dns_transaction_next_dns_server(t);
528
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
535 r = dns_transaction_go(t);
536 if (r < 0)
537 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
538
539 return 0;
540 }
541
542 static int dns_transaction_make_packet(DnsTransaction *t) {
543 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
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
555 r = dns_scope_good_key(t->scope, t->key);
556 if (r < 0)
557 return r;
558 if (r == 0)
559 return -EDOM;
560
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);
566 DNS_PACKET_HEADER(p)->id = t->id;
567
568 t->sent = p;
569 p = NULL;
570
571 return 0;
572 }
573
574 static 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
591 int dns_transaction_go(DnsTransaction *t) {
592 bool had_stream;
593 usec_t ts;
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
619 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
620
621 t->n_attempts++;
622 t->start_usec = ts;
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
639 r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached);
640 if (r < 0)
641 return r;
642 if (r > 0) {
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(),
666 ts + jitter,
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
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 &&
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)) {
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 */
700 r = dns_transaction_emit(t);
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;
708 } else if (r < 0) {
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 */
715 dns_transaction_next_dns_server(t);
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(),
724 ts + transaction_get_resend_timeout(t), 0,
725 on_transaction_timeout, t);
726 if (r < 0)
727 return r;
728
729 t->state = DNS_TRANSACTION_PENDING;
730 return 1;
731 }
732
733 static 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 };
745 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);