Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSCore / DNSCommon.c
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         /* FALLTHROUGH */
1536     }
1537
1538     default:
1539     {
1540         int i;
1541         for (i=0; i+1 < len; i+=2)
1542         {
1543             sum += (((mDNSu32)(ptr[i])) << 8) | ptr[i+1];
1544             sum = (sum<<3) | (sum>>29);
1545         }
1546         if (i < len)
1547         {
1548             sum += ((mDNSu32)(ptr[i])) << 8;
1549         }
1550         return(sum);
1551     }
1552     }
1553 }
1554
1555 // r1 has to be a full ResourceRecord including rrtype and rdlength
1556 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
1557 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename)
1558 {
1559     const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data;
1560     const RDataBody2 *const b2 = (RDataBody2 *)r2;
1561     switch(r1->rrtype)
1562     {
1563     case kDNSType_NS:
1564     case kDNSType_MD:
1565     case kDNSType_MF:
1566     case kDNSType_CNAME:
1567     case kDNSType_MB:
1568     case kDNSType_MG:
1569     case kDNSType_MR:
1570     case kDNSType_PTR:
1571     case kDNSType_NSAP_PTR:
1572     case kDNSType_DNAME: return(SameDomainName(&b1->name, &b2->name));
1573
1574     case kDNSType_SOA:  return (mDNSBool)(   b1->soa.serial   == b2->soa.serial             &&
1575                                              b1->soa.refresh  == b2->soa.refresh            &&
1576                                              b1->soa.retry    == b2->soa.retry              &&
1577                                              b1->soa.expire   == b2->soa.expire             &&
1578                                              b1->soa.min      == b2->soa.min                &&
1579                                              samename(&b1->soa.mname, &b2->soa.mname) &&
1580                                              samename(&b1->soa.rname, &b2->soa.rname));
1581
1582     case kDNSType_MX:
1583     case kDNSType_AFSDB:
1584     case kDNSType_RT:
1585     case kDNSType_KX:   return (mDNSBool)(   b1->mx.preference == b2->mx.preference &&
1586                                              samename(&b1->mx.exchange, &b2->mx.exchange));
1587
1588     case kDNSType_MINFO:
1589     case kDNSType_RP:   return (mDNSBool)(   samename(&b1->rp.mbox, &b2->rp.mbox) &&
1590                                              samename(&b1->rp.txt,  &b2->rp.txt));
1591
1592     case kDNSType_PX:   return (mDNSBool)(   b1->px.preference == b2->px.preference          &&
1593                                              samename(&b1->px.map822,  &b2->px.map822) &&
1594                                              samename(&b1->px.mapx400, &b2->px.mapx400));
1595
1596     case kDNSType_SRV:  return (mDNSBool)(   b1->srv.priority == b2->srv.priority       &&
1597                                              b1->srv.weight   == b2->srv.weight         &&
1598                                              mDNSSameIPPort(b1->srv.port, b2->srv.port) &&
1599                                              samename(&b1->srv.target, &b2->srv.target));
1600
1601     case kDNSType_OPT:  return mDNSfalse;       // OPT is a pseudo-RR container structure; makes no sense to compare
1602     case kDNSType_NSEC: {
1603         // If the "nxt" name changes in case, we want to delete the old
1604         // and store just the new one. If the caller passes in SameDomainCS for "samename",
1605         // we would return "false" when the only change between the two rdata is the case
1606         // change in "nxt".
1607         //
1608         // Note: rdlength of both the RData are same (ensured by the caller) and hence we can
1609         // use just r1->rdlength below
1610
1611         int dlen1 = DomainNameLength((domainname *)b1->data);
1612         int dlen2 = DomainNameLength((domainname *)b2->data);
1613         return (mDNSBool)(dlen1 == dlen2 &&
1614                           samename((domainname *)b1->data, (domainname *)b2->data) &&
1615                           mDNSPlatformMemSame(b1->data + dlen1, b2->data + dlen2, r1->rdlength - dlen1));
1616     }
1617
1618     default:            return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength));
1619     }
1620 }
1621
1622 mDNSexport mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type)
1623 {
1624     int win, wlen;
1625     int wintype;
1626
1627     // The window that this type belongs to. NSEC has 256 windows that
1628     // comprises of 256 types.
1629     wintype = type >> 8;
1630
1631     while (bitmaplen > 0)
1632     {
1633         if (bitmaplen < 3)
1634         {
1635             LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d short", bitmaplen);
1636             return mDNSfalse;
1637         }
1638
1639         win = *bmap++;
1640         wlen = *bmap++;
1641         bitmaplen -= 2;
1642         if (bitmaplen < wlen || wlen < 1 || wlen > 32)
1643         {
1644             LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d wlen %d, win %d", bitmaplen, wlen, win);
1645             return mDNSfalse;
1646         }
1647         if (win < 0 || win >= 256)
1648         {
1649             LogInfo("BitmapTypeCheck: malformed nsec, wlen %d", wlen);
1650             return mDNSfalse;
1651         }
1652         if (win == wintype)
1653         {
1654             // First byte in the window serves 0 to 7, the next one serves 8 to 15 and so on.
1655             // Calculate the right byte offset first.
1656             int boff = (type & 0xff ) >> 3;
1657             if (wlen <= boff)
1658                 return mDNSfalse;
1659             // The last three bits values 0 to 7 corresponds to bit positions
1660             // within the byte.
1661             return (bmap[boff] & (0x80 >> (type & 7)));
1662         }
1663         else
1664         {
1665             // If the windows are ordered, then we could check to see
1666             // if wintype > win and then return early.
1667             bmap += wlen;
1668             bitmaplen -= wlen;
1669         }
1670     }
1671     return mDNSfalse;
1672 }
1673
1674 // Don't call this function if the resource record is not NSEC. It will return false
1675 // which means that the type does not exist.
1676 mDNSexport mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type)
1677 {
1678     const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
1679     mDNSu8 *nsec = (mDNSu8 *)rdb->data;
1680     int len, bitmaplen;
1681     mDNSu8 *bmap;
1682
1683     if (rr->rrtype != kDNSType_NSEC) return mDNSfalse;
1684
1685     len = DomainNameLength((domainname *)nsec);
1686
1687     bitmaplen = rr->rdlength - len;
1688     bmap = nsec + len;
1689     return (BitmapTypeCheck(bmap, bitmaplen, type));
1690 }
1691
1692 // Don't call this function if the resource record is not NSEC. It will return false
1693 // which means that the type exists.
1694 mDNSexport mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type)
1695 {
1696     if (rr->rrtype != kDNSType_NSEC) return mDNSfalse;
1697
1698     return !RRAssertsExistence(rr, type);
1699 }
1700
1701 // Checks whether the RRSIG or NSEC record answers the question "q".
1702 mDNSlocal mDNSBool DNSSECRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q, mDNSBool *checkType)
1703 {
1704     *checkType = mDNStrue;
1705
1706     // This function is called for all questions and as long as the type matches,
1707     // return true. For the types (RRSIG and NSEC) that are specifically checked in
1708     // this function, returning true still holds good.
1709     if (q->qtype == rr->rrtype)
1710         return mDNStrue;
1711
1712     // For DS and DNSKEY questions, the types should match i.e., don't answer using CNAME
1713     // records as it answers any question type.
1714     //
1715     // - DS record comes from the parent zone where CNAME record cannot coexist and hence
1716     //  cannot possibly answer it.
1717     //
1718     // - For DNSKEY, one could potentially follow CNAME but there could be a DNSKEY at
1719     //   the "qname" itself. To keep it simple, we don't follow CNAME.
1720
1721     if ((q->qtype == kDNSType_DS || q->qtype == kDNSType_DNSKEY) && (q->qtype != rr->rrtype))
1722     {
1723         debugf("DNSSECRecordAnswersQuestion: %d type resource record matched question %##s (%s), ignoring", rr->rrtype,
1724             q->qname.c, DNSTypeName(q->qtype));
1725         return mDNSfalse;
1726     }
1727
1728     // If we are validating a response using DNSSEC, we might already have the records
1729     // for the "q->qtype" in the cache but we issued a query with DO bit set
1730     // to get the RRSIGs e.g., if you have two questions one of which does not require
1731     // DNSSEC validation. When the RRSIG is added to the cache, we need to deliver
1732     // the response to the question. The RRSIG type won't match the q->qtype and hence
1733     // we need to bypass the check in that case.
1734     if (rr->rrtype == kDNSType_RRSIG && q->ValidatingResponse)
1735     {
1736         const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
1737         rdataRRSig *rrsig = (rdataRRSig *)rdb->data;
1738         mDNSu16 typeCovered = swap16(rrsig->typeCovered);
1739         debugf("DNSSECRecordAnswersQuestion: Matching RRSIG typeCovered %s", DNSTypeName(typeCovered));
1740         if (typeCovered != kDNSType_CNAME && typeCovered != q->qtype)
1741         {
1742             debugf("DNSSECRecordAnswersQuestion: RRSIG did not match question %##s (%s)", q->qname.c,
1743                     DNSTypeName(q->qtype));
1744             return mDNSfalse;
1745         }
1746         LogInfo("DNSSECRecordAnswersQuestion: RRSIG matched question %##s (%s)", q->qname.c,
1747                 DNSTypeName(q->qtype));
1748         *checkType = mDNSfalse;
1749         return mDNStrue;
1750     }
1751     // If the NSEC record asserts the non-existence of a name looked up by the question, we would
1752     // typically answer that e.g., the bitmap asserts that q->qtype does not exist. If we have
1753     // to prove the non-existence as required by ValidatingResponse and ValidationRequired question,
1754     // then we should not answer that as it may not be the right one always. We may need more than
1755     // one NSEC to prove the non-existence.
1756     if (rr->rrtype == kDNSType_NSEC && DNSSECQuestion(q))
1757     {
1758         debugf("DNSSECRecordAnswersQuestion: Question %##s (%s) matched record %##s (NSEC)", q->qname.c,
1759                 DNSTypeName(q->qtype), rr->name->c);
1760         return mDNSfalse;
1761     }
1762     return mDNStrue;
1763 }
1764
1765 // ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
1766 // SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
1767 // SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
1768 // because it has to check all the way to the end of the names to be sure.
1769 // In cases where we know in advance that the names match it's especially advantageous to skip the
1770 // SameDomainName() call because that's precisely the time when it's most expensive and least useful.
1771
1772 mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
1773 {
1774     mDNSBool checkType = mDNStrue;
1775
1776     // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
1777     // are handled in LocalOnlyRecordAnswersQuestion
1778     if (LocalOnlyOrP2PInterface(rr->InterfaceID))
1779     {
1780         LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
1781         return mDNSfalse;
1782     }
1783     if (QuerySuppressed(q))
1784         return mDNSfalse;
1785
1786     if (rr->InterfaceID &&
1787         q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
1788         rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
1789
1790     // Resource record received via unicast, the resolver group ID should match ?
1791     if (!rr->InterfaceID)
1792     {
1793         mDNSu16 idr = (rr->rDNSServer ? rr->rDNSServer->resGroupID : 0);
1794         mDNSu16 idq = (q->qDNSServer ? q->qDNSServer->resGroupID : 0);
1795         if (idr != idq) return(mDNSfalse);
1796         if (!DNSSECRecordAnswersQuestion(rr, q, &checkType)) return mDNSfalse;
1797     }
1798
1799     // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
1800     if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
1801
1802     // CNAME answers question of any type and a negative cache record should not prevent us from querying other
1803     // valid types at the same name.
1804     if (rr->rrtype == kDNSType_CNAME && rr->RecordType == kDNSRecordTypePacketNegative && rr->rrtype != q->qtype)
1805         return mDNSfalse;
1806
1807     // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
1808     if (checkType && !RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
1809     if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
1810
1811 #if APPLE_OSX_mDNSResponder
1812     if (!mDNSPlatformValidRecordForQuestion(rr, q))
1813         return mDNSfalse;
1814 #endif // APPLE_OSX_mDNSResponder
1815
1816     if (!AnonInfoAnswersQuestion(rr, q))
1817         return mDNSfalse;
1818
1819     return(mDNStrue);
1820 }
1821
1822 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
1823 {
1824     if (!SameNameRecordAnswersQuestion(rr, q))
1825         return mDNSfalse;
1826
1827     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
1828 }
1829
1830 // We have a separate function to handle LocalOnly AuthRecords because they can be created with
1831 // a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
1832 // multicast resource records (which has a valid InterfaceID) which can't be used to answer
1833 // unicast questions. ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion can't tell whether
1834 // a resource record is multicast or LocalOnly by just looking at the ResourceRecord because
1835 // LocalOnly records are truly identified by ARType in the AuthRecord.  As P2P and LocalOnly record
1836 // are kept in the same hash table, we use the same function to make it easy for the callers when
1837 // they walk the hash table to answer LocalOnly/P2P questions
1838 //
1839 mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const DNSQuestion *const q)
1840 {
1841     ResourceRecord *rr = &ar->resrec;
1842
1843     // mDNSInterface_Any questions can be answered with LocalOnly/P2P records in this function. AuthRecord_Any
1844     // records are handled in ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion
1845     if (RRAny(ar))
1846     {
1847         LogMsg("LocalOnlyRecordAnswersQuestion: ERROR!! called with regular AuthRecordAny %##s", rr->name->c);
1848         return mDNSfalse;
1849     }
1850
1851     // Questions with mDNSInterface_LocalOnly InterfaceID should be answered with all resource records that are
1852     // *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
1853     // mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
1854     // the InterfaceID in the resource record.
1855     //
1856     // mDNSInterface_Unicast does not indicate any scope and hence treat them like mDNSInterface_Any.
1857
1858     if (rr->InterfaceID &&
1859         q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_Unicast &&
1860         rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
1861
1862     // Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
1863     // may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
1864     // to mDNSInterface_Any, mDNSInterface_LocalOnly or a real InterfaceID (scoped).
1865     //
1866     // 1) Question: Any, LocalOnly Record: no scope. This question should be answered with this record.
1867     //
1868     // 2) Question: Any, LocalOnly Record: scoped.  This question should be answered with the record because
1869     //    traditionally applications never specify scope e.g., getaddrinfo, but need to be able
1870     //    to get to /etc/hosts entries.
1871     //
1872     // 3) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: no scope. This is the inverse of (2).
1873     //    If we register a LocalOnly record, we need to answer a LocalOnly question. If the /etc/hosts has a
1874     //    non scoped entry, it may not make sense to answer a scoped question. But we can't tell these two
1875     //    cases apart. As we currently answer LocalOnly question with LocalOnly record, we continue to do so.
1876     //
1877     // 4) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: scoped. LocalOnly questions should be
1878     //    answered with any resource record where as if it has a valid InterfaceID, the scope should match.
1879     //
1880     // (1) and (2) is bypassed because we check for a non-NULL InterfaceID above. For (3), the InterfaceID is NULL
1881     // and hence bypassed above. For (4) we bypassed LocalOnly questions and checked the scope of the record
1882     // against the question.
1883     //
1884     // For P2P, InterfaceIDs of the question and the record should match.
1885
1886     // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
1887     // LocalOnly authoritative answers are exempt. LocalOnly authoritative answers are used for /etc/host entries.
1888     // We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com" which would then
1889     // cause other applications (e.g. Safari) to connect to the wrong address. The rpc to register records filters out records
1890     // with names that don't end in local and have mDNSInterface_LocalOnly set.
1891     //
1892     // Note: The check is bypassed for LocalOnly and for P2P it is not needed as only .local records are registered and for
1893     // a question to match its names, it also has to end in .local and that question can't be a unicast question (See
1894     // Question_uDNS macro and its usage). As P2P does not enforce .local only registrations we still make this check
1895     // and also makes it future proof.
1896
1897     if (ar->ARType != AuthRecordLocalOnly && rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
1898
1899     // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
1900     if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
1901     if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
1902
1903     if (!AnonInfoAnswersQuestion(rr, q))
1904         return mDNSfalse;
1905
1906     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
1907 }
1908
1909 mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
1910 {
1911     // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
1912     // are handled in LocalOnlyRecordAnswersQuestion
1913     if (LocalOnlyOrP2PInterface(rr->InterfaceID))
1914     {
1915         LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
1916         return mDNSfalse;
1917     }
1918     if (rr->InterfaceID &&
1919         q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
1920         rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
1921
1922     // Resource record received via unicast, the resolver group ID should match ?
1923     // Note that Auth Records are normally setup with NULL InterfaceID and
1924     // both the DNSServers are assumed to be NULL in that case
1925     if (!rr->InterfaceID)
1926     {
1927         mDNSu16 idr = (rr->rDNSServer ? rr->rDNSServer->resGroupID : 0);
1928         mDNSu16 idq = (q->qDNSServer ? q->qDNSServer->resGroupID : 0);
1929         if (idr != idq) return(mDNSfalse);
1930     }
1931
1932     // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
1933     if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
1934
1935     if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
1936
1937     if (!AnonInfoAnswersQuestion(rr, q))
1938         return mDNSfalse;
1939
1940     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
1941 }
1942
1943 // This is called with both unicast resource record and multicast resource record. The question that
1944 // received the unicast response could be the regular unicast response from a DNS server or a response
1945 // to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the
1946 // question and the resource record because the resource record is not completely initialized in
1947 // mDNSCoreReceiveResponse when this function is called.
1948 mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q)
1949 {
1950     mDNSBool checkType = mDNStrue;
1951
1952     if (QuerySuppressed(q))
1953         return mDNSfalse;
1954
1955     // For resource records created using multicast, the InterfaceIDs have to match
1956     if (rr->InterfaceID &&
1957         q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
1958
1959     // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
1960     if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
1961
1962     if (!DNSSECRecordAnswersQuestion(rr, q, &checkType)) return mDNSfalse;
1963
1964     // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
1965     if (checkType && !RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
1966
1967     if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
1968
1969     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
1970 }
1971
1972 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
1973 {
1974     const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data;
1975     const domainname *const name = estimate ? rr->name : mDNSNULL;
1976     if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength);    // Used in update packets to mean "Delete An RRset" (RFC 2136)
1977     else switch (rr->rrtype)
1978         {
1979         case kDNSType_A:    return(sizeof(rd->ipv4));
1980
1981         case kDNSType_NS:
1982         case kDNSType_CNAME:
1983         case kDNSType_PTR:
1984         case kDNSType_DNAME: return(CompressedDomainNameLength(&rd->name, name));
1985
1986         case kDNSType_SOA:  return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
1987                                              CompressedDomainNameLength(&rd->soa.rname, name) +
1988                                              5 * sizeof(mDNSOpaque32));
1989
1990         case kDNSType_NULL:
1991         case kDNSType_TSIG:
1992         case kDNSType_TXT:
1993         case kDNSType_X25:
1994         case kDNSType_ISDN:
1995         case kDNSType_LOC:
1996         case kDNSType_DHCID: return(rr->rdlength); // Not self-describing, so have to just trust rdlength
1997
1998         case kDNSType_HINFO: return (mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
1999
2000         case kDNSType_MX:
2001         case kDNSType_AFSDB:
2002         case kDNSType_RT:
2003         case kDNSType_KX:   return (mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name));
2004
2005         case kDNSType_RP:   return (mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) +
2006                                              CompressedDomainNameLength(&rd->rp.txt, name));
2007
2008         case kDNSType_PX:   return (mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) +
2009                                              CompressedDomainNameLength(&rd->px.mapx400, name));
2010
2011         case kDNSType_AAAA: return(sizeof(rd->ipv6));
2012
2013         case kDNSType_SRV:  return (mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
2014
2015         case kDNSType_OPT:  return(rr->rdlength);
2016
2017         case kDNSType_NSEC: {
2018             domainname *next = (domainname *)rd->data;
2019             int dlen = DomainNameLength(next);
2020             //
2021             if (UNICAST_NSEC(rr))
2022                 return (mDNSu16)(CompressedDomainNameLength(next, name) + rr->rdlength - dlen);
2023             else
2024                 return (mDNSu16)((estimate ? 2 : dlen) + rr->rdlength - dlen);
2025         }
2026
2027         default:            debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
2028             return(rr->rdlength);
2029         }
2030 }
2031
2032 // When a local client registers (or updates) a record, we use this routine to do some simple validation checks
2033 // to help reduce the risk of bogus malformed data on the network
2034 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
2035 {
2036     mDNSu16 len;
2037
2038     switch(rrtype)
2039     {
2040     case kDNSType_A:    return(rdlength == sizeof(mDNSv4Addr));
2041
2042     case kDNSType_NS:       // Same as PTR
2043     case kDNSType_MD:       // Same as PTR
2044     case kDNSType_MF:       // Same as PTR
2045     case kDNSType_CNAME:    // Same as PTR
2046     //case kDNSType_SOA not checked
2047     case kDNSType_MB:       // Same as PTR
2048     case kDNSType_MG:       // Same as PTR
2049     case kDNSType_MR:       // Same as PTR
2050     //case kDNSType_NULL not checked (no specified format, so always valid)
2051     //case kDNSType_WKS not checked
2052     case kDNSType_PTR:  len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength);
2053         return(len <= MAX_DOMAIN_NAME && rdlength == len);
2054
2055     case kDNSType_HINFO:    // Same as TXT (roughly)
2056     case kDNSType_MINFO:    // Same as TXT (roughly)
2057     case kDNSType_TXT:  if (!rdlength) return(mDNSfalse);     // TXT record has to be at least one byte (RFC 1035)
2058         {
2059             const mDNSu8 *ptr = rd->u.txt.c;
2060             const mDNSu8 *end = rd->u.txt.c + rdlength;
2061             while (ptr < end) ptr += 1 + ptr[0];
2062             return (ptr == end);
2063         }
2064
2065     case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr));
2066
2067     case kDNSType_MX:       // Must be at least two-byte preference, plus domainname
2068                             // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
2069         len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength);
2070         return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
2071
2072     case kDNSType_SRV:      // Must be at least priority+weight+port, plus domainname
2073                             // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
2074         len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength);
2075         return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
2076
2077     //case kDNSType_NSEC not checked
2078
2079     default:            return(mDNStrue);       // Allow all other types without checking
2080     }
2081 }
2082
2083 // ***************************************************************************
2084 #if COMPILER_LIKES_PRAGMA_MARK
2085 #pragma mark -
2086 #pragma mark - DNS Message Creation Functions
2087 #endif
2088
2089 mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
2090 {
2091     h->id             = id;
2092     h->flags          = flags;
2093     h->numQuestions   = 0;
2094     h->numAnswers     = 0;
2095     h->numAuthorities = 0;
2096     h->numAdditionals = 0;
2097 }
2098
2099 mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
2100 {
2101     const mDNSu8 *result = end - *domname - 1;
2102
2103     if (*domname == 0) return(mDNSNULL);    // There's no point trying to match just the root label
2104
2105     // This loop examines each possible starting position in packet, starting end of the packet and working backwards
2106     while (result >= base)
2107     {
2108         // If the length byte and first character of the label match, then check further to see
2109         // if this location in the packet will yield a useful name compression pointer.
2110         if (result[0] == domname[0] && result[1] == domname[1])
2111         {
2112             const mDNSu8 *name = domname;
2113             const mDNSu8 *targ = result;
2114             while (targ + *name < end)
2115             {
2116                 // First see if this label matches
2117                 int i;
2118                 const mDNSu8 *pointertarget;
2119                 for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
2120                 if (i <= *name) break;                          // If label did not match, bail out
2121                 targ += 1 + *name;                              // Else, did match, so advance target pointer
2122                 name += 1 + *name;                              // and proceed to check next label
2123                 if (*name == 0 && *targ == 0) return(result);   // If no more labels, we found a match!
2124                 if (*name == 0) break;                          // If no more labels to match, we failed, so bail out
2125
2126                 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
2127                 if (targ[0] < 0x40) continue;                   // If length value, continue to check next label
2128                 if (targ[0] < 0xC0) break;                      // If 40-BF, not valid
2129                 if (targ+1 >= end) break;                       // Second byte not present!
2130                 pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
2131                 if (targ < pointertarget) break;                // Pointertarget must point *backwards* in the packet
2132                 if (pointertarget[0] >= 0x40) break;            // Pointertarget must point to a valid length byte
2133                 targ = pointertarget;
2134             }
2135         }
2136         result--;   // We failed to match at this search position, so back up the tentative result pointer and try again
2137     }
2138     return(mDNSNULL);
2139 }
2140
2141 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
2142 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
2143 // end points to the end of the message so far
2144 // ptr points to where we want to put the name
2145 // limit points to one byte past the end of the buffer that we must not overrun
2146 // domainname is the name to put
2147 mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
2148                                          mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
2149 {
2150     const mDNSu8 *const base        = (const mDNSu8 *)msg;
2151     const mDNSu8 *      np          = name->c;
2152     const mDNSu8 *const max         = name->c + MAX_DOMAIN_NAME;    // Maximum that's valid
2153     const mDNSu8 *      pointer     = mDNSNULL;
2154     const mDNSu8 *const searchlimit = ptr;
2155
2156     if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); return(mDNSNULL); }
2157
2158     if (!*np)       // If just writing one-byte root label, make sure we have space for that
2159     {
2160         if (ptr >= limit) return(mDNSNULL);
2161     }
2162     else            // else, loop through writing labels and/or a compression offset
2163     {
2164         do  {
2165             if (*np > MAX_DOMAIN_LABEL)
2166             { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
2167
2168             // This check correctly allows for the final trailing root label:
2169             // e.g.
2170             // Suppose our domain name is exactly 256 bytes long, including the final trailing root label.
2171             // Suppose np is now at name->c[249], and we're about to write our last non-null label ("local").
2172             // We know that max will be at name->c[256]
2173             // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
2174             // six bytes, then exit the loop, write the final terminating root label, and the domain
2175             // name we've written is exactly 256 bytes long, exactly at the correct legal limit.
2176             // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
2177             if (np + 1 + *np >= max)
2178             { LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); }
2179
2180             if (base) pointer = FindCompressionPointer(base, searchlimit, np);
2181             if (pointer)                    // Use a compression pointer if we can
2182             {
2183                 const mDNSu16 offset = (mDNSu16)(pointer - base);
2184                 if (ptr+2 > limit) return(mDNSNULL);    // If we don't have two bytes of space left, give up
2185                 *ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
2186                 *ptr++ = (mDNSu8)(        offset &  0xFF);
2187                 return(ptr);
2188             }
2189             else                            // Else copy one label and try again
2190             {
2191                 int i;
2192                 mDNSu8 len = *np++;
2193                 // If we don't at least have enough space for this label *plus* a terminating zero on the end, give up
2194                 if (ptr + 1 + len >= limit) return(mDNSNULL);
2195                 *ptr++ = len;
2196                 for (i=0; i<len; i++) *ptr++ = *np++;
2197             }
2198         } while (*np);                      // While we've got characters remaining in the name, continue
2199     }
2200
2201     *ptr++ = 0;     // Put the final root label
2202     return(ptr);
2203 }
2204
2205 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
2206 {
2207     ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
2208     ptr[1] = (mDNSu8)((val      ) & 0xFF);
2209     return ptr + sizeof(mDNSOpaque16);
2210 }
2211
2212 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
2213 {
2214     ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
2215     ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
2216     ptr[2] = (mDNSu8)((val >>  8) & 0xFF);
2217     ptr[3] = (mDNSu8)((val      ) & 0xFF);
2218     return ptr + sizeof(mDNSu32);
2219 }
2220
2221 // Copy the RDATA information. The actual in memory storage for the data might be bigger than what the rdlength
2222 // says. Hence, the only way to copy out the data from a resource record is to use putRData.
2223 // msg points to the message we're building (pass mDNSNULL for "msg" if we don't want to use compression pointers)
2224 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr)
2225 {
2226     const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
2227     switch (rr->rrtype)
2228     {
2229     case kDNSType_A:    if (rr->rdlength != 4)
2230         { debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); }
2231         if (ptr + 4 > limit) return(mDNSNULL);
2232         *ptr++ = rdb->ipv4.b[0];
2233         *ptr++ = rdb->ipv4.b[1];
2234         *ptr++ = rdb->ipv4.b[2];
2235         *ptr++ = rdb->ipv4.b[3];
2236         return(ptr);
2237
2238     case kDNSType_NS:
2239     case kDNSType_CNAME:
2240     case kDNSType_PTR:
2241     case kDNSType_DNAME: return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name));
2242
2243     case kDNSType_SOA:  ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname);
2244         if (!ptr) return(mDNSNULL);
2245         ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.rname);
2246         if (!ptr || ptr + 20 > limit) return(mDNSNULL);
2247         ptr = putVal32(ptr, rdb->soa.serial);
2248         ptr = putVal32(ptr, rdb->soa.refresh);
2249         ptr = putVal32(ptr, rdb->soa.retry);
2250         ptr = putVal32(ptr, rdb->soa.expire);
2251         ptr = putVal32(ptr, rdb->soa.min);
2252         return(ptr);
2253
2254     case kDNSType_NULL:
2255     case kDNSType_HINFO:
2256     case kDNSType_TSIG:
2257     case kDNSType_TXT:
2258     case kDNSType_X25:
2259     case kDNSType_ISDN:
2260     case kDNSType_LOC:
2261     case kDNSType_DHCID: if (ptr + rr->rdlength > limit) return(mDNSNULL);
2262         mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
2263         return(ptr + rr->rdlength);
2264
2265     case kDNSType_MX:
2266     case kDNSType_AFSDB:
2267     case kDNSType_RT:
2268     case kDNSType_KX:   if (ptr + 3 > limit) return(mDNSNULL);
2269         ptr = putVal16(ptr, rdb->mx.preference);
2270         return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange));
2271
2272     case kDNSType_RP:   ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox);
2273         if (!ptr) return(mDNSNULL);
2274         ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.txt);
2275         return(ptr);
2276
2277     case kDNSType_PX:   if (ptr + 5 > limit) return(mDNSNULL);
2278         ptr = putVal16(ptr, rdb->px.preference);
2279         ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822);
2280         if (!ptr) return(mDNSNULL);
2281         ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400);
2282         return(ptr);
2283
2284     case kDNSType_AAAA: if (rr->rdlength != sizeof(rdb->ipv6))
2285         { debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); }
2286         if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL);
2287         mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6));
2288         return(ptr + sizeof(rdb->ipv6));
2289
2290     case kDNSType_SRV:  if (ptr + 7 > limit) return(mDNSNULL);
2291         *ptr++ = (mDNSu8)(rdb->srv.priority >> 8);
2292         *ptr++ = (mDNSu8)(rdb->srv.priority &  0xFF);
2293         *ptr++ = (mDNSu8)(rdb->srv.weight   >> 8);
2294         *ptr++ = (mDNSu8)(rdb->srv.weight   &  0xFF);
2295         *ptr++ = rdb->srv.port.b[0];
2296         *ptr++ = rdb->srv.port.b[1];
2297         return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target));
2298
2299     case kDNSType_OPT:  {
2300         int len = 0;
2301         const rdataOPT *opt;
2302         const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength];
2303         for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) 
2304             len += DNSOpt_Data_Space(opt);
2305         if (ptr + len > limit) 
2306         { 
2307             LogMsg("ERROR: putOptRData - out of space"); 
2308             return mDNSNULL; 
2309         }
2310         for (opt = &rr->rdata->u.opt[0]; opt < end; opt++)
2311         {
2312             const int space = DNSOpt_Data_Space(opt);
2313             ptr = putVal16(ptr, opt->opt);
2314             ptr = putVal16(ptr, (mDNSu16)space - 4);
2315             switch (opt->opt)
2316             {
2317             case kDNSOpt_LLQ:
2318                 ptr = putVal16(ptr, opt->u.llq.vers);
2319                 ptr = putVal16(ptr, opt->u.llq.llqOp);
2320                 ptr = putVal16(ptr, opt->u.llq.err);
2321                 mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8);                          // 8-byte id
2322                 ptr += 8;
2323                 ptr = putVal32(ptr, opt->u.llq.llqlease);
2324                 break;
2325             case kDNSOpt_Lease:
2326                 ptr = putVal32(ptr, opt->u.updatelease);
2327                 break;
2328             case kDNSOpt_Owner:
2329                 *ptr++ = opt->u.owner.vers;
2330                 *ptr++ = opt->u.owner.seq;
2331                 mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6);                          // 6-byte Host identifier
2332                 ptr += 6;
2333                 if (space >= DNSOpt_OwnerData_ID_Wake_Space)
2334                 {
2335                     mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6);                           // 6-byte interface MAC
2336                     ptr += 6;
2337                     if (space > DNSOpt_OwnerData_ID_Wake_Space)
2338                     {
2339                         mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space);
2340                         ptr += space - DNSOpt_OwnerData_ID_Wake_Space;
2341                     }
2342                 }
2343                 break;
2344             case kDNSOpt_Trace:
2345                 *ptr++ = opt->u.tracer.platf;
2346                 ptr    = putVal32(ptr, opt->u.tracer.mDNSv);
2347                 break;
2348             }
2349         }
2350         return ptr;
2351     }
2352
2353     case kDNSType_NSEC: {
2354         // For NSEC records, rdlength represents the exact number of bytes
2355         // of in memory storage.
2356         mDNSu8 *nsec = (mDNSu8 *)rdb->data;
2357         domainname *name = (domainname *)nsec;
2358         const int dlen = DomainNameLength(name);
2359         nsec += dlen;
2360         // This function is called when we are sending a NSEC record as part of mDNS,
2361         // or to copy the data to any other buffer needed which could be a mDNS or uDNS
2362         // NSEC record. The only time compression is used that when we are sending it
2363         // in mDNS (indicated by non-NULL "msg") and hence we handle mDNS case
2364         // separately.
2365         if (!UNICAST_NSEC(rr))
2366         {
2367             mDNSu8 *save = ptr;
2368             int i, j, wlen;
2369             wlen = *(nsec + 1);
2370             nsec += 2;                     // Skip the window number and len
2371
2372             // For our simplified use of NSEC synthetic records:
2373             //
2374             // nextname is always the record's own name,
2375             // the block number is always 0,
2376             // the count byte is a value in the range 1-32,
2377             // followed by the 1-32 data bytes
2378             //
2379             // Note: When we send the NSEC record in mDNS, the window size is set to 32.
2380             // We need to find out what the last non-NULL byte is.  If we are copying out
2381             // from an RDATA, we have the right length. As we need to handle both the case,
2382             // we loop to find the right value instead of blindly using len to copy.
2383
2384             for (i=wlen; i>0; i--) if (nsec[i-1]) break;
2385
2386             ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
2387             if (!ptr) { LogInfo("putRData: Can't put name, Length %d, record %##s", limit - save, rr->name->c); return(mDNSNULL); }
2388             if (i)                          // Only put a block if at least one type exists for this name
2389             {
2390                 if (ptr + 2 + i > limit) { LogInfo("putRData: Can't put window, Length %d, i %d, record %##s", limit - ptr, i, rr->name->c); return(mDNSNULL); }
2391                 *ptr++ = 0;
2392                 *ptr++ = (mDNSu8)i;
2393                 for (j=0; j<i; j++) *ptr++ = nsec[j];
2394             }
2395             return ptr;
2396         }
2397         else
2398         {
2399             int win, wlen;
2400             int len = rr->rdlength - dlen;
2401
2402             // Sanity check whether the bitmap is good
2403             while (len)
2404             {
2405                 if (len < 3)
2406                 { LogMsg("putRData: invalid length %d", len); return mDNSNULL; }
2407
2408                 win = *nsec++;
2409                 wlen = *nsec++;
2410                 len -= 2;
2411                 if (len < wlen || wlen < 1 || wlen > 32)
2412                 { LogMsg("putRData: invalid window length %d", wlen); return mDNSNULL; }
2413                 if (win < 0 || win >= 256)
2414                 { LogMsg("putRData: invalid window %d", win); return mDNSNULL; }
2415
2416                 nsec += wlen;
2417                 len -= wlen;
2418             }
2419             if (ptr + rr->rdlength > limit) { LogMsg("putRData: NSEC rdlength beyond limit %##s (%s), ptr %p, rdlength %d, limit %p", rr->name->c, DNSTypeName(rr->rrtype), ptr, rr->rdlength, limit); return(mDNSNULL);}
2420
2421             // No compression allowed for "nxt", just copy the data.
2422             mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
2423             return(ptr + rr->rdlength);
2424         }
2425     }
2426
2427     default:            debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
2428         if (ptr + rr->rdlength > limit) return(mDNSNULL);
2429         mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
2430         return(ptr + rr->rdlength);
2431     }
2432 }
2433
2434 #define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update)
2435
2436 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
2437 {
2438     mDNSu8 *endofrdata;
2439     mDNSu16 actualLength;
2440     // When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782)
2441     const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg;
2442
2443     if (rr->RecordType == kDNSRecordTypeUnregistered)
2444     {
2445         LogMsg("PutResourceRecordTTLWithLimit ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
2446         return(ptr);
2447     }
2448
2449     if (!ptr)
2450     {
2451         LogMsg("PutResourceRecordTTLWithLimit ptr is null %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
2452         return(mDNSNULL);
2453     }
2454
2455     ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
2456     // If we're out-of-space, return mDNSNULL
2457     if (!ptr || ptr + 10 >= limit)
2458     {
2459         LogInfo("PutResourceRecordTTLWithLimit: can't put name, out of space %##s (%s), ptr %p, limit %p", rr->name->c,
2460             DNSTypeName(rr->rrtype), ptr, limit);
2461         return(mDNSNULL);
2462     }
2463     ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
2464     ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
2465     ptr[2] = (mDNSu8)(rr->rrclass >> 8);
2466     ptr[3] = (mDNSu8)(rr->rrclass &  0xFF);
2467     ptr[4] = (mDNSu8)((ttl >> 24) &  0xFF);
2468     ptr[5] = (mDNSu8)((ttl >> 16) &  0xFF);
2469     ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
2470     ptr[7] = (mDNSu8)( ttl        &  0xFF);
2471     // ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes
2472
2473     endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr);
2474     if (!endofrdata)
2475     {
2476         LogInfo("PutResourceRecordTTLWithLimit: Ran out of space in PutResourceRecord for %##s (%s), ptr %p, limit %p", rr->name->c,
2477             DNSTypeName(rr->rrtype), ptr+10, limit);
2478         return(mDNSNULL);
2479     }
2480
2481     // Go back and fill in the actual number of data bytes we wrote
2482     // (actualLength can be less than rdlength when domain name compression is used)
2483     actualLength = (mDNSu16)(endofrdata - ptr - 10);
2484     ptr[8] = (mDNSu8)(actualLength >> 8);
2485     ptr[9] = (mDNSu8)(actualLength &  0xFF);
2486
2487     if (count) (*count)++;
2488     else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
2489     return(endofrdata);
2490 }
2491
2492 mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr)
2493 {
2494     ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
2495     if (!ptr || ptr + 10 > limit) return(mDNSNULL);     // If we're out-of-space, return mDNSNULL
2496     ptr[0] = (mDNSu8)(rr->resrec.rrtype  >> 8);             // Put type
2497     ptr[1] = (mDNSu8)(rr->resrec.rrtype  &  0xFF);
2498     ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8);             // Put class
2499     ptr[3] = (mDNSu8)(rr->resrec.rrclass &  0xFF);
2500     ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0;              // TTL is zero
2501     ptr[8] = ptr[9] = 0;                                // RDATA length is zero
2502     (*count)++;
2503     return(ptr + 10);
2504 }
2505
2506 mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
2507 {
2508     ptr = putDomainNameAsLabels(msg, ptr, limit, name);
2509     if (!ptr || ptr+4 >= limit) return(mDNSNULL);           // If we're out-of-space, return mDNSNULL
2510     ptr[0] = (mDNSu8)(rrtype  >> 8);
2511     ptr[1] = (mDNSu8)(rrtype  &  0xFF);
2512     ptr[2] = (mDNSu8)(rrclass >> 8);
2513     ptr[3] = (mDNSu8)(rrclass &  0xFF);
2514     msg->h.numQuestions++;
2515     return(ptr+4);
2516 }
2517
2518 // for dynamic updates
2519 mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
2520 {
2521     ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
2522     if (!ptr || ptr + 4 > limit) return mDNSNULL;       // If we're out-of-space, return NULL
2523     *ptr++ = (mDNSu8)(kDNSType_SOA  >> 8);
2524     *ptr++ = (mDNSu8)(kDNSType_SOA  &  0xFF);
2525     *ptr++ = zoneClass.b[0];
2526     *ptr++ = zoneClass.b[1];
2527     msg->h.mDNS_numZones++;
2528     return ptr;
2529 }
2530
2531 // for dynamic updates
2532 mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end)
2533 {
2534     AuthRecord prereq;
2535     mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
2536     AssignDomainName(&prereq.namestorage, name);
2537     prereq.resrec.rrtype = kDNSQType_ANY;
2538     prereq.resrec.rrclass = kDNSClass_NONE;
2539     return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
2540 }
2541
2542 // for dynamic updates
2543 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
2544 {
2545     // deletion: specify record w/ TTL 0, class NONE
2546     const mDNSu16 origclass = rr->rrclass;
2547     rr->rrclass = kDNSClass_NONE;
2548     ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
2549     rr->rrclass = origclass;
2550     return ptr;
2551 }
2552
2553 // for dynamic updates
2554 mDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit)
2555 {
2556     // deletion: specify record w/ TTL 0, class NONE
2557     const mDNSu16 origclass = rr->rrclass;
2558     rr->rrclass = kDNSClass_NONE;
2559     ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit);
2560     rr->rrclass = origclass;
2561     return ptr;
2562 }
2563
2564 mDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit)
2565 {
2566     mDNSu16 class = kDNSQClass_ANY;
2567
2568     ptr = putDomainNameAsLabels(msg, ptr, limit, name);
2569     if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
2570     ptr[0] = (mDNSu8)(rrtype  >> 8);
2571     ptr[1] = (mDNSu8)(rrtype  &  0xFF);
2572     ptr[2] = (mDNSu8)(class >> 8);
2573     ptr[3] = (mDNSu8)(class &  0xFF);
2574     ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
2575     ptr[8] = ptr[9] = 0; // zero rdlength/rdata
2576
2577     msg->h.mDNS_numUpdates++;
2578     return ptr + 10;
2579 }
2580
2581 // for dynamic updates
2582 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
2583 {
2584     const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
2585     mDNSu16 class = kDNSQClass_ANY;
2586     mDNSu16 rrtype = kDNSQType_ANY;
2587
2588     ptr = putDomainNameAsLabels(msg, ptr, limit, name);
2589     if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
2590     ptr[0] = (mDNSu8)(rrtype >> 8);
2591     ptr[1] = (mDNSu8)(rrtype &  0xFF);
2592     ptr[2] = (mDNSu8)(class >> 8);
2593     ptr[3] = (mDNSu8)(class &  0xFF);
2594     ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
2595     ptr[8] = ptr[9] = 0; // zero rdlength/rdata
2596
2597     msg->h.mDNS_numUpdates++;
2598     return ptr + 10;
2599 }
2600
2601 // for dynamic updates
2602 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease)
2603 {
2604     AuthRecord rr;
2605     mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
2606     rr.resrec.rrclass    = NormalMaxDNSMessageData;
2607     rr.resrec.rdlength   = sizeof(rdataOPT);    // One option in this OPT record
2608     rr.resrec.rdestimate = sizeof(rdataOPT);
2609     rr.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
2610     rr.resrec.rdata->u.opt[0].u.updatelease = lease;
2611     ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0);
2612     if (!ptr) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
2613     return ptr;
2614 }
2615
2616 // for dynamic updates
2617 mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit)
2618 {
2619     AuthRecord rr;
2620     mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
2621     rr.resrec.rrclass    = NormalMaxDNSMessageData;
2622     rr.resrec.rdlength   = sizeof(rdataOPT);    // One option in this OPT record
2623     rr.resrec.rdestimate = sizeof(rdataOPT);
2624     rr.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
2625     rr.resrec.rdata->u.opt[0].u.updatelease = lease;
2626     ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0, limit);
2627     if (!ptr) { LogMsg("ERROR: putUpdateLeaseWithLimit - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
2628     return ptr;
2629 }
2630
2631 mDNSexport mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit)
2632 {
2633     AuthRecord rr;
2634     mDNSu32 ttl = 0;
2635
2636     mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
2637     // It is still not clear what the right size is. We will have to fine tune this once we do
2638     // a lot of testing with DNSSEC.
2639     rr.resrec.rrclass    = 4096;
2640     rr.resrec.rdlength   = 0;
2641     rr.resrec.rdestimate = 0;
2642     // set the DO bit
2643     ttl |= 0x8000;
2644     end = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &rr.resrec, ttl, limit);
2645     if (!end) { LogMsg("ERROR: putDNSSECOption - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
2646     return end;
2647 }
2648
2649 mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
2650 {
2651     if (authInfo && authInfo->AutoTunnel)
2652     {
2653         AuthRecord hinfo;
2654         mDNSu8 *h = hinfo.rdatastorage.u.data;
2655         mDNSu16 len = 2 + m->HIHardware.c[0] + m->HISoftware.c[0];
2656         mDNSu8 *newptr;
2657         mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
2658         AppendDomainLabel(&hinfo.namestorage, &m->hostlabel);
2659         AppendDomainName (&hinfo.namestorage, &authInfo->domain);
2660         hinfo.resrec.rroriginalttl = 0;
2661         mDNSPlatformMemCopy(h, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
2662         h += 1 + (int)h[0];
2663         mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
2664         hinfo.resrec.rdlength   = len;
2665         hinfo.resrec.rdestimate = len;
2666         newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
2667         return newptr;
2668     }
2669     else
2670         return end;
2671 }
2672
2673 // ***************************************************************************
2674 #if COMPILER_LIKES_PRAGMA_MARK
2675 #pragma mark -
2676 #pragma mark - DNS Message Parsing Functions
2677 #endif
2678
2679 mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name)
2680 {
2681     mDNSu32 sum = 0;
2682     const mDNSu8 *c;
2683
2684     for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
2685     {
2686         sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
2687                (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
2688         sum = (sum<<3) | (sum>>29);
2689     }
2690     if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
2691     return(sum);
2692 }
2693
2694 mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
2695 {
2696     domainname *target;
2697     if (NewRData)
2698     {
2699         rr->rdata    = NewRData;
2700         rr->rdlength = rdlength;
2701     }
2702     // Must not try to get target pointer until after updating rr->rdata
2703     target = GetRRDomainNameTarget(rr);
2704     rr->rdlength   = GetRDLength(rr, mDNSfalse);
2705     rr->rdestimate = GetRDLength(rr, mDNStrue);
2706     rr->rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr);
2707 }
2708
2709 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
2710 {
2711     mDNSu16 total = 0;
2712
2713     if (ptr < (mDNSu8*)msg || ptr >= end)
2714     { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
2715
2716     while (1)                       // Read sequence of labels
2717     {
2718         const mDNSu8 len = *ptr++;  // Read length of this label
2719         if (len == 0) return(ptr);  // If length is zero, that means this name is complete
2720         switch (len & 0xC0)
2721         {
2722         case 0x00:  if (ptr + len >= end)                       // Remember: expect at least one more byte for the root label
2723             { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
2724             if (total + 1 + len >= MAX_DOMAIN_NAME)             // Remember: expect at least one more byte for the root label
2725             { debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
2726             ptr += len;
2727             total += 1 + len;
2728             break;
2729
2730         case 0x40:  debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
2731         case 0x80:  debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
2732         case 0xC0:  return(ptr+1);
2733         }
2734     }
2735 }
2736
2737 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
2738 mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
2739                                        domainname *const name)
2740 {
2741     const mDNSu8 *nextbyte = mDNSNULL;                  // Record where we got to before we started following pointers
2742     mDNSu8       *np = name->c;                         // Name pointer
2743     const mDNSu8 *const limit = np + MAX_DOMAIN_NAME;   // Limit so we don't overrun buffer
2744
2745     if (ptr < (mDNSu8*)msg || ptr >= end)
2746     { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
2747
2748     *np = 0;                        // Tentatively place the root label here (may be overwritten if we have more labels)
2749
2750     while (1)                       // Read sequence of labels
2751     {
2752                 int i;
2753                 mDNSu16 offset;
2754         const mDNSu8 len = *ptr++;  // Read length of this label
2755         if (len == 0) break;        // If length is zero, that means this name is complete
2756         switch (len & 0xC0)
2757         {
2758
2759         case 0x00:  if (ptr + len >= end)           // Remember: expect at least one more byte for the root label
2760             { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
2761             if (np + 1 + len >= limit)              // Remember: expect at least one more byte for the root label
2762             { debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
2763             *np++ = len;
2764             for (i=0; i<len; i++) *np++ = *ptr++;
2765             *np = 0;                // Tentatively place the root label here (may be overwritten if we have more labels)
2766             break;
2767
2768         case 0x40:  debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
2769             return(mDNSNULL);
2770
2771         case 0x80:  debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
2772
2773         case 0xC0:  if (ptr >= end)
2774             { debugf("getDomainName: Malformed compression label (overruns packet end)"); return(mDNSNULL); }
2775             offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
2776             if (!nextbyte) nextbyte = ptr;              // Record where we got to before we started following pointers
2777             ptr = (mDNSu8 *)msg + offset;
2778             if (ptr < (mDNSu8*)msg || ptr >= end)
2779             { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
2780             if (*ptr & 0xC0)
2781             { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
2782             break;
2783         }
2784     }
2785
2786     if (nextbyte) return(nextbyte);
2787     else return(ptr);
2788 }
2789
2790 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
2791 {
2792     mDNSu16 pktrdlength;
2793
2794     ptr = skipDomainName(msg, ptr, end);
2795     if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
2796
2797     if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
2798     pktrdlength = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
2799     ptr += 10;
2800     if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
2801
2802     return(ptr + pktrdlength);
2803 }
2804
2805 // Sanity check whether the NSEC/NSEC3 bitmap is good
2806 mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int len)
2807 {
2808     int win, wlen;
2809
2810     while (bmap < end)
2811     {
2812         if (len < 3)
2813         {
2814             LogInfo("SanityCheckBitMap: invalid length %d", len);
2815             return mDNSNULL;
2816         }
2817
2818         win = *bmap++;
2819         wlen = *bmap++;
2820         len -= 2;
2821         if (len < wlen || wlen < 1 || wlen > 32)
2822         {
2823             LogInfo("SanityCheckBitMap: invalid window length %d", wlen);
2824             return mDNSNULL;
2825         }
2826         if (win < 0 || win >= 256)
2827         {
2828             LogInfo("SanityCheckBitMap: invalid window %d", win);
2829             return mDNSNULL;
2830         }
2831
2832         bmap += wlen;
2833         len -= wlen;
2834     }
2835     return (mDNSu8 *)bmap;
2836 }
2837
2838 // This function is called with "msg" when we receive a DNS message and needs to parse a single resource record
2839 // pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded
2840 // (domainnames are expanded to 255 bytes) when stored in memory.
2841 //
2842 // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
2843 // The caller can do this only if the names in the resource records are not compressed and validity of the
2844 // resource record has already been done before. DNSSEC currently uses it this way.
2845 mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end,
2846     LargeCacheRecord *const largecr, mDNSu16 rdlength)
2847 {
2848     CacheRecord *const rr = &largecr->r;
2849     RDataBody2 *const rdb = (RDataBody2 *)rr->smallrdatastorage.data;
2850
2851     switch (rr->resrec.rrtype)
2852     {
2853     case kDNSType_A:
2854         if (rdlength != sizeof(mDNSv4Addr))
2855             goto fail;
2856         rdb->ipv4.b[0] = ptr[0];
2857         rdb->ipv4.b[1] = ptr[1];
2858         rdb->ipv4.b[2] = ptr[2];
2859         rdb->ipv4.b[3] = ptr[3];
2860         break;
2861
2862     case kDNSType_NS:
2863     case kDNSType_MD:
2864     case kDNSType_MF:
2865     case kDNSType_CNAME:
2866     case kDNSType_MB:
2867     case kDNSType_MG:
2868     case kDNSType_MR:
2869     case kDNSType_PTR:
2870     case kDNSType_NSAP_PTR:
2871     case kDNSType_DNAME:
2872         if (msg)
2873         {
2874             ptr = getDomainName(msg, ptr, end, &rdb->name);
2875         }
2876         else
2877         {
2878             AssignDomainName(&rdb->name, (domainname *)ptr);
2879             ptr += DomainNameLength(&rdb->name);
2880         }
2881         if (ptr != end)
2882         {
2883             debugf("SetRData: Malformed CNAME/PTR RDATA name");
2884             goto fail;
2885         }
2886         break;
2887
2888     case kDNSType_SOA:
2889         if (msg)
2890         {
2891             ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
2892         }
2893         else
2894         {
2895             AssignDomainName(&rdb->soa.mname, (domainname *)ptr);
2896             ptr += DomainNameLength(&rdb->soa.mname);
2897         }
2898         if (!ptr)
2899         {
2900             debugf("SetRData: Malformed SOA RDATA mname");
2901             goto fail;
2902         }
2903         if (msg)
2904         {
2905             ptr = getDomainName(msg, ptr, end, &rdb->soa.rname);
2906         }
2907         else
2908         {
2909             AssignDomainName(&rdb->soa.rname, (domainname *)ptr);
2910             ptr += DomainNameLength(&rdb->soa.rname);
2911         }
2912         if (!ptr)
2913         {
2914             debugf("SetRData: Malformed SOA RDATA rname");
2915             goto fail;
2916         }
2917         if (ptr + 0x14 != end)
2918         {
2919             debugf("SetRData: Malformed SOA RDATA");
2920             goto fail;
2921         }
2922         rdb->soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
2923         rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
2924         rdb->soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
2925         rdb->soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
2926         rdb->soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
2927         break;
2928
2929     case kDNSType_NULL:
2930     case kDNSType_HINFO:
2931     case kDNSType_TXT:
2932     case kDNSType_X25:
2933     case kDNSType_ISDN:
2934     case kDNSType_LOC:
2935     case kDNSType_DHCID:
2936         rr->resrec.rdlength = rdlength;
2937         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
2938         break;
2939
2940     case kDNSType_MX:
2941     case kDNSType_AFSDB:
2942     case kDNSType_RT:
2943     case kDNSType_KX:
2944         // Preference + domainname
2945         if (rdlength < 3)
2946             goto fail;
2947         rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
2948         ptr += 2;
2949         if (msg)
2950         {
2951             ptr = getDomainName(msg, ptr, end, &rdb->mx.exchange);
2952         }
2953         else
2954         {
2955             AssignDomainName(&rdb->mx.exchange, (domainname *)ptr);
2956             ptr += DomainNameLength(&rdb->mx.exchange);
2957         }
2958         if (ptr != end)
2959         {
2960             debugf("SetRData: Malformed MX name");
2961             goto fail;
2962         }
2963         break;
2964
2965     case kDNSType_MINFO:
2966     case kDNSType_RP:
2967         // Domainname + domainname
2968         if (msg)
2969         {
2970             ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox);
2971         }
2972         else
2973         {
2974             AssignDomainName(&rdb->rp.mbox, (domainname *)ptr);
2975             ptr += DomainNameLength(&rdb->rp.mbox);
2976         }
2977         if (!ptr)
2978         {
2979             debugf("SetRData: Malformed RP mbox");
2980             goto fail;
2981         }
2982         if (msg)
2983         {
2984             ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
2985         }
2986         else
2987         {
2988             AssignDomainName(&rdb->rp.txt, (domainname *)ptr);
2989             ptr += DomainNameLength(&rdb->rp.txt);
2990         }
2991         if (ptr != end)
2992         {
2993             debugf("SetRData: Malformed RP txt");
2994             goto fail;
2995         }
2996         break;
2997
2998     case kDNSType_PX:
2999         // Preference + domainname + domainname
3000         if (rdlength < 4)
3001             goto fail;
3002         rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3003         ptr += 2;
3004         if (msg)
3005         {
3006             ptr = getDomainName(msg, ptr, end, &rdb->px.map822);
3007         }
3008         else
3009         {
3010             AssignDomainName(&rdb->px.map822, (domainname *)ptr);
3011             ptr += DomainNameLength(&rdb->px.map822);
3012         }
3013         if (!ptr)
3014         {
3015             debugf("SetRData: Malformed PX map822");
3016             goto fail;
3017         }
3018         if (msg)
3019         {
3020             ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
3021         }
3022         else
3023         {
3024             AssignDomainName(&rdb->px.mapx400, (domainname *)ptr);
3025             ptr += DomainNameLength(&rdb->px.mapx400);
3026         }
3027         if (ptr != end)
3028         {
3029             debugf("SetRData: Malformed PX mapx400");
3030             goto fail;
3031         }
3032         break;
3033
3034     case kDNSType_AAAA:
3035         if (rdlength != sizeof(mDNSv6Addr))
3036             goto fail;
3037         mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
3038         break;
3039
3040     case kDNSType_SRV:
3041         // Priority + weight + port + domainname
3042         if (rdlength < 7)
3043             goto fail;
3044         rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3045         rdb->srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
3046         rdb->srv.port.b[0] = ptr[4];
3047         rdb->srv.port.b[1] = ptr[5];
3048         ptr += 6;
3049         if (msg)
3050         {
3051             ptr = getDomainName(msg, ptr, end, &rdb->srv.target);
3052         }
3053         else
3054         {
3055             AssignDomainName(&rdb->srv.target, (domainname *)ptr);
3056             ptr += DomainNameLength(&rdb->srv.target);
3057         }
3058         if (ptr != end)
3059         {
3060             debugf("SetRData: Malformed SRV RDATA name");
3061             goto fail;
3062         }
3063         break;
3064
3065     case kDNSType_NAPTR:
3066     {
3067         int savelen, len;
3068         domainname name;
3069         const mDNSu8 *orig = ptr;
3070
3071         // Make sure the data is parseable and within the limits. DNSSEC code looks at
3072         // the domain name in the end for a valid domainname.
3073         //
3074         // Fixed length: Order, preference (4 bytes)
3075         // Variable length: flags, service, regexp, domainname
3076
3077         if (rdlength < 8)
3078             goto fail;
3079         // Order, preference.
3080         ptr += 4;
3081         // Parse flags, Service and Regexp
3082         // length in the first byte does not include the length byte itself
3083         len = *ptr + 1;
3084         ptr += len;
3085         if (ptr >= end)
3086         {
3087             LogInfo("SetRData: Malformed NAPTR flags");
3088             goto fail;
3089         }
3090
3091         // Service
3092         len = *ptr + 1;
3093         ptr += len;
3094         if (ptr >= end)
3095         {
3096             LogInfo("SetRData: Malformed NAPTR service");
3097             goto fail;
3098         }
3099
3100         // Regexp
3101         len = *ptr + 1;
3102         ptr += len;
3103         if (ptr >= end)
3104         {
3105             LogInfo("SetRData: Malformed NAPTR regexp");
3106             goto fail;
3107         }
3108
3109         savelen = ptr - orig;
3110
3111         // RFC 2915 states that name compression is not allowed for this field. But RFC 3597
3112         // states that for NAPTR we should decompress. We make sure that we store the full
3113         // name rather than the compressed name
3114         if (msg)
3115         {
3116             ptr = getDomainName(msg, ptr, end, &name);
3117         }
3118         else
3119         {
3120             AssignDomainName(&name, (domainname *)ptr);
3121             ptr += DomainNameLength(&name);
3122         }
3123         if (ptr != end)
3124         {
3125             LogInfo("SetRData: Malformed NAPTR RDATA name");
3126             goto fail;
3127         }
3128
3129         rr->resrec.rdlength = savelen + DomainNameLength(&name);
3130         // The uncompressed size should not exceed the limits
3131         if (rr->resrec.rdlength > MaximumRDSize)
3132         {
3133             LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->resrec.rdlength %d, "
3134                     "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
3135             goto fail;
3136         }
3137         mDNSPlatformMemCopy(rdb->data, orig, savelen);
3138         AssignDomainName((domainname *)(rdb->data + savelen), &name);
3139         break;
3140     }
3141     case kDNSType_OPT:  {
3142         mDNSu8 *dataend     = rr->resrec.rdata->u.data;
3143         rdataOPT *opt = rr->resrec.rdata->u.opt;
3144         rr->resrec.rdlength = 0;
3145         while (ptr < end && (mDNSu8 *)(opt+1) < &dataend[MaximumRDSize])
3146         {
3147             const rdataOPT *const currentopt = opt;
3148             if (ptr + 4 > end) { LogInfo("SetRData: OPT RDATA ptr + 4 > end"); goto fail; }
3149             opt->opt    = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3150             opt->optlen = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
3151             ptr += 4;
3152             if (ptr + opt->optlen > end) { LogInfo("SetRData: ptr + opt->optlen > end"); goto fail; }
3153             switch (opt->opt)
3154             {
3155             case kDNSOpt_LLQ:
3156                 if (opt->optlen == DNSOpt_LLQData_Space - 4)
3157                 {
3158                     opt->u.llq.vers  = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
3159                     opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
3160                     opt->u.llq.err   = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
3161                     mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8);
3162                     opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]);
3163                     if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
3164                         opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
3165                     opt++;
3166                 }
3167                 break;
3168             case kDNSOpt_Lease:
3169                 if (opt->optlen == DNSOpt_LeaseData_Space - 4)
3170                 {
3171                     opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
3172                     if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
3173                         opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
3174                     opt++;
3175                 }
3176                 break;
3177             case kDNSOpt_Owner:
3178                 if (ValidOwnerLength(opt->optlen))
3179                 {
3180                     opt->u.owner.vers = ptr[0];
3181                     opt->u.owner.seq  = ptr[1];
3182                     mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6);                         // 6-byte MAC address
3183                     mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6);                         // 6-byte MAC address
3184                     opt->u.owner.password = zeroEthAddr;
3185                     if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
3186                     {
3187                         mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6);                     // 6-byte MAC address
3188                         // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above
3189                         // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4
3190                         if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
3191                             mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
3192                     }
3193                     opt++;
3194                 }
3195                 break;
3196             case kDNSOpt_Trace:
3197                 if (opt->optlen == DNSOpt_TraceData_Space - 4)
3198                 {
3199                     opt->u.tracer.platf   = ptr[0];
3200                     opt->u.tracer.mDNSv   = (mDNSu32) ((mDNSu32)ptr[1] << 24 | (mDNSu32)ptr[2] << 16 | (mDNSu32)ptr[3] << 8 | ptr[4]);
3201                     opt++;
3202                 }
3203                 else
3204                 {
3205                     opt->u.tracer.platf   = 0xFF;
3206                     opt->u.tracer.mDNSv   = 0xFFFFFFFF;
3207                     opt++;
3208                 }
3209                 break;
3210             }
3211             ptr += currentopt->optlen;
3212         }
3213         rr->resrec.rdlength = (mDNSu16)((mDNSu8*)opt - rr->resrec.rdata->u.data);
3214         if (ptr != end) { LogInfo("SetRData: Malformed OptRdata"); goto fail; }
3215         break;
3216     }
3217
3218     case kDNSType_NSEC: {
3219         domainname name;
3220         int len = rdlength;
3221         int bmaplen, dlen;
3222         const mDNSu8 *orig = ptr;
3223         const mDNSu8 *bmap;
3224
3225         if (msg)
3226         {
3227             ptr = getDomainName(msg, ptr, end, &name);
3228         }
3229         else
3230         {
3231             AssignDomainName(&name, (domainname *)ptr);
3232             ptr += DomainNameLength(&name);
3233         }
3234         if (!ptr)
3235         {
3236             LogInfo("SetRData: Malformed NSEC nextname");
3237             goto fail;
3238         }
3239
3240         dlen = DomainNameLength(&name);
3241
3242         // Multicast NSECs use name compression for this field unlike the unicast case which
3243         // does not use compression. And multicast case always succeeds in compression. So,
3244         // the rdlength includes only the compressed space in that case. So, can't
3245         // use the DomainNameLength of name to reduce the length here.
3246         len -= (ptr - orig);
3247         bmaplen = len;                  // Save the length of the bitmap
3248         bmap = ptr;
3249         ptr = SanityCheckBitMap(bmap, end, len);
3250         if (!ptr)
3251             goto fail;
3252         if (ptr != end)
3253         {
3254             LogInfo("SetRData: Malformed NSEC length not right");
3255             goto fail;
3256         }
3257
3258         // Initialize the right length here. When we call SetNewRData below which in turn calls
3259         // GetRDLength and for NSEC case, it assumes that rdlength is intitialized
3260         rr->resrec.rdlength = DomainNameLength(&name) + bmaplen;
3261
3262         // Do we have space after the name expansion ?
3263         if (rr->resrec.rdlength > MaximumRDSize)
3264         {
3265             LogInfo("SetRData: Malformed NSEC rdlength %d, rr->resrec.rdlength %d, "
3266                     "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
3267             goto fail;
3268         }
3269         AssignDomainName((domainname *)rdb->data, &name);
3270         mDNSPlatformMemCopy(rdb->data + dlen, bmap, bmaplen);
3271         break;
3272     }
3273     case kDNSType_NSEC3:
3274     {
3275         rdataNSEC3 *nsec3 = (rdataNSEC3 *)ptr;
3276         mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
3277         int hashLength, bitmaplen;
3278
3279         if (rdlength < NSEC3_FIXED_SIZE + 1)
3280         {
3281             LogInfo("SetRData: NSEC3 too small length %d", rdlength);
3282             goto fail;
3283         }
3284         if (nsec3->alg != SHA1_DIGEST_TYPE)
3285         {
3286             LogInfo("SetRData: nsec3 alg %d not supported", nsec3->alg);
3287             goto fail;
3288         }
3289         if (swap16(nsec3->iterations) > NSEC3_MAX_ITERATIONS)
3290         {
3291             LogInfo("SetRData: nsec3 iteration count %d too big", swap16(nsec3->iterations));
3292             goto fail;
3293         } 
3294         p += nsec3->saltLength;
3295         // There should at least be one byte beyond saltLength
3296         if (p >= end)
3297         {
3298             LogInfo("SetRData: nsec3 too small, at saltlength %d, p %p, end %p", nsec3->saltLength, p, end);
3299             goto fail;
3300         }
3301         // p is pointing at hashLength
3302         hashLength = (int)*p++;
3303         if (!hashLength)
3304         {
3305             LogInfo("SetRData: hashLength zero");
3306             goto fail;
3307         }
3308         p += hashLength;
3309         if (p > end)
3310         {
3311             LogInfo("SetRData: nsec3 too small, at hashLength %d, p %p, end %p", hashLength, p, end);
3312             goto fail;
3313         }
3314
3315         bitmaplen = rdlength - (int)(p - ptr);
3316         p = SanityCheckBitMap(p, end, bitmaplen);
3317         if (!p)
3318             goto fail;
3319         rr->resrec.rdlength = rdlength;
3320         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3321         break;
3322     }
3323     case kDNSType_TKEY:
3324     case kDNSType_TSIG:
3325     {
3326         domainname name;
3327         int dlen, rlen;
3328
3329         // The name should not be compressed. But we take the conservative approach
3330         // and uncompress the name before we store it.
3331         if (msg)
3332         {
3333             ptr = getDomainName(msg, ptr, end, &name);
3334         }
3335         else
3336         {
3337             AssignDomainName(&name, (domainname *)ptr);
3338             ptr += DomainNameLength(&name);
3339         }
3340         if (!ptr || ptr >= end)
3341         {
3342             LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->resrec.rrtype);
3343             goto fail;
3344         }
3345         dlen = DomainNameLength(&name);
3346         rlen = end - ptr;
3347         rr->resrec.rdlength = dlen + rlen;
3348         if (rr->resrec.rdlength > MaximumRDSize)
3349         {
3350             LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->resrec.rdlength %d, "
3351                     "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
3352             goto fail;
3353         }
3354         AssignDomainName((domainname *)rdb->data, &name);
3355         mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen);
3356         break;
3357     }
3358     case kDNSType_RRSIG:
3359     {
3360         const mDNSu8 *sig = ptr + RRSIG_FIXED_SIZE;
3361         const mDNSu8 *orig = sig;
3362         domainname name;
3363         if (rdlength < RRSIG_FIXED_SIZE + 1)
3364         {
3365             LogInfo("SetRData: RRSIG too small length %d", rdlength);
3366             goto fail;
3367         }
3368         if (msg)
3369         {
3370             sig = getDomainName(msg, sig, end, &name);
3371         }
3372         else
3373         {
3374             AssignDomainName(&name, (domainname *)sig);
3375             sig += DomainNameLength(&name);
3376         }
3377         if (!sig)
3378         {
3379             LogInfo("SetRData: Malformed RRSIG record");
3380             goto fail;
3381         }
3382
3383         if ((sig - orig) != DomainNameLength(&name))
3384         {
3385             LogInfo("SetRData: Malformed RRSIG record, signer name compression");
3386             goto fail;
3387         }
3388         // Just ensure that we have at least one byte of the signature
3389         if (sig + 1 >= end)
3390         {
3391             LogInfo("SetRData: Not enough bytes for signature type %d", rr->resrec.rrtype);
3392             goto fail;
3393         }
3394         rr->resrec.rdlength = rdlength;
3395         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3396         break;
3397     }
3398     case kDNSType_DNSKEY:
3399     {
3400         if (rdlength < DNSKEY_FIXED_SIZE + 1)
3401         {
3402             LogInfo("SetRData: DNSKEY too small length %d", rdlength);
3403             goto fail;
3404         }
3405         rr->resrec.rdlength = rdlength;
3406         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3407         break;
3408     }
3409     case kDNSType_DS:
3410     {
3411         if (rdlength < DS_FIXED_SIZE + 1)
3412         {
3413             LogInfo("SetRData: DS too small length %d", rdlength);
3414             goto fail;
3415         }
3416         rr->resrec.rdlength = rdlength;
3417         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3418         break;
3419     }
3420     default:
3421         debugf("SetRData: Warning! Reading resource type %d (%s) as opaque data",
3422                rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
3423         // Note: Just because we don't understand the record type, that doesn't
3424         // mean we fail. The DNS protocol specifies rdlength, so we can
3425         // safely skip over unknown records and ignore them.
3426         // We also grab a binary copy of the rdata anyway, since the caller
3427         // might know how to interpret it even if we don't.
3428         rr->resrec.rdlength = rdlength;
3429         mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3430         break;
3431     }
3432     return mDNStrue;
3433 fail:
3434     return mDNSfalse;
3435 }
3436
3437 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
3438                                                 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr)
3439 {
3440     CacheRecord *const rr = &largecr->r;
3441     mDNSu16 pktrdlength;
3442
3443     if (largecr == &m->rec && m->rec.r.resrec.RecordType)
3444         LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
3445
3446     rr->next              = mDNSNULL;
3447     rr->resrec.name       = &largecr->namestorage;
3448
3449     rr->NextInKAList      = mDNSNULL;
3450     rr->TimeRcvd          = m ? m->timenow : 0;
3451     rr->DelayDelivery     = 0;
3452     rr->NextRequiredQuery = m ? m->timenow : 0;     // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
3453     rr->LastUsed          = m ? m->timenow : 0;
3454     rr->CRActiveQuestion  = mDNSNULL;
3455     rr->UnansweredQueries = 0;
3456     rr->LastUnansweredTime= 0;
3457     rr->NextInCFList      = mDNSNULL;
3458
3459     rr->resrec.InterfaceID       = InterfaceID;
3460     rr->resrec.rDNSServer = mDNSNULL;
3461
3462     ptr = getDomainName(msg, ptr, end, &largecr->namestorage);      // Will bail out correctly if ptr is NULL
3463     if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
3464     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
3465
3466     if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
3467
3468     rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
3469     rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
3470     rr->resrec.rroriginalttl     = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
3471     if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1)
3472         rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
3473     // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
3474     // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
3475     pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
3476
3477     // If mDNS record has cache-flush bit set, we mark it unique
3478     // For uDNS records, all are implicitly deemed unique (a single DNS server is always authoritative for the entire RRSet)
3479     if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || !InterfaceID)
3480         RecordType |= kDNSRecordTypePacketUniqueMask;
3481     ptr += 10;
3482     if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
3483     end = ptr + pktrdlength;        // Adjust end to indicate the end of the rdata for this resource record
3484
3485     rr->resrec.rdata = (RData*)&rr->smallrdatastorage;
3486     rr->resrec.rdata->MaxRDLength = MaximumRDSize;
3487
3488     if (pktrdlength > MaximumRDSize)
3489     {
3490         LogInfo("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
3491                 DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
3492         goto fail;
3493     }
3494
3495     if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
3496
3497     // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding
3498     // cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind
3499     // bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data.
3500     // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that
3501     // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
3502     if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0)   // Used in update packets to mean "Delete An RRset" (RFC 2136)
3503         rr->resrec.rdlength = 0;
3504     else if (!SetRData(msg, ptr, end, largecr, pktrdlength))
3505         goto fail;
3506
3507     SetNewRData(&rr->resrec, mDNSNULL, 0);      // Sets rdlength, rdestimate, rdatahash for us
3508
3509     // Success! Now fill in RecordType to show this record contains valid data
3510     rr->resrec.RecordType = RecordType;
3511     return(end);
3512
3513 fail:
3514     // If we were unable to parse the rdata in this record, we indicate that by
3515     // returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero
3516     rr->resrec.RecordType = kDNSRecordTypePacketNegative;
3517     rr->resrec.rdlength   = 0;
3518     rr->resrec.rdestimate = 0;
3519     rr->resrec.rdatahash  = 0;
3520     return(end);
3521 }
3522
3523 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
3524 {
3525     ptr = skipDomainName(msg, ptr, end);
3526     if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
3527     if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
3528     return(ptr+4);
3529 }
3530
3531 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
3532                                      DNSQuestion *question)
3533 {
3534     mDNSPlatformMemZero(question, sizeof(*question));
3535     question->InterfaceID = InterfaceID;
3536     if (!InterfaceID) question->TargetQID = onesID; // In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast
3537     ptr = getDomainName(msg, ptr, end, &question->qname);
3538     if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
3539     if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
3540
3541     question->qnamehash = DomainNameHashValue(&question->qname);
3542     question->qtype  = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);            // Get type
3543     question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);            // and class
3544     return(ptr+4);
3545 }
3546
3547 mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
3548 {
3549     int i;
3550     const mDNSu8 *ptr = msg->data;
3551     for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
3552     return(ptr);
3553 }
3554
3555 mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
3556 {
3557     int i;
3558     const mDNSu8 *ptr = LocateAnswers(msg, end);
3559     for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
3560     return(ptr);
3561 }
3562
3563 mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end)
3564 {
3565     int i;
3566     const mDNSu8 *ptr = LocateAuthorities(msg, end);
3567     for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end);
3568     return (ptr);
3569 }
3570
3571 mDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize)
3572 {
3573     int i;
3574     const mDNSu8 *ptr = LocateAdditionals(msg, end);
3575
3576     // Locate the OPT record.
3577     // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
3578     // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
3579     // but not necessarily the *last* entry in the Additional Section.
3580     for (i = 0; ptr && i < msg->h.numAdditionals; i++)
3581     {
3582         if (ptr + DNSOpt_Header_Space + minsize <= end &&   // Make sure we have 11+minsize bytes of data
3583             ptr[0] == 0                                &&   // Name must be root label
3584             ptr[1] == (kDNSType_OPT >> 8  )            &&   // rrtype OPT
3585             ptr[2] == (kDNSType_OPT & 0xFF)            &&
3586             ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)minsize)
3587             return(ptr);
3588         else
3589             ptr = skipResourceRecord(msg, ptr, end);
3590     }
3591     return(mDNSNULL);
3592 }
3593
3594 // On success, GetLLQOptData returns pointer to storage within shared "m->rec";
3595 // it is caller's responsibilty to clear m->rec.r.resrec.RecordType after use
3596 // Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together
3597 // The code that currently calls this assumes there's only one, instead of iterating through the set
3598 mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end)
3599 {
3600     const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space);
3601     if (ptr)
3602     {
3603         ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
3604         if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]);
3605     }
3606     return(mDNSNULL);
3607 }
3608
3609 // Get the lease life of records in a dynamic update
3610 mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease)
3611 {
3612     const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
3613     if (ptr)
3614     {
3615         ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
3616         if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
3617         {
3618             const rdataOPT *o;
3619             const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
3620             for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
3621                 if (o->opt == kDNSOpt_Lease)
3622                 {
3623                     *lease = o->u.updatelease;
3624                     m->rec.r.resrec.RecordType = 0;     // Clear RecordType to show we're not still using it
3625                     return mDNStrue;
3626                 }
3627         }
3628         m->rec.r.resrec.RecordType = 0;     // Clear RecordType to show we're not still using it
3629     }
3630     return mDNSfalse;
3631 }
3632
3633 mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
3634 {
3635     int i;
3636     LogInfo("%2d %s", count, label);
3637     for (i = 0; i < count && ptr; i++)
3638     {
3639         // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage,
3640         // but since it's only used for debugging (and probably only on OS X, not on
3641         // embedded systems) putting a 9kB object on the stack isn't a big problem.
3642         LargeCacheRecord largecr;
3643         ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
3644         if (ptr)
3645             LogInfo("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
3646     }
3647     if (!ptr)
3648         LogInfo("DumpRecords: ERROR: Premature end of packet data");
3649     return(ptr);
3650 }
3651
3652 #define DNS_OP_Name(X) (                              \
3653         (X) == kDNSFlag0_OP_StdQuery ? ""         :       \
3654         (X) == kDNSFlag0_OP_Iquery   ? "Iquery "  :       \
3655         (X) == kDNSFlag0_OP_Status   ? "Status "  :       \
3656         (X) == kDNSFlag0_OP_Unused3  ? "Unused3 " :       \
3657         (X) == kDNSFlag0_OP_Notify   ? "Notify "  :       \
3658         (X) == kDNSFlag0_OP_Update   ? "Update "  :       \
3659         (X) == kDNSFlag0_OP_Subscribe? "Subscribe":       \
3660         (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " )
3661
3662 #define DNS_RC_Name(X) (                             \
3663         (X) == kDNSFlag1_RC_NoErr    ? "NoErr"    :      \
3664         (X) == kDNSFlag1_RC_FormErr  ? "FormErr"  :      \
3665         (X) == kDNSFlag1_RC_ServFail ? "ServFail" :      \
3666         (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" :      \
3667         (X) == kDNSFlag1_RC_NotImpl  ? "NotImpl"  :      \
3668         (X) == kDNSFlag1_RC_Refused  ? "Refused"  :      \
3669         (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" :      \
3670         (X) == kDNSFlag1_RC_YXRRSet  ? "YXRRSet"  :      \
3671         (X) == kDNSFlag1_RC_NXRRSet  ? "NXRRSet"  :      \
3672         (X) == kDNSFlag1_RC_NotAuth  ? "NotAuth"  :      \
3673         (X) == kDNSFlag1_RC_NotZone  ? "NotZone"  : "??" )
3674
3675 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order
3676 mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
3677                            const mDNSAddr *srcaddr, mDNSIPPort srcport,
3678                            const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
3679 {
3680     mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update);
3681     const mDNSu8 *ptr = msg->data;
3682     int i;
3683     DNSQuestion q;
3684     char tbuffer[64], sbuffer[64], dbuffer[64] = "";
3685     if (!status) tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), sent ? "Sent" : "Received"                        )] = 0;
3686     else tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), "ERROR %d %sing", status, sent ? "Send" : "Receive")] = 0;
3687     if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port "        )] = 0;
3688     else sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0;
3689     if (dstaddr || !mDNSIPPortIsZero(dstport))
3690         dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0;
3691
3692     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 --",
3693            tbuffer, transport,
3694            DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
3695            msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
3696            msg->h.flags.b[0], msg->h.flags.b[1],
3697            DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
3698            msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
3699            msg->h.flags.b[0] & kDNSFlag0_AA ? "AA " : "",
3700            msg->h.flags.b[0] & kDNSFlag0_TC ? "TC " : "",
3701            msg->h.flags.b[0] & kDNSFlag0_RD ? "RD " : "",
3702            msg->h.flags.b[1] & kDNSFlag1_RA ? "RA " : "",
3703            msg->h.flags.b[1] & kDNSFlag1_AD ? "AD " : "",
3704            msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "",
3705            mDNSVal16(msg->h.id),
3706            end - msg->data,
3707            sbuffer, mDNSVal16(srcport), dbuffer,
3708            (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
3709            );
3710
3711     LogInfo("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
3712     for (i = 0; i < msg->h.numQuestions && ptr; i++)
3713     {
3714         ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
3715         if (ptr) LogInfo("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
3716     }
3717     ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers,     IsUpdate ? "Prerequisites" : "Answers");
3718     ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates"       : "Authorities");
3719           DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals");
3720     LogInfo("--------------");
3721 }
3722
3723 // ***************************************************************************
3724 #if COMPILER_LIKES_PRAGMA_MARK
3725 #pragma mark -
3726 #pragma mark - Packet Sending Functions
3727 #endif
3728
3729 #ifdef UNIT_TEST
3730 // Run the unit test of mDNSSendDNSMessage
3731 UNITTEST_SENDDNSMESSAGE
3732 #else
3733 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
3734 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
3735 // Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
3736 struct UDPSocket_struct { mDNSIPPort     port;  /* ... */ };
3737
3738 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
3739 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
3740 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
3741                                       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, 
3742                                       mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
3743                                       mDNSBool useBackgroundTrafficClass)
3744 {
3745     mStatus status = mStatus_NoError;
3746     const mDNSu16 numAdditionals = msg->h.numAdditionals;
3747     mDNSu8 *newend;
3748     mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
3749
3750 #if APPLE_OSX_mDNSResponder
3751     // maintain outbound packet statistics
3752     if (mDNSOpaque16IsZero(msg->h.id))
3753         m->MulticastPacketsSent++;
3754     else
3755         m->UnicastPacketsSent++;
3756 #endif // APPLE_OSX_mDNSResponder
3757
3758     // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code
3759     if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData)
3760     {
3761         LogMsg("mDNSSendDNSMessage: invalid message %p %p %d", msg->data, end, end - msg->data);
3762         return mStatus_BadParamErr;
3763     }
3764
3765     newend = putHINFO(m, msg, end, authInfo, limit);
3766     if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
3767     else end = newend;
3768
3769     // Put all the integer values in IETF byte-order (MSB first, LSB second)
3770     SwapDNSHeaderBytes(msg);
3771
3772     if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0);    // DNSDigest_SignMessage operates on message in network byte order
3773     if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; }
3774     else
3775     {
3776         // Send the packet on the wire
3777         if (!sock)
3778             status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport, useBackgroundTrafficClass);
3779         else
3780         {
3781             mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
3782             mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
3783             char *buf;
3784             long nsent;
3785
3786             // Try to send them in one packet if we can allocate enough memory
3787             buf = mDNSPlatformMemAllocate(msglen + 2);
3788             if (buf)
3789             {
3790                 buf[0] = lenbuf[0];
3791                 buf[1] = lenbuf[1];
3792                 mDNSPlatformMemCopy(buf+2, msg, msglen);
3793                 nsent = mDNSPlatformWriteTCP(sock, buf, msglen+2);
3794                 if (nsent != (msglen + 2))
3795                 {
3796                     LogMsg("mDNSSendDNSMessage: write message failed %d/%d", nsent, msglen);
3797                     status = mStatus_ConnFailed;
3798                 }
3799                 mDNSPlatformMemFree(buf);
3800             }
3801             else
3802             {
3803                 nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
3804                 if (nsent != 2)
3805                 {
3806                     LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2);
3807                     status = mStatus_ConnFailed;
3808                 }
3809                 else
3810                 {
3811                     nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
3812                     if (nsent != msglen)
3813                     {
3814                         LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen);
3815                         status = mStatus_ConnFailed;
3816                     }
3817                 }
3818             }
3819         }
3820     }
3821
3822     // Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage)
3823     SwapDNSHeaderBytes(msg);
3824
3825     // Dump the packet with the HINFO and TSIG
3826     if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
3827         DumpPacket(m, status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
3828
3829     // put the number of additionals back the way it was
3830     msg->h.numAdditionals = numAdditionals;
3831
3832     return(status);
3833 }
3834 #endif // UNIT_TEST
3835
3836 // ***************************************************************************
3837 #if COMPILER_LIKES_PRAGMA_MARK
3838 #pragma mark -
3839 #pragma mark - RR List Management & Task Management
3840 #endif
3841
3842 mDNSexport void mDNS_Lock_(mDNS *const m, const char * const functionname)
3843 {
3844     // MUST grab the platform lock FIRST!
3845     mDNSPlatformLock(m);
3846
3847     // Normally, mDNS_reentrancy is zero and so is mDNS_busy
3848     // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
3849     // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
3850     // If mDNS_busy != mDNS_reentrancy that's a bad sign
3851     if (m->mDNS_busy != m->mDNS_reentrancy)
3852         LogFatalError("%s: mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
3853
3854     // If this is an initial entry into the mDNSCore code, set m->timenow
3855     // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
3856     if (m->mDNS_busy == 0)
3857     {
3858         if (m->timenow)
3859             LogMsg("%s: mDNS_Lock: m->timenow already set (%ld/%ld)", functionname, m->timenow, mDNS_TimeNow_NoLock(m));
3860         m->timenow = mDNS_TimeNow_NoLock(m);
3861         if (m->timenow == 0) m->timenow = 1;
3862     }
3863     else if (m->timenow == 0)
3864     {
3865         LogMsg("%s: mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", functionname, m->mDNS_busy);
3866         m->timenow = mDNS_TimeNow_NoLock(m);
3867         if (m->timenow == 0) m->timenow = 1;
3868     }
3869
3870     if (m->timenow_last - m->timenow > 0)
3871     {
3872         m->timenow_adjust += m->timenow_last - m->timenow;
3873         LogMsg("%s: mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", functionname, m->timenow_last - m->timenow, m->timenow_adjust);
3874         m->timenow = m->timenow_last;
3875     }
3876     m->timenow_last = m->timenow;
3877
3878     // Increment mDNS_busy so we'll recognise re-entrant calls
3879     m->mDNS_busy++;
3880 }
3881
3882 mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
3883 {
3884     AuthRecord *rr;
3885     for (rr = m->NewLocalRecords; rr; rr = rr->next)
3886         if (LocalRecordReady(rr)) return rr;
3887     return mDNSNULL;
3888 }
3889
3890 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
3891 {
3892     mDNSs32 e = m->timenow + FutureTime;
3893     if (m->mDNSPlatformStatus != mStatus_NoError) return(e);
3894     if (m->NewQuestions)
3895     {
3896         if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
3897         else return(m->timenow);
3898     }
3899     if (m->NewLocalOnlyQuestions) return(m->timenow);
3900     if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
3901     if (m->NewLocalOnlyRecords) return(m->timenow);
3902     if (m->SPSProxyListChanged) return(m->timenow);
3903     if (m->LocalRemoveEvents) return(m->timenow);
3904
3905 #ifndef UNICAST_DISABLED
3906     if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
3907     if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
3908     if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate;
3909 #endif
3910
3911     if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
3912     if (e - m->NextScheduledSPS      > 0) e = m->NextScheduledSPS;
3913     if (e - m->NextScheduledKA       > 0) e = m->NextScheduledKA;
3914
3915 #if BONJOUR_ON_DEMAND
3916     if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
3917 #endif // BONJOUR_ON_DEMAND
3918
3919     // NextScheduledSPRetry only valid when DelaySleep not set
3920     if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
3921     if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
3922
3923     if (m->SuppressSending)
3924     {
3925         if (e - m->SuppressSending       > 0) e = m->SuppressSending;
3926     }
3927     else
3928     {
3929         if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
3930         if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
3931         if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
3932     }
3933     if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime;
3934
3935     if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime;
3936
3937     return(e);
3938 }
3939
3940 #define LogTSE TSE++,LogMsg
3941
3942 mDNSexport void ShowTaskSchedulingError(mDNS *const m)
3943 {
3944     int TSE = 0;
3945     AuthRecord *rr;
3946     mDNS_Lock(m);
3947
3948     LogMsg("Task Scheduling Error: *** Continuously busy for more than a second");
3949
3950     // Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above
3951
3952     if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
3953         LogTSE("Task Scheduling Error: NewQuestion %##s (%s)",
3954                m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
3955
3956     if (m->NewLocalOnlyQuestions)
3957         LogTSE("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
3958                m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
3959
3960     if (m->NewLocalRecords)
3961     {
3962         rr = AnyLocalRecordReady(m);
3963         if (rr) LogTSE("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
3964     }
3965
3966     if (m->NewLocalOnlyRecords) LogTSE("Task Scheduling Error: NewLocalOnlyRecords");
3967
3968     if (m->SPSProxyListChanged) LogTSE("Task Scheduling Error: SPSProxyListChanged");
3969
3970     if (m->LocalRemoveEvents) LogTSE("Task Scheduling Error: LocalRemoveEvents");
3971
3972 #ifndef UNICAST_DISABLED
3973     if (m->timenow - m->NextuDNSEvent         >= 0)
3974         LogTSE("Task Scheduling Error: m->NextuDNSEvent %d",         m->timenow - m->NextuDNSEvent);
3975     if (m->timenow - m->NextScheduledNATOp    >= 0)
3976         LogTSE("Task Scheduling Error: m->NextScheduledNATOp %d",    m->timenow - m->NextScheduledNATOp);
3977     if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0)
3978         LogTSE("Task Scheduling Error: m->NextSRVUpdate %d",         m->timenow - m->NextSRVUpdate);
3979 #endif
3980
3981     if (m->timenow - m->NextCacheCheck        >= 0)
3982         LogTSE("Task Scheduling Error: m->NextCacheCheck %d",        m->timenow - m->NextCacheCheck);
3983     if (m->timenow - m->NextScheduledSPS      >= 0)
3984         LogTSE("Task Scheduling Error: m->NextScheduledSPS %d",      m->timenow - m->NextScheduledSPS);
3985     if (m->timenow - m->NextScheduledKA       >= 0)
3986         LogTSE("Task Scheduling Error: m->NextScheduledKA %d",      m->timenow - m->NextScheduledKA);
3987     if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
3988         LogTSE("Task Scheduling Error: m->NextScheduledSPRetry %d",  m->timenow - m->NextScheduledSPRetry);
3989     if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
3990         LogTSE("Task Scheduling Error: m->DelaySleep %d",            m->timenow - m->DelaySleep);
3991
3992     if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
3993         LogTSE("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
3994     if (m->timenow - m->NextScheduledQuery    >= 0)
3995         LogTSE("Task Scheduling Error: m->NextScheduledQuery %d",    m->timenow - m->NextScheduledQuery);
3996     if (m->timenow - m->NextScheduledProbe    >= 0)
3997         LogTSE("Task Scheduling Error: m->NextScheduledProbe %d",    m->timenow - m->NextScheduledProbe);
3998     if (m->timenow - m->NextScheduledResponse >= 0)
3999         LogTSE("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
4000     if (m->timenow - m->NextScheduledStopTime >= 0)
4001         LogTSE("Task Scheduling Error: m->NextScheduledStopTime %d", m->timenow - m->NextScheduledStopTime);
4002
4003     if (m->timenow - m->NextScheduledEvent    >= 0)
4004         LogTSE("Task Scheduling Error: m->NextScheduledEvent %d",    m->timenow - m->NextScheduledEvent);
4005
4006     if (m->NetworkChanged && m->timenow - m->NetworkChanged >= 0)
4007         LogTSE("Task Scheduling Error: NetworkChanged %d",           m->timenow - m->NetworkChanged);
4008
4009     if (!TSE) LogMsg("Task Scheduling Error: *** No likely causes identified");
4010     else LogMsg("Task Scheduling Error: *** %d potential cause%s identified (significant only if the same cause consistently appears)", TSE, TSE > 1 ? "s" : "");
4011
4012     mDNS_Unlock(m);
4013 }
4014
4015 mDNSexport void mDNS_Unlock_(mDNS *const m, const char *const functionname)
4016 {
4017     // Decrement mDNS_busy
4018     m->mDNS_busy--;
4019
4020     // Check for locking failures
4021     if (m->mDNS_busy != m->mDNS_reentrancy)
4022         LogFatalError("%s: mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
4023
4024     // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
4025     if (m->mDNS_busy == 0)
4026     {
4027         m->NextScheduledEvent = GetNextScheduledEvent(m);
4028         if (m->timenow == 0) LogMsg("%s: mDNS_Unlock: ERROR! m->timenow aready zero", functionname);
4029         m->timenow = 0;
4030     }
4031
4032     // MUST release the platform lock LAST!
4033     mDNSPlatformUnlock(m);
4034 }
4035
4036 // ***************************************************************************
4037 #if COMPILER_LIKES_PRAGMA_MARK
4038 #pragma mark -
4039 #pragma mark - Specialized mDNS version of vsnprintf
4040 #endif
4041
4042 static const struct mDNSprintf_format
4043 {
4044     unsigned leftJustify : 1;
4045     unsigned forceSign : 1;
4046     unsigned zeroPad : 1;
4047     unsigned havePrecision : 1;
4048     unsigned hSize : 1;
4049     unsigned lSize : 1;
4050     char altForm;
4051     char sign;              // +, - or space
4052     unsigned int fieldWidth;
4053     unsigned int precision;
4054 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
4055
4056 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
4057 {
4058     mDNSu32 nwritten = 0;
4059     int c;
4060     if (buflen == 0) return(0);
4061     buflen--;       // Pre-reserve one space in the buffer for the terminating null
4062     if (buflen == 0) goto exit;
4063
4064     for (c = *fmt; c != 0; c = *++fmt)
4065     {
4066         unsigned long n;
4067                 if (c != '%')
4068         {
4069             *sbuffer++ = (char)c;
4070             if (++nwritten >= buflen) goto exit;
4071         }
4072         else
4073         {
4074             unsigned int i=0, j;
4075             // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
4076             // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
4077             // The size needs to be enough for a 256-byte domain name plus some error text.
4078             #define mDNS_VACB_Size 300
4079             char mDNS_VACB[mDNS_VACB_Size];
4080             #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
4081             #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
4082             char *s = mDNS_VACB_Lim, *digits;
4083             struct mDNSprintf_format F = mDNSprintf_format_default;
4084
4085             while (1)   //  decode flags
4086             {
4087                 c = *++fmt;
4088                 if      (c == '-') F.leftJustify = 1;
4089                 else if (c == '+') F.forceSign = 1;
4090                 else if (c == ' ') F.sign = ' ';
4091                 else if (c == '#') F.altForm++;
4092                 else if (c == '0') F.zeroPad = 1;
4093                 else break;
4094             }
4095
4096             if (c == '*')   //  decode field width
4097             {
4098                 int f = va_arg(arg, int);
4099                 if (f < 0) { f = -f; F.leftJustify = 1; }
4100                 F.fieldWidth = (unsigned int)f;
4101                 c = *++fmt;
4102             }
4103             else
4104             {
4105                 for (; c >= '0' && c <= '9'; c = *++fmt)
4106                     F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
4107             }
4108
4109             if (c == '.')   //  decode precision
4110             {
4111                 if ((c = *++fmt) == '*')
4112                 { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
4113                 else for (; c >= '0' && c <= '9'; c = *++fmt)
4114                         F.precision = (10 * F.precision) + (c - '0');
4115                 F.havePrecision = 1;
4116             }
4117
4118             if (F.leftJustify) F.zeroPad = 0;
4119
4120 conv:
4121             switch (c)  //  perform appropriate conversion
4122             {
4123             case 'h':  F.hSize = 1; c = *++fmt; goto conv;
4124             case 'l':       // fall through
4125             case 'L':  F.lSize = 1; c = *++fmt; goto conv;
4126             case 'd':
4127             case 'i':  if (F.lSize) n = (unsigned long)va_arg(arg, long);
4128                 else n = (unsigned long)va_arg(arg, int);
4129                 if (F.hSize) n = (short) n;
4130                 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
4131                 else if (F.forceSign) F.sign = '+';
4132                 goto decimal;
4133             case 'u':  if (F.lSize) n = va_arg(arg, unsigned long);
4134                 else n = va_arg(arg, unsigned int);
4135                 if (F.hSize) n = (unsigned short) n;
4136                 F.sign = 0;
4137                 goto decimal;
4138 decimal:    if (!F.havePrecision)
4139                 {
4140                     if (F.zeroPad)
4141                     {
4142                         F.precision = F.fieldWidth;
4143                         if (F.sign) --F.precision;
4144                     }
4145                     if (F.precision < 1) F.precision = 1;
4146                 }
4147                 if (F.precision > mDNS_VACB_Size - 1)
4148                     F.precision = mDNS_VACB_Size - 1;
4149                 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
4150                 for (; i < F.precision; i++) *--s = '0';
4151                 if (F.sign) { *--s = F.sign; i++; }
4152                 break;
4153
4154             case 'o':  if (F.lSize) n = va_arg(arg, unsigned long);
4155                 else n = va_arg(arg, unsigned int);
4156                 if (F.hSize) n = (unsigned short) n;
4157                 if (!F.havePrecision)
4158                 {
4159                     if (F.zeroPad) F.precision = F.fieldWidth;
4160                     if (F.precision < 1) F.precision = 1;
4161                 }
4162                 if (F.precision > mDNS_VACB_Size - 1)
4163                     F.precision = mDNS_VACB_Size - 1;
4164                 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
4165                 if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
4166                 for (; i < F.precision; i++) *--s = '0';
4167                 break;
4168
4169             case 'a':  {
4170                 unsigned char *a = va_arg(arg, unsigned char *);
4171                 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
4172                 else
4173                 {
4174                     s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
4175                     if (F.altForm)
4176                     {
4177                         mDNSAddr *ip = (mDNSAddr*)a;
4178                         switch (ip->type)
4179                         {
4180                         case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
4181                         case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
4182                         default:                F.precision =  0; break;
4183                         }
4184                     }
4185                     if (F.altForm && !F.precision)
4186                         i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»");
4187                     else switch (F.precision)
4188                         {
4189                         case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
4190                                                    a[0], a[1], a[2], a[3]); break;
4191                         case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
4192                                                    a[0], a[1], a[2], a[3], a[4], a[5]); break;
4193                         case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
4194                                                    "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
4195                                                    a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
4196                                                    a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
4197                         default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
4198                                                    " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
4199                         }
4200                 }
4201             }
4202             break;
4203
4204             case 'p':  F.havePrecision = F.lSize = 1;
4205                 F.precision = sizeof(void*) * 2;                // 8 characters on 32-bit; 16 characters on 64-bit
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
4300             case '%':  *sbuffer++ = (char)c;
4301                 if (++nwritten >= buflen) goto exit;
4302                 break;
4303             }
4304
4305             if (i < F.fieldWidth && !F.leftJustify)         // Pad on the left
4306                 do  {
4307                     *sbuffer++ = ' ';
4308                     if (++nwritten >= buflen) goto exit;
4309                 } while (i < --F.fieldWidth);
4310
4311             // Make sure we don't truncate in the middle of a UTF-8 character.
4312             // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
4313             // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
4314             // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
4315             // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
4316             if (i > buflen - nwritten)
4317             { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
4318             for (j=0; j<i; j++) *sbuffer++ = *s++;          // Write the converted result
4319             nwritten += i;
4320             if (nwritten >= buflen) goto exit;
4321
4322             for (; i < F.fieldWidth; i++)                   // Pad on the right
4323             {
4324                 *sbuffer++ = ' ';
4325                 if (++nwritten >= buflen) goto exit;
4326             }
4327         }
4328     }
4329 exit:
4330     *sbuffer++ = 0;
4331     return(nwritten);
4332 }
4333
4334 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
4335 {
4336     mDNSu32 length;
4337
4338     va_list ptr;
4339     va_start(ptr,fmt);
4340     length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
4341     va_end(ptr);
4342
4343     return(length);
4344 }