Home | History | Annotate | Line # | Download | only in mDNSCore
      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