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-2020 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 * http://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 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 23 #include "dnssec_v2.h" 24 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 25 26 // Disable certain benign warnings with Microsoft compilers 27 #if (defined(_MSC_VER)) 28 // Disable "conditional expression is constant" warning for debug macros. 29 // Otherwise, this generates warnings for the perfectly natural construct "while(1)" 30 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know 31 #pragma warning(disable:4127) 32 // Disable "array is too small to include a terminating null character" warning 33 // -- domain labels have an initial length byte, not a terminating null character 34 #pragma warning(disable:4295) 35 #endif 36 37 // *************************************************************************** 38 #if COMPILER_LIKES_PRAGMA_MARK 39 #pragma mark - Program Constants 40 #endif 41 42 mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0; 43 mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1; 44 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2; 45 mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-3; 46 mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-4; 47 mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-5; 48 49 // Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of 50 // Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP 51 // port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders. 52 // LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355. 53 // Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability 54 // with Microsoft's LLMNR client code. 55 56 #define DiscardPortAsNumber 9 57 #define SSHPortAsNumber 22 58 #define UnicastDNSPortAsNumber 53 59 #define SSDPPortAsNumber 1900 60 #define IPSECPortAsNumber 4500 61 #define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback 62 #define NATPMPAnnouncementPortAsNumber 5350 63 #define NATPMPPortAsNumber 5351 64 #define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc. 65 #define MulticastDNSPortAsNumber 5353 66 #define LoopbackIPCPortAsNumber 5354 67 //#define MulticastDNSPortAsNumber 5355 // LLMNR 68 #define PrivateDNSPortAsNumber 5533 69 70 mDNSexport const mDNSIPPort DiscardPort = { { DiscardPortAsNumber >> 8, DiscardPortAsNumber & 0xFF } }; 71 mDNSexport const mDNSIPPort SSHPort = { { SSHPortAsNumber >> 8, SSHPortAsNumber & 0xFF } }; 72 mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; 73 mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } }; 74 mDNSexport const mDNSIPPort IPSECPort = { { IPSECPortAsNumber >> 8, IPSECPortAsNumber & 0xFF } }; 75 mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 0xFF } }; 76 mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } }; 77 mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } }; 78 mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } }; 79 mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } }; 80 mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } }; 81 mDNSexport const mDNSIPPort PrivateDNSPort = { { PrivateDNSPortAsNumber >> 8, PrivateDNSPortAsNumber & 0xFF } }; 82 83 mDNSexport const OwnerOptData zeroOwner = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } }; 84 85 mDNSexport const mDNSIPPort zeroIPPort = { { 0 } }; 86 mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } }; 87 mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } }; 88 mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } }; 89 mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } }; 90 mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } }; 91 mDNSexport const mDNSEthAddr onesEthAddr = { { 255, 255, 255, 255, 255, 255 } }; 92 mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} }; 93 94 mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } }; 95 mDNSexport const mDNSv4Addr AllHosts_v4 = { { 224, 0, 0, 1 } }; // For NAT-PMP & PCP Annoucements 96 mDNSexport const mDNSv6Addr AllHosts_v6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } }; 97 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 98 mDNSexport const mDNSEthAddr AllHosts_v6_Eth = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } }; 99 mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } }; 100 //mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR 101 mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } }; 102 //mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR 103 104 mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; 105 mDNSexport const mDNSOpaque16 onesID = { { 255, 255 } }; 106 mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; 107 mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; 108 mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; 109 mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; 110 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; 111 112 mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } }; 113 mDNSexport const mDNSOpaque128 zeroOpaque128 = { { 0 } }; 114 115 extern mDNS mDNSStorage; 116 117 // *************************************************************************** 118 #if COMPILER_LIKES_PRAGMA_MARK 119 #pragma mark - 120 #pragma mark - General Utility Functions 121 #endif 122 123 // return true for RFC1918 private addresses 124 mDNSexport mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr) 125 { 126 return ((addr->b[0] == 10) || // 10/8 prefix 127 (addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) || // 172.16/12 128 (addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16 129 } 130 131 mDNSexport const char *DNSScopeToString(mDNSu32 scope) 132 { 133 switch (scope) 134 { 135 case kScopeNone: 136 return "Unscoped"; 137 case kScopeInterfaceID: 138 return "InterfaceScoped"; 139 case kScopeServiceID: 140 return "ServiceScoped"; 141 default: 142 return "Unknown"; 143 } 144 } 145 146 mDNSexport void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out) 147 { 148 out->l[0] = 0; 149 out->l[1] = 0; 150 out->w[4] = 0; 151 out->w[5] = 0xffff; 152 out->b[12] = in->b[0]; 153 out->b[13] = in->b[1]; 154 out->b[14] = in->b[2]; 155 out->b[15] = in->b[3]; 156 } 157 158 mDNSexport mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr* out) 159 { 160 if (in->l[0] != 0 || in->l[1] != 0 || in->w[4] != 0 || in->w[5] != 0xffff) 161 return mDNSfalse; 162 163 out->NotAnInteger = in->l[3]; 164 return mDNStrue; 165 } 166 167 mDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf) 168 { 169 while (intf && !intf->InterfaceActive) intf = intf->next; 170 return(intf); 171 } 172 173 mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf) 174 { 175 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 176 if (next) return(next->InterfaceID);else return(mDNSNULL); 177 } 178 179 mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id) 180 { 181 mDNSu32 slot, used = 0; 182 CacheGroup *cg; 183 const CacheRecord *rr; 184 FORALL_CACHERECORDS(slot, cg, rr) 185 { 186 if (rr->resrec.InterfaceID == id) 187 used++; 188 } 189 return(used); 190 } 191 192 mDNSexport char *DNSTypeName(mDNSu16 rrtype) 193 { 194 switch (rrtype) 195 { 196 case kDNSType_A: return("Addr"); 197 case kDNSType_NS: return("NS"); 198 case kDNSType_CNAME: return("CNAME"); 199 case kDNSType_SOA: return("SOA"); 200 case kDNSType_NULL: return("NULL"); 201 case kDNSType_PTR: return("PTR"); 202 case kDNSType_HINFO: return("HINFO"); 203 case kDNSType_TXT: return("TXT"); 204 case kDNSType_AAAA: return("AAAA"); 205 case kDNSType_SRV: return("SRV"); 206 case kDNSType_OPT: return("OPT"); 207 case kDNSType_NSEC: return("NSEC"); 208 case kDNSType_NSEC3: return("NSEC3"); 209 case kDNSType_NSEC3PARAM: return("NSEC3PARAM"); 210 case kDNSType_TSIG: return("TSIG"); 211 case kDNSType_RRSIG: return("RRSIG"); 212 case kDNSType_DNSKEY: return("DNSKEY"); 213 case kDNSType_DS: return("DS"); 214 case kDNSType_SVCB: return("SVCB"); 215 case kDNSType_HTTPS: return("HTTPS"); 216 case kDNSQType_ANY: return("ANY"); 217 default: { 218 static char buffer[16]; 219 mDNS_snprintf(buffer, sizeof(buffer), "TYPE%d", rrtype); 220 return(buffer); 221 } 222 } 223 } 224 225 mDNSexport const char *mStatusDescription(mStatus error) 226 { 227 const char *error_description; 228 switch (error) { 229 case mStatus_NoError: 230 error_description = "mStatus_NoError"; 231 break; 232 case mStatus_BadParamErr: 233 error_description = "mStatus_BadParamErr"; 234 break; 235 236 default: 237 error_description = "mStatus_UnknownDescription"; 238 break; 239 } 240 241 return error_description; 242 } 243 244 mDNSexport mDNSu32 swap32(mDNSu32 x) 245 { 246 mDNSu8 *ptr = (mDNSu8 *)&x; 247 return (mDNSu32)((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); 248 } 249 250 mDNSexport mDNSu16 swap16(mDNSu16 x) 251 { 252 mDNSu8 *ptr = (mDNSu8 *)&x; 253 return (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 254 } 255 256 mDNSlocal void PrintTypeBitmap(const mDNSu8 *bmap, int bitmaplen, char *const buffer, mDNSu32 length) 257 { 258 int win, wlen, type; 259 260 while (bitmaplen > 0) 261 { 262 int i; 263 264 if (bitmaplen < 3) 265 { 266 LogMsg("PrintTypeBitmap: malformed bitmap, bitmaplen %d short", bitmaplen); 267 break; 268 } 269 270 win = *bmap++; 271 wlen = *bmap++; 272 bitmaplen -= 2; 273 if (bitmaplen < wlen || wlen < 1 || wlen > 32) 274 { 275 LogInfo("PrintTypeBitmap: malformed nsec, bitmaplen %d wlen %d", bitmaplen, wlen); 276 break; 277 } 278 if (win < 0 || win >= 256) 279 { 280 LogInfo("PrintTypeBitmap: malformed nsec, bad window win %d", win); 281 break; 282 } 283 type = win * 256; 284 for (i = 0; i < wlen * 8; i++) 285 { 286 if (bmap[i>>3] & (128 >> (i&7))) 287 length += mDNS_snprintf(buffer+length, (MaxMsg - 1) - length, "%s ", DNSTypeName(type + i)); 288 } 289 bmap += wlen; 290 bitmaplen -= wlen; 291 } 292 } 293 294 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display 295 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as 296 // long as this routine is only used for debugging messages, it probably isn't a big problem. 297 mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer) 298 { 299 const RDataBody2 *const rd = (RDataBody2 *)rd1; 300 #define RemSpc (MaxMsg-1-length) 301 char *ptr = buffer; 302 mDNSu32 length = mDNS_snprintf(buffer, MaxMsg-1, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype)); 303 if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer); 304 if (!rr->rdlength && rr->rrtype != kDNSType_OPT) { mDNS_snprintf(buffer+length, RemSpc, "<< ZERO RDATA LENGTH >>"); return(buffer); } 305 306 switch (rr->rrtype) 307 { 308 case kDNSType_A: mDNS_snprintf(buffer+length, RemSpc, "%.4a", &rd->ipv4); break; 309 310 case kDNSType_NS: // Same as PTR 311 case kDNSType_CNAME: // Same as PTR 312 case kDNSType_PTR: mDNS_snprintf(buffer+length, RemSpc, "%##s", rd->name.c); break; 313 314 case kDNSType_SOA: mDNS_snprintf(buffer+length, RemSpc, "%##s %##s %d %d %d %d %d", 315 rd->soa.mname.c, rd->soa.rname.c, 316 rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min); 317 break; 318 319 case kDNSType_HINFO: // Display this the same as TXT (show all constituent strings) 320 case kDNSType_TXT: { 321 const mDNSu8 *t = rd->txt.c; 322 const mDNSu8 *const rdLimit = rd->data + rr->rdlength; 323 const char *separator = ""; 324 325 while (t < rdLimit) 326 { 327 mDNSu32 characterStrLength = *t; 328 if (characterStrLength + 1 > (mDNSu32)(rdLimit - t)) // Character string goes out of boundary. 329 { 330 const mDNSu8 *const remainderStart = t + 1; 331 const mDNSu32 remainderLength = (mDNSu32)(rdLimit - remainderStart); 332 length += mDNS_snprintf(buffer + length, RemSpc, "%s%.*s<<OUT OF BOUNDARY CHARACTER STRING>>", separator, 333 remainderLength, remainderStart); 334 (void)length; // Acknowledge "dead store" analyzer warning. 335 break; 336 } 337 length += mDNS_snprintf(buffer+length, RemSpc, "%s%.*s", separator, characterStrLength, t + 1); 338 separator = "¦"; 339 t += 1 + characterStrLength; 340 } 341 } 342 break; 343 344 case kDNSType_AAAA: mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6); break; 345 case kDNSType_SRV: mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s", 346 rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break; 347 348 case kDNSType_OPT: { 349 const rdataOPT *opt; 350 const rdataOPT *const end = (const rdataOPT *)&rd->data[rr->rdlength]; 351 length += mDNS_snprintf(buffer+length, RemSpc, "Max %d", rr->rrclass); 352 for (opt = &rd->opt[0]; opt < end; opt++) 353 { 354 switch(opt->opt) 355 { 356 case kDNSOpt_LLQ: 357 length += mDNS_snprintf(buffer+length, RemSpc, " LLQ"); 358 length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.llq.vers); 359 length += mDNS_snprintf(buffer+length, RemSpc, " Op %d", opt->u.llq.llqOp); 360 length += mDNS_snprintf(buffer+length, RemSpc, " Err/Port %d", opt->u.llq.err); 361 length += mDNS_snprintf(buffer+length, RemSpc, " ID %08X%08X", opt->u.llq.id.l[0], opt->u.llq.id.l[1]); 362 length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.llq.llqlease); 363 break; 364 case kDNSOpt_Lease: 365 length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.updatelease); 366 break; 367 case kDNSOpt_Owner: 368 length += mDNS_snprintf(buffer+length, RemSpc, " Owner"); 369 length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.owner.vers); 370 length += mDNS_snprintf(buffer+length, RemSpc, " Seq %3d", (mDNSu8)opt->u.owner.seq); // Display as unsigned 371 length += mDNS_snprintf(buffer+length, RemSpc, " MAC %.6a", opt->u.owner.HMAC.b); 372 if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4) 373 { 374 length += mDNS_snprintf(buffer+length, RemSpc, " I-MAC %.6a", opt->u.owner.IMAC.b); 375 if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4) 376 length += mDNS_snprintf(buffer+length, RemSpc, " Password %.6a", opt->u.owner.password.b); 377 } 378 break; 379 case kDNSOpt_Trace: 380 length += mDNS_snprintf(buffer+length, RemSpc, " Trace"); 381 length += mDNS_snprintf(buffer+length, RemSpc, " Platform %d", opt->u.tracer.platf); 382 length += mDNS_snprintf(buffer+length, RemSpc, " mDNSVers %d", opt->u.tracer.mDNSv); 383 break; 384 default: 385 length += mDNS_snprintf(buffer+length, RemSpc, " Unknown %d", opt->opt); 386 break; 387 } 388 } 389 } 390 break; 391 392 case kDNSType_NSEC: { 393 domainname *next = (domainname *)rd->data; 394 int len, bitmaplen; 395 mDNSu8 *bmap; 396 len = DomainNameLength(next); 397 bitmaplen = rr->rdlength - len; 398 bmap = (mDNSu8 *)((mDNSu8 *)next + len); 399 400 if (UNICAST_NSEC(rr)) 401 length += mDNS_snprintf(buffer+length, RemSpc, "%##s ", next->c); 402 PrintTypeBitmap(bmap, bitmaplen, buffer, length); 403 404 } 405 break; 406 407 default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %.*s", rr->rdlength, rr->rdlength, rd->data); 408 // Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not 409 for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.'; 410 break; 411 } 412 413 return(buffer); 414 } 415 416 // See comments in mDNSEmbeddedAPI.h 417 #if _PLATFORM_HAS_STRONG_PRNG_ 418 #define mDNSRandomNumber mDNSPlatformRandomNumber 419 #else 420 mDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed) 421 { 422 return seed * 21 + 1; 423 } 424 425 mDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration) 426 { 427 return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed; 428 } 429 430 mDNSlocal mDNSu32 mDNSRandomNumber() 431 { 432 static mDNSBool seeded = mDNSfalse; 433 static mDNSu32 seed = 0; 434 if (!seeded) 435 { 436 seed = mDNSMixRandomSeed(mDNSPlatformRandomSeed(), 100); 437 seeded = mDNStrue; 438 } 439 return (seed = mDNSRandomFromSeed(seed)); 440 } 441 #endif // ! _PLATFORM_HAS_STRONG_PRNG_ 442 443 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive 444 { 445 mDNSu32 ret = 0; 446 mDNSu32 mask = 1; 447 448 while (mask < max) mask = (mask << 1) | 1; 449 450 do ret = mDNSRandomNumber() & mask; 451 while (ret > max); 452 453 return ret; 454 } 455 456 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2) 457 { 458 if (ip1->type == ip2->type) 459 { 460 switch (ip1->type) 461 { 462 case mDNSAddrType_None: return(mDNStrue); // Empty addresses have no data and are therefore always equal 463 case mDNSAddrType_IPv4: return (mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4)); 464 case mDNSAddrType_IPv6: return (mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6)); 465 } 466 } 467 return(mDNSfalse); 468 } 469 470 mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip) 471 { 472 switch(ip->type) 473 { 474 case mDNSAddrType_IPv4: return (mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4)); 475 case mDNSAddrType_IPv6: return (mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6)); 476 default: return(mDNSfalse); 477 } 478 } 479 480 // *************************************************************************** 481 #if COMPILER_LIKES_PRAGMA_MARK 482 #pragma mark - 483 #pragma mark - Domain Name Utility Functions 484 #endif 485 486 #if !APPLE_OSX_mDNSResponder 487 488 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b) 489 { 490 int i; 491 const int len = *a++; 492 493 if (len > MAX_DOMAIN_LABEL) 494 { debugf("Malformed label (too long)"); return(mDNSfalse); } 495 496 if (len != *b++) return(mDNSfalse); 497 for (i=0; i<len; i++) 498 { 499 mDNSu8 ac = *a++; 500 mDNSu8 bc = *b++; 501 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A'; 502 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A'; 503 if (ac != bc) return(mDNSfalse); 504 } 505 return(mDNStrue); 506 } 507 508 #endif // !APPLE_OSX_mDNSResponder 509 510 mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2) 511 { 512 const mDNSu8 * a = d1->c; 513 const mDNSu8 * b = d2->c; 514 const mDNSu8 *const max = d1->c + MAX_DOMAIN_NAME; // Maximum that's valid 515 516 while (*a || *b) 517 { 518 if (a + 1 + *a >= max) 519 { debugf("Malformed domain name (more than 256 characters)"); return(mDNSfalse); } 520 if (!SameDomainLabel(a, b)) return(mDNSfalse); 521 a += 1 + *a; 522 b += 1 + *b; 523 } 524 525 return(mDNStrue); 526 } 527 528 mDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2) 529 { 530 mDNSu16 l1 = DomainNameLength(d1); 531 mDNSu16 l2 = DomainNameLength(d2); 532 return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1)); 533 } 534 535 mDNSexport mDNSBool IsLocalDomain(const domainname *d) 536 { 537 // Domains that are defined to be resolved via link-local multicast are: 538 // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa. 539 static const domainname *nL = (const domainname*)"\x5" "local"; 540 static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa"; 541 static const domainname *n8 = (const domainname*)"\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 542 static const domainname *n9 = (const domainname*)"\x1" "9" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 543 static const domainname *nA = (const domainname*)"\x1" "a" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 544 static const domainname *nB = (const domainname*)"\x1" "b" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; 545 546 const domainname *d1, *d2, *d3, *d4, *d5; // Top-level domain, second-level domain, etc. 547 d1 = d2 = d3 = d4 = d5 = mDNSNULL; 548 while (d->c[0]) 549 { 550 d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d; 551 d = (const domainname*)(d->c + 1 + d->c[0]); 552 } 553 554 if (d1 && SameDomainName(d1, nL)) return(mDNStrue); 555 if (d4 && SameDomainName(d4, nR)) return(mDNStrue); 556 if (d5 && SameDomainName(d5, n8)) return(mDNStrue); 557 if (d5 && SameDomainName(d5, n9)) return(mDNStrue); 558 if (d5 && SameDomainName(d5, nA)) return(mDNStrue); 559 if (d5 && SameDomainName(d5, nB)) return(mDNStrue); 560 return(mDNSfalse); 561 } 562 563 mDNSexport const mDNSu8 *LastLabel(const domainname *d) 564 { 565 const mDNSu8 *p = d->c; 566 while (d->c[0]) 567 { 568 p = d->c; 569 d = (const domainname*)(d->c + 1 + d->c[0]); 570 } 571 return(p); 572 } 573 574 // Returns length of a domain name INCLUDING the byte for the final null label 575 // e.g. for the root label "." it returns one 576 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero) 577 // Legal results are 1 (just root label) to 256 (MAX_DOMAIN_NAME) 578 // If the given domainname is invalid, result is 257 (MAX_DOMAIN_NAME+1) 579 mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit) 580 { 581 const mDNSu8 *src = name->c; 582 while (src < limit && *src <= MAX_DOMAIN_LABEL) 583 { 584 if (*src == 0) return((mDNSu16)(src - name->c + 1)); 585 src += 1 + *src; 586 } 587 return(MAX_DOMAIN_NAME+1); 588 } 589 590 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte 591 // for the final null label, e.g. for the root label "." it returns one. 592 // E.g. for the FQDN "foo.com." it returns 9 593 // (length, three data bytes, length, three more data bytes, final zero). 594 // In the case where a parent domain name is provided, and the given name is a child 595 // of that parent, CompressedDomainNameLength returns the length of the prefix portion 596 // of the child name, plus TWO bytes for the compression pointer. 597 // E.g. for the name "foo.com." with parent "com.", it returns 6 598 // (length, three data bytes, two-byte compression pointer). 599 mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent) 600 { 601 const mDNSu8 *src = name->c; 602 if (parent && parent->c[0] == 0) parent = mDNSNULL; 603 while (*src) 604 { 605 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1); 606 if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2)); 607 src += 1 + *src; 608 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1); 609 } 610 return((mDNSu16)(src - name->c + 1)); 611 } 612 613 // CountLabels() returns number of labels in name, excluding final root label 614 // (e.g. for "apple.com." CountLabels returns 2.) 615 mDNSexport int CountLabels(const domainname *d) 616 { 617 int count = 0; 618 const mDNSu8 *ptr; 619 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++; 620 return count; 621 } 622 623 // SkipLeadingLabels skips over the first 'skip' labels in the domainname, 624 // returning a pointer to the suffix with 'skip' labels removed. 625 mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip) 626 { 627 while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; } 628 return(d); 629 } 630 631 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname. 632 // The C string contains the label as-is, with no escaping, etc. 633 // Any dots in the name are literal dots, not label separators 634 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte 635 // in the domainname bufer (i.e. the next byte after the terminating zero). 636 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 637 // AppendLiteralLabelString returns mDNSNULL. 638 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr) 639 { 640 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name 641 const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) 642 const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL; 643 const mDNSu8 *const lim = (lim1 < lim2) ? lim1 : lim2; 644 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go 645 646 while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++; // Copy the data 647 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte 648 *ptr++ = 0; // Put the null root label on the end 649 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input 650 else return(ptr); // Success: return new value of ptr 651 } 652 653 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname. 654 // The C string is in conventional DNS syntax: 655 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots. 656 // If successful, AppendDNSNameString returns a pointer to the next unused byte 657 // in the domainname bufer (i.e. the next byte after the terminating zero). 658 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 659 // AppendDNSNameString returns mDNSNULL. 660 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring) 661 { 662 const char *cstr = cstring; 663 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name 664 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) 665 while (*cstr && ptr < lim) // While more characters, and space to put them... 666 { 667 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go 668 if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); } 669 while (*cstr && *cstr != '.' && ptr < lim) // While we have characters in the label... 670 { 671 mDNSu8 c = (mDNSu8)*cstr++; // Read the character 672 if (c == '\\') // If escape character, check next character 673 { 674 if (*cstr == '\0') break; // If this is the end of the string, then break 675 c = (mDNSu8)*cstr++; // Assume we'll just take the next character 676 if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1])) 677 { // If three decimal digits, 678 int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal 679 int v1 = cstr[ 0] - '0'; 680 int v2 = cstr[ 1] - '0'; 681 int val = v0 * 100 + v1 * 10 + v2; 682 if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it 683 } 684 } 685 *ptr++ = c; // Write the character 686 } 687 if (*cstr == '.') cstr++; // Skip over the trailing dot (if present) 688 if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort 689 return(mDNSNULL); 690 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte 691 } 692 693 *ptr++ = 0; // Put the null root label on the end 694 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input 695 else return(ptr); // Success: return new value of ptr 696 } 697 698 // AppendDomainLabel appends a single label to a name. 699 // If successful, AppendDomainLabel returns a pointer to the next unused byte 700 // in the domainname bufer (i.e. the next byte after the terminating zero). 701 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 702 // AppendDomainLabel returns mDNSNULL. 703 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label) 704 { 705 int i; 706 mDNSu8 *ptr = name->c + DomainNameLength(name) - 1; 707 708 // Check label is legal 709 if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL); 710 711 // Check that ptr + length byte + data bytes + final zero does not exceed our limit 712 if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL); 713 714 for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i]; // Copy the label data 715 *ptr++ = 0; // Put the null root label on the end 716 return(ptr); 717 } 718 719 mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append) 720 { 721 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name 722 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) 723 const mDNSu8 * src = append->c; 724 while (src[0]) 725 { 726 int i; 727 if (ptr + 1 + src[0] > lim) return(mDNSNULL); 728 for (i=0; i<=src[0]; i++) *ptr++ = src[i]; 729 *ptr = 0; // Put the null root label on the end 730 src += i; 731 } 732 return(ptr); 733 } 734 735 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping). 736 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue. 737 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then 738 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse. 739 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored. 740 // In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result. 741 mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr) 742 { 743 mDNSu8 * ptr = label->c + 1; // Where we're putting it 744 const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL; // The maximum we can put 745 while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++; // Copy the label 746 label->c[0] = (mDNSu8)(ptr - label->c - 1); // Set the length byte 747 return(*cstr == 0); // Return mDNStrue if we successfully consumed all input 748 } 749 750 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string. 751 // The C string is in conventional DNS syntax: 752 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots. 753 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte 754 // in the domainname bufer (i.e. the next byte after the terminating zero). 755 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) 756 // MakeDomainNameFromDNSNameString returns mDNSNULL. 757 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr) 758 { 759 name->c[0] = 0; // Make an empty domain name 760 return(AppendDNSNameString(name, cstr)); // And then add this string to it 761 } 762 763 mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc) 764 { 765 const mDNSu8 * src = label->c; // Domain label we're reading 766 const mDNSu8 len = *src++; // Read length of this (non-null) label 767 const mDNSu8 *const end = src + len; // Work out where the label ends 768 if (len > MAX_DOMAIN_LABEL) return(mDNSNULL); // If illegal label, abort 769 while (src < end) // While we have characters in the label 770 { 771 mDNSu8 c = *src++; 772 if (esc) 773 { 774 if (c == '.' || c == esc) // If character is a dot or the escape character 775 *ptr++ = esc; // Output escape character 776 else if (c <= ' ') // If non-printing ascii, 777 { // Output decimal escape sequence 778 *ptr++ = esc; 779 *ptr++ = (char) ('0' + (c / 100) ); 780 *ptr++ = (char) ('0' + (c / 10) % 10); 781 c = (mDNSu8)('0' + (c ) % 10); 782 } 783 } 784 *ptr++ = (char)c; // Copy the character 785 } 786 *ptr = 0; // Null-terminate the string 787 return(ptr); // and return 788 } 789 790 // Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1009 bytes) 791 mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc) 792 { 793 const mDNSu8 *src = name->c; // Domain name we're reading 794 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid 795 796 if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot 797 798 while (*src) // While more characters in the domain name 799 { 800 if (src + 1 + *src >= max) return(mDNSNULL); 801 ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc); 802 if (!ptr) return(mDNSNULL); 803 src += 1 + *src; 804 *ptr++ = '.'; // Write the dot after the label 805 } 806 807 *ptr++ = 0; // Null-terminate the string 808 return(ptr); // and return 809 } 810 811 // RFC 1034 rules: 812 // Host names must start with a letter, end with a letter or digit, 813 // and have as interior characters only letters, digits, and hyphen. 814 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit 815 816 mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel) 817 { 818 const mDNSu8 * src = &UTF8Name[1]; 819 const mDNSu8 *const end = &UTF8Name[1] + UTF8Name[0]; 820 mDNSu8 * ptr = &hostlabel->c[1]; 821 const mDNSu8 *const lim = &hostlabel->c[1] + MAX_DOMAIN_LABEL; 822 while (src < end) 823 { 824 // Delete apostrophes from source name 825 if (src[0] == '\'') { src++; continue; } // Standard straight single quote 826 if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99) 827 { src += 3; continue; } // Unicode curly apostrophe 828 if (ptr < lim) 829 { 830 if (mDNSValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src; 831 else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-'; 832 } 833 src++; 834 } 835 while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks 836 hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]); 837 } 838 839 mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, 840 const domainlabel *name, const domainname *type, const domainname *const domain) 841 { 842 int i, len; 843 mDNSu8 *dst = fqdn->c; 844 const mDNSu8 *src; 845 const char *errormsg; 846 #if APPLE_OSX_mDNSResponder 847 mDNSBool loggedUnderscore = mDNSfalse; 848 static char typeBuf[MAX_ESCAPED_DOMAIN_NAME]; 849 #endif 850 851 // In the case where there is no name (and ONLY in that case), 852 // a single-label subtype is allowed as the first label of a three-part "type" 853 if (!name) 854 { 855 const mDNSu8 *s0 = type->c; 856 if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63) 857 { 858 const mDNSu8 * s1 = s0 + 1 + s0[0]; 859 if (s1[0] && s1[0] < 0x40) // and legal second label (at least one character, and no more than 63) 860 { 861 const mDNSu8 *s2 = s1 + 1 + s1[0]; 862 if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0) // and we have three and only three labels 863 { 864 static const mDNSu8 SubTypeLabel[5] = mDNSSubTypeLabel; 865 src = s0; // Copy the first label 866 len = *src; 867 for (i=0; i <= len; i++) *dst++ = *src++; 868 for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i]; 869 type = (const domainname *)s1; 870 871 // Special support to enable the DNSServiceBrowse call made by Bonjour Browser 872 // For these queries, we retract the "._sub" we just added between the subtype and the main type 873 // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse 874 if (SameDomainName((domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp")) 875 dst -= sizeof(SubTypeLabel); 876 } 877 } 878 } 879 } 880 881 if (name && name->c[0]) 882 { 883 src = name->c; // Put the service name into the domain name 884 len = *src; 885 if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; } 886 for (i=0; i<=len; i++) *dst++ = *src++; 887 } 888 else 889 name = (domainlabel*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below 890 891 src = type->c; // Put the service type into the domain name 892 len = *src; 893 if (len < 2 || len > 16) 894 { 895 LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-15 characters. " 896 "See <http://www.dns-sd.org/ServiceTypes.html>", name->c, type->c, domain->c); 897 } 898 if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL); 899 if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; } 900 for (i=2; i<=len; i++) 901 { 902 // Letters and digits are allowed anywhere 903 if (mDNSIsLetter(src[i]) || mDNSIsDigit(src[i])) continue; 904 // Hyphens are only allowed as interior characters 905 // Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them, 906 // with the same rule as hyphens 907 if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) 908 { 909 #if APPLE_OSX_mDNSResponder 910 if (src[i] == '_' && loggedUnderscore == mDNSfalse) 911 { 912 ConvertDomainNameToCString(type, typeBuf); 913 LogInfo("ConstructServiceName: Service type with non-leading underscore %s", typeBuf); 914 loggedUnderscore = mDNStrue; 915 } 916 #endif 917 continue; 918 } 919 errormsg = "Application protocol name must contain only letters, digits, and hyphens"; 920 goto fail; 921 } 922 for (i=0; i<=len; i++) *dst++ = *src++; 923 924 len = *src; 925 if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; } 926 for (i=0; i<=len; i++) *dst++ = *src++; 927 928 if (*src) { errormsg = "Service type must have only two labels"; goto fail; } 929 930 *dst = 0; 931 if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; } 932 if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa")) 933 { errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; } 934 dst = AppendDomainName(fqdn, domain); 935 if (!dst) { errormsg = "Service domain too long"; goto fail; } 936 return(dst); 937 938 fail: 939 LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg, name->c, type->c, domain->c); 940 return(mDNSNULL); 941 } 942 943 // A service name has the form: instance.application-protocol.transport-protocol.domain 944 // DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character 945 // set or length limits for the protocol names, and the final domain is allowed to be empty. 946 // However, if the given FQDN doesn't contain at least three labels, 947 // DeconstructServiceName will reject it and return mDNSfalse. 948 mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn, 949 domainlabel *const name, domainname *const type, domainname *const domain) 950 { 951 int i, len; 952 const mDNSu8 *src = fqdn->c; 953 const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME; 954 mDNSu8 *dst; 955 956 dst = name->c; // Extract the service name 957 len = *src; 958 if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); } 959 if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); } 960 for (i=0; i<=len; i++) *dst++ = *src++; 961 962 dst = type->c; // Extract the service type 963 len = *src; 964 if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); } 965 if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); } 966 if (src[1] != '_') { debugf("DeconstructServiceName: No _ at start of application protocol"); return(mDNSfalse); } 967 for (i=0; i<=len; i++) *dst++ = *src++; 968 969 len = *src; 970 if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); } 971 if (!ValidTransportProtocol(src)) 972 { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); } 973 for (i=0; i<=len; i++) *dst++ = *src++; 974 *dst++ = 0; // Put terminator on the end of service type 975 976 dst = domain->c; // Extract the service domain 977 while (*src) 978 { 979 len = *src; 980 if (len >= 0x40) 981 { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); } 982 if (src + 1 + len + 1 >= max) 983 { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); } 984 for (i=0; i<=len; i++) *dst++ = *src++; 985 } 986 *dst++ = 0; // Put the null root label on the end 987 988 return(mDNStrue); 989 } 990 991 mDNSexport mStatus DNSNameToLowerCase(domainname *d, domainname *result) 992 { 993 const mDNSu8 *a = d->c; 994 mDNSu8 *b = result->c; 995 const mDNSu8 *const max = d->c + MAX_DOMAIN_NAME; 996 int i, len; 997 998 while (*a) 999 { 1000 if (a + 1 + *a >= max) 1001 { 1002 LogMsg("DNSNameToLowerCase: ERROR!! Malformed Domain name"); 1003 return mStatus_BadParamErr; 1004 } 1005 len = *a++; 1006 *b++ = len; 1007 for (i = 0; i < len; i++) 1008 { 1009 mDNSu8 ac = *a++; 1010 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A'; 1011 *b++ = ac; 1012 } 1013 } 1014 *b = 0; 1015 1016 return mStatus_NoError; 1017 } 1018 1019 // Notes on UTF-8: 1020 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F 1021 // 10xxxxxx is a continuation byte of a multi-byte character 1022 // 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x 80 - 0x 800-1) 1023 // 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x 800 - 0x 10000-1) 1024 // 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x 10000 - 0x 200000-1) 1025 // 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1) 1026 // 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1) 1027 // 1028 // UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF. 1029 // Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive 1030 // about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?") 1031 // The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8), 1032 // and the second is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8). 1033 1034 mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max) 1035 { 1036 if (length > max) 1037 { 1038 mDNSu8 c1 = string[max]; // First byte after cut point 1039 mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0; // Second byte after cut point 1040 length = max; // Trim length down 1041 while (length > 0) 1042 { 1043 // Check if the byte right after the chop point is a UTF-8 continuation byte, 1044 // or if the character right after the chop point is the second of a UTF-16 surrogate pair. 1045 // If so, then we continue to chop more bytes until we get to a legal chop point. 1046 mDNSBool continuation = ((c1 & 0xC0) == 0x80); 1047 mDNSBool secondsurrogate = (c1 == 0xED && (c2 & 0xF0) == 0xB0); 1048 if (!continuation && !secondsurrogate) break; 1049 c2 = c1; 1050 c1 = string[--length]; 1051 } 1052 // Having truncated characters off the end of our string, also cut off any residual white space 1053 while (length > 0 && string[length-1] <= ' ') length--; 1054 } 1055 return(length); 1056 } 1057 1058 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034 1059 // name ends in "-nnn", where n is some decimal number. 1060 mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText) 1061 { 1062 mDNSu16 l = name->c[0]; 1063 1064 if (RichText) 1065 { 1066 if (l < 4) return mDNSfalse; // Need at least " (2)" 1067 if (name->c[l--] != ')') return mDNSfalse; // Last char must be ')' 1068 if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit 1069 l--; 1070 while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits 1071 return (name->c[l] == '(' && name->c[l - 1] == ' '); 1072 } 1073 else 1074 { 1075 if (l < 2) return mDNSfalse; // Need at least "-2" 1076 if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit 1077 l--; 1078 while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits 1079 return (name->c[l] == '-'); 1080 } 1081 } 1082 1083 // removes an auto-generated suffix (appended on a name collision) from a label. caller is 1084 // responsible for ensuring that the label does indeed contain a suffix. returns the number 1085 // from the suffix that was removed. 1086 mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText) 1087 { 1088 mDNSu32 val = 0, multiplier = 1; 1089 1090 // Chop closing parentheses from RichText suffix 1091 if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--; 1092 1093 // Get any existing numerical suffix off the name 1094 while (mDNSIsDigit(name->c[name->c[0]])) 1095 { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; } 1096 1097 // Chop opening parentheses or dash from suffix 1098 if (RichText) 1099 { 1100 if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2; 1101 } 1102 else 1103 { 1104 if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1; 1105 } 1106 1107 return(val); 1108 } 1109 1110 // appends a numerical suffix to a label, with the number following a whitespace and enclosed 1111 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label). 1112 mDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText) 1113 { 1114 mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2") 1115 if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)") 1116 1117 // Truncate trailing spaces from RichText names 1118 if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--; 1119 1120 while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; } 1121 1122 name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars); 1123 1124 if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; } 1125 else { name->c[++name->c[0]] = '-'; } 1126 1127 while (divisor) 1128 { 1129 name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor); 1130 val %= divisor; 1131 divisor /= 10; 1132 } 1133 1134 if (RichText) name->c[++name->c[0]] = ')'; 1135 } 1136 1137 mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText) 1138 { 1139 mDNSu32 val = 0; 1140 1141 if (LabelContainsSuffix(name, RichText)) 1142 val = RemoveLabelSuffix(name, RichText); 1143 1144 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate. 1145 // If existing suffix in the range 2-9, increment it. 1146 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name, 1147 // so add a random increment to improve the chances of finding an available name next time. 1148 if (val == 0) val = 2; 1149 else if (val < 10) val++; 1150 else val += 1 + mDNSRandom(99); 1151 1152 AppendLabelSuffix(name, val, RichText); 1153 } 1154 1155 // *************************************************************************** 1156 #if COMPILER_LIKES_PRAGMA_MARK 1157 #pragma mark - 1158 #pragma mark - Resource Record Utility Functions 1159 #endif 1160 1161 // Set up a AuthRecord with sensible default values. 1162 // These defaults may be overwritten with new values before mDNS_Register is called 1163 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID, 1164 mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context) 1165 { 1166 // 1167 // LocalOnly auth record can be created with LocalOnly InterfaceID or a valid InterfaceID. 1168 // Most of the applications normally create with LocalOnly InterfaceID and we store them as 1169 // such, so that we can deliver the response to questions that specify LocalOnly InterfaceID. 1170 // LocalOnly resource records can also be created with valid InterfaceID which happens today 1171 // when we create LocalOnly records for /etc/hosts. 1172 1173 if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly) 1174 { 1175 LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d", InterfaceID, artype); 1176 } 1177 else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P) 1178 { 1179 LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d", InterfaceID, artype); 1180 } 1181 else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly)) 1182 { 1183 LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d", InterfaceID, artype); 1184 } 1185 1186 // Don't try to store a TTL bigger than we can represent in platform time units 1187 if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond) 1188 ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond; 1189 else if (ttl == 0) // And Zero TTL is illegal 1190 ttl = DefaultTTLforRRType(rrtype); 1191 1192 // Field Group 1: The actual information pertaining to this resource record 1193 rr->resrec.RecordType = RecordType; 1194 rr->resrec.InterfaceID = InterfaceID; 1195 rr->resrec.name = &rr->namestorage; 1196 rr->resrec.rrtype = rrtype; 1197 rr->resrec.rrclass = kDNSClass_IN; 1198 rr->resrec.rroriginalttl = ttl; 1199 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 1200 rr->resrec.dnsservice = NULL; 1201 #else 1202 rr->resrec.rDNSServer = mDNSNULL; 1203 #endif 1204 // rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal 1205 // rr->resrec.rdestimate = set in mDNS_Register_internal 1206 // rr->resrec.rdata = MUST be set by client 1207 1208 if (RDataStorage) 1209 rr->resrec.rdata = RDataStorage; 1210 else 1211 { 1212 rr->resrec.rdata = &rr->rdatastorage; 1213 rr->resrec.rdata->MaxRDLength = sizeof(RDataBody); 1214 } 1215 1216 // Field Group 2: Persistent metadata for Authoritative Records 1217 rr->Additional1 = mDNSNULL; 1218 rr->Additional2 = mDNSNULL; 1219 rr->DependentOn = mDNSNULL; 1220 rr->RRSet = mDNSNULL; 1221 rr->RecordCallback = Callback; 1222 rr->RecordContext = Context; 1223 1224 rr->AutoTarget = Target_Manual; 1225 rr->AllowRemoteQuery = mDNSfalse; 1226 rr->ForceMCast = mDNSfalse; 1227 1228 rr->WakeUp = zeroOwner; 1229 rr->AddressProxy = zeroAddr; 1230 rr->TimeRcvd = 0; 1231 rr->TimeExpire = 0; 1232 rr->ARType = artype; 1233 rr->AuthFlags = 0; 1234 1235 // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal) 1236 // Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal) 1237 1238 // For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case 1239 // (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch 1240 // of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.) 1241 rr->state = regState_Zero; 1242 rr->uselease = 0; 1243 rr->expire = 0; 1244 rr->Private = 0; 1245 rr->updateid = zeroID; 1246 rr->zone = rr->resrec.name; 1247 rr->nta = mDNSNULL; 1248 rr->tcp = mDNSNULL; 1249 rr->OrigRData = 0; 1250 rr->OrigRDLen = 0; 1251 rr->InFlightRData = 0; 1252 rr->InFlightRDLen = 0; 1253 rr->QueuedRData = 0; 1254 rr->QueuedRDLen = 0; 1255 mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); 1256 rr->SRVChanged = mDNSfalse; 1257 rr->mState = mergeState_Zero; 1258 1259 rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() 1260 } 1261 1262 mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name, 1263 const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context) 1264 { 1265 q->InterfaceID = InterfaceID; 1266 q->flags = 0; 1267 AssignDomainName(&q->qname, name); 1268 q->qtype = qtype; 1269 q->qclass = kDNSClass_IN; 1270 q->LongLived = (qtype == kDNSType_PTR); 1271 q->ExpectUnique = (qtype != kDNSType_PTR); 1272 q->ForceMCast = mDNSfalse; 1273 q->ReturnIntermed = mDNSfalse; 1274 q->SuppressUnusable = mDNSfalse; 1275 q->AppendSearchDomains = 0; 1276 q->TimeoutQuestion = 0; 1277 q->WakeOnResolve = 0; 1278 q->UseBackgroundTraffic = mDNSfalse; 1279 q->ProxyQuestion = 0; 1280 q->pid = mDNSPlatformGetPID(); 1281 q->euid = 0; 1282 q->BlockedByPolicy = mDNSfalse; 1283 q->ServiceID = -1; 1284 q->QuestionCallback = callback; 1285 q->QuestionContext = context; 1286 } 1287 1288 mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr) 1289 { 1290 int len = rr->rdlength; 1291 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 1292 const mDNSu8 *ptr = rdb->data; 1293 mDNSu32 sum = 0; 1294 1295 switch(rr->rrtype) 1296 { 1297 case kDNSType_NS: 1298 case kDNSType_MD: 1299 case kDNSType_MF: 1300 case kDNSType_CNAME: 1301 case kDNSType_MB: 1302 case kDNSType_MG: 1303 case kDNSType_MR: 1304 case kDNSType_PTR: 1305 case kDNSType_NSAP_PTR: 1306 case kDNSType_DNAME: return DomainNameHashValue(&rdb->name); 1307 1308 case kDNSType_SOA: return rdb->soa.serial + 1309 rdb->soa.refresh + 1310 rdb->soa.retry + 1311 rdb->soa.expire + 1312 rdb->soa.min + 1313 DomainNameHashValue(&rdb->soa.mname) + 1314 DomainNameHashValue(&rdb->soa.rname); 1315 1316 case kDNSType_MX: 1317 case kDNSType_AFSDB: 1318 case kDNSType_RT: 1319 case kDNSType_KX: return DomainNameHashValue(&rdb->mx.exchange); 1320 1321 case kDNSType_MINFO: 1322 case kDNSType_RP: return DomainNameHashValue(&rdb->rp.mbox) + DomainNameHashValue(&rdb->rp.txt); 1323 1324 case kDNSType_PX: return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400); 1325 1326 case kDNSType_SRV: return DomainNameHashValue(&rdb->srv.target); 1327 1328 case kDNSType_OPT: return 0; // OPT is a pseudo-RR container structure; makes no sense to compare 1329 1330 case kDNSType_NSEC: { 1331 int dlen; 1332 dlen = DomainNameLength((domainname *)rdb->data); 1333 sum = DomainNameHashValue((domainname *)rdb->data); 1334 ptr += dlen; 1335 len -= dlen; 1336 /* FALLTHROUGH */ 1337 } 1338 /* FALLTHROUGH */ 1339 1340 default: 1341 { 1342 int i; 1343 for (i=0; i+1 < len; i+=2) 1344 { 1345 sum += (((mDNSu32)(ptr[i])) << 8) | ptr[i+1]; 1346 sum = (sum<<3) | (sum>>29); 1347 } 1348 if (i < len) 1349 { 1350 sum += ((mDNSu32)(ptr[i])) << 8; 1351 } 1352 return(sum); 1353 } 1354 } 1355 } 1356 1357 // r1 has to be a full ResourceRecord including rrtype and rdlength 1358 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1 1359 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename) 1360 { 1361 const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data; 1362 const RDataBody2 *const b2 = (RDataBody2 *)r2; 1363 switch(r1->rrtype) 1364 { 1365 case kDNSType_NS: 1366 case kDNSType_MD: 1367 case kDNSType_MF: 1368 case kDNSType_CNAME: 1369 case kDNSType_MB: 1370 case kDNSType_MG: 1371 case kDNSType_MR: 1372 case kDNSType_PTR: 1373 case kDNSType_NSAP_PTR: 1374 case kDNSType_DNAME: return(SameDomainName(&b1->name, &b2->name)); 1375 1376 case kDNSType_SOA: return (mDNSBool)( b1->soa.serial == b2->soa.serial && 1377 b1->soa.refresh == b2->soa.refresh && 1378 b1->soa.retry == b2->soa.retry && 1379 b1->soa.expire == b2->soa.expire && 1380 b1->soa.min == b2->soa.min && 1381 samename(&b1->soa.mname, &b2->soa.mname) && 1382 samename(&b1->soa.rname, &b2->soa.rname)); 1383 1384 case kDNSType_MX: 1385 case kDNSType_AFSDB: 1386 case kDNSType_RT: 1387 case kDNSType_KX: return (mDNSBool)( b1->mx.preference == b2->mx.preference && 1388 samename(&b1->mx.exchange, &b2->mx.exchange)); 1389 1390 case kDNSType_MINFO: 1391 case kDNSType_RP: return (mDNSBool)( samename(&b1->rp.mbox, &b2->rp.mbox) && 1392 samename(&b1->rp.txt, &b2->rp.txt)); 1393 1394 case kDNSType_PX: return (mDNSBool)( b1->px.preference == b2->px.preference && 1395 samename(&b1->px.map822, &b2->px.map822) && 1396 samename(&b1->px.mapx400, &b2->px.mapx400)); 1397 1398 case kDNSType_SRV: return (mDNSBool)( b1->srv.priority == b2->srv.priority && 1399 b1->srv.weight == b2->srv.weight && 1400 mDNSSameIPPort(b1->srv.port, b2->srv.port) && 1401 samename(&b1->srv.target, &b2->srv.target)); 1402 1403 case kDNSType_OPT: return mDNSfalse; // OPT is a pseudo-RR container structure; makes no sense to compare 1404 case kDNSType_NSEC: { 1405 // If the "nxt" name changes in case, we want to delete the old 1406 // and store just the new one. If the caller passes in SameDomainCS for "samename", 1407 // we would return "false" when the only change between the two rdata is the case 1408 // change in "nxt". 1409 // 1410 // Note: rdlength of both the RData are same (ensured by the caller) and hence we can 1411 // use just r1->rdlength below 1412 1413 int dlen1 = DomainNameLength((domainname *)b1->data); 1414 int dlen2 = DomainNameLength((domainname *)b2->data); 1415 return (mDNSBool)(dlen1 == dlen2 && 1416 samename((domainname *)b1->data, (domainname *)b2->data) && 1417 mDNSPlatformMemSame(b1->data + dlen1, b2->data + dlen2, r1->rdlength - dlen1)); 1418 } 1419 1420 default: return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength)); 1421 } 1422 } 1423 1424 mDNSexport mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type) 1425 { 1426 int win, wlen; 1427 int wintype; 1428 1429 // The window that this type belongs to. NSEC has 256 windows that 1430 // comprises of 256 types. 1431 wintype = type >> 8; 1432 1433 while (bitmaplen > 0) 1434 { 1435 if (bitmaplen < 3) 1436 { 1437 LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d short", bitmaplen); 1438 return mDNSfalse; 1439 } 1440 1441 win = *bmap++; 1442 wlen = *bmap++; 1443 bitmaplen -= 2; 1444 if (bitmaplen < wlen || wlen < 1 || wlen > 32) 1445 { 1446 LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d wlen %d, win %d", bitmaplen, wlen, win); 1447 return mDNSfalse; 1448 } 1449 if (win < 0 || win >= 256) 1450 { 1451 LogInfo("BitmapTypeCheck: malformed nsec, wlen %d", wlen); 1452 return mDNSfalse; 1453 } 1454 if (win == wintype) 1455 { 1456 // First byte in the window serves 0 to 7, the next one serves 8 to 15 and so on. 1457 // Calculate the right byte offset first. 1458 int boff = (type & 0xff ) >> 3; 1459 if (wlen <= boff) 1460 return mDNSfalse; 1461 // The last three bits values 0 to 7 corresponds to bit positions 1462 // within the byte. 1463 return (bmap[boff] & (0x80 >> (type & 7))); 1464 } 1465 else 1466 { 1467 // If the windows are ordered, then we could check to see 1468 // if wintype > win and then return early. 1469 bmap += wlen; 1470 bitmaplen -= wlen; 1471 } 1472 } 1473 return mDNSfalse; 1474 } 1475 1476 // Don't call this function if the resource record is not NSEC. It will return false 1477 // which means that the type does not exist. 1478 mDNSexport mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type) 1479 { 1480 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 1481 mDNSu8 *nsec = (mDNSu8 *)rdb->data; 1482 int len, bitmaplen; 1483 mDNSu8 *bmap; 1484 1485 if (rr->rrtype != kDNSType_NSEC) return mDNSfalse; 1486 1487 len = DomainNameLength((domainname *)nsec); 1488 1489 bitmaplen = rr->rdlength - len; 1490 bmap = nsec + len; 1491 return (BitmapTypeCheck(bmap, bitmaplen, type)); 1492 } 1493 1494 // Don't call this function if the resource record is not NSEC. It will return false 1495 // which means that the type exists. 1496 mDNSexport mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type) 1497 { 1498 if (rr->rrtype != kDNSType_NSEC) return mDNSfalse; 1499 1500 return !RRAssertsExistence(rr, type); 1501 } 1502 1503 // ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question. 1504 // SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call. 1505 // SameDomainName() is generally cheap when the names don't match, but expensive when they do match, 1506 // because it has to check all the way to the end of the names to be sure. 1507 // In cases where we know in advance that the names match it's especially advantageous to skip the 1508 // SameDomainName() call because that's precisely the time when it's most expensive and least useful. 1509 1510 mDNSlocal mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q) 1511 { 1512 mDNSBool checkType = mDNStrue; 1513 1514 // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records 1515 // are handled in LocalOnlyRecordAnswersQuestion 1516 if (LocalOnlyOrP2PInterface(rr->InterfaceID)) 1517 { 1518 LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID); 1519 return mDNSfalse; 1520 } 1521 if (q->Suppressed) 1522 return mDNSfalse; 1523 1524 if (rr->InterfaceID && 1525 q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && 1526 rr->InterfaceID != q->InterfaceID) return(mDNSfalse); 1527 1528 // Resource record received via unicast, the resolver group ID should match ? 1529 if (!isAuthRecord && !rr->InterfaceID) 1530 { 1531 if (mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); 1532 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 1533 if (rr->dnsservice != q->dnsservice) return(mDNSfalse); 1534 #else 1535 const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0; 1536 const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0; 1537 if (idr != idq) return(mDNSfalse); 1538 #endif 1539 } 1540 1541 // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question 1542 if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); 1543 1544 // CNAME answers question of any type and a negative cache record should not prevent us from querying other 1545 // valid types at the same name. 1546 if (rr->rrtype == kDNSType_CNAME && rr->RecordType == kDNSRecordTypePacketNegative && rr->rrtype != q->qtype) 1547 return mDNSfalse; 1548 1549 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 1550 if (enables_dnssec_validation(q) && record_type_answers_dnssec_question(rr, q->qtype)) checkType = mDNSfalse; 1551 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 1552 1553 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. 1554 if (checkType && !RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse); 1555 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 1556 1557 #if APPLE_OSX_mDNSResponder 1558 if (!mDNSPlatformValidRecordForQuestion(rr, q)) 1559 return mDNSfalse; 1560 #endif // APPLE_OSX_mDNSResponder 1561 1562 return(mDNStrue); 1563 } 1564 1565 mDNSexport mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q) 1566 { 1567 return SameNameRecordAnswersQuestion(&cr->resrec, mDNSfalse, q); 1568 } 1569 1570 mDNSlocal mDNSBool RecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q) 1571 { 1572 if (!SameNameRecordAnswersQuestion(rr, isAuthRecord, q)) 1573 return mDNSfalse; 1574 1575 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 1576 } 1577 1578 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) 1579 { 1580 return RecordAnswersQuestion(rr, mDNSfalse, q); 1581 } 1582 1583 mDNSexport mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q) 1584 { 1585 return RecordAnswersQuestion(&ar->resrec, mDNStrue, q); 1586 } 1587 1588 mDNSexport mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q) 1589 { 1590 return RecordAnswersQuestion(&cr->resrec, mDNSfalse, q); 1591 } 1592 1593 // We have a separate function to handle LocalOnly AuthRecords because they can be created with 1594 // a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike 1595 // multicast resource records (which has a valid InterfaceID) which can't be used to answer 1596 // unicast questions. ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion can't tell whether 1597 // a resource record is multicast or LocalOnly by just looking at the ResourceRecord because 1598 // LocalOnly records are truly identified by ARType in the AuthRecord. As P2P and LocalOnly record 1599 // are kept in the same hash table, we use the same function to make it easy for the callers when 1600 // they walk the hash table to answer LocalOnly/P2P questions 1601 // 1602 mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const DNSQuestion *const q) 1603 { 1604 ResourceRecord *rr = &ar->resrec; 1605 1606 // mDNSInterface_Any questions can be answered with LocalOnly/P2P records in this function. AuthRecord_Any 1607 // records are handled in ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion 1608 if (RRAny(ar)) 1609 { 1610 LogMsg("LocalOnlyRecordAnswersQuestion: ERROR!! called with regular AuthRecordAny %##s", rr->name->c); 1611 return mDNSfalse; 1612 } 1613 1614 // Questions with mDNSInterface_LocalOnly InterfaceID should be answered with all resource records that are 1615 // *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly, 1616 // mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against 1617 // the InterfaceID in the resource record. 1618 1619 if (rr->InterfaceID && 1620 q->InterfaceID != mDNSInterface_LocalOnly && 1621 ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) || 1622 (!q->InterfaceID && !LocalOnlyOrP2PInterface(rr->InterfaceID)))) return(mDNSfalse); 1623 1624 // Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records 1625 // may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set 1626 // to mDNSInterface_Any, mDNSInterface_LocalOnly or a real InterfaceID (scoped). 1627 // 1628 // 1) Question: Any, LocalOnly Record: no scope. This question should be answered with this record. 1629 // 1630 // 2) Question: Any, LocalOnly Record: scoped. This question should be answered with the record because 1631 // traditionally applications never specify scope e.g., getaddrinfo, but need to be able 1632 // to get to /etc/hosts entries. 1633 // 1634 // 3) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: no scope. This is the inverse of (2). 1635 // If we register a LocalOnly record, we need to answer a LocalOnly question. If the /etc/hosts has a 1636 // non scoped entry, it may not make sense to answer a scoped question. But we can't tell these two 1637 // cases apart. As we currently answer LocalOnly question with LocalOnly record, we continue to do so. 1638 // 1639 // 4) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: scoped. LocalOnly questions should be 1640 // answered with any resource record where as if it has a valid InterfaceID, the scope should match. 1641 // 1642 // (1) and (2) is bypassed because we check for a non-NULL InterfaceID above. For (3), the InterfaceID is NULL 1643 // and hence bypassed above. For (4) we bypassed LocalOnly questions and checked the scope of the record 1644 // against the question. 1645 // 1646 // For P2P, InterfaceIDs of the question and the record should match. 1647 1648 // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question. 1649 // LocalOnly authoritative answers are exempt. LocalOnly authoritative answers are used for /etc/host entries. 1650 // We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com" which would then 1651 // cause other applications (e.g. Safari) to connect to the wrong address. The rpc to register records filters out records 1652 // with names that don't end in local and have mDNSInterface_LocalOnly set. 1653 // 1654 // Note: The check is bypassed for LocalOnly and for P2P it is not needed as only .local records are registered and for 1655 // a question to match its names, it also has to end in .local and that question can't be a unicast question (See 1656 // Question_uDNS macro and its usage). As P2P does not enforce .local only registrations we still make this check 1657 // and also makes it future proof. 1658 1659 if (ar->ARType != AuthRecordLocalOnly && rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); 1660 1661 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. 1662 if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse); 1663 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 1664 1665 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 1666 } 1667 1668 mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q) 1669 { 1670 const ResourceRecord *const rr = &ar->resrec; 1671 // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records 1672 // are handled in LocalOnlyRecordAnswersQuestion 1673 if (LocalOnlyOrP2PInterface(rr->InterfaceID)) 1674 { 1675 LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID); 1676 return mDNSfalse; 1677 } 1678 if (rr->InterfaceID && 1679 q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && 1680 rr->InterfaceID != q->InterfaceID) return(mDNSfalse); 1681 1682 // Resource record received via unicast, the resolver group ID should match ? 1683 // Note that Auth Records are normally setup with NULL InterfaceID and 1684 // both the DNSServers are assumed to be NULL in that case 1685 if (!rr->InterfaceID) 1686 { 1687 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 1688 if (rr->dnsservice != q->dnsservice) return(mDNSfalse); 1689 #else 1690 const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0; 1691 const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0; 1692 if (idr != idq) return(mDNSfalse); 1693 #endif 1694 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) 1695 if (!mDNSPlatformValidRecordForInterface(ar, q->InterfaceID)) return(mDNSfalse); 1696 #endif 1697 } 1698 1699 // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question 1700 if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); 1701 1702 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 1703 1704 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 1705 } 1706 1707 // This is called with both unicast resource record and multicast resource record. The question that 1708 // received the unicast response could be the regular unicast response from a DNS server or a response 1709 // to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the 1710 // question and the resource record because the resource record is not completely initialized in 1711 // mDNSCoreReceiveResponse when this function is called. 1712 mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q) 1713 { 1714 mDNSBool checkType = mDNStrue; 1715 1716 if (q->Suppressed) 1717 return mDNSfalse; 1718 1719 // For resource records created using multicast, the InterfaceIDs have to match 1720 if (rr->InterfaceID && 1721 q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse); 1722 1723 // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question. 1724 if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); 1725 1726 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 1727 if (enables_dnssec_validation(q) && record_type_answers_dnssec_question(rr, q->qtype)) checkType = mDNSfalse; 1728 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2) 1729 1730 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. 1731 if (checkType && !RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse); 1732 1733 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); 1734 1735 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); 1736 } 1737 1738 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate) 1739 { 1740 const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data; 1741 const domainname *const name = estimate ? rr->name : mDNSNULL; 1742 if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength); // Used in update packets to mean "Delete An RRset" (RFC 2136) 1743 else switch (rr->rrtype) 1744 { 1745 case kDNSType_A: return(sizeof(rd->ipv4)); 1746 1747 case kDNSType_NS: 1748 case kDNSType_CNAME: 1749 case kDNSType_PTR: 1750 case kDNSType_DNAME: return(CompressedDomainNameLength(&rd->name, name)); 1751 1752 case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) + 1753 CompressedDomainNameLength(&rd->soa.rname, name) + 1754 5 * sizeof(mDNSOpaque32)); 1755 1756 case kDNSType_NULL: 1757 case kDNSType_TSIG: 1758 case kDNSType_TXT: 1759 case kDNSType_X25: 1760 case kDNSType_ISDN: 1761 case kDNSType_LOC: 1762 case kDNSType_DHCID: return(rr->rdlength); // Not self-describing, so have to just trust rdlength 1763 1764 case kDNSType_HINFO: return (mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]); 1765 1766 case kDNSType_MX: 1767 case kDNSType_AFSDB: 1768 case kDNSType_RT: 1769 case kDNSType_KX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name)); 1770 1771 case kDNSType_MINFO: 1772 case kDNSType_RP: return (mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) + 1773 CompressedDomainNameLength(&rd->rp.txt, name)); 1774 1775 case kDNSType_PX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) + 1776 CompressedDomainNameLength(&rd->px.mapx400, name)); 1777 1778 case kDNSType_AAAA: return(sizeof(rd->ipv6)); 1779 1780 case kDNSType_SRV: return (mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name)); 1781 1782 case kDNSType_OPT: return(rr->rdlength); 1783 1784 case kDNSType_NSEC: { 1785 domainname *next = (domainname *)rd->data; 1786 int dlen = DomainNameLength(next); 1787 // 1788 if (UNICAST_NSEC(rr)) 1789 return (mDNSu16)(CompressedDomainNameLength(next, name) + rr->rdlength - dlen); 1790 else 1791 return (mDNSu16)((estimate ? 2 : dlen) + rr->rdlength - dlen); 1792 } 1793 1794 default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype); 1795 return(rr->rdlength); 1796 } 1797 } 1798 1799 // When a local client registers (or updates) a record, we use this routine to do some simple validation checks 1800 // to help reduce the risk of bogus malformed data on the network 1801 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd) 1802 { 1803 mDNSu16 len; 1804 1805 switch(rrtype) 1806 { 1807 case kDNSType_A: return(rdlength == sizeof(mDNSv4Addr)); 1808 1809 case kDNSType_NS: // Same as PTR 1810 case kDNSType_MD: // Same as PTR 1811 case kDNSType_MF: // Same as PTR 1812 case kDNSType_CNAME: // Same as PTR 1813 //case kDNSType_SOA not checked 1814 case kDNSType_MB: // Same as PTR 1815 case kDNSType_MG: // Same as PTR 1816 case kDNSType_MR: // Same as PTR 1817 //case kDNSType_NULL not checked (no specified format, so always valid) 1818 //case kDNSType_WKS not checked 1819 case kDNSType_PTR: len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength); 1820 return(len <= MAX_DOMAIN_NAME && rdlength == len); 1821 1822 case kDNSType_HINFO: // Same as TXT (roughly) 1823 case kDNSType_MINFO: // Same as TXT (roughly) 1824 case kDNSType_TXT: if (!rdlength) return(mDNSfalse); // TXT record has to be at least one byte (RFC 1035) 1825 { 1826 const mDNSu8 *ptr = rd->u.txt.c; 1827 const mDNSu8 *end = rd->u.txt.c + rdlength; 1828 while (ptr < end) ptr += 1 + ptr[0]; 1829 return (ptr == end); 1830 } 1831 1832 case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr)); 1833 1834 case kDNSType_MX: // Must be at least two-byte preference, plus domainname 1835 // Call to DomainNameLengthLimit() implicitly enforces both requirements for us 1836 len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength); 1837 return(len <= MAX_DOMAIN_NAME && rdlength == 2+len); 1838 1839 case kDNSType_SRV: // Must be at least priority+weight+port, plus domainname 1840 // Call to DomainNameLengthLimit() implicitly enforces both requirements for us 1841 len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength); 1842 return(len <= MAX_DOMAIN_NAME && rdlength == 6+len); 1843 1844 //case kDNSType_NSEC not checked 1845 1846 default: return(mDNStrue); // Allow all other types without checking 1847 } 1848 } 1849 1850 // *************************************************************************** 1851 #if COMPILER_LIKES_PRAGMA_MARK 1852 #pragma mark - 1853 #pragma mark - DNS Message Creation Functions 1854 #endif 1855 1856 mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags) 1857 { 1858 h->id = id; 1859 h->flags = flags; 1860 h->numQuestions = 0; 1861 h->numAnswers = 0; 1862 h->numAuthorities = 0; 1863 h->numAdditionals = 0; 1864 } 1865 1866 #endif // !STANDALONE 1867 1868 mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname) 1869 { 1870 const mDNSu8 *result = end - *domname - 1; 1871 1872 if (*domname == 0) return(mDNSNULL); // There's no point trying to match just the root label 1873 1874 // This loop examines each possible starting position in packet, starting end of the packet and working backwards 1875 while (result >= base) 1876 { 1877 // If the length byte and first character of the label match, then check further to see 1878 // if this location in the packet will yield a useful name compression pointer. 1879 if (result[0] == domname[0] && result[1] == domname[1]) 1880 { 1881 const mDNSu8 *name = domname; 1882 const mDNSu8 *targ = result; 1883 while (targ + *name < end) 1884 { 1885 // First see if this label matches 1886 int i; 1887 const mDNSu8 *pointertarget; 1888 for (i=0; i <= *name; i++) if (targ[i] != name[i]) break; 1889 if (i <= *name) break; // If label did not match, bail out 1890 targ += 1 + *name; // Else, did match, so advance target pointer 1891 name += 1 + *name; // and proceed to check next label 1892 if (*name == 0 && *targ == 0) return(result); // If no more labels, we found a match! 1893 if (*name == 0) break; // If no more labels to match, we failed, so bail out 1894 1895 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches 1896 if (targ[0] < 0x40) continue; // If length value, continue to check next label 1897 if (targ[0] < 0xC0) break; // If 40-BF, not valid 1898 if (targ+1 >= end) break; // Second byte not present! 1899 pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1]; 1900 if (targ < pointertarget) break; // Pointertarget must point *backwards* in the packet 1901 if (pointertarget[0] >= 0x40) break; // Pointertarget must point to a valid length byte 1902 targ = pointertarget; 1903 } 1904 } 1905 result--; // We failed to match at this search position, so back up the tentative result pointer and try again 1906 } 1907 return(mDNSNULL); 1908 } 1909 1910 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't) 1911 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers) 1912 // end points to the end of the message so far 1913 // ptr points to where we want to put the name 1914 // limit points to one byte past the end of the buffer that we must not overrun 1915 // domainname is the name to put 1916 mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, 1917 mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name) 1918 { 1919 const mDNSu8 *const base = (const mDNSu8 *)msg; 1920 const mDNSu8 * np = name->c; 1921 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid 1922 const mDNSu8 * pointer = mDNSNULL; 1923 const mDNSu8 *const searchlimit = ptr; 1924 1925 if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); return(mDNSNULL); } 1926 1927 if (!*np) // If just writing one-byte root label, make sure we have space for that 1928 { 1929 if (ptr >= limit) return(mDNSNULL); 1930 } 1931 else // else, loop through writing labels and/or a compression offset 1932 { 1933 do { 1934 if (*np > MAX_DOMAIN_LABEL) 1935 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); } 1936 1937 // This check correctly allows for the final trailing root label: 1938 // e.g. 1939 // Suppose our domain name is exactly 256 bytes long, including the final trailing root label. 1940 // Suppose np is now at name->c[249], and we're about to write our last non-null label ("local"). 1941 // We know that max will be at name->c[256] 1942 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our 1943 // six bytes, then exit the loop, write the final terminating root label, and the domain 1944 // name we've written is exactly 256 bytes long, exactly at the correct legal limit. 1945 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out. 1946 if (np + 1 + *np >= max) 1947 { LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); } 1948 1949 if (base) pointer = FindCompressionPointer(base, searchlimit, np); 1950 if (pointer) // Use a compression pointer if we can 1951 { 1952 const mDNSu16 offset = (mDNSu16)(pointer - base); 1953 if (ptr+2 > limit) return(mDNSNULL); // If we don't have two bytes of space left, give up 1954 *ptr++ = (mDNSu8)(0xC0 | (offset >> 8)); 1955 *ptr++ = (mDNSu8)( offset & 0xFF); 1956 return(ptr); 1957 } 1958 else // Else copy one label and try again 1959 { 1960 int i; 1961 mDNSu8 len = *np++; 1962 // If we don't at least have enough space for this label *plus* a terminating zero on the end, give up 1963 if (ptr + 1 + len >= limit) return(mDNSNULL); 1964 *ptr++ = len; 1965 for (i=0; i<len; i++) *ptr++ = *np++; 1966 } 1967 } while (*np); // While we've got characters remaining in the name, continue 1968 } 1969 1970 *ptr++ = 0; // Put the final root label 1971 return(ptr); 1972 } 1973 1974 #ifndef STANDALONE 1975 1976 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val) 1977 { 1978 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF); 1979 ptr[1] = (mDNSu8)((val ) & 0xFF); 1980 return ptr + sizeof(mDNSOpaque16); 1981 } 1982 1983 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val) 1984 { 1985 ptr[0] = (mDNSu8)((val >> 24) & 0xFF); 1986 ptr[1] = (mDNSu8)((val >> 16) & 0xFF); 1987 ptr[2] = (mDNSu8)((val >> 8) & 0xFF); 1988 ptr[3] = (mDNSu8)((val ) & 0xFF); 1989 return ptr + sizeof(mDNSu32); 1990 } 1991 1992 // Copy the RDATA information. The actual in memory storage for the data might be bigger than what the rdlength 1993 // says. Hence, the only way to copy out the data from a resource record is to use putRData. 1994 // msg points to the message we're building (pass mDNSNULL for "msg" if we don't want to use compression pointers) 1995 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr) 1996 { 1997 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 1998 switch (rr->rrtype) 1999 { 2000 case kDNSType_A: if (rr->rdlength != 4) 2001 { debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); } 2002 if (ptr + 4 > limit) return(mDNSNULL); 2003 *ptr++ = rdb->ipv4.b[0]; 2004 *ptr++ = rdb->ipv4.b[1]; 2005 *ptr++ = rdb->ipv4.b[2]; 2006 *ptr++ = rdb->ipv4.b[3]; 2007 return(ptr); 2008 2009 case kDNSType_NS: 2010 case kDNSType_CNAME: 2011 case kDNSType_PTR: 2012 case kDNSType_DNAME: return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name)); 2013 2014 case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname); 2015 if (!ptr) return(mDNSNULL); 2016 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.rname); 2017 if (!ptr || ptr + 20 > limit) return(mDNSNULL); 2018 ptr = putVal32(ptr, rdb->soa.serial); 2019 ptr = putVal32(ptr, rdb->soa.refresh); 2020 ptr = putVal32(ptr, rdb->soa.retry); 2021 ptr = putVal32(ptr, rdb->soa.expire); 2022 ptr = putVal32(ptr, rdb->soa.min); 2023 return(ptr); 2024 2025 case kDNSType_NULL: 2026 case kDNSType_HINFO: 2027 case kDNSType_TSIG: 2028 case kDNSType_TXT: 2029 case kDNSType_X25: 2030 case kDNSType_ISDN: 2031 case kDNSType_LOC: 2032 case kDNSType_DHCID: if (ptr + rr->rdlength > limit) return(mDNSNULL); 2033 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); 2034 return(ptr + rr->rdlength); 2035 2036 case kDNSType_MX: 2037 case kDNSType_AFSDB: 2038 case kDNSType_RT: 2039 case kDNSType_KX: if (ptr + 3 > limit) return(mDNSNULL); 2040 ptr = putVal16(ptr, rdb->mx.preference); 2041 return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange)); 2042 2043 case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox); 2044 if (!ptr) return(mDNSNULL); 2045 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.txt); 2046 return(ptr); 2047 2048 case kDNSType_PX: if (ptr + 5 > limit) return(mDNSNULL); 2049 ptr = putVal16(ptr, rdb->px.preference); 2050 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822); 2051 if (!ptr) return(mDNSNULL); 2052 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400); 2053 return(ptr); 2054 2055 case kDNSType_AAAA: if (rr->rdlength != sizeof(rdb->ipv6)) 2056 { debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); } 2057 if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL); 2058 mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6)); 2059 return(ptr + sizeof(rdb->ipv6)); 2060 2061 case kDNSType_SRV: if (ptr + 7 > limit) return(mDNSNULL); 2062 *ptr++ = (mDNSu8)(rdb->srv.priority >> 8); 2063 *ptr++ = (mDNSu8)(rdb->srv.priority & 0xFF); 2064 *ptr++ = (mDNSu8)(rdb->srv.weight >> 8); 2065 *ptr++ = (mDNSu8)(rdb->srv.weight & 0xFF); 2066 *ptr++ = rdb->srv.port.b[0]; 2067 *ptr++ = rdb->srv.port.b[1]; 2068 return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target)); 2069 2070 case kDNSType_OPT: { 2071 int len = 0; 2072 const rdataOPT *opt; 2073 const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength]; 2074 for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) 2075 len += DNSOpt_Data_Space(opt); 2076 if (ptr + len > limit) 2077 { 2078 LogMsg("ERROR: putOptRData - out of space"); 2079 return mDNSNULL; 2080 } 2081 for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) 2082 { 2083 const int space = DNSOpt_Data_Space(opt); 2084 ptr = putVal16(ptr, opt->opt); 2085 ptr = putVal16(ptr, (mDNSu16)space - 4); 2086 switch (opt->opt) 2087 { 2088 case kDNSOpt_LLQ: 2089 ptr = putVal16(ptr, opt->u.llq.vers); 2090 ptr = putVal16(ptr, opt->u.llq.llqOp); 2091 ptr = putVal16(ptr, opt->u.llq.err); 2092 mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8); // 8-byte id 2093 ptr += 8; 2094 ptr = putVal32(ptr, opt->u.llq.llqlease); 2095 break; 2096 case kDNSOpt_Lease: 2097 ptr = putVal32(ptr, opt->u.updatelease); 2098 break; 2099 case kDNSOpt_Owner: 2100 *ptr++ = opt->u.owner.vers; 2101 *ptr++ = opt->u.owner.seq; 2102 mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6); // 6-byte Host identifier 2103 ptr += 6; 2104 if (space >= DNSOpt_OwnerData_ID_Wake_Space) 2105 { 2106 mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6); // 6-byte interface MAC 2107 ptr += 6; 2108 if (space > DNSOpt_OwnerData_ID_Wake_Space) 2109 { 2110 mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space); 2111 ptr += space - DNSOpt_OwnerData_ID_Wake_Space; 2112 } 2113 } 2114 break; 2115 case kDNSOpt_Trace: 2116 *ptr++ = opt->u.tracer.platf; 2117 ptr = putVal32(ptr, opt->u.tracer.mDNSv); 2118 break; 2119 } 2120 } 2121 return ptr; 2122 } 2123 2124 case kDNSType_NSEC: { 2125 // For NSEC records, rdlength represents the exact number of bytes 2126 // of in memory storage. 2127 mDNSu8 *nsec = (mDNSu8 *)rdb->data; 2128 domainname *name = (domainname *)nsec; 2129 const int dlen = DomainNameLength(name); 2130 nsec += dlen; 2131 // This function is called when we are sending a NSEC record as part of mDNS, 2132 // or to copy the data to any other buffer needed which could be a mDNS or uDNS 2133 // NSEC record. The only time compression is used that when we are sending it 2134 // in mDNS (indicated by non-NULL "msg") and hence we handle mDNS case 2135 // separately. 2136 if (!UNICAST_NSEC(rr)) 2137 { 2138 mDNSu8 *save = ptr; 2139 int i, j, wlen; 2140 wlen = *(nsec + 1); 2141 nsec += 2; // Skip the window number and len 2142 2143 // For our simplified use of NSEC synthetic records: 2144 // 2145 // nextname is always the record's own name, 2146 // the block number is always 0, 2147 // the count byte is a value in the range 1-32, 2148 // followed by the 1-32 data bytes 2149 // 2150 // Note: When we send the NSEC record in mDNS, the window size is set to 32. 2151 // We need to find out what the last non-NULL byte is. If we are copying out 2152 // from an RDATA, we have the right length. As we need to handle both the case, 2153 // we loop to find the right value instead of blindly using len to copy. 2154 2155 for (i=wlen; i>0; i--) if (nsec[i-1]) break; 2156 2157 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); 2158 if (!ptr) { LogInfo("putRData: Can't put name, Length %d, record %##s", limit - save, rr->name->c); return(mDNSNULL); } 2159 if (i) // Only put a block if at least one type exists for this name 2160 { 2161 if (ptr + 2 + i > limit) { LogInfo("putRData: Can't put window, Length %d, i %d, record %##s", limit - ptr, i, rr->name->c); return(mDNSNULL); } 2162 *ptr++ = 0; 2163 *ptr++ = (mDNSu8)i; 2164 for (j=0; j<i; j++) *ptr++ = nsec[j]; 2165 } 2166 return ptr; 2167 } 2168 else 2169 { 2170 int win, wlen; 2171 int len = rr->rdlength - dlen; 2172 2173 // Sanity check whether the bitmap is good 2174 while (len) 2175 { 2176 if (len < 3) 2177 { LogMsg("putRData: invalid length %d", len); return mDNSNULL; } 2178 2179 win = *nsec++; 2180 wlen = *nsec++; 2181 len -= 2; 2182 if (len < wlen || wlen < 1 || wlen > 32) 2183 { LogMsg("putRData: invalid window length %d", wlen); return mDNSNULL; } 2184 if (win < 0 || win >= 256) 2185 { LogMsg("putRData: invalid window %d", win); return mDNSNULL; } 2186 2187 nsec += wlen; 2188 len -= wlen; 2189 } 2190 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);} 2191 2192 // No compression allowed for "nxt", just copy the data. 2193 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); 2194 return(ptr + rr->rdlength); 2195 } 2196 } 2197 2198 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype); 2199 if (ptr + rr->rdlength > limit) return(mDNSNULL); 2200 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); 2201 return(ptr + rr->rdlength); 2202 } 2203 } 2204 2205 #define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update) 2206 2207 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, 2208 const ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit) 2209 { 2210 mDNSu8 *endofrdata; 2211 mDNSu16 actualLength; 2212 // When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782) 2213 const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg; 2214 2215 if (rr->RecordType == kDNSRecordTypeUnregistered) 2216 { 2217 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 2218 "Attempt to put kDNSRecordTypeUnregistered " PRI_DM_NAME " (" PUB_S ")", 2219 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype)); 2220 return(ptr); 2221 } 2222 2223 if (!ptr) 2224 { 2225 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 2226 "Pointer to message is NULL while filling resource record " PRI_DM_NAME " (" PUB_S ")", 2227 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype)); 2228 return(mDNSNULL); 2229 } 2230 2231 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); 2232 // If we're out-of-space, return mDNSNULL 2233 if (!ptr || ptr + 10 >= limit) 2234 { 2235 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 2236 "Can't put more names into current message, will possibly put it into the next message - " 2237 "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld", 2238 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr)); 2239 return(mDNSNULL); 2240 } 2241 ptr[0] = (mDNSu8)(rr->rrtype >> 8); 2242 ptr[1] = (mDNSu8)(rr->rrtype & 0xFF); 2243 ptr[2] = (mDNSu8)(rr->rrclass >> 8); 2244 ptr[3] = (mDNSu8)(rr->rrclass & 0xFF); 2245 ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF); 2246 ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF); 2247 ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF); 2248 ptr[7] = (mDNSu8)( ttl & 0xFF); 2249 // ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes 2250 2251 endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr); 2252 if (!endofrdata) 2253 { 2254 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 2255 "Can't put more rdata into current message, will possibly put it into the next message - " 2256 "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld", 2257 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr - 10)); 2258 return(mDNSNULL); 2259 } 2260 2261 // Go back and fill in the actual number of data bytes we wrote 2262 // (actualLength can be less than rdlength when domain name compression is used) 2263 actualLength = (mDNSu16)(endofrdata - ptr - 10); 2264 ptr[8] = (mDNSu8)(actualLength >> 8); 2265 ptr[9] = (mDNSu8)(actualLength & 0xFF); 2266 2267 if (count) 2268 { 2269 (*count)++; 2270 } 2271 else 2272 { 2273 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 2274 "No target count to update for " PRI_DM_NAME " (" PUB_S ")", 2275 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype)); 2276 } 2277 return(endofrdata); 2278 } 2279 2280 mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr) 2281 { 2282 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name); 2283 if (!ptr || ptr + 10 > limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL 2284 ptr[0] = (mDNSu8)(rr->resrec.rrtype >> 8); // Put type 2285 ptr[1] = (mDNSu8)(rr->resrec.rrtype & 0xFF); 2286 ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8); // Put class 2287 ptr[3] = (mDNSu8)(rr->resrec.rrclass & 0xFF); 2288 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // TTL is zero 2289 ptr[8] = ptr[9] = 0; // RDATA length is zero 2290 (*count)++; 2291 return(ptr + 10); 2292 } 2293 2294 mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass) 2295 { 2296 ptr = putDomainNameAsLabels(msg, ptr, limit, name); 2297 if (!ptr || ptr+4 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL 2298 ptr[0] = (mDNSu8)(rrtype >> 8); 2299 ptr[1] = (mDNSu8)(rrtype & 0xFF); 2300 ptr[2] = (mDNSu8)(rrclass >> 8); 2301 ptr[3] = (mDNSu8)(rrclass & 0xFF); 2302 msg->h.numQuestions++; 2303 return(ptr+4); 2304 } 2305 2306 // for dynamic updates 2307 mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass) 2308 { 2309 ptr = putDomainNameAsLabels(msg, ptr, limit, zone); 2310 if (!ptr || ptr + 4 > limit) return mDNSNULL; // If we're out-of-space, return NULL 2311 *ptr++ = (mDNSu8)(kDNSType_SOA >> 8); 2312 *ptr++ = (mDNSu8)(kDNSType_SOA & 0xFF); 2313 *ptr++ = zoneClass.b[0]; 2314 *ptr++ = zoneClass.b[1]; 2315 msg->h.mDNS_numZones++; 2316 return ptr; 2317 } 2318 2319 // for dynamic updates 2320 mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end) 2321 { 2322 AuthRecord prereq; 2323 mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL); 2324 AssignDomainName(&prereq.namestorage, name); 2325 prereq.resrec.rrtype = kDNSQType_ANY; 2326 prereq.resrec.rrclass = kDNSClass_NONE; 2327 return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq); 2328 } 2329 2330 // for dynamic updates 2331 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr) 2332 { 2333 // deletion: specify record w/ TTL 0, class NONE 2334 const mDNSu16 origclass = rr->rrclass; 2335 rr->rrclass = kDNSClass_NONE; 2336 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0); 2337 rr->rrclass = origclass; 2338 return ptr; 2339 } 2340 2341 // for dynamic updates 2342 mDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit) 2343 { 2344 // deletion: specify record w/ TTL 0, class NONE 2345 const mDNSu16 origclass = rr->rrclass; 2346 rr->rrclass = kDNSClass_NONE; 2347 ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit); 2348 rr->rrclass = origclass; 2349 return ptr; 2350 } 2351 2352 mDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit) 2353 { 2354 mDNSu16 class = kDNSQClass_ANY; 2355 2356 ptr = putDomainNameAsLabels(msg, ptr, limit, name); 2357 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL 2358 ptr[0] = (mDNSu8)(rrtype >> 8); 2359 ptr[1] = (mDNSu8)(rrtype & 0xFF); 2360 ptr[2] = (mDNSu8)(class >> 8); 2361 ptr[3] = (mDNSu8)(class & 0xFF); 2362 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl 2363 ptr[8] = ptr[9] = 0; // zero rdlength/rdata 2364 2365 msg->h.mDNS_numUpdates++; 2366 return ptr + 10; 2367 } 2368 2369 // for dynamic updates 2370 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name) 2371 { 2372 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData; 2373 mDNSu16 class = kDNSQClass_ANY; 2374 mDNSu16 rrtype = kDNSQType_ANY; 2375 2376 ptr = putDomainNameAsLabels(msg, ptr, limit, name); 2377 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL 2378 ptr[0] = (mDNSu8)(rrtype >> 8); 2379 ptr[1] = (mDNSu8)(rrtype & 0xFF); 2380 ptr[2] = (mDNSu8)(class >> 8); 2381 ptr[3] = (mDNSu8)(class & 0xFF); 2382 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl 2383 ptr[8] = ptr[9] = 0; // zero rdlength/rdata 2384 2385 msg->h.mDNS_numUpdates++; 2386 return ptr + 10; 2387 } 2388 2389 // for dynamic updates 2390 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease) 2391 { 2392 AuthRecord rr; 2393 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 2394 rr.resrec.rrclass = NormalMaxDNSMessageData; 2395 rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 2396 rr.resrec.rdestimate = sizeof(rdataOPT); 2397 rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 2398 rr.resrec.rdata->u.opt[0].u.updatelease = lease; 2399 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0); 2400 if (!ptr) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; } 2401 return ptr; 2402 } 2403 2404 // for dynamic updates 2405 mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit) 2406 { 2407 AuthRecord rr; 2408 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 2409 rr.resrec.rrclass = NormalMaxDNSMessageData; 2410 rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 2411 rr.resrec.rdestimate = sizeof(rdataOPT); 2412 rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 2413 rr.resrec.rdata->u.opt[0].u.updatelease = lease; 2414 ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0, limit); 2415 if (!ptr) { LogMsg("ERROR: putUpdateLeaseWithLimit - PutResourceRecordTTLWithLimit"); return mDNSNULL; } 2416 return ptr; 2417 } 2418 2419 // *************************************************************************** 2420 #if COMPILER_LIKES_PRAGMA_MARK 2421 #pragma mark - 2422 #pragma mark - DNS Message Parsing Functions 2423 #endif 2424 2425 mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name) 2426 { 2427 mDNSu32 sum = 0; 2428 const mDNSu8 *c; 2429 2430 for (c = name->c; c[0] != 0 && c[1] != 0; c += 2) 2431 { 2432 sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) | 2433 (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]); 2434 sum = (sum<<3) | (sum>>29); 2435 } 2436 if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8); 2437 return(sum); 2438 } 2439 2440 mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength) 2441 { 2442 domainname *target; 2443 if (NewRData) 2444 { 2445 rr->rdata = NewRData; 2446 rr->rdlength = rdlength; 2447 } 2448 // Must not try to get target pointer until after updating rr->rdata 2449 target = GetRRDomainNameTarget(rr); 2450 rr->rdlength = GetRDLength(rr, mDNSfalse); 2451 rr->rdestimate = GetRDLength(rr, mDNStrue); 2452 rr->rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr); 2453 } 2454 2455 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end) 2456 { 2457 mDNSu16 total = 0; 2458 2459 if (ptr < (mDNSu8*)msg || ptr >= end) 2460 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); } 2461 2462 while (1) // Read sequence of labels 2463 { 2464 const mDNSu8 len = *ptr++; // Read length of this label 2465 if (len == 0) return(ptr); // If length is zero, that means this name is complete 2466 switch (len & 0xC0) 2467 { 2468 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label 2469 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); } 2470 if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label 2471 { debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); } 2472 ptr += len; 2473 total += 1 + len; 2474 break; 2475 2476 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL); 2477 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL); 2478 case 0xC0: return(ptr+1); 2479 } 2480 } 2481 } 2482 2483 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary. 2484 mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, 2485 domainname *const name) 2486 { 2487 const mDNSu8 *nextbyte = mDNSNULL; // Record where we got to before we started following pointers 2488 mDNSu8 *np = name->c; // Name pointer 2489 const mDNSu8 *const limit = np + MAX_DOMAIN_NAME; // Limit so we don't overrun buffer 2490 2491 if (ptr < (mDNSu8*)msg || ptr >= end) 2492 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); } 2493 2494 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels) 2495 2496 while (1) // Read sequence of labels 2497 { 2498 int i; 2499 mDNSu16 offset; 2500 const mDNSu8 len = *ptr++; // Read length of this label 2501 if (len == 0) break; // If length is zero, that means this name is complete 2502 switch (len & 0xC0) 2503 { 2504 2505 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label 2506 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); } 2507 if (np + 1 + len >= limit) // Remember: expect at least one more byte for the root label 2508 { debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); } 2509 *np++ = len; 2510 for (i=0; i<len; i++) *np++ = *ptr++; 2511 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels) 2512 break; 2513 2514 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c); 2515 return(mDNSNULL); 2516 2517 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL); 2518 2519 case 0xC0: if (ptr >= end) 2520 { debugf("getDomainName: Malformed compression label (overruns packet end)"); return(mDNSNULL); } 2521 offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++); 2522 if (!nextbyte) nextbyte = ptr; // Record where we got to before we started following pointers 2523 ptr = (mDNSu8 *)msg + offset; 2524 if (ptr < (mDNSu8*)msg || ptr >= end) 2525 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); } 2526 if (*ptr & 0xC0) 2527 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); } 2528 break; 2529 } 2530 } 2531 2532 if (nextbyte) return(nextbyte); 2533 else return(ptr); 2534 } 2535 2536 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end) 2537 { 2538 mDNSu16 pktrdlength; 2539 2540 ptr = skipDomainName(msg, ptr, end); 2541 if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); } 2542 2543 if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); } 2544 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); 2545 ptr += 10; 2546 if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } 2547 2548 return(ptr + pktrdlength); 2549 } 2550 2551 // Sanity check whether the NSEC/NSEC3 bitmap is good 2552 mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int len) 2553 { 2554 int win, wlen; 2555 2556 while (bmap < end) 2557 { 2558 if (len < 3) 2559 { 2560 LogInfo("SanityCheckBitMap: invalid length %d", len); 2561 return mDNSNULL; 2562 } 2563 2564 win = *bmap++; 2565 wlen = *bmap++; 2566 len -= 2; 2567 if (len < wlen || wlen < 1 || wlen > 32) 2568 { 2569 LogInfo("SanityCheckBitMap: invalid window length %d", wlen); 2570 return mDNSNULL; 2571 } 2572 if (win < 0 || win >= 256) 2573 { 2574 LogInfo("SanityCheckBitMap: invalid window %d", win); 2575 return mDNSNULL; 2576 } 2577 2578 bmap += wlen; 2579 len -= wlen; 2580 } 2581 return (mDNSu8 *)bmap; 2582 } 2583 2584 mDNSlocal mDNSBool AssignDomainNameWithLimit(domainname *const dst, const domainname *src, const mDNSu8 *const end) 2585 { 2586 const mDNSu32 len = DomainNameLengthLimit(src, end); 2587 if ((len >= 1) && (len <= MAX_DOMAIN_NAME)) 2588 { 2589 mDNSPlatformMemCopy(dst->c, src->c, len); 2590 return mDNStrue; 2591 } 2592 else 2593 { 2594 dst->c[0] = 0; 2595 return mDNSfalse; 2596 } 2597 } 2598 2599 // This function is called with "msg" when we receive a DNS message and needs to parse a single resource record 2600 // pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded 2601 // (domainnames are expanded to 256 bytes) when stored in memory. 2602 // 2603 // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr. 2604 // The caller can do this only if the names in the resource records are not compressed and validity of the 2605 // resource record has already been done before. 2606 mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, ResourceRecord *const rr, 2607 const mDNSu16 rdlength) 2608 { 2609 RDataBody2 *const rdb = (RDataBody2 *)&rr->rdata->u; 2610 2611 switch (rr->rrtype) 2612 { 2613 case kDNSType_A: 2614 if (rdlength != sizeof(mDNSv4Addr)) 2615 goto fail; 2616 rdb->ipv4.b[0] = ptr[0]; 2617 rdb->ipv4.b[1] = ptr[1]; 2618 rdb->ipv4.b[2] = ptr[2]; 2619 rdb->ipv4.b[3] = ptr[3]; 2620 break; 2621 2622 case kDNSType_NS: 2623 case kDNSType_MD: 2624 case kDNSType_MF: 2625 case kDNSType_CNAME: 2626 case kDNSType_MB: 2627 case kDNSType_MG: 2628 case kDNSType_MR: 2629 case kDNSType_PTR: 2630 case kDNSType_NSAP_PTR: 2631 case kDNSType_DNAME: 2632 if (msg) 2633 { 2634 ptr = getDomainName(msg, ptr, end, &rdb->name); 2635 } 2636 else 2637 { 2638 if (!AssignDomainNameWithLimit(&rdb->name, (domainname *)ptr, end)) 2639 { 2640 goto fail; 2641 } 2642 ptr += DomainNameLength(&rdb->name); 2643 } 2644 if (ptr != end) 2645 { 2646 debugf("SetRData: Malformed CNAME/PTR RDATA name"); 2647 goto fail; 2648 } 2649 break; 2650 2651 case kDNSType_SOA: 2652 if (msg) 2653 { 2654 ptr = getDomainName(msg, ptr, end, &rdb->soa.mname); 2655 } 2656 else 2657 { 2658 if (!AssignDomainNameWithLimit(&rdb->soa.mname, (domainname *)ptr, end)) 2659 { 2660 goto fail; 2661 } 2662 ptr += DomainNameLength(&rdb->soa.mname); 2663 } 2664 if (!ptr) 2665 { 2666 debugf("SetRData: Malformed SOA RDATA mname"); 2667 goto fail; 2668 } 2669 if (msg) 2670 { 2671 ptr = getDomainName(msg, ptr, end, &rdb->soa.rname); 2672 } 2673 else 2674 { 2675 if (!AssignDomainNameWithLimit(&rdb->soa.rname, (domainname *)ptr, end)) 2676 { 2677 goto fail; 2678 } 2679 ptr += DomainNameLength(&rdb->soa.rname); 2680 } 2681 if (!ptr) 2682 { 2683 debugf("SetRData: Malformed SOA RDATA rname"); 2684 goto fail; 2685 } 2686 if (ptr + 0x14 != end) 2687 { 2688 debugf("SetRData: Malformed SOA RDATA"); 2689 goto fail; 2690 } 2691 rdb->soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]); 2692 rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]); 2693 rdb->soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]); 2694 rdb->soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]); 2695 rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]); 2696 break; 2697 2698 case kDNSType_HINFO: 2699 // See https://tools.ietf.org/html/rfc1035#section-3.3.2 for HINFO RDATA format. 2700 { 2701 // HINFO should contain RDATA. 2702 if (end <= ptr || rdlength != (mDNSu32)(end - ptr)) 2703 { 2704 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 2705 "SetRData: Malformed HINFO RDATA - invalid RDATA length: %u", rdlength); 2706 goto fail; 2707 } 2708 2709 const mDNSu8 *currentPtr = ptr; 2710 // CPU character string length should be less than the RDATA length. 2711 mDNSu32 cpuCharacterStrLength = currentPtr[0]; 2712 if (1 + cpuCharacterStrLength >= (mDNSu32)(end - currentPtr)) 2713 { 2714 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 2715 "SetRData: Malformed HINFO RDATA - CPU character string goes out of boundary"); 2716 goto fail; 2717 } 2718 currentPtr += 1 + cpuCharacterStrLength; 2719 2720 // OS character string should end at the RDATA ending. 2721 mDNSu32 osCharacterStrLength = currentPtr[0]; 2722 if (1 + osCharacterStrLength != (mDNSu32)(end - currentPtr)) 2723 { 2724 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, 2725 "SetRData: Malformed HINFO RDATA - OS character string does not end at the RDATA ending"); 2726 goto fail; 2727 } 2728 2729 // Copy the validated RDATA. 2730 rr->rdlength = rdlength; 2731 mDNSPlatformMemCopy(rdb->data, ptr, rdlength); 2732 break; 2733 } 2734 case kDNSType_NULL: 2735 case kDNSType_TXT: 2736 case kDNSType_X25: 2737 case kDNSType_ISDN: 2738 case kDNSType_LOC: 2739 case kDNSType_DHCID: 2740 case kDNSType_SVCB: 2741 case kDNSType_HTTPS: 2742 rr->rdlength = rdlength; 2743 mDNSPlatformMemCopy(rdb->data, ptr, rdlength); 2744 break; 2745 2746 case kDNSType_MX: 2747 case kDNSType_AFSDB: 2748 case kDNSType_RT: 2749 case kDNSType_KX: 2750 // Preference + domainname 2751 if (rdlength < 3) 2752 goto fail; 2753 rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 2754 ptr += 2; 2755 if (msg) 2756 { 2757 ptr = getDomainName(msg, ptr, end, &rdb->mx.exchange); 2758 } 2759 else 2760 { 2761 if (!AssignDomainNameWithLimit(&rdb->mx.exchange, (domainname *)ptr, end)) 2762 { 2763 goto fail; 2764 } 2765 ptr += DomainNameLength(&rdb->mx.exchange); 2766 } 2767 if (ptr != end) 2768 { 2769 debugf("SetRData: Malformed MX name"); 2770 goto fail; 2771 } 2772 break; 2773 2774 case kDNSType_MINFO: 2775 case kDNSType_RP: 2776 // Domainname + domainname 2777 if (msg) 2778 { 2779 ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox); 2780 } 2781 else 2782 { 2783 if (!AssignDomainNameWithLimit(&rdb->rp.mbox, (domainname *)ptr, end)) 2784 { 2785 goto fail; 2786 } 2787 ptr += DomainNameLength(&rdb->rp.mbox); 2788 } 2789 if (!ptr) 2790 { 2791 debugf("SetRData: Malformed RP mbox"); 2792 goto fail; 2793 } 2794 if (msg) 2795 { 2796 ptr = getDomainName(msg, ptr, end, &rdb->rp.txt); 2797 } 2798 else 2799 { 2800 if (!AssignDomainNameWithLimit(&rdb->rp.txt, (domainname *)ptr, end)) 2801 { 2802 goto fail; 2803 } 2804 ptr += DomainNameLength(&rdb->rp.txt); 2805 } 2806 if (ptr != end) 2807 { 2808 debugf("SetRData: Malformed RP txt"); 2809 goto fail; 2810 } 2811 break; 2812 2813 case kDNSType_PX: 2814 // Preference + domainname + domainname 2815 if (rdlength < 4) 2816 goto fail; 2817 rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 2818 ptr += 2; 2819 if (msg) 2820 { 2821 ptr = getDomainName(msg, ptr, end, &rdb->px.map822); 2822 } 2823 else 2824 { 2825 if (!AssignDomainNameWithLimit(&rdb->px.map822, (domainname *)ptr, end)) 2826 { 2827 goto fail; 2828 } 2829 ptr += DomainNameLength(&rdb->px.map822); 2830 } 2831 if (!ptr) 2832 { 2833 debugf("SetRData: Malformed PX map822"); 2834 goto fail; 2835 } 2836 if (msg) 2837 { 2838 ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400); 2839 } 2840 else 2841 { 2842 if (!AssignDomainNameWithLimit(&rdb->px.mapx400, (domainname *)ptr, end)) 2843 { 2844 goto fail; 2845 } 2846 ptr += DomainNameLength(&rdb->px.mapx400); 2847 } 2848 if (ptr != end) 2849 { 2850 debugf("SetRData: Malformed PX mapx400"); 2851 goto fail; 2852 } 2853 break; 2854 2855 case kDNSType_AAAA: 2856 if (rdlength != sizeof(mDNSv6Addr)) 2857 goto fail; 2858 mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6)); 2859 break; 2860 2861 case kDNSType_SRV: 2862 // Priority + weight + port + domainname 2863 if (rdlength < 7) 2864 goto fail; 2865 rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 2866 rdb->srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 2867 rdb->srv.port.b[0] = ptr[4]; 2868 rdb->srv.port.b[1] = ptr[5]; 2869 ptr += 6; 2870 if (msg) 2871 { 2872 ptr = getDomainName(msg, ptr, end, &rdb->srv.target); 2873 } 2874 else 2875 { 2876 if (!AssignDomainNameWithLimit(&rdb->srv.target, (domainname *)ptr, end)) 2877 { 2878 goto fail; 2879 } 2880 ptr += DomainNameLength(&rdb->srv.target); 2881 } 2882 if (ptr != end) 2883 { 2884 debugf("SetRData: Malformed SRV RDATA name"); 2885 goto fail; 2886 } 2887 break; 2888 2889 case kDNSType_NAPTR: 2890 { 2891 int savelen, len; 2892 domainname name; 2893 const mDNSu8 *orig = ptr; 2894 2895 // Make sure the data is parseable and within the limits. 2896 // 2897 // Fixed length: Order, preference (4 bytes) 2898 // Variable length: flags, service, regexp, domainname 2899 2900 if (rdlength < 8) 2901 goto fail; 2902 // Order, preference. 2903 ptr += 4; 2904 // Parse flags, Service and Regexp 2905 // length in the first byte does not include the length byte itself 2906 len = *ptr + 1; 2907 ptr += len; 2908 if (ptr >= end) 2909 { 2910 LogInfo("SetRData: Malformed NAPTR flags"); 2911 goto fail; 2912 } 2913 2914 // Service 2915 len = *ptr + 1; 2916 ptr += len; 2917 if (ptr >= end) 2918 { 2919 LogInfo("SetRData: Malformed NAPTR service"); 2920 goto fail; 2921 } 2922 2923 // Regexp 2924 len = *ptr + 1; 2925 ptr += len; 2926 if (ptr >= end) 2927 { 2928 LogInfo("SetRData: Malformed NAPTR regexp"); 2929 goto fail; 2930 } 2931 2932 savelen = (int)(ptr - orig); 2933 2934 // RFC 2915 states that name compression is not allowed for this field. But RFC 3597 2935 // states that for NAPTR we should decompress. We make sure that we store the full 2936 // name rather than the compressed name 2937 if (msg) 2938 { 2939 ptr = getDomainName(msg, ptr, end, &name); 2940 } 2941 else 2942 { 2943 if (!AssignDomainNameWithLimit(&name, (domainname *)ptr, end)) 2944 { 2945 goto fail; 2946 } 2947 ptr += DomainNameLength(&name); 2948 } 2949 if (ptr != end) 2950 { 2951 LogInfo("SetRData: Malformed NAPTR RDATA name"); 2952 goto fail; 2953 } 2954 2955 rr->rdlength = savelen + DomainNameLength(&name); 2956 // The uncompressed size should not exceed the limits 2957 if (rr->rdlength > MaximumRDSize) 2958 { 2959 LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->rdlength %d, " 2960 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c); 2961 goto fail; 2962 } 2963 mDNSPlatformMemCopy(rdb->data, orig, savelen); 2964 AssignDomainName((domainname *)(rdb->data + savelen), &name); 2965 break; 2966 } 2967 case kDNSType_OPT: { 2968 const mDNSu8 * const dataend = &rr->rdata->u.data[rr->rdata->MaxRDLength]; 2969 rdataOPT *opt = rr->rdata->u.opt; 2970 rr->rdlength = 0; 2971 while ((ptr < end) && ((dataend - ((const mDNSu8 *)opt)) >= ((mDNSs32)sizeof(*opt)))) 2972 { 2973 const rdataOPT *const currentopt = opt; 2974 if (ptr + 4 > end) { LogInfo("SetRData: OPT RDATA ptr + 4 > end"); goto fail; } 2975 opt->opt = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 2976 opt->optlen = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 2977 ptr += 4; 2978 if (ptr + opt->optlen > end) { LogInfo("SetRData: ptr + opt->optlen > end"); goto fail; } 2979 switch (opt->opt) 2980 { 2981 case kDNSOpt_LLQ: 2982 if (opt->optlen == DNSOpt_LLQData_Space - 4) 2983 { 2984 opt->u.llq.vers = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 2985 opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 2986 opt->u.llq.err = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 2987 mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8); 2988 opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]); 2989 if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond) 2990 opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond; 2991 opt++; 2992 } 2993 break; 2994 case kDNSOpt_Lease: 2995 if (opt->optlen == DNSOpt_LeaseData_Space - 4) 2996 { 2997 opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); 2998 if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond) 2999 opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond; 3000 opt++; 3001 } 3002 break; 3003 case kDNSOpt_Owner: 3004 if (ValidOwnerLength(opt->optlen)) 3005 { 3006 opt->u.owner.vers = ptr[0]; 3007 opt->u.owner.seq = ptr[1]; 3008 mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6); // 6-byte MAC address 3009 mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6); // 6-byte MAC address 3010 opt->u.owner.password = zeroEthAddr; 3011 if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4) 3012 { 3013 mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6); // 6-byte MAC address 3014 // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above 3015 // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4 3016 if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4) 3017 mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4)); 3018 } 3019 opt++; 3020 } 3021 break; 3022 case kDNSOpt_Trace: 3023 if (opt->optlen == DNSOpt_TraceData_Space - 4) 3024 { 3025 opt->u.tracer.platf = ptr[0]; 3026 opt->u.tracer.mDNSv = (mDNSu32) ((mDNSu32)ptr[1] << 24 | (mDNSu32)ptr[2] << 16 | (mDNSu32)ptr[3] << 8 | ptr[4]); 3027 opt++; 3028 } 3029 else 3030 { 3031 opt->u.tracer.platf = 0xFF; 3032 opt->u.tracer.mDNSv = 0xFFFFFFFF; 3033 opt++; 3034 } 3035 break; 3036 } 3037 ptr += currentopt->optlen; 3038 } 3039 rr->rdlength = (mDNSu16)((mDNSu8*)opt - rr->rdata->u.data); 3040 if (ptr != end) { LogInfo("SetRData: Malformed OptRdata"); goto fail; } 3041 break; 3042 } 3043 3044 case kDNSType_NSEC: { 3045 domainname name; 3046 int len = rdlength; 3047 int bmaplen, dlen; 3048 const mDNSu8 *orig = ptr; 3049 const mDNSu8 *bmap; 3050 3051 if (msg) 3052 { 3053 ptr = getDomainName(msg, ptr, end, &name); 3054 } 3055 else 3056 { 3057 if (!AssignDomainNameWithLimit(&name, (domainname *)ptr, end)) 3058 { 3059 goto fail; 3060 } 3061 ptr += DomainNameLength(&name); 3062 } 3063 if (!ptr) 3064 { 3065 LogInfo("SetRData: Malformed NSEC nextname"); 3066 goto fail; 3067 } 3068 3069 dlen = DomainNameLength(&name); 3070 3071 // Multicast NSECs use name compression for this field unlike the unicast case which 3072 // does not use compression. And multicast case always succeeds in compression. So, 3073 // the rdlength includes only the compressed space in that case. So, can't 3074 // use the DomainNameLength of name to reduce the length here. 3075 len -= (ptr - orig); 3076 bmaplen = len; // Save the length of the bitmap 3077 bmap = ptr; 3078 ptr = SanityCheckBitMap(bmap, end, len); 3079 if (!ptr) 3080 goto fail; 3081 if (ptr != end) 3082 { 3083 LogInfo("SetRData: Malformed NSEC length not right"); 3084 goto fail; 3085 } 3086 3087 // Initialize the right length here. When we call SetNewRData below which in turn calls 3088 // GetRDLength and for NSEC case, it assumes that rdlength is intitialized 3089 rr->rdlength = DomainNameLength(&name) + bmaplen; 3090 3091 // Do we have space after the name expansion ? 3092 if (rr->rdlength > MaximumRDSize) 3093 { 3094 LogInfo("SetRData: Malformed NSEC rdlength %d, rr->rdlength %d, " 3095 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c); 3096 goto fail; 3097 } 3098 AssignDomainName((domainname *)rdb->data, &name); 3099 mDNSPlatformMemCopy(rdb->data + dlen, bmap, bmaplen); 3100 break; 3101 } 3102 case kDNSType_TKEY: 3103 case kDNSType_TSIG: 3104 { 3105 domainname name; 3106 int dlen, rlen; 3107 3108 // The name should not be compressed. But we take the conservative approach 3109 // and uncompress the name before we store it. 3110 if (msg) 3111 { 3112 ptr = getDomainName(msg, ptr, end, &name); 3113 } 3114 else 3115 { 3116 if (!AssignDomainNameWithLimit(&name, (domainname *)ptr, end)) 3117 { 3118 goto fail; 3119 } 3120 ptr += DomainNameLength(&name); 3121 } 3122 if (!ptr || ptr >= end) 3123 { 3124 LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->rrtype); 3125 goto fail; 3126 } 3127 dlen = DomainNameLength(&name); 3128 rlen = (int)(end - ptr); 3129 rr->rdlength = dlen + rlen; 3130 if (rr->rdlength > MaximumRDSize) 3131 { 3132 LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->rdlength %d, " 3133 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c); 3134 goto fail; 3135 } 3136 AssignDomainName((domainname *)rdb->data, &name); 3137 mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen); 3138 break; 3139 } 3140 default: 3141 debugf("SetRData: Warning! Reading resource type %d (%s) as opaque data", 3142 rr->rrtype, DNSTypeName(rr->rrtype)); 3143 // Note: Just because we don't understand the record type, that doesn't 3144 // mean we fail. The DNS protocol specifies rdlength, so we can 3145 // safely skip over unknown records and ignore them. 3146 // We also grab a binary copy of the rdata anyway, since the caller 3147 // might know how to interpret it even if we don't. 3148 rr->rdlength = rdlength; 3149 mDNSPlatformMemCopy(rdb->data, ptr, rdlength); 3150 break; 3151 } 3152 return mDNStrue; 3153 fail: 3154 return mDNSfalse; 3155 } 3156 3157 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, 3158 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr) 3159 { 3160 CacheRecord *const rr = &largecr->r; 3161 mDNSu16 pktrdlength; 3162 mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds; 3163 3164 if (largecr == &m->rec && m->rec.r.resrec.RecordType) 3165 LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r)); 3166 3167 rr->next = mDNSNULL; 3168 rr->resrec.name = &largecr->namestorage; 3169 3170 rr->NextInKAList = mDNSNULL; 3171 rr->TimeRcvd = m ? m->timenow : 0; 3172 rr->DelayDelivery = 0; 3173 rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord() 3174 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS) 3175 rr->LastCachedAnswerTime = 0; 3176 #endif 3177 rr->CRActiveQuestion = mDNSNULL; 3178 rr->UnansweredQueries = 0; 3179 rr->LastUnansweredTime= 0; 3180 rr->NextInCFList = mDNSNULL; 3181 3182 rr->resrec.InterfaceID = InterfaceID; 3183 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 3184 mdns_forget(&rr->resrec.dnsservice); 3185 #else 3186 rr->resrec.rDNSServer = mDNSNULL; 3187 #endif 3188 3189 ptr = getDomainName(msg, ptr, end, &largecr->namestorage); // Will bail out correctly if ptr is NULL 3190 if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); } 3191 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 3192 3193 if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); } 3194 3195 rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]); 3196 rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask); 3197 rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]); 3198 if (rr->resrec.rroriginalttl > maxttl && (mDNSs32)rr->resrec.rroriginalttl != -1) 3199 rr->resrec.rroriginalttl = maxttl; 3200 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for 3201 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly. 3202 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); 3203 3204 // If mDNS record has cache-flush bit set, we mark it unique 3205 // For uDNS records, all are implicitly deemed unique (a single DNS server is always authoritative for the entire RRSet) 3206 if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || !InterfaceID) 3207 RecordType |= kDNSRecordTypePacketUniqueMask; 3208 ptr += 10; 3209 if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } 3210 end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record 3211 3212 rr->resrec.rdata = (RData*)&rr->smallrdatastorage; 3213 rr->resrec.rdata->MaxRDLength = MaximumRDSize; 3214 3215 if (pktrdlength > MaximumRDSize) 3216 { 3217 LogInfo("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)", 3218 DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength); 3219 goto fail; 3220 } 3221 3222 if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c); 3223 3224 // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding 3225 // cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind 3226 // bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data. 3227 // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that 3228 // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ. 3229 if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136) 3230 rr->resrec.rdlength = 0; 3231 else if (!SetRData(msg, ptr, end, &rr->resrec, pktrdlength)) 3232 { 3233 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, 3234 "GetLargeResourceRecord: SetRData failed for " PRI_DM_NAME " (" PUB_S ")", 3235 DM_NAME_PARAM(rr->resrec.name), DNSTypeName(rr->resrec.rrtype)); 3236 goto fail; 3237 } 3238 3239 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us 3240 3241 // Success! Now fill in RecordType to show this record contains valid data 3242 rr->resrec.RecordType = RecordType; 3243 return(end); 3244 3245 fail: 3246 // If we were unable to parse the rdata in this record, we indicate that by 3247 // returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero 3248 rr->resrec.RecordType = kDNSRecordTypePacketNegative; 3249 rr->resrec.rdlength = 0; 3250 rr->resrec.rdestimate = 0; 3251 rr->resrec.rdatahash = 0; 3252 return(end); 3253 } 3254 3255 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end) 3256 { 3257 ptr = skipDomainName(msg, ptr, end); 3258 if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); } 3259 if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); } 3260 return(ptr+4); 3261 } 3262 3263 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, 3264 DNSQuestion *question) 3265 { 3266 mDNSPlatformMemZero(question, sizeof(*question)); 3267 question->InterfaceID = InterfaceID; 3268 if (!InterfaceID) question->TargetQID = onesID; // In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast 3269 ptr = getDomainName(msg, ptr, end, &question->qname); 3270 if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); } 3271 if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); } 3272 3273 question->qnamehash = DomainNameHashValue(&question->qname); 3274 question->qtype = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); // Get type 3275 question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); // and class 3276 return(ptr+4); 3277 } 3278 3279 mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end) 3280 { 3281 int i; 3282 const mDNSu8 *ptr = msg->data; 3283 for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end); 3284 return(ptr); 3285 } 3286 3287 mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end) 3288 { 3289 int i; 3290 const mDNSu8 *ptr = LocateAnswers(msg, end); 3291 for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end); 3292 return(ptr); 3293 } 3294 3295 mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end) 3296 { 3297 int i; 3298 const mDNSu8 *ptr = LocateAuthorities(msg, end); 3299 for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end); 3300 return (ptr); 3301 } 3302 3303 mDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize) 3304 { 3305 int i; 3306 const mDNSu8 *ptr = LocateAdditionals(msg, end); 3307 3308 // Locate the OPT record. 3309 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response." 3310 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section, 3311 // but not necessarily the *last* entry in the Additional Section. 3312 for (i = 0; ptr && i < msg->h.numAdditionals; i++) 3313 { 3314 if (ptr + DNSOpt_Header_Space + minsize <= end && // Make sure we have 11+minsize bytes of data 3315 ptr[0] == 0 && // Name must be root label 3316 ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT 3317 ptr[2] == (kDNSType_OPT & 0xFF) && 3318 ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)minsize) 3319 return(ptr); 3320 else 3321 ptr = skipResourceRecord(msg, ptr, end); 3322 } 3323 return(mDNSNULL); 3324 } 3325 3326 // On success, GetLLQOptData returns pointer to storage within shared "m->rec"; 3327 // it is caller's responsibilty to clear m->rec.r.resrec.RecordType after use 3328 // Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together 3329 // The code that currently calls this assumes there's only one, instead of iterating through the set 3330 mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end) 3331 { 3332 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space); 3333 if (ptr) 3334 { 3335 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 3336 if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]); 3337 } 3338 return(mDNSNULL); 3339 } 3340 3341 // Get the lease life of records in a dynamic update 3342 mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease) 3343 { 3344 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); 3345 if (ptr) 3346 { 3347 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 3348 if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT) 3349 { 3350 const rdataOPT *o; 3351 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 3352 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) 3353 if (o->opt == kDNSOpt_Lease) 3354 { 3355 *lease = o->u.updatelease; 3356 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 3357 return mDNStrue; 3358 } 3359 } 3360 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 3361 } 3362 return mDNSfalse; 3363 } 3364 3365 #define DNS_OP_Name(X) ( \ 3366 (X) == kDNSFlag0_OP_StdQuery ? "" : \ 3367 (X) == kDNSFlag0_OP_Iquery ? "Iquery " : \ 3368 (X) == kDNSFlag0_OP_Status ? "Status " : \ 3369 (X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \ 3370 (X) == kDNSFlag0_OP_Notify ? "Notify " : \ 3371 (X) == kDNSFlag0_OP_Update ? "Update " : \ 3372 (X) == kDNSFlag0_OP_DSO ? "DSO " : "?? " ) 3373 3374 #define DNS_RC_Name(X) ( \ 3375 (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \ 3376 (X) == kDNSFlag1_RC_FormErr ? "FormErr" : \ 3377 (X) == kDNSFlag1_RC_ServFail ? "ServFail" : \ 3378 (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \ 3379 (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \ 3380 (X) == kDNSFlag1_RC_Refused ? "Refused" : \ 3381 (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \ 3382 (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \ 3383 (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \ 3384 (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \ 3385 (X) == kDNSFlag1_RC_NotZone ? "NotZone" : \ 3386 (X) == kDNSFlag1_RC_DSOTypeNI ? "DSOTypeNI" : "??" ) 3387 3388 mDNSexport void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...) 3389 { 3390 va_list args; 3391 mDNSu32 buflen, n; 3392 char *const dst = *ptr; 3393 3394 buflen = (mDNSu32)(lim - dst); 3395 if (buflen > 0) 3396 { 3397 va_start(args, fmt); 3398 n = mDNS_vsnprintf(dst, buflen, fmt, args); 3399 va_end(args); 3400 *ptr = dst + n; 3401 } 3402 } 3403 3404 #define DNSTypeString(X) (((X) == kDNSType_A) ? "A" : DNSTypeName(X)) 3405 3406 #define ReadField16(PTR) ((mDNSu16)((((mDNSu16)((mDNSu8 *)(PTR))[0]) << 8) | ((mDNSu16)((mDNSu8 *)(PTR))[1]))) 3407 #define ReadField32(PTR) \ 3408 ((mDNSu32)( \ 3409 (((mDNSu32)((mDNSu8 *)(PTR))[0]) << 24) | \ 3410 (((mDNSu32)((mDNSu8 *)(PTR))[1]) << 16) | \ 3411 (((mDNSu32)((mDNSu8 *)(PTR))[2]) << 8) | \ 3412 ((mDNSu32)((mDNSu8 *)(PTR))[3]))) 3413 3414 mDNSlocal void DNSMessageDumpToLog(const DNSMessage *const msg, const mDNSu8 *const end) 3415 { 3416 domainname *name = mDNSNULL; 3417 const mDNSu8 *ptr = msg->data; 3418 domainname nameStorage[2]; 3419 3420 char questions[512]; 3421 questions[0] = '\0'; 3422 char *questions_dst = questions; 3423 const char *const questions_lim = &questions[512]; 3424 for (mDNSu32 i = 0; i < msg->h.numQuestions; i++) 3425 { 3426 mDNSu16 qtype, qclass; 3427 3428 name = &nameStorage[0]; 3429 ptr = getDomainName(msg, ptr, end, name); 3430 if (!ptr) goto exit; 3431 3432 if ((end - ptr) < 4) goto exit; 3433 qtype = ReadField16(&ptr[0]); 3434 qclass = ReadField16(&ptr[2]); 3435 ptr += 4; 3436 3437 mDNS_snprintf_add(&questions_dst, questions_lim, " %##s %s", name->c, DNSTypeString(qtype)); 3438 if (qclass != kDNSClass_IN) mDNS_snprintf_add(&questions_dst, questions_lim, "/%u", qclass); 3439 mDNS_snprintf_add(&questions_dst, questions_lim, "?"); 3440 } 3441 3442 char rrs[512]; 3443 rrs[0] = '\0'; 3444 char *rrs_dst = rrs; 3445 const char *const rrs_lim = &rrs[512]; 3446 const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals; 3447 for (mDNSu32 i = 0; i < rrcount; i++) 3448 { 3449 mDNSu16 rrtype, rrclass, rdlength; 3450 mDNSu32 ttl; 3451 int handled; 3452 const mDNSu8 *rdata; 3453 const domainname *const previousName = name; 3454 3455 name = &nameStorage[(name == &nameStorage[0]) ? 1 : 0]; 3456 ptr = getDomainName(msg, ptr, end, name); 3457 if (!ptr) goto exit; 3458 3459 if ((end - ptr) < 10) goto exit; 3460 rrtype = ReadField16(&ptr[0]); 3461 rrclass = ReadField16(&ptr[2]); 3462 ttl = ReadField32(&ptr[4]); 3463 rdlength = ReadField16(&ptr[8]); 3464 ptr += 10; 3465 3466 if ((end - ptr) < rdlength) goto exit; 3467 rdata = ptr; 3468 3469 if (i > 0) mDNS_snprintf_add(&rrs_dst, rrs_lim, ","); 3470 if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&rrs_dst, rrs_lim, " %##s", name); 3471 3472 mDNS_snprintf_add(&rrs_dst, rrs_lim, " %s", DNSTypeString(rrtype)); 3473 if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&rrs_dst, rrs_lim, "/%u", rrclass); 3474 mDNS_snprintf_add(&rrs_dst, rrs_lim, " "); 3475 3476 handled = mDNSfalse; 3477 switch (rrtype) 3478 { 3479 case kDNSType_A: 3480 if (rdlength == 4) 3481 { 3482 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.4a", rdata); 3483 handled = mDNStrue; 3484 } 3485 break; 3486 3487 case kDNSType_AAAA: 3488 if (rdlength == 16) 3489 { 3490 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.16a", rdata); 3491 handled = mDNStrue; 3492 } 3493 break; 3494 3495 case kDNSType_CNAME: 3496 ptr = getDomainName(msg, rdata, end, name); 3497 if (!ptr) goto exit; 3498 3499 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s", name); 3500 handled = mDNStrue; 3501 break; 3502 3503 case kDNSType_SOA: 3504 { 3505 mDNSu32 serial, refresh, retry, expire, minimum; 3506 domainname *const mname = &nameStorage[0]; 3507 domainname *const rname = &nameStorage[1]; 3508 name = mDNSNULL; 3509 3510 ptr = getDomainName(msg, rdata, end, mname); 3511 if (!ptr) goto exit; 3512 3513 ptr = getDomainName(msg, ptr, end, rname); 3514 if (!ptr) goto exit; 3515 3516 if ((end - ptr) < 20) goto exit; 3517 serial = ReadField32(&ptr[0]); 3518 refresh = ReadField32(&ptr[4]); 3519 retry = ReadField32(&ptr[8]); 3520 expire = ReadField32(&ptr[12]); 3521 minimum = ReadField32(&ptr[16]); 3522 3523 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial, 3524 (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum); 3525 3526 handled = mDNStrue; 3527 break; 3528 } 3529 3530 default: 3531 break; 3532 } 3533 if (!handled) mDNS_snprintf_add(&rrs_dst, rrs_lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata); 3534 mDNS_snprintf_add(&rrs_dst, rrs_lim, " (%lu)", (unsigned long)ttl); 3535 ptr = rdata + rdlength; 3536 } 3537 3538 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, 3539 "[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 ":" 3540 PRI_S " %u/%u/%u " PRI_S, 3541 mDNSVal16(msg->h.id), 3542 DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask), 3543 (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query", 3544 (unsigned long)(end - (const mDNSu8 *)msg), 3545 msg->h.flags.b[0], msg->h.flags.b[1], 3546 DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask), 3547 msg->h.flags.b[1] & kDNSFlag1_RC_Mask, 3548 (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "", 3549 (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "", 3550 (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "", 3551 (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "", 3552 (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "", 3553 (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "", 3554 questions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, rrs); 3555 3556 exit: 3557 return; 3558 } 3559 3560 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order 3561 mDNSexport void DumpPacket(mStatus status, mDNSBool sent, const char *transport, 3562 const mDNSAddr *srcaddr, mDNSIPPort srcport,const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, 3563 const mDNSu8 *const end, mDNSInterfaceID interfaceID) 3564 { 3565 const mDNSAddr zeroIPv4Addr = { mDNSAddrType_IPv4, {{{ 0 }}} }; 3566 char action[32]; 3567 const char* interfaceName = "interface"; 3568 3569 if (!status) mDNS_snprintf(action, sizeof(action), sent ? "Sent" : "Received"); 3570 else mDNS_snprintf(action, sizeof(action), "ERROR %d %sing", status, sent ? "Send" : "Receiv"); 3571 3572 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG) 3573 interfaceName = InterfaceNameForID(&mDNSStorage, interfaceID); 3574 #endif 3575 3576 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, 3577 "[Q%u] " PUB_S " " PUB_S " DNS Message %lu bytes from " PRI_IP_ADDR ":%d to " PRI_IP_ADDR ":%d via " PUB_S " (%p)", 3578 mDNSVal16(msg->h.id), action, transport, (unsigned long)(end - (const mDNSu8 *)msg), 3579 srcaddr ? srcaddr : &zeroIPv4Addr, mDNSVal16(srcport), dstaddr ? dstaddr : &zeroIPv4Addr, mDNSVal16(dstport), 3580 interfaceName, interfaceID); 3581 DNSMessageDumpToLog(msg, end); 3582 } 3583 3584 // *************************************************************************** 3585 #if COMPILER_LIKES_PRAGMA_MARK 3586 #pragma mark - 3587 #pragma mark - Packet Sending Functions 3588 #endif 3589 3590 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.) 3591 struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ }; 3592 // Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.) 3593 struct UDPSocket_struct { mDNSIPPort port; /* ... */ }; 3594 3595 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which 3596 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible. 3597 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, 3598 mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst, 3599 mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass) 3600 { 3601 mStatus status = mStatus_NoError; 3602 const mDNSu16 numAdditionals = msg->h.numAdditionals; 3603 3604 #if APPLE_OSX_mDNSResponder 3605 // maintain outbound packet statistics 3606 if (mDNSOpaque16IsZero(msg->h.id)) 3607 m->MulticastPacketsSent++; 3608 else 3609 m->UnicastPacketsSent++; 3610 #endif // APPLE_OSX_mDNSResponder 3611 3612 // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code 3613 if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData) 3614 { 3615 LogMsg("mDNSSendDNSMessage: invalid message %p %p %d", msg->data, end, end - msg->data); 3616 return mStatus_BadParamErr; 3617 } 3618 3619 // Put all the integer values in IETF byte-order (MSB first, LSB second) 3620 SwapDNSHeaderBytes(msg); 3621 3622 if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0); // DNSDigest_SignMessage operates on message in network byte order 3623 if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; } 3624 else 3625 { 3626 // Send the packet on the wire 3627 if (!tcpSrc) 3628 status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, udpSrc, dst, dstport, useBackgroundTrafficClass); 3629 else 3630 { 3631 mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg); 3632 mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) }; 3633 char *buf; 3634 long nsent; 3635 3636 // Try to send them in one packet if we can allocate enough memory 3637 buf = (char *) mDNSPlatformMemAllocate(msglen + 2); 3638 if (buf) 3639 { 3640 buf[0] = lenbuf[0]; 3641 buf[1] = lenbuf[1]; 3642 mDNSPlatformMemCopy(buf+2, msg, msglen); 3643 nsent = mDNSPlatformWriteTCP(tcpSrc, buf, msglen+2); 3644 if (nsent != (msglen + 2)) 3645 { 3646 LogMsg("mDNSSendDNSMessage: write message failed %d/%d", nsent, msglen); 3647 status = mStatus_ConnFailed; 3648 } 3649 mDNSPlatformMemFree(buf); 3650 } 3651 else 3652 { 3653 nsent = mDNSPlatformWriteTCP(tcpSrc, (char*)lenbuf, 2); 3654 if (nsent != 2) 3655 { 3656 LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); 3657 status = mStatus_ConnFailed; 3658 } 3659 else 3660 { 3661 nsent = mDNSPlatformWriteTCP(tcpSrc, (char *)msg, msglen); 3662 if (nsent != msglen) 3663 { 3664 LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); 3665 status = mStatus_ConnFailed; 3666 } 3667 } 3668 } 3669 } 3670 } 3671 3672 // Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage) 3673 SwapDNSHeaderBytes(msg); 3674 3675 // Dump the packet with the HINFO and TSIG 3676 if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id)) 3677 { 3678 char *transport = "UDP"; 3679 mDNSIPPort portNumber = udpSrc ? udpSrc->port : MulticastDNSPort; 3680 if (tcpSrc) 3681 { 3682 if (tcpSrc->flags) 3683 transport = "TLS"; 3684 else 3685 transport = "TCP"; 3686 portNumber = tcpSrc->port; 3687 } 3688 DumpPacket(status, mDNStrue, transport, mDNSNULL, portNumber, dst, dstport, msg, end, InterfaceID); 3689 } 3690 3691 // put the number of additionals back the way it was 3692 msg->h.numAdditionals = numAdditionals; 3693 3694 return(status); 3695 } 3696 3697 // *************************************************************************** 3698 #if COMPILER_LIKES_PRAGMA_MARK 3699 #pragma mark - 3700 #pragma mark - RR List Management & Task Management 3701 #endif 3702 3703 mDNSexport void mDNS_Lock_(mDNS *const m, const char * const functionname) 3704 { 3705 // MUST grab the platform lock FIRST! 3706 mDNSPlatformLock(m); 3707 3708 // Normally, mDNS_reentrancy is zero and so is mDNS_busy 3709 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too 3710 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one 3711 // If mDNS_busy != mDNS_reentrancy that's a bad sign 3712 if (m->mDNS_busy != m->mDNS_reentrancy) 3713 LogFatalError("%s: mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy); 3714 3715 // If this is an initial entry into the mDNSCore code, set m->timenow 3716 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set 3717 if (m->mDNS_busy == 0) 3718 { 3719 if (m->timenow) 3720 LogMsg("%s: mDNS_Lock: m->timenow already set (%ld/%ld)", functionname, m->timenow, mDNS_TimeNow_NoLock(m)); 3721 m->timenow = mDNS_TimeNow_NoLock(m); 3722 if (m->timenow == 0) m->timenow = 1; 3723 } 3724 else if (m->timenow == 0) 3725 { 3726 LogMsg("%s: mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", functionname, m->mDNS_busy); 3727 m->timenow = mDNS_TimeNow_NoLock(m); 3728 if (m->timenow == 0) m->timenow = 1; 3729 } 3730 3731 if (m->timenow_last - m->timenow > 0) 3732 { 3733 m->timenow_adjust += m->timenow_last - m->timenow; 3734 LogMsg("%s: mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", functionname, m->timenow_last - m->timenow, m->timenow_adjust); 3735 m->timenow = m->timenow_last; 3736 } 3737 m->timenow_last = m->timenow; 3738 3739 // Increment mDNS_busy so we'll recognise re-entrant calls 3740 m->mDNS_busy++; 3741 } 3742 3743 mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m) 3744 { 3745 AuthRecord *rr; 3746 for (rr = m->NewLocalRecords; rr; rr = rr->next) 3747 if (LocalRecordReady(rr)) return rr; 3748 return mDNSNULL; 3749 } 3750 3751 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) 3752 { 3753 mDNSs32 e = m->timenow + FutureTime; 3754 if (m->mDNSPlatformStatus != mStatus_NoError) return(e); 3755 if (m->NewQuestions) 3756 { 3757 if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering; 3758 else return(m->timenow); 3759 } 3760 if (m->NewLocalOnlyQuestions) return(m->timenow); 3761 if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow); 3762 if (m->NewLocalOnlyRecords) return(m->timenow); 3763 if (m->SPSProxyListChanged) return(m->timenow); 3764 if (m->LocalRemoveEvents) return(m->timenow); 3765 3766 #ifndef UNICAST_DISABLED 3767 if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent; 3768 if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp; 3769 if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate; 3770 #endif 3771 3772 if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck; 3773 if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS; 3774 if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA; 3775 3776 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND) 3777 if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime; 3778 #endif 3779 3780 // NextScheduledSPRetry only valid when DelaySleep not set 3781 if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry; 3782 if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep; 3783 3784 if (m->SuppressSending) 3785 { 3786 if (e - m->SuppressSending > 0) e = m->SuppressSending; 3787 } 3788 else 3789 { 3790 if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery; 3791 if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe; 3792 if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; 3793 } 3794 if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime; 3795 3796 if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime; 3797 3798 return(e); 3799 } 3800 3801 #define LogTSE TSE++,LogMsg 3802 3803 mDNSexport void ShowTaskSchedulingError(mDNS *const m) 3804 { 3805 int TSE = 0; 3806 AuthRecord *rr; 3807 mDNS_Lock(m); 3808 3809 LogMsg("Task Scheduling Error: *** Continuously busy for more than a second"); 3810 3811 // Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above 3812 3813 if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0)) 3814 LogTSE("Task Scheduling Error: NewQuestion %##s (%s)", 3815 m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype)); 3816 3817 if (m->NewLocalOnlyQuestions) 3818 LogTSE("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)", 3819 m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype)); 3820 3821 if (m->NewLocalRecords) 3822 { 3823 rr = AnyLocalRecordReady(m); 3824 if (rr) LogTSE("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr)); 3825 } 3826 3827 if (m->NewLocalOnlyRecords) LogTSE("Task Scheduling Error: NewLocalOnlyRecords"); 3828 3829 if (m->SPSProxyListChanged) LogTSE("Task Scheduling Error: SPSProxyListChanged"); 3830 3831 if (m->LocalRemoveEvents) LogTSE("Task Scheduling Error: LocalRemoveEvents"); 3832 3833 #ifndef UNICAST_DISABLED 3834 if (m->timenow - m->NextuDNSEvent >= 0) 3835 LogTSE("Task Scheduling Error: m->NextuDNSEvent %d", m->timenow - m->NextuDNSEvent); 3836 if (m->timenow - m->NextScheduledNATOp >= 0) 3837 LogTSE("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp); 3838 if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) 3839 LogTSE("Task Scheduling Error: m->NextSRVUpdate %d", m->timenow - m->NextSRVUpdate); 3840 #endif 3841 3842 if (m->timenow - m->NextCacheCheck >= 0) 3843 LogTSE("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck); 3844 if (m->timenow - m->NextScheduledSPS >= 0) 3845 LogTSE("Task Scheduling Error: m->NextScheduledSPS %d", m->timenow - m->NextScheduledSPS); 3846 if (m->timenow - m->NextScheduledKA >= 0) 3847 LogTSE("Task Scheduling Error: m->NextScheduledKA %d", m->timenow - m->NextScheduledKA); 3848 if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0) 3849 LogTSE("Task Scheduling Error: m->NextScheduledSPRetry %d", m->timenow - m->NextScheduledSPRetry); 3850 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) 3851 LogTSE("Task Scheduling Error: m->DelaySleep %d", m->timenow - m->DelaySleep); 3852 3853 if (m->SuppressSending && m->timenow - m->SuppressSending >= 0) 3854 LogTSE("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending); 3855 if (m->timenow - m->NextScheduledQuery >= 0) 3856 LogTSE("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery); 3857 if (m->timenow - m->NextScheduledProbe >= 0) 3858 LogTSE("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe); 3859 if (m->timenow - m->NextScheduledResponse >= 0) 3860 LogTSE("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse); 3861 if (m->timenow - m->NextScheduledStopTime >= 0) 3862 LogTSE("Task Scheduling Error: m->NextScheduledStopTime %d", m->timenow - m->NextScheduledStopTime); 3863 3864 if (m->timenow - m->NextScheduledEvent >= 0) 3865 LogTSE("Task Scheduling Error: m->NextScheduledEvent %d", m->timenow - m->NextScheduledEvent); 3866 3867 if (m->NetworkChanged && m->timenow - m->NetworkChanged >= 0) 3868 LogTSE("Task Scheduling Error: NetworkChanged %d", m->timenow - m->NetworkChanged); 3869 3870 if (!TSE) LogMsg("Task Scheduling Error: *** No likely causes identified"); 3871 else LogMsg("Task Scheduling Error: *** %d potential cause%s identified (significant only if the same cause consistently appears)", TSE, TSE > 1 ? "s" : ""); 3872 3873 mDNS_Unlock(m); 3874 } 3875 3876 mDNSexport void mDNS_Unlock_(mDNS *const m, const char *const functionname) 3877 { 3878 // Decrement mDNS_busy 3879 m->mDNS_busy--; 3880 3881 // Check for locking failures 3882 if (m->mDNS_busy != m->mDNS_reentrancy) 3883 LogFatalError("%s: mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy); 3884 3885 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow 3886 if (m->mDNS_busy == 0) 3887 { 3888 m->NextScheduledEvent = GetNextScheduledEvent(m); 3889 if (m->timenow == 0) LogMsg("%s: mDNS_Unlock: ERROR! m->timenow aready zero", functionname); 3890 m->timenow = 0; 3891 } 3892 3893 // MUST release the platform lock LAST! 3894 mDNSPlatformUnlock(m); 3895 } 3896 3897 // *************************************************************************** 3898 #if COMPILER_LIKES_PRAGMA_MARK 3899 #pragma mark - 3900 #pragma mark - Specialized mDNS version of vsnprintf 3901 #endif 3902 3903 static const struct mDNSprintf_format 3904 { 3905 unsigned leftJustify : 1; 3906 unsigned forceSign : 1; 3907 unsigned zeroPad : 1; 3908 unsigned havePrecision : 1; 3909 unsigned hSize : 1; 3910 unsigned lSize : 1; 3911 char altForm; 3912 char sign; // +, - or space 3913 unsigned int fieldWidth; 3914 unsigned int precision; 3915 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3916 3917 #define kHexDigitsLowercase "0123456789abcdef" 3918 #define kHexDigitsUppercase "0123456789ABCDEF"; 3919 3920 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) 3921 { 3922 mDNSu32 nwritten = 0; 3923 int c; 3924 if (buflen == 0) return(0); 3925 buflen--; // Pre-reserve one space in the buffer for the terminating null 3926 if (buflen == 0) goto exit; 3927 3928 for (c = *fmt; c != 0; c = *++fmt) 3929 { 3930 unsigned long n; 3931 int hexdump = mDNSfalse; 3932 if (c != '%') 3933 { 3934 *sbuffer++ = (char)c; 3935 if (++nwritten >= buflen) goto exit; 3936 } 3937 else 3938 { 3939 unsigned int i=0, j; 3940 // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for 3941 // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc. 3942 // The size needs to be enough for a 256-byte domain name plus some error text. 3943 #define mDNS_VACB_Size 300 3944 char mDNS_VACB[mDNS_VACB_Size]; 3945 #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size]) 3946 #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s)) 3947 char *s = mDNS_VACB_Lim, *digits; 3948 struct mDNSprintf_format F = mDNSprintf_format_default; 3949 3950 while (1) // decode flags 3951 { 3952 c = *++fmt; 3953 if (c == '-') F.leftJustify = 1; 3954 else if (c == '+') F.forceSign = 1; 3955 else if (c == ' ') F.sign = ' '; 3956 else if (c == '#') F.altForm++; 3957 else if (c == '0') F.zeroPad = 1; 3958 else break; 3959 } 3960 3961 if (c == '*') // decode field width 3962 { 3963 int f = va_arg(arg, int); 3964 if (f < 0) { f = -f; F.leftJustify = 1; } 3965 F.fieldWidth = (unsigned int)f; 3966 c = *++fmt; 3967 } 3968 else 3969 { 3970 for (; c >= '0' && c <= '9'; c = *++fmt) 3971 F.fieldWidth = (10 * F.fieldWidth) + (c - '0'); 3972 } 3973 3974 if (c == '.') // decode precision 3975 { 3976 if ((c = *++fmt) == '*') 3977 { F.precision = va_arg(arg, unsigned int); c = *++fmt; } 3978 else for (; c >= '0' && c <= '9'; c = *++fmt) 3979 F.precision = (10 * F.precision) + (c - '0'); 3980 F.havePrecision = 1; 3981 } 3982 3983 if (F.leftJustify) F.zeroPad = 0; 3984 3985 conv: 3986 switch (c) // perform appropriate conversion 3987 { 3988 case 'h': F.hSize = 1; c = *++fmt; goto conv; 3989 case 'l': // fall through 3990 case 'L': F.lSize = 1; c = *++fmt; goto conv; 3991 case 'd': 3992 case 'i': if (F.lSize) n = (unsigned long)va_arg(arg, long); 3993 else n = (unsigned long)va_arg(arg, int); 3994 if (F.hSize) n = (short) n; 3995 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; } 3996 else if (F.forceSign) F.sign = '+'; 3997 goto decimal; 3998 case 'u': if (F.lSize) n = va_arg(arg, unsigned long); 3999 else n = va_arg(arg, unsigned int); 4000 if (F.hSize) n = (unsigned short) n; 4001 F.sign = 0; 4002 goto decimal; 4003 decimal: if (!F.havePrecision) 4004 { 4005 if (F.zeroPad) 4006 { 4007 F.precision = F.fieldWidth; 4008 if (F.sign) --F.precision; 4009 } 4010 if (F.precision < 1) F.precision = 1; 4011 } 4012 if (F.precision > mDNS_VACB_Size - 1) 4013 F.precision = mDNS_VACB_Size - 1; 4014 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0'); 4015 for (; i < F.precision; i++) *--s = '0'; 4016 if (F.sign) { *--s = F.sign; i++; } 4017 break; 4018 4019 case 'o': if (F.lSize) n = va_arg(arg, unsigned long); 4020 else n = va_arg(arg, unsigned int); 4021 if (F.hSize) n = (unsigned short) n; 4022 if (!F.havePrecision) 4023 { 4024 if (F.zeroPad) F.precision = F.fieldWidth; 4025 if (F.precision < 1) F.precision = 1; 4026 } 4027 if (F.precision > mDNS_VACB_Size - 1) 4028 F.precision = mDNS_VACB_Size - 1; 4029 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0'); 4030 if (F.altForm && i && *s != '0') { *--s = '0'; i++; } 4031 for (; i < F.precision; i++) *--s = '0'; 4032 break; 4033 4034 case 'a': { 4035 unsigned char *a = va_arg(arg, unsigned char *); 4036 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } 4037 else 4038 { 4039 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end 4040 if (F.altForm) 4041 { 4042 mDNSAddr *ip = (mDNSAddr*)a; 4043 switch (ip->type) 4044 { 4045 case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break; 4046 case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break; 4047 default: F.precision = 0; break; 4048 } 4049 } 4050 if (F.altForm && !F.precision) 4051 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»"); 4052 else switch (F.precision) 4053 { 4054 case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d", 4055 a[0], a[1], a[2], a[3]); break; 4056 case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", 4057 a[0], a[1], a[2], a[3], a[4], a[5]); break; 4058 case 16: { 4059 // Print IPv6 addresses according to RFC 5952, A Recommendation for IPv6 Address Text 4060 // Representation. See <https://tools.ietf.org/html/rfc5952>. 4061 4062 int idx, runLen = 0, runStart = 0, maxRunLen = 0, maxRunStart = 0, maxRunEnd; 4063 4064 // Find the leftmost longest run of consecutive zero hextets. 4065 for (idx = 0; idx < 8; ++idx) 4066 { 4067 const unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1]; 4068 if (hextet == 0) 4069 { 4070 if (runLen++ == 0) runStart = idx; 4071 if (runLen > maxRunLen) 4072 { 4073 maxRunStart = runStart; 4074 maxRunLen = runLen; 4075 } 4076 } 4077 else 4078 { 4079 // If the number of remaining hextets is less than or equal to the length of the longest 4080 // run so far, then we've found the leftmost longest run. 4081 if ((8 - (idx + 1)) <= maxRunLen) break; 4082 runLen = 0; 4083 } 4084 } 4085 4086 // Compress the leftmost longest run of two or more consecutive zero hextets as "::". 4087 // For each reminaing hextet, suppress zeros leading up to the least-significant nibble, which 4088 // is always written, even if it's zero. Because of this requirement, it's easier to write the 4089 // IPv6 address in reverse. Also, write a colon separator before each hextet except for the 4090 // first one. 4091 s = mDNS_VACB_Lim; 4092 maxRunEnd = (maxRunLen >= 2) ? (maxRunStart + maxRunLen - 1) : -1; 4093 for (idx = 7; idx >= 0; --idx) 4094 { 4095 if (idx == maxRunEnd) 4096 { 4097 if (idx == 7) *--s = ':'; 4098 idx = maxRunStart; 4099 *--s = ':'; 4100 } 4101 else 4102 { 4103 unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1]; 4104 do { 4105 *--s = kHexDigitsLowercase[hextet % 16]; 4106 hextet /= 16; 4107 } while (hextet); 4108 if (idx > 0) *--s = ':'; 4109 } 4110 } 4111 i = (unsigned int)(mDNS_VACB_Lim - s); 4112 } 4113 break; 4114 4115 default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify" 4116 " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break; 4117 } 4118 } 4119 } 4120 break; 4121 4122 case 'p': F.havePrecision = F.lSize = 1; 4123 F.precision = sizeof(void*) * 2; // 8 characters on 32-bit; 16 characters on 64-bit 4124 /* FALLTHROUGH */ 4125 case 'X': digits = kHexDigitsUppercase; 4126 goto hexadecimal; 4127 case 'x': digits = kHexDigitsLowercase; 4128 hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long); 4129 else n = va_arg(arg, unsigned int); 4130 if (F.hSize) n = (unsigned short) n; 4131 if (!F.havePrecision) 4132 { 4133 if (F.zeroPad) 4134 { 4135 F.precision = F.fieldWidth; 4136 if (F.altForm) F.precision -= 2; 4137 } 4138 if (F.precision < 1) F.precision = 1; 4139 } 4140 if (F.precision > mDNS_VACB_Size - 1) 4141 F.precision = mDNS_VACB_Size - 1; 4142 for (i = 0; n; n /= 16, i++) *--s = digits[n % 16]; 4143 for (; i < F.precision; i++) *--s = '0'; 4144 if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; } 4145 break; 4146 4147 case 'c': *--s = (char)va_arg(arg, int); i = 1; break; 4148 4149 case 's': s = va_arg(arg, char *); 4150 if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } 4151 else switch (F.altForm) 4152 { 4153 case 0: i=0; 4154 if (!F.havePrecision) // C string 4155 while (s[i]) i++; 4156 else 4157 { 4158 while ((i < F.precision) && s[i]) i++; 4159 // Make sure we don't truncate in the middle of a UTF-8 character 4160 // If last character we got was any kind of UTF-8 multi-byte character, 4161 // then see if we have to back up. 4162 // This is not as easy as the similar checks below, because 4163 // here we can't assume it's safe to examine the *next* byte, so we 4164 // have to confine ourselves to working only backwards in the string. 4165 j = i; // Record where we got to 4166 // Now, back up until we find first non-continuation-char 4167 while (i>0 && (s[i-1] & 0xC0) == 0x80) i--; 4168 // Now s[i-1] is the first non-continuation-char 4169 // and (j-i) is the number of continuation-chars we found 4170 if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char 4171 { 4172 i--; // Tentatively eliminate this start-char as well 4173 // Now (j-i) is the number of characters we're considering eliminating. 4174 // To be legal UTF-8, the start-char must contain (j-i) one-bits, 4175 // followed by a zero bit. If we shift it right by (7-(j-i)) bits 4176 // (with sign extension) then the result has to be 0xFE. 4177 // If this is right, then we reinstate the tentatively eliminated bytes. 4178 if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j; 4179 } 4180 } 4181 break; 4182 case 1: i = (unsigned char) *s++; break; // Pascal string 4183 case 2: { // DNS label-sequence name 4184 unsigned char *a = (unsigned char *)s; 4185 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end 4186 if (*a == 0) *s++ = '.'; // Special case for root DNS name 4187 while (*a) 4188 { 4189 char buf[63*4+1]; 4190 if (*a > 63) 4191 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; } 4192 if (s + *a >= &mDNS_VACB[254]) 4193 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; } 4194 // Need to use ConvertDomainLabelToCString to do proper escaping here, 4195 // so it's clear what's a literal dot and what's a label separator 4196 ConvertDomainLabelToCString((domainlabel*)a, buf); 4197 s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf); 4198 a += 1 + *a; 4199 } 4200 i = (mDNSu32)(s - mDNS_VACB); 4201 s = mDNS_VACB; // Reset s back to the start of the buffer 4202 break; 4203 } 4204 } 4205 // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below) 4206 if (F.havePrecision && i > F.precision) 4207 { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} 4208 break; 4209 4210 case 'H': { 4211 s = va_arg(arg, char *); 4212 hexdump = mDNStrue; 4213 } 4214 break; 4215 4216 case 'n': s = va_arg(arg, char *); 4217 if (F.hSize) *(short *) s = (short)nwritten; 4218 else if (F.lSize) *(long *) s = (long)nwritten; 4219 else *(int *) s = (int)nwritten; 4220 continue; 4221 4222 default: s = mDNS_VACB; 4223 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c); 4224 break; 4225 4226 case '%': *sbuffer++ = (char)c; 4227 if (++nwritten >= buflen) goto exit; 4228 break; 4229 } 4230 4231 if (i < F.fieldWidth && !F.leftJustify) // Pad on the left 4232 do { 4233 *sbuffer++ = ' '; 4234 if (++nwritten >= buflen) goto exit; 4235 } while (i < --F.fieldWidth); 4236 4237 if (hexdump) 4238 { 4239 char *dst = sbuffer; 4240 const char *const lim = &sbuffer[buflen - nwritten]; 4241 if (F.havePrecision) 4242 { 4243 for (i = 0; (i < F.precision) && (dst < lim); i++) 4244 { 4245 const unsigned int b = (unsigned int) *s++; 4246 if (i > 0) *dst++ = ' '; 4247 if (dst < lim) *dst++ = kHexDigitsLowercase[(b >> 4) & 0xF]; 4248 if (dst < lim) *dst++ = kHexDigitsLowercase[ b & 0xF]; 4249 } 4250 } 4251 i = (unsigned int)(dst - sbuffer); 4252 sbuffer = dst; 4253 } 4254 else 4255 { 4256 // Make sure we don't truncate in the middle of a UTF-8 character. 4257 // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the 4258 // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half, 4259 // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly 4260 // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). 4261 if (i > buflen - nwritten) 4262 { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} 4263 for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result 4264 } 4265 nwritten += i; 4266 if (nwritten >= buflen) goto exit; 4267 4268 for (; i < F.fieldWidth; i++) // Pad on the right 4269 { 4270 *sbuffer++ = ' '; 4271 if (++nwritten >= buflen) goto exit; 4272 } 4273 } 4274 } 4275 exit: 4276 *sbuffer++ = 0; 4277 return(nwritten); 4278 } 4279 4280 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) 4281 { 4282 mDNSu32 length; 4283 4284 va_list ptr; 4285 va_start(ptr,fmt); 4286 length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr); 4287 va_end(ptr); 4288 4289 return(length); 4290 } 4291 4292 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) 4293 mDNSexport mDNSu32 mDNS_GetNextResolverGroupID(void) 4294 { 4295 static mDNSu32 lastID = 0; 4296 if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero. 4297 return(lastID); 4298 } 4299 #endif 4300 4301 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa") 4302 4303 mDNSexport mDNSBool GetReverseIPv6Addr(const domainname *name, mDNSu8 outIPv6[16]) 4304 { 4305 const mDNSu8 * ptr; 4306 int i; 4307 mDNSu8 ipv6[16]; 4308 4309 // 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 4310 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order. 4311 // See <https://tools.ietf.org/html/rfc3596#section-2.5>. 4312 4313 ptr = name->c; 4314 for (i = 0; i < 32; i++) 4315 { 4316 unsigned int c, nibble; 4317 const int j = 15 - (i / 2); 4318 if (*ptr++ != 1) return (mDNSfalse); // If this label's length is not 1, then fail. 4319 c = *ptr++; // Get label byte. 4320 if ( (c >= '0') && (c <= '9')) nibble = c - '0'; // If it's a hex digit, get its numeric value. 4321 else if ((c >= 'a') && (c <= 'f')) nibble = (c - 'a') + 10; 4322 else if ((c >= 'A') && (c <= 'F')) nibble = (c - 'A') + 10; 4323 else return (mDNSfalse); // Otherwise, fail. 4324 if ((i % 2) == 0) 4325 { 4326 ipv6[j] = (mDNSu8)nibble; 4327 } 4328 else 4329 { 4330 ipv6[j] |= (mDNSu8)(nibble << 4); 4331 } 4332 } 4333 4334 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail. 4335 4336 if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse); 4337 if (outIPv6) mDNSPlatformMemCopy(outIPv6, ipv6, 16); 4338 return (mDNStrue); 4339 } 4340 #endif // !STANDALONE 4341