xref: /illumos-gate/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c (revision c65ebfc7045424bd04a6c7719a27b0ad3399ad54)
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2002-2015 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:  offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
2774             if (!nextbyte) nextbyte = ptr;              // Record where we got to before we started following pointers
2775             ptr = (mDNSu8 *)msg + offset;
2776             if (ptr < (mDNSu8*)msg || ptr >= end)
2777             { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
2778             if (*ptr & 0xC0)
2779             { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
2780             break;
2781         }
2782     }
2783 
2784     if (nextbyte) return(nextbyte);
2785     else return(ptr);
2786 }
2787 
2788 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
2789 {
2790     mDNSu16 pktrdlength;
2791 
2792     ptr = skipDomainName(msg, ptr, end);
2793     if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
2794 
2795     if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
2796     pktrdlength = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
2797     ptr += 10;
2798     if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
2799 
2800     return(ptr + pktrdlength);
2801 }
2802 
2803 // Sanity check whether the NSEC/NSEC3 bitmap is good
2804 mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int len)
2805 {
2806     int win, wlen;
2807 
2808     while (bmap < end)
2809     {
2810         if (len < 3)
2811         {
2812             LogInfo("SanityCheckBitMap: invalid length %d", len);
2813             return mDNSNULL;
2814         }
2815 
2816         win = *bmap++;
2817         wlen = *bmap++;
2818         len -= 2;
2819         if (len < wlen || wlen < 1 || wlen > 32)
2820         {
2821             LogInfo("SanityCheckBitMap: invalid window length %d", wlen);
2822             return mDNSNULL;
2823         }
2824         if (win < 0 || win >= 256)
2825         {
2826             LogInfo("SanityCheckBitMap: invalid window %d", win);
2827             return mDNSNULL;
2828         }
2829 
2830         bmap += wlen;
2831         len -= wlen;
2832     }
2833     return (mDNSu8 *)bmap;
2834 }
2835 
2836 // This function is called with "msg" when we receive a DNS message and needs to parse a single resource record
2837 // pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded
2838 // (domainnames are expanded to 255 bytes) when stored in memory.
2839 //
2840 // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
2841 // The caller can do this only if the names in the resource records are not compressed and validity of the
2842 // resource record has already been done before. DNSSEC currently uses it this way.
2843 mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end,
2844     LargeCacheRecord *const largecr, mDNSu16 rdlength)
2845 {
2846     CacheRecord *const rr = &largecr->r;
2847     RDataBody2 *const rdb = (RDataBody2 *)rr->smallrdatastorage.data;
2848 
2849     switch (rr->resrec.rrtype)
2850     {
2851     case kDNSType_A:
2852         if (rdlength != sizeof(mDNSv4Addr))
2853             goto fail;
2854         rdb->ipv4.b[0] = ptr[0];
2855         rdb->ipv4.b[1] = ptr[1];
2856         rdb->ipv4.b[2] = ptr[2];
2857         rdb->ipv4.b[3] = ptr[3];
2858         break;
2859 
2860     case kDNSType_NS:
2861     case kDNSType_MD:
2862     case kDNSType_MF:
2863     case kDNSType_CNAME:
2864     case kDNSType_MB:
2865     case kDNSType_MG:
2866     case kDNSType_MR:
2867     case kDNSType_PTR:
2868     case kDNSType_NSAP_PTR:
2869     case kDNSType_DNAME:
2870         if (msg)
2871         {
2872             ptr = getDomainName(msg, ptr, end, &rdb->name);
2873         }
2874         else
2875         {
2876             AssignDomainName(&rdb->name, (domainname *)ptr);
2877             ptr += DomainNameLength(&rdb->name);
2878         }
2879         if (ptr != end)
2880         {
2881             debugf("SetRData: Malformed CNAME/PTR RDATA name");
2882             goto fail;
2883         }
2884         break;
2885 
2886     case kDNSType_SOA:
2887         if (msg)
2888         {
2889             ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
2890         }
2891         else
2892         {
2893             AssignDomainName(&rdb->soa.mname, (domainname *)ptr);
2894             ptr += DomainNameLength(&rdb->soa.mname);
2895         }
2896         if (!ptr)
2897         {
2898             debugf("SetRData: Malformed SOA RDATA mname");
2899             goto fail;
2900         }
2901         if (msg)
2902         {
2903             ptr = getDomainName(msg, ptr, end, &rdb->soa.rname);
2904         }
2905         else
2906         {
2907             AssignDomainName(&rdb->soa.rname, (domainname *)ptr);
2908             ptr += DomainNameLength(&rdb->soa.rname);
2909         }
2910         if (!ptr)
2911         {
2912             debugf("SetRData: Malformed SOA RDATA rname");
2913             goto fail;
2914         }
2915         if (ptr + 0x14 != end)
2916         {
2917             debugf("SetRData: Malformed SOA RDATA");
2918             goto fail;
2919         }
2920         rdb->soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
2921         rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
2922         rdb->soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
2923         rdb->soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
2924         rdb->soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
2925         break;
2926 
2927     case kDNSType_NULL:
2928     case kDNSType_HINFO:
2929     case kDNSType_TXT:
2930     case kDNSType_X25:
2931     case kDNSType_ISDN:
2932     case kDNSType_LOC:
2933     case kDNSType_DHCID:
2934         rr->resrec.rdlength = rdlength;
2935         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
2936         break;
2937 
2938     case kDNSType_MX:
2939     case kDNSType_AFSDB:
2940     case kDNSType_RT:
2941     case kDNSType_KX:
2942         // Preference + domainname
2943         if (rdlength < 3)
2944             goto fail;
2945         rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
2946         ptr += 2;
2947         if (msg)
2948         {
2949             ptr = getDomainName(msg, ptr, end, &rdb->mx.exchange);
2950         }
2951         else
2952         {
2953             AssignDomainName(&rdb->mx.exchange, (domainname *)ptr);
2954             ptr += DomainNameLength(&rdb->mx.exchange);
2955         }
2956         if (ptr != end)
2957         {
2958             debugf("SetRData: Malformed MX name");
2959             goto fail;
2960         }
2961         break;
2962 
2963     case kDNSType_MINFO:
2964     case kDNSType_RP:
2965         // Domainname + domainname
2966         if (msg)
2967         {
2968             ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox);
2969         }
2970         else
2971         {
2972             AssignDomainName(&rdb->rp.mbox, (domainname *)ptr);
2973             ptr += DomainNameLength(&rdb->rp.mbox);
2974         }
2975         if (!ptr)
2976         {
2977             debugf("SetRData: Malformed RP mbox");
2978             goto fail;
2979         }
2980         if (msg)
2981         {
2982             ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
2983         }
2984         else
2985         {
2986             AssignDomainName(&rdb->rp.txt, (domainname *)ptr);
2987             ptr += DomainNameLength(&rdb->rp.txt);
2988         }
2989         if (ptr != end)
2990         {
2991             debugf("SetRData: Malformed RP txt");
2992             goto fail;
2993         }
2994         break;
2995 
2996     case kDNSType_PX:
2997         // Preference + domainname + domainname
2998         if (rdlength < 4)
2999             goto fail;
3000         rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3001         ptr += 2;
3002         if (msg)
3003         {
3004             ptr = getDomainName(msg, ptr, end, &rdb->px.map822);
3005         }
3006         else
3007         {
3008             AssignDomainName(&rdb->px.map822, (domainname *)ptr);
3009             ptr += DomainNameLength(&rdb->px.map822);
3010         }
3011         if (!ptr)
3012         {
3013             debugf("SetRData: Malformed PX map822");
3014             goto fail;
3015         }
3016         if (msg)
3017         {
3018             ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
3019         }
3020         else
3021         {
3022             AssignDomainName(&rdb->px.mapx400, (domainname *)ptr);
3023             ptr += DomainNameLength(&rdb->px.mapx400);
3024         }
3025         if (ptr != end)
3026         {
3027             debugf("SetRData: Malformed PX mapx400");
3028             goto fail;
3029         }
3030         break;
3031 
3032     case kDNSType_AAAA:
3033         if (rdlength != sizeof(mDNSv6Addr))
3034             goto fail;
3035         mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
3036         break;
3037 
3038     case kDNSType_SRV:
3039         // Priority + weight + port + domainname
3040         if (rdlength < 7)
3041             goto fail;
3042         rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3043         rdb->srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
3044         rdb->srv.port.b[0] = ptr[4];
3045         rdb->srv.port.b[1] = ptr[5];
3046         ptr += 6;
3047         if (msg)
3048         {
3049             ptr = getDomainName(msg, ptr, end, &rdb->srv.target);
3050         }
3051         else
3052         {
3053             AssignDomainName(&rdb->srv.target, (domainname *)ptr);
3054             ptr += DomainNameLength(&rdb->srv.target);
3055         }
3056         if (ptr != end)
3057         {
3058             debugf("SetRData: Malformed SRV RDATA name");
3059             goto fail;
3060         }
3061         break;
3062 
3063     case kDNSType_NAPTR:
3064     {
3065         int savelen, len;
3066         domainname name;
3067         const mDNSu8 *orig = ptr;
3068 
3069         // Make sure the data is parseable and within the limits. DNSSEC code looks at
3070         // the domain name in the end for a valid domainname.
3071         //
3072         // Fixed length: Order, preference (4 bytes)
3073         // Variable length: flags, service, regexp, domainname
3074 
3075         if (rdlength < 8)
3076             goto fail;
3077         // Order, preference.
3078         ptr += 4;
3079         // Parse flags, Service and Regexp
3080         // length in the first byte does not include the length byte itself
3081         len = *ptr + 1;
3082         ptr += len;
3083         if (ptr >= end)
3084         {
3085             LogInfo("SetRData: Malformed NAPTR flags");
3086             goto fail;
3087         }
3088 
3089         // Service
3090         len = *ptr + 1;
3091         ptr += len;
3092         if (ptr >= end)
3093         {
3094             LogInfo("SetRData: Malformed NAPTR service");
3095             goto fail;
3096         }
3097 
3098         // Regexp
3099         len = *ptr + 1;
3100         ptr += len;
3101         if (ptr >= end)
3102         {
3103             LogInfo("SetRData: Malformed NAPTR regexp");
3104             goto fail;
3105         }
3106 
3107         savelen = ptr - orig;
3108 
3109         // RFC 2915 states that name compression is not allowed for this field. But RFC 3597
3110         // states that for NAPTR we should decompress. We make sure that we store the full
3111         // name rather than the compressed name
3112         if (msg)
3113         {
3114             ptr = getDomainName(msg, ptr, end, &name);
3115         }
3116         else
3117         {
3118             AssignDomainName(&name, (domainname *)ptr);
3119             ptr += DomainNameLength(&name);
3120         }
3121         if (ptr != end)
3122         {
3123             LogInfo("SetRData: Malformed NAPTR RDATA name");
3124             goto fail;
3125         }
3126 
3127         rr->resrec.rdlength = savelen + DomainNameLength(&name);
3128         // The uncompressed size should not exceed the limits
3129         if (rr->resrec.rdlength > MaximumRDSize)
3130         {
3131             LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->resrec.rdlength %d, "
3132                     "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
3133             goto fail;
3134         }
3135         mDNSPlatformMemCopy(rdb->data, orig, savelen);
3136         AssignDomainName((domainname *)(rdb->data + savelen), &name);
3137         break;
3138     }
3139     case kDNSType_OPT:  {
3140         mDNSu8 *dataend     = rr->resrec.rdata->u.data;
3141         rdataOPT *opt = rr->resrec.rdata->u.opt;
3142         rr->resrec.rdlength = 0;
3143         while (ptr < end && (mDNSu8 *)(opt+1) < &dataend[MaximumRDSize])
3144         {
3145             const rdataOPT *const currentopt = opt;
3146             if (ptr + 4 > end) { LogInfo("SetRData: OPT RDATA ptr + 4 > end"); goto fail; }
3147             opt->opt    = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3148             opt->optlen = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
3149             ptr += 4;
3150             if (ptr + opt->optlen > end) { LogInfo("SetRData: ptr + opt->optlen > end"); goto fail; }
3151             switch (opt->opt)
3152             {
3153             case kDNSOpt_LLQ:
3154                 if (opt->optlen == DNSOpt_LLQData_Space - 4)
3155                 {
3156                     opt->u.llq.vers  = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3157                     opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
3158                     opt->u.llq.err   = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
3159                     mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8);
3160                     opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]);
3161                     if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
3162                         opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
3163                     opt++;
3164                 }
3165                 break;
3166             case kDNSOpt_Lease:
3167                 if (opt->optlen == DNSOpt_LeaseData_Space - 4)
3168                 {
3169                     opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
3170                     if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
3171                         opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
3172                     opt++;
3173                 }
3174                 break;
3175             case kDNSOpt_Owner:
3176                 if (ValidOwnerLength(opt->optlen))
3177                 {
3178                     opt->u.owner.vers = ptr[0];
3179                     opt->u.owner.seq  = ptr[1];
3180                     mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6);                         // 6-byte MAC address
3181                     mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6);                         // 6-byte MAC address
3182                     opt->u.owner.password = zeroEthAddr;
3183                     if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
3184                     {
3185                         mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6);                     // 6-byte MAC address
3186                         // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above
3187                         // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4
3188                         if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
3189                             mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
3190                     }
3191                     opt++;
3192                 }
3193                 break;
3194             case kDNSOpt_Trace:
3195                 if (opt->optlen == DNSOpt_TraceData_Space - 4)
3196                 {
3197                     opt->u.tracer.platf   = ptr[0];
3198                     opt->u.tracer.mDNSv   = (mDNSu32) ((mDNSu32)ptr[1] << 24 | (mDNSu32)ptr[2] << 16 | (mDNSu32)ptr[3] << 8 | ptr[4]);
3199                     opt++;
3200                 }
3201                 else
3202                 {
3203                     opt->u.tracer.platf   = 0xFF;
3204                     opt->u.tracer.mDNSv   = 0xFFFFFFFF;
3205                     opt++;
3206                 }
3207                 break;
3208             }
3209             ptr += currentopt->optlen;
3210         }
3211         rr->resrec.rdlength = (mDNSu16)((mDNSu8*)opt - rr->resrec.rdata->u.data);
3212         if (ptr != end) { LogInfo("SetRData: Malformed OptRdata"); goto fail; }
3213         break;
3214     }
3215 
3216     case kDNSType_NSEC: {
3217         domainname name;
3218         int len = rdlength;
3219         int bmaplen, dlen;
3220         const mDNSu8 *orig = ptr;
3221         const mDNSu8 *bmap;
3222 
3223         if (msg)
3224         {
3225             ptr = getDomainName(msg, ptr, end, &name);
3226         }
3227         else
3228         {
3229             AssignDomainName(&name, (domainname *)ptr);
3230             ptr += DomainNameLength(&name);
3231         }
3232         if (!ptr)
3233         {
3234             LogInfo("SetRData: Malformed NSEC nextname");
3235             goto fail;
3236         }
3237 
3238         dlen = DomainNameLength(&name);
3239 
3240         // Multicast NSECs use name compression for this field unlike the unicast case which
3241         // does not use compression. And multicast case always succeeds in compression. So,
3242         // the rdlength includes only the compressed space in that case. So, can't
3243         // use the DomainNameLength of name to reduce the length here.
3244         len -= (ptr - orig);
3245         bmaplen = len;                  // Save the length of the bitmap
3246         bmap = ptr;
3247         ptr = SanityCheckBitMap(bmap, end, len);
3248         if (!ptr)
3249             goto fail;
3250         if (ptr != end)
3251         {
3252             LogInfo("SetRData: Malformed NSEC length not right");
3253             goto fail;
3254         }
3255 
3256         // Initialize the right length here. When we call SetNewRData below which in turn calls
3257         // GetRDLength and for NSEC case, it assumes that rdlength is intitialized
3258         rr->resrec.rdlength = DomainNameLength(&name) + bmaplen;
3259 
3260         // Do we have space after the name expansion ?
3261         if (rr->resrec.rdlength > MaximumRDSize)
3262         {
3263             LogInfo("SetRData: Malformed NSEC rdlength %d, rr->resrec.rdlength %d, "
3264                     "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
3265             goto fail;
3266         }
3267         AssignDomainName((domainname *)rdb->data, &name);
3268         mDNSPlatformMemCopy(rdb->data + dlen, bmap, bmaplen);
3269         break;
3270     }
3271     case kDNSType_NSEC3:
3272     {
3273         rdataNSEC3 *nsec3 = (rdataNSEC3 *)ptr;
3274         mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
3275         int hashLength, bitmaplen;
3276 
3277         if (rdlength < NSEC3_FIXED_SIZE + 1)
3278         {
3279             LogInfo("SetRData: NSEC3 too small length %d", rdlength);
3280             goto fail;
3281         }
3282         if (nsec3->alg != SHA1_DIGEST_TYPE)
3283         {
3284             LogInfo("SetRData: nsec3 alg %d not supported", nsec3->alg);
3285             goto fail;
3286         }
3287         if (swap16(nsec3->iterations) > NSEC3_MAX_ITERATIONS)
3288         {
3289             LogInfo("SetRData: nsec3 iteration count %d too big", swap16(nsec3->iterations));
3290             goto fail;
3291         }
3292         p += nsec3->saltLength;
3293         // There should at least be one byte beyond saltLength
3294         if (p >= end)
3295         {
3296             LogInfo("SetRData: nsec3 too small, at saltlength %d, p %p, end %p", nsec3->saltLength, p, end);
3297             goto fail;
3298         }
3299         // p is pointing at hashLength
3300         hashLength = (int)*p++;
3301         if (!hashLength)
3302         {
3303             LogInfo("SetRData: hashLength zero");
3304             goto fail;
3305         }
3306         p += hashLength;
3307         if (p > end)
3308         {
3309             LogInfo("SetRData: nsec3 too small, at hashLength %d, p %p, end %p", hashLength, p, end);
3310             goto fail;
3311         }
3312 
3313         bitmaplen = rdlength - (int)(p - ptr);
3314         p = SanityCheckBitMap(p, end, bitmaplen);
3315         if (!p)
3316             goto fail;
3317         rr->resrec.rdlength = rdlength;
3318         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3319         break;
3320     }
3321     case kDNSType_TKEY:
3322     case kDNSType_TSIG:
3323     {
3324         domainname name;
3325         int dlen, rlen;
3326 
3327         // The name should not be compressed. But we take the conservative approach
3328         // and uncompress the name before we store it.
3329         if (msg)
3330         {
3331             ptr = getDomainName(msg, ptr, end, &name);
3332         }
3333         else
3334         {
3335             AssignDomainName(&name, (domainname *)ptr);
3336             ptr += DomainNameLength(&name);
3337         }
3338         if (!ptr)
3339         {
3340             LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->resrec.rrtype);
3341             goto fail;
3342         }
3343         dlen = DomainNameLength(&name);
3344         rlen = end - ptr;
3345         rr->resrec.rdlength = dlen + rlen;
3346         if (rr->resrec.rdlength > MaximumRDSize)
3347         {
3348             LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->resrec.rdlength %d, "
3349                     "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
3350             goto fail;
3351         }
3352         AssignDomainName((domainname *)rdb->data, &name);
3353         mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen);
3354         break;
3355     }
3356     case kDNSType_RRSIG:
3357     {
3358         const mDNSu8 *sig = ptr + RRSIG_FIXED_SIZE;
3359         const mDNSu8 *orig = sig;
3360         domainname name;
3361         if (rdlength < RRSIG_FIXED_SIZE + 1)
3362         {
3363             LogInfo("SetRData: RRSIG too small length %d", rdlength);
3364             goto fail;
3365         }
3366         if (msg)
3367         {
3368             sig = getDomainName(msg, sig, end, &name);
3369         }
3370         else
3371         {
3372             AssignDomainName(&name, (domainname *)sig);
3373             sig += DomainNameLength(&name);
3374         }
3375         if (!sig)
3376         {
3377             LogInfo("SetRData: Malformed RRSIG record");
3378             goto fail;
3379         }
3380 
3381         if ((sig - orig) != DomainNameLength(&name))
3382         {
3383             LogInfo("SetRData: Malformed RRSIG record, signer name compression");
3384             goto fail;
3385         }
3386         // Just ensure that we have at least one byte of the signature
3387         if (sig + 1 >= end)
3388         {
3389             LogInfo("SetRData: Not enough bytes for signature type %d", rr->resrec.rrtype);
3390             goto fail;
3391         }
3392         rr->resrec.rdlength = rdlength;
3393         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3394         break;
3395     }
3396     case kDNSType_DNSKEY:
3397     {
3398         if (rdlength < DNSKEY_FIXED_SIZE + 1)
3399         {
3400             LogInfo("SetRData: DNSKEY too small length %d", rdlength);
3401             goto fail;
3402         }
3403         rr->resrec.rdlength = rdlength;
3404         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3405         break;
3406     }
3407     case kDNSType_DS:
3408     {
3409         if (rdlength < DS_FIXED_SIZE + 1)
3410         {
3411             LogInfo("SetRData: DS too small length %d", rdlength);
3412             goto fail;
3413         }
3414         rr->resrec.rdlength = rdlength;
3415         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3416         break;
3417     }
3418     default:
3419         debugf("SetRData: Warning! Reading resource type %d (%s) as opaque data",
3420                rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
3421         // Note: Just because we don't understand the record type, that doesn't
3422         // mean we fail. The DNS protocol specifies rdlength, so we can
3423         // safely skip over unknown records and ignore them.
3424         // We also grab a binary copy of the rdata anyway, since the caller
3425         // might know how to interpret it even if we don't.
3426         rr->resrec.rdlength = rdlength;
3427         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3428         break;
3429     }
3430     return mDNStrue;
3431 fail:
3432     return mDNSfalse;
3433 }
3434 
3435 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
3436                                                 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr)
3437 {
3438     CacheRecord *const rr = &largecr->r;
3439     mDNSu16 pktrdlength;
3440 
3441     if (largecr == &m->rec && m->rec.r.resrec.RecordType)
3442         LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
3443 
3444     rr->next              = mDNSNULL;
3445     rr->resrec.name       = &largecr->namestorage;
3446 
3447     rr->NextInKAList      = mDNSNULL;
3448     rr->TimeRcvd          = m ? m->timenow : 0;
3449     rr->DelayDelivery     = 0;
3450     rr->NextRequiredQuery = m ? m->timenow : 0;     // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
3451     rr->LastUsed          = m ? m->timenow : 0;
3452     rr->CRActiveQuestion  = mDNSNULL;
3453     rr->UnansweredQueries = 0;
3454     rr->LastUnansweredTime= 0;
3455     rr->NextInCFList      = mDNSNULL;
3456 
3457     rr->resrec.InterfaceID       = InterfaceID;
3458     rr->resrec.rDNSServer = mDNSNULL;
3459 
3460     ptr = getDomainName(msg, ptr, end, &largecr->namestorage);      // Will bail out correctly if ptr is NULL
3461     if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
3462     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
3463 
3464     if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
3465 
3466     rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
3467     rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
3468     rr->resrec.rroriginalttl     = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
3469     if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1)
3470         rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
3471     // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
3472     // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
3473     pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
3474 
3475     // If mDNS record has cache-flush bit set, we mark it unique
3476     // For uDNS records, all are implicitly deemed unique (a single DNS server is always
3477     // authoritative for the entire RRSet), unless this is a truncated response
3478     if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || (!InterfaceID && !(msg->h.flags.b[0] & kDNSFlag0_TC)))
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 mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
3633 {
3634     int i;
3635     LogInfo("%2d %s", count, label);
3636     for (i = 0; i < count && ptr; i++)
3637     {
3638         // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage,
3639         // but since it's only used for debugging (and probably only on OS X, not on
3640         // embedded systems) putting a 9kB object on the stack isn't a big problem.
3641         LargeCacheRecord largecr;
3642         ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
3643         if (ptr)
3644             LogInfo("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
3645     }
3646     if (!ptr)
3647         LogInfo("DumpRecords: ERROR: Premature end of packet data");
3648     return(ptr);
3649 }
3650 
3651 #define DNS_OP_Name(X) (                              \
3652         (X) == kDNSFlag0_OP_StdQuery ? ""         :       \
3653         (X) == kDNSFlag0_OP_Iquery   ? "Iquery "  :       \
3654         (X) == kDNSFlag0_OP_Status   ? "Status "  :       \
3655         (X) == kDNSFlag0_OP_Unused3  ? "Unused3 " :       \
3656         (X) == kDNSFlag0_OP_Notify   ? "Notify "  :       \
3657         (X) == kDNSFlag0_OP_Update   ? "Update "  :       \
3658         (X) == kDNSFlag0_OP_Subscribe? "Subscribe":       \
3659         (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " )
3660 
3661 #define DNS_RC_Name(X) (                             \
3662         (X) == kDNSFlag1_RC_NoErr    ? "NoErr"    :      \
3663         (X) == kDNSFlag1_RC_FormErr  ? "FormErr"  :      \
3664         (X) == kDNSFlag1_RC_ServFail ? "ServFail" :      \
3665         (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" :      \
3666         (X) == kDNSFlag1_RC_NotImpl  ? "NotImpl"  :      \
3667         (X) == kDNSFlag1_RC_Refused  ? "Refused"  :      \
3668         (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" :      \
3669         (X) == kDNSFlag1_RC_YXRRSet  ? "YXRRSet"  :      \
3670         (X) == kDNSFlag1_RC_NXRRSet  ? "NXRRSet"  :      \
3671         (X) == kDNSFlag1_RC_NotAuth  ? "NotAuth"  :      \
3672         (X) == kDNSFlag1_RC_NotZone  ? "NotZone"  : "??" )
3673 
3674 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order
3675 mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
3676                            const mDNSAddr *srcaddr, mDNSIPPort srcport,
3677                            const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
3678 {
3679     mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update);
3680     const mDNSu8 *ptr = msg->data;
3681     int i;
3682     DNSQuestion q;
3683     char tbuffer[64], sbuffer[64], dbuffer[64] = "";
3684     if (!status) tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), sent ? "Sent" : "Received"                        )] = 0;
3685     else tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), "ERROR %d %sing", status, sent ? "Send" : "Receive")] = 0;
3686     if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port "        )] = 0;
3687     else sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0;
3688     if (dstaddr || !mDNSIPPortIsZero(dstport))
3689         dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0;
3690 
3691     LogInfo("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --",
3692            tbuffer, transport,
3693            DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
3694            msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
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            end - msg->data,
3706            sbuffer, mDNSVal16(srcport), dbuffer,
3707            (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
3708            );
3709 
3710     LogInfo("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
3711     for (i = 0; i < msg->h.numQuestions && ptr; i++)
3712     {
3713         ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
3714         if (ptr) LogInfo("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
3715     }
3716     ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers,     IsUpdate ? "Prerequisites" : "Answers");
3717     ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates"       : "Authorities");
3718           DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals");
3719     LogInfo("--------------");
3720 }
3721 
3722 // ***************************************************************************
3723 #if COMPILER_LIKES_PRAGMA_MARK
3724 #pragma mark -
3725 #pragma mark - Packet Sending Functions
3726 #endif
3727 
3728 #ifdef UNIT_TEST
3729 // Run the unit test of mDNSSendDNSMessage
3730 UNITTEST_SENDDNSMESSAGE
3731 #else
3732 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
3733 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
3734 // Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
3735 struct UDPSocket_struct { mDNSIPPort     port;  /* ... */ };
3736 
3737 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
3738 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
3739 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
3740                                       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
3741                                       mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
3742                                       mDNSBool useBackgroundTrafficClass)
3743 {
3744     mStatus status = mStatus_NoError;
3745     const mDNSu16 numAdditionals = msg->h.numAdditionals;
3746     mDNSu8 *newend;
3747     mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
3748 
3749 #if APPLE_OSX_mDNSResponder
3750     // maintain outbound packet statistics
3751     if (mDNSOpaque16IsZero(msg->h.id))
3752         m->MulticastPacketsSent++;
3753     else
3754         m->UnicastPacketsSent++;
3755 #endif // APPLE_OSX_mDNSResponder
3756 
3757     // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code
3758     if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData)
3759     {
3760         LogMsg("mDNSSendDNSMessage: invalid message %p %p %d", msg->data, end, end - msg->data);
3761         return mStatus_BadParamErr;
3762     }
3763 
3764     newend = putHINFO(m, msg, end, authInfo, limit);
3765     if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
3766     else end = newend;
3767 
3768     // Put all the integer values in IETF byte-order (MSB first, LSB second)
3769     SwapDNSHeaderBytes(msg);
3770 
3771     if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0);    // DNSDigest_SignMessage operates on message in network byte order
3772     if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; }
3773     else
3774     {
3775         // Send the packet on the wire
3776         if (!sock)
3777             status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport, useBackgroundTrafficClass);
3778         else
3779         {
3780             mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
3781             mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
3782             char *buf;
3783             long nsent;
3784 
3785             // Try to send them in one packet if we can allocate enough memory
3786             buf = mDNSPlatformMemAllocate(msglen + 2);
3787             if (buf)
3788             {
3789                 buf[0] = lenbuf[0];
3790                 buf[1] = lenbuf[1];
3791                 mDNSPlatformMemCopy(buf+2, msg, msglen);
3792                 nsent = mDNSPlatformWriteTCP(sock, buf, msglen+2);
3793                 if (nsent != (msglen + 2))
3794                 {
3795                     LogMsg("mDNSSendDNSMessage: write message failed %d/%d", nsent, msglen);
3796                     status = mStatus_ConnFailed;
3797                 }
3798                 mDNSPlatformMemFree(buf);
3799             }
3800             else
3801             {
3802                 nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
3803                 if (nsent != 2)
3804                 {
3805                     LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2);
3806                     status = mStatus_ConnFailed;
3807                 }
3808                 else
3809                 {
3810                     nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
3811                     if (nsent != msglen)
3812                     {
3813                         LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen);
3814                         status = mStatus_ConnFailed;
3815                     }
3816                 }
3817             }
3818         }
3819     }
3820 
3821     // Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage)
3822     SwapDNSHeaderBytes(msg);
3823 
3824     // Dump the packet with the HINFO and TSIG
3825     if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
3826         DumpPacket(m, status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
3827 
3828     // put the number of additionals back the way it was
3829     msg->h.numAdditionals = numAdditionals;
3830 
3831     return(status);
3832 }
3833 #endif // UNIT_TEST
3834 
3835 // ***************************************************************************
3836 #if COMPILER_LIKES_PRAGMA_MARK
3837 #pragma mark -
3838 #pragma mark - RR List Management & Task Management
3839 #endif
3840 
3841 mDNSexport void mDNS_Lock_(mDNS *const m, const char * const functionname)
3842 {
3843     // MUST grab the platform lock FIRST!
3844     mDNSPlatformLock(m);
3845 
3846     // Normally, mDNS_reentrancy is zero and so is mDNS_busy
3847     // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
3848     // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
3849     // If mDNS_busy != mDNS_reentrancy that's a bad sign
3850     if (m->mDNS_busy != m->mDNS_reentrancy)
3851         LogFatalError("%s: mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
3852 
3853     // If this is an initial entry into the mDNSCore code, set m->timenow
3854     // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
3855     if (m->mDNS_busy == 0)
3856     {
3857         if (m->timenow)
3858             LogMsg("%s: mDNS_Lock: m->timenow already set (%ld/%ld)", functionname, m->timenow, mDNS_TimeNow_NoLock(m));
3859         m->timenow = mDNS_TimeNow_NoLock(m);
3860         if (m->timenow == 0) m->timenow = 1;
3861     }
3862     else if (m->timenow == 0)
3863     {
3864         LogMsg("%s: mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", functionname, m->mDNS_busy);
3865         m->timenow = mDNS_TimeNow_NoLock(m);
3866         if (m->timenow == 0) m->timenow = 1;
3867     }
3868 
3869     if (m->timenow_last - m->timenow > 0)
3870     {
3871         m->timenow_adjust += m->timenow_last - m->timenow;
3872         LogMsg("%s: mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", functionname, m->timenow_last - m->timenow, m->timenow_adjust);
3873         m->timenow = m->timenow_last;
3874     }
3875     m->timenow_last = m->timenow;
3876 
3877     // Increment mDNS_busy so we'll recognise re-entrant calls
3878     m->mDNS_busy++;
3879 }
3880 
3881 mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
3882 {
3883     AuthRecord *rr;
3884     for (rr = m->NewLocalRecords; rr; rr = rr->next)
3885         if (LocalRecordReady(rr)) return rr;
3886     return mDNSNULL;
3887 }
3888 
3889 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
3890 {
3891     mDNSs32 e = m->timenow + FutureTime;
3892     if (m->mDNSPlatformStatus != mStatus_NoError) return(e);
3893     if (m->NewQuestions)
3894     {
3895         if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
3896         else return(m->timenow);
3897     }
3898     if (m->NewLocalOnlyQuestions) return(m->timenow);
3899     if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
3900     if (m->NewLocalOnlyRecords) return(m->timenow);
3901     if (m->SPSProxyListChanged) return(m->timenow);
3902     if (m->LocalRemoveEvents) return(m->timenow);
3903 
3904 #ifndef UNICAST_DISABLED
3905     if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
3906     if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
3907     if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate;
3908 #endif
3909 
3910     if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
3911     if (e - m->NextScheduledSPS      > 0) e = m->NextScheduledSPS;
3912     if (e - m->NextScheduledKA       > 0) e = m->NextScheduledKA;
3913 
3914 #if BONJOUR_ON_DEMAND
3915     if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
3916 #endif // BONJOUR_ON_DEMAND
3917 
3918     // NextScheduledSPRetry only valid when DelaySleep not set
3919     if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
3920     if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
3921 
3922     if (m->SuppressSending)
3923     {
3924         if (e - m->SuppressSending       > 0) e = m->SuppressSending;
3925     }
3926     else
3927     {
3928         if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
3929         if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
3930         if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
3931     }
3932     if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime;
3933 
3934     if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime;
3935 
3936     return(e);
3937 }
3938 
3939 #define LogTSE TSE++,LogMsg
3940 
3941 mDNSexport void ShowTaskSchedulingError(mDNS *const m)
3942 {
3943     int TSE = 0;
3944     AuthRecord *rr;
3945     mDNS_Lock(m);
3946 
3947     LogMsg("Task Scheduling Error: *** Continuously busy for more than a second");
3948 
3949     // Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above
3950 
3951     if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
3952         LogTSE("Task Scheduling Error: NewQuestion %##s (%s)",
3953                m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
3954 
3955     if (m->NewLocalOnlyQuestions)
3956         LogTSE("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
3957                m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
3958 
3959     if (m->NewLocalRecords)
3960     {
3961         rr = AnyLocalRecordReady(m);
3962         if (rr) LogTSE("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
3963     }
3964 
3965     if (m->NewLocalOnlyRecords) LogTSE("Task Scheduling Error: NewLocalOnlyRecords");
3966 
3967     if (m->SPSProxyListChanged) LogTSE("Task Scheduling Error: SPSProxyListChanged");
3968 
3969     if (m->LocalRemoveEvents) LogTSE("Task Scheduling Error: LocalRemoveEvents");
3970 
3971 #ifndef UNICAST_DISABLED
3972     if (m->timenow - m->NextuDNSEvent         >= 0)
3973         LogTSE("Task Scheduling Error: m->NextuDNSEvent %d",         m->timenow - m->NextuDNSEvent);
3974     if (m->timenow - m->NextScheduledNATOp    >= 0)
3975         LogTSE("Task Scheduling Error: m->NextScheduledNATOp %d",    m->timenow - m->NextScheduledNATOp);
3976     if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0)
3977         LogTSE("Task Scheduling Error: m->NextSRVUpdate %d",         m->timenow - m->NextSRVUpdate);
3978 #endif
3979 
3980     if (m->timenow - m->NextCacheCheck        >= 0)
3981         LogTSE("Task Scheduling Error: m->NextCacheCheck %d",        m->timenow - m->NextCacheCheck);
3982     if (m->timenow - m->NextScheduledSPS      >= 0)
3983         LogTSE("Task Scheduling Error: m->NextScheduledSPS %d",      m->timenow - m->NextScheduledSPS);
3984     if (m->timenow - m->NextScheduledKA       >= 0)
3985         LogTSE("Task Scheduling Error: m->NextScheduledKA %d",      m->timenow - m->NextScheduledKA);
3986     if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
3987         LogTSE("Task Scheduling Error: m->NextScheduledSPRetry %d",  m->timenow - m->NextScheduledSPRetry);
3988     if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
3989         LogTSE("Task Scheduling Error: m->DelaySleep %d",            m->timenow - m->DelaySleep);
3990 
3991     if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
3992         LogTSE("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
3993     if (m->timenow - m->NextScheduledQuery    >= 0)
3994         LogTSE("Task Scheduling Error: m->NextScheduledQuery %d",    m->timenow - m->NextScheduledQuery);
3995     if (m->timenow - m->NextScheduledProbe    >= 0)
3996         LogTSE("Task Scheduling Error: m->NextScheduledProbe %d",    m->timenow - m->NextScheduledProbe);
3997     if (m->timenow - m->NextScheduledResponse >= 0)
3998         LogTSE("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
3999     if (m->timenow - m->NextScheduledStopTime >= 0)
4000         LogTSE("Task Scheduling Error: m->NextScheduledStopTime %d", m->timenow - m->NextScheduledStopTime);
4001 
4002     if (m->timenow - m->NextScheduledEvent    >= 0)
4003         LogTSE("Task Scheduling Error: m->NextScheduledEvent %d",    m->timenow - m->NextScheduledEvent);
4004 
4005     if (m->NetworkChanged && m->timenow - m->NetworkChanged >= 0)
4006         LogTSE("Task Scheduling Error: NetworkChanged %d",           m->timenow - m->NetworkChanged);
4007 
4008     if (!TSE) LogMsg("Task Scheduling Error: *** No likely causes identified");
4009     else LogMsg("Task Scheduling Error: *** %d potential cause%s identified (significant only if the same cause consistently appears)", TSE, TSE > 1 ? "s" : "");
4010 
4011     mDNS_Unlock(m);
4012 }
4013 
4014 mDNSexport void mDNS_Unlock_(mDNS *const m, const char *const functionname)
4015 {
4016     // Decrement mDNS_busy
4017     m->mDNS_busy--;
4018 
4019     // Check for locking failures
4020     if (m->mDNS_busy != m->mDNS_reentrancy)
4021         LogFatalError("%s: mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
4022 
4023     // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
4024     if (m->mDNS_busy == 0)
4025     {
4026         m->NextScheduledEvent = GetNextScheduledEvent(m);
4027         if (m->timenow == 0) LogMsg("%s: mDNS_Unlock: ERROR! m->timenow aready zero", functionname);
4028         m->timenow = 0;
4029     }
4030 
4031     // MUST release the platform lock LAST!
4032     mDNSPlatformUnlock(m);
4033 }
4034 
4035 // ***************************************************************************
4036 #if COMPILER_LIKES_PRAGMA_MARK
4037 #pragma mark -
4038 #pragma mark - Specialized mDNS version of vsnprintf
4039 #endif
4040 
4041 static const struct mDNSprintf_format
4042 {
4043     unsigned leftJustify : 1;
4044     unsigned forceSign : 1;
4045     unsigned zeroPad : 1;
4046     unsigned havePrecision : 1;
4047     unsigned hSize : 1;
4048     unsigned lSize : 1;
4049     char altForm;
4050     char sign;              // +, - or space
4051     unsigned int fieldWidth;
4052     unsigned int precision;
4053 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
4054 
4055 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
4056 {
4057     mDNSu32 nwritten = 0;
4058     int c;
4059     if (buflen == 0) return(0);
4060     buflen--;       // Pre-reserve one space in the buffer for the terminating null
4061     if (buflen == 0) goto exit;
4062 
4063     for (c = *fmt; c != 0; c = *++fmt)
4064     {
4065         unsigned long n;
4066 		if (c != '%')
4067         {
4068             *sbuffer++ = (char)c;
4069             if (++nwritten >= buflen) goto exit;
4070         }
4071         else
4072         {
4073             unsigned int i=0, j;
4074             // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
4075             // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
4076             // The size needs to be enough for a 256-byte domain name plus some error text.
4077             #define mDNS_VACB_Size 300
4078             char mDNS_VACB[mDNS_VACB_Size];
4079             #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
4080             #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
4081             char *s = mDNS_VACB_Lim, *digits;
4082             struct mDNSprintf_format F = mDNSprintf_format_default;
4083 
4084             while (1)   //  decode flags
4085             {
4086                 c = *++fmt;
4087                 if      (c == '-') F.leftJustify = 1;
4088                 else if (c == '+') F.forceSign = 1;
4089                 else if (c == ' ') F.sign = ' ';
4090                 else if (c == '#') F.altForm++;
4091                 else if (c == '0') F.zeroPad = 1;
4092                 else break;
4093             }
4094 
4095             if (c == '*')   //  decode field width
4096             {
4097                 int f = va_arg(arg, int);
4098                 if (f < 0) { f = -f; F.leftJustify = 1; }
4099                 F.fieldWidth = (unsigned int)f;
4100                 c = *++fmt;
4101             }
4102             else
4103             {
4104                 for (; c >= '0' && c <= '9'; c = *++fmt)
4105                     F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
4106             }
4107 
4108             if (c == '.')   //  decode precision
4109             {
4110                 if ((c = *++fmt) == '*')
4111                 { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
4112                 else for (; c >= '0' && c <= '9'; c = *++fmt)
4113                         F.precision = (10 * F.precision) + (c - '0');
4114                 F.havePrecision = 1;
4115             }
4116 
4117             if (F.leftJustify) F.zeroPad = 0;
4118 
4119 conv:
4120             switch (c)  //  perform appropriate conversion
4121             {
4122             case 'h':  F.hSize = 1; c = *++fmt; goto conv;
4123             case 'l':       // fall through
4124             case 'L':  F.lSize = 1; c = *++fmt; goto conv;
4125             case 'd':
4126             case 'i':  if (F.lSize) n = (unsigned long)va_arg(arg, long);
4127                 else n = (unsigned long)va_arg(arg, int);
4128                 if (F.hSize) n = (short) n;
4129                 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
4130                 else if (F.forceSign) F.sign = '+';
4131                 goto decimal;
4132             case 'u':  if (F.lSize) n = va_arg(arg, unsigned long);
4133                 else n = va_arg(arg, unsigned int);
4134                 if (F.hSize) n = (unsigned short) n;
4135                 F.sign = 0;
4136                 goto decimal;
4137 decimal:    if (!F.havePrecision)
4138                 {
4139                     if (F.zeroPad)
4140                     {
4141                         F.precision = F.fieldWidth;
4142                         if (F.sign) --F.precision;
4143                     }
4144                     if (F.precision < 1) F.precision = 1;
4145                 }
4146                 if (F.precision > mDNS_VACB_Size - 1)
4147                     F.precision = mDNS_VACB_Size - 1;
4148                 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
4149                 for (; i < F.precision; i++) *--s = '0';
4150                 if (F.sign) { *--s = F.sign; i++; }
4151                 break;
4152 
4153             case 'o':  if (F.lSize) n = va_arg(arg, unsigned long);
4154                 else n = va_arg(arg, unsigned int);
4155                 if (F.hSize) n = (unsigned short) n;
4156                 if (!F.havePrecision)
4157                 {
4158                     if (F.zeroPad) F.precision = F.fieldWidth;
4159                     if (F.precision < 1) F.precision = 1;
4160                 }
4161                 if (F.precision > mDNS_VACB_Size - 1)
4162                     F.precision = mDNS_VACB_Size - 1;
4163                 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
4164                 if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
4165                 for (; i < F.precision; i++) *--s = '0';
4166                 break;
4167 
4168             case 'a':  {
4169                 unsigned char *a = va_arg(arg, unsigned char *);
4170                 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
4171                 else
4172                 {
4173                     s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
4174                     if (F.altForm)
4175                     {
4176                         mDNSAddr *ip = (mDNSAddr*)a;
4177                         switch (ip->type)
4178                         {
4179                         case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
4180                         case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
4181                         default:                F.precision =  0; break;
4182                         }
4183                     }
4184                     if (F.altForm && !F.precision)
4185                         i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»");
4186                     else switch (F.precision)
4187                         {
4188                         case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
4189                                                    a[0], a[1], a[2], a[3]); break;
4190                         case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
4191                                                    a[0], a[1], a[2], a[3], a[4], a[5]); break;
4192                         case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
4193                                                    "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
4194                                                    a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
4195                                                    a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
4196                         default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
4197                                                    " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
4198                         }
4199                 }
4200             }
4201             break;
4202 
4203             case 'p':  F.havePrecision = F.lSize = 1;
4204                 F.precision = sizeof(void*) * 2;                // 8 characters on 32-bit; 16 characters on 64-bit
4205 		/* FALLTHROUGH */
4206             case 'X':  digits = "0123456789ABCDEF";
4207                 goto hexadecimal;
4208             case 'x':  digits = "0123456789abcdef";
4209 hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long);
4210                 else n = va_arg(arg, unsigned int);
4211                 if (F.hSize) n = (unsigned short) n;
4212                 if (!F.havePrecision)
4213                 {
4214                     if (F.zeroPad)
4215                     {
4216                         F.precision = F.fieldWidth;
4217                         if (F.altForm) F.precision -= 2;
4218                     }
4219                     if (F.precision < 1) F.precision = 1;
4220                 }
4221                 if (F.precision > mDNS_VACB_Size - 1)
4222                     F.precision = mDNS_VACB_Size - 1;
4223                 for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
4224                 for (; i < F.precision; i++) *--s = '0';
4225                 if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
4226                 break;
4227 
4228             case 'c':  *--s = (char)va_arg(arg, int); i = 1; break;
4229 
4230             case 's':  s = va_arg(arg, char *);
4231                 if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
4232                 else switch (F.altForm)
4233                     {
4234                     case 0: i=0;
4235                         if (!F.havePrecision)                               // C string
4236                             while (s[i]) i++;
4237                         else
4238                         {
4239                             while ((i < F.precision) && s[i]) i++;
4240                             // Make sure we don't truncate in the middle of a UTF-8 character
4241                             // If last character we got was any kind of UTF-8 multi-byte character,
4242                             // then see if we have to back up.
4243                             // This is not as easy as the similar checks below, because
4244                             // here we can't assume it's safe to examine the *next* byte, so we
4245                             // have to confine ourselves to working only backwards in the string.
4246                             j = i;                      // Record where we got to
4247                             // Now, back up until we find first non-continuation-char
4248                             while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
4249                             // Now s[i-1] is the first non-continuation-char
4250                             // and (j-i) is the number of continuation-chars we found
4251                             if (i>0 && (s[i-1] & 0xC0) == 0xC0)                 // If we found a start-char
4252                             {
4253                                 i--;                        // Tentatively eliminate this start-char as well
4254                                 // Now (j-i) is the number of characters we're considering eliminating.
4255                                 // To be legal UTF-8, the start-char must contain (j-i) one-bits,
4256                                 // followed by a zero bit. If we shift it right by (7-(j-i)) bits
4257                                 // (with sign extension) then the result has to be 0xFE.
4258                                 // If this is right, then we reinstate the tentatively eliminated bytes.
4259                                 if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
4260                             }
4261                         }
4262                         break;
4263                     case 1: i = (unsigned char) *s++; break;                // Pascal string
4264                     case 2: {                                               // DNS label-sequence name
4265                         unsigned char *a = (unsigned char *)s;
4266                         s = mDNS_VACB;                  // Adjust s to point to the start of the buffer, not the end
4267                         if (*a == 0) *s++ = '.';                    // Special case for root DNS name
4268                         while (*a)
4269                         {
4270                             char buf[63*4+1];
4271                             if (*a > 63)
4272                             { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
4273                             if (s + *a >= &mDNS_VACB[254])
4274                             { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
4275                             // Need to use ConvertDomainLabelToCString to do proper escaping here,
4276                             // so it's clear what's a literal dot and what's a label separator
4277                             ConvertDomainLabelToCString((domainlabel*)a, buf);
4278                             s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf);
4279                             a += 1 + *a;
4280                         }
4281                         i = (mDNSu32)(s - mDNS_VACB);
4282                         s = mDNS_VACB;                  // Reset s back to the start of the buffer
4283                         break;
4284                     }
4285                     }
4286                 // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
4287                 if (F.havePrecision && i > F.precision)
4288                 { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
4289                 break;
4290 
4291             case 'n':  s = va_arg(arg, char *);
4292                 if      (F.hSize) *(short *) s = (short)nwritten;
4293                 else if (F.lSize) *(long  *) s = (long)nwritten;
4294                 else *(int   *) s = (int)nwritten;
4295                 continue;
4296 
4297             default:    s = mDNS_VACB;
4298                 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
4299 		/* FALLTHROUGH */
4300 
4301             case '%':  *sbuffer++ = (char)c;
4302                 if (++nwritten >= buflen) goto exit;
4303                 break;
4304             }
4305 
4306             if (i < F.fieldWidth && !F.leftJustify)         // Pad on the left
4307                 do  {
4308                     *sbuffer++ = ' ';
4309                     if (++nwritten >= buflen) goto exit;
4310                 } while (i < --F.fieldWidth);
4311 
4312             // Make sure we don't truncate in the middle of a UTF-8 character.
4313             // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
4314             // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
4315             // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
4316             // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
4317             if (i > buflen - nwritten)
4318             { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
4319             for (j=0; j<i; j++) *sbuffer++ = *s++;          // Write the converted result
4320             nwritten += i;
4321             if (nwritten >= buflen) goto exit;
4322 
4323             for (; i < F.fieldWidth; i++)                   // Pad on the right
4324             {
4325                 *sbuffer++ = ' ';
4326                 if (++nwritten >= buflen) goto exit;
4327             }
4328         }
4329     }
4330 exit:
4331     *sbuffer++ = 0;
4332     return(nwritten);
4333 }
4334 
4335 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
4336 {
4337     mDNSu32 length;
4338 
4339     va_list ptr;
4340     va_start(ptr,fmt);
4341     length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
4342     va_end(ptr);
4343 
4344     return(length);
4345 }
4346