]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-transaction.c
Merge pull request #1681 from ssahani/journal
[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 "dns-domain.h"
25 #include "fd-util.h"
26 #include "random-util.h"
27 #include "resolved-dns-transaction.h"
28 #include "resolved-llmnr.h"
29
30 DnsTransaction* 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
39 dns_packet_unref(t->sent);
40 dns_packet_unref(t->received);
41 dns_answer_unref(t->cached);
42
43 sd_event_source_unref(t->dns_udp_event_source);
44 safe_close(t->dns_udp_fd);
45
46 dns_server_unref(t->server);
47 dns_stream_free(t->stream);
48
49 if (t->scope) {
50 hashmap_remove(t->scope->transactions, t->key);
51
52 if (t->id != 0)
53 hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
54 }
55
56 dns_resource_key_unref(t->key);
57
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
70 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free);
71
72 void 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
82 int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) {
83 _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
84 int r;
85
86 assert(ret);
87 assert(s);
88 assert(key);
89
90 r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL);
91 if (r < 0)
92 return r;
93
94 r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops);
95 if (r < 0)
96 return r;
97
98 t = new0(DnsTransaction, 1);
99 if (!t)
100 return -ENOMEM;
101
102 t->dns_udp_fd = -1;
103 t->key = dns_resource_key_ref(key);
104
105 /* Find a fresh, unused transaction id */
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
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
123 t->scope = s;
124
125 if (ret)
126 *ret = t;
127
128 t = NULL;
129
130 return 0;
131 }
132
133 static 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
140 static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
141 _cleanup_free_ char *pretty = NULL;
142 DnsZoneItem *z;
143
144 assert(t);
145 assert(p);
146
147 if (manager_our_packet(t->scope->manager, p) != 0)
148 return;
149
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",
153 dns_protocol_to_string(t->scope->protocol),
154 t->scope->link ? t->scope->link->name : "*",
155 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
156 pretty);
157
158 /* RFC 4795, Section 4.1 says that the peer with the
159 * lexicographically smaller IP address loses */
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.");
162 return;
163 }
164
165 log_debug("We have the lexicographically larger IP address and thus lost in the conflict.");
166
167 t->block_gc++;
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 */
175 dns_zone_item_conflict(z);
176 }
177 t->block_gc--;
178
179 dns_transaction_gc(t);
180 }
181
182 void 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));
189
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
216 static 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
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
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
254 static int dns_transaction_open_tcp(DnsTransaction *t) {
255 DnsServer *server = NULL;
256 _cleanup_close_ int fd = -1;
257 int r;
258
259 assert(t);
260
261 if (t->stream)
262 return 0;
263
264 switch (t->scope->protocol) {
265 case DNS_PROTOCOL_DNS:
266 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
267 break;
268
269 case DNS_PROTOCOL_LLMNR:
270 /* When we already received a reply to this (but it was truncated), send to its sender address */
271 if (t->received)
272 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
273 else {
274 union in_addr_union address;
275 int family = AF_UNSPEC;
276
277 /* Otherwise, try to talk to the owner of a
278 * the IP address, in case this is a reverse
279 * PTR lookup */
280
281 r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address);
282 if (r < 0)
283 return r;
284 if (r == 0)
285 return -EINVAL;
286 if (family != t->scope->family)
287 return -ESRCH;
288
289 fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
290 }
291
292 break;
293
294 default:
295 return -EAFNOSUPPORT;
296 }
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
313 dns_server_unref(t->server);
314 t->server = dns_server_ref(server);
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
328 static void dns_transaction_next_dns_server(DnsTransaction *t) {
329 assert(t);
330
331 t->server = dns_server_unref(t->server);
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);
334
335 dns_scope_next_dns_server(t->scope);
336 }
337
338 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
339 usec_t ts;
340 int r;
341
342 assert(t);
343 assert(p);
344 assert(t->state == DNS_TRANSACTION_PENDING);
345 assert(t->scope);
346 assert(t->scope->manager);
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
352 switch (t->scope->protocol) {
353 case DNS_PROTOCOL_LLMNR:
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. */
368 if (DNS_PACKET_LLMNR_T(p)) {
369 dns_transaction_tentative(t, p);
370 return;
371 }
372
373 break;
374
375 case DNS_PROTOCOL_DNS:
376 break;
377
378 default:
379 assert_not_reached("Invalid DNS protocol.");
380 }
381
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
401 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
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:
416 break;
417 }
418
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 */
436 dns_transaction_next_dns_server(t);
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
455 /* Only consider responses with equivalent query section to the request */
456 if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) {
457 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
458 return;
459 }
460
461 /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
462 dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
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
470 static 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 &&
483 DNS_PACKET_ID(p) == t->id)
484 dns_transaction_process_reply(t, p);
485 else
486 log_debug("Invalid DNS packet.");
487
488 return 0;
489 }
490
491 static int dns_transaction_emit(DnsTransaction *t) {
492 int r;
493
494 assert(t);
495
496 if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) {
497 DnsServer *server = NULL;
498 _cleanup_close_ int fd = -1;
499
500 fd = dns_scope_udp_dns_socket(t->scope, &server);
501 if (fd < 0)
502 return fd;
503
504 r = sd_event_add_io(t->scope->manager->event, &t->dns_udp_event_source, fd, EPOLLIN, on_dns_packet, t);
505 if (r < 0)
506 return r;
507
508 t->dns_udp_fd = fd;
509 fd = -1;
510 t->server = dns_server_ref(server);
511 }
512
513 r = dns_scope_emit(t->scope, t->dns_udp_fd, t->sent);
514 if (r < 0)
515 return r;
516
517 return 0;
518 }
519
520 static 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 */
528 dns_transaction_next_dns_server(t);
529
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
536 r = dns_transaction_go(t);
537 if (r < 0)
538 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
539
540 return 0;
541 }
542
543 static int dns_transaction_make_packet(DnsTransaction *t) {
544 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
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
556 r = dns_scope_good_key(t->scope, t->key);
557 if (r < 0)
558 return r;
559 if (r == 0)
560 return -EDOM;
561
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);
567 DNS_PACKET_HEADER(p)->id = t->id;
568
569 t->sent = p;
570 p = NULL;
571
572 return 0;
573 }
574
575 static 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
592 int dns_transaction_go(DnsTransaction *t) {
593 bool had_stream;
594 usec_t ts;
595 int r;
596
597 assert(t);
598
599 had_stream = !!t->stream;
600
601 dns_transaction_stop(t);
602
603 log_debug("Excercising transaction on scope %s on %s/%s",
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
620 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
621
622 t->n_attempts++;
623 t->start_usec = ts;
624 t->received = dns_packet_unref(t->received);
625 t->cached = dns_answer_unref(t->cached);
626 t->cached_rcode = 0;
627
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)) {
631
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);
636
637 /* Let's then prune all outdated entries */
638 dns_cache_prune(&t->scope->cache);
639
640 r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached);
641 if (r < 0)
642 return r;
643 if (r > 0) {
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 }
650 }
651
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(),
667 ts + jitter,
668 LLMNR_JITTER_INTERVAL_USEC,
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
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 &&
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)) {
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 */
701 r = dns_transaction_emit(t);
702 if (r == -EMSGSIZE)
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;
709 } else if (r < 0) {
710 if (t->scope->protocol != DNS_PROTOCOL_DNS) {
711 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
712 return 0;
713 }
714
715 /* Couldn't send? Try immediately again, with a new server */
716 dns_transaction_next_dns_server(t);
717
718 return dns_transaction_go(t);
719 }
720
721 r = sd_event_add_time(
722 t->scope->manager->event,
723 &t->timeout_event_source,
724 clock_boottime_or_monotonic(),
725 ts + transaction_get_resend_timeout(t), 0,
726 on_transaction_timeout, t);
727 if (r < 0)
728 return r;
729
730 t->state = DNS_TRANSACTION_PENDING;
731 return 1;
732 }
733
734 static 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 };
746 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);