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