1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*- 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 STANDALONE 19 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary 20 #define mDNS_InstantiateInlines 1 21 #include "DNSCommon.h" 22 #include "DebugServices.h" 23 24 #if MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY) 25 #include "discover_resolver.h" 26 #endif 27 28 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS_PUSH) 29 #include "dns_push_discovery.h" 30 #endif 31 32 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 33 #include "dnssec_obj_rr_ds.h" // For dnssec_obj_rr_ds_t. 34 #include "dnssec_mdns_core.h" // For DNSSEC-related operation on mDNSCore structures. 35 #include "rdata_parser.h" // For DNSSEC-related records parsing. 36 #include "base_encoding.h" // For base64 encoding. 37 #endif 38 39 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK) 40 #include <os/lock.h> // For os_unfair_lock. 41 #endif 42 43 #if MDNSRESPONDER_SUPPORTS(APPLE, LOG_PRIVACY_LEVEL) 44 #include "system_utilities.h" //For is_apple_internal_build(). 45 #endif 46 47 // Disable certain benign warnings with Microsoft compilers 48 #if (defined(_MSC_VER)) 49 // Disable "conditional expression is constant" warning for debug macros. 50 // Otherwise, this generates warnings for the perfectly natural construct "while(1)" 51 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know 52 #pragma warning(disable:4127) 53 // Disable "array is too small to include a terminating null character" warning 54 // -- domain labels have an initial length byte, not a terminating null character 55 #pragma warning(disable:4295) 56 #endif 57 58 // *************************************************************************** 59 // MARK: - Program Constants 60 61 #include "mdns_strict.h" 62 63 mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0; 64 mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1; 65 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2; 66 mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-3; 67 mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-4; 68 mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-5; 69 70 // Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of 71 // Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP 72 // port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders. 73 // LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355. 74 // Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability 75 // with Microsoft's LLMNR client code. 76 77 #define DiscardPortAsNumber 9 78 #define SSHPortAsNumber 22 79 #define UnicastDNSPortAsNumber 53 80 #define SSDPPortAsNumber 1900 81 #define IPSECPortAsNumber 4500 82 #define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback 83 #define NATPMPAnnouncementPortAsNumber 5350 84 #define NATPMPPortAsNumber 5351 85 #define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc. 86 #define MulticastDNSPortAsNumber 5353 87 #define LoopbackIPCPortAsNumber 5354 88 //#define MulticastDNSPortAsNumber 5355 // LLMNR 89 #define PrivateDNSPortAsNumber 5533 90 91 mDNSexport const mDNSIPPort DiscardPort = { { DiscardPortAsNumber >> 8, DiscardPortAsNumber & 0xFF } }; 92 mDNSexport const mDNSIPPort SSHPort = { { SSHPortAsNumber >> 8, SSHPortAsNumber & 0xFF } }; 93 mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; 94 mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } }; 95 mDNSexport const mDNSIPPort IPSECPort = { { IPSECPortAsNumber >> 8, IPSECPortAsNumber & 0xFF } }; 96 mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 0xFF } }; 97 mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } }; 98 mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } }; 99 mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } }; 100 mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } }; 101 mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } }; 102 mDNSexport const mDNSIPPort PrivateDNSPort = { { PrivateDNSPortAsNumber >> 8, PrivateDNSPortAsNumber & 0xFF } }; 103 104 mDNSexport const OwnerOptData zeroOwner = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } }; 105 106 mDNSexport const mDNSIPPort zeroIPPort = { { 0 } }; 107 mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } }; 108 mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } }; 109 mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } }; 110 mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } }; 111 mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } }; 112 mDNSexport const mDNSEthAddr onesEthAddr = { { 255, 255, 255, 255, 255, 255 } }; 113 mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} }; 114 115 mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } }; 116 mDNSexport const mDNSv4Addr AllHosts_v4 = { { 224, 0, 0, 1 } }; // For NAT-PMP & PCP Annoucements 117 mDNSexport const mDNSv6Addr AllHosts_v6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } }; 118 mDNSexport const mDNSv6Addr NDP_prefix = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01, 0xFF,0x00,0x00,0xFB } }; // FF02:0:0:0:0:1:FF00::/104 119 mDNSexport const mDNSEthAddr AllHosts_v6_Eth = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } }; 120 mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } }; 121 //mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR 122 mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } }; 123 //mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR 124 125 mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; 126 mDNSexport const mDNSOpaque16 onesID = { { 255, 255 } }; 127 mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; 128 mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; 129 mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; 130 mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; 131 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; 132 133 mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } }; 134 mDNSexport const mDNSOpaque128 zeroOpaque128 = { { 0 } }; 135 136 extern mDNS mDNSStorage; 137 138 // *************************************************************************** 139 // MARK: - General Utility Functions 140 141 mDNSexport void CacheRecordSetResponseFlags(CacheRecord *const cr, const mDNSOpaque16 responseFlags) 142 { 143 cr->responseFlags = responseFlags; 144 cr->resrec.rcode = cr->responseFlags.b[1] & kDNSFlag1_RC_Mask; 145 } 146 147 mDNSexport void mDNSCoreResetRecord(mDNS *const m) 148 { 149 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 150 CacheRecordSetResponseFlags(&m->rec.r, zeroID); 151 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 152 MDNS_DISPOSE_DNSSEC_OBJ(m->rec.r.resrec.dnssec); 153 #endif 154 } 155 156 // return true for RFC1918 private addresses 157 mDNSexport mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr) 158 { 159 return ((addr->b[0] == 10) || // 10/8 prefix 160 (addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) || // 172.16/12 161 (addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16 162 } 163 164 mDNSexport const char *DNSScopeToString(mDNSu32 scope) 165 { 166 switch (scope) 167 { 168 case kScopeNone: 169 return "Unscoped"; 170 case kScopeInterfaceID: 171 return "InterfaceScoped"; 172 case kScopeServiceID: 173 return "ServiceScoped"; 174 default: 175 return "Unknown"; 176 } 177 } 178 179 mDNSexport void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out) 180 { 181 out->l[0] = 0; 182 out->l[1] = 0; 183 out->w[4] = 0; 184 out->w[5] = 0xffff; 185 out->b[12] = in->b[0]; 186 out->b[13] = in->b[1]; 187 out->b[14] = in->b[2]; 188 out->b[15] = in->b[3]; 189 } 190 191 mDNSexport mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr* out) 192 { 193 if (in->l[0] != 0 || in->l[1] != 0 || in->w[4] != 0 || in->w[5] != 0xffff) 194 return mDNSfalse; 195 196 out->NotAnInteger = in->l[3]; 197 return mDNStrue; 198 } 199 200 NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 201 { 202 NetworkInterfaceInfo *intf = m->HostInterfaces; 203 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; 204 return(intf); 205 } 206 207 NetworkInterfaceInfo *FirstIPv4LLInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 208 { 209 NetworkInterfaceInfo *intf; 210 211 if (!InterfaceID) 212 return mDNSNULL; 213 214 // Note: We don't check for InterfaceActive, as the active interface could be IPv6 and 215 // we still want to find the first IPv4 Link-Local interface 216 for (intf = m->HostInterfaces; intf; intf = intf->next) 217 { 218 if (intf->InterfaceID == InterfaceID && 219 intf->ip.type == mDNSAddrType_IPv4 && mDNSv4AddressIsLinkLocal(&intf->ip.ip.v4)) 220 { 221 debugf("FirstIPv4LLInterfaceForID: found LL interface with address %.4a", &intf->ip.ip.v4); 222 return intf; 223 } 224 } 225 return (mDNSNULL); 226 } 227 228 mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 229 { 230 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 231 return(intf ? intf->ifname : mDNSNULL); 232 } 233 234 mDNSexport const char *InterfaceNameForIDOrEmptyString(const mDNSInterfaceID InterfaceID) 235 { 236 const char *const ifName = InterfaceNameForID(&mDNSStorage, InterfaceID); 237 return (ifName ? ifName : ""); 238 } 239 240 mDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf) 241 { 242 while (intf && !intf->InterfaceActive) intf = intf->next; 243 return(intf); 244 } 245 246 mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf) 247 { 248 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 249 if (next) return(next->InterfaceID);else return(mDNSNULL); 250 } 251 252 mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id) 253 { 254 mDNSu32 slot, used = 0; 255 CacheGroup *cg; 256 const CacheRecord *rr; 257 FORALL_CACHERECORDS(slot, cg, rr) 258 { 259 if (rr->resrec.InterfaceID == id) 260 used++; 261 } 262 return(used); 263 } 264 265 mDNSexport char *DNSTypeName(mDNSu16 rrtype) 266 { 267 switch (rrtype) 268 { 269 case kDNSType_A: return("Addr"); 270 case kDNSType_NS: return("NS"); 271 case kDNSType_CNAME: return("CNAME"); 272 case kDNSType_SOA: return("SOA"); 273 case kDNSType_NULL: return("NULL"); 274 case kDNSType_PTR: return("PTR"); 275 case kDNSType_HINFO: return("HINFO"); 276 case kDNSType_TXT: return("TXT"); 277 case kDNSType_AAAA: return("AAAA"); 278 case kDNSType_SRV: return("SRV"); 279 case kDNSType_OPT: return("OPT"); 280 case kDNSType_NSEC: return("NSEC"); 281 case kDNSType_NSEC3: return("NSEC3"); 282 case kDNSType_NSEC3PARAM: return("NSEC3PARAM"); 283 case kDNSType_TSIG: return("TSIG"); 284 case kDNSType_RRSIG: return("RRSIG"); 285 case kDNSType_DNSKEY: return("DNSKEY"); 286 case kDNSType_DS: return("DS"); 287 case kDNSType_SVCB: return("SVCB"); 288 case kDNSType_HTTPS: return("HTTPS"); 289 case kDNSType_TSR: return("TSR"); 290 case kDNSQType_ANY: return("ANY"); 291 default: { 292 static char buffer[16]; 293 mDNS_snprintf(buffer, sizeof(buffer), "TYPE%d", rrtype); 294 return(buffer); 295 } 296 } 297 } 298 299 mDNSexport const char *mStatusDescription(mStatus error) 300 { 301 const char *error_description; 302 switch (error) { 303 case mStatus_NoError: 304 error_description = "mStatus_NoError"; 305 break; 306 case mStatus_BadParamErr: 307 error_description = "mStatus_BadParamErr"; 308 break; 309 310 default: 311 error_description = "mStatus_UnknownDescription"; 312 break; 313 } 314 315 return error_description; 316 } 317 318 mDNSexport mDNSu32 swap32(mDNSu32 x) 319 { 320 mDNSu8 *ptr = (mDNSu8 *)&x; 321 return (mDNSu32)((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); 322 } 323 324 mDNSexport mDNSu16 swap16(mDNSu16 x) 325 { 326 mDNSu8 *ptr = (mDNSu8 *)&x; 327 return (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 328 } 329 330 mDNSlocal void PrintTypeBitmap(const mDNSu8 *bmap, int bitmaplen, char *const buffer, mDNSu32 length) 331 { 332 int win, wlen, type; 333 334 while (bitmaplen > 0) 335 { 336 int i; 337 338 if (bitmaplen < 3) 339 { 340 LogMsg("PrintTypeBitmap: malformed bitmap, bitmaplen %d short", bitmaplen); 341 break; 342 } 343 344 win = *bmap++; 345 wlen = *bmap++; 346 bitmaplen -= 2; 347 if (bitmaplen < wlen || wlen < 1 || wlen > 32) 348 { 349 LogInfo("PrintTypeBitmap: malformed nsec, bitmaplen %d wlen %d", bitmaplen, wlen); 350 break; 351 } 352 if (win < 0 || win >= 256) 353 { 354 LogInfo("PrintTypeBitmap: malformed nsec, bad window win %d", win); 355 break; 356 } 357 type = win * 256; 358 for (i = 0; i < wlen * 8; i++) 359 { 360 if (bmap[i>>3] & (128 >> (i&7))) 361 length += mDNS_snprintf(buffer+length, (MaxMsg - 1) - length, "%s ", DNSTypeName(type + i)); 362 } 363 bmap += wlen; 364 bitmaplen -= wlen; 365 } 366 } 367 368 #define TXT_RECORD_SEPARATOR '|' 369 370 mDNSlocal mDNSu8 mDNSLengthOfFirstUTF8Character(const mDNSu8 *bytes, mDNSu32 len); 371 372 mDNSlocal const mDNSu8 *mDNSLocateFirstByteToEscape(const mDNSu8 *const bytes, const mDNSu32 bytesLen) 373 { 374 for (const mDNSu8 *ptr = bytes, *const end = bytes + bytesLen; ptr < end;) 375 { 376 const mDNSu8 utf8CharacterLen = mDNSLengthOfFirstUTF8Character(ptr, (mDNSu32)(end - ptr)); 377 if (utf8CharacterLen == 0) 378 { 379 return ptr; 380 } 381 else if (utf8CharacterLen == 1) 382 { 383 const char ch = *ptr; 384 if ((ch == '\\') || (ch == TXT_RECORD_SEPARATOR) || !mDNSIsPrintASCII(ch)) 385 { 386 return ptr; 387 } 388 } 389 ptr += utf8CharacterLen; 390 } 391 return mDNSNULL; 392 } 393 394 mDNSlocal mDNSu32 putTXTRRCharacterString(char *const buffer, const mDNSu32 bufferLen, const mDNSu8 *const bytes, 395 const mDNSu32 bytesLen, const mDNSBool addSeparator, mDNSBool *const outTruncated) 396 { 397 mDNSBool truncated = mDNSfalse; 398 mDNSu32 nWrites = 0; 399 400 if (addSeparator) 401 { 402 require_action_quiet(bufferLen > 1, exit, truncated = mDNStrue); 403 nWrites = mDNS_snprintf(buffer, bufferLen, "%c", TXT_RECORD_SEPARATOR); 404 } 405 406 for (const mDNSu8 *ptr = bytes, *const end = bytes + bytesLen; ptr < end;) 407 { 408 const mDNSu32 remainingLen = (mDNSu32)(end - ptr); 409 const mDNSu8 *const firstByteToEscape = mDNSLocateFirstByteToEscape(ptr, remainingLen); 410 411 // [ptr ... firstByteToEscape ... end] 412 // The bytes between [ptr, firstByteToEscape) are directly-printable. 413 const mDNSu32 normalBytesLenToPrint = (firstByteToEscape ? ((mDNSu32)(firstByteToEscape - ptr)) : remainingLen); 414 // Print UTF-8 characters in [ptr, firstByteToEscape). 415 if (normalBytesLenToPrint > 0) 416 { 417 const mDNSu32 currentNWrites = mDNS_snprintf(buffer + nWrites, bufferLen - nWrites, "%.*s", 418 normalBytesLenToPrint, ptr); 419 nWrites += currentNWrites; 420 require_action_quiet(currentNWrites == normalBytesLenToPrint, exit, truncated = mDNStrue); 421 } 422 423 if (firstByteToEscape) 424 { 425 // Print the *firstByteToEscape if it exists. 426 const mDNSu8 byteToEscape = *firstByteToEscape; 427 428 if ((byteToEscape == '\\') || (byteToEscape == TXT_RECORD_SEPARATOR)) 429 { 430 // One escape character `\\`, one character being escaped, one `\0`. 431 require_action_quiet((bufferLen - nWrites) >= 3, exit, truncated = mDNStrue); 432 nWrites += mDNS_snprintf(buffer + nWrites, bufferLen - nWrites, "\\%c", byteToEscape); 433 } 434 else 435 { 436 // Two-byte hex prefix `\\x`, Two-byte hex value "HH" , one '\0'. 437 require_action_quiet((bufferLen - nWrites) >= 5, exit, truncated = mDNStrue); 438 nWrites += mDNS_snprintf(buffer + nWrites, bufferLen - nWrites, "\\x%02X", byteToEscape); 439 } 440 ptr = firstByteToEscape + 1; 441 } 442 else 443 { 444 // firstByteToEscape is NULL means that the remaining characters are printable. 445 ptr += remainingLen; 446 } 447 } 448 449 exit: 450 if (outTruncated) 451 { 452 *outTruncated = truncated; 453 } 454 return nWrites; 455 } 456 457 mDNSlocal char *GetTXTRRDisplayString(const mDNSu8 *const rdata, const mDNSu32 rdLen, char *const buffer, 458 const mDNSu32 bufferLen) 459 { 460 mDNSu32 currentLen = 0; 461 #define RESERVED_BUFFER_LENGTH 5 // " <C>", " <T>" or " <M>" plus '\0' 462 require_quiet(bufferLen >= RESERVED_BUFFER_LENGTH, exit); 463 464 mDNSu32 adjustedBufferLen = bufferLen - RESERVED_BUFFER_LENGTH; 465 466 mDNSu32 characterStringLen; 467 mDNSBool malformed = mDNSfalse; 468 mDNSBool truncated = mDNSfalse; 469 mDNSBool addSeparator = mDNSfalse; 470 for (const mDNSu8 *src = rdata, *const end = rdata + rdLen; src < end && !truncated; src += characterStringLen) 471 { 472 characterStringLen = *src++; 473 474 if (((mDNSu32)(end - src)) < characterStringLen) 475 { 476 malformed = mDNStrue; 477 break; 478 } 479 480 currentLen += putTXTRRCharacterString((buffer + currentLen), (adjustedBufferLen - currentLen), src, 481 characterStringLen, addSeparator, &truncated); 482 addSeparator = mDNStrue; 483 } 484 485 const char statusCode = (malformed ? 'M' : (truncated ? 'T' : 'C')); 486 currentLen += mDNS_snprintf((buffer + currentLen), (bufferLen - currentLen), " <%c>", statusCode); 487 488 exit: 489 return buffer + currentLen; 490 } 491 492 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display 493 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as 494 // long as this routine is only used for debugging messages, it probably isn't a big problem. 495 mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer) 496 { 497 const RDataBody2 *const rd = (const RDataBody2 *)rd1; 498 #define RemSpc (MaxMsg-1-length) 499 char *ptr = buffer; 500 mDNSu32 length = mDNS_snprintf(buffer, MaxMsg-1, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype)); 501 if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer); 502 if (!rr->rdlength && rr->rrtype != kDNSType_OPT) { mDNS_snprintf(buffer+length, RemSpc, "<< ZERO RDATA LENGTH >>"); return(buffer); } 503 504 switch (rr->rrtype) 505 { 506 case kDNSType_A: mDNS_snprintf(buffer+length, RemSpc, "%.4a", &rd->ipv4); break; 507 508 case kDNSType_NS: // Same as PTR 509 case kDNSType_CNAME: // Same as PTR 510 case kDNSType_PTR: mDNS_snprintf(buffer+length, RemSpc, "%##s", rd->name.c); break; 511 512 case kDNSType_SOA: mDNS_snprintf(buffer+length, RemSpc, "%##s %##s %d %d %d %d %d", 513 rd->soa.mname.c, rd->soa.rname.c, 514 rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min); 515 break; 516 517 case kDNSType_HINFO: // Display this the same as TXT (show all constituent strings) 518 case kDNSType_TXT: 519 GetTXTRRDisplayString(rd->txt.c, rr->rdlength, buffer + length, RemSpc); 520 break; 521 522 case kDNSType_AAAA: mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6); break; 523 case kDNSType_SRV: mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s", 524 rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break; 525 case kDNSType_TSR: mDNS_snprintf(buffer+length, RemSpc, "%d", rd1->tsr_value); break; 526 527 case kDNSType_OPT: { 528 const rdataOPT *opt; 529 const rdataOPT *const end = (const rdataOPT *)&rd->data[rr->rdlength]; 530 length += mDNS_snprintf(buffer+length, RemSpc, "Max %d", rr->rrclass); 531 for (opt = &rd->opt[0]; opt < end; opt++) 532 { 533 switch(opt->opt) 534 { 535 case kDNSOpt_LLQ: 536 length += mDNS_snprintf(buffer+length, RemSpc, " LLQ"); 537 length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.llq.vers); 538 length += mDNS_snprintf(buffer+length, RemSpc, " Op %d", opt->u.llq.llqOp); 539 length += mDNS_snprintf(buffer+length, RemSpc, " Err/Port %d", opt->u.llq.err); 540 length += mDNS_snprintf(buffer+length, RemSpc, " ID %08X%08X", opt->u.llq.id.l[0], opt->u.llq.id.l[1]); 541 length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.llq.llqlease); 542 break; 543 case kDNSOpt_Lease: 544 length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.updatelease); 545 break; 546 case kDNSOpt_Owner: 547 length += mDNS_snprintf(buffer+length, RemSpc, " Owner"); 548 length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.owner.vers); 549 length += mDNS_snprintf(buffer+length, RemSpc, " Seq %3d", (mDNSu8)opt->u.owner.seq); // Display as unsigned 550 length += mDNS_snprintf(buffer+length, RemSpc, " MAC %.6a", opt->u.owner.HMAC.b); 551 if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4) 552 { 553 length += mDNS_snprintf(buffer+length, RemSpc, " I-MAC %.6a", opt->u.owner.IMAC.b); 554 if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4) 555 length += mDNS_snprintf(buffer+length, RemSpc, " Password %.6a", opt->u.owner.password.b); 556 } 557 break; 558 case kDNSOpt_Trace: 559 length += mDNS_snprintf(buffer+length, RemSpc, " Trace"); 560 length += mDNS_snprintf(buffer+length, RemSpc, " Platform %d", opt->u.tracer.platf); 561 length += mDNS_snprintf(buffer+length, RemSpc, " mDNSVers %d", opt->u.tracer.mDNSv); 562 break; 563 case kDNSOpt_TSR: 564 length += mDNS_snprintf(buffer+length, RemSpc, " TSR"); 565 length += mDNS_snprintf(buffer+length, RemSpc, " Tm %d", opt->u.tsr.timeStamp); 566 length += mDNS_snprintf(buffer+length, RemSpc, " Hk %x", opt->u.tsr.hostkeyHash); 567 length += mDNS_snprintf(buffer+length, RemSpc, " Ix %u", opt->u.tsr.recIndex); 568 break; 569 default: 570 length += mDNS_snprintf(buffer+length, RemSpc, " Unknown %d", opt->opt); 571 break; 572 } 573 } 574 } 575 break; 576 577 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 578 case kDNSType_DS: { 579 // See <https://datatracker.ietf.org/doc/html/rfc4034#section-5.3> for DS RR Presentation Format. 580 581 dnssec_error_t err; 582 dnssec_obj_rr_ds_t ds = mDNSNULL; 583 char *ds_rdata_description = mDNSNULL; 584 585 ds = dnssec_obj_rr_ds_create(rr->name->c, rr->rrclass, rr->rdata->u.data, rr->rdlength, false, &err); 586 if (err != DNSSEC_ERROR_NO_ERROR) 587 { 588 goto ds_exit; 589 } 590 591 ds_rdata_description = dnssec_obj_rr_copy_rdata_rfc_description(ds, &err); 592 if (err != DNSSEC_ERROR_NO_ERROR) 593 { 594 goto ds_exit; 595 } 596 597 mDNS_snprintf(buffer + length, RemSpc, "%s", ds_rdata_description); 598 599 ds_exit: 600 MDNS_DISPOSE_DNSSEC_OBJ(ds); 601 mDNSPlatformMemFree(ds_rdata_description); 602 } 603 break; 604 605 case kDNSType_RRSIG: { 606 // See <https://datatracker.ietf.org/doc/html/rfc4034#section-3.2> for RRSIG RR Presentation Format. 607 608 dnssec_error_t err; 609 dnssec_obj_rr_rrsig_t rrsig = NULL; 610 char *rrsig_rdata_description = mDNSNULL; 611 612 rrsig = dnssec_obj_rr_rrsig_create(rr->name->c, rr->rdata->u.data, rr->rdlength, false, &err); 613 if (err != DNSSEC_ERROR_NO_ERROR) { 614 goto rrsig_exit; 615 } 616 617 rrsig_rdata_description = dnssec_obj_rr_copy_rdata_rfc_description(rrsig, &err); 618 if (err != DNSSEC_ERROR_NO_ERROR) 619 { 620 goto rrsig_exit; 621 } 622 623 mDNS_snprintf(buffer + length, RemSpc, "%s", rrsig_rdata_description); 624 625 rrsig_exit: 626 MDNS_DISPOSE_DNSSEC_OBJ(rrsig); 627 mDNSPlatformMemFree(rrsig_rdata_description); 628 } 629 break; 630 #endif 631 632 case kDNSType_NSEC: { 633 const domainname *next = (const domainname *)rd->data; 634 int len, bitmaplen; 635 const mDNSu8 *bmap; 636 len = DomainNameLength(next); 637 bitmaplen = rr->rdlength - len; 638 bmap = (const mDNSu8 *)((const mDNSu8 *)next + len); 639 640 if (UNICAST_NSEC(rr)) 641 length += mDNS_snprintf(buffer+length, RemSpc, "%##s ", next->c); 642 PrintTypeBitmap(bmap, bitmaplen, buffer, length); 643 644 } 645 break; 646 647 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 648 case kDNSType_DNSKEY: { 649 // See <https://datatracker.ietf.org/doc/html/rfc4034#section-2.2> for DNSKEY RR Presentation Format. 650 651 dnssec_error_t err; 652 dnssec_obj_rr_dnskey_t dnskey = mDNSNULL; 653 char *dnskey_rdata_description = mDNSNULL; 654 655 dnskey = dnssec_obj_rr_dnskey_create(rr->name->c, rr->rrclass, rr->rdata->u.data, rr->rdlength, false, &err); 656 if (err != DNSSEC_ERROR_NO_ERROR) { 657 goto dnskey_exit; 658 } 659 660 dnskey_rdata_description = dnssec_obj_rr_copy_rdata_rfc_description(dnskey, &err); 661 if (err != DNSSEC_ERROR_NO_ERROR) { 662 goto dnskey_exit; 663 } 664 665 mDNS_snprintf(buffer + length, RemSpc, "%s", dnskey_rdata_description); 666 667 dnskey_exit: 668 MDNS_DISPOSE_DNSSEC_OBJ(dnskey); 669 mDNSPlatformMemFree(dnskey_rdata_description); 670 } 671 break; 672 #endif 673 674 default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %.*s", rr->rdlength, rr->rdlength, rd->data); 675 // Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not 676 for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.'; 677 break; 678 } 679 680 return(buffer); 681 } 682 683 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG) 684 685 mDNSexport const mDNSu8 *GetPrintableRDataBytes(mDNSu8 *const outBuffer, const mDNSu32 bufferLen, 686 const mDNSu16 recordType, const mDNSu8 * const rdata, const mDNSu32 rdataLen) 687 { 688 const mDNSu32 totalLen = rdataLen + 2; 689 mdns_require_return_value(bufferLen >= totalLen, mDNSNULL); 690 691 outBuffer[0] = (mDNSu8)((recordType >> 8) & 0xFF); 692 outBuffer[1] = (mDNSu8)((recordType ) & 0xFF); 693 mDNSPlatformMemCopy(&outBuffer[2], rdata, (mDNSu32)rdataLen); 694 695 return outBuffer; 696 } 697 698 #endif 699 700 // See comments in mDNSEmbeddedAPI.h 701 #if _PLATFORM_HAS_STRONG_PRNG_ 702 #define mDNSRandomNumber mDNSPlatformRandomNumber 703 #else 704 mDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed) 705 { 706 return seed * 21 + 1; 707 } 708 709 mDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration) 710 { 711 return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed; 712 } 713 714 mDNSlocal mDNSu32 mDNSRandomNumber() 715 { 716 static mDNSBool seeded = mDNSfalse; 717 static mDNSu32 seed = 0; 718 if (!seeded) 719 { 720 seed = mDNSMixRandomSeed(mDNSPlatformRandomSeed(), 100); 721 seeded = mDNStrue; 722 } 723 return (seed = mDNSRandomFromSeed(seed)); 724 } 725 #endif // ! _PLATFORM_HAS_STRONG_PRNG_ 726 727 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive 728 { 729 mDNSu32 ret = 0; 730 mDNSu32 mask = 1; 731 732 while (mask < max) mask = (mask << 1) | 1; 733 734 do ret = mDNSRandomNumber() & mask; 735 while (ret > max); 736 737 return ret; 738 } 739 740 // See <https://datatracker.ietf.org/doc/html/draft-eastlake-fnv-19#section-5> 741 #define MDNSRESPONDER_FNV_32_BIT_OFFSET_BASIS ((mDNSu32)0x811C9DC5) 742 #define MDNSRESPONDER_FNV_32_BIT_PRIME ((mDNSu32)0x01000193) 743 744 mDNSexport mDNSu32 mDNS_NonCryptoHashUpdateBytes(const mDNSNonCryptoHash algorithm, const mDNSu32 previousHash, 745 const mDNSu8 *const bytes, const mDNSu32 len) 746 { 747 mDNSu32 hash = previousHash; 748 749 switch (algorithm) { 750 case mDNSNonCryptoHash_FNV1a: 751 { 752 for (mDNSu32 i = 0; i < len; i++) 753 { 754 hash ^= bytes[i]; 755 hash *= MDNSRESPONDER_FNV_32_BIT_PRIME; 756 } 757 } 758 break; 759 case mDNSNonCryptoHash_SDBM: // See <http://www.cse.yorku.ca/~oz/hash.html> 760 { 761 for (mDNSu32 i = 0; i < len; i++) 762 { 763 // hash(i) = hash(i - 1) * 65599 + byte 764 hash = bytes[i] + (hash << 6) + (hash << 16) - hash; 765 } 766 } 767 break; 768 MDNS_COVERED_SWITCH_DEFAULT: 769 break; 770 } 771 772 return hash; 773 } 774 775 mDNSexport mDNSu32 mDNS_NonCryptoHash(const mDNSNonCryptoHash algorithm, const mDNSu8 *const bytes, const mDNSu32 len) 776 { 777 switch (algorithm) { 778 case mDNSNonCryptoHash_FNV1a: 779 return mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, MDNSRESPONDER_FNV_32_BIT_OFFSET_BASIS, bytes, 780 len); 781 case mDNSNonCryptoHash_SDBM: 782 return mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, 0, bytes, len); 783 MDNS_COVERED_SWITCH_DEFAULT: 784 return 0; 785 } 786 } 787 788 mDNSexport mDNSu32 mDNS_DomainNameFNV1aHash(const domainname *const name) 789 { 790 mDNSu32 hash = MDNSRESPONDER_FNV_32_BIT_OFFSET_BASIS; 791 const mDNSu32 len = DomainNameLength(name); 792 const mDNSu8 *const data = name->c; 793 for (mDNSu32 i = 0; i < len; ++i) 794 { 795 hash ^= mDNSASCIITolower(data[i]); 796 hash *= MDNSRESPONDER_FNV_32_BIT_PRIME; 797 } 798 return hash; 799 } 800 801 mDNSexport mDNSs32 mDNSGetTimeOfDay(struct timeval *const tv, struct timezone *const tz) 802 { 803 return gettimeofday(tv, tz); 804 } 805 806 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2) 807 { 808 if (ip1->type == ip2->type) 809 { 810 switch (ip1->type) 811 { 812 case mDNSAddrType_None: return(mDNStrue); // Empty addresses have no data and are therefore always equal 813 case mDNSAddrType_IPv4: return (mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4)); 814 case mDNSAddrType_IPv6: return (mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6)); 815 default: 816 break; 817 } 818 } 819 return(mDNSfalse); 820 } 821 822 mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip) 823 { 824 switch(ip->type) 825 { 826 case mDNSAddrType_IPv4: return (mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4)); 827 case mDNSAddrType_IPv6: return (mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6)); 828 default: return(mDNSfalse); 829 } 830 } 831 832 mDNSlocal mDNSBool mDNSByteInRange(const mDNSu8 byte, const mDNSu8 min, const mDNSu8 max) 833 { 834 return ((byte >= min) && (byte <= max)); 835 } 836 837 mDNSlocal mDNSBool mDNSisUTF8Tail(const mDNSu8 byte) 838 { 839 // 0x80-0xBF is a common byte range for various well-formed UTF-8 byte sequences. 840 return mDNSByteInRange(byte, 0x80, 0xBF); 841 } 842 843 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8OneByteSequence(const mDNSu8 *const bytes, const mDNSu32 len) 844 { 845 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>: 846 // 847 // Code Points | First Byte 848 // ---------------+------------ 849 // U+0000..U+007F | 00..7F 850 851 return ((len >= 1) && mDNSByteInRange(bytes[0], 0x00, 0x7F)); 852 } 853 854 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8TwoByteSequence(const mDNSu8 *const bytes, const mDNSu32 len) 855 { 856 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>: 857 // 858 // Code Points | First Byte | Second Byte 859 // ---------------+------------+------------- 860 // U+0080..U+07FF | C2..DF | 80..BF 861 862 return ((len >= 2) && mDNSByteInRange(bytes[0], 0xC2, 0xDF) && mDNSisUTF8Tail(bytes[1])); 863 } 864 865 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8ThreeByteSequence(const mDNSu8 *const bytes, const mDNSu32 len) 866 { 867 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>: 868 // 869 // Code Points | First Byte | Second Byte | Third Byte 870 // ---------------+------------+-------------+------------ 871 // U+0800..U+0FFF | E0 | A0..BF | 80..BF 872 // U+1000..U+CFFF | E1..EC | 80..BF | 80..BF 873 // U+D000..U+D7FF | ED | 80..9F | 80..BF 874 // U+E000..U+FFFF | EE..EF | 80..BF | 80..BF 875 876 if ((len >= 3) && mDNSisUTF8Tail(bytes[2])) 877 { 878 if (bytes[0] == 0xE0) 879 { 880 if (mDNSByteInRange(bytes[1], 0xA0, 0xBF)) 881 { 882 return mDNStrue; 883 } 884 } 885 else if (mDNSByteInRange(bytes[0], 0xE1, 0xEC) || mDNSByteInRange(bytes[0], 0xEE, 0xEF)) 886 { 887 if (mDNSisUTF8Tail(bytes[1])) 888 { 889 return mDNStrue; 890 } 891 } 892 else if (bytes[0] == 0xED) 893 { 894 if (mDNSByteInRange(bytes[1], 0x80, 0x9F)) 895 { 896 return mDNStrue; 897 } 898 } 899 } 900 return mDNSfalse; 901 } 902 903 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8FourByteSequence(const mDNSu8 *const bytes, const mDNSu32 len) 904 { 905 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>: 906 // 907 // Code Points | First Byte | Second Byte | Third Byte | Fourth Byte 908 // -------------------+------------+-------------+------------+------------- 909 // U+10000..U+3FFFF | F0 | 90..BF | 80..BF | 80..BF 910 // U+40000..U+FFFFF | F1..F3 | 80..BF | 80..BF | 80..BF 911 // U+100000..U+10FFFF | F4 | 80..8F | 80..BF | 80..BF 912 913 if ((len >= 4) && mDNSisUTF8Tail(bytes[2]) && mDNSisUTF8Tail(bytes[3])) 914 { 915 if (bytes[0] == 0xF0) 916 { 917 if (mDNSByteInRange(bytes[1], 0x90, 0xBF)) 918 { 919 return mDNStrue; 920 } 921 } 922 else if (mDNSByteInRange(bytes[0], 0xF1, 0xF3)) 923 { 924 if (mDNSisUTF8Tail(bytes[1])) 925 { 926 return mDNStrue; 927 } 928 } 929 else if (bytes[0] == 0xF4) 930 { 931 if (mDNSByteInRange(bytes[1], 0x80, 0x8F)) 932 { 933 return mDNStrue; 934 } 935 } 936 } 937 return mDNSfalse; 938 } 939 940 mDNSlocal mDNSu8 mDNSLengthOfFirstUTF8Character(const mDNSu8 *const bytes, const mDNSu32 len) 941 { 942 if (mDNSBytesStartWithWellFormedUTF8OneByteSequence(bytes, len)) 943 { 944 return 1; 945 } 946 else if (mDNSBytesStartWithWellFormedUTF8TwoByteSequence(bytes, len)) 947 { 948 return 2; 949 } 950 else if (mDNSBytesStartWithWellFormedUTF8ThreeByteSequence(bytes, len)) 951 { 952 return 3; 953 } 954 else if (mDNSBytesStartWithWellFormedUTF8FourByteSequence(bytes, len)) 955 { 956 return 4; 957 } 958 else 959 { 960 return 0; 961 } 962 } 963 964 mDNSlocal const mDNSu8 *mDNSLocateFirstMalformedUTF8Byte(const mDNSu8 *const bytes, const mDNSu32 byteLen) 965 { 966 for (const mDNSu8 *ptr = bytes, *const end = bytes + byteLen; ptr < end;) 967 { 968 const mDNSu32 utf8CharacterLen = mDNSLengthOfFirstUTF8Character(ptr, (mDNSu32)(end - ptr)); 969 if (utf8CharacterLen == 0) 970 { 971 return ptr; 972 } 973 ptr += utf8CharacterLen; 974 } 975 return mDNSNULL; 976 } 977 978 mDNSlocal mDNSBool mDNSAreUTF8Bytes(const mDNSu8 *const bytes, const mDNSu32 len) 979 { 980 return (mDNSLocateFirstMalformedUTF8Byte(bytes, len) == mDNSNULL); 981 } 982 983 mDNSexport mDNSBool mDNSAreUTF8String(const char *const str) 984 { 985 return mDNSAreUTF8Bytes((const mDNSu8 *)str, mDNSPlatformStrLen(str)); 986 } 987 988 mDNSexport mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds 989 { 990 if (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease; 991 else if (LLQType == uDNS_LLQ_Events) 992 { 993 // If the TTL is -1 for uDNS LLQ event packet, that means "remove" 994 if (ttl == 0xFFFFFFFF) ttl = 0; 995 else ttl = kLLQ_DefLease; 996 } 997 else // else not LLQ (standard uDNS response) 998 { 999 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we 1000 // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL 1001 if (ttl > 0x60000000UL / mDNSPlatformOneSecond) ttl = 0x60000000UL / mDNSPlatformOneSecond; 1002 1003 ttl = RRAdjustTTL(ttl); 1004 1005 // For mDNS, TTL zero means "delete this record" 1006 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it. 1007 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds. 1008 // This means that we'll do our 80, 85, 90, 95% queries at 12.00, 12.75, 13.50, 14.25 seconds 1009 // respectively, and then if we get no response, delete the record from the cache at 15 seconds. 1010 // This gives the server up to three seconds to respond between when we send our 80% query at 12 seconds 1011 // and when we delete the record at 15 seconds. Allowing cache lifetimes less than 15 seconds would 1012 // (with the current code) result in the server having even less than three seconds to respond 1013 // before we deleted the record and reported a "remove" event to any active questions. 1014 // Furthermore, with the current code, if we were to allow a TTL of less than 2 seconds 1015 // then things really break (e.g. we end up making a negative cache entry). 1016 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers. 1017 if (ttl < 15) ttl = 15; 1018 } 1019 1020 return ttl; 1021 } 1022 1023 // *************************************************************************** 1024 // MARK: - Domain Name Utility Functions 1025 1026 1027 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b) 1028 { 1029 int i; 1030 const int len = *a++; 1031 1032 if (len > MAX_DOMAIN_LABEL) 1033 { debugf("Malformed label (too long)"); return(mDNSfalse); } 1034 1035 if (len != *b++) return(mDNSfalse); 1036 for (i=0; i<len; i++) 1037 { 1038 mDNSu8 ac = *a++; 1039 mDNSu8 bc = *b++; 1040 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A'; 1041 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A'; 1042 if (ac != bc) return(mDNSfalse); 1043 } 1044 return(mDNStrue); 1045 } 1046 1047 1048 mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2) 1049 { 1050 return(SameDomainNameBytes(d1->c, d2->c)); 1051 } 1052 1053 mDNSexport mDNSBool SameDomainNameBytes(const mDNSu8 *const d1, const mDNSu8 *const d2) 1054 { 1055 const mDNSu8 * a = d1; 1056 const mDNSu8 * b = d2; 1057 const mDNSu8 *const max = d1 + MAX_DOMAIN_NAME; // Maximum that's valid 1058 1059 while (*a || *b) 1060 { 1061 if (a + 1 + *a >= max) 1062 { debugf("Malformed domain name (more than 256 characters)"); return(mDNSfalse); } 1063 if (!SameDomainLabel(a, b)) return(mDNSfalse); 1064 a += 1 + *a; 1065 b += 1 + *b; 1066 } 1067 1068 return(mDNStrue); 1069 } 1070 1071 mDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2) 1072 { 1073 mDNSu16 l1 = DomainNameLength(d1); 1074 mDNSu16 l2 = DomainNameLength(d2); 1075 return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1)); 1076 } 1077 1078 mDNSexport mDNSBool IsSubdomain(const domainname *const subdomain, const domainname *const domain) 1079 { 1080 mDNSBool isSubdomain = mDNSfalse; 1081 const int subdomainLabelCount = CountLabels(subdomain); 1082 const int domainLabelCount = CountLabels(domain); 1083 1084 if (subdomainLabelCount >= domainLabelCount) 1085 { 1086 const domainname *const parentDomain = SkipLeadingLabels(subdomain, subdomainLabelCount - domainLabelCount); 1087 isSubdomain = SameDomainName(parentDomain, domain); 1088 } 1089 1090 return isSubdomain; 1091 } 1092 1093 mDNSexport mDNSBool IsLocalDomain(const domainname *d) 1094 { 1095 // Domains that are defined to be resolved via link-local multicast are: 1096 // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa. 1097 static const domainname *nL = (const domainname*)"\x5" "local"; 1098 static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa"; 1099 static const domainname *n8 = (const domainname*)"\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 1100 static const domainname *n9 = (const domainname*)"\x1" "9" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 1101 static const domainname *nA = (const domainname*)"\x1" "a" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 1102 static const domainname *nB = (const domainname*)"\x1" "b" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 1103 1104 const domainname *d1, *d2, *d3, *d4, *d5; // Top-level domain, second-level domain, etc. 1105 d1 = d2 = d3 = d4 = d5 = mDNSNULL; 1106 while (d->c[0]) 1107 { 1108 d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d; 1109 d = (const domainname*)(d->c + 1 + d->c[0]); 1110 } 1111 1112 if (d1 && SameDomainName(d1, nL)) return(mDNStrue); 1113 if (d4 && SameDomainName(d4, nR)) return(mDNStrue); 1114 if (d5 && SameDomainName(d5, n8)) return(mDNStrue); 1115 if (d5 && SameDomainName(d5, n9)) return(mDNStrue); 1116 if (d5 && SameDomainName(d5, nA)) return(mDNStrue); 1117 if (d5 && SameDomainName(d5, nB)) return(mDNStrue); 1118 return(mDNSfalse); 1119 } 1120 1121 mDNSexport mDNSBool IsRootDomain(const domainname *const d) 1122 { 1123 return (d->c[0] == 0); 1124 } 1125 1126 mDNSexport const mDNSu8 *LastLabel(const domainname *d) 1127 { 1128 const mDNSu8 *p = d->c; 1129 while (d->c[0]) 1130 { 1131 p = d->c; 1132 d = (const domainname*)(d->c + 1 + d->c[0]); 1133 } 1134 return(p); 1135 } 1136 1137 // Returns length of a domain name INCLUDING the byte for the final null label 1138 // e.g. for the root label "." it returns one 1139 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero) 1140 // Legal results are 1 (just root label) to 256 (MAX_DOMAIN_NAME) 1141 // If the given domainname is invalid, result is 257 (MAX_DOMAIN_NAME+1) 1142 mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *const limit) 1143 { 1144 return(DomainNameBytesLength(name->c, limit)); 1145 } 1146 1147 mDNSexport mDNSu16 DomainNameBytesLength(const mDNSu8 *const name, const mDNSu8 *const limit) 1148 { 1149 const mDNSu8 *src = name; 1150 while ((!limit || (src < limit)) && src && (*src <= MAX_DOMAIN_LABEL)) 1151 { 1152 if (*src == 0) return((mDNSu16)(src - name + 1)); 1153 src += 1 + *src; 1154 } 1155 return(MAX_DOMAIN_NAME+1); 1156 } 1157 1158 mDNSexport mDNSu8 DomainLabelLength(const domainlabel *const label) 1159 { 1160 return label->c[0]; 1161 } 1162 1163 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte 1164 // for the final null label, e.g. for the root label "." it returns one. 1165 // E.g. for the FQDN "foo.com." it returns 9 1166 // (length, three data bytes, length, three more data bytes, final zero). 1167 // In the case where a parent domain name is provided, and the given name is a child 1168 // of that parent, CompressedDomainNameLength returns the length of the prefix portion 1169 // of the child name, plus TWO bytes for the compression pointer. 1170 // E.g. for the name "foo.com." with parent "com.", it returns 6 1171 // (length, three data bytes, two-byte compression pointer). 1172 mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent) 1173 { 1174 const mDNSu8 *src = name->c; 1175 if (parent && parent->c[0] == 0) parent = mDNSNULL; 1176 while (*src) 1177 { 1178 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1); 1179 if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2)); 1180 src += 1 + *src; 1181 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1); 1182 } 1183 return((mDNSu16)(src - name->c + 1)); 1184 } 1185 1186 // CountLabels() returns number of labels in name, excluding final root label 1187 // (e.g. for "apple.com." CountLabels returns 2.) 1188 mDNSexport int CountLabels(const domainname *d) 1189 { 1190 int count = 0; 1191 const mDNSu8 *ptr; 1192 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++; 1193 return count; 1194 } 1195 1196 // SkipLeadingLabels skips over the first 'skip' labels in the domainname, 1197 // returning a pointer to the suffix with 'skip' labels removed. 1198 mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip) 1199 { 1200 while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; } 1201 return(d); 1202 } 1203 1204 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname. 1205 // The C string contains the label as-is, with no escaping, etc. 1206 // Any dots in the name are literal dots, not label separators 1207 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte 1208 // in the domainname bufer (i.e. the next byte after the terminating zero). 1209 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 1210 // AppendLiteralLabelString returns mDNSNULL. 1211 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr) 1212 { 1213 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name 1214 const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) 1215 const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL; 1216 const mDNSu8 *const lim = (lim1 < lim2) ? lim1 : lim2; 1217 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go 1218 1219 while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++; // Copy the data 1220 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte 1221 *ptr++ = 0; // Put the null root label on the end 1222 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input 1223 else return(ptr); // Success: return new value of ptr 1224 } 1225 1226 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname. 1227 // The C string is in conventional DNS syntax: 1228 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots. 1229 // If successful, AppendDNSNameString returns a pointer to the next unused byte 1230 // in the domainname bufer (i.e. the next byte after the terminating zero). 1231 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 1232 // AppendDNSNameString returns mDNSNULL. 1233 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring) 1234 { 1235 const char * cstr = cstring; 1236 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name 1237 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) 1238 if (cstr[0] == '.' && cstr[1] == '\0') cstr++; // If the domain to be appended is root domain, skip it. 1239 while (*cstr && ptr < lim) // While more characters, and space to put them... 1240 { 1241 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go 1242 if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); } 1243 while (*cstr && *cstr != '.' && ptr < lim) // While we have characters in the label... 1244 { 1245 mDNSu8 c = (mDNSu8)*cstr++; // Read the character 1246 if (c == '\\') // If escape character, check next character 1247 { 1248 if (*cstr == '\0') break; // If this is the end of the string, then break 1249 c = (mDNSu8)*cstr++; // Assume we'll just take the next character 1250 if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1])) 1251 { // If three decimal digits, 1252 int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal 1253 int v1 = cstr[ 0] - '0'; 1254 int v2 = cstr[ 1] - '0'; 1255 int val = v0 * 100 + v1 * 10 + v2; 1256 if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it 1257 } 1258 } 1259 *ptr++ = c; // Write the character 1260 } 1261 if (*cstr == '.') cstr++; // Skip over the trailing dot (if present) 1262 if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort 1263 return(mDNSNULL); 1264 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte 1265 } 1266 1267 *ptr++ = 0; // Put the null root label on the end 1268 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input 1269 else return(ptr); // Success: return new value of ptr 1270 } 1271 1272 // AppendDomainLabel appends a single label to a name. 1273 // If successful, AppendDomainLabel returns a pointer to the next unused byte 1274 // in the domainname bufer (i.e. the next byte after the terminating zero). 1275 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 1276 // AppendDomainLabel returns mDNSNULL. 1277 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label) 1278 { 1279 int i; 1280 mDNSu8 *ptr = name->c + DomainNameLength(name) - 1; 1281 1282 // Check label is legal 1283 if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL); 1284 1285 // Check that ptr + length byte + data bytes + final zero does not exceed our limit 1286 if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL); 1287 1288 for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i]; // Copy the label data 1289 *ptr++ = 0; // Put the null root label on the end 1290 return(ptr); 1291 } 1292 1293 mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append) 1294 { 1295 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name 1296 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) 1297 const mDNSu8 * src = append->c; 1298 while (src[0]) 1299 { 1300 int i; 1301 if (ptr + 1 + src[0] > lim) return(mDNSNULL); 1302 for (i=0; i<=src[0]; i++) *ptr++ = src[i]; 1303 *ptr = 0; // Put the null root label on the end 1304 src += i; 1305 } 1306 return(ptr); 1307 } 1308 1309 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping). 1310 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue. 1311 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then 1312 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse. 1313 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored. 1314 // In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result. 1315 mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr) 1316 { 1317 mDNSu8 * ptr = label->c + 1; // Where we're putting it 1318 const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL; // The maximum we can put 1319 while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++; // Copy the label 1320 label->c[0] = (mDNSu8)(ptr - label->c - 1); // Set the length byte 1321 return(*cstr == 0); // Return mDNStrue if we successfully consumed all input 1322 } 1323 1324 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string. 1325 // The C string is in conventional DNS syntax: 1326 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots. 1327 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte 1328 // in the domainname bufer (i.e. the next byte after the terminating zero). 1329 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 1330 // MakeDomainNameFromDNSNameString returns mDNSNULL. 1331 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr) 1332 { 1333 name->c[0] = 0; // Make an empty domain name 1334 return(AppendDNSNameString(name, cstr)); // And then add this string to it 1335 } 1336 1337 mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc) 1338 { 1339 const mDNSu8 * src = label->c; // Domain label we're reading 1340 const mDNSu8 len = *src++; // Read length of this (non-null) label 1341 const mDNSu8 *const end = src + len; // Work out where the label ends 1342 if (len > MAX_DOMAIN_LABEL) return(mDNSNULL); // If illegal label, abort 1343 while (src < end) // While we have characters in the label 1344 { 1345 mDNSu8 c = *src++; 1346 if (esc) 1347 { 1348 if (c == '.' || c == esc) // If character is a dot or the escape character 1349 *ptr++ = esc; // Output escape character 1350 else if (c <= ' ') // If non-printing ascii, 1351 { // Output decimal escape sequence 1352 *ptr++ = esc; 1353 *ptr++ = (char) ('0' + (c / 100) ); 1354 *ptr++ = (char) ('0' + (c / 10) % 10); 1355 c = (mDNSu8)('0' + (c ) % 10); 1356 } 1357 } 1358 *ptr++ = (char)c; // Copy the character 1359 } 1360 *ptr = 0; // Null-terminate the string 1361 return(ptr); // and return 1362 } 1363 1364 // Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1009 bytes) 1365 mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc) 1366 { 1367 const mDNSu8 *src = name->c; // Domain name we're reading 1368 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid 1369 1370 if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot 1371 1372 while (*src) // While more characters in the domain name 1373 { 1374 if (src + 1 + *src >= max) return(mDNSNULL); 1375 ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc); 1376 if (!ptr) return(mDNSNULL); 1377 src += 1 + *src; 1378 *ptr++ = '.'; // Write the dot after the label 1379 } 1380 1381 *ptr++ = 0; // Null-terminate the string 1382 return(ptr); // and return 1383 } 1384 1385 // RFC 1034 rules: 1386 // Host names must start with a letter, end with a letter or digit, 1387 // and have as interior characters only letters, digits, and hyphen. 1388 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit 1389 1390 mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel) 1391 { 1392 const mDNSu8 * src = &UTF8Name[1]; 1393 const mDNSu8 *const end = &UTF8Name[1] + UTF8Name[0]; 1394 mDNSu8 * ptr = &hostlabel->c[1]; 1395 const mDNSu8 *const lim = &hostlabel->c[1] + MAX_DOMAIN_LABEL; 1396 while (src < end) 1397 { 1398 // Delete apostrophes from source name 1399 if (src[0] == '\'') { src++; continue; } // Standard straight single quote 1400 if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99) 1401 { src += 3; continue; } // Unicode curly apostrophe 1402 if (ptr < lim) 1403 { 1404 if (mDNSValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src; 1405 else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-'; 1406 } 1407 src++; 1408 } 1409 while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks 1410 hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]); 1411 } 1412 1413 mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, 1414 const domainlabel *name, const domainname *type, const domainname *const domain) 1415 { 1416 int i, len; 1417 mDNSu8 *dst = fqdn->c; 1418 const mDNSu8 *src; 1419 const char *errormsg; 1420 1421 // In the case where there is no name (and ONLY in that case), 1422 // a single-label subtype is allowed as the first label of a three-part "type" 1423 if (!name) 1424 { 1425 const mDNSu8 *s0 = type->c; 1426 if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63) 1427 { 1428 const mDNSu8 * s1 = s0 + 1 + s0[0]; 1429 if (s1[0] && s1[0] < 0x40) // and legal second label (at least one character, and no more than 63) 1430 { 1431 const mDNSu8 *s2 = s1 + 1 + s1[0]; 1432 if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0) // and we have three and only three labels 1433 { 1434 static const mDNSu8 SubTypeLabel[5] = mDNSSubTypeLabel; 1435 src = s0; // Copy the first label 1436 len = *src; 1437 for (i=0; i <= len; i++) *dst++ = *src++; 1438 for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i]; 1439 type = (const domainname *)s1; 1440 1441 // Special support to enable the DNSServiceBrowse call made by Bonjour Browser 1442 // For these queries, we retract the "._sub" we just added between the subtype and the main type 1443 // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse 1444 if (SameDomainName((const domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp")) 1445 dst -= sizeof(SubTypeLabel); 1446 } 1447 } 1448 } 1449 } 1450 1451 if (name && name->c[0]) 1452 { 1453 src = name->c; // Put the service name into the domain name 1454 len = *src; 1455 if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; } 1456 for (i=0; i<=len; i++) *dst++ = *src++; 1457 } 1458 else 1459 name = (domainlabel*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below 1460 1461 src = type->c; // Put the service type into the domain name 1462 len = *src; 1463 if (len < 2 || len > 16) 1464 { 1465 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Bad service type in " PRI_DM_LABEL "." PRI_DM_NAME PRI_DM_NAME" Application protocol name must be " 1466 "underscore plus 1-15 characters. See <http://www.dns-sd.org/ServiceTypes.html>", 1467 DM_LABEL_PARAM(name), DM_NAME_PARAM(type), DM_NAME_PARAM(domain)); 1468 } 1469 if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL); 1470 if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; } 1471 for (i=2; i<=len; i++) 1472 { 1473 // Letters and digits are allowed anywhere 1474 if (mDNSIsLetter(src[i]) || mDNSIsDigit(src[i])) continue; 1475 // Hyphens are only allowed as interior characters 1476 // Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them, 1477 // with the same rule as hyphens 1478 if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) 1479 { 1480 continue; 1481 } 1482 errormsg = "Application protocol name must contain only letters, digits, and hyphens"; 1483 goto fail; 1484 } 1485 for (i=0; i<=len; i++) *dst++ = *src++; 1486 1487 len = *src; 1488 if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; } 1489 for (i=0; i<=len; i++) *dst++ = *src++; 1490 1491 if (*src) { errormsg = "Service type must have only two labels"; goto fail; } 1492 1493 *dst = 0; 1494 if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; } 1495 if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa")) 1496 { errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; } 1497 dst = AppendDomainName(fqdn, domain); 1498 if (!dst) { errormsg = "Service domain too long"; goto fail; } 1499 return(dst); 1500 1501 fail: 1502 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "ConstructServiceName: " PUB_S ": " PRI_DM_LABEL "." PRI_DM_NAME PRI_DM_NAME , errormsg, 1503 DM_LABEL_PARAM(name), DM_NAME_PARAM(type), DM_NAME_PARAM(domain)); 1504 return(mDNSNULL); 1505 } 1506 1507 // A service name has the form: instance.application-protocol.transport-protocol.domain 1508 // DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character 1509 // set or length limits for the protocol names, and the final domain is allowed to be empty. 1510 // However, if the given FQDN doesn't contain at least three labels, 1511 // DeconstructServiceName will reject it and return mDNSfalse. 1512 mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn, 1513 domainlabel *const name, domainname *const type, domainname *const domain) 1514 { 1515 int i, len; 1516 const mDNSu8 *src = fqdn->c; 1517 const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME; 1518 mDNSu8 *dst; 1519 1520 dst = name->c; // Extract the service name 1521 len = *src; 1522 if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); } 1523 if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); } 1524 for (i=0; i<=len; i++) *dst++ = *src++; 1525 1526 dst = type->c; // Extract the service type 1527 len = *src; 1528 if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); } 1529 if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); } 1530 if (src[1] != '_') { debugf("DeconstructServiceName: No _ at start of application protocol"); return(mDNSfalse); } 1531 for (i=0; i<=len; i++) *dst++ = *src++; 1532 1533 len = *src; 1534 if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); } 1535 if (!ValidTransportProtocol(src)) 1536 { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); } 1537 for (i=0; i<=len; i++) *dst++ = *src++; 1538 *dst++ = 0; // Put terminator on the end of service type 1539 1540 dst = domain->c; // Extract the service domain 1541 while (*src) 1542 { 1543 len = *src; 1544 if (len >= 0x40) 1545 { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); } 1546 if (src + 1 + len + 1 >= max) 1547 { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); } 1548 for (i=0; i<=len; i++) *dst++ = *src++; 1549 } 1550 *dst++ = 0; // Put the null root label on the end 1551 1552 return(mDNStrue); 1553 } 1554 1555 mDNSexport mStatus DNSNameToLowerCase(domainname *d, domainname *result) 1556 { 1557 const mDNSu8 *a = d->c; 1558 mDNSu8 *b = result->c; 1559 const mDNSu8 *const max = d->c + MAX_DOMAIN_NAME; 1560 int i, len; 1561 1562 while (*a) 1563 { 1564 if (a + 1 + *a >= max) 1565 { 1566 LogMsg("DNSNameToLowerCase: ERROR!! Malformed Domain name"); 1567 return mStatus_BadParamErr; 1568 } 1569 len = *a++; 1570 *b++ = len; 1571 for (i = 0; i < len; i++) 1572 { 1573 mDNSu8 ac = *a++; 1574 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A'; 1575 *b++ = ac; 1576 } 1577 } 1578 *b = 0; 1579 1580 return mStatus_NoError; 1581 } 1582 1583 // Notes on UTF-8: 1584 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F 1585 // 10xxxxxx is a continuation byte of a multi-byte character 1586 // 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x 80 - 0x 800-1) 1587 // 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x 800 - 0x 10000-1) 1588 // 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x 10000 - 0x 200000-1) 1589 // 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1) 1590 // 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1) 1591 // 1592 // UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF. 1593 // Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive 1594 // about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?") 1595 // The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8), 1596 // and the second is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8). 1597 1598 mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max) 1599 { 1600 if (length > max) 1601 { 1602 mDNSu8 c1 = string[max]; // First byte after cut point 1603 mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0; // Second byte after cut point 1604 length = max; // Trim length down 1605 while (length > 0) 1606 { 1607 // Check if the byte right after the chop point is a UTF-8 continuation byte, 1608 // or if the character right after the chop point is the second of a UTF-16 surrogate pair. 1609 // If so, then we continue to chop more bytes until we get to a legal chop point. 1610 mDNSBool continuation = ((c1 & 0xC0) == 0x80); 1611 mDNSBool secondsurrogate = (c1 == 0xED && (c2 & 0xF0) == 0xB0); 1612 if (!continuation && !secondsurrogate) break; 1613 c2 = c1; 1614 c1 = string[--length]; 1615 } 1616 // Having truncated characters off the end of our string, also cut off any residual white space 1617 while (length > 0 && string[length-1] <= ' ') length--; 1618 } 1619 return(length); 1620 } 1621 1622 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034 1623 // name ends in "-nnn", where n is some decimal number. 1624 mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText) 1625 { 1626 mDNSu16 l = name->c[0]; 1627 1628 if (RichText) 1629 { 1630 if (l < 4) return mDNSfalse; // Need at least " (2)" 1631 if (name->c[l--] != ')') return mDNSfalse; // Last char must be ')' 1632 if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit 1633 l--; 1634 while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits 1635 return (name->c[l] == '(' && name->c[l - 1] == ' '); 1636 } 1637 else 1638 { 1639 if (l < 2) return mDNSfalse; // Need at least "-2" 1640 if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit 1641 l--; 1642 while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits 1643 return (name->c[l] == '-'); 1644 } 1645 } 1646 1647 // removes an auto-generated suffix (appended on a name collision) from a label. caller is 1648 // responsible for ensuring that the label does indeed contain a suffix. returns the number 1649 // from the suffix that was removed. 1650 mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText) 1651 { 1652 mDNSu32 val = 0, multiplier = 1; 1653 1654 // Chop closing parentheses from RichText suffix 1655 if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--; 1656 1657 // Get any existing numerical suffix off the name 1658 while (mDNSIsDigit(name->c[name->c[0]])) 1659 { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; } 1660 1661 // Chop opening parentheses or dash from suffix 1662 if (RichText) 1663 { 1664 if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2; 1665 } 1666 else 1667 { 1668 if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1; 1669 } 1670 1671 return(val); 1672 } 1673 1674 // appends a numerical suffix to a label, with the number following a whitespace and enclosed 1675 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label). 1676 mDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText) 1677 { 1678 mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2") 1679 if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)") 1680 1681 // Truncate trailing spaces from RichText names 1682 if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--; 1683 1684 while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; } 1685 1686 name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars); 1687 1688 if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; } 1689 else { name->c[++name->c[0]] = '-'; } 1690 1691 while (divisor) 1692 { 1693 name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor); 1694 val %= divisor; 1695 divisor /= 10; 1696 } 1697 1698 if (RichText) name->c[++name->c[0]] = ')'; 1699 } 1700 1701 mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText) 1702 { 1703 mDNSu32 val = 0; 1704 1705 if (LabelContainsSuffix(name, RichText)) 1706 val = RemoveLabelSuffix(name, RichText); 1707 1708 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate. 1709 // If existing suffix in the range 2-9, increment it. 1710 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name, 1711 // so add a random increment to improve the chances of finding an available name next time. 1712 if (val == 0) val = 2; 1713 else if (val < 10) val++; 1714 else val += 1 + mDNSRandom(99); 1715 1716 AppendLabelSuffix(name, val, RichText); 1717 } 1718 1719 // *************************************************************************** 1720 // MARK: - Resource Record Utility Functions 1721 1722 // Set up a AuthRecord with sensible default values. 1723 // These defaults may be overwritten with new values before mDNS_Register is called 1724 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID, 1725 mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context) 1726 { 1727 // 1728 // LocalOnly auth record can be created with LocalOnly InterfaceID or a valid InterfaceID. 1729 // Most of the applications normally create with LocalOnly InterfaceID and we store them as 1730 // such, so that we can deliver the response to questions that specify LocalOnly InterfaceID. 1731 // LocalOnly resource records can also be created with valid InterfaceID which happens today 1732 // when we create LocalOnly records for /etc/hosts. 1733 1734 if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly) 1735 { 1736 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d", 1737 InterfaceID, artype); 1738 } 1739 else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P) 1740 { 1741 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d", 1742 InterfaceID, artype); 1743 } 1744 else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly)) 1745 { 1746 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d", 1747 InterfaceID, artype); 1748 } 1749 1750 // Don't try to store a TTL bigger than we can represent in platform time units 1751 if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond) 1752 ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond; 1753 else if (ttl == 0) // And Zero TTL is illegal 1754 ttl = DefaultTTLforRRType(rrtype); 1755 1756 // Field Group 1: The actual information pertaining to this resource record 1757 rr->resrec.RecordType = RecordType; 1758 rr->resrec.InterfaceID = InterfaceID; 1759 rr->resrec.name = &rr->namestorage; 1760 rr->resrec.rrtype = rrtype; 1761 rr->resrec.rrclass = kDNSClass_IN; 1762 rr->resrec.rroriginalttl = ttl; 1763 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 1764 rr->resrec.metadata = NULL; 1765 #else 1766 rr->resrec.rDNSServer = mDNSNULL; 1767 #endif 1768 // rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal 1769 // rr->resrec.rdestimate = set in mDNS_Register_internal 1770 // rr->resrec.rdata = MUST be set by client 1771 1772 if (RDataStorage) 1773 rr->resrec.rdata = RDataStorage; 1774 else 1775 { 1776 rr->resrec.rdata = &rr->rdatastorage; 1777 rr->resrec.rdata->MaxRDLength = sizeof(RDataBody); 1778 } 1779 1780 // Field Group 2: Persistent metadata for Authoritative Records 1781 rr->Additional1 = mDNSNULL; 1782 rr->Additional2 = mDNSNULL; 1783 rr->DependentOn = mDNSNULL; 1784 rr->RRSet = 0; 1785 rr->RecordCallback = Callback; 1786 rr->RecordContext = Context; 1787 1788 rr->AutoTarget = Target_Manual; 1789 rr->AllowRemoteQuery = mDNSfalse; 1790 rr->ForceMCast = mDNSfalse; 1791 1792 rr->WakeUp = zeroOwner; 1793 rr->AddressProxy = zeroAddr; 1794 rr->TimeRcvd = 0; 1795 rr->TimeExpire = 0; 1796 rr->ARType = artype; 1797 rr->AuthFlags = 0; 1798 1799 // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal) 1800 // Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal) 1801 1802 // For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case 1803 // (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch 1804 // of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.) 1805 rr->state = regState_Zero; 1806 rr->uselease = 0; 1807 rr->expire = 0; 1808 rr->Private = 0; 1809 rr->updateid = zeroID; 1810 rr->zone = rr->resrec.name; 1811 rr->nta = mDNSNULL; 1812 rr->tcp = mDNSNULL; 1813 rr->OrigRData = 0; 1814 rr->OrigRDLen = 0; 1815 rr->InFlightRData = 0; 1816 rr->InFlightRDLen = 0; 1817 rr->QueuedRData = 0; 1818 rr->QueuedRDLen = 0; 1819 mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); 1820 rr->SRVChanged = mDNSfalse; 1821 rr->mState = mergeState_Zero; 1822 1823 rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() 1824 } 1825 1826 mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name, 1827 const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context) 1828 { 1829 q->InterfaceID = InterfaceID; 1830 q->flags = 0; 1831 AssignDomainName(&q->qname, name); 1832 q->qtype = qtype; 1833 q->qclass = kDNSClass_IN; 1834 q->LongLived = mDNSfalse; 1835 q->ExpectUnique = (qtype != kDNSType_PTR); 1836 q->ForceMCast = mDNSfalse; 1837 q->ReturnIntermed = mDNSfalse; 1838 q->SuppressUnusable = mDNSfalse; 1839 q->AppendSearchDomains = 0; 1840 q->TimeoutQuestion = 0; 1841 q->WakeOnResolve = 0; 1842 q->UseBackgroundTraffic = mDNSfalse; 1843 q->ProxyQuestion = 0; 1844 q->pid = mDNSPlatformGetPID(); 1845 q->euid = 0; 1846 q->BlockedByPolicy = mDNSfalse; 1847 q->ServiceID = -1; 1848 q->QuestionCallback = callback; 1849 q->QuestionContext = context; 1850 } 1851 1852 mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr) 1853 { 1854 int len = rr->rdlength; 1855 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 1856 const mDNSu8 *ptr = rdb->data; 1857 mDNSu32 sum = 0; 1858 1859 switch(rr->rrtype) 1860 { 1861 case kDNSType_NS: 1862 case kDNSType_MD: 1863 case kDNSType_MF: 1864 case kDNSType_CNAME: 1865 case kDNSType_MB: 1866 case kDNSType_MG: 1867 case kDNSType_MR: 1868 case kDNSType_PTR: 1869 case kDNSType_NSAP_PTR: 1870 case kDNSType_DNAME: return DomainNameHashValue(&rdb->name); 1871 1872 case kDNSType_SOA: return rdb->soa.serial + 1873 rdb->soa.refresh + 1874 rdb->soa.retry + 1875 rdb->soa.expire + 1876 rdb->soa.min + 1877 DomainNameHashValue(&rdb->soa.mname) + 1878 DomainNameHashValue(&rdb->soa.rname); 1879 1880 case kDNSType_MX: 1881 case kDNSType_AFSDB: 1882 case kDNSType_RT: 1883 case kDNSType_KX: return DomainNameHashValue(&rdb->mx.exchange); 1884 1885 case kDNSType_MINFO: 1886 case kDNSType_RP: return DomainNameHashValue(&rdb->rp.mbox) + DomainNameHashValue(&rdb->rp.txt); 1887 1888 case kDNSType_PX: return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400); 1889 1890 case kDNSType_SRV: return DomainNameHashValue(&rdb->srv.target); 1891 1892 case kDNSType_OPT: return 0; // OPT is a pseudo-RR container structure; makes no sense to compare 1893 1894 case kDNSType_NSEC: { 1895 int dlen; 1896 dlen = DomainNameLength(&rdb->name); 1897 sum = DomainNameHashValue(&rdb->name); 1898 ptr += dlen; 1899 len -= dlen; 1900 fallthrough(); 1901 /* FALLTHROUGH */ 1902 } 1903 1904 default: 1905 { 1906 int i; 1907 for (i=0; i+1 < len; i+=2) 1908 { 1909 sum += (((mDNSu32)(ptr[i])) << 8) | ptr[i+1]; 1910 sum = (sum<<3) | (sum>>29); 1911 } 1912 if (i < len) 1913 { 1914 sum += ((mDNSu32)(ptr[i])) << 8; 1915 } 1916 return(sum); 1917 } 1918 } 1919 } 1920 1921 // r1 has to be a full ResourceRecord including rrtype and rdlength 1922 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1 1923 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename) 1924 { 1925 const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data; 1926 const RDataBody2 *const b2 = (const RDataBody2 *)r2; 1927 switch(r1->rrtype) 1928 { 1929 case kDNSType_NS: 1930 case kDNSType_MD: 1931 case kDNSType_MF: 1932 case kDNSType_CNAME: 1933 case kDNSType_MB: 1934 case kDNSType_MG: 1935 case kDNSType_MR: 1936 case kDNSType_PTR: 1937 case kDNSType_NSAP_PTR: 1938 case kDNSType_DNAME: return(SameDomainName(&b1->name, &b2->name)); 1939 1940 case kDNSType_SOA: return (mDNSBool)( b1->soa.serial == b2->soa.serial && 1941 b1->soa.refresh == b2->soa.refresh && 1942 b1->soa.retry == b2->soa.retry && 1943 b1->soa.expire == b2->soa.expire && 1944 b1->soa.min == b2->soa.min && 1945 samename(&b1->soa.mname, &b2->soa.mname) && 1946 samename(&b1->soa.rname, &b2->soa.rname)); 1947 1948 case kDNSType_MX: 1949 case kDNSType_AFSDB: 1950 case kDNSType_RT: 1951 case kDNSType_KX: return (mDNSBool)( b1->mx.preference == b2->mx.preference && 1952 samename(&b1->mx.exchange, &b2->mx.exchange)); 1953 1954 case kDNSType_MINFO: 1955 case kDNSType_RP: return (mDNSBool)( samename(&b1->rp.mbox, &b2->rp.mbox) && 1956 samename(&b1->rp.txt, &b2->rp.txt)); 1957 1958 case kDNSType_PX: return (mDNSBool)( b1->px.preference == b2->px.preference && 1959 samename(&b1->px.map822, &b2->px.map822) && 1960 samename(&b1->px.mapx400, &b2->px.mapx400)); 1961 1962 case kDNSType_SRV: return (mDNSBool)( b1->srv.priority == b2->srv.priority && 1963 b1->srv.weight == b2->srv.weight && 1964 mDNSSameIPPort(b1->srv.port, b2->srv.port) && 1965 samename(&b1->srv.target, &b2->srv.target)); 1966 1967 case kDNSType_OPT: return mDNSfalse; // OPT is a pseudo-RR container structure; makes no sense to compare 1968 case kDNSType_NSEC: { 1969 // If the "nxt" name changes in case, we want to delete the old 1970 // and store just the new one. If the caller passes in SameDomainCS for "samename", 1971 // we would return "false" when the only change between the two rdata is the case 1972 // change in "nxt". 1973 // 1974 // Note: rdlength of both the RData are same (ensured by the caller) and hence we can 1975 // use just r1->rdlength below 1976 1977 int dlen1 = DomainNameLength(&b1->name); 1978 int dlen2 = DomainNameLength(&b2->name); 1979 return (mDNSBool)(dlen1 == dlen2 && 1980 samename(&b1->name, &b2->name) && 1981 mDNSPlatformMemSame(b1->data + dlen1, b2->data + dlen2, r1->rdlength - dlen1)); 1982 } 1983 1984 default: return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength)); 1985 } 1986 } 1987 1988 mDNSexport mDNSBool BitmapTypeCheck(const mDNSu8 *bmap, int bitmaplen, mDNSu16 type) 1989 { 1990 int win, wlen; 1991 int wintype; 1992 1993 // The window that this type belongs to. NSEC has 256 windows that 1994 // comprises of 256 types. 1995 wintype = type >> 8; 1996 1997 while (bitmaplen > 0) 1998 { 1999 if (bitmaplen < 3) 2000 { 2001 LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d short", bitmaplen); 2002 return mDNSfalse; 2003 } 2004 2005 win = *bmap++; 2006 wlen = *bmap++; 2007 bitmaplen -= 2; 2008 if (bitmaplen < wlen || wlen < 1 || wlen > 32) 2009 { 2010 LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d wlen %d, win %d", bitmaplen, wlen, win); 2011 return mDNSfalse; 2012 } 2013 if (win < 0 || win >= 256) 2014 { 2015 LogInfo("BitmapTypeCheck: malformed nsec, wlen %d", wlen); 2016 return mDNSfalse; 2017 } 2018 if (win == wintype) 2019 { 2020 // First byte in the window serves 0 to 7, the next one serves 8 to 15 and so on. 2021 // Calculate the right byte offset first. 2022 int boff = (type & 0xff ) >> 3; 2023 if (wlen <= boff) 2024 return mDNSfalse; 2025 // The last three bits values 0 to 7 corresponds to bit positions 2026 // within the byte. 2027 return (bmap[boff] & (0x80 >> (type & 7))); 2028 } 2029 else 2030 { 2031 // If the windows are ordered, then we could check to see 2032 // if wintype > win and then return early. 2033 bmap += wlen; 2034 bitmaplen -= wlen; 2035 } 2036 } 2037 return mDNSfalse; 2038 } 2039 2040 // Don't call this function if the resource record is not NSEC. It will return false 2041 // which means that the type does not exist. 2042 mDNSexport mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type) 2043 { 2044 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 2045 const mDNSu8 *nsec = rdb->data; 2046 int len, bitmaplen; 2047 const mDNSu8 *bmap; 2048 2049 if (rr->rrtype != kDNSType_NSEC) return mDNSfalse; 2050 2051 len = DomainNameLength(&rdb->name); 2052 2053 bitmaplen = rr->rdlength - len; 2054 bmap = nsec + len; 2055 return (BitmapTypeCheck(bmap, bitmaplen, type)); 2056 } 2057 2058 // Don't call this function if the resource record is not NSEC. It will return false 2059 // which means that the type exists. 2060 mDNSexport mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type) 2061 { 2062 if (rr->rrtype != kDNSType_NSEC) return mDNSfalse; 2063 2064 return !RRAssertsExistence(rr, type); 2065 } 2066 2067 mDNSexport mDNSBool RRTypeAnswersQuestionType(const ResourceRecord *const rr, const mDNSu16 qtype, 2068 const RRTypeAnswersQuestionTypeFlags flags) 2069 { 2070 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 2071 // This checks if the record is what the question requires: 2072 // 1. If the question does not enable DNSSEC, either "DNSSEC to be validated" nor "DNSSEC validated" record answers it. 2073 // 2. If the question enables DNSSEC, and it is not a duplicate question, it needs both "DNSSEC to be validated" nor "DNSSEC validated" records: 2074 // a. Get "DNSSEC to be validated" to do DNSSEC validation. 2075 // b. Get "DNSSEC validated" to return to the client. 2076 // 3. If the question enables DNSSEC, and it is a duplicate question, it only needs "DNSSEC validated" records: 2077 // a. Does not need "DNSSEC to be validated" because the non-duplicate question will do the validation. 2078 // b. Get "DNSSEC validated" to return to the client. 2079 const mDNSBool requiresRRToValidate = ((flags & kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate) != 0); 2080 const mDNSBool requiresValidatedRR = ((flags & kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRValidated) != 0); 2081 if (!resource_record_answers_dnssec_question_request_type(rr, requiresRRToValidate, requiresValidatedRR)) 2082 { 2083 return mDNSfalse; 2084 } 2085 #else 2086 (void) flags; 2087 #endif 2088 2089 // OPT should not answer any questions. 2090 if (rr->rrtype == kDNSType_OPT) 2091 { 2092 return mDNSfalse; 2093 } 2094 2095 // CNAME answers any questions, except negative CNAME. (this function is not responsible to check that) 2096 if (rr->rrtype == kDNSType_CNAME) 2097 { 2098 return mDNStrue; 2099 } 2100 2101 // The most usual case where the record type matches the question type. 2102 if (rr->rrtype == qtype) 2103 { 2104 return mDNStrue; 2105 } 2106 2107 // If question asks for any DNS record type, then any record type can answer this question. 2108 if (qtype == kDNSQType_ANY) 2109 { 2110 return mDNStrue; 2111 } 2112 2113 // If the mDNS NSEC record asserts the nonexistence of the question type, then it answers the question type 2114 // negatively. 2115 if (MULTICAST_NSEC(rr) && RRAssertsNonexistence(rr, qtype)) 2116 { 2117 return mDNStrue; 2118 } 2119 2120 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 2121 // The type covered of RRSIG should match the non-duplicate DNSSEC question type, because RRSIG will be used by it 2122 // to do DNSSEC validation. 2123 if (resource_record_as_rrsig_answers_dnssec_question_type(rr, qtype)) 2124 { 2125 return mDNStrue; 2126 } 2127 #endif 2128 2129 return mDNSfalse; 2130 } 2131 2132 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 2133 mDNSlocal mDNSBool RRMatchesQuestionService(const ResourceRecord *const rr, const DNSQuestion *const q) 2134 { 2135 return mdns_cache_metadata_get_dns_service(rr->metadata) == q->dnsservice; 2136 } 2137 #endif 2138 2139 mDNSlocal mDNSBool RRIsResolvedBymDNS(const ResourceRecord *const rr) 2140 { 2141 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 2142 if (mdns_cache_metadata_get_dns_service(rr->metadata)) 2143 { 2144 return mDNSfalse; 2145 } 2146 #endif 2147 return (rr->InterfaceID != 0); 2148 } 2149 2150 // ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question. 2151 // SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call. 2152 // SameDomainName() is generally cheap when the names don't match, but expensive when they do match, 2153 // because it has to check all the way to the end of the names to be sure. 2154 // In cases where we know in advance that the names match it's especially advantageous to skip the 2155 // SameDomainName() call because that's precisely the time when it's most expensive and least useful. 2156 2157 mDNSlocal mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q) 2158 { 2159 // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records 2160 // are handled in LocalOnlyRecordAnswersQuestion 2161 if (LocalOnlyOrP2PInterface(rr->InterfaceID)) 2162 { 2163 LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID); 2164 return mDNSfalse; 2165 } 2166 if (q->Suppressed && (!q->ForceCNAMEFollows || (rr->rrtype != kDNSType_CNAME))) 2167 return mDNSfalse; 2168 2169 if (rr->InterfaceID && 2170 q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && 2171 rr->InterfaceID != q->InterfaceID) return(mDNSfalse); 2172 2173 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY) 2174 if (DNSQuestionUsesMDNSAlternativeService(q)) 2175 { 2176 if (!RRMatchesQuestionService(rr, q)) 2177 { 2178 return mDNSfalse; 2179 } 2180 } 2181 else 2182 #endif 2183 { 2184 const mDNSBool resolvedBymDNS = RRIsResolvedBymDNS(rr); 2185 mDNSBool ismDNSQuestion = mDNSOpaque16IsZero(q->TargetQID); 2186 2187 // If the record is resolved via the non-mDNS channel, the server or service used should match. 2188 if (!isAuthRecord && !resolvedBymDNS) 2189 { 2190 if (ismDNSQuestion) 2191 { 2192 return mDNSfalse; 2193 } 2194 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 2195 if (!RRMatchesQuestionService(rr, q)) return(mDNSfalse); 2196 #else 2197 const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0; 2198 const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0; 2199 if (idr != idq) return(mDNSfalse); 2200 #endif 2201 } 2202 2203 // mDNS records can only be used to answer mDNS questions. 2204 if (resolvedBymDNS && !ismDNSQuestion) 2205 { 2206 return mDNSfalse; 2207 } 2208 } 2209 2210 // CNAME answers question of any type and a negative cache record should not prevent us from querying other 2211 // valid types at the same name. 2212 if (rr->rrtype == kDNSType_CNAME && rr->RecordType == kDNSRecordTypePacketNegative && rr->rrtype != q->qtype) 2213 return mDNSfalse; 2214 2215 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. 2216 RRTypeAnswersQuestionTypeFlags flags = kRRTypeAnswersQuestionTypeFlagsNone; 2217 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 2218 // Primary DNSSEC requestor is the non-duplicate DNSSEC question that does the DNSSEC validation, therefore, it needs 2219 // the "DNSSEC to be validated" record. (It is also DNSSEC requestor, see below) 2220 if (dns_question_is_primary_dnssec_requestor(q)) 2221 { 2222 flags |= kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate; 2223 } 2224 // DNSSEC requestor is the DNSSEC question that needs DNSSEC validated result. 2225 if (dns_question_is_dnssec_requestor(q)) 2226 { 2227 flags |= kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRValidated; 2228 } 2229 #endif 2230 2231 const mDNSBool typeMatches = RRTypeAnswersQuestionType(rr, q->qtype, flags); 2232 if (!typeMatches) 2233 { 2234 return(mDNSfalse); 2235 } 2236 2237 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 2238 2239 2240 return(mDNStrue); 2241 } 2242 2243 mDNSexport mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q) 2244 { 2245 return SameNameRecordAnswersQuestion(&cr->resrec, mDNSfalse, q); 2246 } 2247 2248 mDNSlocal mDNSBool RecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q) 2249 { 2250 if (!SameNameRecordAnswersQuestion(rr, isAuthRecord, q)) 2251 return mDNSfalse; 2252 2253 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 2254 } 2255 2256 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) 2257 { 2258 return RecordAnswersQuestion(rr, mDNSfalse, q); 2259 } 2260 2261 mDNSexport mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q) 2262 { 2263 return RecordAnswersQuestion(&ar->resrec, mDNStrue, q); 2264 } 2265 2266 mDNSexport mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q) 2267 { 2268 return RecordAnswersQuestion(&cr->resrec, mDNSfalse, q); 2269 } 2270 2271 // We have a separate function to handle LocalOnly AuthRecords because they can be created with 2272 // a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike 2273 // multicast resource records (which has a valid InterfaceID) which can't be used to answer 2274 // unicast questions. ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion can't tell whether 2275 // a resource record is multicast or LocalOnly by just looking at the ResourceRecord because 2276 // LocalOnly records are truly identified by ARType in the AuthRecord. As P2P and LocalOnly record 2277 // are kept in the same hash table, we use the same function to make it easy for the callers when 2278 // they walk the hash table to answer LocalOnly/P2P questions 2279 // 2280 mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const DNSQuestion *const q) 2281 { 2282 ResourceRecord *rr = &ar->resrec; 2283 2284 // mDNSInterface_Any questions can be answered with LocalOnly/P2P records in this function. AuthRecord_Any 2285 // records are handled in ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion 2286 if (RRAny(ar)) 2287 { 2288 LogMsg("LocalOnlyRecordAnswersQuestion: ERROR!! called with regular AuthRecordAny %##s", rr->name->c); 2289 return mDNSfalse; 2290 } 2291 2292 // Questions with mDNSInterface_LocalOnly InterfaceID should be answered with all resource records that are 2293 // *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly, 2294 // mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against 2295 // the InterfaceID in the resource record. 2296 2297 if (rr->InterfaceID && 2298 q->InterfaceID != mDNSInterface_LocalOnly && 2299 ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) || 2300 (!q->InterfaceID && !LocalOnlyOrP2PInterface(rr->InterfaceID)))) return(mDNSfalse); 2301 2302 // Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records 2303 // may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set 2304 // to mDNSInterface_Any, mDNSInterface_LocalOnly or a real InterfaceID (scoped). 2305 // 2306 // 1) Question: Any, LocalOnly Record: no scope. This question should be answered with this record. 2307 // 2308 // 2) Question: Any, LocalOnly Record: scoped. This question should be answered with the record because 2309 // traditionally applications never specify scope e.g., getaddrinfo, but need to be able 2310 // to get to /etc/hosts entries. 2311 // 2312 // 3) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: no scope. This is the inverse of (2). 2313 // If we register a LocalOnly record, we need to answer a LocalOnly question. If the /etc/hosts has a 2314 // non scoped entry, it may not make sense to answer a scoped question. But we can't tell these two 2315 // cases apart. As we currently answer LocalOnly question with LocalOnly record, we continue to do so. 2316 // 2317 // 4) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: scoped. LocalOnly questions should be 2318 // answered with any resource record where as if it has a valid InterfaceID, the scope should match. 2319 // 2320 // (1) and (2) is bypassed because we check for a non-NULL InterfaceID above. For (3), the InterfaceID is NULL 2321 // and hence bypassed above. For (4) we bypassed LocalOnly questions and checked the scope of the record 2322 // against the question. 2323 // 2324 // For P2P, InterfaceIDs of the question and the record should match. 2325 2326 // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question. 2327 // LocalOnly authoritative answers are exempt. LocalOnly authoritative answers are used for /etc/host entries. 2328 // We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com" which would then 2329 // cause other applications (e.g. Safari) to connect to the wrong address. The rpc to register records filters out records 2330 // with names that don't end in local and have mDNSInterface_LocalOnly set. 2331 // 2332 // Note: The check is bypassed for LocalOnly and for P2P it is not needed as only .local records are registered and for 2333 // a question to match its names, it also has to end in .local and that question can't be a unicast question (See 2334 // Question_uDNS macro and its usage). As P2P does not enforce .local only registrations we still make this check 2335 // and also makes it future proof. 2336 2337 if (ar->ARType != AuthRecordLocalOnly && rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); 2338 2339 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 2340 // No local only record can answer DNSSEC question. 2341 if (dns_question_is_dnssec_requestor(q)) 2342 { 2343 return mDNSfalse; 2344 } 2345 #endif 2346 2347 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. 2348 RRTypeAnswersQuestionTypeFlags flags = kRRTypeAnswersQuestionTypeFlagsNone; 2349 const mDNSBool typeMatches = RRTypeAnswersQuestionType(rr, q->qtype, flags); 2350 if (!typeMatches) 2351 { 2352 return mDNSfalse; 2353 } 2354 2355 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 2356 2357 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 2358 } 2359 2360 mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q) 2361 { 2362 const ResourceRecord *const rr = &ar->resrec; 2363 // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records 2364 // are handled in LocalOnlyRecordAnswersQuestion 2365 if (LocalOnlyOrP2PInterface(rr->InterfaceID)) 2366 { 2367 LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID); 2368 return mDNSfalse; 2369 } 2370 if (rr->InterfaceID && 2371 q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && 2372 rr->InterfaceID != q->InterfaceID) return(mDNSfalse); 2373 2374 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY) 2375 if (DNSQuestionUsesMDNSAlternativeService(q)) 2376 { 2377 if (!RRMatchesQuestionService(rr, q)) 2378 { 2379 return mDNSfalse; 2380 } 2381 } 2382 else 2383 #endif 2384 { 2385 const mDNSBool resolvedByMDNS = RRIsResolvedBymDNS(rr); 2386 // Resource record received via non-mDNS channel, the server or service should match. 2387 // Note that Auth Records are normally setup with NULL InterfaceID and 2388 // both the DNSServers are assumed to be NULL in that case 2389 if (!resolvedByMDNS) 2390 { 2391 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 2392 if (!RRMatchesQuestionService(rr, q)) return(mDNSfalse); 2393 #else 2394 const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0; 2395 const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0; 2396 if (idr != idq) return(mDNSfalse); 2397 #endif 2398 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) 2399 if (!mDNSPlatformValidRecordForInterface(ar, q->InterfaceID)) return(mDNSfalse); 2400 #endif 2401 } 2402 2403 // mDNS records can only be used to answer mDNS questions. 2404 const mDNSBool isMDNSQuestion = mDNSOpaque16IsZero(q->TargetQID); 2405 if (resolvedByMDNS && !isMDNSQuestion) 2406 { 2407 return mDNSfalse; 2408 } 2409 } 2410 2411 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 2412 2413 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 2414 } 2415 2416 // This is called with both unicast resource record and multicast resource record. The question that 2417 // received the unicast response could be the regular unicast response from a DNS server or a response 2418 // to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the 2419 // question and the resource record because the resource record is not completely initialized in 2420 // mDNSCoreReceiveResponse when this function is called. 2421 mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q) 2422 { 2423 if (q->Suppressed) 2424 return mDNSfalse; 2425 2426 // For resource records created using multicast or DNS push, the InterfaceIDs have to match. 2427 if (rr->InterfaceID && 2428 q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse); 2429 2430 // If record is resolved by mDNS, but question is non-mDNS, then should not use it to answer this question. 2431 const mDNSBool resolvedByMDNS = RRIsResolvedBymDNS(rr); 2432 const mDNSBool isMDNSQuestion = mDNSOpaque16IsZero(q->TargetQID); 2433 if (resolvedByMDNS && !isMDNSQuestion) 2434 { 2435 return mDNSfalse; 2436 } 2437 2438 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. 2439 RRTypeAnswersQuestionTypeFlags flags = kRRTypeAnswersQuestionTypeFlagsNone; 2440 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 2441 // Thus routine is only used for the records received from internet. Right now, we will not receive DNSSEC validated 2442 // record from wire (ODoH will probably give us validated records in the future?). Therefore, we only need to check 2443 // if the record answers primary DNSSEC requestor and can be used for validation. 2444 if (dns_question_is_primary_dnssec_requestor(q)) 2445 { 2446 flags |= kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate; 2447 } 2448 #endif 2449 2450 const mDNSBool typeMatches = RRTypeAnswersQuestionType(rr, q->qtype, flags); 2451 if (!typeMatches) 2452 { 2453 return(mDNSfalse); 2454 } 2455 2456 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 2457 2458 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 2459 } 2460 2461 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate) 2462 { 2463 const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data; 2464 const domainname *const name = estimate ? rr->name : mDNSNULL; 2465 if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength); // Used in update packets to mean "Delete An RRset" (RFC 2136) 2466 else switch (rr->rrtype) 2467 { 2468 case kDNSType_A: return(sizeof(rd->ipv4)); 2469 2470 case kDNSType_NS: 2471 case kDNSType_CNAME: 2472 case kDNSType_PTR: 2473 case kDNSType_DNAME: return(CompressedDomainNameLength(&rd->name, name)); 2474 2475 case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) + 2476 CompressedDomainNameLength(&rd->soa.rname, name) + 2477 5 * sizeof(mDNSOpaque32)); 2478 2479 case kDNSType_NULL: 2480 case kDNSType_TSIG: 2481 case kDNSType_TXT: 2482 case kDNSType_X25: 2483 case kDNSType_ISDN: 2484 case kDNSType_LOC: 2485 case kDNSType_DHCID: return(rr->rdlength); // Not self-describing, so have to just trust rdlength 2486 2487 case kDNSType_HINFO: return (mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]); 2488 2489 case kDNSType_MX: 2490 case kDNSType_AFSDB: 2491 case kDNSType_RT: 2492 case kDNSType_KX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name)); 2493 2494 case kDNSType_MINFO: 2495 case kDNSType_RP: return (mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) + 2496 CompressedDomainNameLength(&rd->rp.txt, name)); 2497 2498 case kDNSType_PX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) + 2499 CompressedDomainNameLength(&rd->px.mapx400, name)); 2500 2501 case kDNSType_AAAA: return(sizeof(rd->ipv6)); 2502 2503 case kDNSType_SRV: return (mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name)); 2504 2505 case kDNSType_OPT: return(rr->rdlength); 2506 2507 case kDNSType_NSEC: 2508 { 2509 const domainname *const next = (const domainname *)rd->data; 2510 const int dlen = DomainNameLength(next); 2511 if (MULTICAST_NSEC(rr)) 2512 { 2513 return (mDNSu16)((estimate ? 2 : dlen) + rr->rdlength - dlen); 2514 } 2515 else 2516 { 2517 // Unicast NSEC does not do name compression. Therefore, we can return `rdlength` directly. 2518 // See [RFC 4034 4.1.1.](https://datatracker.ietf.org/doc/html/rfc4034#section-4.1.1). 2519 return rr->rdlength; 2520 } 2521 } 2522 2523 case kDNSType_TSR: return(sizeof(rd->tsr_value)); 2524 2525 default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype); 2526 return(rr->rdlength); 2527 } 2528 } 2529 2530 // When a local client registers (or updates) a record, we use this routine to do some simple validation checks 2531 // to help reduce the risk of bogus malformed data on the network 2532 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd) 2533 { 2534 mDNSu16 len; 2535 2536 switch(rrtype) 2537 { 2538 case kDNSType_A: return(rdlength == sizeof(mDNSv4Addr)); 2539 2540 case kDNSType_NS: // Same as PTR 2541 case kDNSType_MD: // Same as PTR 2542 case kDNSType_MF: // Same as PTR 2543 case kDNSType_CNAME: // Same as PTR 2544 //case kDNSType_SOA not checked 2545 case kDNSType_MB: // Same as PTR 2546 case kDNSType_MG: // Same as PTR 2547 case kDNSType_MR: // Same as PTR 2548 //case kDNSType_NULL not checked (no specified format, so always valid) 2549 //case kDNSType_WKS not checked 2550 case kDNSType_PTR: len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength); 2551 return(len <= MAX_DOMAIN_NAME && rdlength == len); 2552 2553 case kDNSType_HINFO: // Same as TXT (roughly) 2554 case kDNSType_MINFO: // Same as TXT (roughly) 2555 case kDNSType_TXT: if (!rdlength) return(mDNSfalse); // TXT record has to be at least one byte (RFC 1035) 2556 { 2557 const mDNSu8 *ptr = rd->u.txt.c; 2558 const mDNSu8 *end = rd->u.txt.c + rdlength; 2559 while (ptr < end) ptr += 1 + ptr[0]; 2560 return (ptr == end); 2561 } 2562 2563 case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr)); 2564 2565 case kDNSType_MX: // Must be at least two-byte preference, plus domainname 2566 // Call to DomainNameLengthLimit() implicitly enforces both requirements for us 2567 len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength); 2568 return(len <= MAX_DOMAIN_NAME && rdlength == 2+len); 2569 2570 case kDNSType_SRV: // Must be at least priority+weight+port, plus domainname 2571 // Call to DomainNameLengthLimit() implicitly enforces both requirements for us 2572 len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength); 2573 return(len <= MAX_DOMAIN_NAME && rdlength == 6+len); 2574 2575 //case kDNSType_NSEC not checked 2576 2577 default: return(mDNStrue); // Allow all other types without checking 2578 } 2579 } 2580 2581 mDNSexport const mDNSu8 * ResourceRecordGetRDataBytesPointer(const ResourceRecord *const rr, 2582 mDNSu8 * const bytesBuffer, const mDNSu16 bufferSize, mDNSu16 *const outRDataLen, mStatus *const outError) 2583 { 2584 mStatus err; 2585 const mDNSu8 *rdataBytes = mDNSNULL; 2586 mDNSu16 rdataLen = 0; 2587 switch (rr->rrtype) 2588 { 2589 case kDNSType_SOA: 2590 case kDNSType_MX: 2591 case kDNSType_AFSDB: 2592 case kDNSType_RT: 2593 case kDNSType_RP: 2594 case kDNSType_SRV: 2595 case kDNSType_PX: 2596 case kDNSType_KX: 2597 case kDNSType_OPT: 2598 case kDNSType_NSEC: 2599 case kDNSType_TSR: 2600 { 2601 const mDNSu8 *const rdataBytesEnd = putRData(mDNSNULL, bytesBuffer, bytesBuffer + bufferSize, rr); 2602 mdns_require_action_quiet(rdataBytesEnd && (rdataBytesEnd > bytesBuffer), exit, err = mStatus_BadParamErr); 2603 2604 rdataBytes = bytesBuffer; 2605 rdataLen = (rdataBytesEnd - bytesBuffer); 2606 break; 2607 } 2608 default: 2609 rdataBytes = rr->rdata->u.data; 2610 rdataLen = rr->rdlength; 2611 break; 2612 } 2613 err = mStatus_NoError; 2614 2615 exit: 2616 mdns_assign(outRDataLen, rdataLen); 2617 mdns_assign(outError, err); 2618 return rdataBytes; 2619 } 2620 2621 // *************************************************************************** 2622 // MARK: - DNS Message Creation Functions 2623 2624 mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags) 2625 { 2626 h->id = id; 2627 h->flags = flags; 2628 h->numQuestions = 0; 2629 h->numAnswers = 0; 2630 h->numAuthorities = 0; 2631 h->numAdditionals = 0; 2632 } 2633 2634 #endif // !STANDALONE 2635 2636 mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname) 2637 { 2638 const mDNSu8 *result = end - *domname - 1; 2639 2640 if (*domname == 0) return(mDNSNULL); // There's no point trying to match just the root label 2641 2642 // This loop examines each possible starting position in packet, starting end of the packet and working backwards 2643 while (result >= base) 2644 { 2645 // If the length byte and first character of the label match, then check further to see 2646 // if this location in the packet will yield a useful name compression pointer. 2647 if (result[0] == domname[0] && result[1] == domname[1]) 2648 { 2649 const mDNSu8 *name = domname; 2650 const mDNSu8 *targ = result; 2651 while (targ + *name < end) 2652 { 2653 // First see if this label matches 2654 int i; 2655 const mDNSu8 *pointertarget; 2656 for (i=0; i <= *name; i++) if (targ[i] != name[i]) break; 2657 if (i <= *name) break; // If label did not match, bail out 2658 targ += 1 + *name; // Else, did match, so advance target pointer 2659 name += 1 + *name; // and proceed to check next label 2660 if (*name == 0 && *targ == 0) return(result); // If no more labels, we found a match! 2661 if (*name == 0) break; // If no more labels to match, we failed, so bail out 2662 2663 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches 2664 if (targ[0] < 0x40) continue; // If length value, continue to check next label 2665 if (targ[0] < 0xC0) break; // If 40-BF, not valid 2666 if (targ+1 >= end) break; // Second byte not present! 2667 pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1]; 2668 if (targ < pointertarget) break; // Pointertarget must point *backwards* in the packet 2669 if (pointertarget[0] >= 0x40) break; // Pointertarget must point to a valid length byte 2670 targ = pointertarget; 2671 } 2672 } 2673 result--; // We failed to match at this search position, so back up the tentative result pointer and try again 2674 } 2675 return(mDNSNULL); 2676 } 2677 2678 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't) 2679 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers) 2680 // end points to the end of the message so far 2681 // ptr points to where we want to put the name 2682 // limit points to one byte past the end of the buffer that we must not overrun 2683 // domainname is the name to put 2684 mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, 2685 mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name) 2686 { 2687 const mDNSu8 *const base = (const mDNSu8 *)msg; 2688 const mDNSu8 * np = name->c; 2689 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid 2690 const mDNSu8 * pointer = mDNSNULL; 2691 const mDNSu8 *const searchlimit = ptr; 2692 2693 if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); return(mDNSNULL); } 2694 2695 if (!*np) // If just writing one-byte root label, make sure we have space for that 2696 { 2697 if (ptr >= limit) return(mDNSNULL); 2698 } 2699 else // else, loop through writing labels and/or a compression offset 2700 { 2701 do { 2702 if (*np > MAX_DOMAIN_LABEL) 2703 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); } 2704 2705 // This check correctly allows for the final trailing root label: 2706 // e.g. 2707 // Suppose our domain name is exactly 256 bytes long, including the final trailing root label. 2708 // Suppose np is now at name->c[249], and we're about to write our last non-null label ("local"). 2709 // We know that max will be at name->c[256] 2710 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our 2711 // six bytes, then exit the loop, write the final terminating root label, and the domain 2712 // name we've written is exactly 256 bytes long, exactly at the correct legal limit. 2713 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out. 2714 if (np + 1 + *np >= max) 2715 { LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); } 2716 2717 if (base) pointer = FindCompressionPointer(base, searchlimit, np); 2718 if (pointer) // Use a compression pointer if we can 2719 { 2720 const mDNSu16 offset = (mDNSu16)(pointer - base); 2721 if (ptr+2 > limit) return(mDNSNULL); // If we don't have two bytes of space left, give up 2722 *ptr++ = (mDNSu8)(0xC0 | (offset >> 8)); 2723 *ptr++ = (mDNSu8)( offset & 0xFF); 2724 return(ptr); 2725 } 2726 else // Else copy one label and try again 2727 { 2728 int i; 2729 mDNSu8 len = *np++; 2730 // If we don't at least have enough space for this label *plus* a terminating zero on the end, give up 2731 if (ptr + 1 + len >= limit) return(mDNSNULL); 2732 *ptr++ = len; 2733 for (i=0; i<len; i++) *ptr++ = *np++; 2734 } 2735 } while (*np); // While we've got characters remaining in the name, continue 2736 } 2737 2738 *ptr++ = 0; // Put the final root label 2739 return(ptr); 2740 } 2741 2742 #ifndef STANDALONE 2743 2744 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val) 2745 { 2746 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF); 2747 ptr[1] = (mDNSu8)((val ) & 0xFF); 2748 return ptr + sizeof(mDNSOpaque16); 2749 } 2750 2751 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val) 2752 { 2753 ptr[0] = (mDNSu8)((val >> 24) & 0xFF); 2754 ptr[1] = (mDNSu8)((val >> 16) & 0xFF); 2755 ptr[2] = (mDNSu8)((val >> 8) & 0xFF); 2756 ptr[3] = (mDNSu8)((val ) & 0xFF); 2757 return ptr + sizeof(mDNSu32); 2758 } 2759 2760 // Copy the RDATA information. The actual in memory storage for the data might be bigger than what the rdlength 2761 // says. Hence, the only way to copy out the data from a resource record is to use putRData. 2762 // msg points to the message we're building (pass mDNSNULL for "msg" if we don't want to use compression pointers) 2763 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr) 2764 { 2765 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 2766 switch (rr->rrtype) 2767 { 2768 case kDNSType_A: if (rr->rdlength != 4) 2769 { debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); } 2770 if (ptr + 4 > limit) return(mDNSNULL); 2771 *ptr++ = rdb->ipv4.b[0]; 2772 *ptr++ = rdb->ipv4.b[1]; 2773 *ptr++ = rdb->ipv4.b[2]; 2774 *ptr++ = rdb->ipv4.b[3]; 2775 return(ptr); 2776 2777 case kDNSType_NS: 2778 case kDNSType_CNAME: 2779 case kDNSType_PTR: 2780 case kDNSType_DNAME: return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name)); 2781 2782 case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname); 2783 if (!ptr) return(mDNSNULL); 2784 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.rname); 2785 if (!ptr || ptr + 20 > limit) return(mDNSNULL); 2786 ptr = putVal32(ptr, rdb->soa.serial); 2787 ptr = putVal32(ptr, rdb->soa.refresh); 2788 ptr = putVal32(ptr, rdb->soa.retry); 2789 ptr = putVal32(ptr, rdb->soa.expire); 2790 ptr = putVal32(ptr, rdb->soa.min); 2791 return(ptr); 2792 2793 case kDNSType_NULL: 2794 case kDNSType_HINFO: 2795 case kDNSType_TSIG: 2796 case kDNSType_TXT: 2797 case kDNSType_X25: 2798 case kDNSType_ISDN: 2799 case kDNSType_LOC: 2800 case kDNSType_DHCID: if (ptr + rr->rdlength > limit) return(mDNSNULL); 2801 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); 2802 return(ptr + rr->rdlength); 2803 2804 case kDNSType_MX: 2805 case kDNSType_AFSDB: 2806 case kDNSType_RT: 2807 case kDNSType_KX: if (ptr + 3 > limit) return(mDNSNULL); 2808 ptr = putVal16(ptr, rdb->mx.preference); 2809 return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange)); 2810 2811 case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox); 2812 if (!ptr) return(mDNSNULL); 2813 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.txt); 2814 return(ptr); 2815 2816 case kDNSType_PX: if (ptr + 5 > limit) return(mDNSNULL); 2817 ptr = putVal16(ptr, rdb->px.preference); 2818 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822); 2819 if (!ptr) return(mDNSNULL); 2820 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400); 2821 return(ptr); 2822 2823 case kDNSType_AAAA: if (rr->rdlength != sizeof(rdb->ipv6)) 2824 { debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); } 2825 if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL); 2826 mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6)); 2827 return(ptr + sizeof(rdb->ipv6)); 2828 2829 case kDNSType_SRV: if (ptr + 7 > limit) return(mDNSNULL); 2830 *ptr++ = (mDNSu8)(rdb->srv.priority >> 8); 2831 *ptr++ = (mDNSu8)(rdb->srv.priority & 0xFF); 2832 *ptr++ = (mDNSu8)(rdb->srv.weight >> 8); 2833 *ptr++ = (mDNSu8)(rdb->srv.weight & 0xFF); 2834 *ptr++ = rdb->srv.port.b[0]; 2835 *ptr++ = rdb->srv.port.b[1]; 2836 return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target)); 2837 2838 case kDNSType_TSR: { 2839 // tsr timestamp on wire is relative time since received. 2840 mDNSs32 tsr_relative = mDNSPlatformContinuousTimeSeconds() - rdb->tsr_value; 2841 ptr = putVal32(ptr, tsr_relative); 2842 return(ptr); 2843 } 2844 2845 case kDNSType_OPT: { 2846 int len = 0; 2847 const rdataOPT *opt; 2848 const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength]; 2849 for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) 2850 len += DNSOpt_Data_Space(opt); 2851 if (ptr + len > limit) 2852 { 2853 LogMsg("ERROR: putOptRData - out of space"); 2854 return mDNSNULL; 2855 } 2856 for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) 2857 { 2858 const int space = DNSOpt_Data_Space(opt); 2859 ptr = putVal16(ptr, opt->opt); 2860 ptr = putVal16(ptr, (mDNSu16)space - 4); 2861 switch (opt->opt) 2862 { 2863 case kDNSOpt_LLQ: 2864 ptr = putVal16(ptr, opt->u.llq.vers); 2865 ptr = putVal16(ptr, opt->u.llq.llqOp); 2866 ptr = putVal16(ptr, opt->u.llq.err); 2867 mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8); // 8-byte id 2868 ptr += 8; 2869 ptr = putVal32(ptr, opt->u.llq.llqlease); 2870 break; 2871 case kDNSOpt_Lease: 2872 ptr = putVal32(ptr, opt->u.updatelease); 2873 break; 2874 case kDNSOpt_Owner: 2875 *ptr++ = opt->u.owner.vers; 2876 *ptr++ = opt->u.owner.seq; 2877 mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6); // 6-byte Host identifier 2878 ptr += 6; 2879 if (space >= DNSOpt_OwnerData_ID_Wake_Space) 2880 { 2881 mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6); // 6-byte interface MAC 2882 ptr += 6; 2883 if (space > DNSOpt_OwnerData_ID_Wake_Space) 2884 { 2885 mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space); 2886 ptr += space - DNSOpt_OwnerData_ID_Wake_Space; 2887 } 2888 } 2889 break; 2890 case kDNSOpt_Trace: 2891 *ptr++ = opt->u.tracer.platf; 2892 ptr = putVal32(ptr, opt->u.tracer.mDNSv); 2893 break; 2894 case kDNSOpt_TSR: 2895 { 2896 mDNSs32 tsr_relative = mDNSPlatformContinuousTimeSeconds() - opt->u.tsr.timeStamp; 2897 ptr = putVal32(ptr, tsr_relative); 2898 ptr = putVal32(ptr, opt->u.tsr.hostkeyHash); 2899 ptr = putVal16(ptr, opt->u.tsr.recIndex); 2900 } 2901 break; 2902 default: 2903 break; 2904 } 2905 } 2906 return ptr; 2907 } 2908 2909 case kDNSType_NSEC: { 2910 // For NSEC records, rdlength represents the exact number of bytes 2911 // of in memory storage. 2912 const mDNSu8 *nsec = (const mDNSu8 *)rdb->data; 2913 const domainname *name = (const domainname *)nsec; 2914 const int dlen = DomainNameLength(name); 2915 nsec += dlen; 2916 // This function is called when we are sending a NSEC record as part of mDNS, 2917 // or to copy the data to any other buffer needed which could be a mDNS or uDNS 2918 // NSEC record. The only time compression is used that when we are sending it 2919 // in mDNS (indicated by non-NULL "msg") and hence we handle mDNS case 2920 // separately. 2921 if (MULTICAST_NSEC(rr)) 2922 { 2923 mDNSu8 *save = ptr; 2924 int i, j, wlen; 2925 wlen = *(nsec + 1); 2926 nsec += 2; // Skip the window number and len 2927 2928 // For our simplified use of NSEC synthetic records: 2929 // 2930 // nextname is always the record's own name, 2931 // the block number is always 0, 2932 // the count byte is a value in the range 1-32, 2933 // followed by the 1-32 data bytes 2934 // 2935 // Note: When we send the NSEC record in mDNS, the window size is set to 32. 2936 // We need to find out what the last non-NULL byte is. If we are copying out 2937 // from an RDATA, we have the right length. As we need to handle both the case, 2938 // we loop to find the right value instead of blindly using len to copy. 2939 2940 for (i=wlen; i>0; i--) if (nsec[i-1]) break; 2941 2942 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); 2943 if (!ptr) 2944 { 2945 goto mdns_nsec_exit; 2946 } 2947 if (i) // Only put a block if at least one type exists for this name 2948 { 2949 if (ptr + 2 + i > limit) 2950 { 2951 ptr = mDNSNULL; 2952 goto mdns_nsec_exit; 2953 } 2954 *ptr++ = 0; 2955 *ptr++ = (mDNSu8)i; 2956 for (j=0; j<i; j++) *ptr++ = nsec[j]; 2957 } 2958 mdns_nsec_exit: 2959 if (!ptr) 2960 { 2961 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEBUG, 2962 "The mDNS message does not have enough space for the NSEC record, will add it to the next message (This is not an error message) -- " 2963 "remaining space: %ld, NSEC name: " PRI_DM_NAME, limit - save, DM_NAME_PARAM(rr->name)); 2964 } 2965 return ptr; 2966 } 2967 else 2968 { 2969 int win, wlen; 2970 int len = rr->rdlength - dlen; 2971 2972 // Sanity check whether the bitmap is good 2973 while (len) 2974 { 2975 if (len < 3) 2976 { LogMsg("putRData: invalid length %d", len); return mDNSNULL; } 2977 2978 win = *nsec++; 2979 wlen = *nsec++; 2980 len -= 2; 2981 if (len < wlen || wlen < 1 || wlen > 32) 2982 { LogMsg("putRData: invalid window length %d", wlen); return mDNSNULL; } 2983 if (win < 0 || win >= 256) 2984 { LogMsg("putRData: invalid window %d", win); return mDNSNULL; } 2985 2986 nsec += wlen; 2987 len -= wlen; 2988 } 2989 if (ptr + rr->rdlength > limit) { LogMsg("putRData: NSEC rdlength beyond limit %##s (%s), ptr %p, rdlength %d, limit %p", rr->name->c, DNSTypeName(rr->rrtype), ptr, rr->rdlength, limit); return(mDNSNULL);} 2990 2991 // No compression allowed for "nxt", just copy the data. 2992 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); 2993 return(ptr + rr->rdlength); 2994 } 2995 } 2996 2997 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype); 2998 if (ptr + rr->rdlength > limit) return(mDNSNULL); 2999 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); 3000 return(ptr + rr->rdlength); 3001 } 3002 } 3003 3004 #define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update) 3005 3006 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, 3007 const ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit) 3008 { 3009 mDNSu8 *endofrdata; 3010 mDNSu16 actualLength; 3011 // When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782) 3012 const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg; 3013 3014 if (rr->RecordType == kDNSRecordTypeUnregistered) 3015 { 3016 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 3017 "Attempt to put kDNSRecordTypeUnregistered " PRI_DM_NAME " (" PUB_S ")", 3018 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype)); 3019 return(ptr); 3020 } 3021 3022 if (!ptr) 3023 { 3024 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 3025 "Pointer to message is NULL while filling resource record " PRI_DM_NAME " (" PUB_S ")", 3026 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype)); 3027 return(mDNSNULL); 3028 } 3029 3030 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); 3031 // If we're out-of-space, return mDNSNULL 3032 if (!ptr || ptr + 10 >= limit) 3033 { 3034 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 3035 "Can't put more names into current message, will possibly put it into the next message - " 3036 "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld", 3037 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr)); 3038 return(mDNSNULL); 3039 } 3040 ptr[0] = (mDNSu8)(rr->rrtype >> 8); 3041 ptr[1] = (mDNSu8)(rr->rrtype & 0xFF); 3042 ptr[2] = (mDNSu8)(rr->rrclass >> 8); 3043 ptr[3] = (mDNSu8)(rr->rrclass & 0xFF); 3044 ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF); 3045 ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF); 3046 ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF); 3047 ptr[7] = (mDNSu8)( ttl & 0xFF); 3048 // ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes 3049 3050 endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr); 3051 if (!endofrdata) 3052 { 3053 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 3054 "Can't put more rdata into current message, will possibly put it into the next message - " 3055 "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld", 3056 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr - 10)); 3057 return(mDNSNULL); 3058 } 3059 3060 // Go back and fill in the actual number of data bytes we wrote 3061 // (actualLength can be less than rdlength when domain name compression is used) 3062 actualLength = (mDNSu16)(endofrdata - ptr - 10); 3063 ptr[8] = (mDNSu8)(actualLength >> 8); 3064 ptr[9] = (mDNSu8)(actualLength & 0xFF); 3065 3066 if (count) 3067 { 3068 (*count)++; 3069 } 3070 else 3071 { 3072 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 3073 "No target count to update for " PRI_DM_NAME " (" PUB_S ")", 3074 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype)); 3075 } 3076 return(endofrdata); 3077 } 3078 3079 mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr) 3080 { 3081 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name); 3082 if (!ptr || ptr + 10 > limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL 3083 ptr[0] = (mDNSu8)(rr->resrec.rrtype >> 8); // Put type 3084 ptr[1] = (mDNSu8)(rr->resrec.rrtype & 0xFF); 3085 ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8); // Put class 3086 ptr[3] = (mDNSu8)(rr->resrec.rrclass & 0xFF); 3087 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // TTL is zero 3088 ptr[8] = ptr[9] = 0; // RDATA length is zero 3089 (*count)++; 3090 return(ptr + 10); 3091 } 3092 3093 mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass) 3094 { 3095 ptr = putDomainNameAsLabels(msg, ptr, limit, name); 3096 if (!ptr || ptr+4 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL 3097 ptr[0] = (mDNSu8)(rrtype >> 8); 3098 ptr[1] = (mDNSu8)(rrtype & 0xFF); 3099 ptr[2] = (mDNSu8)(rrclass >> 8); 3100 ptr[3] = (mDNSu8)(rrclass & 0xFF); 3101 msg->h.numQuestions++; 3102 return(ptr+4); 3103 } 3104 3105 // for dynamic updates 3106 mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass) 3107 { 3108 ptr = putDomainNameAsLabels(msg, ptr, limit, zone); 3109 if (!ptr || ptr + 4 > limit) return mDNSNULL; // If we're out-of-space, return NULL 3110 *ptr++ = (mDNSu8)(kDNSType_SOA >> 8); 3111 *ptr++ = (mDNSu8)(kDNSType_SOA & 0xFF); 3112 *ptr++ = zoneClass.b[0]; 3113 *ptr++ = zoneClass.b[1]; 3114 msg->h.mDNS_numZones++; 3115 return ptr; 3116 } 3117 3118 // for dynamic updates 3119 mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end) 3120 { 3121 AuthRecord prereq; 3122 mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL); 3123 AssignDomainName(&prereq.namestorage, name); 3124 prereq.resrec.rrtype = kDNSQType_ANY; 3125 prereq.resrec.rrclass = kDNSClass_NONE; 3126 return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq); 3127 } 3128 3129 // for dynamic updates 3130 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr) 3131 { 3132 // deletion: specify record w/ TTL 0, class NONE 3133 const mDNSu16 origclass = rr->rrclass; 3134 rr->rrclass = kDNSClass_NONE; 3135 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0); 3136 rr->rrclass = origclass; 3137 return ptr; 3138 } 3139 3140 // for dynamic updates 3141 mDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit) 3142 { 3143 // deletion: specify record w/ TTL 0, class NONE 3144 const mDNSu16 origclass = rr->rrclass; 3145 rr->rrclass = kDNSClass_NONE; 3146 ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit); 3147 rr->rrclass = origclass; 3148 return ptr; 3149 } 3150 3151 mDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit) 3152 { 3153 mDNSu16 class = kDNSQClass_ANY; 3154 3155 ptr = putDomainNameAsLabels(msg, ptr, limit, name); 3156 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL 3157 ptr[0] = (mDNSu8)(rrtype >> 8); 3158 ptr[1] = (mDNSu8)(rrtype & 0xFF); 3159 ptr[2] = (mDNSu8)(class >> 8); 3160 ptr[3] = (mDNSu8)(class & 0xFF); 3161 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl 3162 ptr[8] = ptr[9] = 0; // zero rdlength/rdata 3163 3164 msg->h.mDNS_numUpdates++; 3165 return ptr + 10; 3166 } 3167 3168 // for dynamic updates 3169 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name) 3170 { 3171 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData; 3172 mDNSu16 class = kDNSQClass_ANY; 3173 mDNSu16 rrtype = kDNSQType_ANY; 3174 3175 ptr = putDomainNameAsLabels(msg, ptr, limit, name); 3176 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL 3177 ptr[0] = (mDNSu8)(rrtype >> 8); 3178 ptr[1] = (mDNSu8)(rrtype & 0xFF); 3179 ptr[2] = (mDNSu8)(class >> 8); 3180 ptr[3] = (mDNSu8)(class & 0xFF); 3181 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl 3182 ptr[8] = ptr[9] = 0; // zero rdlength/rdata 3183 3184 msg->h.mDNS_numUpdates++; 3185 return ptr + 10; 3186 } 3187 3188 // for dynamic updates 3189 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease) 3190 { 3191 AuthRecord rr; 3192 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 3193 rr.resrec.rrclass = NormalMaxDNSMessageData; 3194 rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 3195 rr.resrec.rdestimate = sizeof(rdataOPT); 3196 rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 3197 rr.resrec.rdata->u.opt[0].u.updatelease = lease; 3198 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0); 3199 if (!ptr) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; } 3200 return ptr; 3201 } 3202 3203 // for dynamic updates 3204 mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit) 3205 { 3206 AuthRecord rr; 3207 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 3208 rr.resrec.rrclass = NormalMaxDNSMessageData; 3209 rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 3210 rr.resrec.rdestimate = sizeof(rdataOPT); 3211 rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 3212 rr.resrec.rdata->u.opt[0].u.updatelease = lease; 3213 ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0, limit); 3214 if (!ptr) { LogMsg("ERROR: putUpdateLeaseWithLimit - PutResourceRecordTTLWithLimit"); return mDNSNULL; } 3215 return ptr; 3216 } 3217 3218 // *************************************************************************** 3219 // MARK: - DNS Message Parsing Functions 3220 3221 mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name) 3222 { 3223 mDNSu32 sum = 0; 3224 const mDNSu8 *c; 3225 3226 for (c = name->c; c[0] != 0 && c[1] != 0; c += 2) 3227 { 3228 sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) | 3229 (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]); 3230 sum = (sum<<3) | (sum>>29); 3231 } 3232 if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8); 3233 return(sum); 3234 } 3235 3236 mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength) 3237 { 3238 if (NewRData) 3239 { 3240 rr->rdata = NewRData; 3241 rr->rdlength = rdlength; 3242 } 3243 rr->rdlength = GetRDLength(rr, mDNSfalse); 3244 rr->rdestimate = GetRDLength(rr, mDNStrue); 3245 rr->rdatahash = RDataHashValue(rr); 3246 } 3247 3248 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end) 3249 { 3250 mDNSu16 total = 0; 3251 3252 if (ptr < (const mDNSu8*)msg || ptr >= end) 3253 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); } 3254 3255 while (1) // Read sequence of labels 3256 { 3257 const mDNSu8 len = *ptr++; // Read length of this label 3258 if (len == 0) return(ptr); // If length is zero, that means this name is complete 3259 switch (len & 0xC0) 3260 { 3261 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label 3262 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); } 3263 if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label 3264 { debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); } 3265 ptr += len; 3266 total += 1 + len; 3267 break; 3268 3269 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL); 3270 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL); 3271 case 0xC0: if (ptr + 1 > end) // Skip the two-byte name compression pointer. 3272 { debugf("skipDomainName: Malformed compression pointer (overruns packet end)"); return(mDNSNULL); } 3273 return(ptr + 1); 3274 default: 3275 break; 3276 } 3277 } 3278 } 3279 3280 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary. 3281 mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, 3282 domainname *const name) 3283 { 3284 const mDNSu8 *nextbyte = mDNSNULL; // Record where we got to before we started following pointers 3285 mDNSu8 *np = name->c; // Name pointer 3286 const mDNSu8 *const limit = np + MAX_DOMAIN_NAME; // Limit so we don't overrun buffer 3287 3288 if (ptr < (const mDNSu8*)msg || ptr >= end) 3289 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); } 3290 3291 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels) 3292 3293 while (1) // Read sequence of labels 3294 { 3295 int i; 3296 mDNSu16 offset; 3297 const mDNSu8 len = *ptr++; // Read length of this label 3298 if (len == 0) break; // If length is zero, that means this name is complete 3299 switch (len & 0xC0) 3300 { 3301 3302 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label 3303 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); } 3304 if (np + 1 + len >= limit) // Remember: expect at least one more byte for the root label 3305 { debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); } 3306 *np++ = len; 3307 for (i=0; i<len; i++) *np++ = *ptr++; 3308 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels) 3309 break; 3310 3311 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c); 3312 return(mDNSNULL); 3313 3314 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL); 3315 3316 case 0xC0: if (ptr >= end) 3317 { debugf("getDomainName: Malformed compression label (overruns packet end)"); return(mDNSNULL); } 3318 offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++); 3319 if (!nextbyte) nextbyte = ptr; // Record where we got to before we started following pointers 3320 ptr = (const mDNSu8 *)msg + offset; 3321 if (ptr < (const mDNSu8*)msg || ptr >= end) 3322 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); } 3323 if (*ptr & 0xC0) 3324 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); } 3325 break; 3326 3327 default: 3328 break; 3329 } 3330 } 3331 3332 if (nextbyte) return(nextbyte); 3333 else return(ptr); 3334 } 3335 3336 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end) 3337 { 3338 mDNSu16 pktrdlength; 3339 3340 ptr = skipDomainName(msg, ptr, end); 3341 if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); } 3342 3343 if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); } 3344 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); 3345 ptr += 10; 3346 if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } 3347 3348 return(ptr + pktrdlength); 3349 } 3350 3351 // Sanity check whether the NSEC/NSEC3 bitmap is good 3352 mDNSlocal const mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int len) 3353 { 3354 int win, wlen; 3355 3356 while (bmap < end) 3357 { 3358 if (len < 3) 3359 { 3360 LogInfo("SanityCheckBitMap: invalid length %d", len); 3361 return mDNSNULL; 3362 } 3363 3364 win = *bmap++; 3365 wlen = *bmap++; 3366 len -= 2; 3367 if (len < wlen || wlen < 1 || wlen > 32) 3368 { 3369 LogInfo("SanityCheckBitMap: invalid window length %d", wlen); 3370 return mDNSNULL; 3371 } 3372 if (win < 0 || win >= 256) 3373 { 3374 LogInfo("SanityCheckBitMap: invalid window %d", win); 3375 return mDNSNULL; 3376 } 3377 3378 bmap += wlen; 3379 len -= wlen; 3380 } 3381 return (const mDNSu8 *)bmap; 3382 } 3383 3384 mDNSlocal mDNSBool AssignDomainNameWithLimit(domainname *const dst, const domainname *src, const mDNSu8 *const end) 3385 { 3386 const mDNSu32 len = DomainNameLengthLimit(src, end); 3387 if ((len >= 1) && (len <= MAX_DOMAIN_NAME)) 3388 { 3389 mDNSPlatformMemCopy(dst->c, src->c, len); 3390 return mDNStrue; 3391 } 3392 else 3393 { 3394 dst->c[0] = 0; 3395 return mDNSfalse; 3396 } 3397 } 3398 3399 // This function is called with "msg" when we receive a DNS message and needs to parse a single resource record 3400 // pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded 3401 // (domainnames are expanded to 256 bytes) when stored in memory. 3402 // 3403 // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr. 3404 // The caller can do this only if the names in the resource records are not compressed and validity of the 3405 // resource record has already been done before. 3406 mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, ResourceRecord *const rr, 3407 const mDNSu16 rdlength) 3408 { 3409 RDataBody2 *const rdb = (RDataBody2 *)&rr->rdata->u; 3410 3411 switch (rr->rrtype) 3412 { 3413 case kDNSType_A: 3414 if (rdlength != sizeof(mDNSv4Addr)) 3415 goto fail; 3416 rdb->ipv4.b[0] = ptr[0]; 3417 rdb->ipv4.b[1] = ptr[1]; 3418 rdb->ipv4.b[2] = ptr[2]; 3419 rdb->ipv4.b[3] = ptr[3]; 3420 break; 3421 3422 case kDNSType_NS: 3423 case kDNSType_MD: 3424 case kDNSType_MF: 3425 case kDNSType_CNAME: 3426 case kDNSType_MB: 3427 case kDNSType_MG: 3428 case kDNSType_MR: 3429 case kDNSType_PTR: 3430 case kDNSType_NSAP_PTR: 3431 case kDNSType_DNAME: 3432 if (msg) 3433 { 3434 ptr = getDomainName(msg, ptr, end, &rdb->name); 3435 } 3436 else 3437 { 3438 if (!AssignDomainNameWithLimit(&rdb->name, (const domainname *)ptr, end)) 3439 { 3440 goto fail; 3441 } 3442 ptr += DomainNameLength(&rdb->name); 3443 } 3444 if (ptr != end) 3445 { 3446 debugf("SetRData: Malformed CNAME/PTR RDATA name"); 3447 goto fail; 3448 } 3449 break; 3450 3451 case kDNSType_SOA: 3452 if (msg) 3453 { 3454 ptr = getDomainName(msg, ptr, end, &rdb->soa.mname); 3455 } 3456 else 3457 { 3458 if (!AssignDomainNameWithLimit(&rdb->soa.mname, (const domainname *)ptr, end)) 3459 { 3460 goto fail; 3461 } 3462 ptr += DomainNameLength(&rdb->soa.mname); 3463 } 3464 if (!ptr) 3465 { 3466 debugf("SetRData: Malformed SOA RDATA mname"); 3467 goto fail; 3468 } 3469 if (msg) 3470 { 3471 ptr = getDomainName(msg, ptr, end, &rdb->soa.rname); 3472 } 3473 else 3474 { 3475 if (!AssignDomainNameWithLimit(&rdb->soa.rname, (const domainname *)ptr, end)) 3476 { 3477 goto fail; 3478 } 3479 ptr += DomainNameLength(&rdb->soa.rname); 3480 } 3481 if (!ptr) 3482 { 3483 debugf("SetRData: Malformed SOA RDATA rname"); 3484 goto fail; 3485 } 3486 if (ptr + 0x14 != end) 3487 { 3488 debugf("SetRData: Malformed SOA RDATA"); 3489 goto fail; 3490 } 3491 rdb->soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]); 3492 rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]); 3493 rdb->soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]); 3494 rdb->soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]); 3495 rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]); 3496 break; 3497 3498 case kDNSType_HINFO: 3499 // See https://tools.ietf.org/html/rfc1035#section-3.3.2 for HINFO RDATA format. 3500 { 3501 // HINFO should contain RDATA. 3502 if (end <= ptr || rdlength != (mDNSu32)(end - ptr)) 3503 { 3504 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 3505 "SetRData: Malformed HINFO RDATA - invalid RDATA length: %u", rdlength); 3506 goto fail; 3507 } 3508 3509 const mDNSu8 *currentPtr = ptr; 3510 // CPU character string length should be less than the RDATA length. 3511 mDNSu32 cpuCharacterStrLength = currentPtr[0]; 3512 if (1 + cpuCharacterStrLength >= (mDNSu32)(end - currentPtr)) 3513 { 3514 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 3515 "SetRData: Malformed HINFO RDATA - CPU character string goes out of boundary"); 3516 goto fail; 3517 } 3518 currentPtr += 1 + cpuCharacterStrLength; 3519 3520 // OS character string should end at the RDATA ending. 3521 mDNSu32 osCharacterStrLength = currentPtr[0]; 3522 if (1 + osCharacterStrLength != (mDNSu32)(end - currentPtr)) 3523 { 3524 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 3525 "SetRData: Malformed HINFO RDATA - OS character string does not end at the RDATA ending"); 3526 goto fail; 3527 } 3528 3529 // Copy the validated RDATA. 3530 rr->rdlength = rdlength; 3531 mDNSPlatformMemCopy(rdb->data, ptr, rdlength); 3532 break; 3533 } 3534 case kDNSType_NULL: 3535 case kDNSType_TXT: 3536 case kDNSType_X25: 3537 case kDNSType_ISDN: 3538 case kDNSType_LOC: 3539 case kDNSType_DHCID: 3540 case kDNSType_SVCB: 3541 case kDNSType_HTTPS: 3542 rr->rdlength = rdlength; 3543 mDNSPlatformMemCopy(rdb->data, ptr, rdlength); 3544 break; 3545 3546 case kDNSType_MX: 3547 case kDNSType_AFSDB: 3548 case kDNSType_RT: 3549 case kDNSType_KX: 3550 // Preference + domainname 3551 if (rdlength < 3) 3552 goto fail; 3553 rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 3554 ptr += 2; 3555 if (msg) 3556 { 3557 ptr = getDomainName(msg, ptr, end, &rdb->mx.exchange); 3558 } 3559 else 3560 { 3561 if (!AssignDomainNameWithLimit(&rdb->mx.exchange, (const domainname *)ptr, end)) 3562 { 3563 goto fail; 3564 } 3565 ptr += DomainNameLength(&rdb->mx.exchange); 3566 } 3567 if (ptr != end) 3568 { 3569 debugf("SetRData: Malformed MX name"); 3570 goto fail; 3571 } 3572 break; 3573 3574 case kDNSType_MINFO: 3575 case kDNSType_RP: 3576 // Domainname + domainname 3577 if (msg) 3578 { 3579 ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox); 3580 } 3581 else 3582 { 3583 if (!AssignDomainNameWithLimit(&rdb->rp.mbox, (const domainname *)ptr, end)) 3584 { 3585 goto fail; 3586 } 3587 ptr += DomainNameLength(&rdb->rp.mbox); 3588 } 3589 if (!ptr) 3590 { 3591 debugf("SetRData: Malformed RP mbox"); 3592 goto fail; 3593 } 3594 if (msg) 3595 { 3596 ptr = getDomainName(msg, ptr, end, &rdb->rp.txt); 3597 } 3598 else 3599 { 3600 if (!AssignDomainNameWithLimit(&rdb->rp.txt, (const domainname *)ptr, end)) 3601 { 3602 goto fail; 3603 } 3604 ptr += DomainNameLength(&rdb->rp.txt); 3605 } 3606 if (ptr != end) 3607 { 3608 debugf("SetRData: Malformed RP txt"); 3609 goto fail; 3610 } 3611 break; 3612 3613 case kDNSType_PX: 3614 // Preference + domainname + domainname 3615 if (rdlength < 4) 3616 goto fail; 3617 rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 3618 ptr += 2; 3619 if (msg) 3620 { 3621 ptr = getDomainName(msg, ptr, end, &rdb->px.map822); 3622 } 3623 else 3624 { 3625 if (!AssignDomainNameWithLimit(&rdb->px.map822, (const domainname *)ptr, end)) 3626 { 3627 goto fail; 3628 } 3629 ptr += DomainNameLength(&rdb->px.map822); 3630 } 3631 if (!ptr) 3632 { 3633 debugf("SetRData: Malformed PX map822"); 3634 goto fail; 3635 } 3636 if (msg) 3637 { 3638 ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400); 3639 } 3640 else 3641 { 3642 if (!AssignDomainNameWithLimit(&rdb->px.mapx400, (const domainname *)ptr, end)) 3643 { 3644 goto fail; 3645 } 3646 ptr += DomainNameLength(&rdb->px.mapx400); 3647 } 3648 if (ptr != end) 3649 { 3650 debugf("SetRData: Malformed PX mapx400"); 3651 goto fail; 3652 } 3653 break; 3654 3655 case kDNSType_AAAA: 3656 if (rdlength != sizeof(mDNSv6Addr)) 3657 goto fail; 3658 mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6)); 3659 break; 3660 3661 case kDNSType_SRV: 3662 // Priority + weight + port + domainname 3663 if (rdlength < 7) 3664 goto fail; 3665 rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 3666 rdb->srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 3667 rdb->srv.port.b[0] = ptr[4]; 3668 rdb->srv.port.b[1] = ptr[5]; 3669 ptr += 6; 3670 if (msg) 3671 { 3672 ptr = getDomainName(msg, ptr, end, &rdb->srv.target); 3673 } 3674 else 3675 { 3676 if (!AssignDomainNameWithLimit(&rdb->srv.target, (const domainname *)ptr, end)) 3677 { 3678 goto fail; 3679 } 3680 ptr += DomainNameLength(&rdb->srv.target); 3681 } 3682 if (ptr != end) 3683 { 3684 debugf("SetRData: Malformed SRV RDATA name"); 3685 goto fail; 3686 } 3687 break; 3688 3689 case kDNSType_NAPTR: 3690 { 3691 int savelen, len; 3692 domainname name; 3693 mDNSu32 namelen; 3694 const mDNSu8 *orig = ptr; 3695 3696 // Make sure the data is parseable and within the limits. 3697 // 3698 // Fixed length: Order, preference (4 bytes) 3699 // Variable length: flags, service, regexp, domainname 3700 3701 if (rdlength < 8) 3702 goto fail; 3703 // Order, preference. 3704 ptr += 4; 3705 // Parse flags, Service and Regexp 3706 // length in the first byte does not include the length byte itself 3707 len = *ptr + 1; 3708 ptr += len; 3709 if (ptr >= end) 3710 { 3711 LogInfo("SetRData: Malformed NAPTR flags"); 3712 goto fail; 3713 } 3714 3715 // Service 3716 len = *ptr + 1; 3717 ptr += len; 3718 if (ptr >= end) 3719 { 3720 LogInfo("SetRData: Malformed NAPTR service"); 3721 goto fail; 3722 } 3723 3724 // Regexp 3725 len = *ptr + 1; 3726 ptr += len; 3727 if (ptr >= end) 3728 { 3729 LogInfo("SetRData: Malformed NAPTR regexp"); 3730 goto fail; 3731 } 3732 3733 savelen = (int)(ptr - orig); 3734 3735 // RFC 2915 states that name compression is not allowed for this field. But RFC 3597 3736 // states that for NAPTR we should decompress. We make sure that we store the full 3737 // name rather than the compressed name 3738 if (msg) 3739 { 3740 ptr = getDomainName(msg, ptr, end, &name); 3741 namelen = DomainNameLength(&name); 3742 } 3743 else 3744 { 3745 if (!AssignDomainNameWithLimit(&name, (const domainname *)ptr, end)) 3746 { 3747 goto fail; 3748 } 3749 namelen = DomainNameLength(&name); 3750 ptr += namelen; 3751 } 3752 if (ptr != end) 3753 { 3754 LogInfo("SetRData: Malformed NAPTR RDATA name"); 3755 goto fail; 3756 } 3757 3758 rr->rdlength = savelen + namelen; 3759 // The uncompressed size should not exceed the limits 3760 if (rr->rdlength > MaximumRDSize) 3761 { 3762 LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->rdlength %d, " 3763 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c); 3764 goto fail; 3765 } 3766 mDNSPlatformMemCopy(rdb->data, orig, savelen); 3767 mDNSPlatformMemCopy(rdb->data + savelen, name.c, namelen); 3768 break; 3769 } 3770 case kDNSType_OPT: { 3771 const mDNSu8 * const dataend = &rr->rdata->u.data[rr->rdata->MaxRDLength]; 3772 rdataOPT *opt = rr->rdata->u.opt; 3773 rr->rdlength = 0; 3774 while ((ptr < end) && ((dataend - ((const mDNSu8 *)opt)) >= ((mDNSs32)sizeof(*opt)))) 3775 { 3776 const rdataOPT *const currentopt = opt; 3777 if (ptr + 4 > end) { LogInfo("SetRData: OPT RDATA ptr + 4 > end"); goto fail; } 3778 opt->opt = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 3779 opt->optlen = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 3780 ptr += 4; 3781 if (ptr + opt->optlen > end) { LogInfo("SetRData: ptr + opt->optlen > end"); goto fail; } 3782 switch (opt->opt) 3783 { 3784 case kDNSOpt_LLQ: 3785 if (opt->optlen == DNSOpt_LLQData_Space - 4) 3786 { 3787 opt->u.llq.vers = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 3788 opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 3789 opt->u.llq.err = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 3790 mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8); 3791 opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]); 3792 if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond) 3793 opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond; 3794 opt++; 3795 } 3796 break; 3797 case kDNSOpt_Lease: 3798 if (opt->optlen == DNSOpt_LeaseData_Space - 4) 3799 { 3800 opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); 3801 if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond) 3802 opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond; 3803 opt++; 3804 } 3805 break; 3806 case kDNSOpt_Owner: 3807 if (ValidOwnerLength(opt->optlen)) 3808 { 3809 opt->u.owner.vers = ptr[0]; 3810 opt->u.owner.seq = ptr[1]; 3811 mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6); // 6-byte MAC address 3812 mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6); // 6-byte MAC address 3813 opt->u.owner.password = zeroEthAddr; 3814 if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4) 3815 { 3816 mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6); // 6-byte MAC address 3817 // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above 3818 // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4 3819 if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4) 3820 mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4)); 3821 } 3822 opt++; 3823 } 3824 break; 3825 case kDNSOpt_Trace: 3826 if (opt->optlen == DNSOpt_TraceData_Space - 4) 3827 { 3828 opt->u.tracer.platf = ptr[0]; 3829 opt->u.tracer.mDNSv = (mDNSu32) ((mDNSu32)ptr[1] << 24 | (mDNSu32)ptr[2] << 16 | (mDNSu32)ptr[3] << 8 | ptr[4]); 3830 opt++; 3831 } 3832 else 3833 { 3834 opt->u.tracer.platf = 0xFF; 3835 opt->u.tracer.mDNSv = 0xFFFFFFFF; 3836 opt++; 3837 } 3838 break; 3839 case kDNSOpt_TSR: 3840 if (opt->optlen == DNSOpt_TSRData_Space - 4) 3841 { 3842 opt->u.tsr.timeStamp = (mDNSs32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); 3843 opt->u.tsr.hostkeyHash = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]); 3844 opt->u.tsr.recIndex = (mDNSu16) ((mDNSu16)ptr[8] << 8 | ptr[9]); 3845 opt++; 3846 } 3847 break; 3848 default: 3849 break; 3850 } 3851 ptr += currentopt->optlen; 3852 } 3853 rr->rdlength = (mDNSu16)((mDNSu8*)opt - rr->rdata->u.data); 3854 if (ptr != end) { LogInfo("SetRData: Malformed OptRdata"); goto fail; } 3855 break; 3856 } 3857 3858 case kDNSType_NSEC: { 3859 domainname name; 3860 int len = rdlength; 3861 int bmaplen, dlen; 3862 const mDNSu8 *orig = ptr; 3863 const mDNSu8 *bmap; 3864 3865 if (msg) 3866 { 3867 ptr = getDomainName(msg, ptr, end, &name); 3868 } 3869 else 3870 { 3871 if (!AssignDomainNameWithLimit(&name, (const domainname *)ptr, end)) 3872 { 3873 goto fail; 3874 } 3875 ptr += DomainNameLength(&name); 3876 } 3877 if (!ptr) 3878 { 3879 LogInfo("SetRData: Malformed NSEC nextname"); 3880 goto fail; 3881 } 3882 3883 dlen = DomainNameLength(&name); 3884 3885 // Multicast NSECs use name compression for this field unlike the unicast case which 3886 // does not use compression. And multicast case always succeeds in compression. So, 3887 // the rdlength includes only the compressed space in that case. So, can't 3888 // use the DomainNameLength of name to reduce the length here. 3889 len -= (ptr - orig); 3890 bmaplen = len; // Save the length of the bitmap 3891 bmap = ptr; 3892 ptr = SanityCheckBitMap(bmap, end, len); 3893 if (!ptr) 3894 goto fail; 3895 if (ptr != end) 3896 { 3897 LogInfo("SetRData: Malformed NSEC length not right"); 3898 goto fail; 3899 } 3900 3901 // Initialize the right length here. When we call SetNewRData below which in turn calls 3902 // GetRDLength and for NSEC case, it assumes that rdlength is intitialized 3903 rr->rdlength = DomainNameLength(&name) + bmaplen; 3904 3905 // Do we have space after the name expansion ? 3906 if (rr->rdlength > MaximumRDSize) 3907 { 3908 LogInfo("SetRData: Malformed NSEC rdlength %d, rr->rdlength %d, " 3909 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c); 3910 goto fail; 3911 } 3912 AssignDomainName(&rdb->name, &name); 3913 mDNSPlatformMemCopy(rdb->data + dlen, bmap, bmaplen); 3914 break; 3915 } 3916 case kDNSType_TKEY: 3917 case kDNSType_TSIG: 3918 { 3919 domainname name; 3920 int dlen, rlen; 3921 3922 // The name should not be compressed. But we take the conservative approach 3923 // and uncompress the name before we store it. 3924 if (msg) 3925 { 3926 ptr = getDomainName(msg, ptr, end, &name); 3927 } 3928 else 3929 { 3930 if (!AssignDomainNameWithLimit(&name, (const domainname *)ptr, end)) 3931 { 3932 goto fail; 3933 } 3934 ptr += DomainNameLength(&name); 3935 } 3936 if (!ptr || ptr >= end) 3937 { 3938 LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->rrtype); 3939 goto fail; 3940 } 3941 dlen = DomainNameLength(&name); 3942 rlen = (int)(end - ptr); 3943 rr->rdlength = dlen + rlen; 3944 if (rr->rdlength > MaximumRDSize) 3945 { 3946 LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->rdlength %d, " 3947 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c); 3948 goto fail; 3949 } 3950 AssignDomainName(&rdb->name, &name); 3951 mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen); 3952 break; 3953 } 3954 case kDNSType_TSR: 3955 { 3956 rdb->tsr_value = (mDNSs32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); 3957 break; 3958 } 3959 default: 3960 debugf("SetRData: Warning! Reading resource type %d (%s) as opaque data", 3961 rr->rrtype, DNSTypeName(rr->rrtype)); 3962 // Note: Just because we don't understand the record type, that doesn't 3963 // mean we fail. The DNS protocol specifies rdlength, so we can 3964 // safely skip over unknown records and ignore them. 3965 // We also grab a binary copy of the rdata anyway, since the caller 3966 // might know how to interpret it even if we don't. 3967 rr->rdlength = rdlength; 3968 mDNSPlatformMemCopy(rdb->data, ptr, rdlength); 3969 break; 3970 } 3971 return mDNStrue; 3972 fail: 3973 return mDNSfalse; 3974 } 3975 3976 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, 3977 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr) 3978 { 3979 CacheRecord *const rr = &largecr->r; 3980 mDNSu16 pktrdlength; 3981 mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds; 3982 3983 if (largecr == &m->rec && m->rec.r.resrec.RecordType) 3984 LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r)); 3985 3986 rr->next = mDNSNULL; 3987 rr->resrec.name = &largecr->namestorage; 3988 3989 rr->NextInKAList = mDNSNULL; 3990 rr->TimeRcvd = m ? m->timenow : 0; 3991 rr->DelayDelivery = 0; 3992 rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord() 3993 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS) 3994 rr->LastCachedAnswerTime = 0; 3995 #endif 3996 rr->CRActiveQuestion = mDNSNULL; 3997 rr->UnansweredQueries = 0; 3998 rr->LastUnansweredTime= 0; 3999 rr->NextInCFList = mDNSNULL; 4000 4001 rr->resrec.InterfaceID = InterfaceID; 4002 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 4003 mdns_forget(&rr->resrec.metadata); 4004 #else 4005 rr->resrec.rDNSServer = mDNSNULL; 4006 #endif 4007 4008 ptr = getDomainName(msg, ptr, end, &largecr->namestorage); // Will bail out correctly if ptr is NULL 4009 if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); } 4010 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 4011 4012 if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); } 4013 4014 rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]); 4015 rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask); 4016 rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]); 4017 if (rr->resrec.rroriginalttl > maxttl && (mDNSs32)rr->resrec.rroriginalttl != -1) 4018 rr->resrec.rroriginalttl = maxttl; 4019 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for 4020 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly. 4021 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); 4022 4023 // If mDNS record has cache-flush bit set, we mark it unique 4024 // For uDNS records, all are implicitly deemed unique (a single DNS server is always authoritative for the entire RRSet) 4025 if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || !InterfaceID) 4026 RecordType |= kDNSRecordTypePacketUniqueMask; 4027 ptr += 10; 4028 if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } 4029 end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record 4030 4031 rr->resrec.rdata = (RData*)&rr->smallrdatastorage; 4032 rr->resrec.rdata->MaxRDLength = MaximumRDSize; 4033 4034 if (pktrdlength > MaximumRDSize) 4035 { 4036 LogInfo("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)", 4037 DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength); 4038 goto fail; 4039 } 4040 4041 if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c); 4042 4043 // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding 4044 // cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind 4045 // bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data. 4046 // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that 4047 // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ. 4048 if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136) 4049 rr->resrec.rdlength = 0; 4050 else if (!SetRData(msg, ptr, end, &rr->resrec, pktrdlength)) 4051 { 4052 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 4053 "GetLargeResourceRecord: SetRData failed for " PRI_DM_NAME " (" PUB_S ")", 4054 DM_NAME_PARAM(rr->resrec.name), DNSTypeName(rr->resrec.rrtype)); 4055 goto fail; 4056 } 4057 4058 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us 4059 4060 // Success! Now fill in RecordType to show this record contains valid data 4061 rr->resrec.RecordType = RecordType; 4062 return(end); 4063 4064 fail: 4065 // If we were unable to parse the rdata in this record, we indicate that by 4066 // returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero 4067 rr->resrec.RecordType = kDNSRecordTypePacketNegative; 4068 rr->resrec.rdlength = 0; 4069 rr->resrec.rdestimate = 0; 4070 rr->resrec.rdatahash = 0; 4071 return(end); 4072 } 4073 4074 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end) 4075 { 4076 ptr = skipDomainName(msg, ptr, end); 4077 if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); } 4078 if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); } 4079 return(ptr+4); 4080 } 4081 4082 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, 4083 DNSQuestion *question) 4084 { 4085 mDNSPlatformMemZero(question, sizeof(*question)); 4086 question->InterfaceID = InterfaceID; 4087 if (!InterfaceID) question->TargetQID = onesID; // In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast 4088 ptr = getDomainName(msg, ptr, end, &question->qname); 4089 if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); } 4090 if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); } 4091 4092 question->qnamehash = DomainNameHashValue(&question->qname); 4093 question->qtype = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); // Get type 4094 question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); // and class 4095 return(ptr+4); 4096 } 4097 4098 mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end) 4099 { 4100 int i; 4101 const mDNSu8 *ptr = msg->data; 4102 for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end); 4103 return(ptr); 4104 } 4105 4106 mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end) 4107 { 4108 int i; 4109 const mDNSu8 *ptr = LocateAnswers(msg, end); 4110 for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end); 4111 return(ptr); 4112 } 4113 4114 mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end) 4115 { 4116 int i; 4117 const mDNSu8 *ptr = LocateAuthorities(msg, end); 4118 for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end); 4119 return (ptr); 4120 } 4121 4122 mDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize) 4123 { 4124 int i; 4125 const mDNSu8 *ptr = LocateAdditionals(msg, end); 4126 4127 // Locate the OPT record. 4128 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response." 4129 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section, 4130 // but not necessarily the *last* entry in the Additional Section. 4131 for (i = 0; ptr && i < msg->h.numAdditionals; i++) 4132 { 4133 if (ptr + DNSOpt_Header_Space + minsize <= end && // Make sure we have 11+minsize bytes of data 4134 ptr[0] == 0 && // Name must be root label 4135 ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT 4136 ptr[2] == (kDNSType_OPT & 0xFF) && 4137 ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)minsize) 4138 return(ptr); 4139 else 4140 ptr = skipResourceRecord(msg, ptr, end); 4141 } 4142 return(mDNSNULL); 4143 } 4144 4145 // On success, GetLLQOptData returns pointer to storage within shared "m->rec"; 4146 // it is caller's responsibilty to clear m->rec.r.resrec.RecordType after use 4147 // Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together 4148 // The code that currently calls this assumes there's only one, instead of iterating through the set 4149 mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end) 4150 { 4151 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space); 4152 if (ptr) 4153 { 4154 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 4155 if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]); 4156 } 4157 return(mDNSNULL); 4158 } 4159 4160 // Get the lease life of records in a dynamic update 4161 mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease) 4162 { 4163 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); 4164 if (ptr) 4165 { 4166 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 4167 if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT) 4168 { 4169 const rdataOPT *o; 4170 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 4171 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) 4172 if (o->opt == kDNSOpt_Lease) 4173 { 4174 *lease = o->u.updatelease; 4175 mDNSCoreResetRecord(m); 4176 return mDNStrue; 4177 } 4178 } 4179 mDNSCoreResetRecord(m); 4180 } 4181 return mDNSfalse; 4182 } 4183 4184 #define DNS_OP_Name(X) ( \ 4185 (X) == kDNSFlag0_OP_StdQuery ? "" : \ 4186 (X) == kDNSFlag0_OP_Iquery ? "Iquery " : \ 4187 (X) == kDNSFlag0_OP_Status ? "Status " : \ 4188 (X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \ 4189 (X) == kDNSFlag0_OP_Notify ? "Notify " : \ 4190 (X) == kDNSFlag0_OP_Update ? "Update " : \ 4191 (X) == kDNSFlag0_OP_DSO ? "DSO " : "?? " ) 4192 4193 #define DNS_RC_Name(X) ( \ 4194 (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \ 4195 (X) == kDNSFlag1_RC_FormErr ? "FormErr" : \ 4196 (X) == kDNSFlag1_RC_ServFail ? "ServFail" : \ 4197 (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \ 4198 (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \ 4199 (X) == kDNSFlag1_RC_Refused ? "Refused" : \ 4200 (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \ 4201 (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \ 4202 (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \ 4203 (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \ 4204 (X) == kDNSFlag1_RC_NotZone ? "NotZone" : \ 4205 (X) == kDNSFlag1_RC_DSOTypeNI ? "DSOTypeNI" : "??" ) 4206 4207 mDNSexport void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...) 4208 { 4209 va_list args; 4210 mDNSu32 buflen, n; 4211 char *const dst = *ptr; 4212 4213 buflen = (mDNSu32)(lim - dst); 4214 if (buflen > 0) 4215 { 4216 va_start(args, fmt); 4217 n = mDNS_vsnprintf(dst, buflen, fmt, args); 4218 va_end(args); 4219 *ptr = dst + n; 4220 } 4221 } 4222 4223 #define DNSTypeString(X) (((X) == kDNSType_A) ? "A" : DNSTypeName(X)) 4224 4225 mDNSlocal void DNSMessageDumpToLog(const DNSMessage *const msg, const mDNSu8 *const end) 4226 { 4227 domainname *name = mDNSNULL; 4228 const mDNSu8 *ptr = msg->data; 4229 domainname nameStorage[2]; 4230 4231 char questions[512]; 4232 questions[0] = '\0'; 4233 char *questions_dst = questions; 4234 const char *const questions_lim = &questions[512]; 4235 for (mDNSu32 i = 0; i < msg->h.numQuestions; i++) 4236 { 4237 mDNSu16 qtype, qclass; 4238 4239 name = &nameStorage[0]; 4240 ptr = getDomainName(msg, ptr, end, name); 4241 if (!ptr) goto exit; 4242 4243 if ((end - ptr) < 4) goto exit; 4244 qtype = ReadField16(&ptr[0]); 4245 qclass = ReadField16(&ptr[2]); 4246 ptr += 4; 4247 4248 mDNS_snprintf_add(&questions_dst, questions_lim, " %##s %s", name->c, DNSTypeString(qtype)); 4249 if (qclass != kDNSClass_IN) mDNS_snprintf_add(&questions_dst, questions_lim, "/%u", qclass); 4250 mDNS_snprintf_add(&questions_dst, questions_lim, "?"); 4251 } 4252 4253 char rrs[512]; 4254 rrs[0] = '\0'; 4255 char *rrs_dst = rrs; 4256 const char *const rrs_lim = &rrs[512]; 4257 const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals; 4258 for (mDNSu32 i = 0; i < rrcount; i++) 4259 { 4260 mDNSu16 rrtype, rrclass, rdlength; 4261 mDNSu32 ttl; 4262 int handled; 4263 const mDNSu8 *rdata; 4264 const domainname *const previousName = name; 4265 4266 name = &nameStorage[(name == &nameStorage[0]) ? 1 : 0]; 4267 ptr = getDomainName(msg, ptr, end, name); 4268 if (!ptr) goto exit; 4269 4270 if ((end - ptr) < 10) goto exit; 4271 rrtype = ReadField16(&ptr[0]); 4272 rrclass = ReadField16(&ptr[2]); 4273 ttl = ReadField32(&ptr[4]); 4274 rdlength = ReadField16(&ptr[8]); 4275 ptr += 10; 4276 4277 if ((end - ptr) < rdlength) goto exit; 4278 rdata = ptr; 4279 4280 if (i > 0) mDNS_snprintf_add(&rrs_dst, rrs_lim, ","); 4281 if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&rrs_dst, rrs_lim, " %##s", name); 4282 4283 mDNS_snprintf_add(&rrs_dst, rrs_lim, " %s", DNSTypeString(rrtype)); 4284 if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&rrs_dst, rrs_lim, "/%u", rrclass); 4285 mDNS_snprintf_add(&rrs_dst, rrs_lim, " "); 4286 4287 handled = mDNSfalse; 4288 switch (rrtype) 4289 { 4290 case kDNSType_A: 4291 if (rdlength == 4) 4292 { 4293 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.4a", rdata); 4294 handled = mDNStrue; 4295 } 4296 break; 4297 4298 case kDNSType_AAAA: 4299 if (rdlength == 16) 4300 { 4301 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.16a", rdata); 4302 handled = mDNStrue; 4303 } 4304 break; 4305 4306 case kDNSType_CNAME: 4307 ptr = getDomainName(msg, rdata, end, name); 4308 if (!ptr) goto exit; 4309 4310 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s", name); 4311 handled = mDNStrue; 4312 break; 4313 4314 case kDNSType_SOA: 4315 { 4316 mDNSu32 serial, refresh, retry, expire, minimum; 4317 domainname *const mname = &nameStorage[0]; 4318 domainname *const rname = &nameStorage[1]; 4319 name = mDNSNULL; 4320 4321 ptr = getDomainName(msg, rdata, end, mname); 4322 if (!ptr) goto exit; 4323 4324 ptr = getDomainName(msg, ptr, end, rname); 4325 if (!ptr) goto exit; 4326 4327 if ((end - ptr) < 20) goto exit; 4328 serial = ReadField32(&ptr[0]); 4329 refresh = ReadField32(&ptr[4]); 4330 retry = ReadField32(&ptr[8]); 4331 expire = ReadField32(&ptr[12]); 4332 minimum = ReadField32(&ptr[16]); 4333 4334 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial, 4335 (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum); 4336 4337 handled = mDNStrue; 4338 break; 4339 } 4340 4341 default: 4342 break; 4343 } 4344 if (!handled) mDNS_snprintf_add(&rrs_dst, rrs_lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata); 4345 mDNS_snprintf_add(&rrs_dst, rrs_lim, " (%lu)", (unsigned long)ttl); 4346 ptr = rdata + rdlength; 4347 } 4348 4349 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, 4350 "[Q%u] DNS " PUB_S PUB_S " (%lu) (flags %02X%02X) RCODE: " PUB_S " (%d)" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S ":" 4351 PRI_S " %u/%u/%u " PRI_S, 4352 mDNSVal16(msg->h.id), 4353 DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask), 4354 (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query", 4355 (unsigned long)(end - (const mDNSu8 *)msg), 4356 msg->h.flags.b[0], msg->h.flags.b[1], 4357 DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask), 4358 msg->h.flags.b[1] & kDNSFlag1_RC_Mask, 4359 (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "", 4360 (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "", 4361 (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "", 4362 (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "", 4363 (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "", 4364 (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "", 4365 questions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, rrs); 4366 4367 exit: 4368 return; 4369 } 4370 4371 mDNSlocal mDNSBool DNSMessageIsResponse(const DNSMessage *const msg) 4372 { 4373 return ((msg->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Response); 4374 } 4375 4376 mDNSlocal mDNSBool DNSMessageIsQuery(const DNSMessage *const msg) 4377 { 4378 return !DNSMessageIsResponse(msg); 4379 } 4380 4381 // This function calculates and checks the hash value of the current DNS message if it matches a previous one already. 4382 mDNSlocal void DumpMDNSPacket_CalculateAndCheckIfMsgAppearsBefore(const DNSMessage *const msg, const mDNSu8 *const end, 4383 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport, 4384 const mDNSu32 ifIndex, mDNSu32 *const outMsgHash, mDNSBool *const outMsgHashSame, 4385 mDNSu32 *const outCompleteHash, mDNSBool *const outCompleteHashSame) 4386 { 4387 // We calculate two hash values with different hash algorithms to avoid having collisions frequently. 4388 const mDNSu32 msgLen = sizeof(DNSMessageHeader) + (mDNSu32)(end - msg->data); 4389 const mDNSu32 msgHash = mDNS_NonCryptoHash(mDNSNonCryptoHash_FNV1a, msg->h.id.b, msgLen); 4390 const mDNSu32 msg2ndHash = mDNS_NonCryptoHash(mDNSNonCryptoHash_SDBM, msg->h.id.b, msgLen); 4391 mdns_assign(outMsgHash, msgHash); 4392 4393 mDNSu32 completeHash = msgHash; 4394 mDNSu32 complete2ndHash = msg2ndHash; 4395 if (srcaddr != mDNSNULL) 4396 { 4397 const mDNSu8 *const bytes = srcaddr->ip.v4.b; 4398 const mDNSu32 len = sizeof(srcaddr->ip.v4.b); 4399 4400 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, bytes, len); 4401 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, srcport.b, 4402 sizeof(srcport.b)); 4403 4404 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, bytes, len); 4405 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, srcport.b, 4406 sizeof(srcport.b)); 4407 } 4408 if (dstaddr != mDNSNULL) 4409 { 4410 const mDNSu8 *const bytes = dstaddr->ip.v4.b; 4411 const mDNSu32 len = sizeof(dstaddr->ip.v4.b); 4412 4413 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, bytes, len); 4414 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, dstport.b, 4415 sizeof(dstport.b)); 4416 4417 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, bytes, len); 4418 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, dstport.b, 4419 sizeof(dstport.b)); 4420 } 4421 4422 mDNSu8 ifIndexBytes[4]; 4423 putVal32(ifIndexBytes, ifIndex); 4424 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, ifIndexBytes, 4425 sizeof(ifIndexBytes)); 4426 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, ifIndexBytes, 4427 sizeof(ifIndexBytes)); 4428 mdns_assign(outCompleteHash, completeHash); 4429 4430 #define NUM_OF_SAVED_HASH_COUNT 20 4431 mDNSu32 i; 4432 mDNSu32 count; 4433 4434 static mDNSu32 previousMsgHashes[NUM_OF_SAVED_HASH_COUNT] = {0}; 4435 static mDNSu32 previousMsg2ndHashes[NUM_OF_SAVED_HASH_COUNT] = {0}; 4436 static mDNSu32 nextMsgHashSlot = 0; 4437 static mDNSu32 nextMsgHashUninitializedSlot = 0; 4438 mdns_compile_time_check_local(mdns_countof(previousMsgHashes) == mdns_countof(previousMsg2ndHashes)); 4439 4440 mDNSBool msgHashSame = mDNSfalse; 4441 count = Min(mdns_countof(previousMsgHashes), nextMsgHashUninitializedSlot); 4442 for (i = 0; i < count; i++) 4443 { 4444 if (previousMsgHashes[i] == msgHash && previousMsg2ndHashes[i] == msg2ndHash) 4445 { 4446 msgHashSame = mDNStrue; 4447 break; 4448 } 4449 } 4450 if (!msgHashSame) 4451 { 4452 previousMsgHashes[nextMsgHashSlot] = msgHash; 4453 previousMsg2ndHashes[nextMsgHashSlot] = msg2ndHash; 4454 nextMsgHashSlot++; 4455 nextMsgHashSlot %= mdns_countof(previousMsgHashes); 4456 if (nextMsgHashUninitializedSlot < mdns_countof(previousMsgHashes)) 4457 { 4458 nextMsgHashUninitializedSlot++; 4459 } 4460 } 4461 mdns_assign(outMsgHashSame, msgHashSame); 4462 4463 static mDNSu32 previousCompleteHashes[NUM_OF_SAVED_HASH_COUNT] = {0}; 4464 static mDNSu32 previousComplete2ndHashes[NUM_OF_SAVED_HASH_COUNT] = {0}; 4465 static mDNSu32 nextCompleteHashSlot = 0; 4466 static mDNSu32 nextCompleteHashUninitializedSlot = 0; 4467 mdns_compile_time_check_local(mdns_countof(previousCompleteHashes) == mdns_countof(previousComplete2ndHashes)); 4468 4469 mDNSBool completeHashSame = mDNSfalse; 4470 count = Min(mdns_countof(previousCompleteHashes), nextCompleteHashUninitializedSlot); 4471 for (i = 0; i < count; i++) 4472 { 4473 if (previousCompleteHashes[i] == completeHash && previousComplete2ndHashes[i] == complete2ndHash) 4474 { 4475 completeHashSame = mDNStrue; 4476 break; 4477 } 4478 } 4479 if (!completeHashSame) 4480 { 4481 previousCompleteHashes[nextCompleteHashSlot] = completeHash; 4482 previousComplete2ndHashes[nextCompleteHashSlot] = complete2ndHash; 4483 nextCompleteHashSlot++; 4484 nextCompleteHashSlot %= mdns_countof(previousCompleteHashes); 4485 if (nextCompleteHashUninitializedSlot < mdns_countof(previousCompleteHashes)) 4486 { 4487 nextCompleteHashUninitializedSlot++; 4488 } 4489 } 4490 mdns_assign(outCompleteHashSame, completeHashSame); 4491 } 4492 4493 mDNSlocal mDNSBool DumpMDNSPacket_GetNameHashTypeClass(const DNSMessage *const msg, const mDNSu8 *ptr, 4494 const mDNSu8 *const end, mDNSu32 *const outNameHash, mDNSu16 *const outType, mDNSu16 *const outClass) 4495 { 4496 mDNSBool found; 4497 domainname name; 4498 4499 ptr = getDomainName(msg, ptr, end, &name); 4500 const mDNSu32 nameHash = mDNS_NonCryptoHash(mDNSNonCryptoHash_FNV1a, name.c, DomainNameLength(&name)); 4501 mdns_require_action_quiet(ptr, exit, found = mDNSfalse); 4502 4503 mdns_require_action_quiet(ptr + 4 <= end, exit, found = mDNSfalse); 4504 const mDNSu16 type = ReadField16(&ptr[0]); 4505 mDNSu16 class = ReadField16(&ptr[2]); 4506 4507 const mDNSBool isMDNS = mDNSOpaque16IsZero(msg->h.id); 4508 if (isMDNS) 4509 { 4510 class &= kDNSClass_Mask; 4511 } 4512 4513 mdns_assign(outNameHash, nameHash); 4514 mdns_assign(outType, type); 4515 mdns_assign(outClass, class); 4516 found = mDNStrue; 4517 4518 exit: 4519 return found; 4520 } 4521 4522 // Each name hash/type pair contains 4-byte uint32_t hash value and 2-byte uint16_t type value, in network byte order. 4523 #define DumpMDNSPacket_PairLen (sizeof(mDNSu32) + sizeof(mDNSu16)) 4524 // Currently, we only log the first 10 pairs. 4525 #define DumpMDNSPacket_MaxPairCount 10 4526 // The buffer size to hold the bytes. 4527 #define DumpMDNSPacket_MaxBytesLen (DumpMDNSPacket_PairLen * DumpMDNSPacket_MaxPairCount) 4528 4529 mDNSlocal mStatus DumpMDNSPacket_GetNameHashTypeArray(const DNSMessage *const msg, const mDNSu8 *const end, 4530 mDNSu8 *const inOutNameHashTypeArray, const mDNSu32 maxByteCount, mDNSu32 *const outByteCount) 4531 { 4532 mStatus err; 4533 const mDNSu8 *ptr_to_read; 4534 mDNSu8 *ptr_to_write = inOutNameHashTypeArray; 4535 mDNSu32 pairCount = 0; 4536 const mDNSu32 maxPairCount = maxByteCount / DumpMDNSPacket_PairLen; 4537 4538 const DNSMessageHeader *const hdr = &msg->h; 4539 4540 ptr_to_read = (const mDNSu8 *)msg->data; 4541 for (mDNSu32 i = 0; i < hdr->numQuestions && pairCount < maxPairCount; i++, pairCount++) 4542 { 4543 mDNSu32 qnameHash; 4544 mDNSu16 type; 4545 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &qnameHash, &type, mDNSNULL); 4546 mdns_require_action_quiet(found, exit, err = mStatus_Invalid); 4547 4548 ptr_to_write = putVal32(ptr_to_write, qnameHash); 4549 ptr_to_write = putVal16(ptr_to_write, type); 4550 4551 ptr_to_read = skipQuestion(msg, ptr_to_read, end); 4552 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid); 4553 } 4554 4555 for (mDNSu32 i = 0; i < hdr->numAnswers && pairCount < maxPairCount; i++, pairCount++) 4556 { 4557 mDNSu32 nameHash; 4558 mDNSu16 type; 4559 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &nameHash, &type, mDNSNULL); 4560 mdns_require_action_quiet(found, exit, err = mStatus_Invalid); 4561 4562 ptr_to_write = putVal32(ptr_to_write, nameHash); 4563 ptr_to_write = putVal16(ptr_to_write, type); 4564 4565 ptr_to_read = skipResourceRecord(msg, ptr_to_read, end); 4566 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid); 4567 } 4568 4569 for (mDNSu32 i = 0; i < hdr->numAuthorities && pairCount < maxPairCount; i++, pairCount++) 4570 { 4571 mDNSu32 nameHash; 4572 mDNSu16 type; 4573 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &nameHash, &type, mDNSNULL); 4574 mdns_require_action_quiet(found, exit, err = mStatus_Invalid); 4575 4576 ptr_to_write = putVal32(ptr_to_write, nameHash); 4577 ptr_to_write = putVal16(ptr_to_write, type); 4578 4579 ptr_to_read = skipResourceRecord(msg, ptr_to_read, end); 4580 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid); 4581 } 4582 4583 for (mDNSu32 i = 0; i < hdr->numAdditionals && pairCount < maxPairCount; i++, pairCount++) 4584 { 4585 mDNSu32 nameHash; 4586 mDNSu16 type; 4587 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &nameHash, &type, mDNSNULL); 4588 mdns_require_action_quiet(found, exit, err = mStatus_Invalid); 4589 4590 ptr_to_write = putVal32(ptr_to_write, nameHash); 4591 ptr_to_write = putVal16(ptr_to_write, type); 4592 4593 ptr_to_read = skipResourceRecord(msg, ptr_to_read, end); 4594 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid); 4595 } 4596 4597 err = mStatus_NoError; 4598 exit: 4599 mdns_assign(outByteCount, pairCount * DumpMDNSPacket_PairLen); 4600 return err; 4601 } 4602 4603 mDNSlocal void DumpMDNSPacket(const mDNSBool sent, const DNSMessage *const msg, const mDNSu8 *const end, 4604 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport, 4605 const mDNSu32 ifIndex, const char *const ifName) 4606 { 4607 const mDNSu32 msgLen = sizeof(DNSMessageHeader) + (mDNSu32)(end - msg->data); 4608 const mDNSBool query = DNSMessageIsQuery(msg); 4609 4610 const mDNSBool unicastAssisted = (dstaddr && !mDNSAddrIsDNSMulticast(dstaddr) && 4611 mDNSSameIPPort(dstport, MulticastDNSPort)); 4612 4613 mDNSu32 msgHash; // Hash of the DNS message. 4614 mDNSBool sameMsg; // If the hash matches a previous DNS message. 4615 mDNSu32 completeMsgHash; // Hash of the DNS message, source address/port, destination address/port. 4616 mDNSBool sameCompleteMsg; // If the hash matches a previous DNS message that is sent from the same source host to 4617 // the same destination host. 4618 DumpMDNSPacket_CalculateAndCheckIfMsgAppearsBefore(msg, end, srcaddr, srcport, dstaddr, dstport, ifIndex, &msgHash, 4619 &sameMsg, &completeMsgHash, &sameCompleteMsg); 4620 4621 // The header fields are already in host byte order. 4622 DNSMessageHeader hdr = msg->h; 4623 4624 // Check if it is IPv6 or IPv4 message. 4625 mDNSBool ipv6Msg = mDNSfalse; 4626 if (srcaddr && srcaddr->type == mDNSAddrType_IPv6) 4627 { 4628 ipv6Msg = mDNStrue; 4629 } 4630 else if (dstaddr && dstaddr->type == mDNSAddrType_IPv6) 4631 { 4632 ipv6Msg = mDNStrue; 4633 } 4634 4635 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG) 4636 // The os_log specifier requires network byte order data. 4637 SwapDNSHeaderBytesWithHeader(&hdr); 4638 const mDNSu32 IDFlags = ReadField32(hdr.id.b); 4639 const uint64_t counts = ReadField64(&hdr.numQuestions); 4640 SwapDNSHeaderBytesWithHeader(&hdr); 4641 #endif 4642 4643 // Get the (Name hash, Type) bytes array from the DNS message, where name is converted to a 4-byte hash value 4644 // type is converted to a 2-byte value. 4645 mDNSu8 nameHashTypeBytes[DumpMDNSPacket_MaxBytesLen]; 4646 mDNSu32 nameHashTypeBytesLen; 4647 if (!sameMsg) 4648 { 4649 // Only calculate the name hash type bytes when we have not seen this message recently. 4650 DumpMDNSPacket_GetNameHashTypeArray(msg, end, nameHashTypeBytes, sizeof(nameHashTypeBytes), 4651 &nameHashTypeBytesLen); 4652 } 4653 else 4654 { 4655 nameHashTypeBytesLen = 0; 4656 } 4657 4658 // Note: 4659 // 1. There are two hash values printed for the message logging in `[Q(%x, %x)]`. 4660 // a) The first value is the FNV-1a hash of the entire DNS message, the first value can be used to easily 4661 // identify the same DNS message quickly. 4662 // b) The second value is the FNV-1a hash of the entire DNS message, plus source address, source port, 4663 // destination address, destination port and interface index. This value can be used to easily identify 4664 // repetitive message transmission. 4665 // c) The two hash values above are also used to avoid unnecessary duplicate logs by checking the hash values of 4666 // the recent DNS message (currently recent means recent 20 messages). 4667 // d) We use two separate hash algorithms to check if the message has occurred recently, but we only print 4668 // FNV-1a hash values. 4669 // 2. For all "Send" events, we do not log destination address because it is always the corresponding multicast 4670 // address, there is no need to log them over and over again. 4671 // 3. We print "query", "response" according to the type of the DNS message. 4672 // 4. If we have not seen the DNS message before, the message header, the record count section will be printed. Also 4673 // the first 10 "(name hash, type)" pairs will be printed to provide more context. 4674 // 5. For the "Receive" event, we log source address so that we know where the query or response comes from. 4675 4676 4677 if (unicastAssisted) // unicast DNS 4678 { 4679 if (ipv6Msg) // IPv6 4680 { 4681 if (sent) // Send 4682 { 4683 if (query) // Query 4684 { 4685 if (sameCompleteMsg) 4686 { 4687 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4688 "[Q(%x, %x)] Sent a previous IPv6 mDNS query over unicast", msgHash, completeMsgHash); 4689 } 4690 else if (sameMsg) 4691 { 4692 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4693 "[Q(%x, %x)] Sent a previous IPv6 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S 4694 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex); 4695 } 4696 else 4697 { 4698 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4699 "[Q(%x, %x)] Sent %u-byte IPv6 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S "/%u " 4700 "-- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, 4701 completeMsgHash, msgLen, dstaddr, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), 4702 DNS_MSG_COUNTS_PARAM(hdr, counts), 4703 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4704 } 4705 } 4706 else // Response 4707 { 4708 if (sameCompleteMsg) 4709 { 4710 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4711 "[A(%x, %x)] Sent a previous IPv6 mDNS response over unicast", msgHash, completeMsgHash); 4712 } 4713 else if (sameMsg) 4714 { 4715 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4716 "[A(%x, %x)] Sent a previous IPv6 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S 4717 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex); 4718 } 4719 else 4720 { 4721 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4722 "[A(%x, %x)] Sent %u-byte IPv6 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S 4723 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4724 msgHash, completeMsgHash, msgLen, dstaddr, ifName, ifIndex, 4725 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4726 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4727 } 4728 } 4729 } 4730 else // Receive 4731 { 4732 if (query) // Query 4733 { 4734 if (sameCompleteMsg) 4735 { 4736 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4737 "[A(%x, %x)] Received a previous IPv6 mDNS query over unicast", 4738 msgHash, completeMsgHash); 4739 } 4740 else if (sameMsg) 4741 { 4742 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4743 "[A(%x, %x)] Received a previous IPv6 mDNS query from " PRI_IP_ADDR " over unicast via " 4744 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex); 4745 } 4746 else 4747 { 4748 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4749 "[A(%x, %x)] Received %u-byte IPv6 mDNS query from " PRI_IP_ADDR " over unicast via " PUB_S 4750 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4751 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex, 4752 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4753 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4754 } 4755 } 4756 else // Response 4757 { 4758 if (sameCompleteMsg) 4759 { 4760 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4761 "[Q(%x, %x)] Received a previous IPv6 mDNS response over unicast", 4762 msgHash, completeMsgHash); 4763 } 4764 else if (sameMsg) 4765 { 4766 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4767 "[Q(%x, %x)] Received a previous IPv6 mDNS response from " PRI_IP_ADDR " over unicast via " 4768 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex); 4769 } 4770 else 4771 { 4772 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4773 "[Q(%x, %x)] Received %u-byte IPv6 mDNS response from " PRI_IP_ADDR " over unicast via " 4774 PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4775 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex, 4776 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4777 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4778 } 4779 } 4780 } 4781 } 4782 else // IPv4 4783 { 4784 if (sent) // Send 4785 { 4786 if (query) // Query 4787 { 4788 if (sameCompleteMsg) 4789 { 4790 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4791 "[Q(%x, %x)] Sent a previous IPv4 mDNS query over unicast", msgHash, completeMsgHash); 4792 } 4793 else if (sameMsg) 4794 { 4795 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4796 "[Q(%x, %x)] Sent a previous IPv4 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S 4797 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex); 4798 } 4799 else 4800 { 4801 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4802 "[Q(%x, %x)] Sent %u-byte IPv4 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S "/%u " 4803 "-- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, 4804 completeMsgHash, msgLen, dstaddr, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), 4805 DNS_MSG_COUNTS_PARAM(hdr, counts), 4806 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4807 } 4808 } 4809 else // Response 4810 { 4811 if (sameCompleteMsg) 4812 { 4813 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4814 "[A(%x, %x)] Sent a previous IPv4 mDNS response over unicast", msgHash, completeMsgHash); 4815 } 4816 else if (sameMsg) 4817 { 4818 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4819 "[A(%x, %x)] Sent a previous IPv4 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S 4820 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex); 4821 } 4822 else 4823 { 4824 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4825 "[A(%x, %x)] Sent %u-byte IPv4 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S 4826 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4827 msgHash, completeMsgHash, msgLen, dstaddr, ifName, ifIndex, 4828 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4829 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4830 } 4831 } 4832 } 4833 else // Receive 4834 { 4835 if (query) // Query 4836 { 4837 if (sameCompleteMsg) 4838 { 4839 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4840 "[A(%x, %x)] Received a previous IPv4 mDNS query over unicast", 4841 msgHash, completeMsgHash); 4842 } 4843 else if (sameMsg) 4844 { 4845 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4846 "[A(%x, %x)] Received a previous IPv4 mDNS query from " PRI_IP_ADDR " over unicast via " 4847 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex); 4848 } 4849 else 4850 { 4851 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4852 "[A(%x, %x)] Received %u-byte IPv4 mDNS query from " PRI_IP_ADDR " over unicast via " PUB_S 4853 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4854 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex, 4855 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4856 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4857 } 4858 } 4859 else // Response 4860 { 4861 if (sameCompleteMsg) 4862 { 4863 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4864 "[Q(%x, %x)] Received a previous IPv4 mDNS response over unicast", 4865 msgHash, completeMsgHash); 4866 } 4867 else if (sameMsg) 4868 { 4869 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4870 "[Q(%x, %x)] Received a previous IPv4 mDNS response from " PRI_IP_ADDR " over unicast via " 4871 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex); 4872 } 4873 else 4874 { 4875 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4876 "[Q(%x, %x)] Received %u-byte IPv4 mDNS response from " PRI_IP_ADDR " over unicast via " 4877 PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4878 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex, 4879 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4880 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4881 } 4882 } 4883 } 4884 } 4885 } 4886 else // multicast DNS 4887 { 4888 if (ipv6Msg) // IPv6 4889 { 4890 if (sent) // Send 4891 { 4892 if (query) // Query 4893 { 4894 if (sameCompleteMsg) 4895 { 4896 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4897 "[Q(%x, %x)] Sent a previous IPv6 mDNS query over multicast", msgHash, completeMsgHash); 4898 } 4899 else if (sameMsg) 4900 { 4901 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4902 "[Q(%x, %x)] Sent a previous IPv6 mDNS query over multicast via " PUB_S "/%u", msgHash, 4903 completeMsgHash, ifName, ifIndex); 4904 } 4905 else 4906 { 4907 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4908 "[Q(%x, %x)] Sent %u-byte IPv6 mDNS query over multicast via " PUB_S "/%u -- " 4909 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4910 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), 4911 DNS_MSG_COUNTS_PARAM(hdr, counts), 4912 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4913 } 4914 } 4915 else // Response 4916 { 4917 if (sameCompleteMsg) 4918 { 4919 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4920 "[A(%x, %x)] Sent a previous IPv6 mDNS response over multicast", msgHash, completeMsgHash); 4921 } 4922 else if (sameMsg) 4923 { 4924 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4925 "[A(%x, %x)] Sent a previous IPv6 mDNS response over multicast via " PUB_S "/%u", msgHash, 4926 completeMsgHash, ifName, ifIndex); 4927 } 4928 else 4929 { 4930 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4931 "[A(%x, %x)] Sent %u-byte IPv6 mDNS response over multicast via " PUB_S "/%u -- " 4932 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 4933 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), 4934 DNS_MSG_COUNTS_PARAM(hdr, counts), 4935 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4936 } 4937 } 4938 } 4939 else // Receive 4940 { 4941 if (query) // Query 4942 { 4943 if (sameCompleteMsg) 4944 { 4945 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4946 "[A(%x, %x)] Received a previous IPv6 mDNS query over multicast", msgHash, 4947 completeMsgHash); 4948 } 4949 else if (sameMsg) 4950 { 4951 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4952 "[A(%x, %x)] Received a previous IPv6 mDNS query from " PRI_IP_ADDR 4953 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, 4954 ifIndex); 4955 } 4956 else 4957 { 4958 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4959 "[A(%x, %x)] Received %u-byte IPv6 mDNS query from " PRI_IP_ADDR 4960 " over multicast via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS 4961 " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, 4962 completeMsgHash, msgLen, srcaddr, ifName, ifIndex, 4963 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4964 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4965 } 4966 } 4967 else // Response 4968 { 4969 if (sameCompleteMsg) 4970 { 4971 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4972 "[Q(%x, %x)] Received a previous IPv6 mDNS response over multicast", 4973 msgHash, completeMsgHash); 4974 } 4975 else if (sameMsg) 4976 { 4977 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4978 "[Q(%x, %x)] Received a previous IPv6 mDNS response from " PRI_IP_ADDR 4979 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, 4980 ifIndex); 4981 } 4982 else 4983 { 4984 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 4985 "[Q(%x, %x)] Received %u-byte IPv6 mDNS response from " PRI_IP_ADDR 4986 " over multicast via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS 4987 " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, completeMsgHash, msgLen, srcaddr, ifName, 4988 ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 4989 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 4990 } 4991 } 4992 } 4993 } 4994 else // IPv4 4995 { 4996 if (sent) // Send 4997 { 4998 if (query) // Query 4999 { 5000 if (sameCompleteMsg) 5001 { 5002 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5003 "[Q(%x, %x)] Sent a previous IPv4 mDNS query over multicast", msgHash, completeMsgHash); 5004 } 5005 else if (sameMsg) 5006 { 5007 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5008 "[Q(%x, %x)] Sent a previous IPv4 mDNS query over multicast via " PUB_S "/%u", msgHash, 5009 completeMsgHash, ifName, ifIndex); 5010 } 5011 else 5012 { 5013 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5014 "[Q(%x, %x)] Sent %u-byte IPv4 mDNS query over multicast via " PUB_S "/%u -- " 5015 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 5016 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), 5017 DNS_MSG_COUNTS_PARAM(hdr, counts), 5018 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 5019 } 5020 } 5021 else // Response 5022 { 5023 if (sameCompleteMsg) 5024 { 5025 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5026 "[A(%x, %x)] Sent a previous IPv4 mDNS response over multicast", msgHash, completeMsgHash); 5027 } 5028 else if (sameMsg) 5029 { 5030 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5031 "[A(%x, %x)] Sent a previous IPv4 mDNS response over multicast via " PUB_S "/%u", msgHash, 5032 completeMsgHash, ifName, ifIndex); 5033 } 5034 else 5035 { 5036 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5037 "[A(%x, %x)] Sent %u-byte IPv4 mDNS response over multicast via " PUB_S "/%u -- " 5038 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, 5039 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), 5040 DNS_MSG_COUNTS_PARAM(hdr, counts), 5041 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 5042 } 5043 } 5044 } 5045 else // Receive 5046 { 5047 if (query) // Query 5048 { 5049 if (sameCompleteMsg) 5050 { 5051 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5052 "[A(%x, %x)] Received a previous IPv4 mDNS query over multicast", msgHash, 5053 completeMsgHash); 5054 } 5055 else if (sameMsg) 5056 { 5057 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5058 "[A(%x, %x)] Received a previous IPv4 mDNS query from " PRI_IP_ADDR 5059 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, 5060 ifIndex); 5061 } 5062 else 5063 { 5064 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5065 "[A(%x, %x)] Received %u-byte IPv4 mDNS query from " PRI_IP_ADDR " over multicast" 5066 " via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " 5067 MDNS_NAME_HASH_TYPE_BYTES, msgHash, completeMsgHash, msgLen, srcaddr, ifName, 5068 ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 5069 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 5070 } 5071 } 5072 else // Response 5073 { 5074 if (sameCompleteMsg) 5075 { 5076 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5077 "[Q(%x, %x)] Received a previous IPv4 mDNS response over multicast", 5078 msgHash, completeMsgHash); 5079 } 5080 else if (sameMsg) 5081 { 5082 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5083 "[Q(%x, %x)] Received a previous IPv4 mDNS response from " PRI_IP_ADDR 5084 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, 5085 ifIndex); 5086 } 5087 else 5088 { 5089 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT, 5090 "[Q(%x, %x)] Received %u-byte IPv4 mDNS response from " PRI_IP_ADDR 5091 " over multicast via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS 5092 " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, completeMsgHash, msgLen, srcaddr, ifName, 5093 ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts), 5094 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen)); 5095 } 5096 } 5097 } 5098 } 5099 } 5100 } 5101 5102 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order 5103 mDNSexport void DumpPacket(mStatus status, mDNSBool sent, const char *transport, 5104 const mDNSAddr *srcaddr, mDNSIPPort srcport,const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, 5105 const mDNSu8 *const end, mDNSInterfaceID interfaceID) 5106 { 5107 const mDNSAddr zeroIPv4Addr = { mDNSAddrType_IPv4, {{{ 0 }}} }; 5108 char action[32]; 5109 5110 if (!status) mDNS_snprintf(action, sizeof(action), sent ? "Sent" : "Received"); 5111 else mDNS_snprintf(action, sizeof(action), "ERROR %d %sing", status, sent ? "Send" : "Receiv"); 5112 5113 #if __APPLE__ 5114 const mDNSu32 interfaceIndex = IIDPrintable(interfaceID); 5115 const char *const interfaceName = InterfaceNameForID(&mDNSStorage, interfaceID); 5116 #else 5117 const mDNSu32 interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, interfaceID, mDNStrue); 5118 const char *const interfaceName = "interface"; 5119 #endif 5120 5121 if (!mDNSOpaque16IsZero(msg->h.id)) 5122 { 5123 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[Q%u] " PUB_S " " PUB_S " DNS Message %lu bytes from " 5124 PRI_IP_ADDR ":%d to " PRI_IP_ADDR ":%d via " PUB_S " (%p)", mDNSVal16(msg->h.id), action, transport, 5125 (unsigned long)(end - (const mDNSu8 *)msg), srcaddr ? srcaddr : &zeroIPv4Addr, mDNSVal16(srcport), 5126 dstaddr ? dstaddr : &zeroIPv4Addr, mDNSVal16(dstport), interfaceName, interfaceID); 5127 DNSMessageDumpToLog(msg, end); 5128 } 5129 else 5130 { 5131 DumpMDNSPacket(sent, msg, end, srcaddr, srcport, dstaddr, dstport, interfaceIndex, interfaceName); 5132 if (status) 5133 { 5134 if (sent) 5135 { 5136 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR, 5137 "Sending mDNS message failed - mStatus: %d", status); 5138 } 5139 else 5140 { 5141 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR, 5142 "Receiving mDNS message failed - mStatus: %d", status); 5143 } 5144 } 5145 } 5146 } 5147 5148 // *************************************************************************** 5149 // MARK: - Packet Sending Functions 5150 5151 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.) 5152 struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ }; 5153 // Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.) 5154 struct UDPSocket_struct { mDNSIPPort port; /* ... */ }; 5155 5156 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which 5157 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible. 5158 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, 5159 mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst, 5160 mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass) 5161 { 5162 mStatus status = mStatus_NoError; 5163 const mDNSu16 numAdditionals = msg->h.numAdditionals; 5164 5165 5166 // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code) 5167 if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData) 5168 { 5169 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: invalid message %p %p %ld", msg->data, end, end - msg->data); 5170 return mStatus_BadParamErr; 5171 } 5172 5173 // Put all the integer values in IETF byte-order (MSB first, LSB second) 5174 SwapDNSHeaderBytes(msg); 5175 5176 if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0); // DNSDigest_SignMessage operates on message in network byte order 5177 5178 #if defined(DEBUG) && DEBUG 5179 if (authInfo && end) 5180 { 5181 // If this is a debug build, every time when we sign the response, use the verifying function to ensure that 5182 // both functions work correctly. 5183 DNSDigest_VerifyMessage_Verify(msg, end, authInfo); 5184 } 5185 #endif 5186 5187 if (!end) 5188 { 5189 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: DNSDigest_SignMessage failed"); 5190 status = mStatus_NoMemoryErr; 5191 } 5192 else 5193 { 5194 // Send the packet on the wire 5195 if (!tcpSrc) 5196 status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, udpSrc, dst, dstport, useBackgroundTrafficClass); 5197 else 5198 { 5199 mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg); 5200 mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) }; 5201 char *buf; 5202 long nsent; 5203 5204 // Try to send them in one packet if we can allocate enough memory 5205 buf = (char *) mDNSPlatformMemAllocate(msglen + 2); 5206 if (buf) 5207 { 5208 buf[0] = lenbuf[0]; 5209 buf[1] = lenbuf[1]; 5210 mDNSPlatformMemCopy(buf+2, msg, msglen); 5211 nsent = mDNSPlatformWriteTCP(tcpSrc, buf, msglen+2); 5212 if (nsent != (msglen + 2)) 5213 { 5214 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: write message failed %ld/%d", nsent, msglen); 5215 status = mStatus_ConnFailed; 5216 } 5217 mDNSPlatformMemFree(buf); 5218 } 5219 else 5220 { 5221 nsent = mDNSPlatformWriteTCP(tcpSrc, (char*)lenbuf, 2); 5222 if (nsent != 2) 5223 { 5224 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: write msg length failed %ld/%d", nsent, 2); 5225 status = mStatus_ConnFailed; 5226 } 5227 else 5228 { 5229 nsent = mDNSPlatformWriteTCP(tcpSrc, (char *)msg, msglen); 5230 if (nsent != msglen) 5231 { 5232 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: write msg body failed %ld/%d", nsent, msglen); 5233 status = mStatus_ConnFailed; 5234 } 5235 } 5236 } 5237 } 5238 } 5239 5240 // Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage) 5241 SwapDNSHeaderBytes(msg); 5242 5243 char *transport = "UDP"; 5244 mDNSIPPort portNumber = udpSrc ? udpSrc->port : MulticastDNSPort; 5245 if (tcpSrc) 5246 { 5247 if (tcpSrc->flags) 5248 transport = "TLS"; 5249 else 5250 transport = "TCP"; 5251 portNumber = tcpSrc->port; 5252 } 5253 DumpPacket(status, mDNStrue, transport, mDNSNULL, portNumber, dst, dstport, msg, end, InterfaceID); 5254 5255 // put the number of additionals back the way it was 5256 msg->h.numAdditionals = numAdditionals; 5257 5258 return(status); 5259 } 5260 5261 // *************************************************************************** 5262 // MARK: - DNSQuestion Functions 5263 5264 #if MDNSRESPONDER_SUPPORTS(APPLE, LOG_PRIVACY_LEVEL) 5265 mDNSBool DNSQuestionNeedsSensitiveLogging(const DNSQuestion *const q) 5266 { 5267 return is_apple_internal_build() && (q->logPrivacyLevel == dnssd_log_privacy_level_private); 5268 } 5269 #endif 5270 5271 #if MDNSRESPONDER_SUPPORTS(APPLE, RUNTIME_MDNS_METRICS) 5272 mDNSBool DNSQuestionCollectsMDNSMetric(const DNSQuestion *const q) 5273 { 5274 return (!q->DuplicateOf && mDNSOpaque16IsZero(q->TargetQID)); 5275 } 5276 #endif 5277 5278 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY) 5279 5280 mDNSlocal mDNSBool DNSQuestionUsesAWDL(const DNSQuestion *const q) 5281 { 5282 if (q->InterfaceID == mDNSInterface_Any) 5283 { 5284 return ((q->flags & kDNSServiceFlagsIncludeAWDL) != 0); 5285 } 5286 else 5287 { 5288 return mDNSPlatformInterfaceIsAWDL(q->InterfaceID); 5289 } 5290 } 5291 5292 mDNSBool DNSQuestionIsEligibleForMDNSAlternativeService(const DNSQuestion *const q) 5293 { 5294 // 0. The system is not in a demo mode where mDNS traffic is ensured to be lossless in a wired connection. 5295 // 1. The question must be an mDNS question. 5296 // 2. The question cannot enable resolution over AWDL. 5297 // (because the resolution over mDNS alternative service is mutual exclusive with the resolution over AWDL) 5298 return (!is_airplay_demo_mode_enabled() && mDNSOpaque16IsZero(q->TargetQID) && !DNSQuestionUsesAWDL(q)); 5299 } 5300 5301 mDNSBool DNSQuestionRequestsMDNSAlternativeService(const DNSQuestion *const q) 5302 { 5303 return (!mDNSOpaque16IsZero(q->TargetQID) && !Question_uDNS(q)); 5304 } 5305 5306 mDNSBool DNSQuestionUsesMDNSAlternativeService(const DNSQuestion *const q) 5307 { 5308 return q->dnsservice && mdns_dns_service_is_mdns_alternative(q->dnsservice); 5309 } 5310 #endif 5311 5312 // *************************************************************************** 5313 // MARK: - RR List Management & Task Management 5314 5315 mDNSexport void mDNS_VerifyLockState(const char *const operation, const mDNSBool checkIfLockHeld, 5316 const mDNSu32 mDNS_busy, const mDNSu32 mDNS_reentrancy, const char *const functionName, const mDNSu32 lineNumber) 5317 { 5318 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK) 5319 static os_unfair_lock logLock = OS_UNFAIR_LOCK_INIT; 5320 #endif 5321 static const char *lastLockOperator = mDNSNULL; // The name of the function that succeeded in doing lock operation last time. 5322 static mDNSu32 lineNumberlastLockOperator = 0; // The line number in the source code when this function gets called last time. 5323 5324 #define CRASH_ON_LOCK_ERROR 0 5325 #if (CRASH_ON_LOCK_ERROR) 5326 // When CRASH_ON_LOCK_ERROR is set to 1, if we encounter lock error, we will make mDNSResponder crash immediately 5327 // to let the bug to be identified easily. 5328 mDNSBool lockErrorEncountered = mDNSfalse; 5329 #endif 5330 5331 if (checkIfLockHeld) 5332 { 5333 // If the lock is held by the caller, then the number of times that the lock has been grabbed should be one more 5334 // than the number of times that the lock has been dropped, so that only one lock is currently being held. 5335 if (mDNS_busy > mDNS_reentrancy + 1) 5336 { 5337 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, 5338 "Lock failure: Check Lock, lock was grabbed by multiple callers - " 5339 "caller: " PUB_S " at line %u, last successful lock holder: " PUB_S " at line %u, " 5340 "mDNS_busy (%u) != mDNS_reentrancy (%u).", functionName, lineNumber, lastLockOperator, 5341 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy); 5342 #if (CRASH_ON_LOCK_ERROR) 5343 lockErrorEncountered = mDNStrue; 5344 #endif 5345 } 5346 else if (mDNS_busy < mDNS_reentrancy + 1) 5347 { 5348 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, 5349 "Lock failure: Check Lock, last lock dropper dropped the lock before grabbing it - " 5350 "caller: " PUB_S " at line %u, last lock dropper: " PUB_S " at line %u, " 5351 "mDNS_busy (%u) != mDNS_reentrancy (%u).", functionName, lineNumber, lastLockOperator, 5352 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy); 5353 #if (CRASH_ON_LOCK_ERROR) 5354 lockErrorEncountered = mDNStrue; 5355 #endif 5356 } 5357 } 5358 else 5359 { 5360 // In non-critical section: 5361 // The number of times that the lock has been grabbed should be equal to the number of times that the lock has 5362 // been dropped, which means, no one is currently holding the real lock. 5363 if (mDNS_busy == mDNS_reentrancy) 5364 { 5365 switch (operation[0]) 5366 { 5367 case 'L': // "Lock" (it is paired with "Unlock") 5368 case 'D': // "Drop Lock" (it is paired with "Reclaim Lock") 5369 // Add new lock state, and we need to remember who succeeds in doing the operation because it might 5370 // lead to invalid lock state. 5371 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK) 5372 os_unfair_lock_lock(&logLock); 5373 #endif 5374 lastLockOperator = functionName; 5375 lineNumberlastLockOperator = lineNumber; 5376 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK) 5377 os_unfair_lock_unlock(&logLock); 5378 #endif 5379 break; 5380 5381 case 'U': // "Unlock" 5382 case 'R': // "Reclaim Lock" 5383 // Remove the previous lock state, and we can remove the name and the line number that has been 5384 // saved. 5385 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK) 5386 os_unfair_lock_lock(&logLock); 5387 #endif 5388 lastLockOperator = mDNSNULL; 5389 lineNumberlastLockOperator = 0; 5390 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK) 5391 os_unfair_lock_unlock(&logLock); 5392 #endif 5393 case 'C': // "Check Lock" 5394 // "Check Lock" operation will never change the lock state, so no need to take a note for that. 5395 break; 5396 5397 default: 5398 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, "Invalid lock operation - " PUB_S, operation); 5399 break; 5400 } 5401 } 5402 else if (mDNS_busy > mDNS_reentrancy) 5403 { 5404 // If mDNS_busy is greater than mDNS_reentrancy, there is someone who has grabbed the lock. This is invalid 5405 // in a critical section. 5406 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, 5407 "Lock failure: " PUB_S ", last lock holder still holds the lock - " 5408 "caller: " PUB_S " at line %u, last successful lock holder: " PUB_S " at line %u, " 5409 "mDNS_busy (%u) != mDNS_reentrancy (%u).", operation, functionName, lineNumber, lastLockOperator, 5410 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy); 5411 #if (CRASH_ON_LOCK_ERROR) 5412 lockErrorEncountered = mDNStrue; 5413 #endif 5414 } 5415 else // m->mDNS_busy < m->mDNS_reentrancy 5416 { 5417 // If mDNS_busy is less than mDNS_reentrancy, something bad happens, because no one should drop the lock 5418 // before grabbing it successfully. This should never heppen. 5419 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, 5420 "Lock failure: " PUB_S ", last lock dropper dropped the lock before grabbing it - " 5421 "caller: " PUB_S " at line %u, last lock dropper: " PUB_S " at line %u, " 5422 "mDNS_busy (%u) != mDNS_reentrancy (%u).", operation, functionName, lineNumber, lastLockOperator, 5423 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy); 5424 #if (CRASH_ON_LOCK_ERROR) 5425 lockErrorEncountered = mDNStrue; 5426 #endif 5427 } 5428 } 5429 5430 #if (CRASH_ON_LOCK_ERROR) 5431 if (lockErrorEncountered) 5432 { 5433 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 5434 "Encounter lock error, make mDNSResponder crash immediately."); 5435 assert(0); 5436 } 5437 #endif 5438 } 5439 5440 mDNSexport void mDNS_Lock_(mDNS *const m, const char *const functionName, const mDNSu32 lineNumber) 5441 { 5442 // MUST grab the platform lock FIRST! 5443 mDNSPlatformLock(m); 5444 5445 // Normally, mDNS_reentrancy is zero and so is mDNS_busy 5446 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too 5447 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one 5448 // If mDNS_busy != mDNS_reentrancy that's a bad sign 5449 mDNS_VerifyLockState("Lock", mDNSfalse, m->mDNS_busy, m->mDNS_reentrancy, functionName, lineNumber); 5450 5451 // If this is an initial entry into the mDNSCore code, set m->timenow 5452 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set 5453 if (m->mDNS_busy == 0) 5454 { 5455 if (m->timenow) 5456 { 5457 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, PUB_S ": mDNS_Lock: m->timenow already set (%u/%u)", 5458 functionName, m->timenow, mDNS_TimeNow_NoLock(m)); 5459 } 5460 5461 m->timenow = mDNS_TimeNow_NoLock(m); 5462 if (m->timenow == 0) m->timenow = 1; 5463 } 5464 else if (m->timenow == 0) 5465 { 5466 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, 5467 PUB_S ": mDNS_Lock: m->mDNS_busy is %u but m->timenow not set", functionName, m->mDNS_busy); 5468 5469 m->timenow = mDNS_TimeNow_NoLock(m); 5470 if (m->timenow == 0) m->timenow = 1; 5471 } 5472 5473 if (m->timenow_last - m->timenow > 0) 5474 { 5475 m->timenow_adjust += m->timenow_last - m->timenow; 5476 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, 5477 PUB_S ": mDNSPlatformRawTime went backwards by %d ticks; setting correction factor to %d", 5478 functionName, m->timenow_last - m->timenow, m->timenow_adjust); 5479 5480 m->timenow = m->timenow_last; 5481 } 5482 m->timenow_last = m->timenow; 5483 5484 // Increment mDNS_busy so we'll recognise re-entrant calls 5485 m->mDNS_busy++; 5486 m->mDNS_Lock_functionname = functionName; 5487 m->mDNS_Lock_lineno = lineNumber; 5488 } 5489 5490 mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m) 5491 { 5492 AuthRecord *rr; 5493 for (rr = m->NewLocalRecords; rr; rr = rr->next) 5494 if (LocalRecordReady(rr)) return rr; 5495 return mDNSNULL; 5496 } 5497 5498 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) 5499 { 5500 mDNSs32 e = m->timenow + FutureTime; 5501 if (m->mDNSPlatformStatus != mStatus_NoError) return(e); 5502 if (m->NewQuestions) 5503 { 5504 if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering; 5505 else return(m->timenow); 5506 } 5507 if (m->NewLocalOnlyQuestions) return(m->timenow); 5508 if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow); 5509 if (m->NewLocalOnlyRecords) return(m->timenow); 5510 if (m->SPSProxyListChanged) return(m->timenow); 5511 if (m->LocalRemoveEvents) return(m->timenow); 5512 5513 #ifndef UNICAST_DISABLED 5514 if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent; 5515 if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp; 5516 if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate; 5517 #endif 5518 5519 if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck; 5520 if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS; 5521 if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA; 5522 5523 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND) 5524 if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime; 5525 #endif 5526 5527 // Check if it is time to stop domain enumeration. 5528 for (const DomainEnumerationOp *op = m->domainsToDoEnumeration; op != mDNSNULL; op = op->next) 5529 { 5530 // Iterate over all types of domain enumeration. 5531 for (mDNSu32 type = 0; type < mDNS_DomainTypeMaxCount; type++) 5532 { 5533 if (op->enumerations[type] == mDNSNULL) 5534 { 5535 continue; 5536 } 5537 5538 // Only check the domain enumeration that starts the stopping process. 5539 if (op->enumerations[type]->state != DomainEnumerationState_StopInProgress) 5540 { 5541 continue; 5542 } 5543 5544 if (e - op->enumerations[type]->nextStopTime > 0) 5545 { 5546 e = op->enumerations[type]->nextStopTime; 5547 } 5548 } 5549 } 5550 5551 #if MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY) 5552 const mDNSs32 nextResolverDiscoveryEvent = ResolverDiscovery_GetNextScheduledEvent(); 5553 if (nextResolverDiscoveryEvent && (e - nextResolverDiscoveryEvent > 0)) e = nextResolverDiscoveryEvent; 5554 #endif 5555 5556 // NextScheduledSPRetry only valid when DelaySleep not set 5557 if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry; 5558 if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep; 5559 5560 if (m->SuppressQueries) 5561 { 5562 if (e - m->SuppressQueries > 0) e = m->SuppressQueries; 5563 } 5564 else 5565 { 5566 if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery; 5567 if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe; 5568 } 5569 if (m->SuppressResponses) 5570 { 5571 if (e - m->SuppressResponses > 0) e = m->SuppressResponses; 5572 } 5573 else 5574 { 5575 if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; 5576 } 5577 if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime; 5578 5579 if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime; 5580 5581 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 5582 if (m->NextUpdateDNSSECValidatedCache && (e - m->NextUpdateDNSSECValidatedCache > 0)) 5583 { 5584 e = m->NextUpdateDNSSECValidatedCache; 5585 } 5586 #endif 5587 5588 #if MDNSRESPONDER_SUPPORTS(APPLE, RUNTIME_MDNS_METRICS) 5589 if (m->NextMDNSResponseDelayReport && (e - m->NextMDNSResponseDelayReport > 0)) 5590 { 5591 e = m->NextMDNSResponseDelayReport; 5592 } 5593 #endif 5594 5595 return(e); 5596 } 5597 5598 #define LogTSE TSE++,LogMsg 5599 5600 mDNSexport void ShowTaskSchedulingError(mDNS *const m) 5601 { 5602 int TSE = 0; 5603 AuthRecord *rr; 5604 mDNS_Lock(m); 5605 5606 LogMsg("Task Scheduling Error: *** Continuously busy for more than a second"); 5607 5608 // Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above 5609 5610 if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0)) 5611 LogTSE("Task Scheduling Error: NewQuestion %##s (%s)", 5612 m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype)); 5613 5614 if (m->NewLocalOnlyQuestions) 5615 LogTSE("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)", 5616 m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype)); 5617 5618 if (m->NewLocalRecords) 5619 { 5620 rr = AnyLocalRecordReady(m); 5621 if (rr) LogTSE("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr)); 5622 } 5623 5624 if (m->NewLocalOnlyRecords) LogTSE("Task Scheduling Error: NewLocalOnlyRecords"); 5625 5626 if (m->SPSProxyListChanged) LogTSE("Task Scheduling Error: SPSProxyListChanged"); 5627 5628 if (m->LocalRemoveEvents) LogTSE("Task Scheduling Error: LocalRemoveEvents"); 5629 5630 #ifndef UNICAST_DISABLED 5631 if (m->timenow - m->NextuDNSEvent >= 0) 5632 LogTSE("Task Scheduling Error: m->NextuDNSEvent %d", m->timenow - m->NextuDNSEvent); 5633 if (m->timenow - m->NextScheduledNATOp >= 0) 5634 LogTSE("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp); 5635 if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) 5636 LogTSE("Task Scheduling Error: m->NextSRVUpdate %d", m->timenow - m->NextSRVUpdate); 5637 #endif 5638 5639 if (m->timenow - m->NextCacheCheck >= 0) 5640 LogTSE("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck); 5641 if (m->timenow - m->NextScheduledSPS >= 0) 5642 LogTSE("Task Scheduling Error: m->NextScheduledSPS %d", m->timenow - m->NextScheduledSPS); 5643 if (m->timenow - m->NextScheduledKA >= 0) 5644 LogTSE("Task Scheduling Error: m->NextScheduledKA %d", m->timenow - m->NextScheduledKA); 5645 if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0) 5646 LogTSE("Task Scheduling Error: m->NextScheduledSPRetry %d", m->timenow - m->NextScheduledSPRetry); 5647 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) 5648 LogTSE("Task Scheduling Error: m->DelaySleep %d", m->timenow - m->DelaySleep); 5649 5650 if (m->SuppressQueries && m->timenow - m->SuppressQueries >= 0) 5651 LogTSE("Task Scheduling Error: m->SuppressQueries %d", m->timenow - m->SuppressQueries); 5652 if (m->SuppressResponses && m->timenow - m->SuppressResponses >= 0) 5653 LogTSE("Task Scheduling Error: m->SuppressResponses %d", m->timenow - m->SuppressResponses); 5654 if (m->timenow - m->NextScheduledQuery >= 0) 5655 LogTSE("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery); 5656 if (m->timenow - m->NextScheduledProbe >= 0) 5657 LogTSE("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe); 5658 if (m->timenow - m->NextScheduledResponse >= 0) 5659 LogTSE("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse); 5660 if (m->timenow - m->NextScheduledStopTime >= 0) 5661 LogTSE("Task Scheduling Error: m->NextScheduledStopTime %d", m->timenow - m->NextScheduledStopTime); 5662 5663 if (m->timenow - m->NextScheduledEvent >= 0) 5664 LogTSE("Task Scheduling Error: m->NextScheduledEvent %d", m->timenow - m->NextScheduledEvent); 5665 5666 if (m->NetworkChanged && m->timenow - m->NetworkChanged >= 0) 5667 LogTSE("Task Scheduling Error: NetworkChanged %d", m->timenow - m->NetworkChanged); 5668 5669 if (!TSE) LogMsg("Task Scheduling Error: *** No likely causes identified"); 5670 else LogMsg("Task Scheduling Error: *** %d potential cause%s identified (significant only if the same cause consistently appears)", TSE, TSE > 1 ? "s" : ""); 5671 5672 mDNS_Unlock(m); 5673 } 5674 5675 mDNSexport void mDNS_Unlock_(mDNS *const m, const char *const functionName, const mDNSu32 lineNumber) 5676 { 5677 // Decrement mDNS_busy 5678 m->mDNS_busy--; 5679 5680 // Check for locking failures 5681 mDNS_VerifyLockState("Unlock", mDNSfalse, m->mDNS_busy, m->mDNS_reentrancy, functionName, lineNumber); 5682 5683 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow 5684 if (m->mDNS_busy == 0) 5685 { 5686 m->NextScheduledEvent = GetNextScheduledEvent(m); 5687 if (m->timenow == 0) 5688 { 5689 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, PUB_S ": mDNS_Unlock: ERROR! m->timenow aready zero", 5690 functionName); 5691 } 5692 m->timenow = 0; 5693 } 5694 5695 // MUST release the platform lock LAST! 5696 mDNSPlatformUnlock(m); 5697 } 5698 5699 // *************************************************************************** 5700 // MARK: - Specialized mDNS version of vsnprintf 5701 5702 static const struct mDNSprintf_format 5703 { 5704 unsigned leftJustify : 1; 5705 unsigned forceSign : 1; 5706 unsigned zeroPad : 1; 5707 unsigned havePrecision : 1; 5708 unsigned hSize : 1; 5709 unsigned lSize : 1; 5710 char altForm; 5711 char sign; // +, - or space 5712 unsigned int fieldWidth; 5713 unsigned int precision; 5714 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 5715 5716 #define kHexDigitsLowercase "0123456789abcdef" 5717 #define kHexDigitsUppercase "0123456789ABCDEF"; 5718 5719 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) 5720 { 5721 mDNSu32 nwritten = 0; 5722 int c; 5723 if (buflen == 0) return(0); 5724 buflen--; // Pre-reserve one space in the buffer for the terminating null 5725 if (buflen == 0) goto exit; 5726 5727 for (c = *fmt; c != '\0'; c = (c != '\0') ? *++fmt : c) 5728 { 5729 unsigned long n; 5730 int hexdump = mDNSfalse; 5731 if (c != '%') 5732 { 5733 *sbuffer++ = (char)c; 5734 if (++nwritten >= buflen) goto exit; 5735 } 5736 else 5737 { 5738 unsigned int i=0, j; 5739 // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for 5740 // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc. 5741 // The size needs to be enough for a 256-byte domain name plus some error text. 5742 #define mDNS_VACB_Size 300 5743 char mDNS_VACB[mDNS_VACB_Size]; 5744 #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size]) 5745 #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s)) 5746 char *s = mDNS_VACB_Lim, *digits; 5747 struct mDNSprintf_format F = mDNSprintf_format_default; 5748 5749 while (1) // decode flags 5750 { 5751 c = *++fmt; 5752 if (c == '-') F.leftJustify = 1; 5753 else if (c == '+') F.forceSign = 1; 5754 else if (c == ' ') F.sign = ' '; 5755 else if (c == '#') F.altForm++; 5756 else if (c == '0') F.zeroPad = 1; 5757 else break; 5758 } 5759 5760 if (c == '*') // decode field width 5761 { 5762 int f = va_arg(arg, int); 5763 if (f < 0) { f = -f; F.leftJustify = 1; } 5764 F.fieldWidth = (unsigned int)f; 5765 c = *++fmt; 5766 } 5767 else 5768 { 5769 for (; c >= '0' && c <= '9'; c = *++fmt) 5770 F.fieldWidth = (10 * F.fieldWidth) + (c - '0'); 5771 } 5772 5773 if (c == '.') // decode precision 5774 { 5775 if ((c = *++fmt) == '*') 5776 { F.precision = va_arg(arg, unsigned int); c = *++fmt; } 5777 else for (; c >= '0' && c <= '9'; c = *++fmt) 5778 F.precision = (10 * F.precision) + (c - '0'); 5779 F.havePrecision = 1; 5780 } 5781 5782 if (F.leftJustify) F.zeroPad = 0; 5783 5784 conv: 5785 switch (c) // perform appropriate conversion 5786 { 5787 case 'h': F.hSize = 1; c = *++fmt; goto conv; 5788 case 'l': // fall through 5789 case 'L': F.lSize = 1; c = *++fmt; goto conv; 5790 case 'd': 5791 case 'i': if (F.lSize) n = (unsigned long)va_arg(arg, long); 5792 else n = (unsigned long)va_arg(arg, int); 5793 if (F.hSize) n = (short) n; 5794 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; } 5795 else if (F.forceSign) F.sign = '+'; 5796 goto decimal; 5797 case 'u': if (F.lSize) n = va_arg(arg, unsigned long); 5798 else n = va_arg(arg, unsigned int); 5799 if (F.hSize) n = (unsigned short) n; 5800 F.sign = 0; 5801 goto decimal; 5802 decimal: if (!F.havePrecision) 5803 { 5804 if (F.zeroPad) 5805 { 5806 F.precision = F.fieldWidth; 5807 if (F.sign) --F.precision; 5808 } 5809 if (F.precision < 1) F.precision = 1; 5810 } 5811 if (F.precision > mDNS_VACB_Size - 1) 5812 F.precision = mDNS_VACB_Size - 1; 5813 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0'); 5814 for (; i < F.precision; i++) *--s = '0'; 5815 if (F.sign) { *--s = F.sign; i++; } 5816 break; 5817 5818 case 'o': if (F.lSize) n = va_arg(arg, unsigned long); 5819 else n = va_arg(arg, unsigned int); 5820 if (F.hSize) n = (unsigned short) n; 5821 if (!F.havePrecision) 5822 { 5823 if (F.zeroPad) F.precision = F.fieldWidth; 5824 if (F.precision < 1) F.precision = 1; 5825 } 5826 if (F.precision > mDNS_VACB_Size - 1) 5827 F.precision = mDNS_VACB_Size - 1; 5828 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0'); 5829 if (F.altForm && i && *s != '0') { *--s = '0'; i++; } 5830 for (; i < F.precision; i++) *--s = '0'; 5831 break; 5832 5833 case 'a': { 5834 unsigned char *a = va_arg(arg, unsigned char *); 5835 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } 5836 else 5837 { 5838 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end 5839 if (F.altForm) 5840 { 5841 const mDNSAddr *const ip = (const mDNSAddr *)a; 5842 switch (ip->type) 5843 { 5844 case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break; 5845 case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break; 5846 default: 5847 if (ip->type == mDNSAddrType_None) 5848 { 5849 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNSPECIFIED IP ADDRESS>>"); 5850 } 5851 else 5852 { 5853 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), 5854 "<<ERROR: %%#a used with unsupported type: %d>>", ip->type); 5855 } 5856 F.precision = 0; 5857 break; 5858 } 5859 } 5860 if (!F.altForm || (F.precision != 0)) 5861 { 5862 switch (F.precision) 5863 { 5864 case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d", 5865 a[0], a[1], a[2], a[3]); break; 5866 case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", 5867 a[0], a[1], a[2], a[3], a[4], a[5]); break; 5868 case 16: { 5869 // Print IPv6 addresses according to RFC 5952, A Recommendation for IPv6 Address Text 5870 // Representation. See <https://tools.ietf.org/html/rfc5952>. 5871 5872 int idx, runLen = 0, runStart = 0, maxRunLen = 0, maxRunStart = 0, maxRunEnd; 5873 5874 // Find the leftmost longest run of consecutive zero hextets. 5875 for (idx = 0; idx < 8; ++idx) 5876 { 5877 const unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1]; 5878 if (hextet == 0) 5879 { 5880 if (runLen++ == 0) runStart = idx; 5881 if (runLen > maxRunLen) 5882 { 5883 maxRunStart = runStart; 5884 maxRunLen = runLen; 5885 } 5886 } 5887 else 5888 { 5889 // If the number of remaining hextets is less than or equal to the length of the longest 5890 // run so far, then we've found the leftmost longest run. 5891 if ((8 - (idx + 1)) <= maxRunLen) break; 5892 runLen = 0; 5893 } 5894 } 5895 5896 // Compress the leftmost longest run of two or more consecutive zero hextets as "::". 5897 // For each reminaing hextet, suppress zeros leading up to the least-significant nibble, which 5898 // is always written, even if it's zero. Because of this requirement, it's easier to write the 5899 // IPv6 address in reverse. Also, write a colon separator before each hextet except for the 5900 // first one. 5901 s = mDNS_VACB_Lim; 5902 maxRunEnd = (maxRunLen >= 2) ? (maxRunStart + maxRunLen - 1) : -1; 5903 for (idx = 7; idx >= 0; --idx) 5904 { 5905 if (idx == maxRunEnd) 5906 { 5907 if (idx == 7) *--s = ':'; 5908 idx = maxRunStart; 5909 *--s = ':'; 5910 } 5911 else 5912 { 5913 unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1]; 5914 do { 5915 *--s = kHexDigitsLowercase[hextet % 16]; 5916 hextet /= 16; 5917 } while (hextet); 5918 if (idx > 0) *--s = ':'; 5919 } 5920 } 5921 i = (unsigned int)(mDNS_VACB_Lim - s); 5922 } 5923 break; 5924 5925 default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify" 5926 " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break; 5927 } 5928 } 5929 } 5930 } 5931 break; 5932 5933 case 'p': F.havePrecision = F.lSize = 1; 5934 F.precision = sizeof(void*) * 2; // 8 characters on 32-bit; 16 characters on 64-bit 5935 fallthrough(); 5936 case 'X': digits = kHexDigitsUppercase; 5937 goto hexadecimal; 5938 case 'x': digits = kHexDigitsLowercase; 5939 hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long); 5940 else n = va_arg(arg, unsigned int); 5941 if (F.hSize) n = (unsigned short) n; 5942 if (!F.havePrecision) 5943 { 5944 if (F.zeroPad) 5945 { 5946 F.precision = F.fieldWidth; 5947 if (F.altForm) F.precision -= 2; 5948 } 5949 if (F.precision < 1) F.precision = 1; 5950 } 5951 if (F.precision > mDNS_VACB_Size - 1) 5952 F.precision = mDNS_VACB_Size - 1; 5953 for (i = 0; n; n /= 16, i++) *--s = digits[n % 16]; 5954 for (; i < F.precision; i++) *--s = '0'; 5955 #ifndef FUZZING // Pascal strings aren't supported for fuzzing 5956 if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; } 5957 #endif 5958 break; 5959 5960 case 'c': *--s = (char)va_arg(arg, int); i = 1; break; 5961 5962 case 's': s = va_arg(arg, char *); 5963 if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } 5964 else switch (F.altForm) 5965 { 5966 case 0: i=0; 5967 if (!F.havePrecision) // C string 5968 while (s[i]) i++; 5969 else 5970 { 5971 while ((i < F.precision) && s[i]) i++; 5972 // Make sure we don't truncate in the middle of a UTF-8 character 5973 // If last character we got was any kind of UTF-8 multi-byte character, 5974 // then see if we have to back up. 5975 // This is not as easy as the similar checks below, because 5976 // here we can't assume it's safe to examine the *next* byte, so we 5977 // have to confine ourselves to working only backwards in the string. 5978 j = i; // Record where we got to 5979 // Now, back up until we find first non-continuation-char 5980 while (i>0 && (s[i-1] & 0xC0) == 0x80) i--; 5981 // Now s[i-1] is the first non-continuation-char 5982 // and (j-i) is the number of continuation-chars we found 5983 if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char 5984 { 5985 i--; // Tentatively eliminate this start-char as well 5986 // Now (j-i) is the number of characters we're considering eliminating. 5987 // To be legal UTF-8, the start-char must contain (j-i) one-bits, 5988 // followed by a zero bit. If we shift it right by (7-(j-i)) bits 5989 // (with sign extension) then the result has to be 0xFE. 5990 // If this is right, then we reinstate the tentatively eliminated bytes. 5991 if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j; 5992 } 5993 } 5994 break; 5995 #ifndef FUZZING // Pascal strings aren't supported for fuzzing 5996 case 1: i = (unsigned char) *s++; break; // Pascal string 5997 #endif 5998 case 2: { // DNS label-sequence name 5999 unsigned char *a = (unsigned char *)s; 6000 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end 6001 if (*a == 0) *s++ = '.'; // Special case for root DNS name 6002 while (*a) 6003 { 6004 char buf[63*4+1]; 6005 if (*a > 63) 6006 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; } 6007 if (s + *a >= &mDNS_VACB[254]) 6008 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; } 6009 // Need to use ConvertDomainLabelToCString to do proper escaping here, 6010 // so it's clear what's a literal dot and what's a label separator 6011 ConvertDomainLabelToCString((domainlabel*)a, buf); 6012 s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf); 6013 a += 1 + *a; 6014 } 6015 i = (mDNSu32)(s - mDNS_VACB); 6016 s = mDNS_VACB; // Reset s back to the start of the buffer 6017 break; 6018 } 6019 default: 6020 break; 6021 } 6022 // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below) 6023 if (F.havePrecision && i > F.precision) 6024 { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} 6025 break; 6026 6027 case 'H': { 6028 s = va_arg(arg, char *); 6029 hexdump = mDNStrue; 6030 } 6031 break; 6032 6033 #ifndef FUZZING 6034 case 'n': 6035 s = va_arg(arg, char *); 6036 if (F.hSize) *(short *) s = (short)nwritten; 6037 else if (F.lSize) *(long *) s = (long)nwritten; 6038 else *(int *) s = (int)nwritten; 6039 continue; 6040 #endif 6041 6042 default: s = mDNS_VACB; 6043 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", mDNSIsPrintASCII(c) ? c : ' '); 6044 break; 6045 6046 case '%': *sbuffer++ = (char)c; 6047 if (++nwritten >= buflen) goto exit; 6048 break; 6049 } 6050 6051 if (i < F.fieldWidth && !F.leftJustify) // Pad on the left 6052 do { 6053 *sbuffer++ = ' '; 6054 if (++nwritten >= buflen) goto exit; 6055 } while (i < --F.fieldWidth); 6056 6057 if (hexdump) 6058 { 6059 #ifndef FUZZING 6060 char *dst = sbuffer; 6061 const char *const lim = &sbuffer[buflen - nwritten]; 6062 if (F.havePrecision) 6063 { 6064 for (i = 0; (i < F.precision) && (dst < lim); i++) 6065 { 6066 const unsigned int b = (unsigned int) *s++; 6067 if (i > 0) *dst++ = ' '; 6068 if (dst < lim) *dst++ = kHexDigitsLowercase[(b >> 4) & 0xF]; 6069 if (dst < lim) *dst++ = kHexDigitsLowercase[ b & 0xF]; 6070 } 6071 } 6072 i = (unsigned int)(dst - sbuffer); 6073 sbuffer = dst; 6074 #endif 6075 } 6076 else 6077 { 6078 // Make sure we don't truncate in the middle of a UTF-8 character. 6079 // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the 6080 // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half, 6081 // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly 6082 // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). 6083 if (i > buflen - nwritten) 6084 { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} 6085 for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result 6086 } 6087 nwritten += i; 6088 if (nwritten >= buflen) goto exit; 6089 6090 for (; i < F.fieldWidth; i++) // Pad on the right 6091 { 6092 *sbuffer++ = ' '; 6093 if (++nwritten >= buflen) goto exit; 6094 } 6095 } 6096 } 6097 exit: 6098 *sbuffer++ = 0; 6099 return(nwritten); 6100 } 6101 6102 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) 6103 { 6104 mDNSu32 length; 6105 6106 va_list ptr; 6107 va_start(ptr,fmt); 6108 length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr); 6109 va_end(ptr); 6110 6111 return(length); 6112 } 6113 6114 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 6115 mDNSexport mDNSu32 mDNS_GetNextResolverGroupID(void) 6116 { 6117 static mDNSu32 lastID = 0; 6118 if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero. 6119 return(lastID); 6120 } 6121 #endif 6122 6123 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa") 6124 6125 mDNSexport mDNSBool GetReverseIPv6Addr(const domainname *name, mDNSu8 outIPv6[16]) 6126 { 6127 const mDNSu8 * ptr; 6128 int i; 6129 mDNSu8 ipv6[16]; 6130 6131 // If the name is of the form "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa.", where each x 6132 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order. 6133 // See <https://tools.ietf.org/html/rfc3596#section-2.5>. 6134 6135 ptr = name->c; 6136 for (i = 0; i < 32; i++) 6137 { 6138 unsigned int c, nibble; 6139 const int j = 15 - (i / 2); 6140 if (*ptr++ != 1) return (mDNSfalse); // If this label's length is not 1, then fail. 6141 c = *ptr++; // Get label byte. 6142 if ( (c >= '0') && (c <= '9')) nibble = c - '0'; // If it's a hex digit, get its numeric value. 6143 else if ((c >= 'a') && (c <= 'f')) nibble = (c - 'a') + 10; 6144 else if ((c >= 'A') && (c <= 'F')) nibble = (c - 'A') + 10; 6145 else return (mDNSfalse); // Otherwise, fail. 6146 if ((i % 2) == 0) 6147 { 6148 ipv6[j] = (mDNSu8)nibble; 6149 } 6150 else 6151 { 6152 ipv6[j] |= (mDNSu8)(nibble << 4); 6153 } 6154 } 6155 6156 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail. 6157 6158 if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse); 6159 if (outIPv6) mDNSPlatformMemCopy(outIPv6, ipv6, 16); 6160 return (mDNStrue); 6161 } 6162 #endif // !STANDALONE 6163