File: | build-scan/../src/resolve/resolved-dns-packet.c |
Warning: | line 580, column 9 Potential leak of memory pointed to by 's' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | /*** | |||
3 | ***/ | |||
4 | ||||
5 | #if HAVE_GCRYPT1 | |||
6 | #include <gcrypt.h> | |||
7 | #endif | |||
8 | ||||
9 | #include "alloc-util.h" | |||
10 | #include "dns-domain.h" | |||
11 | #include "resolved-dns-packet.h" | |||
12 | #include "string-table.h" | |||
13 | #include "strv.h" | |||
14 | #include "unaligned.h" | |||
15 | #include "utf8.h" | |||
16 | #include "util.h" | |||
17 | ||||
18 | #define EDNS0_OPT_DO(1<<15) (1<<15) | |||
19 | ||||
20 | assert_cc(DNS_PACKET_SIZE_START > DNS_PACKET_HEADER_SIZE)GCC diagnostic push
; GCC diagnostic ignored "-Wdeclaration-after-statement" ; struct _assert_struct_16 { char x[(512u > sizeof(DnsPacketHeader )) ? 0 : -1]; }; GCC diagnostic pop | |||
21 | ||||
22 | typedef struct DnsPacketRewinder { | |||
23 | DnsPacket *packet; | |||
24 | size_t saved_rindex; | |||
25 | } DnsPacketRewinder; | |||
26 | ||||
27 | static void rewind_dns_packet(DnsPacketRewinder *rewinder) { | |||
28 | if (rewinder->packet) | |||
29 | dns_packet_rewind(rewinder->packet, rewinder->saved_rindex); | |||
30 | } | |||
31 | ||||
32 | #define INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0) | |||
33 | #define CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0) do { rewinder.packet = NULL((void*)0); } while (0) | |||
34 | ||||
35 | int dns_packet_new( | |||
36 | DnsPacket **ret, | |||
37 | DnsProtocol protocol, | |||
38 | size_t min_alloc_dsize, | |||
39 | size_t max_size) { | |||
40 | ||||
41 | DnsPacket *p; | |||
42 | size_t a; | |||
43 | ||||
44 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-packet.c" , 44, __PRETTY_FUNCTION__); } while (0); | |||
45 | assert(max_size >= DNS_PACKET_HEADER_SIZE)do { if ((__builtin_expect(!!(!(max_size >= sizeof(DnsPacketHeader ))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("max_size >= DNS_PACKET_HEADER_SIZE" ), "../src/resolve/resolved-dns-packet.c", 45, __PRETTY_FUNCTION__ ); } while (0); | |||
46 | ||||
47 | if (max_size > DNS_PACKET_SIZE_MAX0xFFFFu) | |||
48 | max_size = DNS_PACKET_SIZE_MAX0xFFFFu; | |||
49 | ||||
50 | /* The caller may not check what is going to be truly allocated, so do not allow to | |||
51 | * allocate a DNS packet bigger than DNS_PACKET_SIZE_MAX. | |||
52 | */ | |||
53 | if (min_alloc_dsize > DNS_PACKET_SIZE_MAX0xFFFFu) { | |||
54 | log_error("Requested packet data size too big: %zu", min_alloc_dsize)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 54, __func__, "Requested packet data size too big: %zu" , min_alloc_dsize) : -abs(_e); }); | |||
55 | return -EFBIG27; | |||
56 | } | |||
57 | ||||
58 | /* When dns_packet_new() is called with min_alloc_dsize == 0, allocate more than the | |||
59 | * absolute minimum (which is the dns packet header size), to avoid | |||
60 | * resizing immediately again after appending the first data to the packet. | |||
61 | */ | |||
62 | if (min_alloc_dsize < DNS_PACKET_HEADER_SIZEsizeof(DnsPacketHeader)) | |||
63 | a = DNS_PACKET_SIZE_START512u; | |||
64 | else | |||
65 | a = min_alloc_dsize; | |||
66 | ||||
67 | /* round up to next page size */ | |||
68 | a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a)ALIGN_TO(((((sizeof(DnsPacket)) + 7) & ~7) + a), page_size ()) - ALIGN(sizeof(DnsPacket))(((sizeof(DnsPacket)) + 7) & ~7); | |||
69 | ||||
70 | /* make sure we never allocate more than useful */ | |||
71 | if (a > max_size) | |||
72 | a = max_size; | |||
73 | ||||
74 | p = malloc0(ALIGN(sizeof(DnsPacket)) + a)(calloc(1, ((((sizeof(DnsPacket)) + 7) & ~7) + a))); | |||
75 | if (!p) | |||
76 | return -ENOMEM12; | |||
77 | ||||
78 | p->size = p->rindex = DNS_PACKET_HEADER_SIZEsizeof(DnsPacketHeader); | |||
79 | p->allocated = a; | |||
80 | p->max_size = max_size; | |||
81 | p->protocol = protocol; | |||
82 | p->opt_start = p->opt_size = (size_t) -1; | |||
83 | p->n_ref = 1; | |||
84 | ||||
85 | *ret = p; | |||
86 | ||||
87 | return 0; | |||
88 | } | |||
89 | ||||
90 | void dns_packet_set_flags(DnsPacket *p, bool_Bool dnssec_checking_disabled, bool_Bool truncated) { | |||
91 | ||||
92 | DnsPacketHeader *h; | |||
93 | ||||
94 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 94, __PRETTY_FUNCTION__); } while (0); | |||
95 | ||||
96 | h = DNS_PACKET_HEADER(p)((DnsPacketHeader*) DNS_PACKET_DATA(p)); | |||
97 | ||||
98 | switch(p->protocol) { | |||
99 | case DNS_PROTOCOL_LLMNR: | |||
100 | assert(!truncated)do { if ((__builtin_expect(!!(!(!truncated)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!truncated"), "../src/resolve/resolved-dns-packet.c" , 100, __PRETTY_FUNCTION__); } while (0); | |||
101 | ||||
102 | h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
103 | 0 /* opcode */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
104 | 0 /* c */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
105 | 0 /* tc */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
106 | 0 /* t */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
107 | 0 /* ra */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
108 | 0 /* ad */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
109 | 0 /* cd */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
110 | 0 /* rcode */)(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(0) << 4) | ((uint16_t) ((0) & 15)))); | |||
111 | break; | |||
112 | ||||
113 | case DNS_PROTOCOL_MDNS: | |||
114 | h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
115 | 0 /* opcode */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
116 | 0 /* aa */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
117 | truncated /* tc */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
118 | 0 /* rd (ask for recursion) */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
119 | 0 /* ra */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
120 | 0 /* ad */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
121 | 0 /* cd */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15))) | |||
122 | 0 /* rcode */)(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(truncated ) << 9) | ((uint16_t) !!(0) << 8) | ((uint16_t) ! !(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t ) !!(0) << 4) | ((uint16_t) ((0) & 15)))); | |||
123 | break; | |||
124 | ||||
125 | default: | |||
126 | assert(!truncated)do { if ((__builtin_expect(!!(!(!truncated)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!truncated"), "../src/resolve/resolved-dns-packet.c" , 126, __PRETTY_FUNCTION__); } while (0); | |||
127 | ||||
128 | h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
129 | 0 /* opcode */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
130 | 0 /* aa */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
131 | 0 /* tc */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
132 | 1 /* rd (ask for recursion) */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
133 | 0 /* ra */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
134 | 0 /* ad */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
135 | dnssec_checking_disabled /* cd */,(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15))) | |||
136 | 0 /* rcode */)(((uint16_t) !!(0) << 15) | ((uint16_t) ((0) & 15) << 11) | ((uint16_t) !!(0) << 10) | ((uint16_t) !!(0) << 9) | ((uint16_t) !!(1) << 8) | ((uint16_t) !!(0) << 7) | ((uint16_t) !!(0) << 5) | ((uint16_t) !!(dnssec_checking_disabled ) << 4) | ((uint16_t) ((0) & 15)))); | |||
137 | } | |||
138 | } | |||
139 | ||||
140 | int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize, bool_Bool dnssec_checking_disabled) { | |||
141 | DnsPacket *p; | |||
142 | int r; | |||
143 | ||||
144 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-packet.c" , 144, __PRETTY_FUNCTION__); } while (0); | |||
145 | ||||
146 | r = dns_packet_new(&p, protocol, min_alloc_dsize, DNS_PACKET_SIZE_MAX0xFFFFu); | |||
147 | if (r < 0) | |||
148 | return r; | |||
149 | ||||
150 | /* Always set the TC bit to 0 initially. | |||
151 | * If there are multiple packets later, we'll update the bit shortly before sending. | |||
152 | */ | |||
153 | dns_packet_set_flags(p, dnssec_checking_disabled, false0); | |||
154 | ||||
155 | *ret = p; | |||
156 | return 0; | |||
157 | } | |||
158 | ||||
159 | DnsPacket *dns_packet_ref(DnsPacket *p) { | |||
160 | ||||
161 | if (!p) | |||
162 | return NULL((void*)0); | |||
163 | ||||
164 | assert(!p->on_stack)do { if ((__builtin_expect(!!(!(!p->on_stack)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!p->on_stack"), "../src/resolve/resolved-dns-packet.c" , 164, __PRETTY_FUNCTION__); } while (0); | |||
165 | ||||
166 | assert(p->n_ref > 0)do { if ((__builtin_expect(!!(!(p->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p->n_ref > 0"), "../src/resolve/resolved-dns-packet.c" , 166, __PRETTY_FUNCTION__); } while (0); | |||
167 | p->n_ref++; | |||
168 | return p; | |||
169 | } | |||
170 | ||||
171 | static void dns_packet_free(DnsPacket *p) { | |||
172 | char *s; | |||
173 | ||||
174 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 174, __PRETTY_FUNCTION__); } while (0); | |||
175 | ||||
176 | dns_question_unref(p->question); | |||
177 | dns_answer_unref(p->answer); | |||
178 | dns_resource_record_unref(p->opt); | |||
179 | ||||
180 | while ((s = hashmap_steal_first_key(p->names))) | |||
181 | free(s); | |||
182 | hashmap_free(p->names); | |||
183 | ||||
184 | free(p->_data); | |||
185 | ||||
186 | if (!p->on_stack) | |||
187 | free(p); | |||
188 | } | |||
189 | ||||
190 | DnsPacket *dns_packet_unref(DnsPacket *p) { | |||
191 | if (!p) | |||
192 | return NULL((void*)0); | |||
193 | ||||
194 | assert(p->n_ref > 0)do { if ((__builtin_expect(!!(!(p->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p->n_ref > 0"), "../src/resolve/resolved-dns-packet.c" , 194, __PRETTY_FUNCTION__); } while (0); | |||
195 | ||||
196 | dns_packet_unref(p->more); | |||
197 | ||||
198 | if (p->n_ref == 1) | |||
199 | dns_packet_free(p); | |||
200 | else | |||
201 | p->n_ref--; | |||
202 | ||||
203 | return NULL((void*)0); | |||
204 | } | |||
205 | ||||
206 | int dns_packet_validate(DnsPacket *p) { | |||
207 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 207, __PRETTY_FUNCTION__); } while (0); | |||
208 | ||||
209 | if (p->size < DNS_PACKET_HEADER_SIZEsizeof(DnsPacketHeader)) | |||
210 | return -EBADMSG74; | |||
211 | ||||
212 | if (p->size > DNS_PACKET_SIZE_MAX0xFFFFu) | |||
213 | return -EBADMSG74; | |||
214 | ||||
215 | return 1; | |||
216 | } | |||
217 | ||||
218 | int dns_packet_validate_reply(DnsPacket *p) { | |||
219 | int r; | |||
220 | ||||
221 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 221, __PRETTY_FUNCTION__); } while (0); | |||
222 | ||||
223 | r = dns_packet_validate(p); | |||
224 | if (r < 0) | |||
225 | return r; | |||
226 | ||||
227 | if (DNS_PACKET_QR(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 15) & 1) != 1) | |||
228 | return 0; | |||
229 | ||||
230 | if (DNS_PACKET_OPCODE(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 11) & 15) != 0) | |||
231 | return -EBADMSG74; | |||
232 | ||||
233 | switch (p->protocol) { | |||
234 | ||||
235 | case DNS_PROTOCOL_LLMNR: | |||
236 | /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */ | |||
237 | if (DNS_PACKET_QDCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->qdcount) != 1) | |||
238 | return -EBADMSG74; | |||
239 | ||||
240 | break; | |||
241 | ||||
242 | case DNS_PROTOCOL_MDNS: | |||
243 | /* RFC 6762, Section 18 */ | |||
244 | if (DNS_PACKET_RCODE(p) != 0) | |||
245 | return -EBADMSG74; | |||
246 | ||||
247 | break; | |||
248 | ||||
249 | default: | |||
250 | break; | |||
251 | } | |||
252 | ||||
253 | return 1; | |||
254 | } | |||
255 | ||||
256 | int dns_packet_validate_query(DnsPacket *p) { | |||
257 | int r; | |||
258 | ||||
259 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 259, __PRETTY_FUNCTION__); } while (0); | |||
260 | ||||
261 | r = dns_packet_validate(p); | |||
262 | if (r < 0) | |||
263 | return r; | |||
264 | ||||
265 | if (DNS_PACKET_QR(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 15) & 1) != 0) | |||
266 | return 0; | |||
267 | ||||
268 | if (DNS_PACKET_OPCODE(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 11) & 15) != 0) | |||
269 | return -EBADMSG74; | |||
270 | ||||
271 | if (DNS_PACKET_TC(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 9) & 1)) | |||
272 | return -EBADMSG74; | |||
273 | ||||
274 | switch (p->protocol) { | |||
275 | ||||
276 | case DNS_PROTOCOL_LLMNR: | |||
277 | case DNS_PROTOCOL_DNS: | |||
278 | /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */ | |||
279 | if (DNS_PACKET_QDCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->qdcount) != 1) | |||
280 | return -EBADMSG74; | |||
281 | ||||
282 | /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */ | |||
283 | if (DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount) > 0) | |||
284 | return -EBADMSG74; | |||
285 | ||||
286 | /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */ | |||
287 | if (DNS_PACKET_NSCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->nscount) > 0) | |||
288 | return -EBADMSG74; | |||
289 | ||||
290 | break; | |||
291 | ||||
292 | case DNS_PROTOCOL_MDNS: | |||
293 | /* RFC 6762, Section 18 */ | |||
294 | if (DNS_PACKET_AA(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 10) & 1) != 0 || | |||
295 | DNS_PACKET_RD(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 8) & 1) != 0 || | |||
296 | DNS_PACKET_RA(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 7) & 1) != 0 || | |||
297 | DNS_PACKET_AD(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 5) & 1) != 0 || | |||
298 | DNS_PACKET_CD(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 4) & 1) != 0 || | |||
299 | DNS_PACKET_RCODE(p) != 0) | |||
300 | return -EBADMSG74; | |||
301 | ||||
302 | break; | |||
303 | ||||
304 | default: | |||
305 | break; | |||
306 | } | |||
307 | ||||
308 | return 1; | |||
309 | } | |||
310 | ||||
311 | static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) { | |||
312 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 312, __PRETTY_FUNCTION__); } while (0); | |||
313 | ||||
314 | if (p->size + add > p->allocated) { | |||
315 | size_t a, ms; | |||
316 | ||||
317 | a = PAGE_ALIGN((p->size + add) * 2)ALIGN_TO(((p->size + add) * 2), page_size()); | |||
318 | ||||
319 | ms = dns_packet_size_max(p); | |||
320 | if (a > ms) | |||
321 | a = ms; | |||
322 | ||||
323 | if (p->size + add > a) | |||
324 | return -EMSGSIZE90; | |||
325 | ||||
326 | if (p->_data) { | |||
327 | void *d; | |||
328 | ||||
329 | d = realloc(p->_data, a); | |||
330 | if (!d) | |||
331 | return -ENOMEM12; | |||
332 | ||||
333 | p->_data = d; | |||
334 | } else { | |||
335 | p->_data = malloc(a); | |||
336 | if (!p->_data) | |||
337 | return -ENOMEM12; | |||
338 | ||||
339 | memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket))(((sizeof(DnsPacket)) + 7) & ~7), p->size); | |||
340 | memzero((uint8_t*) p->_data + p->size, a - p->size)({ size_t _l_ = (a - p->size); void *_x_ = ((uint8_t*) p-> _data + p->size); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); }); | |||
341 | } | |||
342 | ||||
343 | p->allocated = a; | |||
344 | } | |||
345 | ||||
346 | if (start) | |||
347 | *start = p->size; | |||
348 | ||||
349 | if (ret) | |||
350 | *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size; | |||
351 | ||||
352 | p->size += add; | |||
353 | return 0; | |||
354 | } | |||
355 | ||||
356 | void dns_packet_truncate(DnsPacket *p, size_t sz) { | |||
357 | Iterator i; | |||
358 | char *s; | |||
359 | void *n; | |||
360 | ||||
361 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 361, __PRETTY_FUNCTION__); } while (0); | |||
362 | ||||
363 | if (p->size <= sz) | |||
364 | return; | |||
365 | ||||
366 | HASHMAP_FOREACH_KEY(n, s, p->names, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((p->names), & (i), (void**)&(n), (const void**) &(s)); ) { | |||
367 | ||||
368 | if (PTR_TO_SIZE(n)((size_t) ((uintptr_t) (n))) < sz) | |||
369 | continue; | |||
370 | ||||
371 | hashmap_remove(p->names, s); | |||
372 | free(s); | |||
373 | } | |||
374 | ||||
375 | p->size = sz; | |||
376 | } | |||
377 | ||||
378 | int dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) { | |||
379 | void *q; | |||
380 | int r; | |||
381 | ||||
382 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 382, __PRETTY_FUNCTION__); } while (0); | |||
383 | ||||
384 | r = dns_packet_extend(p, l, &q, start); | |||
385 | if (r < 0) | |||
386 | return r; | |||
387 | ||||
388 | memcpy(q, d, l); | |||
389 | return 0; | |||
390 | } | |||
391 | ||||
392 | int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) { | |||
393 | void *d; | |||
394 | int r; | |||
395 | ||||
396 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 396, __PRETTY_FUNCTION__); } while (0); | |||
397 | ||||
398 | r = dns_packet_extend(p, sizeof(uint8_t), &d, start); | |||
399 | if (r < 0) | |||
400 | return r; | |||
401 | ||||
402 | ((uint8_t*) d)[0] = v; | |||
403 | ||||
404 | return 0; | |||
405 | } | |||
406 | ||||
407 | int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) { | |||
408 | void *d; | |||
409 | int r; | |||
410 | ||||
411 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 411, __PRETTY_FUNCTION__); } while (0); | |||
412 | ||||
413 | r = dns_packet_extend(p, sizeof(uint16_t), &d, start); | |||
414 | if (r < 0) | |||
415 | return r; | |||
416 | ||||
417 | unaligned_write_be16(d, v); | |||
418 | ||||
419 | return 0; | |||
420 | } | |||
421 | ||||
422 | int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) { | |||
423 | void *d; | |||
424 | int r; | |||
425 | ||||
426 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 426, __PRETTY_FUNCTION__); } while (0); | |||
427 | ||||
428 | r = dns_packet_extend(p, sizeof(uint32_t), &d, start); | |||
429 | if (r < 0) | |||
430 | return r; | |||
431 | ||||
432 | unaligned_write_be32(d, v); | |||
433 | ||||
434 | return 0; | |||
435 | } | |||
436 | ||||
437 | int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) { | |||
438 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 438, __PRETTY_FUNCTION__); } while (0); | |||
439 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-packet.c" , 439, __PRETTY_FUNCTION__); } while (0); | |||
440 | ||||
441 | return dns_packet_append_raw_string(p, s, strlen(s), start); | |||
442 | } | |||
443 | ||||
444 | int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start) { | |||
445 | void *d; | |||
446 | int r; | |||
447 | ||||
448 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 448, __PRETTY_FUNCTION__); } while (0); | |||
449 | assert(s || size == 0)do { if ((__builtin_expect(!!(!(s || size == 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s || size == 0"), "../src/resolve/resolved-dns-packet.c" , 449, __PRETTY_FUNCTION__); } while (0); | |||
450 | ||||
451 | if (size > 255) | |||
452 | return -E2BIG7; | |||
453 | ||||
454 | r = dns_packet_extend(p, 1 + size, &d, start); | |||
455 | if (r < 0) | |||
456 | return r; | |||
457 | ||||
458 | ((uint8_t*) d)[0] = (uint8_t) size; | |||
459 | ||||
460 | memcpy_safe(((uint8_t*) d) + 1, s, size); | |||
461 | ||||
462 | return 0; | |||
463 | } | |||
464 | ||||
465 | int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, bool_Bool canonical_candidate, size_t *start) { | |||
466 | uint8_t *w; | |||
467 | int r; | |||
468 | ||||
469 | /* Append a label to a packet. Optionally, does this in DNSSEC | |||
470 | * canonical form, if this label is marked as a candidate for | |||
471 | * it, and the canonical form logic is enabled for the | |||
472 | * packet */ | |||
473 | ||||
474 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 474, __PRETTY_FUNCTION__); } while (0); | |||
475 | assert(d)do { if ((__builtin_expect(!!(!(d)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("d"), "../src/resolve/resolved-dns-packet.c" , 475, __PRETTY_FUNCTION__); } while (0); | |||
476 | ||||
477 | if (l > DNS_LABEL_MAX63) | |||
478 | return -E2BIG7; | |||
479 | ||||
480 | r = dns_packet_extend(p, 1 + l, (void**) &w, start); | |||
481 | if (r < 0) | |||
482 | return r; | |||
483 | ||||
484 | *(w++) = (uint8_t) l; | |||
485 | ||||
486 | if (p->canonical_form && canonical_candidate) { | |||
487 | size_t i; | |||
488 | ||||
489 | /* Generate in canonical form, as defined by DNSSEC | |||
490 | * RFC 4034, Section 6.2, i.e. all lower-case. */ | |||
491 | ||||
492 | for (i = 0; i < l; i++) | |||
493 | w[i] = (uint8_t) ascii_tolower(d[i]); | |||
494 | } else | |||
495 | /* Otherwise, just copy the string unaltered. This is | |||
496 | * essential for DNS-SD, where the casing of labels | |||
497 | * matters and needs to be retained. */ | |||
498 | memcpy(w, d, l); | |||
499 | ||||
500 | return 0; | |||
501 | } | |||
502 | ||||
503 | int dns_packet_append_name( | |||
504 | DnsPacket *p, | |||
505 | const char *name, | |||
506 | bool_Bool allow_compression, | |||
507 | bool_Bool canonical_candidate, | |||
508 | size_t *start) { | |||
509 | ||||
510 | size_t saved_size; | |||
511 | int r; | |||
512 | ||||
513 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 513, __PRETTY_FUNCTION__); } while (0); | |||
514 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/resolve/resolved-dns-packet.c" , 514, __PRETTY_FUNCTION__); } while (0); | |||
515 | ||||
516 | if (p->refuse_compression) | |||
517 | allow_compression = false0; | |||
518 | ||||
519 | saved_size = p->size; | |||
520 | ||||
521 | while (!dns_name_is_root(name)) { | |||
522 | const char *z = name; | |||
523 | char label[DNS_LABEL_MAX63]; | |||
524 | size_t n = 0; | |||
525 | ||||
526 | if (allow_compression
| |||
527 | n = PTR_TO_SIZE(hashmap_get(p->names, name))((size_t) ((uintptr_t) (hashmap_get(p->names, name)))); | |||
528 | if (n > 0) { | |||
529 | assert(n < p->size)do { if ((__builtin_expect(!!(!(n < p->size)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n < p->size"), "../src/resolve/resolved-dns-packet.c" , 529, __PRETTY_FUNCTION__); } while (0); | |||
530 | ||||
531 | if (n < 0x4000) { | |||
532 | r = dns_packet_append_uint16(p, 0xC000 | n, NULL((void*)0)); | |||
533 | if (r < 0) | |||
534 | goto fail; | |||
535 | ||||
536 | goto done; | |||
537 | } | |||
538 | } | |||
539 | ||||
540 | r = dns_label_unescape(&name, label, sizeof(label)); | |||
541 | if (r < 0) | |||
542 | goto fail; | |||
543 | ||||
544 | r = dns_packet_append_label(p, label, r, canonical_candidate, &n); | |||
545 | if (r < 0) | |||
546 | goto fail; | |||
547 | ||||
548 | if (allow_compression
| |||
549 | _cleanup_free___attribute__((cleanup(freep))) char *s = NULL((void*)0); | |||
550 | ||||
551 | s = strdup(z); | |||
552 | if (!s) { | |||
553 | r = -ENOMEM12; | |||
554 | goto fail; | |||
555 | } | |||
556 | ||||
557 | r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops)internal_hashmap_ensure_allocated(&p->names, &dns_name_hash_ops ); | |||
558 | if (r < 0) | |||
559 | goto fail; | |||
560 | ||||
561 | r = hashmap_put(p->names, s, SIZE_TO_PTR(n)((void *) ((uintptr_t) (n)))); | |||
562 | if (r < 0) | |||
563 | goto fail; | |||
564 | ||||
565 | s = NULL((void*)0); | |||
566 | } | |||
567 | } | |||
568 | ||||
569 | r = dns_packet_append_uint8(p, 0, NULL((void*)0)); | |||
570 | if (r < 0) | |||
571 | return r; | |||
572 | ||||
573 | done: | |||
574 | if (start) | |||
575 | *start = saved_size; | |||
576 | ||||
577 | return 0; | |||
578 | ||||
579 | fail: | |||
580 | dns_packet_truncate(p, saved_size); | |||
| ||||
581 | return r; | |||
582 | } | |||
583 | ||||
584 | int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, const DnsAnswerFlags flags, size_t *start) { | |||
585 | size_t saved_size; | |||
586 | uint16_t class; | |||
587 | int r; | |||
588 | ||||
589 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 589, __PRETTY_FUNCTION__); } while (0); | |||
590 | assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("k"), "../src/resolve/resolved-dns-packet.c" , 590, __PRETTY_FUNCTION__); } while (0); | |||
591 | ||||
592 | saved_size = p->size; | |||
593 | ||||
594 | r = dns_packet_append_name(p, dns_resource_key_name(k), true1, true1, NULL((void*)0)); | |||
595 | if (r < 0) | |||
596 | goto fail; | |||
597 | ||||
598 | r = dns_packet_append_uint16(p, k->type, NULL((void*)0)); | |||
599 | if (r < 0) | |||
600 | goto fail; | |||
601 | ||||
602 | class = flags & DNS_ANSWER_CACHE_FLUSH ? k->class | MDNS_RR_CACHE_FLUSH(1 << 15) : k->class; | |||
603 | r = dns_packet_append_uint16(p, class, NULL((void*)0)); | |||
604 | if (r < 0) | |||
605 | goto fail; | |||
606 | ||||
607 | if (start) | |||
608 | *start = saved_size; | |||
609 | ||||
610 | return 0; | |||
611 | ||||
612 | fail: | |||
613 | dns_packet_truncate(p, saved_size); | |||
614 | return r; | |||
615 | } | |||
616 | ||||
617 | static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, const uint8_t *types, size_t *start) { | |||
618 | size_t saved_size; | |||
619 | int r; | |||
620 | ||||
621 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 621, __PRETTY_FUNCTION__); } while (0); | |||
622 | assert(types)do { if ((__builtin_expect(!!(!(types)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("types"), "../src/resolve/resolved-dns-packet.c" , 622, __PRETTY_FUNCTION__); } while (0); | |||
623 | assert(length > 0)do { if ((__builtin_expect(!!(!(length > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("length > 0"), "../src/resolve/resolved-dns-packet.c" , 623, __PRETTY_FUNCTION__); } while (0); | |||
624 | ||||
625 | saved_size = p->size; | |||
626 | ||||
627 | r = dns_packet_append_uint8(p, window, NULL((void*)0)); | |||
628 | if (r < 0) | |||
629 | goto fail; | |||
630 | ||||
631 | r = dns_packet_append_uint8(p, length, NULL((void*)0)); | |||
632 | if (r < 0) | |||
633 | goto fail; | |||
634 | ||||
635 | r = dns_packet_append_blob(p, types, length, NULL((void*)0)); | |||
636 | if (r < 0) | |||
637 | goto fail; | |||
638 | ||||
639 | if (start) | |||
640 | *start = saved_size; | |||
641 | ||||
642 | return 0; | |||
643 | fail: | |||
644 | dns_packet_truncate(p, saved_size); | |||
645 | return r; | |||
646 | } | |||
647 | ||||
648 | static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) { | |||
649 | Iterator i; | |||
650 | uint8_t window = 0; | |||
651 | uint8_t entry = 0; | |||
652 | uint8_t bitmaps[32] = {}; | |||
653 | unsigned n; | |||
654 | size_t saved_size; | |||
655 | int r; | |||
656 | ||||
657 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 657, __PRETTY_FUNCTION__); } while (0); | |||
658 | ||||
659 | saved_size = p->size; | |||
660 | ||||
661 | BITMAP_FOREACH(n, types, i)for ((i).idx = 0; bitmap_iterate((types), &(i), (unsigned *)&(n)); ) { | |||
662 | assert(n <= 0xffff)do { if ((__builtin_expect(!!(!(n <= 0xffff)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n <= 0xffff"), "../src/resolve/resolved-dns-packet.c" , 662, __PRETTY_FUNCTION__); } while (0); | |||
663 | ||||
664 | if ((n >> 8) != window && bitmaps[entry / 8] != 0) { | |||
665 | r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL((void*)0)); | |||
666 | if (r < 0) | |||
667 | goto fail; | |||
668 | ||||
669 | zero(bitmaps)(({ size_t _l_ = (sizeof(bitmaps)); void *_x_ = (&(bitmaps )); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
670 | } | |||
671 | ||||
672 | window = n >> 8; | |||
673 | entry = n & 255; | |||
674 | ||||
675 | bitmaps[entry / 8] |= 1 << (7 - (entry % 8)); | |||
676 | } | |||
677 | ||||
678 | if (bitmaps[entry / 8] != 0) { | |||
679 | r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL((void*)0)); | |||
680 | if (r < 0) | |||
681 | goto fail; | |||
682 | } | |||
683 | ||||
684 | if (start) | |||
685 | *start = saved_size; | |||
686 | ||||
687 | return 0; | |||
688 | fail: | |||
689 | dns_packet_truncate(p, saved_size); | |||
690 | return r; | |||
691 | } | |||
692 | ||||
693 | /* Append the OPT pseudo-RR described in RFC6891 */ | |||
694 | int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool_Bool edns0_do, int rcode, size_t *start) { | |||
695 | size_t saved_size; | |||
696 | int r; | |||
697 | ||||
698 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 698, __PRETTY_FUNCTION__); } while (0); | |||
699 | /* we must never advertise supported packet size smaller than the legacy max */ | |||
700 | assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX)do { if ((__builtin_expect(!!(!(max_udp_size >= 512u)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX" ), "../src/resolve/resolved-dns-packet.c", 700, __PRETTY_FUNCTION__ ); } while (0); | |||
701 | assert(rcode >= 0)do { if ((__builtin_expect(!!(!(rcode >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rcode >= 0"), "../src/resolve/resolved-dns-packet.c" , 701, __PRETTY_FUNCTION__); } while (0); | |||
702 | assert(rcode <= _DNS_RCODE_MAX)do { if ((__builtin_expect(!!(!(rcode <= _DNS_RCODE_MAX)), 0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("rcode <= _DNS_RCODE_MAX" ), "../src/resolve/resolved-dns-packet.c", 702, __PRETTY_FUNCTION__ ); } while (0); | |||
703 | ||||
704 | if (p->opt_start != (size_t) -1) | |||
705 | return -EBUSY16; | |||
706 | ||||
707 | assert(p->opt_size == (size_t) -1)do { if ((__builtin_expect(!!(!(p->opt_size == (size_t) -1 )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("p->opt_size == (size_t) -1" ), "../src/resolve/resolved-dns-packet.c", 707, __PRETTY_FUNCTION__ ); } while (0); | |||
708 | ||||
709 | saved_size = p->size; | |||
710 | ||||
711 | /* empty name */ | |||
712 | r = dns_packet_append_uint8(p, 0, NULL((void*)0)); | |||
713 | if (r < 0) | |||
714 | return r; | |||
715 | ||||
716 | /* type */ | |||
717 | r = dns_packet_append_uint16(p, DNS_TYPE_OPT, NULL((void*)0)); | |||
718 | if (r < 0) | |||
719 | goto fail; | |||
720 | ||||
721 | /* class: maximum udp packet that can be received */ | |||
722 | r = dns_packet_append_uint16(p, max_udp_size, NULL((void*)0)); | |||
723 | if (r < 0) | |||
724 | goto fail; | |||
725 | ||||
726 | /* extended RCODE and VERSION */ | |||
727 | r = dns_packet_append_uint16(p, ((uint16_t) rcode & 0x0FF0) << 4, NULL((void*)0)); | |||
728 | if (r < 0) | |||
729 | goto fail; | |||
730 | ||||
731 | /* flags: DNSSEC OK (DO), see RFC3225 */ | |||
732 | r = dns_packet_append_uint16(p, edns0_do ? EDNS0_OPT_DO(1<<15) : 0, NULL((void*)0)); | |||
733 | if (r < 0) | |||
734 | goto fail; | |||
735 | ||||
736 | /* RDLENGTH */ | |||
737 | if (edns0_do && !DNS_PACKET_QR(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 15) & 1)) { | |||
738 | /* If DO is on and this is not a reply, also append RFC6975 Algorithm data */ | |||
739 | ||||
740 | static const uint8_t rfc6975[] = { | |||
741 | ||||
742 | 0, 5, /* OPTION_CODE: DAU */ | |||
743 | #if HAVE_GCRYPT1 && GCRYPT_VERSION_NUMBER0x010903 >= 0x010600 | |||
744 | 0, 7, /* LIST_LENGTH */ | |||
745 | #else | |||
746 | 0, 6, /* LIST_LENGTH */ | |||
747 | #endif | |||
748 | DNSSEC_ALGORITHM_RSASHA1, | |||
749 | DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, | |||
750 | DNSSEC_ALGORITHM_RSASHA256, | |||
751 | DNSSEC_ALGORITHM_RSASHA512, | |||
752 | DNSSEC_ALGORITHM_ECDSAP256SHA256, | |||
753 | DNSSEC_ALGORITHM_ECDSAP384SHA384, | |||
754 | #if HAVE_GCRYPT1 && GCRYPT_VERSION_NUMBER0x010903 >= 0x010600 | |||
755 | DNSSEC_ALGORITHM_ED25519, | |||
756 | #endif | |||
757 | ||||
758 | 0, 6, /* OPTION_CODE: DHU */ | |||
759 | 0, 3, /* LIST_LENGTH */ | |||
760 | DNSSEC_DIGEST_SHA1, | |||
761 | DNSSEC_DIGEST_SHA256, | |||
762 | DNSSEC_DIGEST_SHA384, | |||
763 | ||||
764 | 0, 7, /* OPTION_CODE: N3U */ | |||
765 | 0, 1, /* LIST_LENGTH */ | |||
766 | NSEC3_ALGORITHM_SHA1, | |||
767 | }; | |||
768 | ||||
769 | r = dns_packet_append_uint16(p, sizeof(rfc6975), NULL((void*)0)); | |||
770 | if (r < 0) | |||
771 | goto fail; | |||
772 | ||||
773 | r = dns_packet_append_blob(p, rfc6975, sizeof(rfc6975), NULL((void*)0)); | |||
774 | } else | |||
775 | r = dns_packet_append_uint16(p, 0, NULL((void*)0)); | |||
776 | if (r < 0) | |||
777 | goto fail; | |||
778 | ||||
779 | DNS_PACKET_HEADER(p)((DnsPacketHeader*) DNS_PACKET_DATA(p))->arcount = htobe16(DNS_PACKET_ARCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->arcount) + 1); | |||
780 | ||||
781 | p->opt_start = saved_size; | |||
782 | p->opt_size = p->size - saved_size; | |||
783 | ||||
784 | if (start) | |||
785 | *start = saved_size; | |||
786 | ||||
787 | return 0; | |||
788 | ||||
789 | fail: | |||
790 | dns_packet_truncate(p, saved_size); | |||
791 | return r; | |||
792 | } | |||
793 | ||||
794 | int dns_packet_truncate_opt(DnsPacket *p) { | |||
795 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 795, __PRETTY_FUNCTION__); } while (0); | |||
796 | ||||
797 | if (p->opt_start == (size_t) -1) { | |||
798 | assert(p->opt_size == (size_t) -1)do { if ((__builtin_expect(!!(!(p->opt_size == (size_t) -1 )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("p->opt_size == (size_t) -1" ), "../src/resolve/resolved-dns-packet.c", 798, __PRETTY_FUNCTION__ ); } while (0); | |||
799 | return 0; | |||
800 | } | |||
801 | ||||
802 | assert(p->opt_size != (size_t) -1)do { if ((__builtin_expect(!!(!(p->opt_size != (size_t) -1 )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("p->opt_size != (size_t) -1" ), "../src/resolve/resolved-dns-packet.c", 802, __PRETTY_FUNCTION__ ); } while (0); | |||
803 | assert(DNS_PACKET_ARCOUNT(p) > 0)do { if ((__builtin_expect(!!(!(be16toh(((DnsPacketHeader*) DNS_PACKET_DATA (p))->arcount) > 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("DNS_PACKET_ARCOUNT(p) > 0"), "../src/resolve/resolved-dns-packet.c" , 803, __PRETTY_FUNCTION__); } while (0); | |||
804 | ||||
805 | if (p->opt_start + p->opt_size != p->size) | |||
806 | return -EBUSY16; | |||
807 | ||||
808 | dns_packet_truncate(p, p->opt_start); | |||
809 | DNS_PACKET_HEADER(p)((DnsPacketHeader*) DNS_PACKET_DATA(p))->arcount = htobe16(DNS_PACKET_ARCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->arcount) - 1); | |||
810 | p->opt_start = p->opt_size = (size_t) -1; | |||
811 | ||||
812 | return 1; | |||
813 | } | |||
814 | ||||
815 | int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start) { | |||
816 | ||||
817 | size_t saved_size, rdlength_offset, end, rdlength, rds; | |||
818 | uint32_t ttl; | |||
819 | int r; | |||
820 | ||||
821 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 821, __PRETTY_FUNCTION__); } while (0); | |||
822 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-packet.c" , 822, __PRETTY_FUNCTION__); } while (0); | |||
823 | ||||
824 | saved_size = p->size; | |||
825 | ||||
826 | r = dns_packet_append_key(p, rr->key, flags, NULL((void*)0)); | |||
827 | if (r < 0) | |||
828 | goto fail; | |||
829 | ||||
830 | ttl = flags & DNS_ANSWER_GOODBYE ? 0 : rr->ttl; | |||
831 | r = dns_packet_append_uint32(p, ttl, NULL((void*)0)); | |||
832 | if (r < 0) | |||
833 | goto fail; | |||
834 | ||||
835 | /* Initially we write 0 here */ | |||
836 | r = dns_packet_append_uint16(p, 0, &rdlength_offset); | |||
837 | if (r < 0) | |||
838 | goto fail; | |||
839 | ||||
840 | rds = p->size - saved_size; | |||
841 | ||||
842 | switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { | |||
843 | ||||
844 | case DNS_TYPE_SRV: | |||
845 | r = dns_packet_append_uint16(p, rr->srv.priority, NULL((void*)0)); | |||
846 | if (r < 0) | |||
847 | goto fail; | |||
848 | ||||
849 | r = dns_packet_append_uint16(p, rr->srv.weight, NULL((void*)0)); | |||
850 | if (r < 0) | |||
851 | goto fail; | |||
852 | ||||
853 | r = dns_packet_append_uint16(p, rr->srv.port, NULL((void*)0)); | |||
854 | if (r < 0) | |||
855 | goto fail; | |||
856 | ||||
857 | r = dns_packet_append_name(p, rr->srv.name, true1, false0, NULL((void*)0)); | |||
858 | break; | |||
859 | ||||
860 | case DNS_TYPE_PTR: | |||
861 | case DNS_TYPE_NS: | |||
862 | case DNS_TYPE_CNAME: | |||
863 | case DNS_TYPE_DNAME: | |||
864 | r = dns_packet_append_name(p, rr->ptr.name, true1, false0, NULL((void*)0)); | |||
865 | break; | |||
866 | ||||
867 | case DNS_TYPE_HINFO: | |||
868 | r = dns_packet_append_string(p, rr->hinfo.cpu, NULL((void*)0)); | |||
869 | if (r < 0) | |||
870 | goto fail; | |||
871 | ||||
872 | r = dns_packet_append_string(p, rr->hinfo.os, NULL((void*)0)); | |||
873 | break; | |||
874 | ||||
875 | case DNS_TYPE_SPF: /* exactly the same as TXT */ | |||
876 | case DNS_TYPE_TXT: | |||
877 | ||||
878 | if (!rr->txt.items) { | |||
879 | /* RFC 6763, section 6.1 suggests to generate | |||
880 | * single empty string for an empty array. */ | |||
881 | ||||
882 | r = dns_packet_append_raw_string(p, NULL((void*)0), 0, NULL((void*)0)); | |||
883 | if (r < 0) | |||
884 | goto fail; | |||
885 | } else { | |||
886 | DnsTxtItem *i; | |||
887 | ||||
888 | LIST_FOREACH(items, i, rr->txt.items)for ((i) = (rr->txt.items); (i); (i) = (i)->items_next) { | |||
889 | r = dns_packet_append_raw_string(p, i->data, i->length, NULL((void*)0)); | |||
890 | if (r < 0) | |||
891 | goto fail; | |||
892 | } | |||
893 | } | |||
894 | ||||
895 | r = 0; | |||
896 | break; | |||
897 | ||||
898 | case DNS_TYPE_A: | |||
899 | r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL((void*)0)); | |||
900 | break; | |||
901 | ||||
902 | case DNS_TYPE_AAAA: | |||
903 | r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL((void*)0)); | |||
904 | break; | |||
905 | ||||
906 | case DNS_TYPE_SOA: | |||
907 | r = dns_packet_append_name(p, rr->soa.mname, true1, false0, NULL((void*)0)); | |||
908 | if (r < 0) | |||
909 | goto fail; | |||
910 | ||||
911 | r = dns_packet_append_name(p, rr->soa.rname, true1, false0, NULL((void*)0)); | |||
912 | if (r < 0) | |||
913 | goto fail; | |||
914 | ||||
915 | r = dns_packet_append_uint32(p, rr->soa.serial, NULL((void*)0)); | |||
916 | if (r < 0) | |||
917 | goto fail; | |||
918 | ||||
919 | r = dns_packet_append_uint32(p, rr->soa.refresh, NULL((void*)0)); | |||
920 | if (r < 0) | |||
921 | goto fail; | |||
922 | ||||
923 | r = dns_packet_append_uint32(p, rr->soa.retry, NULL((void*)0)); | |||
924 | if (r < 0) | |||
925 | goto fail; | |||
926 | ||||
927 | r = dns_packet_append_uint32(p, rr->soa.expire, NULL((void*)0)); | |||
928 | if (r < 0) | |||
929 | goto fail; | |||
930 | ||||
931 | r = dns_packet_append_uint32(p, rr->soa.minimum, NULL((void*)0)); | |||
932 | break; | |||
933 | ||||
934 | case DNS_TYPE_MX: | |||
935 | r = dns_packet_append_uint16(p, rr->mx.priority, NULL((void*)0)); | |||
936 | if (r < 0) | |||
937 | goto fail; | |||
938 | ||||
939 | r = dns_packet_append_name(p, rr->mx.exchange, true1, false0, NULL((void*)0)); | |||
940 | break; | |||
941 | ||||
942 | case DNS_TYPE_LOC: | |||
943 | r = dns_packet_append_uint8(p, rr->loc.version, NULL((void*)0)); | |||
944 | if (r < 0) | |||
945 | goto fail; | |||
946 | ||||
947 | r = dns_packet_append_uint8(p, rr->loc.size, NULL((void*)0)); | |||
948 | if (r < 0) | |||
949 | goto fail; | |||
950 | ||||
951 | r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL((void*)0)); | |||
952 | if (r < 0) | |||
953 | goto fail; | |||
954 | ||||
955 | r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL((void*)0)); | |||
956 | if (r < 0) | |||
957 | goto fail; | |||
958 | ||||
959 | r = dns_packet_append_uint32(p, rr->loc.latitude, NULL((void*)0)); | |||
960 | if (r < 0) | |||
961 | goto fail; | |||
962 | ||||
963 | r = dns_packet_append_uint32(p, rr->loc.longitude, NULL((void*)0)); | |||
964 | if (r < 0) | |||
965 | goto fail; | |||
966 | ||||
967 | r = dns_packet_append_uint32(p, rr->loc.altitude, NULL((void*)0)); | |||
968 | break; | |||
969 | ||||
970 | case DNS_TYPE_DS: | |||
971 | r = dns_packet_append_uint16(p, rr->ds.key_tag, NULL((void*)0)); | |||
972 | if (r < 0) | |||
973 | goto fail; | |||
974 | ||||
975 | r = dns_packet_append_uint8(p, rr->ds.algorithm, NULL((void*)0)); | |||
976 | if (r < 0) | |||
977 | goto fail; | |||
978 | ||||
979 | r = dns_packet_append_uint8(p, rr->ds.digest_type, NULL((void*)0)); | |||
980 | if (r < 0) | |||
981 | goto fail; | |||
982 | ||||
983 | r = dns_packet_append_blob(p, rr->ds.digest, rr->ds.digest_size, NULL((void*)0)); | |||
984 | break; | |||
985 | ||||
986 | case DNS_TYPE_SSHFP: | |||
987 | r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL((void*)0)); | |||
988 | if (r < 0) | |||
989 | goto fail; | |||
990 | ||||
991 | r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL((void*)0)); | |||
992 | if (r < 0) | |||
993 | goto fail; | |||
994 | ||||
995 | r = dns_packet_append_blob(p, rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, NULL((void*)0)); | |||
996 | break; | |||
997 | ||||
998 | case DNS_TYPE_DNSKEY: | |||
999 | r = dns_packet_append_uint16(p, rr->dnskey.flags, NULL((void*)0)); | |||
1000 | if (r < 0) | |||
1001 | goto fail; | |||
1002 | ||||
1003 | r = dns_packet_append_uint8(p, rr->dnskey.protocol, NULL((void*)0)); | |||
1004 | if (r < 0) | |||
1005 | goto fail; | |||
1006 | ||||
1007 | r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL((void*)0)); | |||
1008 | if (r < 0) | |||
1009 | goto fail; | |||
1010 | ||||
1011 | r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL((void*)0)); | |||
1012 | break; | |||
1013 | ||||
1014 | case DNS_TYPE_RRSIG: | |||
1015 | r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL((void*)0)); | |||
1016 | if (r < 0) | |||
1017 | goto fail; | |||
1018 | ||||
1019 | r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL((void*)0)); | |||
1020 | if (r < 0) | |||
1021 | goto fail; | |||
1022 | ||||
1023 | r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL((void*)0)); | |||
1024 | if (r < 0) | |||
1025 | goto fail; | |||
1026 | ||||
1027 | r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL((void*)0)); | |||
1028 | if (r < 0) | |||
1029 | goto fail; | |||
1030 | ||||
1031 | r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL((void*)0)); | |||
1032 | if (r < 0) | |||
1033 | goto fail; | |||
1034 | ||||
1035 | r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL((void*)0)); | |||
1036 | if (r < 0) | |||
1037 | goto fail; | |||
1038 | ||||
1039 | r = dns_packet_append_uint16(p, rr->rrsig.key_tag, NULL((void*)0)); | |||
1040 | if (r < 0) | |||
1041 | goto fail; | |||
1042 | ||||
1043 | r = dns_packet_append_name(p, rr->rrsig.signer, false0, true1, NULL((void*)0)); | |||
1044 | if (r < 0) | |||
1045 | goto fail; | |||
1046 | ||||
1047 | r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL((void*)0)); | |||
1048 | break; | |||
1049 | ||||
1050 | case DNS_TYPE_NSEC: | |||
1051 | r = dns_packet_append_name(p, rr->nsec.next_domain_name, false0, false0, NULL((void*)0)); | |||
1052 | if (r < 0) | |||
1053 | goto fail; | |||
1054 | ||||
1055 | r = dns_packet_append_types(p, rr->nsec.types, NULL((void*)0)); | |||
1056 | if (r < 0) | |||
1057 | goto fail; | |||
1058 | ||||
1059 | break; | |||
1060 | ||||
1061 | case DNS_TYPE_NSEC3: | |||
1062 | r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL((void*)0)); | |||
1063 | if (r < 0) | |||
1064 | goto fail; | |||
1065 | ||||
1066 | r = dns_packet_append_uint8(p, rr->nsec3.flags, NULL((void*)0)); | |||
1067 | if (r < 0) | |||
1068 | goto fail; | |||
1069 | ||||
1070 | r = dns_packet_append_uint16(p, rr->nsec3.iterations, NULL((void*)0)); | |||
1071 | if (r < 0) | |||
1072 | goto fail; | |||
1073 | ||||
1074 | r = dns_packet_append_uint8(p, rr->nsec3.salt_size, NULL((void*)0)); | |||
1075 | if (r < 0) | |||
1076 | goto fail; | |||
1077 | ||||
1078 | r = dns_packet_append_blob(p, rr->nsec3.salt, rr->nsec3.salt_size, NULL((void*)0)); | |||
1079 | if (r < 0) | |||
1080 | goto fail; | |||
1081 | ||||
1082 | r = dns_packet_append_uint8(p, rr->nsec3.next_hashed_name_size, NULL((void*)0)); | |||
1083 | if (r < 0) | |||
1084 | goto fail; | |||
1085 | ||||
1086 | r = dns_packet_append_blob(p, rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, NULL((void*)0)); | |||
1087 | if (r < 0) | |||
1088 | goto fail; | |||
1089 | ||||
1090 | r = dns_packet_append_types(p, rr->nsec3.types, NULL((void*)0)); | |||
1091 | if (r < 0) | |||
1092 | goto fail; | |||
1093 | ||||
1094 | break; | |||
1095 | ||||
1096 | case DNS_TYPE_TLSA: | |||
1097 | r = dns_packet_append_uint8(p, rr->tlsa.cert_usage, NULL((void*)0)); | |||
1098 | if (r < 0) | |||
1099 | goto fail; | |||
1100 | ||||
1101 | r = dns_packet_append_uint8(p, rr->tlsa.selector, NULL((void*)0)); | |||
1102 | if (r < 0) | |||
1103 | goto fail; | |||
1104 | ||||
1105 | r = dns_packet_append_uint8(p, rr->tlsa.matching_type, NULL((void*)0)); | |||
1106 | if (r < 0) | |||
1107 | goto fail; | |||
1108 | ||||
1109 | r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL((void*)0)); | |||
1110 | break; | |||
1111 | ||||
1112 | case DNS_TYPE_CAA: | |||
1113 | r = dns_packet_append_uint8(p, rr->caa.flags, NULL((void*)0)); | |||
1114 | if (r < 0) | |||
1115 | goto fail; | |||
1116 | ||||
1117 | r = dns_packet_append_string(p, rr->caa.tag, NULL((void*)0)); | |||
1118 | if (r < 0) | |||
1119 | goto fail; | |||
1120 | ||||
1121 | r = dns_packet_append_blob(p, rr->caa.value, rr->caa.value_size, NULL((void*)0)); | |||
1122 | break; | |||
1123 | ||||
1124 | case DNS_TYPE_OPT: | |||
1125 | case DNS_TYPE_OPENPGPKEY: | |||
1126 | case _DNS_TYPE_INVALID: /* unparseable */ | |||
1127 | default: | |||
1128 | ||||
1129 | r = dns_packet_append_blob(p, rr->generic.data, rr->generic.data_size, NULL((void*)0)); | |||
1130 | break; | |||
1131 | } | |||
1132 | if (r < 0) | |||
1133 | goto fail; | |||
1134 | ||||
1135 | /* Let's calculate the actual data size and update the field */ | |||
1136 | rdlength = p->size - rdlength_offset - sizeof(uint16_t); | |||
1137 | if (rdlength > 0xFFFF) { | |||
1138 | r = -ENOSPC28; | |||
1139 | goto fail; | |||
1140 | } | |||
1141 | ||||
1142 | end = p->size; | |||
1143 | p->size = rdlength_offset; | |||
1144 | r = dns_packet_append_uint16(p, rdlength, NULL((void*)0)); | |||
1145 | if (r < 0) | |||
1146 | goto fail; | |||
1147 | p->size = end; | |||
1148 | ||||
1149 | if (start) | |||
1150 | *start = saved_size; | |||
1151 | ||||
1152 | if (rdata_start) | |||
1153 | *rdata_start = rds; | |||
1154 | ||||
1155 | return 0; | |||
1156 | ||||
1157 | fail: | |||
1158 | dns_packet_truncate(p, saved_size); | |||
1159 | return r; | |||
1160 | } | |||
1161 | ||||
1162 | int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) { | |||
1163 | DnsResourceKey *key; | |||
1164 | int r; | |||
1165 | ||||
1166 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1166, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
1167 | ||||
1168 | DNS_QUESTION_FOREACH(key, q)for (size_t __unique_prefix_i17 = ({ (key) = ((q) && ( q)->n_keys > 0) ? (q)->keys[0] : ((void*)0); 0; }); ( q) && (__unique_prefix_i17 < (q)->n_keys); __unique_prefix_i17 ++, (key) = (__unique_prefix_i17 < (q)->n_keys ? (q)-> keys[__unique_prefix_i17] : ((void*)0))) { | |||
1169 | r = dns_packet_append_key(p, key, 0, NULL((void*)0)); | |||
1170 | if (r < 0) | |||
1171 | return r; | |||
1172 | } | |||
1173 | ||||
1174 | return 0; | |||
1175 | } | |||
1176 | ||||
1177 | int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) { | |||
1178 | DnsResourceRecord *rr; | |||
1179 | DnsAnswerFlags flags; | |||
1180 | int r; | |||
1181 | ||||
1182 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1182, __PRETTY_FUNCTION__); } while (0); | |||
1183 | ||||
1184 | DNS_ANSWER_FOREACH_FLAGS(rr, flags, a)for (size_t __unique_prefix_i18 = ({ (rr) = ((a) && ( a)->n_rrs > 0) ? (a)->items[0].rr : ((void*)0); (flags ) = ((a) && (a)->n_rrs > 0) ? (a)->items[0]. flags : 0; 0; }); (a) && (__unique_prefix_i18 < (a )->n_rrs); __unique_prefix_i18++, (rr) = ((__unique_prefix_i18 < (a)->n_rrs) ? (a)->items[__unique_prefix_i18].rr : ((void*)0)), (flags) = ((__unique_prefix_i18 < (a)->n_rrs ) ? (a)->items[__unique_prefix_i18].flags : 0)) { | |||
1185 | r = dns_packet_append_rr(p, rr, flags, NULL((void*)0), NULL((void*)0)); | |||
1186 | if (r < 0) | |||
1187 | return r; | |||
1188 | } | |||
1189 | ||||
1190 | return 0; | |||
1191 | } | |||
1192 | ||||
1193 | int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) { | |||
1194 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1194, __PRETTY_FUNCTION__); } while (0); | |||
1195 | ||||
1196 | if (p->rindex + sz > p->size) | |||
1197 | return -EMSGSIZE90; | |||
1198 | ||||
1199 | if (ret) | |||
1200 | *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex; | |||
1201 | ||||
1202 | if (start) | |||
1203 | *start = p->rindex; | |||
1204 | ||||
1205 | p->rindex += sz; | |||
1206 | return 0; | |||
1207 | } | |||
1208 | ||||
1209 | void dns_packet_rewind(DnsPacket *p, size_t idx) { | |||
1210 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1210, __PRETTY_FUNCTION__); } while (0); | |||
1211 | assert(idx <= p->size)do { if ((__builtin_expect(!!(!(idx <= p->size)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("idx <= p->size"), "../src/resolve/resolved-dns-packet.c" , 1211, __PRETTY_FUNCTION__); } while (0); | |||
1212 | assert(idx >= DNS_PACKET_HEADER_SIZE)do { if ((__builtin_expect(!!(!(idx >= sizeof(DnsPacketHeader ))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("idx >= DNS_PACKET_HEADER_SIZE" ), "../src/resolve/resolved-dns-packet.c", 1212, __PRETTY_FUNCTION__ ); } while (0); | |||
1213 | ||||
1214 | p->rindex = idx; | |||
1215 | } | |||
1216 | ||||
1217 | int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) { | |||
1218 | const void *q; | |||
1219 | int r; | |||
1220 | ||||
1221 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1221, __PRETTY_FUNCTION__); } while (0); | |||
1222 | assert(d)do { if ((__builtin_expect(!!(!(d)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("d"), "../src/resolve/resolved-dns-packet.c" , 1222, __PRETTY_FUNCTION__); } while (0); | |||
1223 | ||||
1224 | r = dns_packet_read(p, sz, &q, start); | |||
1225 | if (r < 0) | |||
1226 | return r; | |||
1227 | ||||
1228 | memcpy(d, q, sz); | |||
1229 | return 0; | |||
1230 | } | |||
1231 | ||||
1232 | static int dns_packet_read_memdup( | |||
1233 | DnsPacket *p, size_t size, | |||
1234 | void **ret, size_t *ret_size, | |||
1235 | size_t *ret_start) { | |||
1236 | ||||
1237 | const void *src; | |||
1238 | size_t start; | |||
1239 | int r; | |||
1240 | ||||
1241 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1241, __PRETTY_FUNCTION__); } while (0); | |||
1242 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-packet.c" , 1242, __PRETTY_FUNCTION__); } while (0); | |||
1243 | ||||
1244 | r = dns_packet_read(p, size, &src, &start); | |||
1245 | if (r < 0) | |||
1246 | return r; | |||
1247 | ||||
1248 | if (size <= 0) | |||
1249 | *ret = NULL((void*)0); | |||
1250 | else { | |||
1251 | void *copy; | |||
1252 | ||||
1253 | copy = memdup(src, size); | |||
1254 | if (!copy) | |||
1255 | return -ENOMEM12; | |||
1256 | ||||
1257 | *ret = copy; | |||
1258 | } | |||
1259 | ||||
1260 | if (ret_size) | |||
1261 | *ret_size = size; | |||
1262 | if (ret_start) | |||
1263 | *ret_start = start; | |||
1264 | ||||
1265 | return 0; | |||
1266 | } | |||
1267 | ||||
1268 | int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) { | |||
1269 | const void *d; | |||
1270 | int r; | |||
1271 | ||||
1272 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1272, __PRETTY_FUNCTION__); } while (0); | |||
1273 | ||||
1274 | r = dns_packet_read(p, sizeof(uint8_t), &d, start); | |||
1275 | if (r < 0) | |||
1276 | return r; | |||
1277 | ||||
1278 | *ret = ((uint8_t*) d)[0]; | |||
1279 | return 0; | |||
1280 | } | |||
1281 | ||||
1282 | int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) { | |||
1283 | const void *d; | |||
1284 | int r; | |||
1285 | ||||
1286 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1286, __PRETTY_FUNCTION__); } while (0); | |||
1287 | ||||
1288 | r = dns_packet_read(p, sizeof(uint16_t), &d, start); | |||
1289 | if (r < 0) | |||
1290 | return r; | |||
1291 | ||||
1292 | *ret = unaligned_read_be16(d); | |||
1293 | ||||
1294 | return 0; | |||
1295 | } | |||
1296 | ||||
1297 | int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) { | |||
1298 | const void *d; | |||
1299 | int r; | |||
1300 | ||||
1301 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1301, __PRETTY_FUNCTION__); } while (0); | |||
1302 | ||||
1303 | r = dns_packet_read(p, sizeof(uint32_t), &d, start); | |||
1304 | if (r < 0) | |||
1305 | return r; | |||
1306 | ||||
1307 | *ret = unaligned_read_be32(d); | |||
1308 | ||||
1309 | return 0; | |||
1310 | } | |||
1311 | ||||
1312 | int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) { | |||
1313 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1314 | const void *d; | |||
1315 | char *t; | |||
1316 | uint8_t c; | |||
1317 | int r; | |||
1318 | ||||
1319 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1319, __PRETTY_FUNCTION__); } while (0); | |||
1320 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1321 | ||||
1322 | r = dns_packet_read_uint8(p, &c, NULL((void*)0)); | |||
1323 | if (r < 0) | |||
1324 | return r; | |||
1325 | ||||
1326 | r = dns_packet_read(p, c, &d, NULL((void*)0)); | |||
1327 | if (r < 0) | |||
1328 | return r; | |||
1329 | ||||
1330 | if (memchr(d, 0, c)) | |||
1331 | return -EBADMSG74; | |||
1332 | ||||
1333 | t = strndup(d, c); | |||
1334 | if (!t) | |||
1335 | return -ENOMEM12; | |||
1336 | ||||
1337 | if (!utf8_is_valid(t)) { | |||
1338 | free(t); | |||
1339 | return -EBADMSG74; | |||
1340 | } | |||
1341 | ||||
1342 | *ret = t; | |||
1343 | ||||
1344 | if (start) | |||
1345 | *start = rewinder.saved_rindex; | |||
1346 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
1347 | ||||
1348 | return 0; | |||
1349 | } | |||
1350 | ||||
1351 | int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) { | |||
1352 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1353 | uint8_t c; | |||
1354 | int r; | |||
1355 | ||||
1356 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1356, __PRETTY_FUNCTION__); } while (0); | |||
1357 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1358 | ||||
1359 | r = dns_packet_read_uint8(p, &c, NULL((void*)0)); | |||
1360 | if (r < 0) | |||
1361 | return r; | |||
1362 | ||||
1363 | r = dns_packet_read(p, c, ret, NULL((void*)0)); | |||
1364 | if (r < 0) | |||
1365 | return r; | |||
1366 | ||||
1367 | if (size) | |||
1368 | *size = c; | |||
1369 | if (start) | |||
1370 | *start = rewinder.saved_rindex; | |||
1371 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
1372 | ||||
1373 | return 0; | |||
1374 | } | |||
1375 | ||||
1376 | int dns_packet_read_name( | |||
1377 | DnsPacket *p, | |||
1378 | char **_ret, | |||
1379 | bool_Bool allow_compression, | |||
1380 | size_t *start) { | |||
1381 | ||||
1382 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1383 | size_t after_rindex = 0, jump_barrier; | |||
1384 | _cleanup_free___attribute__((cleanup(freep))) char *ret = NULL((void*)0); | |||
1385 | size_t n = 0, allocated = 0; | |||
1386 | bool_Bool first = true1; | |||
1387 | int r; | |||
1388 | ||||
1389 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1389, __PRETTY_FUNCTION__); } while (0); | |||
1390 | assert(_ret)do { if ((__builtin_expect(!!(!(_ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_ret"), "../src/resolve/resolved-dns-packet.c" , 1390, __PRETTY_FUNCTION__); } while (0); | |||
1391 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1392 | jump_barrier = p->rindex; | |||
1393 | ||||
1394 | if (p->refuse_compression) | |||
1395 | allow_compression = false0; | |||
1396 | ||||
1397 | for (;;) { | |||
1398 | uint8_t c, d; | |||
1399 | ||||
1400 | r = dns_packet_read_uint8(p, &c, NULL((void*)0)); | |||
1401 | if (r < 0) | |||
1402 | return r; | |||
1403 | ||||
1404 | if (c == 0) | |||
1405 | /* End of name */ | |||
1406 | break; | |||
1407 | else if (c <= 63) { | |||
1408 | const char *label; | |||
1409 | ||||
1410 | /* Literal label */ | |||
1411 | r = dns_packet_read(p, c, (const void**) &label, NULL((void*)0)); | |||
1412 | if (r < 0) | |||
1413 | return r; | |||
1414 | ||||
1415 | if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)greedy_realloc((void**) &(ret), &(allocated), (n + !first + (63*4+1)), sizeof((ret)[0]))) | |||
1416 | return -ENOMEM12; | |||
1417 | ||||
1418 | if (first) | |||
1419 | first = false0; | |||
1420 | else | |||
1421 | ret[n++] = '.'; | |||
1422 | ||||
1423 | r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX(63*4+1)); | |||
1424 | if (r < 0) | |||
1425 | return r; | |||
1426 | ||||
1427 | n += r; | |||
1428 | continue; | |||
1429 | } else if (allow_compression && (c & 0xc0) == 0xc0) { | |||
1430 | uint16_t ptr; | |||
1431 | ||||
1432 | /* Pointer */ | |||
1433 | r = dns_packet_read_uint8(p, &d, NULL((void*)0)); | |||
1434 | if (r < 0) | |||
1435 | return r; | |||
1436 | ||||
1437 | ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; | |||
1438 | if (ptr < DNS_PACKET_HEADER_SIZEsizeof(DnsPacketHeader) || ptr >= jump_barrier) | |||
1439 | return -EBADMSG74; | |||
1440 | ||||
1441 | if (after_rindex == 0) | |||
1442 | after_rindex = p->rindex; | |||
1443 | ||||
1444 | /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */ | |||
1445 | jump_barrier = ptr; | |||
1446 | p->rindex = ptr; | |||
1447 | } else | |||
1448 | return -EBADMSG74; | |||
1449 | } | |||
1450 | ||||
1451 | if (!GREEDY_REALLOC(ret, allocated, n + 1)greedy_realloc((void**) &(ret), &(allocated), (n + 1) , sizeof((ret)[0]))) | |||
1452 | return -ENOMEM12; | |||
1453 | ||||
1454 | ret[n] = 0; | |||
1455 | ||||
1456 | if (after_rindex != 0) | |||
1457 | p->rindex= after_rindex; | |||
1458 | ||||
1459 | *_ret = TAKE_PTR(ret)({ typeof(ret) _ptr_ = (ret); (ret) = ((void*)0); _ptr_; }); | |||
1460 | ||||
1461 | if (start) | |||
1462 | *start = rewinder.saved_rindex; | |||
1463 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
1464 | ||||
1465 | return 0; | |||
1466 | } | |||
1467 | ||||
1468 | static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) { | |||
1469 | uint8_t window; | |||
1470 | uint8_t length; | |||
1471 | const uint8_t *bitmap; | |||
1472 | uint8_t bit = 0; | |||
1473 | unsigned i; | |||
1474 | bool_Bool found = false0; | |||
1475 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1476 | int r; | |||
1477 | ||||
1478 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1478, __PRETTY_FUNCTION__); } while (0); | |||
1479 | assert(types)do { if ((__builtin_expect(!!(!(types)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("types"), "../src/resolve/resolved-dns-packet.c" , 1479, __PRETTY_FUNCTION__); } while (0); | |||
1480 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1481 | ||||
1482 | r = bitmap_ensure_allocated(types); | |||
1483 | if (r < 0) | |||
1484 | return r; | |||
1485 | ||||
1486 | r = dns_packet_read_uint8(p, &window, NULL((void*)0)); | |||
1487 | if (r < 0) | |||
1488 | return r; | |||
1489 | ||||
1490 | r = dns_packet_read_uint8(p, &length, NULL((void*)0)); | |||
1491 | if (r < 0) | |||
1492 | return r; | |||
1493 | ||||
1494 | if (length == 0 || length > 32) | |||
1495 | return -EBADMSG74; | |||
1496 | ||||
1497 | r = dns_packet_read(p, length, (const void **)&bitmap, NULL((void*)0)); | |||
1498 | if (r < 0) | |||
1499 | return r; | |||
1500 | ||||
1501 | for (i = 0; i < length; i++) { | |||
1502 | uint8_t bitmask = 1 << 7; | |||
1503 | ||||
1504 | if (!bitmap[i]) { | |||
1505 | found = false0; | |||
1506 | bit += 8; | |||
1507 | continue; | |||
1508 | } | |||
1509 | ||||
1510 | found = true1; | |||
1511 | ||||
1512 | for (; bitmask; bit++, bitmask >>= 1) | |||
1513 | if (bitmap[i] & bitmask) { | |||
1514 | uint16_t n; | |||
1515 | ||||
1516 | n = (uint16_t) window << 8 | (uint16_t) bit; | |||
1517 | ||||
1518 | /* Ignore pseudo-types. see RFC4034 section 4.1.2 */ | |||
1519 | if (dns_type_is_pseudo(n)) | |||
1520 | continue; | |||
1521 | ||||
1522 | r = bitmap_set(*types, n); | |||
1523 | if (r < 0) | |||
1524 | return r; | |||
1525 | } | |||
1526 | } | |||
1527 | ||||
1528 | if (!found) | |||
1529 | return -EBADMSG74; | |||
1530 | ||||
1531 | if (start) | |||
1532 | *start = rewinder.saved_rindex; | |||
1533 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
1534 | ||||
1535 | return 0; | |||
1536 | } | |||
1537 | ||||
1538 | static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) { | |||
1539 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1540 | int r; | |||
1541 | ||||
1542 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1543 | ||||
1544 | while (p->rindex < rewinder.saved_rindex + size) { | |||
1545 | r = dns_packet_read_type_window(p, types, NULL((void*)0)); | |||
1546 | if (r < 0) | |||
1547 | return r; | |||
1548 | ||||
1549 | /* don't read past end of current RR */ | |||
1550 | if (p->rindex > rewinder.saved_rindex + size) | |||
1551 | return -EBADMSG74; | |||
1552 | } | |||
1553 | ||||
1554 | if (p->rindex != rewinder.saved_rindex + size) | |||
1555 | return -EBADMSG74; | |||
1556 | ||||
1557 | if (start) | |||
1558 | *start = rewinder.saved_rindex; | |||
1559 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
1560 | ||||
1561 | return 0; | |||
1562 | } | |||
1563 | ||||
1564 | int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool_Bool *ret_cache_flush, size_t *start) { | |||
1565 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1566 | _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0); | |||
1567 | bool_Bool cache_flush = false0; | |||
1568 | uint16_t class, type; | |||
1569 | DnsResourceKey *key; | |||
1570 | int r; | |||
1571 | ||||
1572 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1572, __PRETTY_FUNCTION__); } while (0); | |||
1573 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-packet.c" , 1573, __PRETTY_FUNCTION__); } while (0); | |||
1574 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1575 | ||||
1576 | r = dns_packet_read_name(p, &name, true1, NULL((void*)0)); | |||
1577 | if (r < 0) | |||
1578 | return r; | |||
1579 | ||||
1580 | r = dns_packet_read_uint16(p, &type, NULL((void*)0)); | |||
1581 | if (r < 0) | |||
1582 | return r; | |||
1583 | ||||
1584 | r = dns_packet_read_uint16(p, &class, NULL((void*)0)); | |||
1585 | if (r < 0) | |||
1586 | return r; | |||
1587 | ||||
1588 | if (p->protocol == DNS_PROTOCOL_MDNS) { | |||
1589 | /* See RFC6762, Section 10.2 */ | |||
1590 | ||||
1591 | if (type != DNS_TYPE_OPT && (class & MDNS_RR_CACHE_FLUSH(1 << 15))) { | |||
1592 | class &= ~MDNS_RR_CACHE_FLUSH(1 << 15); | |||
1593 | cache_flush = true1; | |||
1594 | } | |||
1595 | } | |||
1596 | ||||
1597 | key = dns_resource_key_new_consume(class, type, name); | |||
1598 | if (!key) | |||
1599 | return -ENOMEM12; | |||
1600 | ||||
1601 | name = NULL((void*)0); | |||
1602 | *ret = key; | |||
1603 | ||||
1604 | if (ret_cache_flush) | |||
1605 | *ret_cache_flush = cache_flush; | |||
1606 | if (start) | |||
1607 | *start = rewinder.saved_rindex; | |||
1608 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
1609 | ||||
1610 | return 0; | |||
1611 | } | |||
1612 | ||||
1613 | static bool_Bool loc_size_ok(uint8_t size) { | |||
1614 | uint8_t m = size >> 4, e = size & 0xF; | |||
1615 | ||||
1616 | return m <= 9 && e <= 9 && (m > 0 || e == 0); | |||
1617 | } | |||
1618 | ||||
1619 | int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool_Bool *ret_cache_flush, size_t *start) { | |||
1620 | _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *rr = NULL((void*)0); | |||
1621 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | |||
1622 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder; | |||
1623 | size_t offset; | |||
1624 | uint16_t rdlength; | |||
1625 | bool_Bool cache_flush; | |||
1626 | int r; | |||
1627 | ||||
1628 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 1628, __PRETTY_FUNCTION__); } while (0); | |||
1629 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-packet.c" , 1629, __PRETTY_FUNCTION__); } while (0); | |||
1630 | ||||
1631 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
1632 | ||||
1633 | r = dns_packet_read_key(p, &key, &cache_flush, NULL((void*)0)); | |||
1634 | if (r < 0) | |||
1635 | return r; | |||
1636 | ||||
1637 | if (!dns_class_is_valid_rr(key->class) || !dns_type_is_valid_rr(key->type)) | |||
1638 | return -EBADMSG74; | |||
1639 | ||||
1640 | rr = dns_resource_record_new(key); | |||
1641 | if (!rr) | |||
1642 | return -ENOMEM12; | |||
1643 | ||||
1644 | r = dns_packet_read_uint32(p, &rr->ttl, NULL((void*)0)); | |||
1645 | if (r < 0) | |||
1646 | return r; | |||
1647 | ||||
1648 | /* RFC 2181, Section 8, suggests to | |||
1649 | * treat a TTL with the MSB set as a zero TTL. */ | |||
1650 | if (rr->ttl & UINT32_C(0x80000000)0x80000000U) | |||
1651 | rr->ttl = 0; | |||
1652 | ||||
1653 | r = dns_packet_read_uint16(p, &rdlength, NULL((void*)0)); | |||
1654 | if (r < 0) | |||
1655 | return r; | |||
1656 | ||||
1657 | if (p->rindex + rdlength > p->size) | |||
1658 | return -EBADMSG74; | |||
1659 | ||||
1660 | offset = p->rindex; | |||
1661 | ||||
1662 | switch (rr->key->type) { | |||
1663 | ||||
1664 | case DNS_TYPE_SRV: | |||
1665 | r = dns_packet_read_uint16(p, &rr->srv.priority, NULL((void*)0)); | |||
1666 | if (r < 0) | |||
1667 | return r; | |||
1668 | r = dns_packet_read_uint16(p, &rr->srv.weight, NULL((void*)0)); | |||
1669 | if (r < 0) | |||
1670 | return r; | |||
1671 | r = dns_packet_read_uint16(p, &rr->srv.port, NULL((void*)0)); | |||
1672 | if (r < 0) | |||
1673 | return r; | |||
1674 | r = dns_packet_read_name(p, &rr->srv.name, true1, NULL((void*)0)); | |||
1675 | break; | |||
1676 | ||||
1677 | case DNS_TYPE_PTR: | |||
1678 | case DNS_TYPE_NS: | |||
1679 | case DNS_TYPE_CNAME: | |||
1680 | case DNS_TYPE_DNAME: | |||
1681 | r = dns_packet_read_name(p, &rr->ptr.name, true1, NULL((void*)0)); | |||
1682 | break; | |||
1683 | ||||
1684 | case DNS_TYPE_HINFO: | |||
1685 | r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL((void*)0)); | |||
1686 | if (r < 0) | |||
1687 | return r; | |||
1688 | ||||
1689 | r = dns_packet_read_string(p, &rr->hinfo.os, NULL((void*)0)); | |||
1690 | break; | |||
1691 | ||||
1692 | case DNS_TYPE_SPF: /* exactly the same as TXT */ | |||
1693 | case DNS_TYPE_TXT: | |||
1694 | if (rdlength <= 0) { | |||
1695 | r = dns_txt_item_new_empty(&rr->txt.items); | |||
1696 | if (r < 0) | |||
1697 | return r; | |||
1698 | } else { | |||
1699 | DnsTxtItem *last = NULL((void*)0); | |||
1700 | ||||
1701 | while (p->rindex < offset + rdlength) { | |||
1702 | DnsTxtItem *i; | |||
1703 | const void *data; | |||
1704 | size_t sz; | |||
1705 | ||||
1706 | r = dns_packet_read_raw_string(p, &data, &sz, NULL((void*)0)); | |||
1707 | if (r < 0) | |||
1708 | return r; | |||
1709 | ||||
1710 | i = malloc0(offsetof(DnsTxtItem, data) + sz + 1)(calloc(1, (__builtin_offsetof(DnsTxtItem, data) + sz + 1))); /* extra NUL byte at the end */ | |||
1711 | if (!i) | |||
1712 | return -ENOMEM12; | |||
1713 | ||||
1714 | memcpy(i->data, data, sz); | |||
1715 | i->length = sz; | |||
1716 | ||||
1717 | LIST_INSERT_AFTER(items, rr->txt.items, last, i)do { typeof(*(rr->txt.items)) **_head = &(rr->txt.items ), *_a = (last), *_b = (i); do { if ((__builtin_expect(!!(!(_b )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_b"), "../src/resolve/resolved-dns-packet.c" , 1717, __PRETTY_FUNCTION__); } while (0); if (!_a) { if ((_b ->items_next = *_head)) _b->items_next->items_prev = _b; _b->items_prev = ((void*)0); *_head = _b; } else { if ((_b->items_next = _a->items_next)) _b->items_next-> items_prev = _b; _b->items_prev = _a; _a->items_next = _b ; } } while (0); | |||
1718 | last = i; | |||
1719 | } | |||
1720 | } | |||
1721 | ||||
1722 | r = 0; | |||
1723 | break; | |||
1724 | ||||
1725 | case DNS_TYPE_A: | |||
1726 | r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL((void*)0)); | |||
1727 | break; | |||
1728 | ||||
1729 | case DNS_TYPE_AAAA: | |||
1730 | r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL((void*)0)); | |||
1731 | break; | |||
1732 | ||||
1733 | case DNS_TYPE_SOA: | |||
1734 | r = dns_packet_read_name(p, &rr->soa.mname, true1, NULL((void*)0)); | |||
1735 | if (r < 0) | |||
1736 | return r; | |||
1737 | ||||
1738 | r = dns_packet_read_name(p, &rr->soa.rname, true1, NULL((void*)0)); | |||
1739 | if (r < 0) | |||
1740 | return r; | |||
1741 | ||||
1742 | r = dns_packet_read_uint32(p, &rr->soa.serial, NULL((void*)0)); | |||
1743 | if (r < 0) | |||
1744 | return r; | |||
1745 | ||||
1746 | r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL((void*)0)); | |||
1747 | if (r < 0) | |||
1748 | return r; | |||
1749 | ||||
1750 | r = dns_packet_read_uint32(p, &rr->soa.retry, NULL((void*)0)); | |||
1751 | if (r < 0) | |||
1752 | return r; | |||
1753 | ||||
1754 | r = dns_packet_read_uint32(p, &rr->soa.expire, NULL((void*)0)); | |||
1755 | if (r < 0) | |||
1756 | return r; | |||
1757 | ||||
1758 | r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL((void*)0)); | |||
1759 | break; | |||
1760 | ||||
1761 | case DNS_TYPE_MX: | |||
1762 | r = dns_packet_read_uint16(p, &rr->mx.priority, NULL((void*)0)); | |||
1763 | if (r < 0) | |||
1764 | return r; | |||
1765 | ||||
1766 | r = dns_packet_read_name(p, &rr->mx.exchange, true1, NULL((void*)0)); | |||
1767 | break; | |||
1768 | ||||
1769 | case DNS_TYPE_LOC: { | |||
1770 | uint8_t t; | |||
1771 | size_t pos; | |||
1772 | ||||
1773 | r = dns_packet_read_uint8(p, &t, &pos); | |||
1774 | if (r < 0) | |||
1775 | return r; | |||
1776 | ||||
1777 | if (t == 0) { | |||
1778 | rr->loc.version = t; | |||
1779 | ||||
1780 | r = dns_packet_read_uint8(p, &rr->loc.size, NULL((void*)0)); | |||
1781 | if (r < 0) | |||
1782 | return r; | |||
1783 | ||||
1784 | if (!loc_size_ok(rr->loc.size)) | |||
1785 | return -EBADMSG74; | |||
1786 | ||||
1787 | r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL((void*)0)); | |||
1788 | if (r < 0) | |||
1789 | return r; | |||
1790 | ||||
1791 | if (!loc_size_ok(rr->loc.horiz_pre)) | |||
1792 | return -EBADMSG74; | |||
1793 | ||||
1794 | r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL((void*)0)); | |||
1795 | if (r < 0) | |||
1796 | return r; | |||
1797 | ||||
1798 | if (!loc_size_ok(rr->loc.vert_pre)) | |||
1799 | return -EBADMSG74; | |||
1800 | ||||
1801 | r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL((void*)0)); | |||
1802 | if (r < 0) | |||
1803 | return r; | |||
1804 | ||||
1805 | r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL((void*)0)); | |||
1806 | if (r < 0) | |||
1807 | return r; | |||
1808 | ||||
1809 | r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL((void*)0)); | |||
1810 | if (r < 0) | |||
1811 | return r; | |||
1812 | ||||
1813 | break; | |||
1814 | } else { | |||
1815 | dns_packet_rewind(p, pos); | |||
1816 | rr->unparseable = true1; | |||
1817 | goto unparseable; | |||
1818 | } | |||
1819 | } | |||
1820 | ||||
1821 | case DNS_TYPE_DS: | |||
1822 | r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL((void*)0)); | |||
1823 | if (r < 0) | |||
1824 | return r; | |||
1825 | ||||
1826 | r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL((void*)0)); | |||
1827 | if (r < 0) | |||
1828 | return r; | |||
1829 | ||||
1830 | r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL((void*)0)); | |||
1831 | if (r < 0) | |||
1832 | return r; | |||
1833 | ||||
1834 | if (rdlength < 4) | |||
1835 | return -EBADMSG74; | |||
1836 | ||||
1837 | r = dns_packet_read_memdup(p, rdlength - 4, | |||
1838 | &rr->ds.digest, &rr->ds.digest_size, | |||
1839 | NULL((void*)0)); | |||
1840 | if (r < 0) | |||
1841 | return r; | |||
1842 | ||||
1843 | if (rr->ds.digest_size <= 0) | |||
1844 | /* the accepted size depends on the algorithm, but for now | |||
1845 | just ensure that the value is greater than zero */ | |||
1846 | return -EBADMSG74; | |||
1847 | ||||
1848 | break; | |||
1849 | ||||
1850 | case DNS_TYPE_SSHFP: | |||
1851 | r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL((void*)0)); | |||
1852 | if (r < 0) | |||
1853 | return r; | |||
1854 | ||||
1855 | r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL((void*)0)); | |||
1856 | if (r < 0) | |||
1857 | return r; | |||
1858 | ||||
1859 | if (rdlength < 2) | |||
1860 | return -EBADMSG74; | |||
1861 | ||||
1862 | r = dns_packet_read_memdup(p, rdlength - 2, | |||
1863 | &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size, | |||
1864 | NULL((void*)0)); | |||
1865 | ||||
1866 | if (rr->sshfp.fingerprint_size <= 0) | |||
1867 | /* the accepted size depends on the algorithm, but for now | |||
1868 | just ensure that the value is greater than zero */ | |||
1869 | return -EBADMSG74; | |||
1870 | ||||
1871 | break; | |||
1872 | ||||
1873 | case DNS_TYPE_DNSKEY: | |||
1874 | r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL((void*)0)); | |||
1875 | if (r < 0) | |||
1876 | return r; | |||
1877 | ||||
1878 | r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL((void*)0)); | |||
1879 | if (r < 0) | |||
1880 | return r; | |||
1881 | ||||
1882 | r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL((void*)0)); | |||
1883 | if (r < 0) | |||
1884 | return r; | |||
1885 | ||||
1886 | if (rdlength < 4) | |||
1887 | return -EBADMSG74; | |||
1888 | ||||
1889 | r = dns_packet_read_memdup(p, rdlength - 4, | |||
1890 | &rr->dnskey.key, &rr->dnskey.key_size, | |||
1891 | NULL((void*)0)); | |||
1892 | ||||
1893 | if (rr->dnskey.key_size <= 0) | |||
1894 | /* the accepted size depends on the algorithm, but for now | |||
1895 | just ensure that the value is greater than zero */ | |||
1896 | return -EBADMSG74; | |||
1897 | ||||
1898 | break; | |||
1899 | ||||
1900 | case DNS_TYPE_RRSIG: | |||
1901 | r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL((void*)0)); | |||
1902 | if (r < 0) | |||
1903 | return r; | |||
1904 | ||||
1905 | r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL((void*)0)); | |||
1906 | if (r < 0) | |||
1907 | return r; | |||
1908 | ||||
1909 | r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL((void*)0)); | |||
1910 | if (r < 0) | |||
1911 | return r; | |||
1912 | ||||
1913 | r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL((void*)0)); | |||
1914 | if (r < 0) | |||
1915 | return r; | |||
1916 | ||||
1917 | r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL((void*)0)); | |||
1918 | if (r < 0) | |||
1919 | return r; | |||
1920 | ||||
1921 | r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL((void*)0)); | |||
1922 | if (r < 0) | |||
1923 | return r; | |||
1924 | ||||
1925 | r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL((void*)0)); | |||
1926 | if (r < 0) | |||
1927 | return r; | |||
1928 | ||||
1929 | r = dns_packet_read_name(p, &rr->rrsig.signer, false0, NULL((void*)0)); | |||
1930 | if (r < 0) | |||
1931 | return r; | |||
1932 | ||||
1933 | if (rdlength + offset < p->rindex) | |||
1934 | return -EBADMSG74; | |||
1935 | ||||
1936 | r = dns_packet_read_memdup(p, offset + rdlength - p->rindex, | |||
1937 | &rr->rrsig.signature, &rr->rrsig.signature_size, | |||
1938 | NULL((void*)0)); | |||
1939 | ||||
1940 | if (rr->rrsig.signature_size <= 0) | |||
1941 | /* the accepted size depends on the algorithm, but for now | |||
1942 | just ensure that the value is greater than zero */ | |||
1943 | return -EBADMSG74; | |||
1944 | ||||
1945 | break; | |||
1946 | ||||
1947 | case DNS_TYPE_NSEC: { | |||
1948 | ||||
1949 | /* | |||
1950 | * RFC6762, section 18.14 explictly states mDNS should use name compression. | |||
1951 | * This contradicts RFC3845, section 2.1.1 | |||
1952 | */ | |||
1953 | ||||
1954 | bool_Bool allow_compressed = p->protocol == DNS_PROTOCOL_MDNS; | |||
1955 | ||||
1956 | r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL((void*)0)); | |||
1957 | if (r < 0) | |||
1958 | return r; | |||
1959 | ||||
1960 | r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL((void*)0)); | |||
1961 | ||||
1962 | /* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself | |||
1963 | * is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records | |||
1964 | * without the NSEC bit set. */ | |||
1965 | ||||
1966 | break; | |||
1967 | } | |||
1968 | case DNS_TYPE_NSEC3: { | |||
1969 | uint8_t size; | |||
1970 | ||||
1971 | r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL((void*)0)); | |||
1972 | if (r < 0) | |||
1973 | return r; | |||
1974 | ||||
1975 | r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL((void*)0)); | |||
1976 | if (r < 0) | |||
1977 | return r; | |||
1978 | ||||
1979 | r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL((void*)0)); | |||
1980 | if (r < 0) | |||
1981 | return r; | |||
1982 | ||||
1983 | /* this may be zero */ | |||
1984 | r = dns_packet_read_uint8(p, &size, NULL((void*)0)); | |||
1985 | if (r < 0) | |||
1986 | return r; | |||
1987 | ||||
1988 | r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL((void*)0)); | |||
1989 | if (r < 0) | |||
1990 | return r; | |||
1991 | ||||
1992 | r = dns_packet_read_uint8(p, &size, NULL((void*)0)); | |||
1993 | if (r < 0) | |||
1994 | return r; | |||
1995 | ||||
1996 | if (size <= 0) | |||
1997 | return -EBADMSG74; | |||
1998 | ||||
1999 | r = dns_packet_read_memdup(p, size, | |||
2000 | &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, | |||
2001 | NULL((void*)0)); | |||
2002 | if (r < 0) | |||
2003 | return r; | |||
2004 | ||||
2005 | r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL((void*)0)); | |||
2006 | ||||
2007 | /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */ | |||
2008 | ||||
2009 | break; | |||
2010 | } | |||
2011 | ||||
2012 | case DNS_TYPE_TLSA: | |||
2013 | r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL((void*)0)); | |||
2014 | if (r < 0) | |||
2015 | return r; | |||
2016 | ||||
2017 | r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL((void*)0)); | |||
2018 | if (r < 0) | |||
2019 | return r; | |||
2020 | ||||
2021 | r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL((void*)0)); | |||
2022 | if (r < 0) | |||
2023 | return r; | |||
2024 | ||||
2025 | if (rdlength < 3) | |||
2026 | return -EBADMSG74; | |||
2027 | ||||
2028 | r = dns_packet_read_memdup(p, rdlength - 3, | |||
2029 | &rr->tlsa.data, &rr->tlsa.data_size, | |||
2030 | NULL((void*)0)); | |||
2031 | ||||
2032 | if (rr->tlsa.data_size <= 0) | |||
2033 | /* the accepted size depends on the algorithm, but for now | |||
2034 | just ensure that the value is greater than zero */ | |||
2035 | return -EBADMSG74; | |||
2036 | ||||
2037 | break; | |||
2038 | ||||
2039 | case DNS_TYPE_CAA: | |||
2040 | r = dns_packet_read_uint8(p, &rr->caa.flags, NULL((void*)0)); | |||
2041 | if (r < 0) | |||
2042 | return r; | |||
2043 | ||||
2044 | r = dns_packet_read_string(p, &rr->caa.tag, NULL((void*)0)); | |||
2045 | if (r < 0) | |||
2046 | return r; | |||
2047 | ||||
2048 | if (rdlength + offset < p->rindex) | |||
2049 | return -EBADMSG74; | |||
2050 | ||||
2051 | r = dns_packet_read_memdup(p, | |||
2052 | rdlength + offset - p->rindex, | |||
2053 | &rr->caa.value, &rr->caa.value_size, NULL((void*)0)); | |||
2054 | ||||
2055 | break; | |||
2056 | ||||
2057 | case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */ | |||
2058 | case DNS_TYPE_OPENPGPKEY: | |||
2059 | default: | |||
2060 | unparseable: | |||
2061 | r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL((void*)0)); | |||
2062 | ||||
2063 | break; | |||
2064 | } | |||
2065 | if (r < 0) | |||
2066 | return r; | |||
2067 | if (p->rindex != offset + rdlength) | |||
2068 | return -EBADMSG74; | |||
2069 | ||||
2070 | *ret = TAKE_PTR(rr)({ typeof(rr) _ptr_ = (rr); (rr) = ((void*)0); _ptr_; }); | |||
2071 | ||||
2072 | if (ret_cache_flush) | |||
2073 | *ret_cache_flush = cache_flush; | |||
2074 | if (start) | |||
2075 | *start = rewinder.saved_rindex; | |||
2076 | CANCEL_REWINDER(rewinder)do { rewinder.packet = ((void*)0); } while (0); | |||
2077 | ||||
2078 | return 0; | |||
2079 | } | |||
2080 | ||||
2081 | static bool_Bool opt_is_good(DnsResourceRecord *rr, bool_Bool *rfc6975) { | |||
2082 | const uint8_t* p; | |||
2083 | bool_Bool found_dau_dhu_n3u = false0; | |||
2084 | size_t l; | |||
2085 | ||||
2086 | /* Checks whether the specified OPT RR is well-formed and whether it contains RFC6975 data (which is not OK in | |||
2087 | * a reply). */ | |||
2088 | ||||
2089 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-packet.c" , 2089, __PRETTY_FUNCTION__); } while (0); | |||
2090 | assert(rr->key->type == DNS_TYPE_OPT)do { if ((__builtin_expect(!!(!(rr->key->type == DNS_TYPE_OPT )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("rr->key->type == DNS_TYPE_OPT" ), "../src/resolve/resolved-dns-packet.c", 2090, __PRETTY_FUNCTION__ ); } while (0); | |||
2091 | ||||
2092 | /* Check that the version is 0 */ | |||
2093 | if (((rr->ttl >> 16) & UINT32_C(0xFF)0xFFU) != 0) { | |||
2094 | *rfc6975 = false0; | |||
2095 | return true1; /* if it's not version 0, it's OK, but we will ignore the OPT field contents */ | |||
2096 | } | |||
2097 | ||||
2098 | p = rr->opt.data; | |||
2099 | l = rr->opt.data_size; | |||
2100 | while (l > 0) { | |||
2101 | uint16_t option_code, option_length; | |||
2102 | ||||
2103 | /* At least four bytes for OPTION-CODE and OPTION-LENGTH are required */ | |||
2104 | if (l < 4U) | |||
2105 | return false0; | |||
2106 | ||||
2107 | option_code = unaligned_read_be16(p); | |||
2108 | option_length = unaligned_read_be16(p + 2); | |||
2109 | ||||
2110 | if (l < option_length + 4U) | |||
2111 | return false0; | |||
2112 | ||||
2113 | /* RFC 6975 DAU, DHU or N3U fields found. */ | |||
2114 | if (IN_SET(option_code, 5, 6, 7)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){5, 6, 7})/sizeof(int)]; switch(option_code ) { case 5: case 6: case 7: _found = 1; break; default: break ; } _found; })) | |||
2115 | found_dau_dhu_n3u = true1; | |||
2116 | ||||
2117 | p += option_length + 4U; | |||
2118 | l -= option_length + 4U; | |||
2119 | } | |||
2120 | ||||
2121 | *rfc6975 = found_dau_dhu_n3u; | |||
2122 | return true1; | |||
2123 | } | |||
2124 | ||||
2125 | static int dns_packet_extract_question(DnsPacket *p, DnsQuestion **ret_question) { | |||
2126 | _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *question = NULL((void*)0); | |||
2127 | unsigned n, i; | |||
2128 | int r; | |||
2129 | ||||
2130 | n = DNS_PACKET_QDCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->qdcount); | |||
2131 | if (n > 0) { | |||
2132 | question = dns_question_new(n); | |||
2133 | if (!question) | |||
2134 | return -ENOMEM12; | |||
2135 | ||||
2136 | for (i = 0; i < n; i++) { | |||
2137 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | |||
2138 | bool_Bool cache_flush; | |||
2139 | ||||
2140 | r = dns_packet_read_key(p, &key, &cache_flush, NULL((void*)0)); | |||
2141 | if (r < 0) | |||
2142 | return r; | |||
2143 | ||||
2144 | if (cache_flush) | |||
2145 | return -EBADMSG74; | |||
2146 | ||||
2147 | if (!dns_type_is_valid_query(key->type)) | |||
2148 | return -EBADMSG74; | |||
2149 | ||||
2150 | r = dns_question_add(question, key); | |||
2151 | if (r < 0) | |||
2152 | return r; | |||
2153 | } | |||
2154 | } | |||
2155 | ||||
2156 | *ret_question = TAKE_PTR(question)({ typeof(question) _ptr_ = (question); (question) = ((void*) 0); _ptr_; }); | |||
2157 | ||||
2158 | return 0; | |||
2159 | } | |||
2160 | ||||
2161 | static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) { | |||
2162 | _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *answer = NULL((void*)0); | |||
2163 | unsigned n, i; | |||
2164 | _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *previous = NULL((void*)0); | |||
2165 | bool_Bool bad_opt = false0; | |||
2166 | int r; | |||
2167 | ||||
2168 | n = DNS_PACKET_RRCOUNT(p); | |||
2169 | if (n == 0) | |||
2170 | return 0; | |||
2171 | ||||
2172 | answer = dns_answer_new(n); | |||
2173 | if (!answer) | |||
2174 | return -ENOMEM12; | |||
2175 | ||||
2176 | for (i = 0; i < n; i++) { | |||
2177 | _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *rr = NULL((void*)0); | |||
2178 | bool_Bool cache_flush = false0; | |||
2179 | ||||
2180 | r = dns_packet_read_rr(p, &rr, &cache_flush, NULL((void*)0)); | |||
2181 | if (r < 0) | |||
2182 | return r; | |||
2183 | ||||
2184 | /* Try to reduce memory usage a bit */ | |||
2185 | if (previous) | |||
2186 | dns_resource_key_reduce(&rr->key, &previous->key); | |||
2187 | ||||
2188 | if (rr->key->type == DNS_TYPE_OPT) { | |||
2189 | bool_Bool has_rfc6975; | |||
2190 | ||||
2191 | if (p->opt || bad_opt) { | |||
2192 | /* Multiple OPT RRs? if so, let's ignore all, because there's | |||
2193 | * something wrong with the server, and if one is valid we wouldn't | |||
2194 | * know which one. */ | |||
2195 | log_debug("Multiple OPT RRs detected, ignoring all.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 2195, __func__, "Multiple OPT RRs detected, ignoring all." ) : -abs(_e); }); | |||
2196 | bad_opt = true1; | |||
2197 | continue; | |||
2198 | } | |||
2199 | ||||
2200 | if (!dns_name_is_root(dns_resource_key_name(rr->key))) { | |||
2201 | /* If the OPT RR is not owned by the root domain, then it is bad, | |||
2202 | * let's ignore it. */ | |||
2203 | log_debug("OPT RR is not owned by root domain, ignoring.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 2203, __func__, "OPT RR is not owned by root domain, ignoring." ) : -abs(_e); }); | |||
2204 | bad_opt = true1; | |||
2205 | continue; | |||
2206 | } | |||
2207 | ||||
2208 | if (i < DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount) + DNS_PACKET_NSCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->nscount)) { | |||
2209 | /* OPT RR is in the wrong section? Some Belkin routers do this. This | |||
2210 | * is a hint the EDNS implementation is borked, like the Belkin one | |||
2211 | * is, hence ignore it. */ | |||
2212 | log_debug("OPT RR in wrong section, ignoring.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 2212, __func__, "OPT RR in wrong section, ignoring." ) : -abs(_e); }); | |||
2213 | bad_opt = true1; | |||
2214 | continue; | |||
2215 | } | |||
2216 | ||||
2217 | if (!opt_is_good(rr, &has_rfc6975)) { | |||
2218 | log_debug("Malformed OPT RR, ignoring.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 2218, __func__, "Malformed OPT RR, ignoring." ) : -abs(_e); }); | |||
2219 | bad_opt = true1; | |||
2220 | continue; | |||
2221 | } | |||
2222 | ||||
2223 | if (DNS_PACKET_QR(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 15) & 1)) { | |||
2224 | /* Additional checks for responses */ | |||
2225 | ||||
2226 | if (!DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(rr)) { | |||
2227 | /* If this is a reply and we don't know the EDNS version | |||
2228 | * then something is weird... */ | |||
2229 | log_debug("EDNS version newer that our request, bad server.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 2229, __func__, "EDNS version newer that our request, bad server." ) : -abs(_e); }); | |||
2230 | return -EBADMSG74; | |||
2231 | } | |||
2232 | ||||
2233 | if (has_rfc6975) { | |||
2234 | /* If the OPT RR contains RFC6975 algorithm data, then this | |||
2235 | * is indication that the server just copied the OPT it got | |||
2236 | * from us (which contained that data) back into the reply. | |||
2237 | * If so, then it doesn't properly support EDNS, as RFC6975 | |||
2238 | * makes it very clear that the algorithm data should only | |||
2239 | * be contained in questions, never in replies. Crappy | |||
2240 | * Belkin routers copy the OPT data for example, hence let's | |||
2241 | * detect this so that we downgrade early. */ | |||
2242 | log_debug("OPT RR contained RFC6975 data, ignoring.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-dns-packet.c", 2242, __func__, "OPT RR contained RFC6975 data, ignoring." ) : -abs(_e); }); | |||
2243 | bad_opt = true1; | |||
2244 | continue; | |||
2245 | } | |||
2246 | } | |||
2247 | ||||
2248 | p->opt = dns_resource_record_ref(rr); | |||
2249 | } else { | |||
2250 | /* According to RFC 4795, section 2.9. only the RRs from the Answer section | |||
2251 | * shall be cached. Hence mark only those RRs as cacheable by default, but | |||
2252 | * not the ones from the Additional or Authority sections. */ | |||
2253 | DnsAnswerFlags flags = | |||
2254 | (i < DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount) ? DNS_ANSWER_CACHEABLE : 0) | | |||
2255 | (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0); | |||
2256 | ||||
2257 | r = dns_answer_add(answer, rr, p->ifindex, flags); | |||
2258 | if (r < 0) | |||
2259 | return r; | |||
2260 | } | |||
2261 | ||||
2262 | /* Remember this RR, so that we potentically can merge it's ->key object with the | |||
2263 | * next RR. Note that we only do this if we actually decided to keep the RR around. | |||
2264 | */ | |||
2265 | dns_resource_record_unref(previous); | |||
2266 | previous = dns_resource_record_ref(rr); | |||
2267 | } | |||
2268 | ||||
2269 | if (bad_opt) | |||
2270 | p->opt = dns_resource_record_unref(p->opt); | |||
2271 | ||||
2272 | *ret_answer = TAKE_PTR(answer)({ typeof(answer) _ptr_ = (answer); (answer) = ((void*)0); _ptr_ ; }); | |||
2273 | ||||
2274 | return 0; | |||
2275 | } | |||
2276 | ||||
2277 | int dns_packet_extract(DnsPacket *p) { | |||
2278 | _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *question = NULL((void*)0); | |||
2279 | _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *answer = NULL((void*)0); | |||
2280 | _cleanup_(rewind_dns_packet)__attribute__((cleanup(rewind_dns_packet))) DnsPacketRewinder rewinder = {}; | |||
2281 | int r; | |||
2282 | ||||
2283 | if (p->extracted) | |||
2284 | return 0; | |||
2285 | ||||
2286 | INIT_REWINDER(rewinder, p)do { rewinder.packet = p; rewinder.saved_rindex = p->rindex ; } while (0); | |||
2287 | dns_packet_rewind(p, DNS_PACKET_HEADER_SIZEsizeof(DnsPacketHeader)); | |||
2288 | ||||
2289 | r = dns_packet_extract_question(p, &question); | |||
2290 | if (r < 0) | |||
2291 | return r; | |||
2292 | ||||
2293 | r = dns_packet_extract_answer(p, &answer); | |||
2294 | if (r < 0) | |||
2295 | return r; | |||
2296 | ||||
2297 | p->question = TAKE_PTR(question)({ typeof(question) _ptr_ = (question); (question) = ((void*) 0); _ptr_; }); | |||
2298 | p->answer = TAKE_PTR(answer)({ typeof(answer) _ptr_ = (answer); (answer) = ((void*)0); _ptr_ ; }); | |||
2299 | ||||
2300 | p->extracted = true1; | |||
2301 | ||||
2302 | /* no CANCEL, always rewind */ | |||
2303 | return 0; | |||
2304 | } | |||
2305 | ||||
2306 | int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) { | |||
2307 | int r; | |||
2308 | ||||
2309 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-packet.c" , 2309, __PRETTY_FUNCTION__); } while (0); | |||
2310 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-packet.c" , 2310, __PRETTY_FUNCTION__); } while (0); | |||
2311 | ||||
2312 | /* Checks if the specified packet is a reply for the specified | |||
2313 | * key and the specified key is the only one in the question | |||
2314 | * section. */ | |||
2315 | ||||
2316 | if (DNS_PACKET_QR(p)((be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->flags) >> 15) & 1) != 1) | |||
2317 | return 0; | |||
2318 | ||||
2319 | /* Let's unpack the packet, if that hasn't happened yet. */ | |||
2320 | r = dns_packet_extract(p); | |||
2321 | if (r < 0) | |||
2322 | return r; | |||
2323 | ||||
2324 | if (!p->question) | |||
2325 | return 0; | |||
2326 | ||||
2327 | if (p->question->n_keys != 1) | |||
2328 | return 0; | |||
2329 | ||||
2330 | return dns_resource_key_equal(p->question->keys[0], key); | |||
2331 | } | |||
2332 | ||||
2333 | static void dns_packet_hash_func(const void *p, struct siphash *state) { | |||
2334 | const DnsPacket *s = p; | |||
2335 | ||||
2336 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-packet.c" , 2336, __PRETTY_FUNCTION__); } while (0); | |||
2337 | ||||
2338 | siphash24_compress(&s->size, sizeof(s->size), state); | |||
2339 | siphash24_compress(DNS_PACKET_DATA((DnsPacket*) s), s->size, state); | |||
2340 | } | |||
2341 | ||||
2342 | static int dns_packet_compare_func(const void *a, const void *b) { | |||
2343 | const DnsPacket *x = a, *y = b; | |||
2344 | ||||
2345 | if (x->size < y->size) | |||
2346 | return -1; | |||
2347 | if (x->size > y->size) | |||
2348 | return 1; | |||
2349 | ||||
2350 | return memcmp(DNS_PACKET_DATA((DnsPacket*) x), DNS_PACKET_DATA((DnsPacket*) y), x->size); | |||
2351 | } | |||
2352 | ||||
2353 | const struct hash_ops dns_packet_hash_ops = { | |||
2354 | .hash = dns_packet_hash_func, | |||
2355 | .compare = dns_packet_compare_func | |||
2356 | }; | |||
2357 | ||||
2358 | static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = { | |||
2359 | [DNS_RCODE_SUCCESS] = "SUCCESS", | |||
2360 | [DNS_RCODE_FORMERR] = "FORMERR", | |||
2361 | [DNS_RCODE_SERVFAIL] = "SERVFAIL", | |||
2362 | [DNS_RCODE_NXDOMAIN] = "NXDOMAIN", | |||
2363 | [DNS_RCODE_NOTIMP] = "NOTIMP", | |||
2364 | [DNS_RCODE_REFUSED] = "REFUSED", | |||
2365 | [DNS_RCODE_YXDOMAIN] = "YXDOMAIN", | |||
2366 | [DNS_RCODE_YXRRSET] = "YRRSET", | |||
2367 | [DNS_RCODE_NXRRSET] = "NXRRSET", | |||
2368 | [DNS_RCODE_NOTAUTH] = "NOTAUTH", | |||
2369 | [DNS_RCODE_NOTZONE] = "NOTZONE", | |||
2370 | [DNS_RCODE_BADVERS] = "BADVERS", | |||
2371 | [DNS_RCODE_BADKEY] = "BADKEY", | |||
2372 | [DNS_RCODE_BADTIME] = "BADTIME", | |||
2373 | [DNS_RCODE_BADMODE] = "BADMODE", | |||
2374 | [DNS_RCODE_BADNAME] = "BADNAME", | |||
2375 | [DNS_RCODE_BADALG] = "BADALG", | |||
2376 | [DNS_RCODE_BADTRUNC] = "BADTRUNC", | |||
2377 | [DNS_RCODE_BADCOOKIE] = "BADCOOKIE", | |||
2378 | }; | |||
2379 | DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int)const char *dns_rcode_to_string(int i) { if (i < 0 || i >= (int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(dns_rcode_table), typeof(&*(dns_rcode_table))), sizeof (dns_rcode_table)/sizeof((dns_rcode_table)[0]), ((void)0)))) return ((void*)0); return dns_rcode_table[i]; } int dns_rcode_from_string (const char *s) { return (int) string_table_lookup(dns_rcode_table , __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(dns_rcode_table), typeof(&*(dns_rcode_table))), sizeof (dns_rcode_table)/sizeof((dns_rcode_table)[0]), ((void)0))), s ); }; | |||
2380 | ||||
2381 | static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = { | |||
2382 | [DNS_PROTOCOL_DNS] = "dns", | |||
2383 | [DNS_PROTOCOL_MDNS] = "mdns", | |||
2384 | [DNS_PROTOCOL_LLMNR] = "llmnr", | |||
2385 | }; | |||
2386 | DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol)const char *dns_protocol_to_string(DnsProtocol i) { if (i < 0 || i >= (DnsProtocol) __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(dns_protocol_table), typeof (&*(dns_protocol_table))), sizeof(dns_protocol_table)/sizeof ((dns_protocol_table)[0]), ((void)0)))) return ((void*)0); return dns_protocol_table[i]; } DnsProtocol dns_protocol_from_string (const char *s) { return (DnsProtocol) string_table_lookup(dns_protocol_table , __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(dns_protocol_table), typeof(&*(dns_protocol_table ))), sizeof(dns_protocol_table)/sizeof((dns_protocol_table)[0 ]), ((void)0))), s); }; |