1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2024 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #ifndef __DNSCOMMON_H_ 19 #define __DNSCOMMON_H_ 20 21 #include "mDNSEmbeddedAPI.h" 22 23 // For gettimeofday 24 #if !defined(_WIN32) 25 #include <sys/time.h> 26 #else 27 #include "PosixCompat.h" 28 #endif 29 30 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 31 #include "dnssec_mdns_core.h" 32 #endif 33 34 #ifdef __cplusplus 35 extern "C" { 36 #endif 37 38 //************************************************************************************************************* 39 // Macros 40 41 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion 42 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" 43 // To expand "version" to its value before making the string, use STRINGIFY(version) instead 44 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s 45 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) 46 47 #define ReadField16(PTR) ((mDNSu16)((((mDNSu16)((const mDNSu8 *)(PTR))[0]) << 8) | ((mDNSu16)((const mDNSu8 *)(PTR))[1]))) 48 #define ReadField32(PTR) \ 49 ((mDNSu32)( \ 50 (((mDNSu32)((const mDNSu8 *)(PTR))[0]) << 24) | \ 51 (((mDNSu32)((const mDNSu8 *)(PTR))[1]) << 16) | \ 52 (((mDNSu32)((const mDNSu8 *)(PTR))[2]) << 8) | \ 53 ((mDNSu32)((const mDNSu8 *)(PTR))[3]))) 54 55 #ifdef UINT64_MAX 56 57 #define ReadField64(PTR) \ 58 ((uint64_t)( \ 59 (((uint64_t)((const mDNSu8 *)(PTR))[0]) << 56) | \ 60 (((uint64_t)((const mDNSu8 *)(PTR))[1]) << 48) | \ 61 (((uint64_t)((const mDNSu8 *)(PTR))[2]) << 40) | \ 62 (((uint64_t)((const mDNSu8 *)(PTR))[3]) << 32) | \ 63 (((uint64_t)((const mDNSu8 *)(PTR))[4]) << 24) | \ 64 (((uint64_t)((const mDNSu8 *)(PTR))[5]) << 16) | \ 65 (((uint64_t)((const mDNSu8 *)(PTR))[6]) << 8) | \ 66 ((uint64_t)((const mDNSu8 *)(PTR))[7]))) 67 68 #endif 69 70 // *************************************************************************** 71 // MARK: - DNS Protocol Constants 72 73 typedef enum 74 { 75 kDNSFlag0_QR_Mask = 0x80, // Query or response? 76 kDNSFlag0_QR_Query = 0x00, 77 kDNSFlag0_QR_Response = 0x80, 78 79 kDNSFlag0_OP_Mask = 0xF << 3, // Operation type 80 kDNSFlag0_OP_StdQuery = 0x0 << 3, 81 kDNSFlag0_OP_Iquery = 0x1 << 3, 82 kDNSFlag0_OP_Status = 0x2 << 3, 83 kDNSFlag0_OP_Unused3 = 0x3 << 3, 84 kDNSFlag0_OP_Notify = 0x4 << 3, 85 kDNSFlag0_OP_Update = 0x5 << 3, 86 kDNSFlag0_OP_DSO = 0x6 << 3, 87 88 kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask, 89 90 kDNSFlag0_AA = 0x04, // Authoritative Answer? 91 kDNSFlag0_TC = 0x02, // Truncated? 92 kDNSFlag0_RD = 0x01, // Recursion Desired? 93 kDNSFlag1_RA = 0x80, // Recursion Available? 94 95 kDNSFlag1_Zero = 0x40, // Reserved; must be zero 96 kDNSFlag1_AD = 0x20, // Authentic Data [RFC 2535] 97 kDNSFlag1_CD = 0x10, // Checking Disabled [RFC 2535] 98 99 kDNSFlag1_RC_Mask = 0x0F, // Response code 100 kDNSFlag1_RC_NoErr = 0x00, 101 kDNSFlag1_RC_FormErr = 0x01, 102 kDNSFlag1_RC_ServFail = 0x02, 103 kDNSFlag1_RC_NXDomain = 0x03, 104 kDNSFlag1_RC_NotImpl = 0x04, 105 kDNSFlag1_RC_Refused = 0x05, 106 kDNSFlag1_RC_YXDomain = 0x06, 107 kDNSFlag1_RC_YXRRSet = 0x07, 108 kDNSFlag1_RC_NXRRSet = 0x08, 109 kDNSFlag1_RC_NotAuth = 0x09, 110 kDNSFlag1_RC_NotZone = 0x0A, 111 kDNSFlag1_RC_DSOTypeNI = 0x0B 112 } DNS_Flags; 113 114 typedef enum 115 { 116 TSIG_ErrBadSig = 16, 117 TSIG_ErrBadKey = 17, 118 TSIG_ErrBadTime = 18 119 } TSIG_ErrorCode; 120 121 122 // *************************************************************************** 123 // MARK: - General Utility Functions 124 125 extern NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf); 126 extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf); 127 128 extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from zero to max inclusive 129 130 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 131 extern mDNSu32 mDNS_GetNextResolverGroupID(void); 132 #endif 133 134 MDNS_CLOSED_ENUM(mDNSNonCryptoHash, mDNSu8, 135 mDNSNonCryptoHash_FNV1a = 0, 136 mDNSNonCryptoHash_SDBM = 1, 137 ); 138 139 /*! 140 * @brief 141 * Calculate hash given previous calculated hash and new bytes, with given hash algorithm. 142 * 143 * @param algorithm 144 * The hash algorithm to use. 145 * 146 * @param previousHash 147 * The hash of previous bytes that has been calculated. 148 * 149 * @param bytes 150 * Bytes to update the hash. 151 * 152 * @param len 153 * The length of the bytes. 154 * 155 * @result 156 * The hash value of (previous bytes + new bytes). 157 */ 158 extern mDNSu32 mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash algorithm, mDNSu32 previousHash, const mDNSu8 *bytes, 159 mDNSu32 len); 160 161 /*! 162 * @brief 163 * Calculate hash of the bytes. 164 * 165 * @param algorithm 166 * The hash algorithm to use. 167 * 168 * @param bytes 169 * Bytes to calculate the hash. 170 * 171 * @param len 172 * The length of the bytes. 173 * 174 * @result 175 * The hash value. 176 */ 177 extern mDNSu32 mDNS_NonCryptoHash(mDNSNonCryptoHash algorithm, const mDNSu8 *bytes, mDNSu32 len); 178 179 /*! 180 * @brief 181 * Computes the 32-bit FNV-1a (non-cryptographic) hash value for an domain name. 182 * 183 * @param name 184 * The domain name. 185 * 186 * @result 187 * The hash value. 188 * 189 * @discussion 190 * Since domain name is case-insensitive, to make sure that hash values still match when the case changes, 191 * the hash value is calculated with the normalized domain name by treating uppercase ASCII letters to their 192 * lowercase counterparts. 193 * 194 * For more information about FNV Non-Cryptographic Hash , 195 * see <https://datatracker.ietf.org/doc/html/draft-eastlake-fnv-21>. 196 */ 197 extern mDNSu32 mDNS_DomainNameFNV1aHash(const domainname *name); 198 199 extern mDNSs32 mDNSGetTimeOfDay(struct timeval *tv, struct timezone *tz); 200 201 // *************************************************************************** 202 // MARK: - Domain Name Utility Functions 203 204 #define mDNSSubTypeLabel "\x04_sub" 205 206 #define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9') 207 #define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z') 208 #define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z') 209 #define mDNSIsLetter(X) (mDNSIsUpperCase(X) || mDNSIsLowerCase(X)) 210 #define mDNSIsPrintASCII(X) (((X) >= 32) && ((X) <= 126)) 211 212 /*! 213 * @brief 214 * Convert ASCII uppercase character to its lowercase counterparts. 215 * 216 * @param c 217 * The ASCII character. 218 * 219 * @result 220 * The lowercase value of the character, if the original one is uppercase, otherwise, the original value. 221 */ 222 static inline int 223 mDNSASCIITolower(const int c) 224 { 225 if (mDNSIsUpperCase(c)) 226 { 227 return (c + ('a' - 'A')); 228 } 229 else 230 { 231 return c; 232 } 233 } 234 235 /*! 236 * @brief 237 * Check if the string consists of all valid UTF-8 characters. 238 * 239 * @param str 240 * The string ending with NULL. 241 * 242 * @result 243 * True if the string consists of valid UTF-8 characters, otherwise, false. 244 */ 245 extern mDNSBool mDNSAreUTF8String(const char *str); 246 247 // We believe we have adequate safeguards to protect against cache poisoning. 248 // In the event that someone does find a workable cache poisoning attack, we want to limit the lifetime of the poisoned entry. 249 // We set the maximum allowable TTL to one hour. 250 // With the 25% correction factor to avoid the DNS Zeno's paradox bug, that gives us an actual maximum lifetime of 75 minutes. 251 252 #define mDNSMaximumMulticastTTLSeconds (mDNSu32)4500 253 #define mDNSMaximumUnicastTTLSeconds (mDNSu32)3600 254 255 // Adjustment factor to avoid race condition (used for unicast cache entries) : 256 // Suppose real record has TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100. 257 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another 258 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox. 259 // To avoid this, we extend the record's effective TTL to give it a little extra grace period. 260 // We adjust the 100 second TTL to 127. This means that when we do our 80% query after 102 seconds, 261 // the cached copy at our local caching server will already have expired, so the server will be forced 262 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds. 263 264 #define RRAdjustTTL(ttl) ((ttl) + ((ttl)/4) + 2) 265 #define RRUnadjustedTTL(ttl) ((((ttl) - 2) * 4) / 5) 266 267 typedef enum 268 { 269 uDNS_LLQ_Not = 0, // Normal uDNS answer: Flush any stale records from cache, and respect record TTL 270 uDNS_LLQ_Ignore, // LLQ initial challenge packet: ignore -- has no useful records for us 271 uDNS_LLQ_Entire, // LLQ initial set of answers: Flush any stale records from cache, but assume TTL is 2 x LLQ refresh interval 272 uDNS_LLQ_Events // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval 273 } uDNS_LLQType; 274 275 extern mDNSu32 GetEffectiveTTL(uDNS_LLQType LLQType, mDNSu32 ttl); 276 277 #define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') ) 278 279 extern mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent); 280 extern int CountLabels(const domainname *d); 281 extern const domainname *SkipLeadingLabels(const domainname *d, int skip); 282 283 extern mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max); 284 extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText); 285 extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText); 286 extern void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText); 287 #define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME) 288 289 extern mDNSBool IsSubdomain(const domainname *const subdomain, const domainname *const domain); 290 291 // *************************************************************************** 292 // MARK: - Resource Record Utility Functions 293 294 // IdenticalResourceRecord returns true if two resources records have 295 // the same name, type, class, and identical rdata (InterfaceID and TTL may differ) 296 297 // IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check, 298 // which is at its most expensive and least useful in cases where we know in advance that the names match 299 300 // Note: The dominant use of IdenticalResourceRecord is from ProcessQuery(), handling known-answer lists. In this case 301 // it's common to have a whole bunch or records with exactly the same name (e.g. "_http._tcp.local") but different RDATA. 302 // The SameDomainName() check is expensive when the names match, and in this case *all* the names match, so we 303 // used to waste a lot of CPU time verifying that the names match, only then to find that the RDATA is different. 304 // We observed mDNSResponder spending 30% of its total CPU time on this single task alone. 305 // By swapping the checks so that we check the RDATA first, we can quickly detect when it's different 306 // (99% of the time) and then bail out before we waste time on the expensive SameDomainName() check. 307 308 extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename); 309 310 static inline mDNSBool IdenticalSameNameRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) 311 { 312 return 313 ( 314 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 315 // Other than the ordinary non-DNSSEC records, there are two types of DNSSEC records: 316 // 1. DNSSEC to be validated: Records that come from DNSSEC-enabled response (with DNSSEC OK/Checking Disabled bits set). 317 // 2. DNSSEC validated: Records that come from the "DNSSEC to be validated" records, and has passed the DNSSEC validation. 318 // Only the records that have the same type can be compared. 319 (resource_records_have_same_dnssec_rr_category(r1, r2)) && 320 #endif 321 r1->rrtype == r2->rrtype && 322 r1->rrclass == r2->rrclass && 323 r1->rdlength == r2->rdlength && 324 r1->rdatahash == r2->rdatahash && 325 SameRDataBody(r1, &r2->rdata->u, SameDomainName) 326 ); 327 } 328 329 static inline mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) 330 { 331 return 332 ( 333 r1->namehash == r2->namehash && 334 IdenticalSameNameRecord(r1, r2) && 335 SameDomainName(r1->name, r2->name) 336 ); 337 } 338 339 // A given RRType answers a QuestionType if RRType is CNAME, or types match, or QuestionType is ANY, 340 // or the RRType is NSEC and positively asserts the nonexistence of the type being requested from multicast, 341 // or the question requires the corresponding DNSSEC RRs, 342 // or the RRType is RRSIG that covers the the type being requested. 343 344 typedef mDNSu32 RRTypeAnswersQuestionTypeFlags; 345 #define kRRTypeAnswersQuestionTypeFlagsNone 0 346 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 347 #define kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate (1U << 0) // Use this flag to indicate that question needs "DNSSEC to be validated" records to do validation. 348 #define kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRValidated (1U << 1) // Use this flag to indicate that question needs "DNSSEC validated" records to return to the client. 349 #endif 350 extern mDNSBool RRTypeAnswersQuestionType(const ResourceRecord *rr, mDNSu16 qtype, RRTypeAnswersQuestionTypeFlags flags); 351 352 // Unicast NSEC records have the NSEC bit set whereas the multicast NSEC ones don't 353 #define UNICAST_NSEC(rr) ((rr)->rrtype == kDNSType_NSEC && RRAssertsExistence((rr), kDNSType_NSEC)) 354 #define MULTICAST_NSEC(rr) ((rr)->rrtype == kDNSType_NSEC && RRAssertsNonexistence((rr), kDNSType_NSEC)) 355 356 extern mDNSu32 RDataHashValue(const ResourceRecord *const rr); 357 extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename); 358 extern mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q); 359 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); 360 extern mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q); 361 extern mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q); 362 extern mDNSBool AnyTypeRecordAnswersQuestion (const AuthRecord *const ar, const DNSQuestion *const q); 363 extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q); 364 extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q); 365 extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate); 366 extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd); 367 extern mStatus DNSNameToLowerCase(domainname *d, domainname *result); 368 369 /*! 370 * @brief 371 * Gets a pointer to a resource record's record data in wire format. 372 * 373 * @param rr 374 * The resource record object. 375 * 376 * @param bytesBuffer 377 * The buffer to be used as a temporary space to hold a resource record's record data in wire format if no 378 * existing wire-format rdata is available. 379 * 380 * @param bufferSize 381 * The size of the buffer. 382 * 383 * @param outRDataLen 384 * If non-NULL, the address of a variable to set to the length of the resource record's record data in 385 * wire format. 386 * 387 * @param outError 388 * If non-NULL, the address of a variable to set to either a non-zero error code if this function fails, or 389 * `mStatus_NoError` if this function succeeds. 390 * 391 * @result 392 * The pointer to the resource record's record data in wire format if no error occurs. Otherwise mDNSNULL 393 * and `outError` is set to a non-zero error code. 394 */ 395 extern const mDNSu8 * ResourceRecordGetRDataBytesPointer(const ResourceRecord *rr, mDNSu8 *bytesBuffer, 396 mDNSu16 bufferSize, mDNSu16 *outRDataLen, mStatus *outError); 397 398 #define GetRRDomainNameTarget(RR) ( \ 399 ((RR)->rrtype == kDNSType_NS || (RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_DNAME) ? &(RR)->rdata->u.name : \ 400 ((RR)->rrtype == kDNSType_MX || (RR)->rrtype == kDNSType_AFSDB || (RR)->rrtype == kDNSType_RT || (RR)->rrtype == kDNSType_KX ) ? &(RR)->rdata->u.mx.exchange : \ 401 ((RR)->rrtype == kDNSType_SRV ) ? &(RR)->rdata->u.srv.target : mDNSNULL ) 402 403 #define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique) 404 405 // *************************************************************************** 406 // MARK: - DNS Message Creation Functions 407 408 extern void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags); 409 extern const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname); 410 extern mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name); 411 extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr); 412 413 // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes, 414 // but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet 415 416 #define AllowedRRSpace(msg) (((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) 417 418 extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, const ResourceRecord *rr, 419 mDNSu32 ttl, const mDNSu8 *limit); 420 421 #define PutResourceRecordTTL(msg, ptr, count, rr, ttl) \ 422 PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AllowedRRSpace(msg)) 423 424 #define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) \ 425 PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData) 426 427 #define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl) 428 429 // Calculate TSR only OPT space 430 // Assume local variable 'tsrOptsCount' 431 #define TSR_OPT_SPACE (tsrOptsCount * DNSOpt_TSRData_Space) 432 #define TSR_OPT_HEADER_SPACE (tsrOptsCount ? DNSOpt_Header_Space : 0) 433 #define TSR_OPT_TOTAL_SPACE (TSR_OPT_SPACE + TSR_OPT_HEADER_SPACE) 434 435 #define PutResourceRecordTSR(msg, ptr, count, rr) \ 436 PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (rr)->rroriginalttl, (msg)->data + AllowedRRSpace(msg) - TSR_OPT_TOTAL_SPACE) 437 438 // Calculate OPT space 439 // Assume local variables 'OwnerRecordSpace', 'TraceRecordSpace' & 'tsrOptsCount' 440 #define RR_OPT_SPACE \ 441 (OwnerRecordSpace + TraceRecordSpace + TSR_OPT_SPACE + \ 442 ((OwnerRecordSpace || TraceRecordSpace) ? 0 : TSR_OPT_HEADER_SPACE)) 443 444 // The PutRR_OS variants assume a local variable 'm', put build the packet at m->omsg, 445 #define PutRR_OS_TTL(ptr, count, rr, ttl) \ 446 PutResourceRecordTTLWithLimit(&m->omsg, (ptr), (count), (rr), (ttl), m->omsg.data + AllowedRRSpace(&m->omsg) - RR_OPT_SPACE) 447 448 #define PutRR_OS(P, C, RR) PutRR_OS_TTL((P), (C), (RR), (RR)->rroriginalttl) 449 450 extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass); 451 extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass); 452 extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end); 453 extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr); 454 extern mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit); 455 extern mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit); 456 extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name); 457 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease); 458 extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit); 459 460 extern int baseEncode(char *buffer, int blen, const mDNSu8 *data, int len, int encAlg); 461 extern void NSEC3Parse(const ResourceRecord *const rr, mDNSu8 **salt, int *hashLength, mDNSu8 **nxtName, int *bitmaplen, mDNSu8 **bitmap); 462 463 // *************************************************************************** 464 // MARK: - DNS Message Parsing Functions 465 466 #define HashSlotFromNameHash(X) ((X) % CACHE_HASH_SLOTS) 467 extern mDNSu32 DomainNameHashValue(const domainname *const name); 468 extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength); 469 extern const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end); 470 extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, 471 domainname *const name); 472 extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end); 473 extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, 474 const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr); 475 extern mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, ResourceRecord *rr, 476 mDNSu16 rdlength); 477 extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end); 478 extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, 479 DNSQuestion *question); 480 extern const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end); 481 extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end); 482 extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end); 483 extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize); 484 extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end); 485 extern mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease); 486 extern void DumpPacket(mStatus status, mDNSBool sent, const char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport, 487 const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end, 488 mDNSInterfaceID interfaceID); 489 extern mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type); 490 extern mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type); 491 extern mDNSBool BitmapTypeCheck(const mDNSu8 *bmap, int bitmaplen, mDNSu16 type); 492 493 extern mDNSu16 swap16(mDNSu16 x); 494 extern mDNSu32 swap32(mDNSu32 x); 495 496 extern mDNSBool GetReverseIPv6Addr(const domainname *inQName, mDNSu8 outIPv6[16]); 497 498 // *************************************************************************** 499 // MARK: - Packet Sending Functions 500 extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, 501 mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst, 502 mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass); 503 504 // *************************************************************************** 505 // MARK: - DNSQuestion Functions 506 507 #if MDNSRESPONDER_SUPPORTS(APPLE, LOG_PRIVACY_LEVEL) 508 extern mDNSBool DNSQuestionNeedsSensitiveLogging(const DNSQuestion *q); 509 #endif 510 511 #if MDNSRESPONDER_SUPPORTS(APPLE, RUNTIME_MDNS_METRICS) 512 extern mDNSBool DNSQuestionCollectsMDNSMetric(const DNSQuestion *q); 513 #endif 514 515 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY) 516 extern mDNSBool DNSQuestionIsEligibleForMDNSAlternativeService(const DNSQuestion *q); 517 extern mDNSBool DNSQuestionRequestsMDNSAlternativeService(const DNSQuestion *q); 518 extern mDNSBool DNSQuestionUsesMDNSAlternativeService(const DNSQuestion *q); 519 #endif 520 521 // *************************************************************************** 522 // MARK: - RR List Management & Task Management 523 524 extern void ShowTaskSchedulingError(mDNS *const m); 525 526 /*! 527 * @brief 528 * Check if the locking state is valid or not by comparing the values of <code> mDNS_busy</code> and <code> mDNS_reentrancy</code>, and it also 529 * remembers the last function (with the source file line number) that succeeds in doing lock operation including "Lock", "Unlock", "Drop", "Reclaim". If any 530 * invalid lock state is detected, an error message with the function name of the last successful lock operator will be printed to help debug. 531 * 532 * @param operation 533 * A text description of the lock operation that would be finished after(or before) this lock state checking, possible values are "Lock", "Unlock", 534 * "Drop Lock", "Reclaim Lock" and "Check Lock". 535 * 536 * @param checkIfLockHeld 537 * A boolean value to indicate if the caller wants to check if it currently holds the lock. If the lock is not held or the lock state is invalid, an error message will 538 * be printed. 539 * 540 * @param mDNS_busy 541 * The mDNS_busy value getting from the mDNS_struct object, its value indicates how many times the lock have been grabbed. Note that the caller can grab 542 * the lock and drop it before the user callback to allow the callback to grab the lock again. There should be only one who has grabbed the lock while not 543 * dropping it. 544 * 545 * @param mDNS_reentrancy 546 * The mDNS_reentrancy getting from the mDNS_struct object, its value indicates how many times the lock have been dropped before callback after being 547 * grabbed by others. In other words, it indicates the depth of callback stack. 548 * 549 * @param functionName 550 * The name of the function that calls <code>mDNS_VerifyLockState()</code>. 551 * 552 * @param lineNumber 553 * The line number in the source code file where <code>mDNS_VerifyLockState()</code> gets called. 554 * 555 * @discussion 556 * This function is called whenever mDNSResponder enters/exits the critical section to help avoid the lock-related bug when mDNSResponder is compiled 557 * with multi-thread support. On all Apple platforms, we have only two threads, one is the main queue for the main event loop, the other one is the K queue for 558 * the network configuration event, so we can almost treat mDNSResponder on Apple platform as a single-thread daemon. Such locking issues do not 559 * always happen because the lock cannot be grabbed twice by different process in a single-thread process. However, mDNSResponder core code should 560 * not assume that single-thread model is always available, and it should be aware of the possible locking race condition and avoid those. 561 * <code>mDNS_VerifyLockState()</code> is created to check the state of the lock and make sure the lock is operated correctly even on a single-thread 562 * environment. When it detects any possible lock inconsistency, it will print a log message with the last successful lock operator's name and the line number, 563 * to help debug the lock-related bugs. 564 * 565 */ 566 void mDNS_VerifyLockState(const char *operation, mDNSBool checkIfLockHeld, 567 mDNSu32 mDNS_busy, mDNSu32 mDNS_reentrancy, const char *functionName, mDNSu32 lineNumber); 568 569 extern void mDNS_Lock_(mDNS *m, const char *functionname, mDNSu32 lineNumber); 570 extern void mDNS_Unlock_(mDNS *m, const char *functionname, mDNSu32 lineNumber); 571 572 #if defined(_WIN32) 573 #define __func__ __FUNCTION__ 574 #endif 575 576 #define mDNS_Lock(X) mDNS_Lock_((X), __func__, __LINE__) 577 578 #define mDNS_Unlock(X) mDNS_Unlock_((X), __func__, __LINE__) 579 580 #define mDNS_CheckLock(X) mDNS_VerifyLockState("Check Lock", mDNStrue, (X)->mDNS_busy, (X)->mDNS_reentrancy, \ 581 __func__, __LINE__) 582 583 #define mDNS_DropLockBeforeCallback() \ 584 do \ 585 { \ 586 m->mDNS_reentrancy++; \ 587 mDNS_VerifyLockState("Drop Lock", mDNSfalse, m->mDNS_busy, m->mDNS_reentrancy, __func__, __LINE__); \ 588 } while (mDNSfalse) 589 590 #define mDNS_ReclaimLockAfterCallback() \ 591 do \ 592 { \ 593 mDNS_VerifyLockState("Reclaim Lock", mDNSfalse, m->mDNS_busy, m->mDNS_reentrancy, __func__, __LINE__); \ 594 m->mDNS_reentrancy--; \ 595 } while (mDNSfalse) 596 597 #ifdef __cplusplus 598 } 599 #endif 600 601 #endif // __DNSCOMMON_H_ 602