1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
19 #define mDNS_InstantiateInlines 1
20 #include "DNSCommon.h"
21 #include "CryptoAlg.h"
22 #include "anonymous.h"
23 
24 #ifdef UNIT_TEST
25 #include "unittest.h"
26 #endif
27 
28 // Disable certain benign warnings with Microsoft compilers
29 #if (defined(_MSC_VER))
30 // Disable "conditional expression is constant" warning for debug macros.
31 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
32 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
33     #pragma warning(disable:4127)
34 // Disable "array is too small to include a terminating null character" warning
35 // -- domain labels have an initial length byte, not a terminating null character
36     #pragma warning(disable:4295)
37 #endif
38 
39 // ***************************************************************************
40 #if COMPILER_LIKES_PRAGMA_MARK
41 #pragma mark - Program Constants
42 #endif
43 
44 mDNSexport const mDNSInterfaceID mDNSInterface_Any       = 0;
45 mDNSexport const mDNSInterfaceID mDNSInterfaceMark       = (mDNSInterfaceID)-1;
46 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
47 mDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)-3;
48 mDNSexport const mDNSInterfaceID mDNSInterface_P2P       = (mDNSInterfaceID)-4;
49 mDNSexport const mDNSInterfaceID uDNSInterfaceMark       = (mDNSInterfaceID)-5;
50 mDNSexport const mDNSInterfaceID mDNSInterface_BLE       = (mDNSInterfaceID)-6;
51 
52 // Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
53 // Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
54 // port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders.
55 // LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355.
56 // Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability
57 // with Microsoft's LLMNR client code.
58 
59 #define   DiscardPortAsNumber               9
60 #define   SSHPortAsNumber                  22
61 #define   UnicastDNSPortAsNumber           53
62 #define   SSDPPortAsNumber               1900
63 #define   IPSECPortAsNumber              4500
64 #define   NSIPCPortAsNumber              5030       // Port used for dnsextd to talk to local nameserver bound to loopback
65 #define   NATPMPAnnouncementPortAsNumber 5350
66 #define   NATPMPPortAsNumber             5351
67 #define   DNSEXTPortAsNumber             5352       // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
68 #define   MulticastDNSPortAsNumber       5353
69 #define   LoopbackIPCPortAsNumber        5354
70 //#define MulticastDNSPortAsNumber       5355		// LLMNR
71 #define   PrivateDNSPortAsNumber         5533
72 
73 mDNSexport const mDNSIPPort DiscardPort            = { { DiscardPortAsNumber            >> 8, DiscardPortAsNumber            & 0xFF } };
74 mDNSexport const mDNSIPPort SSHPort                = { { SSHPortAsNumber                >> 8, SSHPortAsNumber                & 0xFF } };
75 mDNSexport const mDNSIPPort UnicastDNSPort         = { { UnicastDNSPortAsNumber         >> 8, UnicastDNSPortAsNumber         & 0xFF } };
76 mDNSexport const mDNSIPPort SSDPPort               = { { SSDPPortAsNumber               >> 8, SSDPPortAsNumber               & 0xFF } };
77 mDNSexport const mDNSIPPort IPSECPort              = { { IPSECPortAsNumber              >> 8, IPSECPortAsNumber              & 0xFF } };
78 mDNSexport const mDNSIPPort NSIPCPort              = { { NSIPCPortAsNumber              >> 8, NSIPCPortAsNumber              & 0xFF } };
79 mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } };
80 mDNSexport const mDNSIPPort NATPMPPort             = { { NATPMPPortAsNumber             >> 8, NATPMPPortAsNumber             & 0xFF } };
81 mDNSexport const mDNSIPPort DNSEXTPort             = { { DNSEXTPortAsNumber             >> 8, DNSEXTPortAsNumber             & 0xFF } };
82 mDNSexport const mDNSIPPort MulticastDNSPort       = { { MulticastDNSPortAsNumber       >> 8, MulticastDNSPortAsNumber       & 0xFF } };
83 mDNSexport const mDNSIPPort LoopbackIPCPort        = { { LoopbackIPCPortAsNumber        >> 8, LoopbackIPCPortAsNumber        & 0xFF } };
84 mDNSexport const mDNSIPPort PrivateDNSPort         = { { PrivateDNSPortAsNumber         >> 8, PrivateDNSPortAsNumber         & 0xFF } };
85 
86 mDNSexport const OwnerOptData zeroOwner         = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
87 
88 mDNSexport const mDNSIPPort zeroIPPort        = { { 0 } };
89 mDNSexport const mDNSv4Addr zerov4Addr        = { { 0 } };
90 mDNSexport const mDNSv6Addr zerov6Addr        = { { 0 } };
91 mDNSexport const mDNSEthAddr zeroEthAddr       = { { 0 } };
92 mDNSexport const mDNSv4Addr onesIPv4Addr      = { { 255, 255, 255, 255 } };
93 mDNSexport const mDNSv6Addr onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
94 mDNSexport const mDNSEthAddr onesEthAddr       = { { 255, 255, 255, 255, 255, 255 } };
95 mDNSexport const mDNSAddr zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
96 
97 mDNSexport const mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
98 mDNSexport const mDNSv4Addr AllHosts_v4        = { { 224,   0,   0,   1 } };  // For NAT-PMP & PCP Annoucements
99 mDNSexport const mDNSv6Addr AllHosts_v6        = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } };
100 mDNSexport const mDNSv6Addr NDP_prefix         = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01, 0xFF,0x00,0x00,0xFB } };  // FF02:0:0:0:0:1:FF00::/104
101 mDNSexport const mDNSEthAddr AllHosts_v6_Eth    = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } };
102 mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
103 //mDNSexport const mDNSAddr  AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 252 } } } }; // LLMNR
104 mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
105 //mDNSexport const mDNSAddr  AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
106 
107 mDNSexport const mDNSOpaque16 zeroID          = { { 0, 0 } };
108 mDNSexport const mDNSOpaque16 onesID          = { { 255, 255 } };
109 mDNSexport const mDNSOpaque16 QueryFlags      = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
110 mDNSexport const mDNSOpaque16 uQueryFlags     = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
111 mDNSexport const mDNSOpaque16 DNSSecQFlags    = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, kDNSFlag1_CD } };
112 mDNSexport const mDNSOpaque16 ResponseFlags   = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
113 mDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
114 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
115 mDNSexport const mDNSOpaque16 SubscribeFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Subscribe, 0 } };
116 mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_UnSubscribe, 0 } };
117 
118 mDNSexport const mDNSOpaque64  zeroOpaque64     = { { 0 } };
119 mDNSexport const mDNSOpaque128 zeroOpaque128    = { { 0 } };
120 
121 // ***************************************************************************
122 #if COMPILER_LIKES_PRAGMA_MARK
123 #pragma mark -
124 #pragma mark - General Utility Functions
125 #endif
126 
127 // return true for RFC1918 private addresses
mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr)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 
mDNSAddrMapIPv4toIPv6(mDNSv4Addr * in,mDNSv6Addr * out)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 
mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr * in,mDNSv4Addr * out)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 
GetFirstActiveInterface(NetworkInterfaceInfo * intf)156 mDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf)
157 {
158     while (intf && !intf->InterfaceActive) intf = intf->next;
159     return(intf);
160 }
161 
GetNextActiveInterfaceID(const NetworkInterfaceInfo * intf)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 
NumCacheRecordsForInterfaceID(const mDNS * const m,mDNSInterfaceID id)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 
DNSTypeName(mDNSu16 rrtype)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 
DNSSECAlgName(mDNSu8 alg)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 
DNSSECDigestName(mDNSu8 digest)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 
swap32(mDNSu32 x)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 
swap16(mDNSu16 x)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 //
keytag(mDNSu8 * key,mDNSu32 keysize)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 
baseEncode(char * buffer,int blen,const mDNSu8 * data,int len,int encAlg)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 
PrintTypeBitmap(const mDNSu8 * bmap,int bitmaplen,char * const buffer,mDNSu32 length)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.
NSEC3Parse(const ResourceRecord * const rr,mDNSu8 ** salt,int * hashLength,mDNSu8 ** nxtName,int * bitmaplen,mDNSu8 ** bitmap)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.
GetRRDisplayString_rdb(const ResourceRecord * const rr,const RDataBody * const rd1,char * const buffer)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
mDNSRandomFromSeed(mDNSu32 seed)564 mDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed)
565 {
566     return seed * 21 + 1;
567 }
568 
mDNSMixRandomSeed(mDNSu32 seed,mDNSu8 iteration)569 mDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration)
570 {
571     return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed;
572 }
573 
mDNSRandomNumber()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 
mDNSRandom(mDNSu32 max)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 
mDNSSameAddress(const mDNSAddr * ip1,const mDNSAddr * ip2)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 
mDNSAddrIsDNSMulticast(const mDNSAddr * ip)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 
SameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)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 
SameDomainName(const domainname * const d1,const domainname * const d2)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 
SameDomainNameCS(const domainname * const d1,const domainname * const d2)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 
IsLocalDomain(const domainname * d)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 
LastLabel(const domainname * d)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)
DomainNameLengthLimit(const domainname * const name,const mDNSu8 * limit)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).
CompressedDomainNameLength(const domainname * const name,const domainname * parent)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.)
CountLabels(const domainname * d)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.
SkipLeadingLabels(const domainname * d,int skip)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.
AppendLiteralLabelString(domainname * const name,const char * cstr)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.
AppendDNSNameString(domainname * const name,const char * cstring)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.
AppendDomainLabel(domainname * const name,const domainlabel * const label)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 
AppendDomainName(domainname * const name,const domainname * const append)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.
MakeDomainLabelFromLiteralString(domainlabel * const label,const char * cstr)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.
MakeDomainNameFromDNSNameString(domainname * const name,const char * cstr)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 
ConvertDomainLabelToCString_withescape(const domainlabel * const label,char * ptr,char esc)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)
ConvertDomainNameToCString_withescape(const domainname * const name,char * ptr,char esc)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 
ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[],domainlabel * const hostlabel)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 
ConstructServiceName(domainname * const fqdn,const domainlabel * name,const domainname * type,const domainname * const domain)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.
DeconstructServiceName(const domainname * const fqdn,domainlabel * const name,domainname * const type,domainname * const domain)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 
DNSNameToLowerCase(domainname * d,domainname * result)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 
NSEC3HashName(const domainname * name,rdataNSEC3 * nsec3,const mDNSu8 * AnonData,int AnonDataLen,const mDNSu8 hash[NSEC3_MAX_HASH_LEN],int * dlen)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 
TruncateUTF8ToLength(mDNSu8 * string,mDNSu32 length,mDNSu32 max)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.
LabelContainsSuffix(const domainlabel * const name,const mDNSBool RichText)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.
RemoveLabelSuffix(domainlabel * name,mDNSBool RichText)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).
AppendLabelSuffix(domainlabel * const name,mDNSu32 val,const mDNSBool RichText)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 
IncrementLabelSuffix(domainlabel * name,mDNSBool RichText)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
mDNS_SetupResourceRecord(AuthRecord * rr,RData * RDataStorage,mDNSInterfaceID InterfaceID,mDNSu16 rrtype,mDNSu32 ttl,mDNSu8 RecordType,AuthRecType artype,mDNSRecordCallback Callback,void * Context)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 
mDNS_SetupQuestion(DNSQuestion * const q,const mDNSInterfaceID InterfaceID,const domainname * const name,const mDNSu16 qtype,mDNSQuestionCallback * const callback,void * const context)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 
RDataHashValue(const ResourceRecord * const rr)1487 mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
1488 {
1489     int len = rr->rdlength;
1490     const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
1491     const mDNSu8 *ptr = rdb->data;
1492     mDNSu32 sum = 0;
1493 
1494     switch(rr->rrtype)
1495     {
1496     case kDNSType_NS:
1497     case kDNSType_MD:
1498     case kDNSType_MF:
1499     case kDNSType_CNAME:
1500     case kDNSType_MB:
1501     case kDNSType_MG:
1502     case kDNSType_MR:
1503     case kDNSType_PTR:
1504     case kDNSType_NSAP_PTR:
1505     case kDNSType_DNAME: return DomainNameHashValue(&rdb->name);
1506 
1507     case kDNSType_SOA:   return rdb->soa.serial  +
1508                rdb->soa.refresh +
1509                rdb->soa.retry   +
1510                rdb->soa.expire  +
1511                rdb->soa.min     +
1512                DomainNameHashValue(&rdb->soa.mname) +
1513                DomainNameHashValue(&rdb->soa.rname);
1514 
1515     case kDNSType_MX:
1516     case kDNSType_AFSDB:
1517     case kDNSType_RT:
1518     case kDNSType_KX:    return DomainNameHashValue(&rdb->mx.exchange);
1519 
1520     case kDNSType_MINFO:
1521     case kDNSType_RP:    return DomainNameHashValue(&rdb->rp.mbox)   + DomainNameHashValue(&rdb->rp.txt);
1522 
1523     case kDNSType_PX:    return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400);
1524 
1525     case kDNSType_SRV:   return DomainNameHashValue(&rdb->srv.target);
1526 
1527     case kDNSType_OPT:   return 0;      // OPT is a pseudo-RR container structure; makes no sense to compare
1528 
1529     case kDNSType_NSEC: {
1530         int dlen;
1531         dlen = DomainNameLength((domainname *)rdb->data);
1532         sum = DomainNameHashValue((domainname *)rdb->data);
1533         ptr += dlen;
1534         len -= dlen;
1535     }
1536     /* FALLTHROUGH */
1537 
1538     default:
1539     {
1540         int i;
1541         for (i=0; i+1 < len; i+=2)
1542         {
1543             sum += (((mDNSu32)(ptr[i])) << 8) | ptr[i+1];
1544             sum = (sum<<3) | (sum>>29);
1545         }
1546         if (i < len)
1547         {
1548             sum += ((mDNSu32)(ptr[i])) << 8;
1549         }
1550         return(sum);
1551     }
1552     }
1553 }
1554 
1555 // r1 has to be a full ResourceRecord including rrtype and rdlength
1556 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
SameRDataBody(const ResourceRecord * const r1,const RDataBody * const r2,DomainNameComparisonFn * samename)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 
BitmapTypeCheck(mDNSu8 * bmap,int bitmaplen,mDNSu16 type)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.
RRAssertsExistence(const ResourceRecord * const rr,mDNSu16 type)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.
RRAssertsNonexistence(const ResourceRecord * const rr,mDNSu16 type)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".
DNSSECRecordAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q,mDNSBool * checkType)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 
SameNameRecordAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)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 
ResourceRecordAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)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 //
LocalOnlyRecordAnswersQuestion(AuthRecord * const ar,const DNSQuestion * const q)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 
AnyTypeRecordAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)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.
ResourceRecordAnswersUnicastResponse(const ResourceRecord * const rr,const DNSQuestion * const q)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 
GetRDLength(const ResourceRecord * const rr,mDNSBool estimate)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
ValidateRData(const mDNSu16 rrtype,const mDNSu16 rdlength,const RData * const rd)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 
InitializeDNSMessage(DNSMessageHeader * h,mDNSOpaque16 id,mDNSOpaque16 flags)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 
FindCompressionPointer(const mDNSu8 * const base,const mDNSu8 * const end,const mDNSu8 * const domname)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
putDomainNameAsLabels(const DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,const domainname * const name)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 
putVal16(mDNSu8 * ptr,mDNSu16 val)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 
putVal32(mDNSu8 * ptr,mDNSu32 val)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)
putRData(const DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,const ResourceRecord * const rr)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 
PutResourceRecordTTLWithLimit(DNSMessage * const msg,mDNSu8 * ptr,mDNSu16 * count,ResourceRecord * rr,mDNSu32 ttl,const mDNSu8 * limit)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->