1 /*
2 	Copyright (c) 2016-2020 Apple Inc. All rights reserved.
3 */
4 
5 #ifndef	__DNSMessage_h
6 #define	__DNSMessage_h
7 
8 #include <CoreUtils/CommonServices.h>
9 
10 CU_ASSUME_NONNULL_BEGIN
11 
12 __BEGIN_DECLS
13 
14 //---------------------------------------------------------------------------------------------------------------------------
15 /*!	@group		DNS domain name size limits
16 
17 	@discussion See <https://tools.ietf.org/html/rfc1035#section-2.3.4>.
18 */
19 #define kDomainLabelLengthMax		63
20 #define kDomainNameLengthMax		256	// For compatibility with mDNS. See <https://tools.ietf.org/html/rfc6762#appendix-C>.
21 
22 //---------------------------------------------------------------------------------------------------------------------------
23 /*!	@group		DNS message header
24 */
25 typedef struct
26 {
27 	uint8_t		id[ 2 ];
28 	uint8_t		flags[ 2 ];
29 	uint8_t		questionCount[ 2 ];
30 	uint8_t		answerCount[ 2 ];
31 	uint8_t		authorityCount[ 2 ];
32 	uint8_t		additionalCount[ 2 ];
33 
34 }	DNSHeader;
35 
36 #define kDNSHeaderLength		12
37 check_compile_time( sizeof( DNSHeader ) == kDNSHeaderLength );
38 
39 #define DNSHeaderGetID( HDR )					ReadBig16( ( HDR )->id )
40 #define DNSHeaderGetFlags( HDR )				ReadBig16( ( HDR )->flags )
41 #define DNSHeaderGetQuestionCount( HDR )		ReadBig16( ( HDR )->questionCount )
42 #define DNSHeaderGetAnswerCount( HDR )			ReadBig16( ( HDR )->answerCount )
43 #define DNSHeaderGetAuthorityCount( HDR )		ReadBig16( ( HDR )->authorityCount )
44 #define DNSHeaderGetAdditionalCount( HDR )		ReadBig16( ( HDR )->additionalCount )
45 
46 #define DNSHeaderSetID( HDR, X )					WriteBig16( ( HDR )->id, (X) )
47 #define DNSHeaderSetFlags( HDR, X )					WriteBig16( ( HDR )->flags, (X) )
48 #define DNSHeaderSetQuestionCount( HDR, X )			WriteBig16( ( HDR )->questionCount, (X) )
49 #define DNSHeaderSetAnswerCount( HDR, X )			WriteBig16( ( HDR )->answerCount, (X) )
50 #define DNSHeaderSetAuthorityCount( HDR, X )		WriteBig16( ( HDR )->authorityCount, (X) )
51 #define DNSHeaderSetAdditionalCount( HDR, X )		WriteBig16( ( HDR )->additionalCount, (X) )
52 
53 // Single-bit DNS header fields
54 
55 #define kDNSHeaderFlag_Response					( 1U << 15 )	// QR (bit 15), Query (0)/Response (1)
56 #define kDNSHeaderFlag_AuthAnswer				( 1U << 10 )	// AA (bit 10), Authoritative Answer
57 #define kDNSHeaderFlag_Truncation				( 1U <<  9 )	// TC (bit  9), TrunCation
58 #define kDNSHeaderFlag_RecursionDesired			( 1U <<  8 )	// RD (bit  8), Recursion Desired
59 #define kDNSHeaderFlag_RecursionAvailable		( 1U <<  7 )	// RA (bit  7), Recursion Available
60 #define kDNSHeaderFlag_Z						( 1U <<  6 )	//  Z (bit  6), Reserved (must be zero)
61 #define kDNSHeaderFlag_AuthenticData			( 1U <<  5 )	// AD (bit  5), Authentic Data (RFC 2535, Section 6)
62 #define kDNSHeaderFlag_CheckingDisabled			( 1U <<  4 )	// CD (bit  4), Checking Disabled (RFC 2535, Section 6)
63 
64 // OPCODE (bits 14-11), Operation Code
65 
66 #define DNSFlagsGetOpCode( FLAGS )		( ( (FLAGS) >> 11 ) & 0x0FU )
67 #define DNSFlagsSetOpCode( FLAGS, OPCODE ) \
68 		do { (FLAGS) = ( (FLAGS) & ~0x7800U ) | ( ( (OPCODE) & 0x0FU ) << 11 ); } while( 0 )
69 
70 #define kDNSOpCode_Query			0	// QUERY (standard query)
71 #define kDNSOpCode_InverseQuery		1	// IQUERY (inverse query)
72 #define kDNSOpCode_Status			2	// STATUS
73 #define kDNSOpCode_Notify			4	// NOTIFY
74 #define kDNSOpCode_Update			5	// UPDATE
75 
76 // RCODE (bits 3-0), Response Code
77 
78 #define DNSFlagsGetRCode( FLAGS )				( (FLAGS) & 0x0FU )
79 #define DNSFlagsSetRCode( FLAGS, RCODE ) \
80 	do { (FLAGS) = ( (FLAGS) & ~0x000FU ) | ( ( (unsigned int)(RCODE) ) & 0x0FU ); } while( 0 )
81 
82 //---------------------------------------------------------------------------------------------------------------------------
83 /*!	@group		Multicast DNS Constants
84 */
85 
86 #define kMDNSClassUnicastResponseBit		( 1U << 15 ) // See <https://tools.ietf.org/html/rfc6762#section-18.12>.
87 #define kMDNSClassCacheFlushBit				( 1U << 15 ) // See <https://tools.ietf.org/html/rfc6762#section-18.13>.
88 
89 //---------------------------------------------------------------------------------------------------------------------------
90 /*!	@group		Misc. DNS message data structures
91 */
92 
93 #define _DNSMessageGet8( PTR )			Read8( PTR )
94 #define _DNSMessageGet16( PTR )			ReadBig16( PTR )
95 #define _DNSMessageGet32( PTR )			ReadBig32( PTR )
96 #define _DNSMessageSet8( PTR, X )		Write8( PTR, X )
97 #define _DNSMessageSet16( PTR, X )		WriteBig16( PTR, X )
98 #define _DNSMessageSet32( PTR, X )		WriteBig32( PTR, X )
99 
100 #define dns_fields_define_accessors( PREFIX, TYPE, FIELD, BIT_SIZE )	\
101 	STATIC_INLINE uint ## BIT_SIZE ## _t								\
102 		dns_ ## PREFIX ## _ ## TYPE ## _get_ ## FIELD (					\
103 			const dns_ ## PREFIX ## _ ## TYPE *	inFields )				\
104 	{																	\
105 		return _DNSMessageGet ## BIT_SIZE ( inFields->FIELD );			\
106 	}																	\
107 																		\
108 	STATIC_INLINE void													\
109 		dns_ ## PREFIX ## _ ## TYPE ## _set_ ## FIELD (					\
110 			dns_ ## PREFIX ## _ ## TYPE *	inFields,					\
111 			uint ## BIT_SIZE ## _t			inValue )					\
112 	{																	\
113 		_DNSMessageSet ## BIT_SIZE ( inFields->FIELD, inValue );		\
114 	}																	\
115 	check_compile_time( ( sizeof_field( dns_ ## PREFIX ## _ ## TYPE, FIELD ) * 8 ) == (BIT_SIZE) )
116 
117 #define dns_fixed_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
118 	dns_fields_define_accessors( fixed_fields, TYPE, FIELD, BIT_SIZE )
119 
120 #define dns_dnskey_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
121 	dns_fields_define_accessors( dnskey, TYPE, FIELD, BIT_SIZE )
122 
123 #define dns_ds_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
124 	dns_fields_define_accessors( ds, TYPE, FIELD, BIT_SIZE )
125 
126 // DNS question fixed-length fields
127 // See <https://tools.ietf.org/html/rfc1035#section-4.1.2>
128 
129 typedef struct
130 {
131 	uint8_t		type[ 2 ];
132 	uint8_t		class[ 2 ];
133 
134 }	dns_fixed_fields_question;
135 
136 check_compile_time( sizeof( dns_fixed_fields_question ) == 4 );
137 
138 dns_fixed_fields_define_accessors( question, type,  16 );
139 dns_fixed_fields_define_accessors( question, class, 16 );
140 
141 STATIC_INLINE void
dns_fixed_fields_question_init(dns_fixed_fields_question * inFields,uint16_t inQType,uint16_t inQClass)142 	dns_fixed_fields_question_init(
143 		dns_fixed_fields_question *	inFields,
144 		uint16_t					inQType,
145 		uint16_t					inQClass )
146 {
147 	dns_fixed_fields_question_set_type( inFields, inQType );
148 	dns_fixed_fields_question_set_class( inFields, inQClass );
149 }
150 
151 // DNS resource record fixed-length fields
152 // See <https://tools.ietf.org/html/rfc1035#section-4.1.3>
153 
154 typedef struct
155 {
156 	uint8_t		type[ 2 ];
157 	uint8_t		class[ 2 ];
158 	uint8_t		ttl[ 4 ];
159 	uint8_t		rdlength[ 2 ];
160 
161 }	dns_fixed_fields_record;
162 
163 check_compile_time( sizeof( dns_fixed_fields_record ) == 10 );
164 
165 dns_fixed_fields_define_accessors( record, type,     16 );
166 dns_fixed_fields_define_accessors( record, class,    16 );
167 dns_fixed_fields_define_accessors( record, ttl,      32 );
168 dns_fixed_fields_define_accessors( record, rdlength, 16 );
169 
170 STATIC_INLINE void
dns_fixed_fields_record_init(dns_fixed_fields_record * inFields,uint16_t inType,uint16_t inClass,uint32_t inTTL,uint16_t inRDLength)171 	dns_fixed_fields_record_init(
172 		dns_fixed_fields_record *	inFields,
173 		uint16_t					inType,
174 		uint16_t					inClass,
175 		uint32_t					inTTL,
176 		uint16_t					inRDLength )
177 {
178 	dns_fixed_fields_record_set_type( inFields, inType );
179 	dns_fixed_fields_record_set_class( inFields, inClass );
180 	dns_fixed_fields_record_set_ttl( inFields, inTTL );
181 	dns_fixed_fields_record_set_rdlength( inFields, inRDLength );
182 }
183 
184 // DNS SRV record data fixed-length fields
185 // See <https://tools.ietf.org/html/rfc2782>
186 
187 typedef struct
188 {
189 	uint8_t		priority[ 2 ];
190 	uint8_t		weight[ 2 ];
191 	uint8_t		port[ 2 ];
192 
193 }	dns_fixed_fields_srv;
194 
195 check_compile_time( sizeof( dns_fixed_fields_srv ) == 6 );
196 
197 dns_fixed_fields_define_accessors( srv, priority, 16 );
198 dns_fixed_fields_define_accessors( srv, weight,   16 );
199 dns_fixed_fields_define_accessors( srv, port,     16 );
200 
201 STATIC_INLINE void
dns_fixed_fields_srv_init(dns_fixed_fields_srv * inFields,uint16_t inPriority,uint16_t inWeight,uint16_t inPort)202 	dns_fixed_fields_srv_init(
203 		dns_fixed_fields_srv *	inFields,
204 		uint16_t				inPriority,
205 		uint16_t				inWeight,
206 		uint16_t				inPort )
207 {
208 	dns_fixed_fields_srv_set_priority( inFields, inPriority );
209 	dns_fixed_fields_srv_set_weight( inFields, inWeight );
210 	dns_fixed_fields_srv_set_port( inFields, inPort );
211 }
212 
213 // DNS SOA record data fixed-length fields
214 // See <https://tools.ietf.org/html/rfc1035#section-3.3.13>
215 
216 typedef struct
217 {
218 	uint8_t		serial[ 4 ];
219 	uint8_t		refresh[ 4 ];
220 	uint8_t		retry[ 4 ];
221 	uint8_t		expire[ 4 ];
222 	uint8_t		minimum[ 4 ];
223 
224 }	dns_fixed_fields_soa;
225 
226 check_compile_time( sizeof( dns_fixed_fields_soa ) == 20 );
227 
228 dns_fixed_fields_define_accessors( soa, serial,  32 );
229 dns_fixed_fields_define_accessors( soa, refresh, 32 );
230 dns_fixed_fields_define_accessors( soa, retry,   32 );
231 dns_fixed_fields_define_accessors( soa, expire,  32 );
232 dns_fixed_fields_define_accessors( soa, minimum, 32 );
233 
234 STATIC_INLINE void
dns_fixed_fields_soa_init(dns_fixed_fields_soa * inFields,uint32_t inSerial,uint32_t inRefresh,uint32_t inRetry,uint32_t inExpire,uint32_t inMinimum)235 	dns_fixed_fields_soa_init(
236 		dns_fixed_fields_soa *	inFields,
237 		uint32_t				inSerial,
238 		uint32_t				inRefresh,
239 		uint32_t				inRetry,
240 		uint32_t				inExpire,
241 		uint32_t				inMinimum )
242 {
243 	dns_fixed_fields_soa_set_serial( inFields, inSerial );
244 	dns_fixed_fields_soa_set_refresh( inFields, inRefresh );
245 	dns_fixed_fields_soa_set_retry( inFields, inRetry );
246 	dns_fixed_fields_soa_set_expire( inFields, inExpire );
247 	dns_fixed_fields_soa_set_minimum( inFields, inMinimum );
248 }
249 
250 // OPT pseudo-resource record fixed-length fields without RDATA
251 // See <https://tools.ietf.org/html/rfc6891#section-6.1.2>
252 
253 typedef struct
254 {
255 	uint8_t		name[ 1 ];
256 	uint8_t		type[ 2 ];
257 	uint8_t		udp_payload_size[ 2 ];
258 	uint8_t		extended_rcode[ 1 ];
259 	uint8_t		version[ 1 ];
260 	uint8_t		extended_flags[ 2 ];
261 	uint8_t		rdlen[ 2 ];
262 
263 }	dns_fixed_fields_opt;
264 
265 check_compile_time( sizeof( dns_fixed_fields_opt ) == 11 );
266 
267 #define kDNSExtendedFlag_DNSSECOK		( 1U << 15 ) // <https://tools.ietf.org/html/rfc3225#section-3>
268 
269 dns_fixed_fields_define_accessors( opt, name,              8 );
270 dns_fixed_fields_define_accessors( opt, type,             16 );
271 dns_fixed_fields_define_accessors( opt, udp_payload_size, 16 );
272 dns_fixed_fields_define_accessors( opt, extended_rcode,    8 );
273 dns_fixed_fields_define_accessors( opt, version,           8 );
274 dns_fixed_fields_define_accessors( opt, extended_flags,   16 );
275 dns_fixed_fields_define_accessors( opt, rdlen,            16 );
276 
277 // OPT pseudo-resource record fixed-length fields with OPTION-CODE and OPTION-LENGTH
278 // See <https://tools.ietf.org/html/rfc6891#section-6.1.2>
279 
280 typedef struct
281 {
282 	uint8_t		name[ 1 ];
283 	uint8_t		type[ 2 ];
284 	uint8_t		udp_payload_size[ 2 ];
285 	uint8_t		extended_rcode[ 1 ];
286 	uint8_t		version[ 1 ];
287 	uint8_t		extended_flags[ 2 ];
288 	uint8_t		rdlen[ 2 ];
289 	uint8_t		option_code[ 2 ];
290 	uint8_t		option_length[ 2 ];
291 
292 }	dns_fixed_fields_opt1;
293 
294 check_compile_time( sizeof( dns_fixed_fields_opt1 ) == 15 );
295 
296 dns_fixed_fields_define_accessors( opt1, name,              8 );
297 dns_fixed_fields_define_accessors( opt1, type,             16 );
298 dns_fixed_fields_define_accessors( opt1, udp_payload_size, 16 );
299 dns_fixed_fields_define_accessors( opt1, extended_rcode,    8 );
300 dns_fixed_fields_define_accessors( opt1, version,           8 );
301 dns_fixed_fields_define_accessors( opt1, extended_flags,   16 );
302 dns_fixed_fields_define_accessors( opt1, rdlen,            16 );
303 dns_fixed_fields_define_accessors( opt1, option_code,      16 );
304 dns_fixed_fields_define_accessors( opt1, option_length,    16 );
305 
306 // OPT pseudo-resource record RDATA option fixed-length fields
307 // See <https://tools.ietf.org/html/rfc6891#section-6.1.2>
308 
309 typedef struct
310 {
311 	uint8_t		code[ 2 ];
312 	uint8_t		length[ 2 ];
313 
314 }	dns_fixed_fields_option;
315 
316 check_compile_time( sizeof( dns_fixed_fields_option ) == 4 );
317 
318 dns_fixed_fields_define_accessors( option, code,   16 );
319 dns_fixed_fields_define_accessors( option, length, 16 );
320 
321 // DNS DNSKEY record data fixed-length fields
322 // See <https://tools.ietf.org/html/rfc4034#section-2.1>
323 
324 typedef struct
325 {
326 	uint8_t		flags[ 2 ];
327 	uint8_t		protocol[ 1 ];
328 	uint8_t		algorithm[ 1 ];
329 
330 }	dns_fixed_fields_dnskey;
331 
332 check_compile_time( sizeof( dns_fixed_fields_dnskey ) == 4 );
333 
334 dns_fixed_fields_define_accessors( dnskey, flags,     16 );
335 dns_fixed_fields_define_accessors( dnskey, protocol,   8 );
336 dns_fixed_fields_define_accessors( dnskey, algorithm,  8 );
337 
338 #define kDNSKeyFlag_ZoneKey		( 1U << ( 15 -  7 ) )	// MSB bit 7  <https://tools.ietf.org/html/rfc4034#section-2.1.1>
339 #define kDNSKeyFlag_SEP			( 1U << ( 15 - 15 ) )	// MSB bit 15 <https://tools.ietf.org/html/rfc4034#section-2.1.1>
340 
341 #define kDNSKeyProtocol_DNSSEC		3	// Protocol value must be 3. <https://tools.ietf.org/html/rfc4034#section-2.1.2>
342 
343 // DNSSEC Algoritm Numbers
344 // See <https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#dns-sec-alg-numbers-1>
345 
346 #define kDNSSECAlgorithm_RSASHA1			 5	// RSA/SHA-1
347 #define kDNSSECAlgorithm_RSASHA256			 8	// RSA/SHA-256
348 #define kDNSSECAlgorithm_RSASHA512			10	// RSA/SHA-512
349 #define kDNSSECAlgorithm_ECDSAP256SHA256	13	// ECDSA P-256 curve/SHA-256
350 #define kDNSSECAlgorithm_ECDSAP384SHA384	14	// ECDSA P-384 curve/SHA-384
351 #define kDNSSECAlgorithm_Ed25519			15	// Ed25519
352 
353 // DNS RRSIG record data fixed-length fields
354 // See <https://tools.ietf.org/html/rfc4034#section-3.1>
355 
356 typedef struct
357 {
358 	uint8_t		type_covered[ 2 ];
359 	uint8_t		algorithm[ 1 ];
360 	uint8_t		labels[ 1 ];
361 	uint8_t		original_ttl[ 4 ];
362 	uint8_t		signature_expiration[ 4 ];
363 	uint8_t		signature_inception[ 4 ];
364 	uint8_t		key_tag[ 2 ];
365 
366 }	dns_fixed_fields_rrsig;
367 
368 check_compile_time( sizeof( dns_fixed_fields_rrsig ) == 18 );
369 
370 dns_fixed_fields_define_accessors( rrsig, type_covered,         16 );
371 dns_fixed_fields_define_accessors( rrsig, algorithm,             8 );
372 dns_fixed_fields_define_accessors( rrsig, labels,                8 );
373 dns_fixed_fields_define_accessors( rrsig, original_ttl,         32 );
374 dns_fixed_fields_define_accessors( rrsig, signature_expiration, 32 );
375 dns_fixed_fields_define_accessors( rrsig, signature_inception,  32 );
376 dns_fixed_fields_define_accessors( rrsig, key_tag,              16 );
377 
378 // DNS DS record data fixed-length fields
379 // See <https://tools.ietf.org/html/rfc4034#section-5.1>
380 
381 typedef struct
382 {
383 	uint8_t		key_tag[ 2 ];
384 	uint8_t		algorithm[ 1 ];
385 	uint8_t		digest_type[ 1 ];
386 
387 }	dns_fixed_fields_ds;
388 
389 check_compile_time( sizeof( dns_fixed_fields_ds ) == 4 );
390 
391 dns_fixed_fields_define_accessors( ds, key_tag,     16 );
392 dns_fixed_fields_define_accessors( ds, algorithm,    8 );
393 dns_fixed_fields_define_accessors( ds, digest_type,  8 );
394 
395 #define kDSDigestType_SHA1			1	// SHA-1   <https://tools.ietf.org/html/rfc4034#appendix-A.2>
396 #define kDSDigestType_SHA256		2	// SHA-256 <https://tools.ietf.org/html/rfc4509#section-5>
397 
398 // DNS DS record data
399 // See <https://tools.ietf.org/html/rfc4509#section-2.2>
400 
401 typedef struct
402 {
403 	uint8_t		key_tag[ 2 ];
404 	uint8_t		algorithm[ 1 ];
405 	uint8_t		digest_type[ 1 ];
406 	uint8_t		digest[ 32 ];
407 
408 }	dns_ds_sha256;
409 
410 check_compile_time( sizeof( dns_ds_sha256 ) == 36 );
411 
412 dns_ds_fields_define_accessors( sha256, key_tag,     16 );
413 dns_ds_fields_define_accessors( sha256, algorithm,    8 );
414 dns_ds_fields_define_accessors( sha256, digest_type,  8 );
415 
416 // DNS NSEC3 record data fixed-length fields
417 // See <https://tools.ietf.org/html/rfc5155#section-3.2>
418 
419 typedef struct
420 {
421 	uint8_t		hash_alg[ 1 ];
422 	uint8_t		flags[ 1 ];
423 	uint8_t		iterations[ 2 ];
424 
425 }	dns_fixed_fields_nsec3;
426 
427 check_compile_time( sizeof( dns_fixed_fields_nsec3 ) == 4 );
428 
429 dns_fixed_fields_define_accessors( nsec3, hash_alg,    8 );
430 dns_fixed_fields_define_accessors( nsec3, flags,       8 );
431 dns_fixed_fields_define_accessors( nsec3, iterations, 16 );
432 
433 // DNS SVCB record data fixed-length fields
434 // See <https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-00#section-2.2>
435 
436 typedef struct
437 {
438 	uint8_t		priority[ 2 ];
439 
440 }	dns_fixed_fields_svcb;
441 
442 check_compile_time( sizeof( dns_fixed_fields_svcb ) == 2 );
443 
444 dns_fixed_fields_define_accessors( svcb, priority, 16 );
445 
446 typedef struct
447 {
448 	uint8_t		key[ 2 ];
449 	uint8_t		value_length[ 2 ];
450 
451 }	dns_fixed_fields_svcb_param;
452 
453 check_compile_time( sizeof( dns_fixed_fields_svcb_param ) == 4 );
454 
455 dns_fixed_fields_define_accessors( svcb_param, key,          16 );
456 dns_fixed_fields_define_accessors( svcb_param, value_length, 16 );
457 
458 //---------------------------------------------------------------------------------------------------------------------------
459 /*!	@group		DNS record types
460 */
461 // This code was autogenerated on 2020-06-30 by dns-rr-func-autogen version 1.3
462 // Data source URL: https://www.iana.org/assignments/dns-parameters/dns-parameters-4.csv
463 // Overrides: none
464 
465 typedef enum
466 {
467 	kDNSRecordType_A          = 1,
468 	kDNSRecordType_NS         = 2,
469 	kDNSRecordType_MD         = 3,
470 	kDNSRecordType_MF         = 4,
471 	kDNSRecordType_CNAME      = 5,
472 	kDNSRecordType_SOA        = 6,
473 	kDNSRecordType_MB         = 7,
474 	kDNSRecordType_MG         = 8,
475 	kDNSRecordType_MR         = 9,
476 	kDNSRecordType_NULL       = 10,
477 	kDNSRecordType_WKS        = 11,
478 	kDNSRecordType_PTR        = 12,
479 	kDNSRecordType_HINFO      = 13,
480 	kDNSRecordType_MINFO      = 14,
481 	kDNSRecordType_MX         = 15,
482 	kDNSRecordType_TXT        = 16,
483 	kDNSRecordType_RP         = 17,
484 	kDNSRecordType_AFSDB      = 18,
485 	kDNSRecordType_X25        = 19,
486 	kDNSRecordType_ISDN       = 20,
487 	kDNSRecordType_RT         = 21,
488 	kDNSRecordType_NSAP       = 22,
489 	kDNSRecordType_NSAP_PTR   = 23,
490 	kDNSRecordType_SIG        = 24,
491 	kDNSRecordType_KEY        = 25,
492 	kDNSRecordType_PX         = 26,
493 	kDNSRecordType_GPOS       = 27,
494 	kDNSRecordType_AAAA       = 28,
495 	kDNSRecordType_LOC        = 29,
496 	kDNSRecordType_NXT        = 30,
497 	kDNSRecordType_EID        = 31,
498 	kDNSRecordType_NIMLOC     = 32,
499 	kDNSRecordType_SRV        = 33,
500 	kDNSRecordType_ATMA       = 34,
501 	kDNSRecordType_NAPTR      = 35,
502 	kDNSRecordType_KX         = 36,
503 	kDNSRecordType_CERT       = 37,
504 	kDNSRecordType_A6         = 38,
505 	kDNSRecordType_DNAME      = 39,
506 	kDNSRecordType_SINK       = 40,
507 	kDNSRecordType_OPT        = 41,
508 	kDNSRecordType_APL        = 42,
509 	kDNSRecordType_DS         = 43,
510 	kDNSRecordType_SSHFP      = 44,
511 	kDNSRecordType_IPSECKEY   = 45,
512 	kDNSRecordType_RRSIG      = 46,
513 	kDNSRecordType_NSEC       = 47,
514 	kDNSRecordType_DNSKEY     = 48,
515 	kDNSRecordType_DHCID      = 49,
516 	kDNSRecordType_NSEC3      = 50,
517 	kDNSRecordType_NSEC3PARAM = 51,
518 	kDNSRecordType_TLSA       = 52,
519 	kDNSRecordType_SMIMEA     = 53,
520 	kDNSRecordType_HIP        = 55,
521 	kDNSRecordType_NINFO      = 56,
522 	kDNSRecordType_RKEY       = 57,
523 	kDNSRecordType_TALINK     = 58,
524 	kDNSRecordType_CDS        = 59,
525 	kDNSRecordType_CDNSKEY    = 60,
526 	kDNSRecordType_OPENPGPKEY = 61,
527 	kDNSRecordType_CSYNC      = 62,
528 	kDNSRecordType_ZONEMD     = 63,
529 	kDNSRecordType_SVCB       = 64,
530 	kDNSRecordType_HTTPS      = 65,
531 	kDNSRecordType_SPF        = 99,
532 	kDNSRecordType_UINFO      = 100,
533 	kDNSRecordType_UID        = 101,
534 	kDNSRecordType_GID        = 102,
535 	kDNSRecordType_UNSPEC     = 103,
536 	kDNSRecordType_NID        = 104,
537 	kDNSRecordType_L32        = 105,
538 	kDNSRecordType_L64        = 106,
539 	kDNSRecordType_LP         = 107,
540 	kDNSRecordType_EUI48      = 108,
541 	kDNSRecordType_EUI64      = 109,
542 	kDNSRecordType_TKEY       = 249,
543 	kDNSRecordType_TSIG       = 250,
544 	kDNSRecordType_IXFR       = 251,
545 	kDNSRecordType_AXFR       = 252,
546 	kDNSRecordType_MAILB      = 253,
547 	kDNSRecordType_MAILA      = 254,
548 	kDNSRecordType_ANY        = 255,
549 	kDNSRecordType_URI        = 256,
550 	kDNSRecordType_CAA        = 257,
551 	kDNSRecordType_AVC        = 258,
552 	kDNSRecordType_DOA        = 259,
553 	kDNSRecordType_AMTRELAY   = 260,
554 	kDNSRecordType_TA         = 32768,
555 	kDNSRecordType_DLV        = 32769,
556 	kDNSRecordType_Reserved   = 65535,
557 
558 }	DNSRecordType;
559 
560 //---------------------------------------------------------------------------------------------------------------------------
561 /*!	@group		DNS RCODEs
562 */
563 // This code was autogenerated on 2020-06-15 by dns-rcode-func-autogen version 1.0
564 // Data source URL: https://www.iana.org/assignments/dns-parameters/dns-parameters-6.csv
565 
566 typedef enum
567 {
568 	kDNSRCode_NoError   = 0,
569 	kDNSRCode_FormErr   = 1,
570 	kDNSRCode_ServFail  = 2,
571 	kDNSRCode_NXDomain  = 3,
572 	kDNSRCode_NotImp    = 4,
573 	kDNSRCode_Refused   = 5,
574 	kDNSRCode_YXDomain  = 6,
575 	kDNSRCode_YXRRSet   = 7,
576 	kDNSRCode_NXRRSet   = 8,
577 	kDNSRCode_NotAuth   = 9,
578 	kDNSRCode_NotZone   = 10,
579 	kDNSRCode_DSOTYPENI = 11
580 
581 }	DNSRCode;
582 
583 //---------------------------------------------------------------------------------------------------------------------------
584 /*!	@group		DNS classes
585 */
586 
587 typedef enum
588 {
589 	kDNSClassType_IN = 1	// See <https://tools.ietf.org/html/rfc1035#section-3.2.4>.
590 
591 }	DNSClassType;
592 
593 //---------------------------------------------------------------------------------------------------------------------------
594 /*!	@group		DNS EDNS0 Option Codes
595 */
596 typedef enum
597 {
598 	kDNSEDNS0OptionCode_Padding = 12	// <https://tools.ietf.org/html/rfc7830#section-3>
599 
600 }	DNSEDNS0OptionCode;
601 
602 //---------------------------------------------------------------------------------------------------------------------------
603 /*!	@group		DNS EDNS0 Option Codes
604 	@discussion	See <https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-00#section-12.1.2>.
605 */
606 typedef enum
607 {
608 	kDNSSVCParamKey_Mandatory		= 0,
609 	kDNSSVCParamKey_ALPN			= 1,
610 	kDNSSVCParamKey_NoDefaultALPN	= 2,
611 	kDNSSVCParamKey_Port			= 3,
612 	kDNSSVCParamKey_IPv4Hint		= 4,
613 	kDNSSVCParamKey_ECHConfig		= 5,
614 	kDNSSVCParamKey_IPv6Hint		= 6,
615 	kDNSSVCParamKey_DOHURI			= 32768 // XXX: Apple Internal
616 
617 }	DNSSVCParamKey;
618 
619 //---------------------------------------------------------------------------------------------------------------------------
620 /*!	@brief		Extracts a domain name from a DNS message.
621 
622 	@param		inMsgPtr		Pointer to the beginning of the DNS message containing the domain name.
623 	@param		inMsgLen		Length of the DNS message containing the domain name.
624 	@param		inPtr			Pointer to the domain name field.
625 	@param		outName			Buffer to write extracted domain name. (Optional)
626 	@param		outPtr			Gets set to point to the end of the domain name field. (Optional)
627 */
628 OSStatus
629 	DNSMessageExtractDomainName(
630 		const uint8_t *							inMsgPtr,
631 		size_t									inMsgLen,
632 		const uint8_t *							inPtr,
633 		uint8_t									outName[ _Nullable kDomainNameLengthMax ],
634 		const uint8_t * _Nullable * _Nullable	outPtr );
635 
636 //---------------------------------------------------------------------------------------------------------------------------
637 /*!	@brief		Extracts a domain name from a DNS message as a C string.
638 
639 	@param		inMsgPtr		Pointer to the beginning of the DNS message containing the domain name.
640 	@param		inMsgLen		Length of the DNS message containing the domain name.
641 	@param		inPtr			Pointer to the domain name field.
642 	@param		outName			Buffer to write extracted domain name. (Optional)
643 	@param		outPtr			Gets set to point to the end of the domain name field. (Optional)
644 */
645 OSStatus
646 	DNSMessageExtractDomainNameString(
647 		const void *							inMsgPtr,
648 		size_t									inMsgLen,
649 		const void *							inPtr,
650 		char									outName[ _Nullable kDNSServiceMaxDomainName ],
651 		const uint8_t * _Nullable * _Nullable	outPtr );
652 
653 //---------------------------------------------------------------------------------------------------------------------------
654 /*!	@brief		Extracts a question from a DNS message.
655 
656 	@param		inMsgPtr		Pointer to the beginning of the DNS message containing a question.
657 	@param		inMsgLen		Length of the DNS message containing the question.
658 	@param		inPtr			Pointer to the question.
659 	@param		outName			Buffer to write the question's QNAME. (Optional)
660 	@param		outType			Gets set to question's QTYPE value. (Optional)
661 	@param		outClass		Gets set to question's QCLASS value. (Optional)
662 	@param		outPtr			Gets set to point to the end of the question. (Optional)
663 */
664 OSStatus
665 	DNSMessageExtractQuestion(
666 		const uint8_t *							inMsgPtr,
667 		size_t									inMsgLen,
668 		const uint8_t *							inPtr,
669 		uint8_t									outName[ _Nullable kDomainNameLengthMax ],
670 		uint16_t * _Nullable					outType,
671 		uint16_t * _Nullable					outClass,
672 		const uint8_t * _Nullable * _Nullable	outPtr );
673 
674 //---------------------------------------------------------------------------------------------------------------------------
675 /*!	@brief		Extracts a resource record from a DNS message.
676 
677 	@param		inMsgPtr		Pointer to the beginning of the DNS message containing the resource record.
678 	@param		inMsgLen		Length of the DNS message containing the resource record.
679 	@param		inPtr			Pointer to the resource record.
680 	@param		outName			Buffer to write the resource record's NAME. (Optional)
681 	@param		outType			Gets set to resource record's TYPE value. (Optional)
682 	@param		outClass		Gets set to resource record's CLASS value. (Optional)
683 	@param		outTTL			Gets set to resource record's TTL value. (Optional)
684 	@param		outRDataPtr		Gets set to point to the resource record's RDATA. (Optional)
685 	@param		outRDataLen		Gets set to the resource record's RDLENGTH. (Optional)
686 	@param		outPtr			Gets set to point to the end of the resource record. (Optional)
687 */
688 OSStatus
689 	DNSMessageExtractRecord(
690 		const uint8_t *							inMsgPtr,
691 		size_t									inMsgLen,
692 		const uint8_t *							inPtr,
693 		uint8_t									outName[ _Nullable kDomainNameLengthMax ],
694 		uint16_t * _Nullable					outType,
695 		uint16_t * _Nullable					outClass,
696 		uint32_t * _Nullable					outTTL,
697 		const uint8_t * _Nullable * _Nullable	outRDataPtr,
698 		size_t * _Nullable						outRDataLen,
699 		const uint8_t * _Nullable * _Nullable	outPtr );
700 
701 //---------------------------------------------------------------------------------------------------------------------------
702 /*!	@brief		Gets a DNS message's answer section, i.e., the end of the message's question section.
703 
704 	@param		inMsgPtr		Pointer to the beginning of the DNS message.
705 	@param		inMsgLen		Length of the DNS message.
706 	@param		outPtr			Gets set to point to the start of the answer section. (Optional)
707 */
708 OSStatus
709 	DNSMessageGetAnswerSection(
710 		const uint8_t *							inMsgPtr,
711 		size_t									inMsgLen,
712 		const uint8_t * _Nullable * _Nullable	outPtr );
713 
714 //---------------------------------------------------------------------------------------------------------------------------
715 /*!	@brief		Gets a DNS message's OPT record if it exists.
716 
717 	@param		inMsgPtr		Pointer to the beginning of the DNS message.
718 	@param		inMsgLen		Length of the DNS message.
719 	@param		outOptPtr		Gets set to point to the start of the OPT record. (Optional)
720 	@param		outOptLen		Gets set to point to the length of the OPT record. (Optional)
721 */
722 OSStatus
723 	DNSMessageGetOptRecord(
724 		const uint8_t *							inMsgPtr,
725 		size_t									inMsgLen,
726 		const uint8_t * _Nullable * _Nullable	outOptPtr,
727 		size_t * _Nullable						outOptLen );
728 
729 //---------------------------------------------------------------------------------------------------------------------------
730 /*!	@brief		Writes a DNS message compression label pointer.
731 
732 	@param		inLabelPtr		Pointer to the two bytes to which to write the label pointer.
733 	@param		inOffset		The label pointer's offset value. This offset is relative to the start of the DNS message.
734 
735 	@discussion	See <https://tools.ietf.org/html/rfc1035#section-4.1.4>.
736 */
DNSMessageWriteLabelPointer(uint8_t inLabelPtr[STATIC_PARAM2],size_t inOffset)737 STATIC_INLINE void	DNSMessageWriteLabelPointer( uint8_t inLabelPtr[ STATIC_PARAM 2 ], size_t inOffset )
738 {
739 	inLabelPtr[ 0 ] = (uint8_t)( ( ( inOffset >> 8 ) & 0x3F ) | 0xC0 );
740 	inLabelPtr[ 1 ] = (uint8_t)(     inOffset        & 0xFF          );
741 }
742 
743 #define kDNSCompressionOffsetMax			0x3FFF
744 #define kDNSCompressionPointerLength		2
745 
746 //---------------------------------------------------------------------------------------------------------------------------
747 #define kDNSQueryMessageMaxLen		( kDNSHeaderLength + kDomainNameLengthMax + sizeof( dns_fixed_fields_question ) )
748 
749 /*!	@brief		Writes a single-question DNS query message.
750 
751 	@param		inMsgID			The query message's ID.
752 	@param		inFlags			The query message's flags.
753 	@param		inQName			The question's QNAME in label format.
754 	@param		inQType			The question's QTYPE.
755 	@param		inQClass		The question's QCLASS.
756 	@param		outMsg			Buffer to write DNS query message.
757 	@param		outLen			Gets set to the length of the DNS query message.
758 */
759 OSStatus
760 	DNSMessageWriteQuery(
761 		uint16_t		inMsgID,
762 		uint16_t		inFlags,
763 		const uint8_t *	inQName,
764 		uint16_t		inQType,
765 		uint16_t		inQClass,
766 		uint8_t			outMsg[ STATIC_PARAM kDNSQueryMessageMaxLen ],
767 		size_t *		outLen );
768 
769 //---------------------------------------------------------------------------------------------------------------------------
770 /*!	@brief		Creates a collapsed version of a DNS message.
771 
772 	@param		inMsgPtr		Pointer to the start of the DNS message.
773 	@param		inMsgLen		Length of the DNS message.
774 	@param		outMsgLen		Pointer of variable to set to the length of the collapsed DNS message.
775 	@param		outError		Pointer of variable to set to the error encountered by this function, if any.
776 
777 	@result		A dynamically allocated collapsed version of the DNS message.
778 
779 	@discussion This function creates a copy of a DNS message, except that
780 
781 	1. All records not in the Authority and Additional sections are removed.
782 	2. The CNAME chain, if any, from the QNAME to the non-CNAME records is collapsed, i.e., all CNAME records are removed.
783 	3. All records that are not direct or indirect answers to the question are also removed.
784 
785 	Note: Collapsing a DNS message is a non-standard operation and should be used with caution.
786 */
787 uint8_t * _Nullable
788 	DNSMessageCollapse(
789 		const uint8_t *			inMsgPtr,
790 		size_t					inMsgLen,
791 		size_t * _Nullable		outMsgLen,
792 		OSStatus * _Nullable	outError );
793 
794 //---------------------------------------------------------------------------------------------------------------------------
795 /*!	@brief		Appends one domain name to another.
796 
797 	@param		inName			Pointer to the target domain name.
798 	@param		inOtherName		Pointer to the domain name to append to the target domain name.
799 	@param		outEnd			Gets set to point to the new end of the domain name if the append succeeded. (Optional)
800 */
801 OSStatus
802 	DomainNameAppendDomainName(
803 		uint8_t							inName[ STATIC_PARAM kDomainNameLengthMax ],
804 		const uint8_t *					inOtherName,
805 		uint8_t * _Nullable * _Nullable	outEnd );
806 
807 //---------------------------------------------------------------------------------------------------------------------------
808 /*!	@brief		Appends a C string representing a textual sequence of labels to a domain name.
809 
810 	@param		inName			Pointer to the domain name.
811 	@param		inString		Pointer to textual sequence of labels as a C string.
812 	@param		outEnd			Gets set to point to the new end of the domain name if the append succeeded. (Optional)
813 */
814 OSStatus
815 	DomainNameAppendString(
816 		uint8_t							inName[ STATIC_PARAM kDomainNameLengthMax ],
817 		const char *					inString,
818 		uint8_t * _Nullable * _Nullable	outEnd );
819 
820 //---------------------------------------------------------------------------------------------------------------------------
821 /*!	@brief		Creates a duplicate domain name.
822 
823 	@param		inName			The domain name to duplicate.
824 	@param		inLower			If true, uppercase letters in the duplicate are converted to lowercase.
825 	@param		outNamePtr		Gets set to point to a dynamically allocated duplicate.
826 	@param		outNameLen		Gets set to the length of the duplicate. (Optional)
827 
828 	@discussion	The duplicate domain name must be freed with free() when no longer needed.
829 */
830 OSStatus
831 	DomainNameDupEx(
832 		const uint8_t *					inName,
833 		Boolean							inLower,
834 		uint8_t * _Nullable * _Nonnull	outNamePtr,
835 		size_t * _Nullable				outNameLen );
836 
837 #define DomainNameDup( IN_NAME, OUT_NAME, OUT_LEN )				DomainNameDupEx( IN_NAME, false, OUT_NAME, OUT_LEN )
838 #define DomainNameDupLower( IN_NAME, OUT_NAME, OUT_LEN )		DomainNameDupEx( IN_NAME, true, OUT_NAME, OUT_LEN )
839 
840 //---------------------------------------------------------------------------------------------------------------------------
841 /*!	@brief		Compares two domain names in label format for case-insensitive equality.
842 
843 	@param		inName1		Pointer to the first domain name.
844 	@param		inName2		Pointer to the second domain name.
845 
846 	@result		If the domain names are equal, returns true, otherwise, returns false.
847 */
848 Boolean	DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 );
849 
850 //---------------------------------------------------------------------------------------------------------------------------
851 /*!	@brief		Converts a domain name's textual representation to a domain name in label format.
852 
853 	@param		outName			Buffer to write the domain name in label format.
854 	@param		inString		Textual representation of a domain name as a C string.
855 	@param		outEnd			Gets set to point to the new end of the domain name if the append succeeded. (Optional)
856 */
857 OSStatus
858 	DomainNameFromString(
859 		uint8_t							outName[ STATIC_PARAM kDomainNameLengthMax ],
860 		const char *					inString,
861 		uint8_t * _Nullable * _Nullable	outEnd );
862 
863 //---------------------------------------------------------------------------------------------------------------------------
864 /*!	@brief		Gets the next label in a domain name label sequence.
865 
866 	@param		inLabel		Pointer to the current label.
867 
868 	@result		If the current label is a root label, returns NULL. Otherwise, returns the next label.
869 */
DomainNameGetNextLabel(const uint8_t * inLabel)870 STATIC_INLINE const uint8_t *	DomainNameGetNextLabel( const uint8_t *inLabel )
871 {
872 	const int len = *inLabel;
873 	return ( ( len == 0 ) ? NULL : &inLabel[ 1 + len ] );
874 }
875 
876 //---------------------------------------------------------------------------------------------------------------------------
877 /*!	@brief		Returns the length of a domain name.
878 
879 	@param		inName		The domain name in label format.
880 */
881 size_t	DomainNameLength( const uint8_t *inName );
882 
883 //---------------------------------------------------------------------------------------------------------------------------
884 /*!	@brief		Returns the number of labels that make up a domain name.
885 
886 	@param		inName		The uncompressed domain name in label format.
887 
888 	@result		Returns -1 if the domain name is malformed. Otherwise, returns the number of labels, not counting the root.
889 */
890 int	DomainNameLabelCount( const uint8_t *inName );
891 
892 //---------------------------------------------------------------------------------------------------------------------------
893 /*!	@brief		Converts a domain name in label format to its textual representation as a C string.
894 
895 	@param		inName		Pointer to the domain name.
896 	@param		inLimit		Pointer to not exceed while parsing a potentially truncated domain name. (Optional)
897 	@param		outString	Buffer to write the C string.
898 	@param		outPtr		Gets set to point to the end of the domain name. (Optional)
899 */
900 OSStatus
901 	DomainNameToString(
902 		const uint8_t *							inName,
903 		const uint8_t * _Nullable				inLimit,
904 		char									outString[ STATIC_PARAM kDNSServiceMaxDomainName ],
905 		const uint8_t * _Nullable * _Nullable	outPtr );
906 
907 //---------------------------------------------------------------------------------------------------------------------------
908 /*!	@brief		Compares two domain name labels for case-insensitive equality.
909 
910 	@param		inLabel1	Pointer to the first label.
911 	@param		inLabel2	Pointer to the second label.
912 
913 	@result		If the label are equal, returns true. Otherwise, returns false.
914 */
915 Boolean	DomainLabelEqual( const uint8_t *inLabel1, const uint8_t *inLabel2 );
916 
917 //---------------------------------------------------------------------------------------------------------------------------
918 /*!	@brief		For a resource record type's numeric value, returns the resource record type's mnemonic as a C string.
919 
920 	@param		inValue		A resource record type's numeric value.
921 
922 	@result		The resource record type's mnemonic as a C string if the numeric value is recognized, otherwise, NULL.
923 */
924 const char * _Nullable	DNSRecordTypeValueToString( int inValue );
925 
926 //---------------------------------------------------------------------------------------------------------------------------
927 /*!	@brief		For a resource record type's mnemonic, returns the resource record type's numeric value.
928 
929 	@param		inString	A resource record type's mnemonic as a C string.
930 
931 	@result		The resource record type's numeric value if the mnemonic is recognized, otherwise, 0.
932 */
933 uint16_t	DNSRecordTypeStringToValue( const char *inString );
934 
935 //---------------------------------------------------------------------------------------------------------------------------
936 /*!	@brief		For an RCODE value, returns the corresponding RCODE mnemonic as a C string.
937 
938 	@param		inValue		An RCODE value.
939 
940 	@result		The mnemonic as a C string if the RCODE value is recognized. Otherwise, NULL.
941 */
942 const char * _Nullable	DNSRCodeToString( int inValue );
943 
944 //---------------------------------------------------------------------------------------------------------------------------
945 /*!	@brief		For an RCODE mnemonic, returns the corresponding RCODE value.
946 
947 	@param		inString	An RCODE mnemonic as a C string.
948 
949 	@result		If the mnemonic is recognized, the corresponding RCODE value (between 0 and 15, inclusive). Otherwise, -1.
950 */
951 int	DNSRCodeFromString( const char * const inString );
952 
953 //---------------------------------------------------------------------------------------------------------------------------
954 /*!	@typedef	DNSMessageToStringFlags
955 
956 	@brief		Formatting options for DNSMessageToString().
957 */
958 typedef uint32_t		DNSMessageToStringFlags;
959 
960 #define kDNSMessageToStringFlag_Null		0
961 #define kDNSMessageToStringFlag_MDNS		( 1U << 0 ) // Treat the message as an mDNS message as opposed to DNS.
962 #define kDNSMessageToStringFlag_RawRData	( 1U << 1 ) // Print record data as a hex string, i.e., no formatting.
963 #define kDNSMessageToStringFlag_OneLine		( 1U << 2 ) // Format the string as a single line.
964 #define kDNSMessageToStringFlag_Privacy		( 1U << 3 ) // Obfuscate or redact items such as domain names and IP addresses.
965 #define kDNSMessageToStringFlag_HeaderOnly	( 1U << 4 ) // Limit printing to just the message header.
966 #define kDNSMessageToStringFlag_BodyOnly	( 1U << 5 ) // Limit printing to just the message body.
967 
968 #define kDNSMessageToStringFlags_None		kDNSMessageToStringFlag_Null
969 
970 //---------------------------------------------------------------------------------------------------------------------------
971 /*!	@brief		Creates a textual representation of a DNS message as a C string.
972 
973 	@param		inMsgPtr	Pointer to the beginning of the DNS message.
974 	@param		inMsgLen	Length of the DNS message.
975 	@param		inFlags		Flags that specify formatting options.
976 	@param		outString	Gets set to point to the dynamically allocated C string.
977 
978 	@discussion	The created string must be freed with free() when no longer needed.
979 */
980 OSStatus
981 	DNSMessageToString(
982 		const uint8_t *				inMsgPtr,
983 		size_t						inMsgLen,
984 		DNSMessageToStringFlags		inFlags,
985 		char * _Nullable * _Nonnull	outString );
986 
987 //---------------------------------------------------------------------------------------------------------------------------
988 /*!	@brief		Creates a textual representation of a DNS resource record's data as a C string.
989 
990 	@param		inRDataPtr		Pointer to the beginning of record data.
991 	@param		inRDataLen		Length of the record data.
992 	@param		inRecordType	The record's numeric type.
993 	@param		inMsgPtr		Pointer to the beginning of the DNS message containing the resource record. (Optional)
994 	@param		inMsgLen		Length of the DNS message containing the resource record.
995 	@param		inPrivacy		If true, sensitive items, such as domain names and IP addresses, are obfuscated or redacted.
996 	@param		outString		Gets set to point to the dynamically allocated C string.
997 
998 	@discussion	The created string must be freed with free() when no longer needed.
999 */
1000 OSStatus
1001 	DNSRecordDataToStringEx(
1002 		const void *					inRDataPtr,
1003 		size_t							inRDataLen,
1004 		int								inRecordType,
1005 		const void * _Nullable			inMsgPtr,
1006 		size_t							inMsgLen,
1007 		Boolean							inPrivacy,
1008 		char * _Nullable * _Nonnull		outString );
1009 
1010 #define DNSRecordDataToString(IN_RDATA_PTR, IN_RDATA_LEN, IN_RECORD_TYPE, OUT_STRING) \
1011 	DNSRecordDataToStringEx(IN_RDATA_PTR, IN_RDATA_LEN, IN_RECORD_TYPE, NULL, 0, false, OUT_STRING)
1012 
1013 //---------------------------------------------------------------------------------------------------------------------------
1014 /*!	@brief		Computes a DNSKEY record data's DNSSEC key tag.
1015 
1016 	@param		inRDataPtr		Pointer to the beginning of the DNSKEY record data.
1017 	@param		inRDataLen		Length of the DNSKEY record data.
1018 
1019 	@discussion	Uses calculation described by <https://tools.ietf.org/html/rfc4034#appendix-B>.
1020 */
1021 uint16_t	DNSComputeDNSKeyTag( const void *inRDataPtr, size_t inRDataLen );
1022 
1023 //---------------------------------------------------------------------------------------------------------------------------
1024 /*!	@brief		Writes an obfuscated version of a C string to a buffer as a C string.
1025 
1026 	@param		inBufPtr		Pointer to the beginning of the buffer to write the obfuscated version of the string.
1027 	@param		inBufLen		Length of the buffer.
1028 	@param		inString		The string to obfuscate.
1029 
1030 	@result
1031 		If the value returned is non-negative, then the value is the number of non-NUL characters that would have been
1032 		written if the size of the buffer were unlimited. If the value returned is negative, then the function failed.
1033 		In this case, the value returned is an error code.
1034 
1035 	@discussion
1036 		This function is useful for obfuscating domain name strings using the same type of obfuscation used by
1037 		DNSMessageToString().
1038 
1039 		If the returned value is non-negative, then, unless inBufLen is 0, the output string will be NUL-terminated.
1040 		If inBufLen is too small, then the end of the output string will be truncated. If inBufLen is not greater than
1041 		a non-negative return value, then the output string was truncated.
1042 */
1043 int	DNSMessagePrintObfuscatedString( char *inBufPtr, size_t inBufLen, const char *inString );
1044 
1045 //---------------------------------------------------------------------------------------------------------------------------
1046 /*!	@brief		Writes an obfuscated version of an IPv4 address to a buffer as a C string.
1047 
1048 	@param		inBufPtr		Pointer to the beginning of the buffer to write the obfuscated version of the string.
1049 	@param		inBufLen		Length of the buffer.
1050 	@param		inAddr			IPv4 address in host byte order.
1051 
1052 	@result
1053 		If the value returned is non-negative, then the value is the number of non-NUL characters that would have been
1054 		written if the size of the buffer were unlimited. If the value returned is negative, then the function failed.
1055 		In this case, the value returned is an error code.
1056 
1057 	@discussion
1058 		This function is useful for obfuscating an IPv4 addresses using the same type of obfuscation used by
1059 		DNSMessageToString().
1060 
1061 		If the returned value is non-negative, then, unless inBufLen is 0, the output string will be NUL-terminated.
1062 		If inBufLen is too small, then the end of the output string will be truncated. If inBufLen is not greater than
1063 		a non-negative return value, then the output string was truncated.
1064 */
1065 int	DNSMessagePrintObfuscatedIPv4Address( char *inBufPtr, size_t inBufLen, const uint32_t inAddr );
1066 
1067 //---------------------------------------------------------------------------------------------------------------------------
1068 /*!	@brief		Writes an obfuscated version of an IPv6 address to a buffer as a C string.
1069 
1070 	@param		inBufPtr		Pointer to the beginning of the buffer to write the obfuscated version of the string.
1071 	@param		inBufLen		Length of the buffer.
1072 	@param		inAddr			IPv6 address as an array of 16 bytes.
1073 
1074 	@result
1075 		If the value returned is non-negative, then the value is the number of non-NUL characters that would have been
1076 		written if the size of the buffer were unlimited. If the value returned is negative, then the function failed.
1077 		In this case, the value returned is an error code.
1078 
1079 	@discussion
1080 		This function is useful for obfuscating an IPv6 address using the same type of obfuscation used by
1081 		DNSMessageToString().
1082 
1083 		If the returned value is non-negative, then, unless inBufLen is 0, the output string will be NUL-terminated.
1084 		If inBufLen is too small, then the end of the output string will be truncated. If inBufLen is not greater than
1085 		a non-negative return value, then the output string was truncated.
1086 */
1087 int	DNSMessagePrintObfuscatedIPv6Address( char *inBufPtr, size_t inBufLen, const uint8_t inAddr[ STATIC_PARAM 16 ] );
1088 
1089 __END_DECLS
1090 
1091 CU_ASSUME_NONNULL_END
1092 
1093 #endif // __DNSMessage_h
1094