2 * Copyright (c) 2020 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * https://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "mdns_message.h"
19 #include "mdns_objects.h"
21 #include "DNSMessage.h"
22 #include <CoreUtils/CoreUtils.h>
24 //======================================================================================================================
25 // MARK: - Message Kind Definition
27 struct mdns_message_s
{
28 struct mdns_object_s base
; // Object base.
29 dispatch_data_t msg_data
; // Underlying object for message data.
30 const uint8_t * msg_ptr
; // Pointer to first byte of message data.
31 size_t msg_len
; // Length of message.
32 bool print_body_only
; // True if only the message body should be printed in description.
35 MDNS_OBJECT_SUBKIND_DEFINE(message
);
37 typedef const struct mdns_message_kind_s
* mdns_message_kind_t
;
38 struct mdns_message_kind_s
{
39 struct mdns_kind_s base
;
43 #define MDNS_MESSAGE_SUBKIND_DEFINE(NAME) \
45 _mdns_ ## NAME ## _message_finalize(mdns_ ## NAME ## _message_t message); \
47 static const struct mdns_message_kind_s _mdns_ ## NAME ## _message_kind = { \
49 .superkind = &_mdns_message_kind, \
50 .name = "mdns_" # NAME "_message", \
51 .finalize = _mdns_ ## NAME ## _message_finalize \
53 .name = # NAME "_message" \
56 static mdns_ ## NAME ## _message_t \
57 _mdns_ ## NAME ## _message_alloc(void) \
59 mdns_ ## NAME ## _message_t obj; \
60 obj = mdns_ ## NAME ## _message_object_alloc(sizeof(struct mdns_ ## NAME ## _message_s)); \
61 require_return_value(obj, NULL); \
63 const mdns_object_t object = (mdns_object_t)obj; \
64 object->kind = &_mdns_ ## NAME ## _message_kind.base; \
67 MDNS_BASE_CHECK(NAME ## _message, message)
69 //======================================================================================================================
70 // MARK: - Query Message Kind Definition
72 struct mdns_query_message_s
{
73 struct mdns_message_s base
; // Message object base.
74 uint8_t * qname
; // Question's QNAME.
75 uint16_t qtype
; // Question's QTYPE.
76 uint16_t qclass
; // Question's QCLASS.
77 uint16_t msg_id
; // Message ID.
78 bool set_ad_bit
; // True if the AD (authentic data) bit is to be set.
79 bool set_cd_bit
; // True if the CD (checking disabled) bit is to be set.
80 bool set_do_bit
; // True if the DO (DNSSEC OK) bit is to be set in OPT record.
81 bool use_edns0_padding
; // True if the query uses EDNS0 padding.
82 bool constructed
; // True if the message has been constructed.
85 MDNS_MESSAGE_SUBKIND_DEFINE(query
);
87 //======================================================================================================================
88 // MARK: - Local Prototypes
91 _mdns_message_init(mdns_any_message_t message
, dispatch_data_t msg_data
, mdns_message_init_options_t options
);
94 _mdns_message_set_msg_data(mdns_any_message_t message
, dispatch_data_t msg_data
);
97 _mdns_query_message_get_qname_safe(mdns_query_message_t query_message
);
99 //======================================================================================================================
100 // MARK: - Messge Public Methods
103 mdns_message_create_with_dispatch_data(const dispatch_data_t data
, const mdns_message_init_options_t options
)
105 mdns_message_t message
= NULL
;
106 mdns_message_t obj
= _mdns_message_alloc();
107 require_quiet(obj
, exit
);
109 const OSStatus err
= _mdns_message_init(obj
, data
, options
);
110 require_noerr_quiet(err
, exit
);
116 mdns_release_null_safe(obj
);
120 //======================================================================================================================
123 mdns_message_get_dispatch_data(const mdns_message_t me
)
128 //======================================================================================================================
131 mdns_message_get_byte_ptr(const mdns_message_t me
)
136 //======================================================================================================================
139 mdns_message_get_length(const mdns_message_t me
)
144 //======================================================================================================================
145 // MARK: - Message Private Methods
148 _mdns_message_copy_description(mdns_message_t me
, __unused
const bool debug
, const bool privacy
)
150 char *description
= NULL
;
152 DNSMessageToStringFlags flags
= kDNSMessageToStringFlag_OneLine
;
153 if (me
->print_body_only
) {
154 flags
|= kDNSMessageToStringFlag_BodyOnly
;
157 flags
|= kDNSMessageToStringFlag_Privacy
;
159 DNSMessageToString(me
->msg_ptr
, me
->msg_len
, flags
, &description
);
164 //======================================================================================================================
167 _mdns_message_finalize(const mdns_message_t me
)
170 dispatch_forget(&me
->msg_data
);
173 //======================================================================================================================
176 _mdns_message_init(const mdns_any_message_t any
, const dispatch_data_t msg_data
,
177 const mdns_message_init_options_t options
)
179 const mdns_message_t me
= any
.message
;
180 if (options
& mdns_message_init_option_disable_header_printing
) {
181 me
->print_body_only
= true;
183 return _mdns_message_set_msg_data(me
, msg_data
);
186 //======================================================================================================================
189 _mdns_message_set_msg_data(const mdns_any_message_t any
, const dispatch_data_t msg_data
)
191 dispatch_data_t msg_data_new
;
192 const uint8_t * msg_ptr
;
195 msg_data_new
= dispatch_data_create_map(msg_data
, (const void **)&msg_ptr
, &msg_len
);
196 require_return_value(msg_data_new
, kNoMemoryErr
);
198 msg_data_new
= dispatch_data_empty
;
202 const mdns_message_t me
= any
.message
;
203 dispatch_release_null_safe(me
->msg_data
);
204 me
->msg_data
= msg_data_new
;
205 me
->msg_ptr
= msg_ptr
;
206 me
->msg_len
= msg_len
;
210 //======================================================================================================================
211 // MARK: - Query Messge Public Methods
214 mdns_query_message_create(const mdns_message_init_options_t options
)
216 mdns_query_message_t message
= NULL
;
217 mdns_query_message_t obj
= _mdns_query_message_alloc();
218 require_quiet(obj
, exit
);
220 const OSStatus err
= _mdns_message_init(obj
, NULL
, options
);
221 require_noerr_quiet(err
, exit
);
227 mdns_release_null_safe(obj
);
231 //======================================================================================================================
234 mdns_query_message_set_qname(const mdns_query_message_t me
, const uint8_t * const qname
)
236 require_return_value(!me
->constructed
, kNoErr
);
238 uint8_t *qname_dup
= NULL
;
239 OSStatus err
= DomainNameDup(qname
, &qname_dup
, NULL
);
240 require_noerr_quiet(err
, exit
);
242 FreeNullSafe(me
->qname
);
243 me
->qname
= qname_dup
;
251 //======================================================================================================================
254 mdns_query_message_set_qtype(const mdns_query_message_t me
, const uint16_t qtype
)
256 require_return(!me
->constructed
);
260 //======================================================================================================================
263 mdns_query_message_set_qclass(const mdns_query_message_t me
, const uint16_t qclass
)
265 require_return(!me
->constructed
);
269 //======================================================================================================================
272 mdns_query_message_set_message_id(const mdns_query_message_t me
, const uint16_t msg_id
)
274 require_return(!me
->constructed
);
278 //======================================================================================================================
281 mdns_query_message_set_ad_bit(const mdns_query_message_t me
, const bool set
)
283 require_return(!me
->constructed
);
284 me
->set_ad_bit
= set
;
287 //======================================================================================================================
290 mdns_query_message_set_cd_bit(const mdns_query_message_t me
, const bool set
)
292 require_return(!me
->constructed
);
293 me
->set_cd_bit
= set
;
296 //======================================================================================================================
299 mdns_query_message_set_do_bit(const mdns_query_message_t me
, const bool set
)
301 require_return(!me
->constructed
);
302 me
->set_do_bit
= set
;
305 //======================================================================================================================
308 mdns_query_message_use_edns0_padding(const mdns_query_message_t me
, const bool use
)
310 require_return(!me
->constructed
);
311 me
->use_edns0_padding
= use
;
314 //======================================================================================================================
316 #define MDNS_EDNS0_PADDING_OVERHEAD 15 // Size of OPT pseudo-RR with OPTION-CODE and OPTION-LENGTH
317 #define MDNS_EDNS0_PADDING_BLOCK_SIZE 128 // <https://tools.ietf.org/html/rfc8467#section-4.1>
319 #define MDNS_QUERY_MESSAGE_BUFFER_SIZE \
320 RoundUp(kDNSQueryMessageMaxLen + MDNS_EDNS0_PADDING_OVERHEAD, MDNS_EDNS0_PADDING_BLOCK_SIZE)
323 _mdns_query_message_add_edns0_padding(uint8_t query_buf
[static MDNS_QUERY_MESSAGE_BUFFER_SIZE
], size_t query_len
,
324 bool set_do_bit
, size_t *out_len
);
327 _mdns_query_message_add_edns0_dnssec_ok(uint8_t query_buf
[static MDNS_QUERY_MESSAGE_BUFFER_SIZE
], size_t query_len
,
331 mdns_query_message_construct(const mdns_query_message_t me
)
333 uint16_t flags
= kDNSHeaderFlag_RecursionDesired
;
334 if (me
->set_ad_bit
) {
335 flags
|= kDNSHeaderFlag_AuthenticData
;
337 if (me
->set_cd_bit
) {
338 flags
|= kDNSHeaderFlag_CheckingDisabled
;
340 uint8_t query_buf
[MDNS_QUERY_MESSAGE_BUFFER_SIZE
];
342 const uint8_t * const qname
= _mdns_query_message_get_qname_safe(me
);
343 OSStatus err
= DNSMessageWriteQuery(me
->msg_id
, flags
, qname
, me
->qtype
, me
->qclass
, query_buf
, &query_len
);
344 require_noerr_quiet(err
, exit
);
346 if (me
->use_edns0_padding
) {
347 err
= _mdns_query_message_add_edns0_padding(query_buf
, query_len
, me
->set_do_bit
, &query_len
);
348 require_noerr_quiet(err
, exit
);
349 } else if (me
->set_do_bit
) {
350 err
= _mdns_query_message_add_edns0_dnssec_ok(query_buf
, query_len
, &query_len
);
351 require_noerr_quiet(err
, exit
);
353 dispatch_data_t query_data
= dispatch_data_create(query_buf
, query_len
, NULL
, DISPATCH_DATA_DESTRUCTOR_DEFAULT
);
354 require_action_quiet(query_data
, exit
, err
= kNoMemoryErr
);
356 err
= _mdns_message_set_msg_data(me
, query_data
);
357 dispatch_forget(&query_data
);
358 require_noerr_quiet(err
, exit
);
360 me
->constructed
= true;
367 _mdns_query_message_add_edns0_padding(uint8_t query_buf
[static MDNS_QUERY_MESSAGE_BUFFER_SIZE
], const size_t query_len
,
368 const bool set_do_bit
, size_t * const out_len
)
370 const size_t new_len
= RoundUp(query_len
+ MDNS_EDNS0_PADDING_OVERHEAD
, MDNS_EDNS0_PADDING_BLOCK_SIZE
);
371 require_return_value(new_len
<= MDNS_QUERY_MESSAGE_BUFFER_SIZE
, kSizeErr
);
373 uint8_t * const end
= &query_buf
[query_len
];
374 const uint8_t * const new_end
= &query_buf
[new_len
];
375 memset(end
, 0, (size_t)(new_end
- end
));
377 check_compile_time_code(MDNS_EDNS0_PADDING_OVERHEAD
== sizeof(dns_fixed_fields_opt1
));
379 dns_fixed_fields_opt1
* const pad_opt
= (dns_fixed_fields_opt1
*)end
;
380 const uint8_t * const pad_start
= (const uint8_t *)&pad_opt
[1];
381 dns_fixed_fields_opt1_set_type(pad_opt
, kDNSRecordType_OPT
);
382 dns_fixed_fields_opt1_set_udp_payload_size(pad_opt
, 512);
383 dns_fixed_fields_opt1_set_rdlen(pad_opt
, (uint16_t)(new_end
- pad_opt
->option_code
));
384 dns_fixed_fields_opt1_set_option_code(pad_opt
, kDNSEDNS0OptionCode_Padding
);
385 dns_fixed_fields_opt1_set_option_length(pad_opt
, (uint16_t)(new_end
- pad_start
));
387 dns_fixed_fields_opt1_set_extended_flags(pad_opt
, kDNSExtendedFlag_DNSSECOK
);
389 DNSHeaderSetAdditionalCount((DNSHeader
*)&query_buf
[0], 1);
397 _mdns_query_message_add_edns0_dnssec_ok(uint8_t query_buf
[static MDNS_QUERY_MESSAGE_BUFFER_SIZE
],
398 const size_t query_len
, size_t * const out_len
)
400 dns_fixed_fields_opt
*opt
;
401 const size_t new_len
= query_len
+ sizeof(*opt
);
402 require_return_value(new_len
<= MDNS_QUERY_MESSAGE_BUFFER_SIZE
, kSizeErr
);
404 opt
= (dns_fixed_fields_opt
*)&query_buf
[query_len
];
405 memset(opt
, 0, sizeof(*opt
));
406 dns_fixed_fields_opt_set_type(opt
, kDNSRecordType_OPT
);
407 dns_fixed_fields_opt_set_udp_payload_size(opt
, 512);
408 dns_fixed_fields_opt_set_extended_flags(opt
, kDNSExtendedFlag_DNSSECOK
);
410 DNSHeaderSetAdditionalCount((DNSHeader
*)&query_buf
[0], 1);
417 //======================================================================================================================
420 mdns_query_message_get_qname(const mdns_query_message_t me
)
422 return _mdns_query_message_get_qname_safe(me
);
425 //======================================================================================================================
428 mdns_query_message_get_qtype(const mdns_query_message_t me
)
433 //======================================================================================================================
436 mdns_query_message_get_qclass(const mdns_query_message_t me
)
441 //======================================================================================================================
444 mdns_query_message_get_message_id(const mdns_query_message_t me
)
449 //======================================================================================================================
452 mdns_query_message_do_bit_is_set(const mdns_query_message_t me
)
454 return me
->set_do_bit
;
457 //======================================================================================================================
458 // MARK: - Query Message Private Methods
461 _mdns_query_message_finalize(const mdns_query_message_t me
)
463 ForgetMem(&me
->qname
);
466 //======================================================================================================================
469 _mdns_query_message_get_qname_safe(const mdns_query_message_t me
)
471 return (me
->qname
? me
->qname
: (const uint8_t *)"");