]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-transaction.c
resolved: remove runtime check for previously asserted condition
[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_event_source);
43 safe_close(t->dns_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_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 if (t->scope->protocol == DNS_PROTOCOL_DNS)
264 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
265 else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
266
267 /* When we already received a reply to this (but it was truncated), send to its sender address */
268 if (t->received)
269 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
270 else {
271 union in_addr_union address;
272 int family = AF_UNSPEC;
273
274 /* Otherwise, try to talk to the owner of a
275 * the IP address, in case this is a reverse
276 * PTR lookup */
277
278 r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address);
279 if (r < 0)
280 return r;
281 if (r == 0)
282 return -EINVAL;
283 if (family != t->scope->family)
284 return -ESRCH;
285
286 fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
287 }
288 } else
289 return -EAFNOSUPPORT;
290
291 if (fd < 0)
292 return fd;
293
294 r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
295 if (r < 0)
296 return r;
297
298 fd = -1;
299
300 r = dns_stream_write_packet(t->stream, t->sent);
301 if (r < 0) {
302 t->stream = dns_stream_free(t->stream);
303 return r;
304 }
305
306 dns_server_unref(t->server);
307 t->server = dns_server_ref(server);
308 t->received = dns_packet_unref(t->received);
309 t->stream->complete = on_stream_complete;
310 t->stream->transaction = t;
311
312 /* The interface index is difficult to determine if we are
313 * connecting to the local host, hence fill this in right away
314 * instead of determining it from the socket */
315 if (t->scope->link)
316 t->stream->ifindex = t->scope->link->ifindex;
317
318 return 0;
319 }
320
321 static void dns_transaction_next_dns_server(DnsTransaction *t) {
322 assert(t);
323
324 t->server = dns_server_unref(t->server);
325 t->dns_event_source = sd_event_source_unref(t->dns_event_source);
326 t->dns_fd = safe_close(t->dns_fd);
327
328 dns_scope_next_dns_server(t->scope);
329 }
330
331 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
332 usec_t ts;
333 int r;
334
335 assert(t);
336 assert(p);
337 assert(t->state == DNS_TRANSACTION_PENDING);
338 assert(t->scope);
339 assert(t->scope->manager);
340
341 /* Note that this call might invalidate the query. Callers
342 * should hence not attempt to access the query or transaction
343 * after calling this function. */
344
345 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
346 assert(t->scope->link);
347
348 /* For LLMNR we will not accept any packets from other
349 * interfaces */
350
351 if (p->ifindex != t->scope->link->ifindex)
352 return;
353
354 if (p->family != t->scope->family)
355 return;
356
357 /* Tentative packets are not full responses but still
358 * useful for identifying uniqueness conflicts during
359 * probing. */
360 if (DNS_PACKET_LLMNR_T(p)) {
361 dns_transaction_tentative(t, p);
362 return;
363 }
364 }
365
366 if (t->received != p) {
367 dns_packet_unref(t->received);
368 t->received = dns_packet_ref(p);
369 }
370
371 if (p->ipproto == IPPROTO_TCP) {
372 if (DNS_PACKET_TC(p)) {
373 /* Truncated via TCP? Somebody must be fucking with us */
374 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
375 return;
376 }
377
378 if (DNS_PACKET_ID(p) != t->id) {
379 /* Not the reply to our query? Somebody must be fucking with us */
380 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
381 return;
382 }
383 }
384
385 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
386
387 switch (t->scope->protocol) {
388 case DNS_PROTOCOL_DNS:
389 assert(t->server);
390
391 dns_server_packet_received(t->server, ts - t->start_usec);
392
393 break;
394 case DNS_PROTOCOL_LLMNR:
395 case DNS_PROTOCOL_MDNS:
396 dns_scope_packet_received(t->scope, ts - t->start_usec);
397
398 break;
399 default:
400 assert_not_reached("Invalid DNS protocol.");
401 }
402
403 if (DNS_PACKET_TC(p)) {
404 /* Response was truncated, let's try again with good old TCP */
405 r = dns_transaction_open_tcp(t);
406 if (r == -ESRCH) {
407 /* No servers found? Damn! */
408 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
409 return;
410 }
411 if (r < 0) {
412 /* On LLMNR, if we cannot connect to the host,
413 * we immediately give up */
414 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
415 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
416 return;
417 }
418
419 /* On DNS, couldn't send? Try immediately again, with a new server */
420 dns_transaction_next_dns_server(t);
421
422 r = dns_transaction_go(t);
423 if (r < 0) {
424 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
425 return;
426 }
427
428 return;
429 }
430 }
431
432 /* Parse and update the cache */
433 r = dns_packet_extract(p);
434 if (r < 0) {
435 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
436 return;
437 }
438
439 /* Only consider responses with equivalent query section to the request */
440 if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) {
441 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
442 return;
443 }
444
445 /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
446 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
447
448 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
449 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
450 else
451 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
452 }
453
454 static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
455 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
456 DnsTransaction *t = userdata;
457 int r;
458
459 assert(t);
460 assert(t->scope);
461
462 r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
463 if (r <= 0)
464 return r;
465
466 if (dns_packet_validate_reply(p) > 0 &&
467 DNS_PACKET_ID(p) == t->id)
468 dns_transaction_process_reply(t, p);
469 else
470 log_debug("Invalid DNS packet.");
471
472 return 0;
473 }
474
475 static int dns_transaction_emit(DnsTransaction *t) {
476 int r;
477
478 assert(t);
479
480 if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) {
481 DnsServer *server = NULL;
482 _cleanup_close_ int fd = -1;
483
484 fd = dns_scope_udp_dns_socket(t->scope, &server);
485 if (fd < 0)
486 return fd;
487
488 r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, fd, EPOLLIN, on_dns_packet, t);
489 if (r < 0)
490 return r;
491
492 t->dns_fd = fd;
493 fd = -1;
494 t->server = dns_server_ref(server);
495 }
496
497 r = dns_scope_emit(t->scope, t->dns_fd, t->sent);
498 if (r < 0)
499 return r;
500
501 return 0;
502 }
503
504 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
505 DnsTransaction *t = userdata;
506 int r;
507
508 assert(s);
509 assert(t);
510
511 /* Timeout reached? Try again, with a new server */
512 dns_transaction_next_dns_server(t);
513
514 /* ... and possibly increased timeout */
515 if (t->server)
516 dns_server_packet_lost(t->server, usec - t->start_usec);
517 else
518 dns_scope_packet_lost(t->scope, usec - t->start_usec);
519
520 r = dns_transaction_go(t);
521 if (r < 0)
522 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
523
524 return 0;
525 }
526
527 static int dns_transaction_make_packet(DnsTransaction *t) {
528 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
529 int r;
530
531 assert(t);
532
533 if (t->sent)
534 return 0;
535
536 r = dns_packet_new_query(&p, t->scope->protocol, 0);
537 if (r < 0)
538 return r;
539
540 r = dns_scope_good_key(t->scope, t->key);
541 if (r < 0)
542 return r;
543 if (r == 0)
544 return -EDOM;
545
546 r = dns_packet_append_key(p, t->key, NULL);
547 if (r < 0)
548 return r;
549
550 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
551 DNS_PACKET_HEADER(p)->id = t->id;
552
553 t->sent = p;
554 p = NULL;
555
556 return 0;
557 }
558
559 static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
560 assert(t);
561 assert(t->scope);
562
563 switch (t->scope->protocol) {
564 case DNS_PROTOCOL_DNS:
565 assert(t->server);
566
567 return t->server->resend_timeout;
568 case DNS_PROTOCOL_LLMNR:
569 case DNS_PROTOCOL_MDNS:
570 return t->scope->resend_timeout;
571 default:
572 assert_not_reached("Invalid DNS protocol.");
573 }
574 }
575
576 int dns_transaction_go(DnsTransaction *t) {
577 bool had_stream;
578 usec_t ts;
579 int r;
580
581 assert(t);
582
583 had_stream = !!t->stream;
584
585 dns_transaction_stop(t);
586
587 log_debug("Excercising transaction on scope %s on %s/%s",
588 dns_protocol_to_string(t->scope->protocol),
589 t->scope->link ? t->scope->link->name : "*",
590 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
591
592 if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
593 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
594 return 0;
595 }
596
597 if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) {
598 /* If we already tried via a stream, then we don't
599 * retry on LLMNR. See RFC 4795, Section 2.7. */
600 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
601 return 0;
602 }
603
604 assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
605
606 t->n_attempts++;
607 t->start_usec = ts;
608 t->received = dns_packet_unref(t->received);
609 t->cached = dns_answer_unref(t->cached);
610 t->cached_rcode = 0;
611
612 /* Check the cache, but only if this transaction is not used
613 * for probing or verifying a zone item. */
614 if (set_isempty(t->zone_items)) {
615
616 /* Before trying the cache, let's make sure we figured out a
617 * server to use. Should this cause a change of server this
618 * might flush the cache. */
619 dns_scope_get_dns_server(t->scope);
620
621 /* Let's then prune all outdated entries */
622 dns_cache_prune(&t->scope->cache);
623
624 r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached);
625 if (r < 0)
626 return r;
627 if (r > 0) {
628 if (t->cached_rcode == DNS_RCODE_SUCCESS)
629 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
630 else
631 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
632 return 0;
633 }
634 }
635
636 if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) {
637 usec_t jitter;
638
639 /* RFC 4795 Section 2.7 suggests all queries should be
640 * delayed by a random time from 0 to JITTER_INTERVAL. */
641
642 t->initial_jitter = true;
643
644 random_bytes(&jitter, sizeof(jitter));
645 jitter %= LLMNR_JITTER_INTERVAL_USEC;
646
647 r = sd_event_add_time(
648 t->scope->manager->event,
649 &t->timeout_event_source,
650 clock_boottime_or_monotonic(),
651 ts + jitter,
652 LLMNR_JITTER_INTERVAL_USEC,
653 on_transaction_timeout, t);
654 if (r < 0)
655 return r;
656
657 t->n_attempts = 0;
658 t->state = DNS_TRANSACTION_PENDING;
659
660 log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter);
661 return 0;
662 }
663
664 /* Otherwise, we need to ask the network */
665 r = dns_transaction_make_packet(t);
666 if (r == -EDOM) {
667 /* Not the right request to make on this network?
668 * (i.e. an A request made on IPv6 or an AAAA request
669 * made on IPv4, on LLMNR or mDNS.) */
670 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
671 return 0;
672 }
673 if (r < 0)
674 return r;
675
676 if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
677 (dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "in-addr.arpa") > 0 ||
678 dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "ip6.arpa") > 0)) {
679
680 /* RFC 4795, Section 2.4. says reverse lookups shall
681 * always be made via TCP on LLMNR */
682 r = dns_transaction_open_tcp(t);
683 } else {
684 /* Try via UDP, and if that fails due to large size try via TCP */
685 r = dns_transaction_emit(t);
686 if (r == -EMSGSIZE)
687 r = dns_transaction_open_tcp(t);
688 }
689 if (r == -ESRCH) {
690 /* No servers to send this to? */
691 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
692 return 0;
693 } else if (r < 0) {
694 if (t->scope->protocol != DNS_PROTOCOL_DNS) {
695 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
696 return 0;
697 }
698
699 /* Couldn't send? Try immediately again, with a new server */
700 dns_transaction_next_dns_server(t);
701
702 return dns_transaction_go(t);
703 }
704
705 r = sd_event_add_time(
706 t->scope->manager->event,
707 &t->timeout_event_source,
708 clock_boottime_or_monotonic(),
709 ts + transaction_get_resend_timeout(t), 0,
710 on_transaction_timeout, t);
711 if (r < 0)
712 return r;
713
714 t->state = DNS_TRANSACTION_PENDING;
715 return 1;
716 }
717
718 static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
719 [DNS_TRANSACTION_NULL] = "null",
720 [DNS_TRANSACTION_PENDING] = "pending",
721 [DNS_TRANSACTION_FAILURE] = "failure",
722 [DNS_TRANSACTION_SUCCESS] = "success",
723 [DNS_TRANSACTION_NO_SERVERS] = "no-servers",
724 [DNS_TRANSACTION_TIMEOUT] = "timeout",
725 [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached",
726 [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply",
727 [DNS_TRANSACTION_RESOURCES] = "resources",
728 [DNS_TRANSACTION_ABORTED] = "aborted",
729 };
730 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);