2 Copyright (c) 2016-2020 Apple Inc. All rights reserved.
8 #include <CoreUtils/CommonServices.h>
10 CU_ASSUME_NONNULL_BEGIN
14 //---------------------------------------------------------------------------------------------------------------------------
15 /*! @group DNS domain name size limits
17 @discussion See <https://tools.ietf.org/html/rfc1035#section-2.3.4>.
19 #define kDomainLabelLengthMax 63
20 #define kDomainNameLengthMax 256 // For compatibility with mDNS. See <https://tools.ietf.org/html/rfc6762#appendix-C>.
22 //---------------------------------------------------------------------------------------------------------------------------
23 /*! @group DNS message header
29 uint8_t questionCount
[ 2 ];
30 uint8_t answerCount
[ 2 ];
31 uint8_t authorityCount
[ 2 ];
32 uint8_t additionalCount
[ 2 ];
36 #define kDNSHeaderLength 12
37 check_compile_time( sizeof( DNSHeader
) == kDNSHeaderLength
);
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 )
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) )
53 // Single-bit DNS header fields
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)
64 // OPCODE (bits 14-11), Operation Code
66 #define DNSFlagsGetOpCode( FLAGS ) ( ( (FLAGS) >> 11 ) & 0x0FU )
67 #define DNSFlagsSetOpCode( FLAGS, OPCODE ) \
68 do { (FLAGS) = ( (FLAGS) & ~0x7800U ) | ( ( (OPCODE) & 0x0FU ) << 11 ); } while( 0 )
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
76 // RCODE (bits 3-0), Response Code
78 #define DNSFlagsGetRCode( FLAGS ) ( (FLAGS) & 0x0FU )
79 #define DNSFlagsSetRCode( FLAGS, RCODE ) \
80 do { (FLAGS) = ( (FLAGS) & ~0x000FU ) | ( ( (unsigned int)(RCODE) ) & 0x0FU ); } while( 0 )
82 //---------------------------------------------------------------------------------------------------------------------------
83 /*! @group Multicast DNS Constants
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>.
89 //---------------------------------------------------------------------------------------------------------------------------
90 /*! @group Misc. DNS message data structures
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 )
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 ) \
105 return _DNSMessageGet ## BIT_SIZE ( inFields->FIELD ); \
109 dns_ ## PREFIX ## _ ## TYPE ## _set_ ## FIELD ( \
110 dns_ ## PREFIX ## _ ## TYPE * inFields, \
111 uint ## BIT_SIZE ## _t inValue ) \
113 _DNSMessageSet ## BIT_SIZE ( inFields->FIELD, inValue ); \
115 check_compile_time( ( sizeof_field( dns_ ## PREFIX ## _ ## TYPE, FIELD ) * 8 ) == (BIT_SIZE) )
117 #define dns_fixed_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
118 dns_fields_define_accessors( fixed_fields, TYPE, FIELD, BIT_SIZE )
120 #define dns_dnskey_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
121 dns_fields_define_accessors( dnskey, TYPE, FIELD, BIT_SIZE )
123 #define dns_ds_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
124 dns_fields_define_accessors( ds, TYPE, FIELD, BIT_SIZE )
126 // DNS question fixed-length fields
127 // See <https://tools.ietf.org/html/rfc1035#section-4.1.2>
134 } dns_fixed_fields_question
;
136 check_compile_time( sizeof( dns_fixed_fields_question
) == 4 );
138 dns_fixed_fields_define_accessors( question
, type
, 16 );
139 dns_fixed_fields_define_accessors( question
, class, 16 );
142 dns_fixed_fields_question_init(
143 dns_fixed_fields_question
* inFields
,
147 dns_fixed_fields_question_set_type( inFields
, inQType
);
148 dns_fixed_fields_question_set_class( inFields
, inQClass
);
151 // DNS resource record fixed-length fields
152 // See <https://tools.ietf.org/html/rfc1035#section-4.1.3>
159 uint8_t rdlength
[ 2 ];
161 } dns_fixed_fields_record
;
163 check_compile_time( sizeof( dns_fixed_fields_record
) == 10 );
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 );
171 dns_fixed_fields_record_init(
172 dns_fixed_fields_record
* inFields
,
176 uint16_t inRDLength
)
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
);
184 // DNS SRV record data fixed-length fields
185 // See <https://tools.ietf.org/html/rfc2782>
189 uint8_t priority
[ 2 ];
193 } dns_fixed_fields_srv
;
195 check_compile_time( sizeof( dns_fixed_fields_srv
) == 6 );
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 );
202 dns_fixed_fields_srv_init(
203 dns_fixed_fields_srv
* inFields
,
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
);
213 // DNS SOA record data fixed-length fields
214 // See <https://tools.ietf.org/html/rfc1035#section-3.3.13>
219 uint8_t refresh
[ 4 ];
222 uint8_t minimum
[ 4 ];
224 } dns_fixed_fields_soa
;
226 check_compile_time( sizeof( dns_fixed_fields_soa
) == 20 );
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 );
235 dns_fixed_fields_soa_init(
236 dns_fixed_fields_soa
* inFields
,
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
);
250 // OPT pseudo-resource record fixed-length fields without RDATA
251 // See <https://tools.ietf.org/html/rfc6891#section-6.1.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 ];
263 } dns_fixed_fields_opt
;
265 check_compile_time( sizeof( dns_fixed_fields_opt
) == 11 );
267 #define kDNSExtendedFlag_DNSSECOK ( 1U << 15 ) // <https://tools.ietf.org/html/rfc3225#section-3>
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 );
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>
284 uint8_t udp_payload_size
[ 2 ];
285 uint8_t extended_rcode
[ 1 ];
286 uint8_t version
[ 1 ];
287 uint8_t extended_flags
[ 2 ];
289 uint8_t option_code
[ 2 ];
290 uint8_t option_length
[ 2 ];
292 } dns_fixed_fields_opt1
;
294 check_compile_time( sizeof( dns_fixed_fields_opt1
) == 15 );
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 );
306 // OPT pseudo-resource record RDATA option fixed-length fields
307 // See <https://tools.ietf.org/html/rfc6891#section-6.1.2>
314 } dns_fixed_fields_option
;
316 check_compile_time( sizeof( dns_fixed_fields_option
) == 4 );
318 dns_fixed_fields_define_accessors( option
, code
, 16 );
319 dns_fixed_fields_define_accessors( option
, length
, 16 );
321 // DNS DNSKEY record data fixed-length fields
322 // See <https://tools.ietf.org/html/rfc4034#section-2.1>
327 uint8_t protocol
[ 1 ];
328 uint8_t algorithm
[ 1 ];
330 } dns_fixed_fields_dnskey
;
332 check_compile_time( sizeof( dns_fixed_fields_dnskey
) == 4 );
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 );
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>
341 #define kDNSKeyProtocol_DNSSEC 3 // Protocol value must be 3. <https://tools.ietf.org/html/rfc4034#section-2.1.2>
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>
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
353 // DNS RRSIG record data fixed-length fields
354 // See <https://tools.ietf.org/html/rfc4034#section-3.1>
358 uint8_t type_covered
[ 2 ];
359 uint8_t algorithm
[ 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 ];
366 } dns_fixed_fields_rrsig
;
368 check_compile_time( sizeof( dns_fixed_fields_rrsig
) == 18 );
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 );
378 // DNS DS record data fixed-length fields
379 // See <https://tools.ietf.org/html/rfc4034#section-5.1>
383 uint8_t key_tag
[ 2 ];
384 uint8_t algorithm
[ 1 ];
385 uint8_t digest_type
[ 1 ];
387 } dns_fixed_fields_ds
;
389 check_compile_time( sizeof( dns_fixed_fields_ds
) == 4 );
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 );
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>
398 // DNS DS record data
399 // See <https://tools.ietf.org/html/rfc4509#section-2.2>
403 uint8_t key_tag
[ 2 ];
404 uint8_t algorithm
[ 1 ];
405 uint8_t digest_type
[ 1 ];
406 uint8_t digest
[ 32 ];
410 check_compile_time( sizeof( dns_ds_sha256
) == 36 );
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 );
416 // DNS NSEC3 record data fixed-length fields
417 // See <https://tools.ietf.org/html/rfc5155#section-3.2>
421 uint8_t hash_alg
[ 1 ];
423 uint8_t iterations
[ 2 ];
425 } dns_fixed_fields_nsec3
;
427 check_compile_time( sizeof( dns_fixed_fields_nsec3
) == 4 );
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 );
433 // DNS SVCB record data fixed-length fields
434 // See <https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-00#section-2.2>
438 uint8_t priority
[ 2 ];
440 } dns_fixed_fields_svcb
;
442 check_compile_time( sizeof( dns_fixed_fields_svcb
) == 2 );
444 dns_fixed_fields_define_accessors( svcb
, priority
, 16 );
449 uint8_t value_length
[ 2 ];
451 } dns_fixed_fields_svcb_param
;
453 check_compile_time( sizeof( dns_fixed_fields_svcb_param
) == 4 );
455 dns_fixed_fields_define_accessors( svcb_param
, key
, 16 );
456 dns_fixed_fields_define_accessors( svcb_param
, value_length
, 16 );
458 //---------------------------------------------------------------------------------------------------------------------------
459 /*! @group DNS record types
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
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,
560 //---------------------------------------------------------------------------------------------------------------------------
561 /*! @group DNS RCODEs
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
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
583 //---------------------------------------------------------------------------------------------------------------------------
584 /*! @group DNS classes
589 kDNSClassType_IN
= 1 // See <https://tools.ietf.org/html/rfc1035#section-3.2.4>.
593 //---------------------------------------------------------------------------------------------------------------------------
594 /*! @group DNS EDNS0 Option Codes
598 kDNSEDNS0OptionCode_Padding
= 12 // <https://tools.ietf.org/html/rfc7830#section-3>
600 } DNSEDNS0OptionCode
;
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>.
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
619 //---------------------------------------------------------------------------------------------------------------------------
620 /*! @brief Extracts a domain name from a DNS message.
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)
629 DNSMessageExtractDomainName(
630 const uint8_t * inMsgPtr
,
632 const uint8_t * inPtr
,
633 uint8_t outName
[ _Nullable kDomainNameLengthMax
],
634 const uint8_t * _Nullable
* _Nullable outPtr
);
636 //---------------------------------------------------------------------------------------------------------------------------
637 /*! @brief Extracts a domain name from a DNS message as a C string.
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)
646 DNSMessageExtractDomainNameString(
647 const void * inMsgPtr
,
650 char outName
[ _Nullable kDNSServiceMaxDomainName
],
651 const uint8_t * _Nullable
* _Nullable outPtr
);
653 //---------------------------------------------------------------------------------------------------------------------------
654 /*! @brief Extracts a question from a DNS message.
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)
665 DNSMessageExtractQuestion(
666 const uint8_t * inMsgPtr
,
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
);
674 //---------------------------------------------------------------------------------------------------------------------------
675 /*! @brief Extracts a resource record from a DNS message.
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)
689 DNSMessageExtractRecord(
690 const uint8_t * inMsgPtr
,
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
);
701 //---------------------------------------------------------------------------------------------------------------------------
702 /*! @brief Gets a DNS message's answer section, i.e., the end of the message's question section.
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)
709 DNSMessageGetAnswerSection(
710 const uint8_t * inMsgPtr
,
712 const uint8_t * _Nullable
* _Nullable outPtr
);
714 //---------------------------------------------------------------------------------------------------------------------------
715 /*! @brief Gets a DNS message's OPT record if it exists.
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)
723 DNSMessageGetOptRecord(
724 const uint8_t * inMsgPtr
,
726 const uint8_t * _Nullable
* _Nullable outOptPtr
,
727 size_t * _Nullable outOptLen
);
729 //---------------------------------------------------------------------------------------------------------------------------
730 /*! @brief Writes a DNS message compression label pointer.
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.
735 @discussion See <https://tools.ietf.org/html/rfc1035#section-4.1.4>.
737 STATIC_INLINE
void DNSMessageWriteLabelPointer( uint8_t inLabelPtr
[ STATIC_PARAM
2 ], size_t inOffset
)
739 inLabelPtr
[ 0 ] = (uint8_t)( ( ( inOffset
>> 8 ) & 0x3F ) | 0xC0 );
740 inLabelPtr
[ 1 ] = (uint8_t)( inOffset
& 0xFF );
743 #define kDNSCompressionOffsetMax 0x3FFF
744 #define kDNSCompressionPointerLength 2
746 //---------------------------------------------------------------------------------------------------------------------------
747 #define kDNSQueryMessageMaxLen ( kDNSHeaderLength + kDomainNameLengthMax + sizeof( dns_fixed_fields_question ) )
749 /*! @brief Writes a single-question DNS query message.
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.
760 DNSMessageWriteQuery(
763 const uint8_t * inQName
,
766 uint8_t outMsg
[ STATIC_PARAM kDNSQueryMessageMaxLen
],
769 //---------------------------------------------------------------------------------------------------------------------------
770 /*! @brief Creates a collapsed version of a DNS message.
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.
777 @result A dynamically allocated collapsed version of the DNS message.
779 @discussion This function creates a copy of a DNS message, except that
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.
785 Note: Collapsing a DNS message is a non-standard operation and should be used with caution.
789 const uint8_t * inMsgPtr
,
791 size_t * _Nullable outMsgLen
,
792 OSStatus
* _Nullable outError
);
794 //---------------------------------------------------------------------------------------------------------------------------
795 /*! @brief Appends one domain name to another.
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)
802 DomainNameAppendDomainName(
803 uint8_t inName
[ STATIC_PARAM kDomainNameLengthMax
],
804 const uint8_t * inOtherName
,
805 uint8_t * _Nullable
* _Nullable outEnd
);
807 //---------------------------------------------------------------------------------------------------------------------------
808 /*! @brief Appends a C string representing a textual sequence of labels to a domain name.
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)
815 DomainNameAppendString(
816 uint8_t inName
[ STATIC_PARAM kDomainNameLengthMax
],
817 const char * inString
,
818 uint8_t * _Nullable
* _Nullable outEnd
);
820 //---------------------------------------------------------------------------------------------------------------------------
821 /*! @brief Creates a duplicate domain name.
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)
828 @discussion The duplicate domain name must be freed with free() when no longer needed.
832 const uint8_t * inName
,
834 uint8_t * _Nullable
* _Nonnull outNamePtr
,
835 size_t * _Nullable outNameLen
);
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 )
840 //---------------------------------------------------------------------------------------------------------------------------
841 /*! @brief Compares two domain names in label format for case-insensitive equality.
843 @param inName1 Pointer to the first domain name.
844 @param inName2 Pointer to the second domain name.
846 @result If the domain names are equal, returns true, otherwise, returns false.
848 Boolean
DomainNameEqual( const uint8_t *inName1
, const uint8_t *inName2
);
850 //---------------------------------------------------------------------------------------------------------------------------
851 /*! @brief Converts a domain name's textual representation to a domain name in label format.
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)
858 DomainNameFromString(
859 uint8_t outName
[ STATIC_PARAM kDomainNameLengthMax
],
860 const char * inString
,
861 uint8_t * _Nullable
* _Nullable outEnd
);
863 //---------------------------------------------------------------------------------------------------------------------------
864 /*! @brief Gets the next label in a domain name label sequence.
866 @param inLabel Pointer to the current label.
868 @result If the current label is a root label, returns NULL. Otherwise, returns the next label.
870 STATIC_INLINE
const uint8_t * DomainNameGetNextLabel( const uint8_t *inLabel
)
872 const int len
= *inLabel
;
873 return ( ( len
== 0 ) ? NULL
: &inLabel
[ 1 + len
] );
876 //---------------------------------------------------------------------------------------------------------------------------
877 /*! @brief Returns the length of a domain name.
879 @param inName The domain name in label format.
881 size_t DomainNameLength( const uint8_t *inName
);
883 //---------------------------------------------------------------------------------------------------------------------------
884 /*! @brief Returns the number of labels that make up a domain name.
886 @param inName The uncompressed domain name in label format.
888 @result Returns -1 if the domain name is malformed. Otherwise, returns the number of labels, not counting the root.
890 int DomainNameLabelCount( const uint8_t *inName
);
892 //---------------------------------------------------------------------------------------------------------------------------
893 /*! @brief Converts a domain name in label format to its textual representation as a C string.
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)
902 const uint8_t * inName
,
903 const uint8_t * _Nullable inLimit
,
904 char outString
[ STATIC_PARAM kDNSServiceMaxDomainName
],
905 const uint8_t * _Nullable
* _Nullable outPtr
);
907 //---------------------------------------------------------------------------------------------------------------------------
908 /*! @brief Compares two domain name labels for case-insensitive equality.
910 @param inLabel1 Pointer to the first label.
911 @param inLabel2 Pointer to the second label.
913 @result If the label are equal, returns true. Otherwise, returns false.
915 Boolean
DomainLabelEqual( const uint8_t *inLabel1
, const uint8_t *inLabel2
);
917 //---------------------------------------------------------------------------------------------------------------------------
918 /*! @brief For a resource record type's numeric value, returns the resource record type's mnemonic as a C string.
920 @param inValue A resource record type's numeric value.
922 @result The resource record type's mnemonic as a C string if the numeric value is recognized, otherwise, NULL.
924 const char * _Nullable
DNSRecordTypeValueToString( int inValue
);
926 //---------------------------------------------------------------------------------------------------------------------------
927 /*! @brief For a resource record type's mnemonic, returns the resource record type's numeric value.
929 @param inString A resource record type's mnemonic as a C string.
931 @result The resource record type's numeric value if the mnemonic is recognized, otherwise, 0.
933 uint16_t DNSRecordTypeStringToValue( const char *inString
);
935 //---------------------------------------------------------------------------------------------------------------------------
936 /*! @brief For an RCODE value, returns the corresponding RCODE mnemonic as a C string.
938 @param inValue An RCODE value.
940 @result The mnemonic as a C string if the RCODE value is recognized. Otherwise, NULL.
942 const char * _Nullable
DNSRCodeToString( int inValue
);
944 //---------------------------------------------------------------------------------------------------------------------------
945 /*! @brief For an RCODE mnemonic, returns the corresponding RCODE value.
947 @param inString An RCODE mnemonic as a C string.
949 @result If the mnemonic is recognized, the corresponding RCODE value (between 0 and 15, inclusive). Otherwise, -1.
951 int DNSRCodeFromString( const char * const inString
);
953 //---------------------------------------------------------------------------------------------------------------------------
954 /*! @typedef DNSMessageToStringFlags
956 @brief Formatting options for DNSMessageToString().
958 typedef uint32_t DNSMessageToStringFlags
;
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.
968 #define kDNSMessageToStringFlags_None kDNSMessageToStringFlag_Null
970 //---------------------------------------------------------------------------------------------------------------------------
971 /*! @brief Creates a textual representation of a DNS message as a C string.
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.
978 @discussion The created string must be freed with free() when no longer needed.
982 const uint8_t * inMsgPtr
,
984 DNSMessageToStringFlags inFlags
,
985 char * _Nullable
* _Nonnull outString
);
987 //---------------------------------------------------------------------------------------------------------------------------
988 /*! @brief Creates a textual representation of a DNS resource record's data as a C string.
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.
998 @discussion The created string must be freed with free() when no longer needed.
1001 DNSRecordDataToStringEx(
1002 const void * inRDataPtr
,
1005 const void * _Nullable inMsgPtr
,
1008 char * _Nullable
* _Nonnull outString
);
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)
1013 //---------------------------------------------------------------------------------------------------------------------------
1014 /*! @brief Computes a DNSKEY record data's DNSSEC key tag.
1016 @param inRDataPtr Pointer to the beginning of the DNSKEY record data.
1017 @param inRDataLen Length of the DNSKEY record data.
1019 @discussion Uses calculation described by <https://tools.ietf.org/html/rfc4034#appendix-B>.
1021 uint16_t DNSComputeDNSKeyTag( const void *inRDataPtr
, size_t inRDataLen
);
1023 //---------------------------------------------------------------------------------------------------------------------------
1024 /*! @brief Writes an obfuscated version of a C string to a buffer as a C string.
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.
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.
1036 This function is useful for obfuscating domain name strings using the same type of obfuscation used by
1037 DNSMessageToString().
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.
1043 int DNSMessagePrintObfuscatedString( char *inBufPtr
, size_t inBufLen
, const char *inString
);
1045 //---------------------------------------------------------------------------------------------------------------------------
1046 /*! @brief Writes an obfuscated version of an IPv4 address to a buffer as a C string.
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.
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.
1058 This function is useful for obfuscating an IPv4 addresses using the same type of obfuscation used by
1059 DNSMessageToString().
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.
1065 int DNSMessagePrintObfuscatedIPv4Address( char *inBufPtr
, size_t inBufLen
, const uint32_t inAddr
);
1067 //---------------------------------------------------------------------------------------------------------------------------
1068 /*! @brief Writes an obfuscated version of an IPv6 address to a buffer as a C string.
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.
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.
1080 This function is useful for obfuscating an IPv6 address using the same type of obfuscation used by
1081 DNSMessageToString().
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.
1087 int DNSMessagePrintObfuscatedIPv6Address( char *inBufPtr
, size_t inBufLen
, const uint8_t inAddr
[ STATIC_PARAM
16 ] );
1091 CU_ASSUME_NONNULL_END
1093 #endif // __DNSMessage_h