1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (c) 2002-2024 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 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #ifndef STANDALONE
19 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
20 #define mDNS_InstantiateInlines 1
21 #include "DNSCommon.h"
22 #include "DebugServices.h"
23
24 #if MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY)
25 #include "discover_resolver.h"
26 #endif
27
28 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS_PUSH)
29 #include "dns_push_discovery.h"
30 #endif
31
32 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
33 #include "dnssec_obj_rr_ds.h" // For dnssec_obj_rr_ds_t.
34 #include "dnssec_mdns_core.h" // For DNSSEC-related operation on mDNSCore structures.
35 #include "rdata_parser.h" // For DNSSEC-related records parsing.
36 #include "base_encoding.h" // For base64 encoding.
37 #endif
38
39 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK)
40 #include <os/lock.h> // For os_unfair_lock.
41 #endif
42
43 #if MDNSRESPONDER_SUPPORTS(APPLE, LOG_PRIVACY_LEVEL)
44 #include "system_utilities.h" //For is_apple_internal_build().
45 #endif
46
47 // Disable certain benign warnings with Microsoft compilers
48 #if (defined(_MSC_VER))
49 // Disable "conditional expression is constant" warning for debug macros.
50 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
51 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
52 #pragma warning(disable:4127)
53 // Disable "array is too small to include a terminating null character" warning
54 // -- domain labels have an initial length byte, not a terminating null character
55 #pragma warning(disable:4295)
56 #endif
57
58 // ***************************************************************************
59 // MARK: - Program Constants
60
61 #include "mdns_strict.h"
62
63 mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
64 mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1;
65 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
66 mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-3;
67 mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-4;
68 mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-5;
69
70 // Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
71 // Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
72 // port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders.
73 // LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355.
74 // Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability
75 // with Microsoft's LLMNR client code.
76
77 #define DiscardPortAsNumber 9
78 #define SSHPortAsNumber 22
79 #define UnicastDNSPortAsNumber 53
80 #define SSDPPortAsNumber 1900
81 #define IPSECPortAsNumber 4500
82 #define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback
83 #define NATPMPAnnouncementPortAsNumber 5350
84 #define NATPMPPortAsNumber 5351
85 #define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
86 #define MulticastDNSPortAsNumber 5353
87 #define LoopbackIPCPortAsNumber 5354
88 //#define MulticastDNSPortAsNumber 5355 // LLMNR
89 #define PrivateDNSPortAsNumber 5533
90
91 mDNSexport const mDNSIPPort DiscardPort = { { DiscardPortAsNumber >> 8, DiscardPortAsNumber & 0xFF } };
92 mDNSexport const mDNSIPPort SSHPort = { { SSHPortAsNumber >> 8, SSHPortAsNumber & 0xFF } };
93 mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } };
94 mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } };
95 mDNSexport const mDNSIPPort IPSECPort = { { IPSECPortAsNumber >> 8, IPSECPortAsNumber & 0xFF } };
96 mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 0xFF } };
97 mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } };
98 mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } };
99 mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } };
100 mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
101 mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } };
102 mDNSexport const mDNSIPPort PrivateDNSPort = { { PrivateDNSPortAsNumber >> 8, PrivateDNSPortAsNumber & 0xFF } };
103
104 mDNSexport const OwnerOptData zeroOwner = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
105
106 mDNSexport const mDNSIPPort zeroIPPort = { { 0 } };
107 mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } };
108 mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } };
109 mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } };
110 mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } };
111 mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
112 mDNSexport const mDNSEthAddr onesEthAddr = { { 255, 255, 255, 255, 255, 255 } };
113 mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} };
114
115 mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
116 mDNSexport const mDNSv4Addr AllHosts_v4 = { { 224, 0, 0, 1 } }; // For NAT-PMP & PCP Annoucements
117 mDNSexport const mDNSv6Addr AllHosts_v6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } };
118 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
119 mDNSexport const mDNSEthAddr AllHosts_v6_Eth = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } };
120 mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
121 //mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR
122 mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
123 //mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
124
125 mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
126 mDNSexport const mDNSOpaque16 onesID = { { 255, 255 } };
127 mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
128 mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
129 mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
130 mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
131 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
132
133 mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
134 mDNSexport const mDNSOpaque128 zeroOpaque128 = { { 0 } };
135
136 extern mDNS mDNSStorage;
137
138 // ***************************************************************************
139 // MARK: - General Utility Functions
140
CacheRecordSetResponseFlags(CacheRecord * const cr,const mDNSOpaque16 responseFlags)141 mDNSexport void CacheRecordSetResponseFlags(CacheRecord *const cr, const mDNSOpaque16 responseFlags)
142 {
143 cr->responseFlags = responseFlags;
144 cr->resrec.rcode = cr->responseFlags.b[1] & kDNSFlag1_RC_Mask;
145 }
146
mDNSCoreResetRecord(mDNS * const m)147 mDNSexport void mDNSCoreResetRecord(mDNS *const m)
148 {
149 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
150 CacheRecordSetResponseFlags(&m->rec.r, zeroID);
151 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
152 MDNS_DISPOSE_DNSSEC_OBJ(m->rec.r.resrec.dnssec);
153 #endif
154 }
155
156 // return true for RFC1918 private addresses
mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr)157 mDNSexport mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr)
158 {
159 return ((addr->b[0] == 10) || // 10/8 prefix
160 (addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) || // 172.16/12
161 (addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16
162 }
163
DNSScopeToString(mDNSu32 scope)164 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
165 {
166 switch (scope)
167 {
168 case kScopeNone:
169 return "Unscoped";
170 case kScopeInterfaceID:
171 return "InterfaceScoped";
172 case kScopeServiceID:
173 return "ServiceScoped";
174 default:
175 return "Unknown";
176 }
177 }
178
mDNSAddrMapIPv4toIPv6(mDNSv4Addr * in,mDNSv6Addr * out)179 mDNSexport void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out)
180 {
181 out->l[0] = 0;
182 out->l[1] = 0;
183 out->w[4] = 0;
184 out->w[5] = 0xffff;
185 out->b[12] = in->b[0];
186 out->b[13] = in->b[1];
187 out->b[14] = in->b[2];
188 out->b[15] = in->b[3];
189 }
190
mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr * in,mDNSv4Addr * out)191 mDNSexport mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr* out)
192 {
193 if (in->l[0] != 0 || in->l[1] != 0 || in->w[4] != 0 || in->w[5] != 0xffff)
194 return mDNSfalse;
195
196 out->NotAnInteger = in->l[3];
197 return mDNStrue;
198 }
199
FirstInterfaceForID(mDNS * const m,const mDNSInterfaceID InterfaceID)200 NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
201 {
202 NetworkInterfaceInfo *intf = m->HostInterfaces;
203 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next;
204 return(intf);
205 }
206
FirstIPv4LLInterfaceForID(mDNS * const m,const mDNSInterfaceID InterfaceID)207 NetworkInterfaceInfo *FirstIPv4LLInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
208 {
209 NetworkInterfaceInfo *intf;
210
211 if (!InterfaceID)
212 return mDNSNULL;
213
214 // Note: We don't check for InterfaceActive, as the active interface could be IPv6 and
215 // we still want to find the first IPv4 Link-Local interface
216 for (intf = m->HostInterfaces; intf; intf = intf->next)
217 {
218 if (intf->InterfaceID == InterfaceID &&
219 intf->ip.type == mDNSAddrType_IPv4 && mDNSv4AddressIsLinkLocal(&intf->ip.ip.v4))
220 {
221 debugf("FirstIPv4LLInterfaceForID: found LL interface with address %.4a", &intf->ip.ip.v4);
222 return intf;
223 }
224 }
225 return (mDNSNULL);
226 }
227
InterfaceNameForID(mDNS * const m,const mDNSInterfaceID InterfaceID)228 mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
229 {
230 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
231 return(intf ? intf->ifname : mDNSNULL);
232 }
233
InterfaceNameForIDOrEmptyString(const mDNSInterfaceID InterfaceID)234 mDNSexport const char *InterfaceNameForIDOrEmptyString(const mDNSInterfaceID InterfaceID)
235 {
236 const char *const ifName = InterfaceNameForID(&mDNSStorage, InterfaceID);
237 return (ifName ? ifName : "");
238 }
239
GetFirstActiveInterface(NetworkInterfaceInfo * intf)240 mDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf)
241 {
242 while (intf && !intf->InterfaceActive) intf = intf->next;
243 return(intf);
244 }
245
GetNextActiveInterfaceID(const NetworkInterfaceInfo * intf)246 mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf)
247 {
248 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
249 if (next) return(next->InterfaceID);else return(mDNSNULL);
250 }
251
NumCacheRecordsForInterfaceID(const mDNS * const m,mDNSInterfaceID id)252 mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id)
253 {
254 mDNSu32 slot, used = 0;
255 CacheGroup *cg;
256 const CacheRecord *rr;
257 FORALL_CACHERECORDS(slot, cg, rr)
258 {
259 if (rr->resrec.InterfaceID == id)
260 used++;
261 }
262 return(used);
263 }
264
DNSTypeName(mDNSu16 rrtype)265 mDNSexport char *DNSTypeName(mDNSu16 rrtype)
266 {
267 switch (rrtype)
268 {
269 case kDNSType_A: return("Addr");
270 case kDNSType_NS: return("NS");
271 case kDNSType_CNAME: return("CNAME");
272 case kDNSType_SOA: return("SOA");
273 case kDNSType_NULL: return("NULL");
274 case kDNSType_PTR: return("PTR");
275 case kDNSType_HINFO: return("HINFO");
276 case kDNSType_TXT: return("TXT");
277 case kDNSType_AAAA: return("AAAA");
278 case kDNSType_SRV: return("SRV");
279 case kDNSType_OPT: return("OPT");
280 case kDNSType_NSEC: return("NSEC");
281 case kDNSType_NSEC3: return("NSEC3");
282 case kDNSType_NSEC3PARAM: return("NSEC3PARAM");
283 case kDNSType_TSIG: return("TSIG");
284 case kDNSType_RRSIG: return("RRSIG");
285 case kDNSType_DNSKEY: return("DNSKEY");
286 case kDNSType_DS: return("DS");
287 case kDNSType_SVCB: return("SVCB");
288 case kDNSType_HTTPS: return("HTTPS");
289 case kDNSType_TSR: return("TSR");
290 case kDNSQType_ANY: return("ANY");
291 default: {
292 static char buffer[16];
293 mDNS_snprintf(buffer, sizeof(buffer), "TYPE%d", rrtype);
294 return(buffer);
295 }
296 }
297 }
298
mStatusDescription(mStatus error)299 mDNSexport const char *mStatusDescription(mStatus error)
300 {
301 const char *error_description;
302 switch (error) {
303 case mStatus_NoError:
304 error_description = "mStatus_NoError";
305 break;
306 case mStatus_BadParamErr:
307 error_description = "mStatus_BadParamErr";
308 break;
309
310 default:
311 error_description = "mStatus_UnknownDescription";
312 break;
313 }
314
315 return error_description;
316 }
317
swap32(mDNSu32 x)318 mDNSexport mDNSu32 swap32(mDNSu32 x)
319 {
320 mDNSu8 *ptr = (mDNSu8 *)&x;
321 return (mDNSu32)((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
322 }
323
swap16(mDNSu16 x)324 mDNSexport mDNSu16 swap16(mDNSu16 x)
325 {
326 mDNSu8 *ptr = (mDNSu8 *)&x;
327 return (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
328 }
329
PrintTypeBitmap(const mDNSu8 * bmap,int bitmaplen,char * const buffer,mDNSu32 length)330 mDNSlocal void PrintTypeBitmap(const mDNSu8 *bmap, int bitmaplen, char *const buffer, mDNSu32 length)
331 {
332 int win, wlen, type;
333
334 while (bitmaplen > 0)
335 {
336 int i;
337
338 if (bitmaplen < 3)
339 {
340 LogMsg("PrintTypeBitmap: malformed bitmap, bitmaplen %d short", bitmaplen);
341 break;
342 }
343
344 win = *bmap++;
345 wlen = *bmap++;
346 bitmaplen -= 2;
347 if (bitmaplen < wlen || wlen < 1 || wlen > 32)
348 {
349 LogInfo("PrintTypeBitmap: malformed nsec, bitmaplen %d wlen %d", bitmaplen, wlen);
350 break;
351 }
352 if (win < 0 || win >= 256)
353 {
354 LogInfo("PrintTypeBitmap: malformed nsec, bad window win %d", win);
355 break;
356 }
357 type = win * 256;
358 for (i = 0; i < wlen * 8; i++)
359 {
360 if (bmap[i>>3] & (128 >> (i&7)))
361 length += mDNS_snprintf(buffer+length, (MaxMsg - 1) - length, "%s ", DNSTypeName(type + i));
362 }
363 bmap += wlen;
364 bitmaplen -= wlen;
365 }
366 }
367
368 #define TXT_RECORD_SEPARATOR '|'
369
370 mDNSlocal mDNSu8 mDNSLengthOfFirstUTF8Character(const mDNSu8 *bytes, mDNSu32 len);
371
mDNSLocateFirstByteToEscape(const mDNSu8 * const bytes,const mDNSu32 bytesLen)372 mDNSlocal const mDNSu8 *mDNSLocateFirstByteToEscape(const mDNSu8 *const bytes, const mDNSu32 bytesLen)
373 {
374 for (const mDNSu8 *ptr = bytes, *const end = bytes + bytesLen; ptr < end;)
375 {
376 const mDNSu8 utf8CharacterLen = mDNSLengthOfFirstUTF8Character(ptr, (mDNSu32)(end - ptr));
377 if (utf8CharacterLen == 0)
378 {
379 return ptr;
380 }
381 else if (utf8CharacterLen == 1)
382 {
383 const char ch = *ptr;
384 if ((ch == '\\') || (ch == TXT_RECORD_SEPARATOR) || !mDNSIsPrintASCII(ch))
385 {
386 return ptr;
387 }
388 }
389 ptr += utf8CharacterLen;
390 }
391 return mDNSNULL;
392 }
393
putTXTRRCharacterString(char * const buffer,const mDNSu32 bufferLen,const mDNSu8 * const bytes,const mDNSu32 bytesLen,const mDNSBool addSeparator,mDNSBool * const outTruncated)394 mDNSlocal mDNSu32 putTXTRRCharacterString(char *const buffer, const mDNSu32 bufferLen, const mDNSu8 *const bytes,
395 const mDNSu32 bytesLen, const mDNSBool addSeparator, mDNSBool *const outTruncated)
396 {
397 mDNSBool truncated = mDNSfalse;
398 mDNSu32 nWrites = 0;
399
400 if (addSeparator)
401 {
402 require_action_quiet(bufferLen > 1, exit, truncated = mDNStrue);
403 nWrites = mDNS_snprintf(buffer, bufferLen, "%c", TXT_RECORD_SEPARATOR);
404 }
405
406 for (const mDNSu8 *ptr = bytes, *const end = bytes + bytesLen; ptr < end;)
407 {
408 const mDNSu32 remainingLen = (mDNSu32)(end - ptr);
409 const mDNSu8 *const firstByteToEscape = mDNSLocateFirstByteToEscape(ptr, remainingLen);
410
411 // [ptr ... firstByteToEscape ... end]
412 // The bytes between [ptr, firstByteToEscape) are directly-printable.
413 const mDNSu32 normalBytesLenToPrint = (firstByteToEscape ? ((mDNSu32)(firstByteToEscape - ptr)) : remainingLen);
414 // Print UTF-8 characters in [ptr, firstByteToEscape).
415 if (normalBytesLenToPrint > 0)
416 {
417 const mDNSu32 currentNWrites = mDNS_snprintf(buffer + nWrites, bufferLen - nWrites, "%.*s",
418 normalBytesLenToPrint, ptr);
419 nWrites += currentNWrites;
420 require_action_quiet(currentNWrites == normalBytesLenToPrint, exit, truncated = mDNStrue);
421 }
422
423 if (firstByteToEscape)
424 {
425 // Print the *firstByteToEscape if it exists.
426 const mDNSu8 byteToEscape = *firstByteToEscape;
427
428 if ((byteToEscape == '\\') || (byteToEscape == TXT_RECORD_SEPARATOR))
429 {
430 // One escape character `\\`, one character being escaped, one `\0`.
431 require_action_quiet((bufferLen - nWrites) >= 3, exit, truncated = mDNStrue);
432 nWrites += mDNS_snprintf(buffer + nWrites, bufferLen - nWrites, "\\%c", byteToEscape);
433 }
434 else
435 {
436 // Two-byte hex prefix `\\x`, Two-byte hex value "HH" , one '\0'.
437 require_action_quiet((bufferLen - nWrites) >= 5, exit, truncated = mDNStrue);
438 nWrites += mDNS_snprintf(buffer + nWrites, bufferLen - nWrites, "\\x%02X", byteToEscape);
439 }
440 ptr = firstByteToEscape + 1;
441 }
442 else
443 {
444 // firstByteToEscape is NULL means that the remaining characters are printable.
445 ptr += remainingLen;
446 }
447 }
448
449 exit:
450 if (outTruncated)
451 {
452 *outTruncated = truncated;
453 }
454 return nWrites;
455 }
456
GetTXTRRDisplayString(const mDNSu8 * const rdata,const mDNSu32 rdLen,char * const buffer,const mDNSu32 bufferLen)457 mDNSlocal char *GetTXTRRDisplayString(const mDNSu8 *const rdata, const mDNSu32 rdLen, char *const buffer,
458 const mDNSu32 bufferLen)
459 {
460 mDNSu32 currentLen = 0;
461 #define RESERVED_BUFFER_LENGTH 5 // " <C>", " <T>" or " <M>" plus '\0'
462 require_quiet(bufferLen >= RESERVED_BUFFER_LENGTH, exit);
463
464 mDNSu32 adjustedBufferLen = bufferLen - RESERVED_BUFFER_LENGTH;
465
466 mDNSu32 characterStringLen;
467 mDNSBool malformed = mDNSfalse;
468 mDNSBool truncated = mDNSfalse;
469 mDNSBool addSeparator = mDNSfalse;
470 for (const mDNSu8 *src = rdata, *const end = rdata + rdLen; src < end && !truncated; src += characterStringLen)
471 {
472 characterStringLen = *src++;
473
474 if (((mDNSu32)(end - src)) < characterStringLen)
475 {
476 malformed = mDNStrue;
477 break;
478 }
479
480 currentLen += putTXTRRCharacterString((buffer + currentLen), (adjustedBufferLen - currentLen), src,
481 characterStringLen, addSeparator, &truncated);
482 addSeparator = mDNStrue;
483 }
484
485 const char statusCode = (malformed ? 'M' : (truncated ? 'T' : 'C'));
486 currentLen += mDNS_snprintf((buffer + currentLen), (bufferLen - currentLen), " <%c>", statusCode);
487
488 exit:
489 return buffer + currentLen;
490 }
491
492 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
493 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
494 // 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)495 mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer)
496 {
497 const RDataBody2 *const rd = (const RDataBody2 *)rd1;
498 #define RemSpc (MaxMsg-1-length)
499 char *ptr = buffer;
500 mDNSu32 length = mDNS_snprintf(buffer, MaxMsg-1, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
501 if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer);
502 if (!rr->rdlength && rr->rrtype != kDNSType_OPT) { mDNS_snprintf(buffer+length, RemSpc, "<< ZERO RDATA LENGTH >>"); return(buffer); }
503
504 switch (rr->rrtype)
505 {
506 case kDNSType_A: mDNS_snprintf(buffer+length, RemSpc, "%.4a", &rd->ipv4); break;
507
508 case kDNSType_NS: // Same as PTR
509 case kDNSType_CNAME: // Same as PTR
510 case kDNSType_PTR: mDNS_snprintf(buffer+length, RemSpc, "%##s", rd->name.c); break;
511
512 case kDNSType_SOA: mDNS_snprintf(buffer+length, RemSpc, "%##s %##s %d %d %d %d %d",
513 rd->soa.mname.c, rd->soa.rname.c,
514 rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min);
515 break;
516
517 case kDNSType_HINFO: // Display this the same as TXT (show all constituent strings)
518 case kDNSType_TXT:
519 GetTXTRRDisplayString(rd->txt.c, rr->rdlength, buffer + length, RemSpc);
520 break;
521
522 case kDNSType_AAAA: mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6); break;
523 case kDNSType_SRV: mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s",
524 rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
525 case kDNSType_TSR: mDNS_snprintf(buffer+length, RemSpc, "%d", rd1->tsr_value); break;
526
527 case kDNSType_OPT: {
528 const rdataOPT *opt;
529 const rdataOPT *const end = (const rdataOPT *)&rd->data[rr->rdlength];
530 length += mDNS_snprintf(buffer+length, RemSpc, "Max %d", rr->rrclass);
531 for (opt = &rd->opt[0]; opt < end; opt++)
532 {
533 switch(opt->opt)
534 {
535 case kDNSOpt_LLQ:
536 length += mDNS_snprintf(buffer+length, RemSpc, " LLQ");
537 length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.llq.vers);
538 length += mDNS_snprintf(buffer+length, RemSpc, " Op %d", opt->u.llq.llqOp);
539 length += mDNS_snprintf(buffer+length, RemSpc, " Err/Port %d", opt->u.llq.err);
540 length += mDNS_snprintf(buffer+length, RemSpc, " ID %08X%08X", opt->u.llq.id.l[0], opt->u.llq.id.l[1]);
541 length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.llq.llqlease);
542 break;
543 case kDNSOpt_Lease:
544 length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.updatelease);
545 break;
546 case kDNSOpt_Owner:
547 length += mDNS_snprintf(buffer+length, RemSpc, " Owner");
548 length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.owner.vers);
549 length += mDNS_snprintf(buffer+length, RemSpc, " Seq %3d", (mDNSu8)opt->u.owner.seq); // Display as unsigned
550 length += mDNS_snprintf(buffer+length, RemSpc, " MAC %.6a", opt->u.owner.HMAC.b);
551 if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
552 {
553 length += mDNS_snprintf(buffer+length, RemSpc, " I-MAC %.6a", opt->u.owner.IMAC.b);
554 if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
555 length += mDNS_snprintf(buffer+length, RemSpc, " Password %.6a", opt->u.owner.password.b);
556 }
557 break;
558 case kDNSOpt_Trace:
559 length += mDNS_snprintf(buffer+length, RemSpc, " Trace");
560 length += mDNS_snprintf(buffer+length, RemSpc, " Platform %d", opt->u.tracer.platf);
561 length += mDNS_snprintf(buffer+length, RemSpc, " mDNSVers %d", opt->u.tracer.mDNSv);
562 break;
563 case kDNSOpt_TSR:
564 length += mDNS_snprintf(buffer+length, RemSpc, " TSR");
565 length += mDNS_snprintf(buffer+length, RemSpc, " Tm %d", opt->u.tsr.timeStamp);
566 length += mDNS_snprintf(buffer+length, RemSpc, " Hk %x", opt->u.tsr.hostkeyHash);
567 length += mDNS_snprintf(buffer+length, RemSpc, " Ix %u", opt->u.tsr.recIndex);
568 break;
569 default:
570 length += mDNS_snprintf(buffer+length, RemSpc, " Unknown %d", opt->opt);
571 break;
572 }
573 }
574 }
575 break;
576
577 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
578 case kDNSType_DS: {
579 // See <https://datatracker.ietf.org/doc/html/rfc4034#section-5.3> for DS RR Presentation Format.
580
581 dnssec_error_t err;
582 dnssec_obj_rr_ds_t ds = mDNSNULL;
583 char *ds_rdata_description = mDNSNULL;
584
585 ds = dnssec_obj_rr_ds_create(rr->name->c, rr->rrclass, rr->rdata->u.data, rr->rdlength, false, &err);
586 if (err != DNSSEC_ERROR_NO_ERROR)
587 {
588 goto ds_exit;
589 }
590
591 ds_rdata_description = dnssec_obj_rr_copy_rdata_rfc_description(ds, &err);
592 if (err != DNSSEC_ERROR_NO_ERROR)
593 {
594 goto ds_exit;
595 }
596
597 mDNS_snprintf(buffer + length, RemSpc, "%s", ds_rdata_description);
598
599 ds_exit:
600 MDNS_DISPOSE_DNSSEC_OBJ(ds);
601 mDNSPlatformMemFree(ds_rdata_description);
602 }
603 break;
604
605 case kDNSType_RRSIG: {
606 // See <https://datatracker.ietf.org/doc/html/rfc4034#section-3.2> for RRSIG RR Presentation Format.
607
608 dnssec_error_t err;
609 dnssec_obj_rr_rrsig_t rrsig = NULL;
610 char *rrsig_rdata_description = mDNSNULL;
611
612 rrsig = dnssec_obj_rr_rrsig_create(rr->name->c, rr->rdata->u.data, rr->rdlength, false, &err);
613 if (err != DNSSEC_ERROR_NO_ERROR) {
614 goto rrsig_exit;
615 }
616
617 rrsig_rdata_description = dnssec_obj_rr_copy_rdata_rfc_description(rrsig, &err);
618 if (err != DNSSEC_ERROR_NO_ERROR)
619 {
620 goto rrsig_exit;
621 }
622
623 mDNS_snprintf(buffer + length, RemSpc, "%s", rrsig_rdata_description);
624
625 rrsig_exit:
626 MDNS_DISPOSE_DNSSEC_OBJ(rrsig);
627 mDNSPlatformMemFree(rrsig_rdata_description);
628 }
629 break;
630 #endif
631
632 case kDNSType_NSEC: {
633 const domainname *next = (const domainname *)rd->data;
634 int len, bitmaplen;
635 const mDNSu8 *bmap;
636 len = DomainNameLength(next);
637 bitmaplen = rr->rdlength - len;
638 bmap = (const mDNSu8 *)((const mDNSu8 *)next + len);
639
640 if (UNICAST_NSEC(rr))
641 length += mDNS_snprintf(buffer+length, RemSpc, "%##s ", next->c);
642 PrintTypeBitmap(bmap, bitmaplen, buffer, length);
643
644 }
645 break;
646
647 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
648 case kDNSType_DNSKEY: {
649 // See <https://datatracker.ietf.org/doc/html/rfc4034#section-2.2> for DNSKEY RR Presentation Format.
650
651 dnssec_error_t err;
652 dnssec_obj_rr_dnskey_t dnskey = mDNSNULL;
653 char *dnskey_rdata_description = mDNSNULL;
654
655 dnskey = dnssec_obj_rr_dnskey_create(rr->name->c, rr->rrclass, rr->rdata->u.data, rr->rdlength, false, &err);
656 if (err != DNSSEC_ERROR_NO_ERROR) {
657 goto dnskey_exit;
658 }
659
660 dnskey_rdata_description = dnssec_obj_rr_copy_rdata_rfc_description(dnskey, &err);
661 if (err != DNSSEC_ERROR_NO_ERROR) {
662 goto dnskey_exit;
663 }
664
665 mDNS_snprintf(buffer + length, RemSpc, "%s", dnskey_rdata_description);
666
667 dnskey_exit:
668 MDNS_DISPOSE_DNSSEC_OBJ(dnskey);
669 mDNSPlatformMemFree(dnskey_rdata_description);
670 }
671 break;
672 #endif
673
674 default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %.*s", rr->rdlength, rr->rdlength, rd->data);
675 // Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not
676 for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.';
677 break;
678 }
679
680 return(buffer);
681 }
682
683 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
684
GetPrintableRDataBytes(mDNSu8 * const outBuffer,const mDNSu32 bufferLen,const mDNSu16 recordType,const mDNSu8 * const rdata,const mDNSu32 rdataLen)685 mDNSexport const mDNSu8 *GetPrintableRDataBytes(mDNSu8 *const outBuffer, const mDNSu32 bufferLen,
686 const mDNSu16 recordType, const mDNSu8 * const rdata, const mDNSu32 rdataLen)
687 {
688 const mDNSu32 totalLen = rdataLen + 2;
689 mdns_require_return_value(bufferLen >= totalLen, mDNSNULL);
690
691 outBuffer[0] = (mDNSu8)((recordType >> 8) & 0xFF);
692 outBuffer[1] = (mDNSu8)((recordType ) & 0xFF);
693 mDNSPlatformMemCopy(&outBuffer[2], rdata, (mDNSu32)rdataLen);
694
695 return outBuffer;
696 }
697
698 #endif
699
700 // See comments in mDNSEmbeddedAPI.h
701 #if _PLATFORM_HAS_STRONG_PRNG_
702 #define mDNSRandomNumber mDNSPlatformRandomNumber
703 #else
mDNSRandomFromSeed(mDNSu32 seed)704 mDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed)
705 {
706 return seed * 21 + 1;
707 }
708
mDNSMixRandomSeed(mDNSu32 seed,mDNSu8 iteration)709 mDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration)
710 {
711 return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed;
712 }
713
mDNSRandomNumber()714 mDNSlocal mDNSu32 mDNSRandomNumber()
715 {
716 static mDNSBool seeded = mDNSfalse;
717 static mDNSu32 seed = 0;
718 if (!seeded)
719 {
720 seed = mDNSMixRandomSeed(mDNSPlatformRandomSeed(), 100);
721 seeded = mDNStrue;
722 }
723 return (seed = mDNSRandomFromSeed(seed));
724 }
725 #endif // ! _PLATFORM_HAS_STRONG_PRNG_
726
mDNSRandom(mDNSu32 max)727 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive
728 {
729 mDNSu32 ret = 0;
730 mDNSu32 mask = 1;
731
732 while (mask < max) mask = (mask << 1) | 1;
733
734 do ret = mDNSRandomNumber() & mask;
735 while (ret > max);
736
737 return ret;
738 }
739
740 // See <https://datatracker.ietf.org/doc/html/draft-eastlake-fnv-19#section-5>
741 #define MDNSRESPONDER_FNV_32_BIT_OFFSET_BASIS ((mDNSu32)0x811C9DC5)
742 #define MDNSRESPONDER_FNV_32_BIT_PRIME ((mDNSu32)0x01000193)
743
mDNS_NonCryptoHashUpdateBytes(const mDNSNonCryptoHash algorithm,const mDNSu32 previousHash,const mDNSu8 * const bytes,const mDNSu32 len)744 mDNSexport mDNSu32 mDNS_NonCryptoHashUpdateBytes(const mDNSNonCryptoHash algorithm, const mDNSu32 previousHash,
745 const mDNSu8 *const bytes, const mDNSu32 len)
746 {
747 mDNSu32 hash = previousHash;
748
749 switch (algorithm) {
750 case mDNSNonCryptoHash_FNV1a:
751 {
752 for (mDNSu32 i = 0; i < len; i++)
753 {
754 hash ^= bytes[i];
755 hash *= MDNSRESPONDER_FNV_32_BIT_PRIME;
756 }
757 }
758 break;
759 case mDNSNonCryptoHash_SDBM: // See <http://www.cse.yorku.ca/~oz/hash.html>
760 {
761 for (mDNSu32 i = 0; i < len; i++)
762 {
763 // hash(i) = hash(i - 1) * 65599 + byte
764 hash = bytes[i] + (hash << 6) + (hash << 16) - hash;
765 }
766 }
767 break;
768 MDNS_COVERED_SWITCH_DEFAULT:
769 break;
770 }
771
772 return hash;
773 }
774
mDNS_NonCryptoHash(const mDNSNonCryptoHash algorithm,const mDNSu8 * const bytes,const mDNSu32 len)775 mDNSexport mDNSu32 mDNS_NonCryptoHash(const mDNSNonCryptoHash algorithm, const mDNSu8 *const bytes, const mDNSu32 len)
776 {
777 switch (algorithm) {
778 case mDNSNonCryptoHash_FNV1a:
779 return mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, MDNSRESPONDER_FNV_32_BIT_OFFSET_BASIS, bytes,
780 len);
781 case mDNSNonCryptoHash_SDBM:
782 return mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, 0, bytes, len);
783 MDNS_COVERED_SWITCH_DEFAULT:
784 return 0;
785 }
786 }
787
mDNS_DomainNameFNV1aHash(const domainname * const name)788 mDNSexport mDNSu32 mDNS_DomainNameFNV1aHash(const domainname *const name)
789 {
790 mDNSu32 hash = MDNSRESPONDER_FNV_32_BIT_OFFSET_BASIS;
791 const mDNSu32 len = DomainNameLength(name);
792 const mDNSu8 *const data = name->c;
793 for (mDNSu32 i = 0; i < len; ++i)
794 {
795 hash ^= mDNSASCIITolower(data[i]);
796 hash *= MDNSRESPONDER_FNV_32_BIT_PRIME;
797 }
798 return hash;
799 }
800
mDNSGetTimeOfDay(struct timeval * const tv,struct timezone * const tz)801 mDNSexport mDNSs32 mDNSGetTimeOfDay(struct timeval *const tv, struct timezone *const tz)
802 {
803 return gettimeofday(tv, tz);
804 }
805
mDNSSameAddress(const mDNSAddr * ip1,const mDNSAddr * ip2)806 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
807 {
808 if (ip1->type == ip2->type)
809 {
810 switch (ip1->type)
811 {
812 case mDNSAddrType_None: return(mDNStrue); // Empty addresses have no data and are therefore always equal
813 case mDNSAddrType_IPv4: return (mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
814 case mDNSAddrType_IPv6: return (mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
815 default:
816 break;
817 }
818 }
819 return(mDNSfalse);
820 }
821
mDNSAddrIsDNSMulticast(const mDNSAddr * ip)822 mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
823 {
824 switch(ip->type)
825 {
826 case mDNSAddrType_IPv4: return (mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4));
827 case mDNSAddrType_IPv6: return (mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6));
828 default: return(mDNSfalse);
829 }
830 }
831
mDNSByteInRange(const mDNSu8 byte,const mDNSu8 min,const mDNSu8 max)832 mDNSlocal mDNSBool mDNSByteInRange(const mDNSu8 byte, const mDNSu8 min, const mDNSu8 max)
833 {
834 return ((byte >= min) && (byte <= max));
835 }
836
mDNSisUTF8Tail(const mDNSu8 byte)837 mDNSlocal mDNSBool mDNSisUTF8Tail(const mDNSu8 byte)
838 {
839 // 0x80-0xBF is a common byte range for various well-formed UTF-8 byte sequences.
840 return mDNSByteInRange(byte, 0x80, 0xBF);
841 }
842
mDNSBytesStartWithWellFormedUTF8OneByteSequence(const mDNSu8 * const bytes,const mDNSu32 len)843 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8OneByteSequence(const mDNSu8 *const bytes, const mDNSu32 len)
844 {
845 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>:
846 //
847 // Code Points | First Byte
848 // ---------------+------------
849 // U+0000..U+007F | 00..7F
850
851 return ((len >= 1) && mDNSByteInRange(bytes[0], 0x00, 0x7F));
852 }
853
mDNSBytesStartWithWellFormedUTF8TwoByteSequence(const mDNSu8 * const bytes,const mDNSu32 len)854 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8TwoByteSequence(const mDNSu8 *const bytes, const mDNSu32 len)
855 {
856 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>:
857 //
858 // Code Points | First Byte | Second Byte
859 // ---------------+------------+-------------
860 // U+0080..U+07FF | C2..DF | 80..BF
861
862 return ((len >= 2) && mDNSByteInRange(bytes[0], 0xC2, 0xDF) && mDNSisUTF8Tail(bytes[1]));
863 }
864
mDNSBytesStartWithWellFormedUTF8ThreeByteSequence(const mDNSu8 * const bytes,const mDNSu32 len)865 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8ThreeByteSequence(const mDNSu8 *const bytes, const mDNSu32 len)
866 {
867 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>:
868 //
869 // Code Points | First Byte | Second Byte | Third Byte
870 // ---------------+------------+-------------+------------
871 // U+0800..U+0FFF | E0 | A0..BF | 80..BF
872 // U+1000..U+CFFF | E1..EC | 80..BF | 80..BF
873 // U+D000..U+D7FF | ED | 80..9F | 80..BF
874 // U+E000..U+FFFF | EE..EF | 80..BF | 80..BF
875
876 if ((len >= 3) && mDNSisUTF8Tail(bytes[2]))
877 {
878 if (bytes[0] == 0xE0)
879 {
880 if (mDNSByteInRange(bytes[1], 0xA0, 0xBF))
881 {
882 return mDNStrue;
883 }
884 }
885 else if (mDNSByteInRange(bytes[0], 0xE1, 0xEC) || mDNSByteInRange(bytes[0], 0xEE, 0xEF))
886 {
887 if (mDNSisUTF8Tail(bytes[1]))
888 {
889 return mDNStrue;
890 }
891 }
892 else if (bytes[0] == 0xED)
893 {
894 if (mDNSByteInRange(bytes[1], 0x80, 0x9F))
895 {
896 return mDNStrue;
897 }
898 }
899 }
900 return mDNSfalse;
901 }
902
mDNSBytesStartWithWellFormedUTF8FourByteSequence(const mDNSu8 * const bytes,const mDNSu32 len)903 mDNSlocal mDNSBool mDNSBytesStartWithWellFormedUTF8FourByteSequence(const mDNSu8 *const bytes, const mDNSu32 len)
904 {
905 // From Table 3-7. Well-Formed UTF-8 Byte Sequences of <https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>:
906 //
907 // Code Points | First Byte | Second Byte | Third Byte | Fourth Byte
908 // -------------------+------------+-------------+------------+-------------
909 // U+10000..U+3FFFF | F0 | 90..BF | 80..BF | 80..BF
910 // U+40000..U+FFFFF | F1..F3 | 80..BF | 80..BF | 80..BF
911 // U+100000..U+10FFFF | F4 | 80..8F | 80..BF | 80..BF
912
913 if ((len >= 4) && mDNSisUTF8Tail(bytes[2]) && mDNSisUTF8Tail(bytes[3]))
914 {
915 if (bytes[0] == 0xF0)
916 {
917 if (mDNSByteInRange(bytes[1], 0x90, 0xBF))
918 {
919 return mDNStrue;
920 }
921 }
922 else if (mDNSByteInRange(bytes[0], 0xF1, 0xF3))
923 {
924 if (mDNSisUTF8Tail(bytes[1]))
925 {
926 return mDNStrue;
927 }
928 }
929 else if (bytes[0] == 0xF4)
930 {
931 if (mDNSByteInRange(bytes[1], 0x80, 0x8F))
932 {
933 return mDNStrue;
934 }
935 }
936 }
937 return mDNSfalse;
938 }
939
mDNSLengthOfFirstUTF8Character(const mDNSu8 * const bytes,const mDNSu32 len)940 mDNSlocal mDNSu8 mDNSLengthOfFirstUTF8Character(const mDNSu8 *const bytes, const mDNSu32 len)
941 {
942 if (mDNSBytesStartWithWellFormedUTF8OneByteSequence(bytes, len))
943 {
944 return 1;
945 }
946 else if (mDNSBytesStartWithWellFormedUTF8TwoByteSequence(bytes, len))
947 {
948 return 2;
949 }
950 else if (mDNSBytesStartWithWellFormedUTF8ThreeByteSequence(bytes, len))
951 {
952 return 3;
953 }
954 else if (mDNSBytesStartWithWellFormedUTF8FourByteSequence(bytes, len))
955 {
956 return 4;
957 }
958 else
959 {
960 return 0;
961 }
962 }
963
mDNSLocateFirstMalformedUTF8Byte(const mDNSu8 * const bytes,const mDNSu32 byteLen)964 mDNSlocal const mDNSu8 *mDNSLocateFirstMalformedUTF8Byte(const mDNSu8 *const bytes, const mDNSu32 byteLen)
965 {
966 for (const mDNSu8 *ptr = bytes, *const end = bytes + byteLen; ptr < end;)
967 {
968 const mDNSu32 utf8CharacterLen = mDNSLengthOfFirstUTF8Character(ptr, (mDNSu32)(end - ptr));
969 if (utf8CharacterLen == 0)
970 {
971 return ptr;
972 }
973 ptr += utf8CharacterLen;
974 }
975 return mDNSNULL;
976 }
977
mDNSAreUTF8Bytes(const mDNSu8 * const bytes,const mDNSu32 len)978 mDNSlocal mDNSBool mDNSAreUTF8Bytes(const mDNSu8 *const bytes, const mDNSu32 len)
979 {
980 return (mDNSLocateFirstMalformedUTF8Byte(bytes, len) == mDNSNULL);
981 }
982
mDNSAreUTF8String(const char * const str)983 mDNSexport mDNSBool mDNSAreUTF8String(const char *const str)
984 {
985 return mDNSAreUTF8Bytes((const mDNSu8 *)str, mDNSPlatformStrLen(str));
986 }
987
GetEffectiveTTL(const uDNS_LLQType LLQType,mDNSu32 ttl)988 mDNSexport mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds
989 {
990 if (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease;
991 else if (LLQType == uDNS_LLQ_Events)
992 {
993 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
994 if (ttl == 0xFFFFFFFF) ttl = 0;
995 else ttl = kLLQ_DefLease;
996 }
997 else // else not LLQ (standard uDNS response)
998 {
999 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
1000 // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL
1001 if (ttl > 0x60000000UL / mDNSPlatformOneSecond) ttl = 0x60000000UL / mDNSPlatformOneSecond;
1002
1003 ttl = RRAdjustTTL(ttl);
1004
1005 // For mDNS, TTL zero means "delete this record"
1006 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
1007 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
1008 // This means that we'll do our 80, 85, 90, 95% queries at 12.00, 12.75, 13.50, 14.25 seconds
1009 // respectively, and then if we get no response, delete the record from the cache at 15 seconds.
1010 // This gives the server up to three seconds to respond between when we send our 80% query at 12 seconds
1011 // and when we delete the record at 15 seconds. Allowing cache lifetimes less than 15 seconds would
1012 // (with the current code) result in the server having even less than three seconds to respond
1013 // before we deleted the record and reported a "remove" event to any active questions.
1014 // Furthermore, with the current code, if we were to allow a TTL of less than 2 seconds
1015 // then things really break (e.g. we end up making a negative cache entry).
1016 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
1017 if (ttl < 15) ttl = 15;
1018 }
1019
1020 return ttl;
1021 }
1022
1023 // ***************************************************************************
1024 // MARK: - Domain Name Utility Functions
1025
1026
SameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)1027 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
1028 {
1029 int i;
1030 const int len = *a++;
1031
1032 if (len > MAX_DOMAIN_LABEL)
1033 { debugf("Malformed label (too long)"); return(mDNSfalse); }
1034
1035 if (len != *b++) return(mDNSfalse);
1036 for (i=0; i<len; i++)
1037 {
1038 mDNSu8 ac = *a++;
1039 mDNSu8 bc = *b++;
1040 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
1041 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
1042 if (ac != bc) return(mDNSfalse);
1043 }
1044 return(mDNStrue);
1045 }
1046
1047
SameDomainName(const domainname * const d1,const domainname * const d2)1048 mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
1049 {
1050 return(SameDomainNameBytes(d1->c, d2->c));
1051 }
1052
SameDomainNameBytes(const mDNSu8 * const d1,const mDNSu8 * const d2)1053 mDNSexport mDNSBool SameDomainNameBytes(const mDNSu8 *const d1, const mDNSu8 *const d2)
1054 {
1055 const mDNSu8 * a = d1;
1056 const mDNSu8 * b = d2;
1057 const mDNSu8 *const max = d1 + MAX_DOMAIN_NAME; // Maximum that's valid
1058
1059 while (*a || *b)
1060 {
1061 if (a + 1 + *a >= max)
1062 { debugf("Malformed domain name (more than 256 characters)"); return(mDNSfalse); }
1063 if (!SameDomainLabel(a, b)) return(mDNSfalse);
1064 a += 1 + *a;
1065 b += 1 + *b;
1066 }
1067
1068 return(mDNStrue);
1069 }
1070
SameDomainNameCS(const domainname * const d1,const domainname * const d2)1071 mDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2)
1072 {
1073 mDNSu16 l1 = DomainNameLength(d1);
1074 mDNSu16 l2 = DomainNameLength(d2);
1075 return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1));
1076 }
1077
IsSubdomain(const domainname * const subdomain,const domainname * const domain)1078 mDNSexport mDNSBool IsSubdomain(const domainname *const subdomain, const domainname *const domain)
1079 {
1080 mDNSBool isSubdomain = mDNSfalse;
1081 const int subdomainLabelCount = CountLabels(subdomain);
1082 const int domainLabelCount = CountLabels(domain);
1083
1084 if (subdomainLabelCount >= domainLabelCount)
1085 {
1086 const domainname *const parentDomain = SkipLeadingLabels(subdomain, subdomainLabelCount - domainLabelCount);
1087 isSubdomain = SameDomainName(parentDomain, domain);
1088 }
1089
1090 return isSubdomain;
1091 }
1092
IsLocalDomain(const domainname * d)1093 mDNSexport mDNSBool IsLocalDomain(const domainname *d)
1094 {
1095 // Domains that are defined to be resolved via link-local multicast are:
1096 // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa.
1097 static const domainname *nL = (const domainname*)"\x5" "local";
1098 static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
1099 static const domainname *n8 = (const domainname*)"\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
1100 static const domainname *n9 = (const domainname*)"\x1" "9" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
1101 static const domainname *nA = (const domainname*)"\x1" "a" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
1102 static const domainname *nB = (const domainname*)"\x1" "b" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
1103
1104 const domainname *d1, *d2, *d3, *d4, *d5; // Top-level domain, second-level domain, etc.
1105 d1 = d2 = d3 = d4 = d5 = mDNSNULL;
1106 while (d->c[0])
1107 {
1108 d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
1109 d = (const domainname*)(d->c + 1 + d->c[0]);
1110 }
1111
1112 if (d1 && SameDomainName(d1, nL)) return(mDNStrue);
1113 if (d4 && SameDomainName(d4, nR)) return(mDNStrue);
1114 if (d5 && SameDomainName(d5, n8)) return(mDNStrue);
1115 if (d5 && SameDomainName(d5, n9)) return(mDNStrue);
1116 if (d5 && SameDomainName(d5, nA)) return(mDNStrue);
1117 if (d5 && SameDomainName(d5, nB)) return(mDNStrue);
1118 return(mDNSfalse);
1119 }
1120
IsRootDomain(const domainname * const d)1121 mDNSexport mDNSBool IsRootDomain(const domainname *const d)
1122 {
1123 return (d->c[0] == 0);
1124 }
1125
LastLabel(const domainname * d)1126 mDNSexport const mDNSu8 *LastLabel(const domainname *d)
1127 {
1128 const mDNSu8 *p = d->c;
1129 while (d->c[0])
1130 {
1131 p = d->c;
1132 d = (const domainname*)(d->c + 1 + d->c[0]);
1133 }
1134 return(p);
1135 }
1136
1137 // Returns length of a domain name INCLUDING the byte for the final null label
1138 // e.g. for the root label "." it returns one
1139 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
1140 // Legal results are 1 (just root label) to 256 (MAX_DOMAIN_NAME)
1141 // If the given domainname is invalid, result is 257 (MAX_DOMAIN_NAME+1)
DomainNameLengthLimit(const domainname * const name,const mDNSu8 * const limit)1142 mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *const limit)
1143 {
1144 return(DomainNameBytesLength(name->c, limit));
1145 }
1146
DomainNameBytesLength(const mDNSu8 * const name,const mDNSu8 * const limit)1147 mDNSexport mDNSu16 DomainNameBytesLength(const mDNSu8 *const name, const mDNSu8 *const limit)
1148 {
1149 const mDNSu8 *src = name;
1150 while ((!limit || (src < limit)) && src && (*src <= MAX_DOMAIN_LABEL))
1151 {
1152 if (*src == 0) return((mDNSu16)(src - name + 1));
1153 src += 1 + *src;
1154 }
1155 return(MAX_DOMAIN_NAME+1);
1156 }
1157
DomainLabelLength(const domainlabel * const label)1158 mDNSexport mDNSu8 DomainLabelLength(const domainlabel *const label)
1159 {
1160 return label->c[0];
1161 }
1162
1163 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
1164 // for the final null label, e.g. for the root label "." it returns one.
1165 // E.g. for the FQDN "foo.com." it returns 9
1166 // (length, three data bytes, length, three more data bytes, final zero).
1167 // In the case where a parent domain name is provided, and the given name is a child
1168 // of that parent, CompressedDomainNameLength returns the length of the prefix portion
1169 // of the child name, plus TWO bytes for the compression pointer.
1170 // E.g. for the name "foo.com." with parent "com.", it returns 6
1171 // (length, three data bytes, two-byte compression pointer).
CompressedDomainNameLength(const domainname * const name,const domainname * parent)1172 mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent)
1173 {
1174 const mDNSu8 *src = name->c;
1175 if (parent && parent->c[0] == 0) parent = mDNSNULL;
1176 while (*src)
1177 {
1178 if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
1179 if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
1180 src += 1 + *src;
1181 if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
1182 }
1183 return((mDNSu16)(src - name->c + 1));
1184 }
1185
1186 // CountLabels() returns number of labels in name, excluding final root label
1187 // (e.g. for "apple.com." CountLabels returns 2.)
CountLabels(const domainname * d)1188 mDNSexport int CountLabels(const domainname *d)
1189 {
1190 int count = 0;
1191 const mDNSu8 *ptr;
1192 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
1193 return count;
1194 }
1195
1196 // SkipLeadingLabels skips over the first 'skip' labels in the domainname,
1197 // returning a pointer to the suffix with 'skip' labels removed.
SkipLeadingLabels(const domainname * d,int skip)1198 mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip)
1199 {
1200 while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; }
1201 return(d);
1202 }
1203
1204 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
1205 // The C string contains the label as-is, with no escaping, etc.
1206 // Any dots in the name are literal dots, not label separators
1207 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte
1208 // in the domainname bufer (i.e. the next byte after the terminating zero).
1209 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
1210 // AppendLiteralLabelString returns mDNSNULL.
AppendLiteralLabelString(domainname * const name,const char * cstr)1211 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
1212 {
1213 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
1214 const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
1215 const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL;
1216 const mDNSu8 *const lim = (lim1 < lim2) ? lim1 : lim2;
1217 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go
1218
1219 while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++; // Copy the data
1220 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
1221 *ptr++ = 0; // Put the null root label on the end
1222 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input
1223 else return(ptr); // Success: return new value of ptr
1224 }
1225
1226 // AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
1227 // The C string is in conventional DNS syntax:
1228 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
1229 // If successful, AppendDNSNameString returns a pointer to the next unused byte
1230 // in the domainname bufer (i.e. the next byte after the terminating zero).
1231 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
1232 // AppendDNSNameString returns mDNSNULL.
AppendDNSNameString(domainname * const name,const char * cstring)1233 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
1234 {
1235 const char * cstr = cstring;
1236 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
1237 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
1238 if (cstr[0] == '.' && cstr[1] == '\0') cstr++; // If the domain to be appended is root domain, skip it.
1239 while (*cstr && ptr < lim) // While more characters, and space to put them...
1240 {
1241 mDNSu8 *lengthbyte = ptr++; // Record where the length is going to go
1242 if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); }
1243 while (*cstr && *cstr != '.' && ptr < lim) // While we have characters in the label...
1244 {
1245 mDNSu8 c = (mDNSu8)*cstr++; // Read the character
1246 if (c == '\\') // If escape character, check next character
1247 {
1248 if (*cstr == '\0') break; // If this is the end of the string, then break
1249 c = (mDNSu8)*cstr++; // Assume we'll just take the next character
1250 if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1]))
1251 { // If three decimal digits,
1252 int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal
1253 int v1 = cstr[ 0] - '0';
1254 int v2 = cstr[ 1] - '0';
1255 int val = v0 * 100 + v1 * 10 + v2;
1256 if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it
1257 }
1258 }
1259 *ptr++ = c; // Write the character
1260 }
1261 if (*cstr == '.') cstr++; // Skip over the trailing dot (if present)
1262 if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort
1263 return(mDNSNULL);
1264 *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
1265 }
1266
1267 *ptr++ = 0; // Put the null root label on the end
1268 if (*cstr) return(mDNSNULL); // Failure: We didn't successfully consume all input
1269 else return(ptr); // Success: return new value of ptr
1270 }
1271
1272 // AppendDomainLabel appends a single label to a name.
1273 // If successful, AppendDomainLabel returns a pointer to the next unused byte
1274 // in the domainname bufer (i.e. the next byte after the terminating zero).
1275 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
1276 // AppendDomainLabel returns mDNSNULL.
AppendDomainLabel(domainname * const name,const domainlabel * const label)1277 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
1278 {
1279 int i;
1280 mDNSu8 *ptr = name->c + DomainNameLength(name) - 1;
1281
1282 // Check label is legal
1283 if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL);
1284
1285 // Check that ptr + length byte + data bytes + final zero does not exceed our limit
1286 if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL);
1287
1288 for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i]; // Copy the label data
1289 *ptr++ = 0; // Put the null root label on the end
1290 return(ptr);
1291 }
1292
AppendDomainName(domainname * const name,const domainname * const append)1293 mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append)
1294 {
1295 mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
1296 const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
1297 const mDNSu8 * src = append->c;
1298 while (src[0])
1299 {
1300 int i;
1301 if (ptr + 1 + src[0] > lim) return(mDNSNULL);
1302 for (i=0; i<=src[0]; i++) *ptr++ = src[i];
1303 *ptr = 0; // Put the null root label on the end
1304 src += i;
1305 }
1306 return(ptr);
1307 }
1308
1309 // MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
1310 // If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
1311 // If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
1312 // MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
1313 // In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
1314 // 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)1315 mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr)
1316 {
1317 mDNSu8 * ptr = label->c + 1; // Where we're putting it
1318 const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL; // The maximum we can put
1319 while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++; // Copy the label
1320 label->c[0] = (mDNSu8)(ptr - label->c - 1); // Set the length byte
1321 return(*cstr == 0); // Return mDNStrue if we successfully consumed all input
1322 }
1323
1324 // MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
1325 // The C string is in conventional DNS syntax:
1326 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
1327 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
1328 // in the domainname bufer (i.e. the next byte after the terminating zero).
1329 // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
1330 // MakeDomainNameFromDNSNameString returns mDNSNULL.
MakeDomainNameFromDNSNameString(domainname * const name,const char * cstr)1331 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
1332 {
1333 name->c[0] = 0; // Make an empty domain name
1334 return(AppendDNSNameString(name, cstr)); // And then add this string to it
1335 }
1336
ConvertDomainLabelToCString_withescape(const domainlabel * const label,char * ptr,char esc)1337 mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
1338 {
1339 const mDNSu8 * src = label->c; // Domain label we're reading
1340 const mDNSu8 len = *src++; // Read length of this (non-null) label
1341 const mDNSu8 *const end = src + len; // Work out where the label ends
1342 if (len > MAX_DOMAIN_LABEL) return(mDNSNULL); // If illegal label, abort
1343 while (src < end) // While we have characters in the label
1344 {
1345 mDNSu8 c = *src++;
1346 if (esc)
1347 {
1348 if (c == '.' || c == esc) // If character is a dot or the escape character
1349 *ptr++ = esc; // Output escape character
1350 else if (c <= ' ') // If non-printing ascii,
1351 { // Output decimal escape sequence
1352 *ptr++ = esc;
1353 *ptr++ = (char) ('0' + (c / 100) );
1354 *ptr++ = (char) ('0' + (c / 10) % 10);
1355 c = (mDNSu8)('0' + (c ) % 10);
1356 }
1357 }
1358 *ptr++ = (char)c; // Copy the character
1359 }
1360 *ptr = 0; // Null-terminate the string
1361 return(ptr); // and return
1362 }
1363
1364 // 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)1365 mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
1366 {
1367 const mDNSu8 *src = name->c; // Domain name we're reading
1368 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
1369
1370 if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot
1371
1372 while (*src) // While more characters in the domain name
1373 {
1374 if (src + 1 + *src >= max) return(mDNSNULL);
1375 ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
1376 if (!ptr) return(mDNSNULL);
1377 src += 1 + *src;
1378 *ptr++ = '.'; // Write the dot after the label
1379 }
1380
1381 *ptr++ = 0; // Null-terminate the string
1382 return(ptr); // and return
1383 }
1384
1385 // RFC 1034 rules:
1386 // Host names must start with a letter, end with a letter or digit,
1387 // and have as interior characters only letters, digits, and hyphen.
1388 // This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
1389
ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[],domainlabel * const hostlabel)1390 mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel)
1391 {
1392 const mDNSu8 * src = &UTF8Name[1];
1393 const mDNSu8 *const end = &UTF8Name[1] + UTF8Name[0];
1394 mDNSu8 * ptr = &hostlabel->c[1];
1395 const mDNSu8 *const lim = &hostlabel->c[1] + MAX_DOMAIN_LABEL;
1396 while (src < end)
1397 {
1398 // Delete apostrophes from source name
1399 if (src[0] == '\'') { src++; continue; } // Standard straight single quote
1400 if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99)
1401 { src += 3; continue; } // Unicode curly apostrophe
1402 if (ptr < lim)
1403 {
1404 if (mDNSValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
1405 else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
1406 }
1407 src++;
1408 }
1409 while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks
1410 hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
1411 }
1412
ConstructServiceName(domainname * const fqdn,const domainlabel * name,const domainname * type,const domainname * const domain)1413 mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
1414 const domainlabel *name, const domainname *type, const domainname *const domain)
1415 {
1416 int i, len;
1417 mDNSu8 *dst = fqdn->c;
1418 const mDNSu8 *src;
1419 const char *errormsg;
1420
1421 // In the case where there is no name (and ONLY in that case),
1422 // a single-label subtype is allowed as the first label of a three-part "type"
1423 if (!name)
1424 {
1425 const mDNSu8 *s0 = type->c;
1426 if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63)
1427 {
1428 const mDNSu8 * s1 = s0 + 1 + s0[0];
1429 if (s1[0] && s1[0] < 0x40) // and legal second label (at least one character, and no more than 63)
1430 {
1431 const mDNSu8 *s2 = s1 + 1 + s1[0];
1432 if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0) // and we have three and only three labels
1433 {
1434 static const mDNSu8 SubTypeLabel[5] = mDNSSubTypeLabel;
1435 src = s0; // Copy the first label
1436 len = *src;
1437 for (i=0; i <= len; i++) *dst++ = *src++;
1438 for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
1439 type = (const domainname *)s1;
1440
1441 // Special support to enable the DNSServiceBrowse call made by Bonjour Browser
1442 // For these queries, we retract the "._sub" we just added between the subtype and the main type
1443 // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
1444 if (SameDomainName((const domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
1445 dst -= sizeof(SubTypeLabel);
1446 }
1447 }
1448 }
1449 }
1450
1451 if (name && name->c[0])
1452 {
1453 src = name->c; // Put the service name into the domain name
1454 len = *src;
1455 if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; }
1456 for (i=0; i<=len; i++) *dst++ = *src++;
1457 }
1458 else
1459 name = (domainlabel*)""; // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
1460
1461 src = type->c; // Put the service type into the domain name
1462 len = *src;
1463 if (len < 2 || len > 16)
1464 {
1465 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Bad service type in " PRI_DM_LABEL "." PRI_DM_NAME PRI_DM_NAME" Application protocol name must be "
1466 "underscore plus 1-15 characters. See <http://www.dns-sd.org/ServiceTypes.html>",
1467 DM_LABEL_PARAM(name), DM_NAME_PARAM(type), DM_NAME_PARAM(domain));
1468 }
1469 if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
1470 if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
1471 for (i=2; i<=len; i++)
1472 {
1473 // Letters and digits are allowed anywhere
1474 if (mDNSIsLetter(src[i]) || mDNSIsDigit(src[i])) continue;
1475 // Hyphens are only allowed as interior characters
1476 // Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them,
1477 // with the same rule as hyphens
1478 if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len)
1479 {
1480 continue;
1481 }
1482 errormsg = "Application protocol name must contain only letters, digits, and hyphens";
1483 goto fail;
1484 }
1485 for (i=0; i<=len; i++) *dst++ = *src++;
1486
1487 len = *src;
1488 if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; }
1489 for (i=0; i<=len; i++) *dst++ = *src++;
1490
1491 if (*src) { errormsg = "Service type must have only two labels"; goto fail; }
1492
1493 *dst = 0;
1494 if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; }
1495 if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa"))
1496 { errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
1497 dst = AppendDomainName(fqdn, domain);
1498 if (!dst) { errormsg = "Service domain too long"; goto fail; }
1499 return(dst);
1500
1501 fail:
1502 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "ConstructServiceName: " PUB_S ": " PRI_DM_LABEL "." PRI_DM_NAME PRI_DM_NAME , errormsg,
1503 DM_LABEL_PARAM(name), DM_NAME_PARAM(type), DM_NAME_PARAM(domain));
1504 return(mDNSNULL);
1505 }
1506
1507 // A service name has the form: instance.application-protocol.transport-protocol.domain
1508 // DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character
1509 // set or length limits for the protocol names, and the final domain is allowed to be empty.
1510 // However, if the given FQDN doesn't contain at least three labels,
1511 // DeconstructServiceName will reject it and return mDNSfalse.
DeconstructServiceName(const domainname * const fqdn,domainlabel * const name,domainname * const type,domainname * const domain)1512 mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
1513 domainlabel *const name, domainname *const type, domainname *const domain)
1514 {
1515 int i, len;
1516 const mDNSu8 *src = fqdn->c;
1517 const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
1518 mDNSu8 *dst;
1519
1520 dst = name->c; // Extract the service name
1521 len = *src;
1522 if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); }
1523 if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
1524 for (i=0; i<=len; i++) *dst++ = *src++;
1525
1526 dst = type->c; // Extract the service type
1527 len = *src;
1528 if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); }
1529 if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
1530 if (src[1] != '_') { debugf("DeconstructServiceName: No _ at start of application protocol"); return(mDNSfalse); }
1531 for (i=0; i<=len; i++) *dst++ = *src++;
1532
1533 len = *src;
1534 if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); }
1535 if (!ValidTransportProtocol(src))
1536 { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); }
1537 for (i=0; i<=len; i++) *dst++ = *src++;
1538 *dst++ = 0; // Put terminator on the end of service type
1539
1540 dst = domain->c; // Extract the service domain
1541 while (*src)
1542 {
1543 len = *src;
1544 if (len >= 0x40)
1545 { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); }
1546 if (src + 1 + len + 1 >= max)
1547 { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); }
1548 for (i=0; i<=len; i++) *dst++ = *src++;
1549 }
1550 *dst++ = 0; // Put the null root label on the end
1551
1552 return(mDNStrue);
1553 }
1554
DNSNameToLowerCase(domainname * d,domainname * result)1555 mDNSexport mStatus DNSNameToLowerCase(domainname *d, domainname *result)
1556 {
1557 const mDNSu8 *a = d->c;
1558 mDNSu8 *b = result->c;
1559 const mDNSu8 *const max = d->c + MAX_DOMAIN_NAME;
1560 int i, len;
1561
1562 while (*a)
1563 {
1564 if (a + 1 + *a >= max)
1565 {
1566 LogMsg("DNSNameToLowerCase: ERROR!! Malformed Domain name");
1567 return mStatus_BadParamErr;
1568 }
1569 len = *a++;
1570 *b++ = len;
1571 for (i = 0; i < len; i++)
1572 {
1573 mDNSu8 ac = *a++;
1574 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
1575 *b++ = ac;
1576 }
1577 }
1578 *b = 0;
1579
1580 return mStatus_NoError;
1581 }
1582
1583 // Notes on UTF-8:
1584 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
1585 // 10xxxxxx is a continuation byte of a multi-byte character
1586 // 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x 80 - 0x 800-1)
1587 // 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x 800 - 0x 10000-1)
1588 // 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x 10000 - 0x 200000-1)
1589 // 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1)
1590 // 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1)
1591 //
1592 // UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF.
1593 // Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive
1594 // about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?")
1595 // The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8),
1596 // and the second is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8).
1597
TruncateUTF8ToLength(mDNSu8 * string,mDNSu32 length,mDNSu32 max)1598 mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max)
1599 {
1600 if (length > max)
1601 {
1602 mDNSu8 c1 = string[max]; // First byte after cut point
1603 mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0; // Second byte after cut point
1604 length = max; // Trim length down
1605 while (length > 0)
1606 {
1607 // Check if the byte right after the chop point is a UTF-8 continuation byte,
1608 // or if the character right after the chop point is the second of a UTF-16 surrogate pair.
1609 // If so, then we continue to chop more bytes until we get to a legal chop point.
1610 mDNSBool continuation = ((c1 & 0xC0) == 0x80);
1611 mDNSBool secondsurrogate = (c1 == 0xED && (c2 & 0xF0) == 0xB0);
1612 if (!continuation && !secondsurrogate) break;
1613 c2 = c1;
1614 c1 = string[--length];
1615 }
1616 // Having truncated characters off the end of our string, also cut off any residual white space
1617 while (length > 0 && string[length-1] <= ' ') length--;
1618 }
1619 return(length);
1620 }
1621
1622 // Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
1623 // name ends in "-nnn", where n is some decimal number.
LabelContainsSuffix(const domainlabel * const name,const mDNSBool RichText)1624 mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText)
1625 {
1626 mDNSu16 l = name->c[0];
1627
1628 if (RichText)
1629 {
1630 if (l < 4) return mDNSfalse; // Need at least " (2)"
1631 if (name->c[l--] != ')') return mDNSfalse; // Last char must be ')'
1632 if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit
1633 l--;
1634 while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits
1635 return (name->c[l] == '(' && name->c[l - 1] == ' ');
1636 }
1637 else
1638 {
1639 if (l < 2) return mDNSfalse; // Need at least "-2"
1640 if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit
1641 l--;
1642 while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits
1643 return (name->c[l] == '-');
1644 }
1645 }
1646
1647 // removes an auto-generated suffix (appended on a name collision) from a label. caller is
1648 // responsible for ensuring that the label does indeed contain a suffix. returns the number
1649 // from the suffix that was removed.
RemoveLabelSuffix(domainlabel * name,mDNSBool RichText)1650 mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
1651 {
1652 mDNSu32 val = 0, multiplier = 1;
1653
1654 // Chop closing parentheses from RichText suffix
1655 if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
1656
1657 // Get any existing numerical suffix off the name
1658 while (mDNSIsDigit(name->c[name->c[0]]))
1659 { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
1660
1661 // Chop opening parentheses or dash from suffix
1662 if (RichText)
1663 {
1664 if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2;
1665 }
1666 else
1667 {
1668 if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1;
1669 }
1670
1671 return(val);
1672 }
1673
1674 // appends a numerical suffix to a label, with the number following a whitespace and enclosed
1675 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
AppendLabelSuffix(domainlabel * const name,mDNSu32 val,const mDNSBool RichText)1676 mDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText)
1677 {
1678 mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
1679 if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)")
1680
1681 // Truncate trailing spaces from RichText names
1682 if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
1683
1684 while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; }
1685
1686 name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars);
1687
1688 if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; }
1689 else { name->c[++name->c[0]] = '-'; }
1690
1691 while (divisor)
1692 {
1693 name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor);
1694 val %= divisor;
1695 divisor /= 10;
1696 }
1697
1698 if (RichText) name->c[++name->c[0]] = ')';
1699 }
1700
IncrementLabelSuffix(domainlabel * name,mDNSBool RichText)1701 mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
1702 {
1703 mDNSu32 val = 0;
1704
1705 if (LabelContainsSuffix(name, RichText))
1706 val = RemoveLabelSuffix(name, RichText);
1707
1708 // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
1709 // If existing suffix in the range 2-9, increment it.
1710 // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
1711 // so add a random increment to improve the chances of finding an available name next time.
1712 if (val == 0) val = 2;
1713 else if (val < 10) val++;
1714 else val += 1 + mDNSRandom(99);
1715
1716 AppendLabelSuffix(name, val, RichText);
1717 }
1718
1719 // ***************************************************************************
1720 // MARK: - Resource Record Utility Functions
1721
1722 // Set up a AuthRecord with sensible default values.
1723 // 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)1724 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
1725 mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context)
1726 {
1727 //
1728 // LocalOnly auth record can be created with LocalOnly InterfaceID or a valid InterfaceID.
1729 // Most of the applications normally create with LocalOnly InterfaceID and we store them as
1730 // such, so that we can deliver the response to questions that specify LocalOnly InterfaceID.
1731 // LocalOnly resource records can also be created with valid InterfaceID which happens today
1732 // when we create LocalOnly records for /etc/hosts.
1733
1734 if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly)
1735 {
1736 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d",
1737 InterfaceID, artype);
1738 }
1739 else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P)
1740 {
1741 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d",
1742 InterfaceID, artype);
1743 }
1744 else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly))
1745 {
1746 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d",
1747 InterfaceID, artype);
1748 }
1749
1750 // Don't try to store a TTL bigger than we can represent in platform time units
1751 if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
1752 ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
1753 else if (ttl == 0) // And Zero TTL is illegal
1754 ttl = DefaultTTLforRRType(rrtype);
1755
1756 // Field Group 1: The actual information pertaining to this resource record
1757 rr->resrec.RecordType = RecordType;
1758 rr->resrec.InterfaceID = InterfaceID;
1759 rr->resrec.name = &rr->namestorage;
1760 rr->resrec.rrtype = rrtype;
1761 rr->resrec.rrclass = kDNSClass_IN;
1762 rr->resrec.rroriginalttl = ttl;
1763 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
1764 rr->resrec.metadata = NULL;
1765 #else
1766 rr->resrec.rDNSServer = mDNSNULL;
1767 #endif
1768 // rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
1769 // rr->resrec.rdestimate = set in mDNS_Register_internal
1770 // rr->resrec.rdata = MUST be set by client
1771
1772 if (RDataStorage)
1773 rr->resrec.rdata = RDataStorage;
1774 else
1775 {
1776 rr->resrec.rdata = &rr->rdatastorage;
1777 rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
1778 }
1779
1780 // Field Group 2: Persistent metadata for Authoritative Records
1781 rr->Additional1 = mDNSNULL;
1782 rr->Additional2 = mDNSNULL;
1783 rr->DependentOn = mDNSNULL;
1784 rr->RRSet = 0;
1785 rr->RecordCallback = Callback;
1786 rr->RecordContext = Context;
1787
1788 rr->AutoTarget = Target_Manual;
1789 rr->AllowRemoteQuery = mDNSfalse;
1790 rr->ForceMCast = mDNSfalse;
1791
1792 rr->WakeUp = zeroOwner;
1793 rr->AddressProxy = zeroAddr;
1794 rr->TimeRcvd = 0;
1795 rr->TimeExpire = 0;
1796 rr->ARType = artype;
1797 rr->AuthFlags = 0;
1798
1799 // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
1800 // Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal)
1801
1802 // For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case
1803 // (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch
1804 // of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.)
1805 rr->state = regState_Zero;
1806 rr->uselease = 0;
1807 rr->expire = 0;
1808 rr->Private = 0;
1809 rr->updateid = zeroID;
1810 rr->zone = rr->resrec.name;
1811 rr->nta = mDNSNULL;
1812 rr->tcp = mDNSNULL;
1813 rr->OrigRData = 0;
1814 rr->OrigRDLen = 0;
1815 rr->InFlightRData = 0;
1816 rr->InFlightRDLen = 0;
1817 rr->QueuedRData = 0;
1818 rr->QueuedRDLen = 0;
1819 mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo));
1820 rr->SRVChanged = mDNSfalse;
1821 rr->mState = mergeState_Zero;
1822
1823 rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register()
1824 }
1825
mDNS_SetupQuestion(DNSQuestion * const q,const mDNSInterfaceID InterfaceID,const domainname * const name,const mDNSu16 qtype,mDNSQuestionCallback * const callback,void * const context)1826 mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name,
1827 const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context)
1828 {
1829 q->InterfaceID = InterfaceID;
1830 q->flags = 0;
1831 AssignDomainName(&q->qname, name);
1832 q->qtype = qtype;
1833 q->qclass = kDNSClass_IN;
1834 q->LongLived = mDNSfalse;
1835 q->ExpectUnique = (qtype != kDNSType_PTR);
1836 q->ForceMCast = mDNSfalse;
1837 q->ReturnIntermed = mDNSfalse;
1838 q->SuppressUnusable = mDNSfalse;
1839 q->AppendSearchDomains = 0;
1840 q->TimeoutQuestion = 0;
1841 q->WakeOnResolve = 0;
1842 q->UseBackgroundTraffic = mDNSfalse;
1843 q->ProxyQuestion = 0;
1844 q->pid = mDNSPlatformGetPID();
1845 q->euid = 0;
1846 q->BlockedByPolicy = mDNSfalse;
1847 q->ServiceID = -1;
1848 q->QuestionCallback = callback;
1849 q->QuestionContext = context;
1850 }
1851
RDataHashValue(const ResourceRecord * const rr)1852 mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
1853 {
1854 int len = rr->rdlength;
1855 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
1856 const mDNSu8 *ptr = rdb->data;
1857 mDNSu32 sum = 0;
1858
1859 switch(rr->rrtype)
1860 {
1861 case kDNSType_NS:
1862 case kDNSType_MD:
1863 case kDNSType_MF:
1864 case kDNSType_CNAME:
1865 case kDNSType_MB:
1866 case kDNSType_MG:
1867 case kDNSType_MR:
1868 case kDNSType_PTR:
1869 case kDNSType_NSAP_PTR:
1870 case kDNSType_DNAME: return DomainNameHashValue(&rdb->name);
1871
1872 case kDNSType_SOA: return rdb->soa.serial +
1873 rdb->soa.refresh +
1874 rdb->soa.retry +
1875 rdb->soa.expire +
1876 rdb->soa.min +
1877 DomainNameHashValue(&rdb->soa.mname) +
1878 DomainNameHashValue(&rdb->soa.rname);
1879
1880 case kDNSType_MX:
1881 case kDNSType_AFSDB:
1882 case kDNSType_RT:
1883 case kDNSType_KX: return DomainNameHashValue(&rdb->mx.exchange);
1884
1885 case kDNSType_MINFO:
1886 case kDNSType_RP: return DomainNameHashValue(&rdb->rp.mbox) + DomainNameHashValue(&rdb->rp.txt);
1887
1888 case kDNSType_PX: return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400);
1889
1890 case kDNSType_SRV: return DomainNameHashValue(&rdb->srv.target);
1891
1892 case kDNSType_OPT: return 0; // OPT is a pseudo-RR container structure; makes no sense to compare
1893
1894 case kDNSType_NSEC: {
1895 int dlen;
1896 dlen = DomainNameLength(&rdb->name);
1897 sum = DomainNameHashValue(&rdb->name);
1898 ptr += dlen;
1899 len -= dlen;
1900 fallthrough();
1901 /* FALLTHROUGH */
1902 }
1903
1904 default:
1905 {
1906 int i;
1907 for (i=0; i+1 < len; i+=2)
1908 {
1909 sum += (((mDNSu32)(ptr[i])) << 8) | ptr[i+1];
1910 sum = (sum<<3) | (sum>>29);
1911 }
1912 if (i < len)
1913 {
1914 sum += ((mDNSu32)(ptr[i])) << 8;
1915 }
1916 return(sum);
1917 }
1918 }
1919 }
1920
1921 // r1 has to be a full ResourceRecord including rrtype and rdlength
1922 // 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)1923 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename)
1924 {
1925 const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data;
1926 const RDataBody2 *const b2 = (const RDataBody2 *)r2;
1927 switch(r1->rrtype)
1928 {
1929 case kDNSType_NS:
1930 case kDNSType_MD:
1931 case kDNSType_MF:
1932 case kDNSType_CNAME:
1933 case kDNSType_MB:
1934 case kDNSType_MG:
1935 case kDNSType_MR:
1936 case kDNSType_PTR:
1937 case kDNSType_NSAP_PTR:
1938 case kDNSType_DNAME: return(SameDomainName(&b1->name, &b2->name));
1939
1940 case kDNSType_SOA: return (mDNSBool)( b1->soa.serial == b2->soa.serial &&
1941 b1->soa.refresh == b2->soa.refresh &&
1942 b1->soa.retry == b2->soa.retry &&
1943 b1->soa.expire == b2->soa.expire &&
1944 b1->soa.min == b2->soa.min &&
1945 samename(&b1->soa.mname, &b2->soa.mname) &&
1946 samename(&b1->soa.rname, &b2->soa.rname));
1947
1948 case kDNSType_MX:
1949 case kDNSType_AFSDB:
1950 case kDNSType_RT:
1951 case kDNSType_KX: return (mDNSBool)( b1->mx.preference == b2->mx.preference &&
1952 samename(&b1->mx.exchange, &b2->mx.exchange));
1953
1954 case kDNSType_MINFO:
1955 case kDNSType_RP: return (mDNSBool)( samename(&b1->rp.mbox, &b2->rp.mbox) &&
1956 samename(&b1->rp.txt, &b2->rp.txt));
1957
1958 case kDNSType_PX: return (mDNSBool)( b1->px.preference == b2->px.preference &&
1959 samename(&b1->px.map822, &b2->px.map822) &&
1960 samename(&b1->px.mapx400, &b2->px.mapx400));
1961
1962 case kDNSType_SRV: return (mDNSBool)( b1->srv.priority == b2->srv.priority &&
1963 b1->srv.weight == b2->srv.weight &&
1964 mDNSSameIPPort(b1->srv.port, b2->srv.port) &&
1965 samename(&b1->srv.target, &b2->srv.target));
1966
1967 case kDNSType_OPT: return mDNSfalse; // OPT is a pseudo-RR container structure; makes no sense to compare
1968 case kDNSType_NSEC: {
1969 // If the "nxt" name changes in case, we want to delete the old
1970 // and store just the new one. If the caller passes in SameDomainCS for "samename",
1971 // we would return "false" when the only change between the two rdata is the case
1972 // change in "nxt".
1973 //
1974 // Note: rdlength of both the RData are same (ensured by the caller) and hence we can
1975 // use just r1->rdlength below
1976
1977 int dlen1 = DomainNameLength(&b1->name);
1978 int dlen2 = DomainNameLength(&b2->name);
1979 return (mDNSBool)(dlen1 == dlen2 &&
1980 samename(&b1->name, &b2->name) &&
1981 mDNSPlatformMemSame(b1->data + dlen1, b2->data + dlen2, r1->rdlength - dlen1));
1982 }
1983
1984 default: return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength));
1985 }
1986 }
1987
BitmapTypeCheck(const mDNSu8 * bmap,int bitmaplen,mDNSu16 type)1988 mDNSexport mDNSBool BitmapTypeCheck(const mDNSu8 *bmap, int bitmaplen, mDNSu16 type)
1989 {
1990 int win, wlen;
1991 int wintype;
1992
1993 // The window that this type belongs to. NSEC has 256 windows that
1994 // comprises of 256 types.
1995 wintype = type >> 8;
1996
1997 while (bitmaplen > 0)
1998 {
1999 if (bitmaplen < 3)
2000 {
2001 LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d short", bitmaplen);
2002 return mDNSfalse;
2003 }
2004
2005 win = *bmap++;
2006 wlen = *bmap++;
2007 bitmaplen -= 2;
2008 if (bitmaplen < wlen || wlen < 1 || wlen > 32)
2009 {
2010 LogInfo("BitmapTypeCheck: malformed nsec, bitmaplen %d wlen %d, win %d", bitmaplen, wlen, win);
2011 return mDNSfalse;
2012 }
2013 if (win < 0 || win >= 256)
2014 {
2015 LogInfo("BitmapTypeCheck: malformed nsec, wlen %d", wlen);
2016 return mDNSfalse;
2017 }
2018 if (win == wintype)
2019 {
2020 // First byte in the window serves 0 to 7, the next one serves 8 to 15 and so on.
2021 // Calculate the right byte offset first.
2022 int boff = (type & 0xff ) >> 3;
2023 if (wlen <= boff)
2024 return mDNSfalse;
2025 // The last three bits values 0 to 7 corresponds to bit positions
2026 // within the byte.
2027 return (bmap[boff] & (0x80 >> (type & 7)));
2028 }
2029 else
2030 {
2031 // If the windows are ordered, then we could check to see
2032 // if wintype > win and then return early.
2033 bmap += wlen;
2034 bitmaplen -= wlen;
2035 }
2036 }
2037 return mDNSfalse;
2038 }
2039
2040 // Don't call this function if the resource record is not NSEC. It will return false
2041 // which means that the type does not exist.
RRAssertsExistence(const ResourceRecord * const rr,mDNSu16 type)2042 mDNSexport mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type)
2043 {
2044 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
2045 const mDNSu8 *nsec = rdb->data;
2046 int len, bitmaplen;
2047 const mDNSu8 *bmap;
2048
2049 if (rr->rrtype != kDNSType_NSEC) return mDNSfalse;
2050
2051 len = DomainNameLength(&rdb->name);
2052
2053 bitmaplen = rr->rdlength - len;
2054 bmap = nsec + len;
2055 return (BitmapTypeCheck(bmap, bitmaplen, type));
2056 }
2057
2058 // Don't call this function if the resource record is not NSEC. It will return false
2059 // which means that the type exists.
RRAssertsNonexistence(const ResourceRecord * const rr,mDNSu16 type)2060 mDNSexport mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type)
2061 {
2062 if (rr->rrtype != kDNSType_NSEC) return mDNSfalse;
2063
2064 return !RRAssertsExistence(rr, type);
2065 }
2066
RRTypeAnswersQuestionType(const ResourceRecord * const rr,const mDNSu16 qtype,const RRTypeAnswersQuestionTypeFlags flags)2067 mDNSexport mDNSBool RRTypeAnswersQuestionType(const ResourceRecord *const rr, const mDNSu16 qtype,
2068 const RRTypeAnswersQuestionTypeFlags flags)
2069 {
2070 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
2071 // This checks if the record is what the question requires:
2072 // 1. If the question does not enable DNSSEC, either "DNSSEC to be validated" nor "DNSSEC validated" record answers it.
2073 // 2. If the question enables DNSSEC, and it is not a duplicate question, it needs both "DNSSEC to be validated" nor "DNSSEC validated" records:
2074 // a. Get "DNSSEC to be validated" to do DNSSEC validation.
2075 // b. Get "DNSSEC validated" to return to the client.
2076 // 3. If the question enables DNSSEC, and it is a duplicate question, it only needs "DNSSEC validated" records:
2077 // a. Does not need "DNSSEC to be validated" because the non-duplicate question will do the validation.
2078 // b. Get "DNSSEC validated" to return to the client.
2079 const mDNSBool requiresRRToValidate = ((flags & kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate) != 0);
2080 const mDNSBool requiresValidatedRR = ((flags & kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRValidated) != 0);
2081 if (!resource_record_answers_dnssec_question_request_type(rr, requiresRRToValidate, requiresValidatedRR))
2082 {
2083 return mDNSfalse;
2084 }
2085 #else
2086 (void) flags;
2087 #endif
2088
2089 // OPT should not answer any questions.
2090 if (rr->rrtype == kDNSType_OPT)
2091 {
2092 return mDNSfalse;
2093 }
2094
2095 // CNAME answers any questions, except negative CNAME. (this function is not responsible to check that)
2096 if (rr->rrtype == kDNSType_CNAME)
2097 {
2098 return mDNStrue;
2099 }
2100
2101 // The most usual case where the record type matches the question type.
2102 if (rr->rrtype == qtype)
2103 {
2104 return mDNStrue;
2105 }
2106
2107 // If question asks for any DNS record type, then any record type can answer this question.
2108 if (qtype == kDNSQType_ANY)
2109 {
2110 return mDNStrue;
2111 }
2112
2113 // If the mDNS NSEC record asserts the nonexistence of the question type, then it answers the question type
2114 // negatively.
2115 if (MULTICAST_NSEC(rr) && RRAssertsNonexistence(rr, qtype))
2116 {
2117 return mDNStrue;
2118 }
2119
2120 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
2121 // The type covered of RRSIG should match the non-duplicate DNSSEC question type, because RRSIG will be used by it
2122 // to do DNSSEC validation.
2123 if (resource_record_as_rrsig_answers_dnssec_question_type(rr, qtype))
2124 {
2125 return mDNStrue;
2126 }
2127 #endif
2128
2129 return mDNSfalse;
2130 }
2131
2132 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
RRMatchesQuestionService(const ResourceRecord * const rr,const DNSQuestion * const q)2133 mDNSlocal mDNSBool RRMatchesQuestionService(const ResourceRecord *const rr, const DNSQuestion *const q)
2134 {
2135 return mdns_cache_metadata_get_dns_service(rr->metadata) == q->dnsservice;
2136 }
2137 #endif
2138
RRIsResolvedBymDNS(const ResourceRecord * const rr)2139 mDNSlocal mDNSBool RRIsResolvedBymDNS(const ResourceRecord *const rr)
2140 {
2141 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
2142 if (mdns_cache_metadata_get_dns_service(rr->metadata))
2143 {
2144 return mDNSfalse;
2145 }
2146 #endif
2147 return (rr->InterfaceID != 0);
2148 }
2149
2150 // ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
2151 // SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
2152 // SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
2153 // because it has to check all the way to the end of the names to be sure.
2154 // In cases where we know in advance that the names match it's especially advantageous to skip the
2155 // SameDomainName() call because that's precisely the time when it's most expensive and least useful.
2156
SameNameRecordAnswersQuestion(const ResourceRecord * const rr,mDNSBool isAuthRecord,const DNSQuestion * const q)2157 mDNSlocal mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
2158 {
2159 // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
2160 // are handled in LocalOnlyRecordAnswersQuestion
2161 if (LocalOnlyOrP2PInterface(rr->InterfaceID))
2162 {
2163 LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
2164 return mDNSfalse;
2165 }
2166 if (q->Suppressed && (!q->ForceCNAMEFollows || (rr->rrtype != kDNSType_CNAME)))
2167 return mDNSfalse;
2168
2169 if (rr->InterfaceID &&
2170 q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
2171 rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
2172
2173 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY)
2174 if (DNSQuestionUsesMDNSAlternativeService(q))
2175 {
2176 if (!RRMatchesQuestionService(rr, q))
2177 {
2178 return mDNSfalse;
2179 }
2180 }
2181 else
2182 #endif
2183 {
2184 const mDNSBool resolvedBymDNS = RRIsResolvedBymDNS(rr);
2185 mDNSBool ismDNSQuestion = mDNSOpaque16IsZero(q->TargetQID);
2186
2187 // If the record is resolved via the non-mDNS channel, the server or service used should match.
2188 if (!isAuthRecord && !resolvedBymDNS)
2189 {
2190 if (ismDNSQuestion)
2191 {
2192 return mDNSfalse;
2193 }
2194 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
2195 if (!RRMatchesQuestionService(rr, q)) return(mDNSfalse);
2196 #else
2197 const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
2198 const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
2199 if (idr != idq) return(mDNSfalse);
2200 #endif
2201 }
2202
2203 // mDNS records can only be used to answer mDNS questions.
2204 if (resolvedBymDNS && !ismDNSQuestion)
2205 {
2206 return mDNSfalse;
2207 }
2208 }
2209
2210 // CNAME answers question of any type and a negative cache record should not prevent us from querying other
2211 // valid types at the same name.
2212 if (rr->rrtype == kDNSType_CNAME && rr->RecordType == kDNSRecordTypePacketNegative && rr->rrtype != q->qtype)
2213 return mDNSfalse;
2214
2215 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
2216 RRTypeAnswersQuestionTypeFlags flags = kRRTypeAnswersQuestionTypeFlagsNone;
2217 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
2218 // Primary DNSSEC requestor is the non-duplicate DNSSEC question that does the DNSSEC validation, therefore, it needs
2219 // the "DNSSEC to be validated" record. (It is also DNSSEC requestor, see below)
2220 if (dns_question_is_primary_dnssec_requestor(q))
2221 {
2222 flags |= kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate;
2223 }
2224 // DNSSEC requestor is the DNSSEC question that needs DNSSEC validated result.
2225 if (dns_question_is_dnssec_requestor(q))
2226 {
2227 flags |= kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRValidated;
2228 }
2229 #endif
2230
2231 const mDNSBool typeMatches = RRTypeAnswersQuestionType(rr, q->qtype, flags);
2232 if (!typeMatches)
2233 {
2234 return(mDNSfalse);
2235 }
2236
2237 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
2238
2239
2240 return(mDNStrue);
2241 }
2242
SameNameCacheRecordAnswersQuestion(const CacheRecord * const cr,const DNSQuestion * const q)2243 mDNSexport mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
2244 {
2245 return SameNameRecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
2246 }
2247
RecordAnswersQuestion(const ResourceRecord * const rr,mDNSBool isAuthRecord,const DNSQuestion * const q)2248 mDNSlocal mDNSBool RecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
2249 {
2250 if (!SameNameRecordAnswersQuestion(rr, isAuthRecord, q))
2251 return mDNSfalse;
2252
2253 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
2254 }
2255
ResourceRecordAnswersQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)2256 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
2257 {
2258 return RecordAnswersQuestion(rr, mDNSfalse, q);
2259 }
2260
AuthRecordAnswersQuestion(const AuthRecord * const ar,const DNSQuestion * const q)2261 mDNSexport mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
2262 {
2263 return RecordAnswersQuestion(&ar->resrec, mDNStrue, q);
2264 }
2265
CacheRecordAnswersQuestion(const CacheRecord * const cr,const DNSQuestion * const q)2266 mDNSexport mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
2267 {
2268 return RecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
2269 }
2270
2271 // We have a separate function to handle LocalOnly AuthRecords because they can be created with
2272 // a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
2273 // multicast resource records (which has a valid InterfaceID) which can't be used to answer
2274 // unicast questions. ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion can't tell whether
2275 // a resource record is multicast or LocalOnly by just looking at the ResourceRecord because
2276 // LocalOnly records are truly identified by ARType in the AuthRecord. As P2P and LocalOnly record
2277 // are kept in the same hash table, we use the same function to make it easy for the callers when
2278 // they walk the hash table to answer LocalOnly/P2P questions
2279 //
LocalOnlyRecordAnswersQuestion(AuthRecord * const ar,const DNSQuestion * const q)2280 mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const DNSQuestion *const q)
2281 {
2282 ResourceRecord *rr = &ar->resrec;
2283
2284 // mDNSInterface_Any questions can be answered with LocalOnly/P2P records in this function. AuthRecord_Any
2285 // records are handled in ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion
2286 if (RRAny(ar))
2287 {
2288 LogMsg("LocalOnlyRecordAnswersQuestion: ERROR!! called with regular AuthRecordAny %##s", rr->name->c);
2289 return mDNSfalse;
2290 }
2291
2292 // Questions with mDNSInterface_LocalOnly InterfaceID should be answered with all resource records that are
2293 // *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
2294 // mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
2295 // the InterfaceID in the resource record.
2296
2297 if (rr->InterfaceID &&
2298 q->InterfaceID != mDNSInterface_LocalOnly &&
2299 ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) ||
2300 (!q->InterfaceID && !LocalOnlyOrP2PInterface(rr->InterfaceID)))) return(mDNSfalse);
2301
2302 // Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
2303 // may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
2304 // to mDNSInterface_Any, mDNSInterface_LocalOnly or a real InterfaceID (scoped).
2305 //
2306 // 1) Question: Any, LocalOnly Record: no scope. This question should be answered with this record.
2307 //
2308 // 2) Question: Any, LocalOnly Record: scoped. This question should be answered with the record because
2309 // traditionally applications never specify scope e.g., getaddrinfo, but need to be able
2310 // to get to /etc/hosts entries.
2311 //
2312 // 3) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: no scope. This is the inverse of (2).
2313 // If we register a LocalOnly record, we need to answer a LocalOnly question. If the /etc/hosts has a
2314 // non scoped entry, it may not make sense to answer a scoped question. But we can't tell these two
2315 // cases apart. As we currently answer LocalOnly question with LocalOnly record, we continue to do so.
2316 //
2317 // 4) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: scoped. LocalOnly questions should be
2318 // answered with any resource record where as if it has a valid InterfaceID, the scope should match.
2319 //
2320 // (1) and (2) is bypassed because we check for a non-NULL InterfaceID above. For (3), the InterfaceID is NULL
2321 // and hence bypassed above. For (4) we bypassed LocalOnly questions and checked the scope of the record
2322 // against the question.
2323 //
2324 // For P2P, InterfaceIDs of the question and the record should match.
2325
2326 // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
2327 // LocalOnly authoritative answers are exempt. LocalOnly authoritative answers are used for /etc/host entries.
2328 // We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com" which would then
2329 // cause other applications (e.g. Safari) to connect to the wrong address. The rpc to register records filters out records
2330 // with names that don't end in local and have mDNSInterface_LocalOnly set.
2331 //
2332 // Note: The check is bypassed for LocalOnly and for P2P it is not needed as only .local records are registered and for
2333 // a question to match its names, it also has to end in .local and that question can't be a unicast question (See
2334 // Question_uDNS macro and its usage). As P2P does not enforce .local only registrations we still make this check
2335 // and also makes it future proof.
2336
2337 if (ar->ARType != AuthRecordLocalOnly && rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
2338
2339 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
2340 // No local only record can answer DNSSEC question.
2341 if (dns_question_is_dnssec_requestor(q))
2342 {
2343 return mDNSfalse;
2344 }
2345 #endif
2346
2347 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
2348 RRTypeAnswersQuestionTypeFlags flags = kRRTypeAnswersQuestionTypeFlagsNone;
2349 const mDNSBool typeMatches = RRTypeAnswersQuestionType(rr, q->qtype, flags);
2350 if (!typeMatches)
2351 {
2352 return mDNSfalse;
2353 }
2354
2355 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
2356
2357 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
2358 }
2359
AnyTypeRecordAnswersQuestion(const AuthRecord * const ar,const DNSQuestion * const q)2360 mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
2361 {
2362 const ResourceRecord *const rr = &ar->resrec;
2363 // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
2364 // are handled in LocalOnlyRecordAnswersQuestion
2365 if (LocalOnlyOrP2PInterface(rr->InterfaceID))
2366 {
2367 LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
2368 return mDNSfalse;
2369 }
2370 if (rr->InterfaceID &&
2371 q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
2372 rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
2373
2374 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY)
2375 if (DNSQuestionUsesMDNSAlternativeService(q))
2376 {
2377 if (!RRMatchesQuestionService(rr, q))
2378 {
2379 return mDNSfalse;
2380 }
2381 }
2382 else
2383 #endif
2384 {
2385 const mDNSBool resolvedByMDNS = RRIsResolvedBymDNS(rr);
2386 // Resource record received via non-mDNS channel, the server or service should match.
2387 // Note that Auth Records are normally setup with NULL InterfaceID and
2388 // both the DNSServers are assumed to be NULL in that case
2389 if (!resolvedByMDNS)
2390 {
2391 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
2392 if (!RRMatchesQuestionService(rr, q)) return(mDNSfalse);
2393 #else
2394 const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
2395 const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
2396 if (idr != idq) return(mDNSfalse);
2397 #endif
2398 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
2399 if (!mDNSPlatformValidRecordForInterface(ar, q->InterfaceID)) return(mDNSfalse);
2400 #endif
2401 }
2402
2403 // mDNS records can only be used to answer mDNS questions.
2404 const mDNSBool isMDNSQuestion = mDNSOpaque16IsZero(q->TargetQID);
2405 if (resolvedByMDNS && !isMDNSQuestion)
2406 {
2407 return mDNSfalse;
2408 }
2409 }
2410
2411 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
2412
2413 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
2414 }
2415
2416 // This is called with both unicast resource record and multicast resource record. The question that
2417 // received the unicast response could be the regular unicast response from a DNS server or a response
2418 // to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the
2419 // question and the resource record because the resource record is not completely initialized in
2420 // mDNSCoreReceiveResponse when this function is called.
ResourceRecordAnswersUnicastResponse(const ResourceRecord * const rr,const DNSQuestion * const q)2421 mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q)
2422 {
2423 if (q->Suppressed)
2424 return mDNSfalse;
2425
2426 // For resource records created using multicast or DNS push, the InterfaceIDs have to match.
2427 if (rr->InterfaceID &&
2428 q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
2429
2430 // If record is resolved by mDNS, but question is non-mDNS, then should not use it to answer this question.
2431 const mDNSBool resolvedByMDNS = RRIsResolvedBymDNS(rr);
2432 const mDNSBool isMDNSQuestion = mDNSOpaque16IsZero(q->TargetQID);
2433 if (resolvedByMDNS && !isMDNSQuestion)
2434 {
2435 return mDNSfalse;
2436 }
2437
2438 // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
2439 RRTypeAnswersQuestionTypeFlags flags = kRRTypeAnswersQuestionTypeFlagsNone;
2440 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
2441 // Thus routine is only used for the records received from internet. Right now, we will not receive DNSSEC validated
2442 // record from wire (ODoH will probably give us validated records in the future?). Therefore, we only need to check
2443 // if the record answers primary DNSSEC requestor and can be used for validation.
2444 if (dns_question_is_primary_dnssec_requestor(q))
2445 {
2446 flags |= kRRTypeAnswersQuestionTypeFlagsRequiresDNSSECRRToValidate;
2447 }
2448 #endif
2449
2450 const mDNSBool typeMatches = RRTypeAnswersQuestionType(rr, q->qtype, flags);
2451 if (!typeMatches)
2452 {
2453 return(mDNSfalse);
2454 }
2455
2456 if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
2457
2458 return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
2459 }
2460
GetRDLength(const ResourceRecord * const rr,mDNSBool estimate)2461 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
2462 {
2463 const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data;
2464 const domainname *const name = estimate ? rr->name : mDNSNULL;
2465 if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength); // Used in update packets to mean "Delete An RRset" (RFC 2136)
2466 else switch (rr->rrtype)
2467 {
2468 case kDNSType_A: return(sizeof(rd->ipv4));
2469
2470 case kDNSType_NS:
2471 case kDNSType_CNAME:
2472 case kDNSType_PTR:
2473 case kDNSType_DNAME: return(CompressedDomainNameLength(&rd->name, name));
2474
2475 case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
2476 CompressedDomainNameLength(&rd->soa.rname, name) +
2477 5 * sizeof(mDNSOpaque32));
2478
2479 case kDNSType_NULL:
2480 case kDNSType_TSIG:
2481 case kDNSType_TXT:
2482 case kDNSType_X25:
2483 case kDNSType_ISDN:
2484 case kDNSType_LOC:
2485 case kDNSType_DHCID: return(rr->rdlength); // Not self-describing, so have to just trust rdlength
2486
2487 case kDNSType_HINFO: return (mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
2488
2489 case kDNSType_MX:
2490 case kDNSType_AFSDB:
2491 case kDNSType_RT:
2492 case kDNSType_KX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name));
2493
2494 case kDNSType_MINFO:
2495 case kDNSType_RP: return (mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) +
2496 CompressedDomainNameLength(&rd->rp.txt, name));
2497
2498 case kDNSType_PX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) +
2499 CompressedDomainNameLength(&rd->px.mapx400, name));
2500
2501 case kDNSType_AAAA: return(sizeof(rd->ipv6));
2502
2503 case kDNSType_SRV: return (mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
2504
2505 case kDNSType_OPT: return(rr->rdlength);
2506
2507 case kDNSType_NSEC:
2508 {
2509 const domainname *const next = (const domainname *)rd->data;
2510 const int dlen = DomainNameLength(next);
2511 if (MULTICAST_NSEC(rr))
2512 {
2513 return (mDNSu16)((estimate ? 2 : dlen) + rr->rdlength - dlen);
2514 }
2515 else
2516 {
2517 // Unicast NSEC does not do name compression. Therefore, we can return `rdlength` directly.
2518 // See [RFC 4034 4.1.1.](https://datatracker.ietf.org/doc/html/rfc4034#section-4.1.1).
2519 return rr->rdlength;
2520 }
2521 }
2522
2523 case kDNSType_TSR: return(sizeof(rd->tsr_value));
2524
2525 default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
2526 return(rr->rdlength);
2527 }
2528 }
2529
2530 // When a local client registers (or updates) a record, we use this routine to do some simple validation checks
2531 // to help reduce the risk of bogus malformed data on the network
ValidateRData(const mDNSu16 rrtype,const mDNSu16 rdlength,const RData * const rd)2532 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
2533 {
2534 mDNSu16 len;
2535
2536 switch(rrtype)
2537 {
2538 case kDNSType_A: return(rdlength == sizeof(mDNSv4Addr));
2539
2540 case kDNSType_NS: // Same as PTR
2541 case kDNSType_MD: // Same as PTR
2542 case kDNSType_MF: // Same as PTR
2543 case kDNSType_CNAME: // Same as PTR
2544 //case kDNSType_SOA not checked
2545 case kDNSType_MB: // Same as PTR
2546 case kDNSType_MG: // Same as PTR
2547 case kDNSType_MR: // Same as PTR
2548 //case kDNSType_NULL not checked (no specified format, so always valid)
2549 //case kDNSType_WKS not checked
2550 case kDNSType_PTR: len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength);
2551 return(len <= MAX_DOMAIN_NAME && rdlength == len);
2552
2553 case kDNSType_HINFO: // Same as TXT (roughly)
2554 case kDNSType_MINFO: // Same as TXT (roughly)
2555 case kDNSType_TXT: if (!rdlength) return(mDNSfalse); // TXT record has to be at least one byte (RFC 1035)
2556 {
2557 const mDNSu8 *ptr = rd->u.txt.c;
2558 const mDNSu8 *end = rd->u.txt.c + rdlength;
2559 while (ptr < end) ptr += 1 + ptr[0];
2560 return (ptr == end);
2561 }
2562
2563 case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr));
2564
2565 case kDNSType_MX: // Must be at least two-byte preference, plus domainname
2566 // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
2567 len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength);
2568 return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
2569
2570 case kDNSType_SRV: // Must be at least priority+weight+port, plus domainname
2571 // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
2572 len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength);
2573 return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
2574
2575 //case kDNSType_NSEC not checked
2576
2577 default: return(mDNStrue); // Allow all other types without checking
2578 }
2579 }
2580
ResourceRecordGetRDataBytesPointer(const ResourceRecord * const rr,mDNSu8 * const bytesBuffer,const mDNSu16 bufferSize,mDNSu16 * const outRDataLen,mStatus * const outError)2581 mDNSexport const mDNSu8 * ResourceRecordGetRDataBytesPointer(const ResourceRecord *const rr,
2582 mDNSu8 * const bytesBuffer, const mDNSu16 bufferSize, mDNSu16 *const outRDataLen, mStatus *const outError)
2583 {
2584 mStatus err;
2585 const mDNSu8 *rdataBytes = mDNSNULL;
2586 mDNSu16 rdataLen = 0;
2587 switch (rr->rrtype)
2588 {
2589 case kDNSType_SOA:
2590 case kDNSType_MX:
2591 case kDNSType_AFSDB:
2592 case kDNSType_RT:
2593 case kDNSType_RP:
2594 case kDNSType_SRV:
2595 case kDNSType_PX:
2596 case kDNSType_KX:
2597 case kDNSType_OPT:
2598 case kDNSType_NSEC:
2599 case kDNSType_TSR:
2600 {
2601 const mDNSu8 *const rdataBytesEnd = putRData(mDNSNULL, bytesBuffer, bytesBuffer + bufferSize, rr);
2602 mdns_require_action_quiet(rdataBytesEnd && (rdataBytesEnd > bytesBuffer), exit, err = mStatus_BadParamErr);
2603
2604 rdataBytes = bytesBuffer;
2605 rdataLen = (rdataBytesEnd - bytesBuffer);
2606 break;
2607 }
2608 default:
2609 rdataBytes = rr->rdata->u.data;
2610 rdataLen = rr->rdlength;
2611 break;
2612 }
2613 err = mStatus_NoError;
2614
2615 exit:
2616 mdns_assign(outRDataLen, rdataLen);
2617 mdns_assign(outError, err);
2618 return rdataBytes;
2619 }
2620
2621 // ***************************************************************************
2622 // MARK: - DNS Message Creation Functions
2623
InitializeDNSMessage(DNSMessageHeader * h,mDNSOpaque16 id,mDNSOpaque16 flags)2624 mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
2625 {
2626 h->id = id;
2627 h->flags = flags;
2628 h->numQuestions = 0;
2629 h->numAnswers = 0;
2630 h->numAuthorities = 0;
2631 h->numAdditionals = 0;
2632 }
2633
2634 #endif // !STANDALONE
2635
FindCompressionPointer(const mDNSu8 * const base,const mDNSu8 * const end,const mDNSu8 * const domname)2636 mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
2637 {
2638 const mDNSu8 *result = end - *domname - 1;
2639
2640 if (*domname == 0) return(mDNSNULL); // There's no point trying to match just the root label
2641
2642 // This loop examines each possible starting position in packet, starting end of the packet and working backwards
2643 while (result >= base)
2644 {
2645 // If the length byte and first character of the label match, then check further to see
2646 // if this location in the packet will yield a useful name compression pointer.
2647 if (result[0] == domname[0] && result[1] == domname[1])
2648 {
2649 const mDNSu8 *name = domname;
2650 const mDNSu8 *targ = result;
2651 while (targ + *name < end)
2652 {
2653 // First see if this label matches
2654 int i;
2655 const mDNSu8 *pointertarget;
2656 for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
2657 if (i <= *name) break; // If label did not match, bail out
2658 targ += 1 + *name; // Else, did match, so advance target pointer
2659 name += 1 + *name; // and proceed to check next label
2660 if (*name == 0 && *targ == 0) return(result); // If no more labels, we found a match!
2661 if (*name == 0) break; // If no more labels to match, we failed, so bail out
2662
2663 // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
2664 if (targ[0] < 0x40) continue; // If length value, continue to check next label
2665 if (targ[0] < 0xC0) break; // If 40-BF, not valid
2666 if (targ+1 >= end) break; // Second byte not present!
2667 pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
2668 if (targ < pointertarget) break; // Pointertarget must point *backwards* in the packet
2669 if (pointertarget[0] >= 0x40) break; // Pointertarget must point to a valid length byte
2670 targ = pointertarget;
2671 }
2672 }
2673 result--; // We failed to match at this search position, so back up the tentative result pointer and try again
2674 }
2675 return(mDNSNULL);
2676 }
2677
2678 // domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
2679 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
2680 // end points to the end of the message so far
2681 // ptr points to where we want to put the name
2682 // limit points to one byte past the end of the buffer that we must not overrun
2683 // domainname is the name to put
putDomainNameAsLabels(const DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,const domainname * const name)2684 mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
2685 mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
2686 {
2687 const mDNSu8 *const base = (const mDNSu8 *)msg;
2688 const mDNSu8 * np = name->c;
2689 const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
2690 const mDNSu8 * pointer = mDNSNULL;
2691 const mDNSu8 *const searchlimit = ptr;
2692
2693 if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); return(mDNSNULL); }
2694
2695 if (!*np) // If just writing one-byte root label, make sure we have space for that
2696 {
2697 if (ptr >= limit) return(mDNSNULL);
2698 }
2699 else // else, loop through writing labels and/or a compression offset
2700 {
2701 do {
2702 if (*np > MAX_DOMAIN_LABEL)
2703 { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
2704
2705 // This check correctly allows for the final trailing root label:
2706 // e.g.
2707 // Suppose our domain name is exactly 256 bytes long, including the final trailing root label.
2708 // Suppose np is now at name->c[249], and we're about to write our last non-null label ("local").
2709 // We know that max will be at name->c[256]
2710 // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
2711 // six bytes, then exit the loop, write the final terminating root label, and the domain
2712 // name we've written is exactly 256 bytes long, exactly at the correct legal limit.
2713 // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
2714 if (np + 1 + *np >= max)
2715 { LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); }
2716
2717 if (base) pointer = FindCompressionPointer(base, searchlimit, np);
2718 if (pointer) // Use a compression pointer if we can
2719 {
2720 const mDNSu16 offset = (mDNSu16)(pointer - base);
2721 if (ptr+2 > limit) return(mDNSNULL); // If we don't have two bytes of space left, give up
2722 *ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
2723 *ptr++ = (mDNSu8)( offset & 0xFF);
2724 return(ptr);
2725 }
2726 else // Else copy one label and try again
2727 {
2728 int i;
2729 mDNSu8 len = *np++;
2730 // If we don't at least have enough space for this label *plus* a terminating zero on the end, give up
2731 if (ptr + 1 + len >= limit) return(mDNSNULL);
2732 *ptr++ = len;
2733 for (i=0; i<len; i++) *ptr++ = *np++;
2734 }
2735 } while (*np); // While we've got characters remaining in the name, continue
2736 }
2737
2738 *ptr++ = 0; // Put the final root label
2739 return(ptr);
2740 }
2741
2742 #ifndef STANDALONE
2743
putVal16(mDNSu8 * ptr,mDNSu16 val)2744 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
2745 {
2746 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
2747 ptr[1] = (mDNSu8)((val ) & 0xFF);
2748 return ptr + sizeof(mDNSOpaque16);
2749 }
2750
putVal32(mDNSu8 * ptr,mDNSu32 val)2751 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
2752 {
2753 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
2754 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
2755 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
2756 ptr[3] = (mDNSu8)((val ) & 0xFF);
2757 return ptr + sizeof(mDNSu32);
2758 }
2759
2760 // Copy the RDATA information. The actual in memory storage for the data might be bigger than what the rdlength
2761 // says. Hence, the only way to copy out the data from a resource record is to use putRData.
2762 // 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)2763 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr)
2764 {
2765 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
2766 switch (rr->rrtype)
2767 {
2768 case kDNSType_A: if (rr->rdlength != 4)
2769 { debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); }
2770 if (ptr + 4 > limit) return(mDNSNULL);
2771 *ptr++ = rdb->ipv4.b[0];
2772 *ptr++ = rdb->ipv4.b[1];
2773 *ptr++ = rdb->ipv4.b[2];
2774 *ptr++ = rdb->ipv4.b[3];
2775 return(ptr);
2776
2777 case kDNSType_NS:
2778 case kDNSType_CNAME:
2779 case kDNSType_PTR:
2780 case kDNSType_DNAME: return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name));
2781
2782 case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname);
2783 if (!ptr) return(mDNSNULL);
2784 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.rname);
2785 if (!ptr || ptr + 20 > limit) return(mDNSNULL);
2786 ptr = putVal32(ptr, rdb->soa.serial);
2787 ptr = putVal32(ptr, rdb->soa.refresh);
2788 ptr = putVal32(ptr, rdb->soa.retry);
2789 ptr = putVal32(ptr, rdb->soa.expire);
2790 ptr = putVal32(ptr, rdb->soa.min);
2791 return(ptr);
2792
2793 case kDNSType_NULL:
2794 case kDNSType_HINFO:
2795 case kDNSType_TSIG:
2796 case kDNSType_TXT:
2797 case kDNSType_X25:
2798 case kDNSType_ISDN:
2799 case kDNSType_LOC:
2800 case kDNSType_DHCID: if (ptr + rr->rdlength > limit) return(mDNSNULL);
2801 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
2802 return(ptr + rr->rdlength);
2803
2804 case kDNSType_MX:
2805 case kDNSType_AFSDB:
2806 case kDNSType_RT:
2807 case kDNSType_KX: if (ptr + 3 > limit) return(mDNSNULL);
2808 ptr = putVal16(ptr, rdb->mx.preference);
2809 return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange));
2810
2811 case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox);
2812 if (!ptr) return(mDNSNULL);
2813 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.txt);
2814 return(ptr);
2815
2816 case kDNSType_PX: if (ptr + 5 > limit) return(mDNSNULL);
2817 ptr = putVal16(ptr, rdb->px.preference);
2818 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822);
2819 if (!ptr) return(mDNSNULL);
2820 ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400);
2821 return(ptr);
2822
2823 case kDNSType_AAAA: if (rr->rdlength != sizeof(rdb->ipv6))
2824 { debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); }
2825 if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL);
2826 mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6));
2827 return(ptr + sizeof(rdb->ipv6));
2828
2829 case kDNSType_SRV: if (ptr + 7 > limit) return(mDNSNULL);
2830 *ptr++ = (mDNSu8)(rdb->srv.priority >> 8);
2831 *ptr++ = (mDNSu8)(rdb->srv.priority & 0xFF);
2832 *ptr++ = (mDNSu8)(rdb->srv.weight >> 8);
2833 *ptr++ = (mDNSu8)(rdb->srv.weight & 0xFF);
2834 *ptr++ = rdb->srv.port.b[0];
2835 *ptr++ = rdb->srv.port.b[1];
2836 return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target));
2837
2838 case kDNSType_TSR: {
2839 // tsr timestamp on wire is relative time since received.
2840 mDNSs32 tsr_relative = mDNSPlatformContinuousTimeSeconds() - rdb->tsr_value;
2841 ptr = putVal32(ptr, tsr_relative);
2842 return(ptr);
2843 }
2844
2845 case kDNSType_OPT: {
2846 int len = 0;
2847 const rdataOPT *opt;
2848 const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength];
2849 for (opt = &rr->rdata->u.opt[0]; opt < end; opt++)
2850 len += DNSOpt_Data_Space(opt);
2851 if (ptr + len > limit)
2852 {
2853 LogMsg("ERROR: putOptRData - out of space");
2854 return mDNSNULL;
2855 }
2856 for (opt = &rr->rdata->u.opt[0]; opt < end; opt++)
2857 {
2858 const int space = DNSOpt_Data_Space(opt);
2859 ptr = putVal16(ptr, opt->opt);
2860 ptr = putVal16(ptr, (mDNSu16)space - 4);
2861 switch (opt->opt)
2862 {
2863 case kDNSOpt_LLQ:
2864 ptr = putVal16(ptr, opt->u.llq.vers);
2865 ptr = putVal16(ptr, opt->u.llq.llqOp);
2866 ptr = putVal16(ptr, opt->u.llq.err);
2867 mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8); // 8-byte id
2868 ptr += 8;
2869 ptr = putVal32(ptr, opt->u.llq.llqlease);
2870 break;
2871 case kDNSOpt_Lease:
2872 ptr = putVal32(ptr, opt->u.updatelease);
2873 break;
2874 case kDNSOpt_Owner:
2875 *ptr++ = opt->u.owner.vers;
2876 *ptr++ = opt->u.owner.seq;
2877 mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6); // 6-byte Host identifier
2878 ptr += 6;
2879 if (space >= DNSOpt_OwnerData_ID_Wake_Space)
2880 {
2881 mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6); // 6-byte interface MAC
2882 ptr += 6;
2883 if (space > DNSOpt_OwnerData_ID_Wake_Space)
2884 {
2885 mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space);
2886 ptr += space - DNSOpt_OwnerData_ID_Wake_Space;
2887 }
2888 }
2889 break;
2890 case kDNSOpt_Trace:
2891 *ptr++ = opt->u.tracer.platf;
2892 ptr = putVal32(ptr, opt->u.tracer.mDNSv);
2893 break;
2894 case kDNSOpt_TSR:
2895 {
2896 mDNSs32 tsr_relative = mDNSPlatformContinuousTimeSeconds() - opt->u.tsr.timeStamp;
2897 ptr = putVal32(ptr, tsr_relative);
2898 ptr = putVal32(ptr, opt->u.tsr.hostkeyHash);
2899 ptr = putVal16(ptr, opt->u.tsr.recIndex);
2900 }
2901 break;
2902 default:
2903 break;
2904 }
2905 }
2906 return ptr;
2907 }
2908
2909 case kDNSType_NSEC: {
2910 // For NSEC records, rdlength represents the exact number of bytes
2911 // of in memory storage.
2912 const mDNSu8 *nsec = (const mDNSu8 *)rdb->data;
2913 const domainname *name = (const domainname *)nsec;
2914 const int dlen = DomainNameLength(name);
2915 nsec += dlen;
2916 // This function is called when we are sending a NSEC record as part of mDNS,
2917 // or to copy the data to any other buffer needed which could be a mDNS or uDNS
2918 // NSEC record. The only time compression is used that when we are sending it
2919 // in mDNS (indicated by non-NULL "msg") and hence we handle mDNS case
2920 // separately.
2921 if (MULTICAST_NSEC(rr))
2922 {
2923 mDNSu8 *save = ptr;
2924 int i, j, wlen;
2925 wlen = *(nsec + 1);
2926 nsec += 2; // Skip the window number and len
2927
2928 // For our simplified use of NSEC synthetic records:
2929 //
2930 // nextname is always the record's own name,
2931 // the block number is always 0,
2932 // the count byte is a value in the range 1-32,
2933 // followed by the 1-32 data bytes
2934 //
2935 // Note: When we send the NSEC record in mDNS, the window size is set to 32.
2936 // We need to find out what the last non-NULL byte is. If we are copying out
2937 // from an RDATA, we have the right length. As we need to handle both the case,
2938 // we loop to find the right value instead of blindly using len to copy.
2939
2940 for (i=wlen; i>0; i--) if (nsec[i-1]) break;
2941
2942 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
2943 if (!ptr)
2944 {
2945 goto mdns_nsec_exit;
2946 }
2947 if (i) // Only put a block if at least one type exists for this name
2948 {
2949 if (ptr + 2 + i > limit)
2950 {
2951 ptr = mDNSNULL;
2952 goto mdns_nsec_exit;
2953 }
2954 *ptr++ = 0;
2955 *ptr++ = (mDNSu8)i;
2956 for (j=0; j<i; j++) *ptr++ = nsec[j];
2957 }
2958 mdns_nsec_exit:
2959 if (!ptr)
2960 {
2961 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEBUG,
2962 "The mDNS message does not have enough space for the NSEC record, will add it to the next message (This is not an error message) -- "
2963 "remaining space: %ld, NSEC name: " PRI_DM_NAME, limit - save, DM_NAME_PARAM(rr->name));
2964 }
2965 return ptr;
2966 }
2967 else
2968 {
2969 int win, wlen;
2970 int len = rr->rdlength - dlen;
2971
2972 // Sanity check whether the bitmap is good
2973 while (len)
2974 {
2975 if (len < 3)
2976 { LogMsg("putRData: invalid length %d", len); return mDNSNULL; }
2977
2978 win = *nsec++;
2979 wlen = *nsec++;
2980 len -= 2;
2981 if (len < wlen || wlen < 1 || wlen > 32)
2982 { LogMsg("putRData: invalid window length %d", wlen); return mDNSNULL; }
2983 if (win < 0 || win >= 256)
2984 { LogMsg("putRData: invalid window %d", win); return mDNSNULL; }
2985
2986 nsec += wlen;
2987 len -= wlen;
2988 }
2989 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);}
2990
2991 // No compression allowed for "nxt", just copy the data.
2992 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
2993 return(ptr + rr->rdlength);
2994 }
2995 }
2996
2997 default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
2998 if (ptr + rr->rdlength > limit) return(mDNSNULL);
2999 mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
3000 return(ptr + rr->rdlength);
3001 }
3002 }
3003
3004 #define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update)
3005
PutResourceRecordTTLWithLimit(DNSMessage * const msg,mDNSu8 * ptr,mDNSu16 * count,const ResourceRecord * rr,mDNSu32 ttl,const mDNSu8 * limit)3006 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count,
3007 const ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
3008 {
3009 mDNSu8 *endofrdata;
3010 mDNSu16 actualLength;
3011 // When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782)
3012 const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg;
3013
3014 if (rr->RecordType == kDNSRecordTypeUnregistered)
3015 {
3016 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
3017 "Attempt to put kDNSRecordTypeUnregistered " PRI_DM_NAME " (" PUB_S ")",
3018 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype));
3019 return(ptr);
3020 }
3021
3022 if (!ptr)
3023 {
3024 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
3025 "Pointer to message is NULL while filling resource record " PRI_DM_NAME " (" PUB_S ")",
3026 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype));
3027 return(mDNSNULL);
3028 }
3029
3030 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
3031 // If we're out-of-space, return mDNSNULL
3032 if (!ptr || ptr + 10 >= limit)
3033 {
3034 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
3035 "Can't put more names into current message, will possibly put it into the next message - "
3036 "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld",
3037 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr));
3038 return(mDNSNULL);
3039 }
3040 ptr[0] = (mDNSu8)(rr->rrtype >> 8);
3041 ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
3042 ptr[2] = (mDNSu8)(rr->rrclass >> 8);
3043 ptr[3] = (mDNSu8)(rr->rrclass & 0xFF);
3044 ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF);
3045 ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF);
3046 ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF);
3047 ptr[7] = (mDNSu8)( ttl & 0xFF);
3048 // ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes
3049
3050 endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr);
3051 if (!endofrdata)
3052 {
3053 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
3054 "Can't put more rdata into current message, will possibly put it into the next message - "
3055 "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld",
3056 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr - 10));
3057 return(mDNSNULL);
3058 }
3059
3060 // Go back and fill in the actual number of data bytes we wrote
3061 // (actualLength can be less than rdlength when domain name compression is used)
3062 actualLength = (mDNSu16)(endofrdata - ptr - 10);
3063 ptr[8] = (mDNSu8)(actualLength >> 8);
3064 ptr[9] = (mDNSu8)(actualLength & 0xFF);
3065
3066 if (count)
3067 {
3068 (*count)++;
3069 }
3070 else
3071 {
3072 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
3073 "No target count to update for " PRI_DM_NAME " (" PUB_S ")",
3074 DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype));
3075 }
3076 return(endofrdata);
3077 }
3078
putEmptyResourceRecord(DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,mDNSu16 * count,const AuthRecord * rr)3079 mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr)
3080 {
3081 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
3082 if (!ptr || ptr + 10 > limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
3083 ptr[0] = (mDNSu8)(rr->resrec.rrtype >> 8); // Put type
3084 ptr[1] = (mDNSu8)(rr->resrec.rrtype & 0xFF);
3085 ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8); // Put class
3086 ptr[3] = (mDNSu8)(rr->resrec.rrclass & 0xFF);
3087 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // TTL is zero
3088 ptr[8] = ptr[9] = 0; // RDATA length is zero
3089 (*count)++;
3090 return(ptr + 10);
3091 }
3092
putQuestion(DNSMessage * const msg,mDNSu8 * ptr,const mDNSu8 * const limit,const domainname * const name,mDNSu16 rrtype,mDNSu16 rrclass)3093 mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
3094 {
3095 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
3096 if (!ptr || ptr+4 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
3097 ptr[0] = (mDNSu8)(rrtype >> 8);
3098 ptr[1] = (mDNSu8)(rrtype & 0xFF);
3099 ptr[2] = (mDNSu8)(rrclass >> 8);
3100 ptr[3] = (mDNSu8)(rrclass & 0xFF);
3101 msg->h.numQuestions++;
3102 return(ptr+4);
3103 }
3104
3105 // for dynamic updates
putZone(DNSMessage * const msg,mDNSu8 * ptr,mDNSu8 * limit,const domainname * zone,mDNSOpaque16 zoneClass)3106 mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
3107 {
3108 ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
3109 if (!ptr || ptr + 4 > limit) return mDNSNULL; // If we're out-of-space, return NULL
3110 *ptr++ = (mDNSu8)(kDNSType_SOA >> 8);
3111 *ptr++ = (mDNSu8)(kDNSType_SOA & 0xFF);
3112 *ptr++ = zoneClass.b[0];
3113 *ptr++ = zoneClass.b[1];
3114 msg->h.mDNS_numZones++;
3115 return ptr;
3116 }
3117
3118 // for dynamic updates
putPrereqNameNotInUse(const domainname * const name,DNSMessage * const msg,mDNSu8 * const ptr,mDNSu8 * const end)3119 mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end)
3120 {
3121 AuthRecord prereq;
3122 mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
3123 AssignDomainName(&prereq.namestorage, name);
3124 prereq.resrec.rrtype = kDNSQType_ANY;
3125 prereq.resrec.rrclass = kDNSClass_NONE;
3126 return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
3127 }
3128
3129 // for dynamic updates
putDeletionRecord(DNSMessage * msg,mDNSu8 * ptr,ResourceRecord * rr)3130 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
3131 {
3132 // deletion: specify record w/ TTL 0, class NONE
3133 const mDNSu16 origclass = rr->rrclass;
3134 rr->rrclass = kDNSClass_NONE;
3135 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
3136 rr->rrclass = origclass;
3137 return ptr;
3138 }
3139
3140 // for dynamic updates
putDeletionRecordWithLimit(DNSMessage * msg,mDNSu8 * ptr,ResourceRecord * rr,mDNSu8 * limit)3141 mDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit)
3142 {
3143 // deletion: specify record w/ TTL 0, class NONE
3144 const mDNSu16 origclass = rr->rrclass;
3145 rr->rrclass = kDNSClass_NONE;
3146 ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit);
3147 rr->rrclass = origclass;
3148 return ptr;
3149 }
3150
putDeleteRRSetWithLimit(DNSMessage * msg,mDNSu8 * ptr,const domainname * name,mDNSu16 rrtype,mDNSu8 * limit)3151 mDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit)
3152 {
3153 mDNSu16 class = kDNSQClass_ANY;
3154
3155 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
3156 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
3157 ptr[0] = (mDNSu8)(rrtype >> 8);
3158 ptr[1] = (mDNSu8)(rrtype & 0xFF);
3159 ptr[2] = (mDNSu8)(class >> 8);
3160 ptr[3] = (mDNSu8)(class & 0xFF);
3161 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
3162 ptr[8] = ptr[9] = 0; // zero rdlength/rdata
3163
3164 msg->h.mDNS_numUpdates++;
3165 return ptr + 10;
3166 }
3167
3168 // for dynamic updates
putDeleteAllRRSets(DNSMessage * msg,mDNSu8 * ptr,const domainname * name)3169 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
3170 {
3171 const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
3172 mDNSu16 class = kDNSQClass_ANY;
3173 mDNSu16 rrtype = kDNSQType_ANY;
3174
3175 ptr = putDomainNameAsLabels(msg, ptr, limit, name);
3176 if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
3177 ptr[0] = (mDNSu8)(rrtype >> 8);
3178 ptr[1] = (mDNSu8)(rrtype & 0xFF);
3179 ptr[2] = (mDNSu8)(class >> 8);
3180 ptr[3] = (mDNSu8)(class & 0xFF);
3181 ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
3182 ptr[8] = ptr[9] = 0; // zero rdlength/rdata
3183
3184 msg->h.mDNS_numUpdates++;
3185 return ptr + 10;
3186 }
3187
3188 // for dynamic updates
putUpdateLease(DNSMessage * msg,mDNSu8 * ptr,mDNSu32 lease)3189 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease)
3190 {
3191 AuthRecord rr;
3192 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
3193 rr.resrec.rrclass = NormalMaxDNSMessageData;
3194 rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
3195 rr.resrec.rdestimate = sizeof(rdataOPT);
3196 rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease;
3197 rr.resrec.rdata->u.opt[0].u.updatelease = lease;
3198 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0);
3199 if (!ptr) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
3200 return ptr;
3201 }
3202
3203 // for dynamic updates
putUpdateLeaseWithLimit(DNSMessage * msg,mDNSu8 * ptr,mDNSu32 lease,mDNSu8 * limit)3204 mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit)
3205 {
3206 AuthRecord rr;
3207 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
3208 rr.resrec.rrclass = NormalMaxDNSMessageData;
3209 rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
3210 rr.resrec.rdestimate = sizeof(rdataOPT);
3211 rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease;
3212 rr.resrec.rdata->u.opt[0].u.updatelease = lease;
3213 ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.numAdditionals, &rr.resrec, 0, limit);
3214 if (!ptr) { LogMsg("ERROR: putUpdateLeaseWithLimit - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
3215 return ptr;
3216 }
3217
3218 // ***************************************************************************
3219 // MARK: - DNS Message Parsing Functions
3220
DomainNameHashValue(const domainname * const name)3221 mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name)
3222 {
3223 mDNSu32 sum = 0;
3224 const mDNSu8 *c;
3225
3226 for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
3227 {
3228 sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
3229 (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
3230 sum = (sum<<3) | (sum>>29);
3231 }
3232 if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
3233 return(sum);
3234 }
3235
SetNewRData(ResourceRecord * const rr,RData * NewRData,mDNSu16 rdlength)3236 mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
3237 {
3238 if (NewRData)
3239 {
3240 rr->rdata = NewRData;
3241 rr->rdlength = rdlength;
3242 }
3243 rr->rdlength = GetRDLength(rr, mDNSfalse);
3244 rr->rdestimate = GetRDLength(rr, mDNStrue);
3245 rr->rdatahash = RDataHashValue(rr);
3246 }
3247
skipDomainName(const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * const end)3248 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
3249 {
3250 mDNSu16 total = 0;
3251
3252 if (ptr < (const mDNSu8*)msg || ptr >= end)
3253 { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
3254
3255 while (1) // Read sequence of labels
3256 {
3257 const mDNSu8 len = *ptr++; // Read length of this label
3258 if (len == 0) return(ptr); // If length is zero, that means this name is complete
3259 switch (len & 0xC0)
3260 {
3261 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
3262 { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
3263 if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label
3264 { debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
3265 ptr += len;
3266 total += 1 + len;
3267 break;
3268
3269 case 0x40: debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
3270 case 0x80: debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
3271 case 0xC0: if (ptr + 1 > end) // Skip the two-byte name compression pointer.
3272 { debugf("skipDomainName: Malformed compression pointer (overruns packet end)"); return(mDNSNULL); }
3273 return(ptr + 1);
3274 default:
3275 break;
3276 }
3277 }
3278 }
3279
3280 // Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
getDomainName(const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * const end,domainname * const name)3281 mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
3282 domainname *const name)
3283 {
3284 const mDNSu8 *nextbyte = mDNSNULL; // Record where we got to before we started following pointers
3285 mDNSu8 *np = name->c; // Name pointer
3286 const mDNSu8 *const limit = np + MAX_DOMAIN_NAME; // Limit so we don't overrun buffer
3287
3288 if (ptr < (const mDNSu8*)msg || ptr >= end)
3289 { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
3290
3291 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels)
3292
3293 while (1) // Read sequence of labels
3294 {
3295 int i;
3296 mDNSu16 offset;
3297 const mDNSu8 len = *ptr++; // Read length of this label
3298 if (len == 0) break; // If length is zero, that means this name is complete
3299 switch (len & 0xC0)
3300 {
3301
3302 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
3303 { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
3304 if (np + 1 + len >= limit) // Remember: expect at least one more byte for the root label
3305 { debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
3306 *np++ = len;
3307 for (i=0; i<len; i++) *np++ = *ptr++;
3308 *np = 0; // Tentatively place the root label here (may be overwritten if we have more labels)
3309 break;
3310
3311 case 0x40: debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
3312 return(mDNSNULL);
3313
3314 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
3315
3316 case 0xC0: if (ptr >= end)
3317 { debugf("getDomainName: Malformed compression label (overruns packet end)"); return(mDNSNULL); }
3318 offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
3319 if (!nextbyte) nextbyte = ptr; // Record where we got to before we started following pointers
3320 ptr = (const mDNSu8 *)msg + offset;
3321 if (ptr < (const mDNSu8*)msg || ptr >= end)
3322 { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
3323 if (*ptr & 0xC0)
3324 { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
3325 break;
3326
3327 default:
3328 break;
3329 }
3330 }
3331
3332 if (nextbyte) return(nextbyte);
3333 else return(ptr);
3334 }
3335
skipResourceRecord(const DNSMessage * msg,const mDNSu8 * ptr,const mDNSu8 * end)3336 mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
3337 {
3338 mDNSu16 pktrdlength;
3339
3340 ptr = skipDomainName(msg, ptr, end);
3341 if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
3342
3343 if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
3344 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
3345 ptr += 10;
3346 if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
3347
3348 return(ptr + pktrdlength);
3349 }
3350
3351 // Sanity check whether the NSEC/NSEC3 bitmap is good
SanityCheckBitMap(const mDNSu8 * bmap,const mDNSu8 * end,int len)3352 mDNSlocal const mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int len)
3353 {
3354 int win, wlen;
3355
3356 while (bmap < end)
3357 {
3358 if (len < 3)
3359 {
3360 LogInfo("SanityCheckBitMap: invalid length %d", len);
3361 return mDNSNULL;
3362 }
3363
3364 win = *bmap++;
3365 wlen = *bmap++;
3366 len -= 2;
3367 if (len < wlen || wlen < 1 || wlen > 32)
3368 {
3369 LogInfo("SanityCheckBitMap: invalid window length %d", wlen);
3370 return mDNSNULL;
3371 }
3372 if (win < 0 || win >= 256)
3373 {
3374 LogInfo("SanityCheckBitMap: invalid window %d", win);
3375 return mDNSNULL;
3376 }
3377
3378 bmap += wlen;
3379 len -= wlen;
3380 }
3381 return (const mDNSu8 *)bmap;
3382 }
3383
AssignDomainNameWithLimit(domainname * const dst,const domainname * src,const mDNSu8 * const end)3384 mDNSlocal mDNSBool AssignDomainNameWithLimit(domainname *const dst, const domainname *src, const mDNSu8 *const end)
3385 {
3386 const mDNSu32 len = DomainNameLengthLimit(src, end);
3387 if ((len >= 1) && (len <= MAX_DOMAIN_NAME))
3388 {
3389 mDNSPlatformMemCopy(dst->c, src->c, len);
3390 return mDNStrue;
3391 }
3392 else
3393 {
3394 dst->c[0] = 0;
3395 return mDNSfalse;
3396 }
3397 }
3398
3399 // This function is called with "msg" when we receive a DNS message and needs to parse a single resource record
3400 // pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded
3401 // (domainnames are expanded to 256 bytes) when stored in memory.
3402 //
3403 // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
3404 // The caller can do this only if the names in the resource records are not compressed and validity of the
3405 // resource record has already been done before.
SetRData(const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * end,ResourceRecord * const rr,const mDNSu16 rdlength)3406 mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, ResourceRecord *const rr,
3407 const mDNSu16 rdlength)
3408 {
3409 RDataBody2 *const rdb = (RDataBody2 *)&rr->rdata->u;
3410
3411 switch (rr->rrtype)
3412 {
3413 case kDNSType_A:
3414 if (rdlength != sizeof(mDNSv4Addr))
3415 goto fail;
3416 rdb->ipv4.b[0] = ptr[0];
3417 rdb->ipv4.b[1] = ptr[1];
3418 rdb->ipv4.b[2] = ptr[2];
3419 rdb->ipv4.b[3] = ptr[3];
3420 break;
3421
3422 case kDNSType_NS:
3423 case kDNSType_MD:
3424 case kDNSType_MF:
3425 case kDNSType_CNAME:
3426 case kDNSType_MB:
3427 case kDNSType_MG:
3428 case kDNSType_MR:
3429 case kDNSType_PTR:
3430 case kDNSType_NSAP_PTR:
3431 case kDNSType_DNAME:
3432 if (msg)
3433 {
3434 ptr = getDomainName(msg, ptr, end, &rdb->name);
3435 }
3436 else
3437 {
3438 if (!AssignDomainNameWithLimit(&rdb->name, (const domainname *)ptr, end))
3439 {
3440 goto fail;
3441 }
3442 ptr += DomainNameLength(&rdb->name);
3443 }
3444 if (ptr != end)
3445 {
3446 debugf("SetRData: Malformed CNAME/PTR RDATA name");
3447 goto fail;
3448 }
3449 break;
3450
3451 case kDNSType_SOA:
3452 if (msg)
3453 {
3454 ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
3455 }
3456 else
3457 {
3458 if (!AssignDomainNameWithLimit(&rdb->soa.mname, (const domainname *)ptr, end))
3459 {
3460 goto fail;
3461 }
3462 ptr += DomainNameLength(&rdb->soa.mname);
3463 }
3464 if (!ptr)
3465 {
3466 debugf("SetRData: Malformed SOA RDATA mname");
3467 goto fail;
3468 }
3469 if (msg)
3470 {
3471 ptr = getDomainName(msg, ptr, end, &rdb->soa.rname);
3472 }
3473 else
3474 {
3475 if (!AssignDomainNameWithLimit(&rdb->soa.rname, (const domainname *)ptr, end))
3476 {
3477 goto fail;
3478 }
3479 ptr += DomainNameLength(&rdb->soa.rname);
3480 }
3481 if (!ptr)
3482 {
3483 debugf("SetRData: Malformed SOA RDATA rname");
3484 goto fail;
3485 }
3486 if (ptr + 0x14 != end)
3487 {
3488 debugf("SetRData: Malformed SOA RDATA");
3489 goto fail;
3490 }
3491 rdb->soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
3492 rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
3493 rdb->soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
3494 rdb->soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
3495 rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
3496 break;
3497
3498 case kDNSType_HINFO:
3499 // See https://tools.ietf.org/html/rfc1035#section-3.3.2 for HINFO RDATA format.
3500 {
3501 // HINFO should contain RDATA.
3502 if (end <= ptr || rdlength != (mDNSu32)(end - ptr))
3503 {
3504 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
3505 "SetRData: Malformed HINFO RDATA - invalid RDATA length: %u", rdlength);
3506 goto fail;
3507 }
3508
3509 const mDNSu8 *currentPtr = ptr;
3510 // CPU character string length should be less than the RDATA length.
3511 mDNSu32 cpuCharacterStrLength = currentPtr[0];
3512 if (1 + cpuCharacterStrLength >= (mDNSu32)(end - currentPtr))
3513 {
3514 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
3515 "SetRData: Malformed HINFO RDATA - CPU character string goes out of boundary");
3516 goto fail;
3517 }
3518 currentPtr += 1 + cpuCharacterStrLength;
3519
3520 // OS character string should end at the RDATA ending.
3521 mDNSu32 osCharacterStrLength = currentPtr[0];
3522 if (1 + osCharacterStrLength != (mDNSu32)(end - currentPtr))
3523 {
3524 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
3525 "SetRData: Malformed HINFO RDATA - OS character string does not end at the RDATA ending");
3526 goto fail;
3527 }
3528
3529 // Copy the validated RDATA.
3530 rr->rdlength = rdlength;
3531 mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3532 break;
3533 }
3534 case kDNSType_NULL:
3535 case kDNSType_TXT:
3536 case kDNSType_X25:
3537 case kDNSType_ISDN:
3538 case kDNSType_LOC:
3539 case kDNSType_DHCID:
3540 case kDNSType_SVCB:
3541 case kDNSType_HTTPS:
3542 rr->rdlength = rdlength;
3543 mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3544 break;
3545
3546 case kDNSType_MX:
3547 case kDNSType_AFSDB:
3548 case kDNSType_RT:
3549 case kDNSType_KX:
3550 // Preference + domainname
3551 if (rdlength < 3)
3552 goto fail;
3553 rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
3554 ptr += 2;
3555 if (msg)
3556 {
3557 ptr = getDomainName(msg, ptr, end, &rdb->mx.exchange);
3558 }
3559 else
3560 {
3561 if (!AssignDomainNameWithLimit(&rdb->mx.exchange, (const domainname *)ptr, end))
3562 {
3563 goto fail;
3564 }
3565 ptr += DomainNameLength(&rdb->mx.exchange);
3566 }
3567 if (ptr != end)
3568 {
3569 debugf("SetRData: Malformed MX name");
3570 goto fail;
3571 }
3572 break;
3573
3574 case kDNSType_MINFO:
3575 case kDNSType_RP:
3576 // Domainname + domainname
3577 if (msg)
3578 {
3579 ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox);
3580 }
3581 else
3582 {
3583 if (!AssignDomainNameWithLimit(&rdb->rp.mbox, (const domainname *)ptr, end))
3584 {
3585 goto fail;
3586 }
3587 ptr += DomainNameLength(&rdb->rp.mbox);
3588 }
3589 if (!ptr)
3590 {
3591 debugf("SetRData: Malformed RP mbox");
3592 goto fail;
3593 }
3594 if (msg)
3595 {
3596 ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
3597 }
3598 else
3599 {
3600 if (!AssignDomainNameWithLimit(&rdb->rp.txt, (const domainname *)ptr, end))
3601 {
3602 goto fail;
3603 }
3604 ptr += DomainNameLength(&rdb->rp.txt);
3605 }
3606 if (ptr != end)
3607 {
3608 debugf("SetRData: Malformed RP txt");
3609 goto fail;
3610 }
3611 break;
3612
3613 case kDNSType_PX:
3614 // Preference + domainname + domainname
3615 if (rdlength < 4)
3616 goto fail;
3617 rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
3618 ptr += 2;
3619 if (msg)
3620 {
3621 ptr = getDomainName(msg, ptr, end, &rdb->px.map822);
3622 }
3623 else
3624 {
3625 if (!AssignDomainNameWithLimit(&rdb->px.map822, (const domainname *)ptr, end))
3626 {
3627 goto fail;
3628 }
3629 ptr += DomainNameLength(&rdb->px.map822);
3630 }
3631 if (!ptr)
3632 {
3633 debugf("SetRData: Malformed PX map822");
3634 goto fail;
3635 }
3636 if (msg)
3637 {
3638 ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
3639 }
3640 else
3641 {
3642 if (!AssignDomainNameWithLimit(&rdb->px.mapx400, (const domainname *)ptr, end))
3643 {
3644 goto fail;
3645 }
3646 ptr += DomainNameLength(&rdb->px.mapx400);
3647 }
3648 if (ptr != end)
3649 {
3650 debugf("SetRData: Malformed PX mapx400");
3651 goto fail;
3652 }
3653 break;
3654
3655 case kDNSType_AAAA:
3656 if (rdlength != sizeof(mDNSv6Addr))
3657 goto fail;
3658 mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
3659 break;
3660
3661 case kDNSType_SRV:
3662 // Priority + weight + port + domainname
3663 if (rdlength < 7)
3664 goto fail;
3665 rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
3666 rdb->srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
3667 rdb->srv.port.b[0] = ptr[4];
3668 rdb->srv.port.b[1] = ptr[5];
3669 ptr += 6;
3670 if (msg)
3671 {
3672 ptr = getDomainName(msg, ptr, end, &rdb->srv.target);
3673 }
3674 else
3675 {
3676 if (!AssignDomainNameWithLimit(&rdb->srv.target, (const domainname *)ptr, end))
3677 {
3678 goto fail;
3679 }
3680 ptr += DomainNameLength(&rdb->srv.target);
3681 }
3682 if (ptr != end)
3683 {
3684 debugf("SetRData: Malformed SRV RDATA name");
3685 goto fail;
3686 }
3687 break;
3688
3689 case kDNSType_NAPTR:
3690 {
3691 int savelen, len;
3692 domainname name;
3693 mDNSu32 namelen;
3694 const mDNSu8 *orig = ptr;
3695
3696 // Make sure the data is parseable and within the limits.
3697 //
3698 // Fixed length: Order, preference (4 bytes)
3699 // Variable length: flags, service, regexp, domainname
3700
3701 if (rdlength < 8)
3702 goto fail;
3703 // Order, preference.
3704 ptr += 4;
3705 // Parse flags, Service and Regexp
3706 // length in the first byte does not include the length byte itself
3707 len = *ptr + 1;
3708 ptr += len;
3709 if (ptr >= end)
3710 {
3711 LogInfo("SetRData: Malformed NAPTR flags");
3712 goto fail;
3713 }
3714
3715 // Service
3716 len = *ptr + 1;
3717 ptr += len;
3718 if (ptr >= end)
3719 {
3720 LogInfo("SetRData: Malformed NAPTR service");
3721 goto fail;
3722 }
3723
3724 // Regexp
3725 len = *ptr + 1;
3726 ptr += len;
3727 if (ptr >= end)
3728 {
3729 LogInfo("SetRData: Malformed NAPTR regexp");
3730 goto fail;
3731 }
3732
3733 savelen = (int)(ptr - orig);
3734
3735 // RFC 2915 states that name compression is not allowed for this field. But RFC 3597
3736 // states that for NAPTR we should decompress. We make sure that we store the full
3737 // name rather than the compressed name
3738 if (msg)
3739 {
3740 ptr = getDomainName(msg, ptr, end, &name);
3741 namelen = DomainNameLength(&name);
3742 }
3743 else
3744 {
3745 if (!AssignDomainNameWithLimit(&name, (const domainname *)ptr, end))
3746 {
3747 goto fail;
3748 }
3749 namelen = DomainNameLength(&name);
3750 ptr += namelen;
3751 }
3752 if (ptr != end)
3753 {
3754 LogInfo("SetRData: Malformed NAPTR RDATA name");
3755 goto fail;
3756 }
3757
3758 rr->rdlength = savelen + namelen;
3759 // The uncompressed size should not exceed the limits
3760 if (rr->rdlength > MaximumRDSize)
3761 {
3762 LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->rdlength %d, "
3763 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c);
3764 goto fail;
3765 }
3766 mDNSPlatformMemCopy(rdb->data, orig, savelen);
3767 mDNSPlatformMemCopy(rdb->data + savelen, name.c, namelen);
3768 break;
3769 }
3770 case kDNSType_OPT: {
3771 const mDNSu8 * const dataend = &rr->rdata->u.data[rr->rdata->MaxRDLength];
3772 rdataOPT *opt = rr->rdata->u.opt;
3773 rr->rdlength = 0;
3774 while ((ptr < end) && ((dataend - ((const mDNSu8 *)opt)) >= ((mDNSs32)sizeof(*opt))))
3775 {
3776 const rdataOPT *const currentopt = opt;
3777 if (ptr + 4 > end) { LogInfo("SetRData: OPT RDATA ptr + 4 > end"); goto fail; }
3778 opt->opt = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
3779 opt->optlen = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
3780 ptr += 4;
3781 if (ptr + opt->optlen > end) { LogInfo("SetRData: ptr + opt->optlen > end"); goto fail; }
3782 switch (opt->opt)
3783 {
3784 case kDNSOpt_LLQ:
3785 if (opt->optlen == DNSOpt_LLQData_Space - 4)
3786 {
3787 opt->u.llq.vers = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
3788 opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
3789 opt->u.llq.err = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
3790 mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8);
3791 opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]);
3792 if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
3793 opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
3794 opt++;
3795 }
3796 break;
3797 case kDNSOpt_Lease:
3798 if (opt->optlen == DNSOpt_LeaseData_Space - 4)
3799 {
3800 opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
3801 if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
3802 opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
3803 opt++;
3804 }
3805 break;
3806 case kDNSOpt_Owner:
3807 if (ValidOwnerLength(opt->optlen))
3808 {
3809 opt->u.owner.vers = ptr[0];
3810 opt->u.owner.seq = ptr[1];
3811 mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6); // 6-byte MAC address
3812 mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6); // 6-byte MAC address
3813 opt->u.owner.password = zeroEthAddr;
3814 if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
3815 {
3816 mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6); // 6-byte MAC address
3817 // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above
3818 // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4
3819 if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
3820 mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
3821 }
3822 opt++;
3823 }
3824 break;
3825 case kDNSOpt_Trace:
3826 if (opt->optlen == DNSOpt_TraceData_Space - 4)
3827 {
3828 opt->u.tracer.platf = ptr[0];
3829 opt->u.tracer.mDNSv = (mDNSu32) ((mDNSu32)ptr[1] << 24 | (mDNSu32)ptr[2] << 16 | (mDNSu32)ptr[3] << 8 | ptr[4]);
3830 opt++;
3831 }
3832 else
3833 {
3834 opt->u.tracer.platf = 0xFF;
3835 opt->u.tracer.mDNSv = 0xFFFFFFFF;
3836 opt++;
3837 }
3838 break;
3839 case kDNSOpt_TSR:
3840 if (opt->optlen == DNSOpt_TSRData_Space - 4)
3841 {
3842 opt->u.tsr.timeStamp = (mDNSs32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
3843 opt->u.tsr.hostkeyHash = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
3844 opt->u.tsr.recIndex = (mDNSu16) ((mDNSu16)ptr[8] << 8 | ptr[9]);
3845 opt++;
3846 }
3847 break;
3848 default:
3849 break;
3850 }
3851 ptr += currentopt->optlen;
3852 }
3853 rr->rdlength = (mDNSu16)((mDNSu8*)opt - rr->rdata->u.data);
3854 if (ptr != end) { LogInfo("SetRData: Malformed OptRdata"); goto fail; }
3855 break;
3856 }
3857
3858 case kDNSType_NSEC: {
3859 domainname name;
3860 int len = rdlength;
3861 int bmaplen, dlen;
3862 const mDNSu8 *orig = ptr;
3863 const mDNSu8 *bmap;
3864
3865 if (msg)
3866 {
3867 ptr = getDomainName(msg, ptr, end, &name);
3868 }
3869 else
3870 {
3871 if (!AssignDomainNameWithLimit(&name, (const domainname *)ptr, end))
3872 {
3873 goto fail;
3874 }
3875 ptr += DomainNameLength(&name);
3876 }
3877 if (!ptr)
3878 {
3879 LogInfo("SetRData: Malformed NSEC nextname");
3880 goto fail;
3881 }
3882
3883 dlen = DomainNameLength(&name);
3884
3885 // Multicast NSECs use name compression for this field unlike the unicast case which
3886 // does not use compression. And multicast case always succeeds in compression. So,
3887 // the rdlength includes only the compressed space in that case. So, can't
3888 // use the DomainNameLength of name to reduce the length here.
3889 len -= (ptr - orig);
3890 bmaplen = len; // Save the length of the bitmap
3891 bmap = ptr;
3892 ptr = SanityCheckBitMap(bmap, end, len);
3893 if (!ptr)
3894 goto fail;
3895 if (ptr != end)
3896 {
3897 LogInfo("SetRData: Malformed NSEC length not right");
3898 goto fail;
3899 }
3900
3901 // Initialize the right length here. When we call SetNewRData below which in turn calls
3902 // GetRDLength and for NSEC case, it assumes that rdlength is intitialized
3903 rr->rdlength = DomainNameLength(&name) + bmaplen;
3904
3905 // Do we have space after the name expansion ?
3906 if (rr->rdlength > MaximumRDSize)
3907 {
3908 LogInfo("SetRData: Malformed NSEC rdlength %d, rr->rdlength %d, "
3909 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c);
3910 goto fail;
3911 }
3912 AssignDomainName(&rdb->name, &name);
3913 mDNSPlatformMemCopy(rdb->data + dlen, bmap, bmaplen);
3914 break;
3915 }
3916 case kDNSType_TKEY:
3917 case kDNSType_TSIG:
3918 {
3919 domainname name;
3920 int dlen, rlen;
3921
3922 // The name should not be compressed. But we take the conservative approach
3923 // and uncompress the name before we store it.
3924 if (msg)
3925 {
3926 ptr = getDomainName(msg, ptr, end, &name);
3927 }
3928 else
3929 {
3930 if (!AssignDomainNameWithLimit(&name, (const domainname *)ptr, end))
3931 {
3932 goto fail;
3933 }
3934 ptr += DomainNameLength(&name);
3935 }
3936 if (!ptr || ptr >= end)
3937 {
3938 LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->rrtype);
3939 goto fail;
3940 }
3941 dlen = DomainNameLength(&name);
3942 rlen = (int)(end - ptr);
3943 rr->rdlength = dlen + rlen;
3944 if (rr->rdlength > MaximumRDSize)
3945 {
3946 LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->rdlength %d, "
3947 "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c);
3948 goto fail;
3949 }
3950 AssignDomainName(&rdb->name, &name);
3951 mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen);
3952 break;
3953 }
3954 case kDNSType_TSR:
3955 {
3956 rdb->tsr_value = (mDNSs32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
3957 break;
3958 }
3959 default:
3960 debugf("SetRData: Warning! Reading resource type %d (%s) as opaque data",
3961 rr->rrtype, DNSTypeName(rr->rrtype));
3962 // Note: Just because we don't understand the record type, that doesn't
3963 // mean we fail. The DNS protocol specifies rdlength, so we can
3964 // safely skip over unknown records and ignore them.
3965 // We also grab a binary copy of the rdata anyway, since the caller
3966 // might know how to interpret it even if we don't.
3967 rr->rdlength = rdlength;
3968 mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
3969 break;
3970 }
3971 return mDNStrue;
3972 fail:
3973 return mDNSfalse;
3974 }
3975
GetLargeResourceRecord(mDNS * const m,const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * end,const mDNSInterfaceID InterfaceID,mDNSu8 RecordType,LargeCacheRecord * const largecr)3976 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
3977 const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr)
3978 {
3979 CacheRecord *const rr = &largecr->r;
3980 mDNSu16 pktrdlength;
3981 mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
3982
3983 if (largecr == &m->rec && m->rec.r.resrec.RecordType)
3984 LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
3985
3986 rr->next = mDNSNULL;
3987 rr->resrec.name = &largecr->namestorage;
3988
3989 rr->NextInKAList = mDNSNULL;
3990 rr->TimeRcvd = m ? m->timenow : 0;
3991 rr->DelayDelivery = 0;
3992 rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
3993 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
3994 rr->LastCachedAnswerTime = 0;
3995 #endif
3996 rr->CRActiveQuestion = mDNSNULL;
3997 rr->UnansweredQueries = 0;
3998 rr->LastUnansweredTime= 0;
3999 rr->NextInCFList = mDNSNULL;
4000
4001 rr->resrec.InterfaceID = InterfaceID;
4002 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4003 mdns_forget(&rr->resrec.metadata);
4004 #else
4005 rr->resrec.rDNSServer = mDNSNULL;
4006 #endif
4007
4008 ptr = getDomainName(msg, ptr, end, &largecr->namestorage); // Will bail out correctly if ptr is NULL
4009 if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
4010 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
4011
4012 if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
4013
4014 rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
4015 rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask);
4016 rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
4017 if (rr->resrec.rroriginalttl > maxttl && (mDNSs32)rr->resrec.rroriginalttl != -1)
4018 rr->resrec.rroriginalttl = maxttl;
4019 // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
4020 // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
4021 pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
4022
4023 // If mDNS record has cache-flush bit set, we mark it unique
4024 // For uDNS records, all are implicitly deemed unique (a single DNS server is always authoritative for the entire RRSet)
4025 if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || !InterfaceID)
4026 RecordType |= kDNSRecordTypePacketUniqueMask;
4027 ptr += 10;
4028 if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
4029 end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record
4030
4031 rr->resrec.rdata = (RData*)&rr->smallrdatastorage;
4032 rr->resrec.rdata->MaxRDLength = MaximumRDSize;
4033
4034 if (pktrdlength > MaximumRDSize)
4035 {
4036 LogInfo("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
4037 DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
4038 goto fail;
4039 }
4040
4041 if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
4042
4043 // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding
4044 // cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind
4045 // bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data.
4046 // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that
4047 // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
4048 if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136)
4049 rr->resrec.rdlength = 0;
4050 else if (!SetRData(msg, ptr, end, &rr->resrec, pktrdlength))
4051 {
4052 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4053 "GetLargeResourceRecord: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
4054 DM_NAME_PARAM(rr->resrec.name), DNSTypeName(rr->resrec.rrtype));
4055 goto fail;
4056 }
4057
4058 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us
4059
4060 // Success! Now fill in RecordType to show this record contains valid data
4061 rr->resrec.RecordType = RecordType;
4062 return(end);
4063
4064 fail:
4065 // If we were unable to parse the rdata in this record, we indicate that by
4066 // returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero
4067 rr->resrec.RecordType = kDNSRecordTypePacketNegative;
4068 rr->resrec.rdlength = 0;
4069 rr->resrec.rdestimate = 0;
4070 rr->resrec.rdatahash = 0;
4071 return(end);
4072 }
4073
skipQuestion(const DNSMessage * msg,const mDNSu8 * ptr,const mDNSu8 * end)4074 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
4075 {
4076 ptr = skipDomainName(msg, ptr, end);
4077 if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
4078 if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
4079 return(ptr+4);
4080 }
4081
getQuestion(const DNSMessage * msg,const mDNSu8 * ptr,const mDNSu8 * end,const mDNSInterfaceID InterfaceID,DNSQuestion * question)4082 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
4083 DNSQuestion *question)
4084 {
4085 mDNSPlatformMemZero(question, sizeof(*question));
4086 question->InterfaceID = InterfaceID;
4087 if (!InterfaceID) question->TargetQID = onesID; // In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast
4088 ptr = getDomainName(msg, ptr, end, &question->qname);
4089 if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
4090 if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
4091
4092 question->qnamehash = DomainNameHashValue(&question->qname);
4093 question->qtype = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); // Get type
4094 question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); // and class
4095 return(ptr+4);
4096 }
4097
LocateAnswers(const DNSMessage * const msg,const mDNSu8 * const end)4098 mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
4099 {
4100 int i;
4101 const mDNSu8 *ptr = msg->data;
4102 for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
4103 return(ptr);
4104 }
4105
LocateAuthorities(const DNSMessage * const msg,const mDNSu8 * const end)4106 mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
4107 {
4108 int i;
4109 const mDNSu8 *ptr = LocateAnswers(msg, end);
4110 for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
4111 return(ptr);
4112 }
4113
LocateAdditionals(const DNSMessage * const msg,const mDNSu8 * const end)4114 mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end)
4115 {
4116 int i;
4117 const mDNSu8 *ptr = LocateAuthorities(msg, end);
4118 for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end);
4119 return (ptr);
4120 }
4121
LocateOptRR(const DNSMessage * const msg,const mDNSu8 * const end,int minsize)4122 mDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize)
4123 {
4124 int i;
4125 const mDNSu8 *ptr = LocateAdditionals(msg, end);
4126
4127 // Locate the OPT record.
4128 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
4129 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
4130 // but not necessarily the *last* entry in the Additional Section.
4131 for (i = 0; ptr && i < msg->h.numAdditionals; i++)
4132 {
4133 if (ptr + DNSOpt_Header_Space + minsize <= end && // Make sure we have 11+minsize bytes of data
4134 ptr[0] == 0 && // Name must be root label
4135 ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT
4136 ptr[2] == (kDNSType_OPT & 0xFF) &&
4137 ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)minsize)
4138 return(ptr);
4139 else
4140 ptr = skipResourceRecord(msg, ptr, end);
4141 }
4142 return(mDNSNULL);
4143 }
4144
4145 // On success, GetLLQOptData returns pointer to storage within shared "m->rec";
4146 // it is caller's responsibilty to clear m->rec.r.resrec.RecordType after use
4147 // Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together
4148 // The code that currently calls this assumes there's only one, instead of iterating through the set
GetLLQOptData(mDNS * const m,const DNSMessage * const msg,const mDNSu8 * const end)4149 mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end)
4150 {
4151 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space);
4152 if (ptr)
4153 {
4154 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
4155 if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]);
4156 }
4157 return(mDNSNULL);
4158 }
4159
4160 // Get the lease life of records in a dynamic update
GetPktLease(mDNS * const m,const DNSMessage * const msg,const mDNSu8 * const end,mDNSu32 * const lease)4161 mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease)
4162 {
4163 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
4164 if (ptr)
4165 {
4166 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
4167 if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
4168 {
4169 const rdataOPT *o;
4170 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
4171 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
4172 if (o->opt == kDNSOpt_Lease)
4173 {
4174 *lease = o->u.updatelease;
4175 mDNSCoreResetRecord(m);
4176 return mDNStrue;
4177 }
4178 }
4179 mDNSCoreResetRecord(m);
4180 }
4181 return mDNSfalse;
4182 }
4183
4184 #define DNS_OP_Name(X) ( \
4185 (X) == kDNSFlag0_OP_StdQuery ? "" : \
4186 (X) == kDNSFlag0_OP_Iquery ? "Iquery " : \
4187 (X) == kDNSFlag0_OP_Status ? "Status " : \
4188 (X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \
4189 (X) == kDNSFlag0_OP_Notify ? "Notify " : \
4190 (X) == kDNSFlag0_OP_Update ? "Update " : \
4191 (X) == kDNSFlag0_OP_DSO ? "DSO " : "?? " )
4192
4193 #define DNS_RC_Name(X) ( \
4194 (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
4195 (X) == kDNSFlag1_RC_FormErr ? "FormErr" : \
4196 (X) == kDNSFlag1_RC_ServFail ? "ServFail" : \
4197 (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \
4198 (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \
4199 (X) == kDNSFlag1_RC_Refused ? "Refused" : \
4200 (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \
4201 (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \
4202 (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \
4203 (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \
4204 (X) == kDNSFlag1_RC_NotZone ? "NotZone" : \
4205 (X) == kDNSFlag1_RC_DSOTypeNI ? "DSOTypeNI" : "??" )
4206
mDNS_snprintf_add(char ** ptr,const char * lim,const char * fmt,...)4207 mDNSexport void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
4208 {
4209 va_list args;
4210 mDNSu32 buflen, n;
4211 char *const dst = *ptr;
4212
4213 buflen = (mDNSu32)(lim - dst);
4214 if (buflen > 0)
4215 {
4216 va_start(args, fmt);
4217 n = mDNS_vsnprintf(dst, buflen, fmt, args);
4218 va_end(args);
4219 *ptr = dst + n;
4220 }
4221 }
4222
4223 #define DNSTypeString(X) (((X) == kDNSType_A) ? "A" : DNSTypeName(X))
4224
DNSMessageDumpToLog(const DNSMessage * const msg,const mDNSu8 * const end)4225 mDNSlocal void DNSMessageDumpToLog(const DNSMessage *const msg, const mDNSu8 *const end)
4226 {
4227 domainname *name = mDNSNULL;
4228 const mDNSu8 *ptr = msg->data;
4229 domainname nameStorage[2];
4230
4231 char questions[512];
4232 questions[0] = '\0';
4233 char *questions_dst = questions;
4234 const char *const questions_lim = &questions[512];
4235 for (mDNSu32 i = 0; i < msg->h.numQuestions; i++)
4236 {
4237 mDNSu16 qtype, qclass;
4238
4239 name = &nameStorage[0];
4240 ptr = getDomainName(msg, ptr, end, name);
4241 if (!ptr) goto exit;
4242
4243 if ((end - ptr) < 4) goto exit;
4244 qtype = ReadField16(&ptr[0]);
4245 qclass = ReadField16(&ptr[2]);
4246 ptr += 4;
4247
4248 mDNS_snprintf_add(&questions_dst, questions_lim, " %##s %s", name->c, DNSTypeString(qtype));
4249 if (qclass != kDNSClass_IN) mDNS_snprintf_add(&questions_dst, questions_lim, "/%u", qclass);
4250 mDNS_snprintf_add(&questions_dst, questions_lim, "?");
4251 }
4252
4253 char rrs[512];
4254 rrs[0] = '\0';
4255 char *rrs_dst = rrs;
4256 const char *const rrs_lim = &rrs[512];
4257 const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
4258 for (mDNSu32 i = 0; i < rrcount; i++)
4259 {
4260 mDNSu16 rrtype, rrclass, rdlength;
4261 mDNSu32 ttl;
4262 int handled;
4263 const mDNSu8 *rdata;
4264 const domainname *const previousName = name;
4265
4266 name = &nameStorage[(name == &nameStorage[0]) ? 1 : 0];
4267 ptr = getDomainName(msg, ptr, end, name);
4268 if (!ptr) goto exit;
4269
4270 if ((end - ptr) < 10) goto exit;
4271 rrtype = ReadField16(&ptr[0]);
4272 rrclass = ReadField16(&ptr[2]);
4273 ttl = ReadField32(&ptr[4]);
4274 rdlength = ReadField16(&ptr[8]);
4275 ptr += 10;
4276
4277 if ((end - ptr) < rdlength) goto exit;
4278 rdata = ptr;
4279
4280 if (i > 0) mDNS_snprintf_add(&rrs_dst, rrs_lim, ",");
4281 if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&rrs_dst, rrs_lim, " %##s", name);
4282
4283 mDNS_snprintf_add(&rrs_dst, rrs_lim, " %s", DNSTypeString(rrtype));
4284 if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&rrs_dst, rrs_lim, "/%u", rrclass);
4285 mDNS_snprintf_add(&rrs_dst, rrs_lim, " ");
4286
4287 handled = mDNSfalse;
4288 switch (rrtype)
4289 {
4290 case kDNSType_A:
4291 if (rdlength == 4)
4292 {
4293 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.4a", rdata);
4294 handled = mDNStrue;
4295 }
4296 break;
4297
4298 case kDNSType_AAAA:
4299 if (rdlength == 16)
4300 {
4301 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.16a", rdata);
4302 handled = mDNStrue;
4303 }
4304 break;
4305
4306 case kDNSType_CNAME:
4307 ptr = getDomainName(msg, rdata, end, name);
4308 if (!ptr) goto exit;
4309
4310 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s", name);
4311 handled = mDNStrue;
4312 break;
4313
4314 case kDNSType_SOA:
4315 {
4316 mDNSu32 serial, refresh, retry, expire, minimum;
4317 domainname *const mname = &nameStorage[0];
4318 domainname *const rname = &nameStorage[1];
4319 name = mDNSNULL;
4320
4321 ptr = getDomainName(msg, rdata, end, mname);
4322 if (!ptr) goto exit;
4323
4324 ptr = getDomainName(msg, ptr, end, rname);
4325 if (!ptr) goto exit;
4326
4327 if ((end - ptr) < 20) goto exit;
4328 serial = ReadField32(&ptr[0]);
4329 refresh = ReadField32(&ptr[4]);
4330 retry = ReadField32(&ptr[8]);
4331 expire = ReadField32(&ptr[12]);
4332 minimum = ReadField32(&ptr[16]);
4333
4334 mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
4335 (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
4336
4337 handled = mDNStrue;
4338 break;
4339 }
4340
4341 default:
4342 break;
4343 }
4344 if (!handled) mDNS_snprintf_add(&rrs_dst, rrs_lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
4345 mDNS_snprintf_add(&rrs_dst, rrs_lim, " (%lu)", (unsigned long)ttl);
4346 ptr = rdata + rdlength;
4347 }
4348
4349 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
4350 "[Q%u] DNS " PUB_S PUB_S " (%lu) (flags %02X%02X) RCODE: " PUB_S " (%d)" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S ":"
4351 PRI_S " %u/%u/%u " PRI_S,
4352 mDNSVal16(msg->h.id),
4353 DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
4354 (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
4355 (unsigned long)(end - (const mDNSu8 *)msg),
4356 msg->h.flags.b[0], msg->h.flags.b[1],
4357 DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
4358 msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
4359 (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "",
4360 (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "",
4361 (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "",
4362 (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "",
4363 (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "",
4364 (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "",
4365 questions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, rrs);
4366
4367 exit:
4368 return;
4369 }
4370
DNSMessageIsResponse(const DNSMessage * const msg)4371 mDNSlocal mDNSBool DNSMessageIsResponse(const DNSMessage *const msg)
4372 {
4373 return ((msg->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Response);
4374 }
4375
DNSMessageIsQuery(const DNSMessage * const msg)4376 mDNSlocal mDNSBool DNSMessageIsQuery(const DNSMessage *const msg)
4377 {
4378 return !DNSMessageIsResponse(msg);
4379 }
4380
4381 // This function calculates and checks the hash value of the current DNS message if it matches a previous one already.
DumpMDNSPacket_CalculateAndCheckIfMsgAppearsBefore(const DNSMessage * const msg,const mDNSu8 * const end,const mDNSAddr * const srcaddr,const mDNSIPPort srcport,const mDNSAddr * const dstaddr,const mDNSIPPort dstport,const mDNSu32 ifIndex,mDNSu32 * const outMsgHash,mDNSBool * const outMsgHashSame,mDNSu32 * const outCompleteHash,mDNSBool * const outCompleteHashSame)4382 mDNSlocal void DumpMDNSPacket_CalculateAndCheckIfMsgAppearsBefore(const DNSMessage *const msg, const mDNSu8 *const end,
4383 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
4384 const mDNSu32 ifIndex, mDNSu32 *const outMsgHash, mDNSBool *const outMsgHashSame,
4385 mDNSu32 *const outCompleteHash, mDNSBool *const outCompleteHashSame)
4386 {
4387 // We calculate two hash values with different hash algorithms to avoid having collisions frequently.
4388 const mDNSu32 msgLen = sizeof(DNSMessageHeader) + (mDNSu32)(end - msg->data);
4389 const mDNSu32 msgHash = mDNS_NonCryptoHash(mDNSNonCryptoHash_FNV1a, msg->h.id.b, msgLen);
4390 const mDNSu32 msg2ndHash = mDNS_NonCryptoHash(mDNSNonCryptoHash_SDBM, msg->h.id.b, msgLen);
4391 mdns_assign(outMsgHash, msgHash);
4392
4393 mDNSu32 completeHash = msgHash;
4394 mDNSu32 complete2ndHash = msg2ndHash;
4395 if (srcaddr != mDNSNULL)
4396 {
4397 const mDNSu8 *const bytes = srcaddr->ip.v4.b;
4398 const mDNSu32 len = sizeof(srcaddr->ip.v4.b);
4399
4400 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, bytes, len);
4401 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, srcport.b,
4402 sizeof(srcport.b));
4403
4404 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, bytes, len);
4405 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, srcport.b,
4406 sizeof(srcport.b));
4407 }
4408 if (dstaddr != mDNSNULL)
4409 {
4410 const mDNSu8 *const bytes = dstaddr->ip.v4.b;
4411 const mDNSu32 len = sizeof(dstaddr->ip.v4.b);
4412
4413 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, bytes, len);
4414 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, dstport.b,
4415 sizeof(dstport.b));
4416
4417 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, bytes, len);
4418 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, dstport.b,
4419 sizeof(dstport.b));
4420 }
4421
4422 mDNSu8 ifIndexBytes[4];
4423 putVal32(ifIndexBytes, ifIndex);
4424 completeHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_FNV1a, completeHash, ifIndexBytes,
4425 sizeof(ifIndexBytes));
4426 complete2ndHash = mDNS_NonCryptoHashUpdateBytes(mDNSNonCryptoHash_SDBM, complete2ndHash, ifIndexBytes,
4427 sizeof(ifIndexBytes));
4428 mdns_assign(outCompleteHash, completeHash);
4429
4430 #define NUM_OF_SAVED_HASH_COUNT 20
4431 mDNSu32 i;
4432 mDNSu32 count;
4433
4434 static mDNSu32 previousMsgHashes[NUM_OF_SAVED_HASH_COUNT] = {0};
4435 static mDNSu32 previousMsg2ndHashes[NUM_OF_SAVED_HASH_COUNT] = {0};
4436 static mDNSu32 nextMsgHashSlot = 0;
4437 static mDNSu32 nextMsgHashUninitializedSlot = 0;
4438 mdns_compile_time_check_local(mdns_countof(previousMsgHashes) == mdns_countof(previousMsg2ndHashes));
4439
4440 mDNSBool msgHashSame = mDNSfalse;
4441 count = Min(mdns_countof(previousMsgHashes), nextMsgHashUninitializedSlot);
4442 for (i = 0; i < count; i++)
4443 {
4444 if (previousMsgHashes[i] == msgHash && previousMsg2ndHashes[i] == msg2ndHash)
4445 {
4446 msgHashSame = mDNStrue;
4447 break;
4448 }
4449 }
4450 if (!msgHashSame)
4451 {
4452 previousMsgHashes[nextMsgHashSlot] = msgHash;
4453 previousMsg2ndHashes[nextMsgHashSlot] = msg2ndHash;
4454 nextMsgHashSlot++;
4455 nextMsgHashSlot %= mdns_countof(previousMsgHashes);
4456 if (nextMsgHashUninitializedSlot < mdns_countof(previousMsgHashes))
4457 {
4458 nextMsgHashUninitializedSlot++;
4459 }
4460 }
4461 mdns_assign(outMsgHashSame, msgHashSame);
4462
4463 static mDNSu32 previousCompleteHashes[NUM_OF_SAVED_HASH_COUNT] = {0};
4464 static mDNSu32 previousComplete2ndHashes[NUM_OF_SAVED_HASH_COUNT] = {0};
4465 static mDNSu32 nextCompleteHashSlot = 0;
4466 static mDNSu32 nextCompleteHashUninitializedSlot = 0;
4467 mdns_compile_time_check_local(mdns_countof(previousCompleteHashes) == mdns_countof(previousComplete2ndHashes));
4468
4469 mDNSBool completeHashSame = mDNSfalse;
4470 count = Min(mdns_countof(previousCompleteHashes), nextCompleteHashUninitializedSlot);
4471 for (i = 0; i < count; i++)
4472 {
4473 if (previousCompleteHashes[i] == completeHash && previousComplete2ndHashes[i] == complete2ndHash)
4474 {
4475 completeHashSame = mDNStrue;
4476 break;
4477 }
4478 }
4479 if (!completeHashSame)
4480 {
4481 previousCompleteHashes[nextCompleteHashSlot] = completeHash;
4482 previousComplete2ndHashes[nextCompleteHashSlot] = complete2ndHash;
4483 nextCompleteHashSlot++;
4484 nextCompleteHashSlot %= mdns_countof(previousCompleteHashes);
4485 if (nextCompleteHashUninitializedSlot < mdns_countof(previousCompleteHashes))
4486 {
4487 nextCompleteHashUninitializedSlot++;
4488 }
4489 }
4490 mdns_assign(outCompleteHashSame, completeHashSame);
4491 }
4492
DumpMDNSPacket_GetNameHashTypeClass(const DNSMessage * const msg,const mDNSu8 * ptr,const mDNSu8 * const end,mDNSu32 * const outNameHash,mDNSu16 * const outType,mDNSu16 * const outClass)4493 mDNSlocal mDNSBool DumpMDNSPacket_GetNameHashTypeClass(const DNSMessage *const msg, const mDNSu8 *ptr,
4494 const mDNSu8 *const end, mDNSu32 *const outNameHash, mDNSu16 *const outType, mDNSu16 *const outClass)
4495 {
4496 mDNSBool found;
4497 domainname name;
4498
4499 ptr = getDomainName(msg, ptr, end, &name);
4500 const mDNSu32 nameHash = mDNS_NonCryptoHash(mDNSNonCryptoHash_FNV1a, name.c, DomainNameLength(&name));
4501 mdns_require_action_quiet(ptr, exit, found = mDNSfalse);
4502
4503 mdns_require_action_quiet(ptr + 4 <= end, exit, found = mDNSfalse);
4504 const mDNSu16 type = ReadField16(&ptr[0]);
4505 mDNSu16 class = ReadField16(&ptr[2]);
4506
4507 const mDNSBool isMDNS = mDNSOpaque16IsZero(msg->h.id);
4508 if (isMDNS)
4509 {
4510 class &= kDNSClass_Mask;
4511 }
4512
4513 mdns_assign(outNameHash, nameHash);
4514 mdns_assign(outType, type);
4515 mdns_assign(outClass, class);
4516 found = mDNStrue;
4517
4518 exit:
4519 return found;
4520 }
4521
4522 // Each name hash/type pair contains 4-byte uint32_t hash value and 2-byte uint16_t type value, in network byte order.
4523 #define DumpMDNSPacket_PairLen (sizeof(mDNSu32) + sizeof(mDNSu16))
4524 // Currently, we only log the first 10 pairs.
4525 #define DumpMDNSPacket_MaxPairCount 10
4526 // The buffer size to hold the bytes.
4527 #define DumpMDNSPacket_MaxBytesLen (DumpMDNSPacket_PairLen * DumpMDNSPacket_MaxPairCount)
4528
DumpMDNSPacket_GetNameHashTypeArray(const DNSMessage * const msg,const mDNSu8 * const end,mDNSu8 * const inOutNameHashTypeArray,const mDNSu32 maxByteCount,mDNSu32 * const outByteCount)4529 mDNSlocal mStatus DumpMDNSPacket_GetNameHashTypeArray(const DNSMessage *const msg, const mDNSu8 *const end,
4530 mDNSu8 *const inOutNameHashTypeArray, const mDNSu32 maxByteCount, mDNSu32 *const outByteCount)
4531 {
4532 mStatus err;
4533 const mDNSu8 *ptr_to_read;
4534 mDNSu8 *ptr_to_write = inOutNameHashTypeArray;
4535 mDNSu32 pairCount = 0;
4536 const mDNSu32 maxPairCount = maxByteCount / DumpMDNSPacket_PairLen;
4537
4538 const DNSMessageHeader *const hdr = &msg->h;
4539
4540 ptr_to_read = (const mDNSu8 *)msg->data;
4541 for (mDNSu32 i = 0; i < hdr->numQuestions && pairCount < maxPairCount; i++, pairCount++)
4542 {
4543 mDNSu32 qnameHash;
4544 mDNSu16 type;
4545 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &qnameHash, &type, mDNSNULL);
4546 mdns_require_action_quiet(found, exit, err = mStatus_Invalid);
4547
4548 ptr_to_write = putVal32(ptr_to_write, qnameHash);
4549 ptr_to_write = putVal16(ptr_to_write, type);
4550
4551 ptr_to_read = skipQuestion(msg, ptr_to_read, end);
4552 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid);
4553 }
4554
4555 for (mDNSu32 i = 0; i < hdr->numAnswers && pairCount < maxPairCount; i++, pairCount++)
4556 {
4557 mDNSu32 nameHash;
4558 mDNSu16 type;
4559 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &nameHash, &type, mDNSNULL);
4560 mdns_require_action_quiet(found, exit, err = mStatus_Invalid);
4561
4562 ptr_to_write = putVal32(ptr_to_write, nameHash);
4563 ptr_to_write = putVal16(ptr_to_write, type);
4564
4565 ptr_to_read = skipResourceRecord(msg, ptr_to_read, end);
4566 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid);
4567 }
4568
4569 for (mDNSu32 i = 0; i < hdr->numAuthorities && pairCount < maxPairCount; i++, pairCount++)
4570 {
4571 mDNSu32 nameHash;
4572 mDNSu16 type;
4573 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &nameHash, &type, mDNSNULL);
4574 mdns_require_action_quiet(found, exit, err = mStatus_Invalid);
4575
4576 ptr_to_write = putVal32(ptr_to_write, nameHash);
4577 ptr_to_write = putVal16(ptr_to_write, type);
4578
4579 ptr_to_read = skipResourceRecord(msg, ptr_to_read, end);
4580 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid);
4581 }
4582
4583 for (mDNSu32 i = 0; i < hdr->numAdditionals && pairCount < maxPairCount; i++, pairCount++)
4584 {
4585 mDNSu32 nameHash;
4586 mDNSu16 type;
4587 const mDNSBool found = DumpMDNSPacket_GetNameHashTypeClass(msg, ptr_to_read, end, &nameHash, &type, mDNSNULL);
4588 mdns_require_action_quiet(found, exit, err = mStatus_Invalid);
4589
4590 ptr_to_write = putVal32(ptr_to_write, nameHash);
4591 ptr_to_write = putVal16(ptr_to_write, type);
4592
4593 ptr_to_read = skipResourceRecord(msg, ptr_to_read, end);
4594 mdns_require_action_quiet(ptr_to_read, exit, err = mStatus_Invalid);
4595 }
4596
4597 err = mStatus_NoError;
4598 exit:
4599 mdns_assign(outByteCount, pairCount * DumpMDNSPacket_PairLen);
4600 return err;
4601 }
4602
DumpMDNSPacket(const mDNSBool sent,const DNSMessage * const msg,const mDNSu8 * const end,const mDNSAddr * const srcaddr,const mDNSIPPort srcport,const mDNSAddr * const dstaddr,const mDNSIPPort dstport,const mDNSu32 ifIndex,const char * const ifName)4603 mDNSlocal void DumpMDNSPacket(const mDNSBool sent, const DNSMessage *const msg, const mDNSu8 *const end,
4604 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
4605 const mDNSu32 ifIndex, const char *const ifName)
4606 {
4607 const mDNSu32 msgLen = sizeof(DNSMessageHeader) + (mDNSu32)(end - msg->data);
4608 const mDNSBool query = DNSMessageIsQuery(msg);
4609
4610 const mDNSBool unicastAssisted = (dstaddr && !mDNSAddrIsDNSMulticast(dstaddr) &&
4611 mDNSSameIPPort(dstport, MulticastDNSPort));
4612
4613 mDNSu32 msgHash; // Hash of the DNS message.
4614 mDNSBool sameMsg; // If the hash matches a previous DNS message.
4615 mDNSu32 completeMsgHash; // Hash of the DNS message, source address/port, destination address/port.
4616 mDNSBool sameCompleteMsg; // If the hash matches a previous DNS message that is sent from the same source host to
4617 // the same destination host.
4618 DumpMDNSPacket_CalculateAndCheckIfMsgAppearsBefore(msg, end, srcaddr, srcport, dstaddr, dstport, ifIndex, &msgHash,
4619 &sameMsg, &completeMsgHash, &sameCompleteMsg);
4620
4621 // The header fields are already in host byte order.
4622 DNSMessageHeader hdr = msg->h;
4623
4624 // Check if it is IPv6 or IPv4 message.
4625 mDNSBool ipv6Msg = mDNSfalse;
4626 if (srcaddr && srcaddr->type == mDNSAddrType_IPv6)
4627 {
4628 ipv6Msg = mDNStrue;
4629 }
4630 else if (dstaddr && dstaddr->type == mDNSAddrType_IPv6)
4631 {
4632 ipv6Msg = mDNStrue;
4633 }
4634
4635 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
4636 // The os_log specifier requires network byte order data.
4637 SwapDNSHeaderBytesWithHeader(&hdr);
4638 const mDNSu32 IDFlags = ReadField32(hdr.id.b);
4639 const uint64_t counts = ReadField64(&hdr.numQuestions);
4640 SwapDNSHeaderBytesWithHeader(&hdr);
4641 #endif
4642
4643 // Get the (Name hash, Type) bytes array from the DNS message, where name is converted to a 4-byte hash value
4644 // type is converted to a 2-byte value.
4645 mDNSu8 nameHashTypeBytes[DumpMDNSPacket_MaxBytesLen];
4646 mDNSu32 nameHashTypeBytesLen;
4647 if (!sameMsg)
4648 {
4649 // Only calculate the name hash type bytes when we have not seen this message recently.
4650 DumpMDNSPacket_GetNameHashTypeArray(msg, end, nameHashTypeBytes, sizeof(nameHashTypeBytes),
4651 &nameHashTypeBytesLen);
4652 }
4653 else
4654 {
4655 nameHashTypeBytesLen = 0;
4656 }
4657
4658 // Note:
4659 // 1. There are two hash values printed for the message logging in `[Q(%x, %x)]`.
4660 // a) The first value is the FNV-1a hash of the entire DNS message, the first value can be used to easily
4661 // identify the same DNS message quickly.
4662 // b) The second value is the FNV-1a hash of the entire DNS message, plus source address, source port,
4663 // destination address, destination port and interface index. This value can be used to easily identify
4664 // repetitive message transmission.
4665 // c) The two hash values above are also used to avoid unnecessary duplicate logs by checking the hash values of
4666 // the recent DNS message (currently recent means recent 20 messages).
4667 // d) We use two separate hash algorithms to check if the message has occurred recently, but we only print
4668 // FNV-1a hash values.
4669 // 2. For all "Send" events, we do not log destination address because it is always the corresponding multicast
4670 // address, there is no need to log them over and over again.
4671 // 3. We print "query", "response" according to the type of the DNS message.
4672 // 4. If we have not seen the DNS message before, the message header, the record count section will be printed. Also
4673 // the first 10 "(name hash, type)" pairs will be printed to provide more context.
4674 // 5. For the "Receive" event, we log source address so that we know where the query or response comes from.
4675
4676
4677 if (unicastAssisted) // unicast DNS
4678 {
4679 if (ipv6Msg) // IPv6
4680 {
4681 if (sent) // Send
4682 {
4683 if (query) // Query
4684 {
4685 if (sameCompleteMsg)
4686 {
4687 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4688 "[Q(%x, %x)] Sent a previous IPv6 mDNS query over unicast", msgHash, completeMsgHash);
4689 }
4690 else if (sameMsg)
4691 {
4692 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4693 "[Q(%x, %x)] Sent a previous IPv6 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S
4694 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex);
4695 }
4696 else
4697 {
4698 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4699 "[Q(%x, %x)] Sent %u-byte IPv6 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S "/%u "
4700 "-- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, msgHash,
4701 completeMsgHash, msgLen, dstaddr, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags),
4702 DNS_MSG_COUNTS_PARAM(hdr, counts),
4703 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4704 }
4705 }
4706 else // Response
4707 {
4708 if (sameCompleteMsg)
4709 {
4710 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4711 "[A(%x, %x)] Sent a previous IPv6 mDNS response over unicast", msgHash, completeMsgHash);
4712 }
4713 else if (sameMsg)
4714 {
4715 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4716 "[A(%x, %x)] Sent a previous IPv6 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S
4717 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex);
4718 }
4719 else
4720 {
4721 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4722 "[A(%x, %x)] Sent %u-byte IPv6 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S
4723 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4724 msgHash, completeMsgHash, msgLen, dstaddr, ifName, ifIndex,
4725 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4726 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4727 }
4728 }
4729 }
4730 else // Receive
4731 {
4732 if (query) // Query
4733 {
4734 if (sameCompleteMsg)
4735 {
4736 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4737 "[A(%x, %x)] Received a previous IPv6 mDNS query over unicast",
4738 msgHash, completeMsgHash);
4739 }
4740 else if (sameMsg)
4741 {
4742 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4743 "[A(%x, %x)] Received a previous IPv6 mDNS query from " PRI_IP_ADDR " over unicast via "
4744 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex);
4745 }
4746 else
4747 {
4748 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4749 "[A(%x, %x)] Received %u-byte IPv6 mDNS query from " PRI_IP_ADDR " over unicast via " PUB_S
4750 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4751 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex,
4752 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4753 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4754 }
4755 }
4756 else // Response
4757 {
4758 if (sameCompleteMsg)
4759 {
4760 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4761 "[Q(%x, %x)] Received a previous IPv6 mDNS response over unicast",
4762 msgHash, completeMsgHash);
4763 }
4764 else if (sameMsg)
4765 {
4766 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4767 "[Q(%x, %x)] Received a previous IPv6 mDNS response from " PRI_IP_ADDR " over unicast via "
4768 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex);
4769 }
4770 else
4771 {
4772 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4773 "[Q(%x, %x)] Received %u-byte IPv6 mDNS response from " PRI_IP_ADDR " over unicast via "
4774 PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4775 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex,
4776 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4777 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4778 }
4779 }
4780 }
4781 }
4782 else // IPv4
4783 {
4784 if (sent) // Send
4785 {
4786 if (query) // Query
4787 {
4788 if (sameCompleteMsg)
4789 {
4790 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4791 "[Q(%x, %x)] Sent a previous IPv4 mDNS query over unicast", msgHash, completeMsgHash);
4792 }
4793 else if (sameMsg)
4794 {
4795 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4796 "[Q(%x, %x)] Sent a previous IPv4 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S
4797 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex);
4798 }
4799 else
4800 {
4801 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4802 "[Q(%x, %x)] Sent %u-byte IPv4 mDNS query to " PRI_IP_ADDR " over unicast via " PUB_S "/%u "
4803 "-- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES, msgHash,
4804 completeMsgHash, msgLen, dstaddr, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags),
4805 DNS_MSG_COUNTS_PARAM(hdr, counts),
4806 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4807 }
4808 }
4809 else // Response
4810 {
4811 if (sameCompleteMsg)
4812 {
4813 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4814 "[A(%x, %x)] Sent a previous IPv4 mDNS response over unicast", msgHash, completeMsgHash);
4815 }
4816 else if (sameMsg)
4817 {
4818 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4819 "[A(%x, %x)] Sent a previous IPv4 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S
4820 "/%u", msgHash, completeMsgHash, dstaddr, ifName, ifIndex);
4821 }
4822 else
4823 {
4824 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4825 "[A(%x, %x)] Sent %u-byte IPv4 mDNS response to " PRI_IP_ADDR " over unicast via " PUB_S
4826 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4827 msgHash, completeMsgHash, msgLen, dstaddr, ifName, ifIndex,
4828 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4829 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4830 }
4831 }
4832 }
4833 else // Receive
4834 {
4835 if (query) // Query
4836 {
4837 if (sameCompleteMsg)
4838 {
4839 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4840 "[A(%x, %x)] Received a previous IPv4 mDNS query over unicast",
4841 msgHash, completeMsgHash);
4842 }
4843 else if (sameMsg)
4844 {
4845 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4846 "[A(%x, %x)] Received a previous IPv4 mDNS query from " PRI_IP_ADDR " over unicast via "
4847 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex);
4848 }
4849 else
4850 {
4851 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4852 "[A(%x, %x)] Received %u-byte IPv4 mDNS query from " PRI_IP_ADDR " over unicast via " PUB_S
4853 "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4854 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex,
4855 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4856 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4857 }
4858 }
4859 else // Response
4860 {
4861 if (sameCompleteMsg)
4862 {
4863 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4864 "[Q(%x, %x)] Received a previous IPv4 mDNS response over unicast",
4865 msgHash, completeMsgHash);
4866 }
4867 else if (sameMsg)
4868 {
4869 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4870 "[Q(%x, %x)] Received a previous IPv4 mDNS response from " PRI_IP_ADDR " over unicast via "
4871 PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName, ifIndex);
4872 }
4873 else
4874 {
4875 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4876 "[Q(%x, %x)] Received %u-byte IPv4 mDNS response from " PRI_IP_ADDR " over unicast via "
4877 PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4878 msgHash, completeMsgHash, msgLen, srcaddr, ifName, ifIndex,
4879 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4880 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4881 }
4882 }
4883 }
4884 }
4885 }
4886 else // multicast DNS
4887 {
4888 if (ipv6Msg) // IPv6
4889 {
4890 if (sent) // Send
4891 {
4892 if (query) // Query
4893 {
4894 if (sameCompleteMsg)
4895 {
4896 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4897 "[Q(%x, %x)] Sent a previous IPv6 mDNS query over multicast", msgHash, completeMsgHash);
4898 }
4899 else if (sameMsg)
4900 {
4901 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4902 "[Q(%x, %x)] Sent a previous IPv6 mDNS query over multicast via " PUB_S "/%u", msgHash,
4903 completeMsgHash, ifName, ifIndex);
4904 }
4905 else
4906 {
4907 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4908 "[Q(%x, %x)] Sent %u-byte IPv6 mDNS query over multicast via " PUB_S "/%u -- "
4909 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4910 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags),
4911 DNS_MSG_COUNTS_PARAM(hdr, counts),
4912 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4913 }
4914 }
4915 else // Response
4916 {
4917 if (sameCompleteMsg)
4918 {
4919 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4920 "[A(%x, %x)] Sent a previous IPv6 mDNS response over multicast", msgHash, completeMsgHash);
4921 }
4922 else if (sameMsg)
4923 {
4924 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4925 "[A(%x, %x)] Sent a previous IPv6 mDNS response over multicast via " PUB_S "/%u", msgHash,
4926 completeMsgHash, ifName, ifIndex);
4927 }
4928 else
4929 {
4930 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4931 "[A(%x, %x)] Sent %u-byte IPv6 mDNS response over multicast via " PUB_S "/%u -- "
4932 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
4933 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags),
4934 DNS_MSG_COUNTS_PARAM(hdr, counts),
4935 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4936 }
4937 }
4938 }
4939 else // Receive
4940 {
4941 if (query) // Query
4942 {
4943 if (sameCompleteMsg)
4944 {
4945 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4946 "[A(%x, %x)] Received a previous IPv6 mDNS query over multicast", msgHash,
4947 completeMsgHash);
4948 }
4949 else if (sameMsg)
4950 {
4951 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4952 "[A(%x, %x)] Received a previous IPv6 mDNS query from " PRI_IP_ADDR
4953 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName,
4954 ifIndex);
4955 }
4956 else
4957 {
4958 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4959 "[A(%x, %x)] Received %u-byte IPv6 mDNS query from " PRI_IP_ADDR
4960 " over multicast via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS
4961 " " MDNS_NAME_HASH_TYPE_BYTES, msgHash,
4962 completeMsgHash, msgLen, srcaddr, ifName, ifIndex,
4963 DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4964 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4965 }
4966 }
4967 else // Response
4968 {
4969 if (sameCompleteMsg)
4970 {
4971 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4972 "[Q(%x, %x)] Received a previous IPv6 mDNS response over multicast",
4973 msgHash, completeMsgHash);
4974 }
4975 else if (sameMsg)
4976 {
4977 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4978 "[Q(%x, %x)] Received a previous IPv6 mDNS response from " PRI_IP_ADDR
4979 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName,
4980 ifIndex);
4981 }
4982 else
4983 {
4984 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
4985 "[Q(%x, %x)] Received %u-byte IPv6 mDNS response from " PRI_IP_ADDR
4986 " over multicast via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS
4987 " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, completeMsgHash, msgLen, srcaddr, ifName,
4988 ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
4989 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
4990 }
4991 }
4992 }
4993 }
4994 else // IPv4
4995 {
4996 if (sent) // Send
4997 {
4998 if (query) // Query
4999 {
5000 if (sameCompleteMsg)
5001 {
5002 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5003 "[Q(%x, %x)] Sent a previous IPv4 mDNS query over multicast", msgHash, completeMsgHash);
5004 }
5005 else if (sameMsg)
5006 {
5007 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5008 "[Q(%x, %x)] Sent a previous IPv4 mDNS query over multicast via " PUB_S "/%u", msgHash,
5009 completeMsgHash, ifName, ifIndex);
5010 }
5011 else
5012 {
5013 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5014 "[Q(%x, %x)] Sent %u-byte IPv4 mDNS query over multicast via " PUB_S "/%u -- "
5015 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
5016 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags),
5017 DNS_MSG_COUNTS_PARAM(hdr, counts),
5018 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
5019 }
5020 }
5021 else // Response
5022 {
5023 if (sameCompleteMsg)
5024 {
5025 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5026 "[A(%x, %x)] Sent a previous IPv4 mDNS response over multicast", msgHash, completeMsgHash);
5027 }
5028 else if (sameMsg)
5029 {
5030 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5031 "[A(%x, %x)] Sent a previous IPv4 mDNS response over multicast via " PUB_S "/%u", msgHash,
5032 completeMsgHash, ifName, ifIndex);
5033 }
5034 else
5035 {
5036 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5037 "[A(%x, %x)] Sent %u-byte IPv4 mDNS response over multicast via " PUB_S "/%u -- "
5038 DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " " MDNS_NAME_HASH_TYPE_BYTES,
5039 msgHash, completeMsgHash, msgLen, ifName, ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags),
5040 DNS_MSG_COUNTS_PARAM(hdr, counts),
5041 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
5042 }
5043 }
5044 }
5045 else // Receive
5046 {
5047 if (query) // Query
5048 {
5049 if (sameCompleteMsg)
5050 {
5051 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5052 "[A(%x, %x)] Received a previous IPv4 mDNS query over multicast", msgHash,
5053 completeMsgHash);
5054 }
5055 else if (sameMsg)
5056 {
5057 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5058 "[A(%x, %x)] Received a previous IPv4 mDNS query from " PRI_IP_ADDR
5059 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName,
5060 ifIndex);
5061 }
5062 else
5063 {
5064 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5065 "[A(%x, %x)] Received %u-byte IPv4 mDNS query from " PRI_IP_ADDR " over multicast"
5066 " via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS " "
5067 MDNS_NAME_HASH_TYPE_BYTES, msgHash, completeMsgHash, msgLen, srcaddr, ifName,
5068 ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
5069 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
5070 }
5071 }
5072 else // Response
5073 {
5074 if (sameCompleteMsg)
5075 {
5076 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5077 "[Q(%x, %x)] Received a previous IPv4 mDNS response over multicast",
5078 msgHash, completeMsgHash);
5079 }
5080 else if (sameMsg)
5081 {
5082 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5083 "[Q(%x, %x)] Received a previous IPv4 mDNS response from " PRI_IP_ADDR
5084 " over multicast via " PUB_S "/%u", msgHash, completeMsgHash, srcaddr, ifName,
5085 ifIndex);
5086 }
5087 else
5088 {
5089 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
5090 "[Q(%x, %x)] Received %u-byte IPv4 mDNS response from " PRI_IP_ADDR
5091 " over multicast via " PUB_S "/%u -- " DNS_MSG_ID_FLAGS ", counts: " DNS_MSG_COUNTS
5092 " " MDNS_NAME_HASH_TYPE_BYTES, msgHash, completeMsgHash, msgLen, srcaddr, ifName,
5093 ifIndex, DNS_MSG_ID_FLAGS_PARAM(hdr, IDFlags), DNS_MSG_COUNTS_PARAM(hdr, counts),
5094 MDNS_NAME_HASH_TYPE_BYTES_PARAM(nameHashTypeBytes, nameHashTypeBytesLen));
5095 }
5096 }
5097 }
5098 }
5099 }
5100 }
5101
5102 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order
DumpPacket(mStatus status,mDNSBool sent,const char * transport,const mDNSAddr * srcaddr,mDNSIPPort srcport,const mDNSAddr * dstaddr,mDNSIPPort dstport,const DNSMessage * const msg,const mDNSu8 * const end,mDNSInterfaceID interfaceID)5103 mDNSexport void DumpPacket(mStatus status, mDNSBool sent, const char *transport,
5104 const mDNSAddr *srcaddr, mDNSIPPort srcport,const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg,
5105 const mDNSu8 *const end, mDNSInterfaceID interfaceID)
5106 {
5107 const mDNSAddr zeroIPv4Addr = { mDNSAddrType_IPv4, {{{ 0 }}} };
5108 char action[32];
5109
5110 if (!status) mDNS_snprintf(action, sizeof(action), sent ? "Sent" : "Received");
5111 else mDNS_snprintf(action, sizeof(action), "ERROR %d %sing", status, sent ? "Send" : "Receiv");
5112
5113 #if __APPLE__
5114 const mDNSu32 interfaceIndex = IIDPrintable(interfaceID);
5115 const char *const interfaceName = InterfaceNameForID(&mDNSStorage, interfaceID);
5116 #else
5117 const mDNSu32 interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, interfaceID, mDNStrue);
5118 const char *const interfaceName = "interface";
5119 #endif
5120
5121 if (!mDNSOpaque16IsZero(msg->h.id))
5122 {
5123 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[Q%u] " PUB_S " " PUB_S " DNS Message %lu bytes from "
5124 PRI_IP_ADDR ":%d to " PRI_IP_ADDR ":%d via " PUB_S " (%p)", mDNSVal16(msg->h.id), action, transport,
5125 (unsigned long)(end - (const mDNSu8 *)msg), srcaddr ? srcaddr : &zeroIPv4Addr, mDNSVal16(srcport),
5126 dstaddr ? dstaddr : &zeroIPv4Addr, mDNSVal16(dstport), interfaceName, interfaceID);
5127 DNSMessageDumpToLog(msg, end);
5128 }
5129 else
5130 {
5131 DumpMDNSPacket(sent, msg, end, srcaddr, srcport, dstaddr, dstport, interfaceIndex, interfaceName);
5132 if (status)
5133 {
5134 if (sent)
5135 {
5136 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR,
5137 "Sending mDNS message failed - mStatus: %d", status);
5138 }
5139 else
5140 {
5141 LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR,
5142 "Receiving mDNS message failed - mStatus: %d", status);
5143 }
5144 }
5145 }
5146 }
5147
5148 // ***************************************************************************
5149 // MARK: - Packet Sending Functions
5150
5151 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
5152 struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
5153 // Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
5154 struct UDPSocket_struct { mDNSIPPort port; /* ... */ };
5155
5156 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
5157 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
mDNSSendDNSMessage(mDNS * const m,DNSMessage * const msg,mDNSu8 * end,mDNSInterfaceID InterfaceID,TCPSocket * tcpSrc,UDPSocket * udpSrc,const mDNSAddr * dst,mDNSIPPort dstport,DomainAuthInfo * authInfo,mDNSBool useBackgroundTrafficClass)5158 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
5159 mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
5160 mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass)
5161 {
5162 mStatus status = mStatus_NoError;
5163 const mDNSu16 numAdditionals = msg->h.numAdditionals;
5164
5165
5166 // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code)
5167 if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData)
5168 {
5169 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: invalid message %p %p %ld", msg->data, end, end - msg->data);
5170 return mStatus_BadParamErr;
5171 }
5172
5173 // Put all the integer values in IETF byte-order (MSB first, LSB second)
5174 SwapDNSHeaderBytes(msg);
5175
5176 if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0); // DNSDigest_SignMessage operates on message in network byte order
5177
5178 #if defined(DEBUG) && DEBUG
5179 if (authInfo && end)
5180 {
5181 // If this is a debug build, every time when we sign the response, use the verifying function to ensure that
5182 // both functions work correctly.
5183 DNSDigest_VerifyMessage_Verify(msg, end, authInfo);
5184 }
5185 #endif
5186
5187 if (!end)
5188 {
5189 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: DNSDigest_SignMessage failed");
5190 status = mStatus_NoMemoryErr;
5191 }
5192 else
5193 {
5194 // Send the packet on the wire
5195 if (!tcpSrc)
5196 status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, udpSrc, dst, dstport, useBackgroundTrafficClass);
5197 else
5198 {
5199 mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
5200 mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
5201 char *buf;
5202 long nsent;
5203
5204 // Try to send them in one packet if we can allocate enough memory
5205 buf = (char *) mDNSPlatformMemAllocate(msglen + 2);
5206 if (buf)
5207 {
5208 buf[0] = lenbuf[0];
5209 buf[1] = lenbuf[1];
5210 mDNSPlatformMemCopy(buf+2, msg, msglen);
5211 nsent = mDNSPlatformWriteTCP(tcpSrc, buf, msglen+2);
5212 if (nsent != (msglen + 2))
5213 {
5214 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: write message failed %ld/%d", nsent, msglen);
5215 status = mStatus_ConnFailed;
5216 }
5217 mDNSPlatformMemFree(buf);
5218 }
5219 else
5220 {
5221 nsent = mDNSPlatformWriteTCP(tcpSrc, (char*)lenbuf, 2);
5222 if (nsent != 2)
5223 {
5224 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: write msg length failed %ld/%d", nsent, 2);
5225 status = mStatus_ConnFailed;
5226 }
5227 else
5228 {
5229 nsent = mDNSPlatformWriteTCP(tcpSrc, (char *)msg, msglen);
5230 if (nsent != msglen)
5231 {
5232 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNSSendDNSMessage: write msg body failed %ld/%d", nsent, msglen);
5233 status = mStatus_ConnFailed;
5234 }
5235 }
5236 }
5237 }
5238 }
5239
5240 // Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage)
5241 SwapDNSHeaderBytes(msg);
5242
5243 char *transport = "UDP";
5244 mDNSIPPort portNumber = udpSrc ? udpSrc->port : MulticastDNSPort;
5245 if (tcpSrc)
5246 {
5247 if (tcpSrc->flags)
5248 transport = "TLS";
5249 else
5250 transport = "TCP";
5251 portNumber = tcpSrc->port;
5252 }
5253 DumpPacket(status, mDNStrue, transport, mDNSNULL, portNumber, dst, dstport, msg, end, InterfaceID);
5254
5255 // put the number of additionals back the way it was
5256 msg->h.numAdditionals = numAdditionals;
5257
5258 return(status);
5259 }
5260
5261 // ***************************************************************************
5262 // MARK: - DNSQuestion Functions
5263
5264 #if MDNSRESPONDER_SUPPORTS(APPLE, LOG_PRIVACY_LEVEL)
DNSQuestionNeedsSensitiveLogging(const DNSQuestion * const q)5265 mDNSBool DNSQuestionNeedsSensitiveLogging(const DNSQuestion *const q)
5266 {
5267 return is_apple_internal_build() && (q->logPrivacyLevel == dnssd_log_privacy_level_private);
5268 }
5269 #endif
5270
5271 #if MDNSRESPONDER_SUPPORTS(APPLE, RUNTIME_MDNS_METRICS)
DNSQuestionCollectsMDNSMetric(const DNSQuestion * const q)5272 mDNSBool DNSQuestionCollectsMDNSMetric(const DNSQuestion *const q)
5273 {
5274 return (!q->DuplicateOf && mDNSOpaque16IsZero(q->TargetQID));
5275 }
5276 #endif
5277
5278 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY)
5279
DNSQuestionUsesAWDL(const DNSQuestion * const q)5280 mDNSlocal mDNSBool DNSQuestionUsesAWDL(const DNSQuestion *const q)
5281 {
5282 if (q->InterfaceID == mDNSInterface_Any)
5283 {
5284 return ((q->flags & kDNSServiceFlagsIncludeAWDL) != 0);
5285 }
5286 else
5287 {
5288 return mDNSPlatformInterfaceIsAWDL(q->InterfaceID);
5289 }
5290 }
5291
DNSQuestionIsEligibleForMDNSAlternativeService(const DNSQuestion * const q)5292 mDNSBool DNSQuestionIsEligibleForMDNSAlternativeService(const DNSQuestion *const q)
5293 {
5294 // 0. The system is not in a demo mode where mDNS traffic is ensured to be lossless in a wired connection.
5295 // 1. The question must be an mDNS question.
5296 // 2. The question cannot enable resolution over AWDL.
5297 // (because the resolution over mDNS alternative service is mutual exclusive with the resolution over AWDL)
5298 return (!is_airplay_demo_mode_enabled() && mDNSOpaque16IsZero(q->TargetQID) && !DNSQuestionUsesAWDL(q));
5299 }
5300
DNSQuestionRequestsMDNSAlternativeService(const DNSQuestion * const q)5301 mDNSBool DNSQuestionRequestsMDNSAlternativeService(const DNSQuestion *const q)
5302 {
5303 return (!mDNSOpaque16IsZero(q->TargetQID) && !Question_uDNS(q));
5304 }
5305
DNSQuestionUsesMDNSAlternativeService(const DNSQuestion * const q)5306 mDNSBool DNSQuestionUsesMDNSAlternativeService(const DNSQuestion *const q)
5307 {
5308 return q->dnsservice && mdns_dns_service_is_mdns_alternative(q->dnsservice);
5309 }
5310 #endif
5311
5312 // ***************************************************************************
5313 // MARK: - RR List Management & Task Management
5314
mDNS_VerifyLockState(const char * const operation,const mDNSBool checkIfLockHeld,const mDNSu32 mDNS_busy,const mDNSu32 mDNS_reentrancy,const char * const functionName,const mDNSu32 lineNumber)5315 mDNSexport void mDNS_VerifyLockState(const char *const operation, const mDNSBool checkIfLockHeld,
5316 const mDNSu32 mDNS_busy, const mDNSu32 mDNS_reentrancy, const char *const functionName, const mDNSu32 lineNumber)
5317 {
5318 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK)
5319 static os_unfair_lock logLock = OS_UNFAIR_LOCK_INIT;
5320 #endif
5321 static const char *lastLockOperator = mDNSNULL; // The name of the function that succeeded in doing lock operation last time.
5322 static mDNSu32 lineNumberlastLockOperator = 0; // The line number in the source code when this function gets called last time.
5323
5324 #define CRASH_ON_LOCK_ERROR 0
5325 #if (CRASH_ON_LOCK_ERROR)
5326 // When CRASH_ON_LOCK_ERROR is set to 1, if we encounter lock error, we will make mDNSResponder crash immediately
5327 // to let the bug to be identified easily.
5328 mDNSBool lockErrorEncountered = mDNSfalse;
5329 #endif
5330
5331 if (checkIfLockHeld)
5332 {
5333 // If the lock is held by the caller, then the number of times that the lock has been grabbed should be one more
5334 // than the number of times that the lock has been dropped, so that only one lock is currently being held.
5335 if (mDNS_busy > mDNS_reentrancy + 1)
5336 {
5337 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
5338 "Lock failure: Check Lock, lock was grabbed by multiple callers - "
5339 "caller: " PUB_S " at line %u, last successful lock holder: " PUB_S " at line %u, "
5340 "mDNS_busy (%u) != mDNS_reentrancy (%u).", functionName, lineNumber, lastLockOperator,
5341 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy);
5342 #if (CRASH_ON_LOCK_ERROR)
5343 lockErrorEncountered = mDNStrue;
5344 #endif
5345 }
5346 else if (mDNS_busy < mDNS_reentrancy + 1)
5347 {
5348 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
5349 "Lock failure: Check Lock, last lock dropper dropped the lock before grabbing it - "
5350 "caller: " PUB_S " at line %u, last lock dropper: " PUB_S " at line %u, "
5351 "mDNS_busy (%u) != mDNS_reentrancy (%u).", functionName, lineNumber, lastLockOperator,
5352 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy);
5353 #if (CRASH_ON_LOCK_ERROR)
5354 lockErrorEncountered = mDNStrue;
5355 #endif
5356 }
5357 }
5358 else
5359 {
5360 // In non-critical section:
5361 // The number of times that the lock has been grabbed should be equal to the number of times that the lock has
5362 // been dropped, which means, no one is currently holding the real lock.
5363 if (mDNS_busy == mDNS_reentrancy)
5364 {
5365 switch (operation[0])
5366 {
5367 case 'L': // "Lock" (it is paired with "Unlock")
5368 case 'D': // "Drop Lock" (it is paired with "Reclaim Lock")
5369 // Add new lock state, and we need to remember who succeeds in doing the operation because it might
5370 // lead to invalid lock state.
5371 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK)
5372 os_unfair_lock_lock(&logLock);
5373 #endif
5374 lastLockOperator = functionName;
5375 lineNumberlastLockOperator = lineNumber;
5376 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK)
5377 os_unfair_lock_unlock(&logLock);
5378 #endif
5379 break;
5380
5381 case 'U': // "Unlock"
5382 case 'R': // "Reclaim Lock"
5383 // Remove the previous lock state, and we can remove the name and the line number that has been
5384 // saved.
5385 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK)
5386 os_unfair_lock_lock(&logLock);
5387 #endif
5388 lastLockOperator = mDNSNULL;
5389 lineNumberlastLockOperator = 0;
5390 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_UNFAIR_LOCK)
5391 os_unfair_lock_unlock(&logLock);
5392 #endif
5393 case 'C': // "Check Lock"
5394 // "Check Lock" operation will never change the lock state, so no need to take a note for that.
5395 break;
5396
5397 default:
5398 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, "Invalid lock operation - " PUB_S, operation);
5399 break;
5400 }
5401 }
5402 else if (mDNS_busy > mDNS_reentrancy)
5403 {
5404 // If mDNS_busy is greater than mDNS_reentrancy, there is someone who has grabbed the lock. This is invalid
5405 // in a critical section.
5406 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
5407 "Lock failure: " PUB_S ", last lock holder still holds the lock - "
5408 "caller: " PUB_S " at line %u, last successful lock holder: " PUB_S " at line %u, "
5409 "mDNS_busy (%u) != mDNS_reentrancy (%u).", operation, functionName, lineNumber, lastLockOperator,
5410 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy);
5411 #if (CRASH_ON_LOCK_ERROR)
5412 lockErrorEncountered = mDNStrue;
5413 #endif
5414 }
5415 else // m->mDNS_busy < m->mDNS_reentrancy
5416 {
5417 // If mDNS_busy is less than mDNS_reentrancy, something bad happens, because no one should drop the lock
5418 // before grabbing it successfully. This should never heppen.
5419 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
5420 "Lock failure: " PUB_S ", last lock dropper dropped the lock before grabbing it - "
5421 "caller: " PUB_S " at line %u, last lock dropper: " PUB_S " at line %u, "
5422 "mDNS_busy (%u) != mDNS_reentrancy (%u).", operation, functionName, lineNumber, lastLockOperator,
5423 lineNumberlastLockOperator, mDNS_busy, mDNS_reentrancy);
5424 #if (CRASH_ON_LOCK_ERROR)
5425 lockErrorEncountered = mDNStrue;
5426 #endif
5427 }
5428 }
5429
5430 #if (CRASH_ON_LOCK_ERROR)
5431 if (lockErrorEncountered)
5432 {
5433 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
5434 "Encounter lock error, make mDNSResponder crash immediately.");
5435 assert(0);
5436 }
5437 #endif
5438 }
5439
mDNS_Lock_(mDNS * const m,const char * const functionName,const mDNSu32 lineNumber)5440 mDNSexport void mDNS_Lock_(mDNS *const m, const char *const functionName, const mDNSu32 lineNumber)
5441 {
5442 // MUST grab the platform lock FIRST!
5443 mDNSPlatformLock(m);
5444
5445 // Normally, mDNS_reentrancy is zero and so is mDNS_busy
5446 // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
5447 // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
5448 // If mDNS_busy != mDNS_reentrancy that's a bad sign
5449 mDNS_VerifyLockState("Lock", mDNSfalse, m->mDNS_busy, m->mDNS_reentrancy, functionName, lineNumber);
5450
5451 // If this is an initial entry into the mDNSCore code, set m->timenow
5452 // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
5453 if (m->mDNS_busy == 0)
5454 {
5455 if (m->timenow)
5456 {
5457 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, PUB_S ": mDNS_Lock: m->timenow already set (%u/%u)",
5458 functionName, m->timenow, mDNS_TimeNow_NoLock(m));
5459 }
5460
5461 m->timenow = mDNS_TimeNow_NoLock(m);
5462 if (m->timenow == 0) m->timenow = 1;
5463 }
5464 else if (m->timenow == 0)
5465 {
5466 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
5467 PUB_S ": mDNS_Lock: m->mDNS_busy is %u but m->timenow not set", functionName, m->mDNS_busy);
5468
5469 m->timenow = mDNS_TimeNow_NoLock(m);
5470 if (m->timenow == 0) m->timenow = 1;
5471 }
5472
5473 if (m->timenow_last - m->timenow > 0)
5474 {
5475 m->timenow_adjust += m->timenow_last - m->timenow;
5476 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
5477 PUB_S ": mDNSPlatformRawTime went backwards by %d ticks; setting correction factor to %d",
5478 functionName, m->timenow_last - m->timenow, m->timenow_adjust);
5479
5480 m->timenow = m->timenow_last;
5481 }
5482 m->timenow_last = m->timenow;
5483
5484 // Increment mDNS_busy so we'll recognise re-entrant calls
5485 m->mDNS_busy++;
5486 m->mDNS_Lock_functionname = functionName;
5487 m->mDNS_Lock_lineno = lineNumber;
5488 }
5489
AnyLocalRecordReady(const mDNS * const m)5490 mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
5491 {
5492 AuthRecord *rr;
5493 for (rr = m->NewLocalRecords; rr; rr = rr->next)
5494 if (LocalRecordReady(rr)) return rr;
5495 return mDNSNULL;
5496 }
5497
GetNextScheduledEvent(const mDNS * const m)5498 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
5499 {
5500 mDNSs32 e = m->timenow + FutureTime;
5501 if (m->mDNSPlatformStatus != mStatus_NoError) return(e);
5502 if (m->NewQuestions)
5503 {
5504 if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
5505 else return(m->timenow);
5506 }
5507 if (m->NewLocalOnlyQuestions) return(m->timenow);
5508 if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
5509 if (m->NewLocalOnlyRecords) return(m->timenow);
5510 if (m->SPSProxyListChanged) return(m->timenow);
5511 if (m->LocalRemoveEvents) return(m->timenow);
5512
5513 #ifndef UNICAST_DISABLED
5514 if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent;
5515 if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp;
5516 if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate;
5517 #endif
5518
5519 if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck;
5520 if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS;
5521 if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA;
5522
5523 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
5524 if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
5525 #endif
5526
5527 // Check if it is time to stop domain enumeration.
5528 for (const DomainEnumerationOp *op = m->domainsToDoEnumeration; op != mDNSNULL; op = op->next)
5529 {
5530 // Iterate over all types of domain enumeration.
5531 for (mDNSu32 type = 0; type < mDNS_DomainTypeMaxCount; type++)
5532 {
5533 if (op->enumerations[type] == mDNSNULL)
5534 {
5535 continue;
5536 }
5537
5538 // Only check the domain enumeration that starts the stopping process.
5539 if (op->enumerations[type]->state != DomainEnumerationState_StopInProgress)
5540 {
5541 continue;
5542 }
5543
5544 if (e - op->enumerations[type]->nextStopTime > 0)
5545 {
5546 e = op->enumerations[type]->nextStopTime;
5547 }
5548 }
5549 }
5550
5551 #if MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY)
5552 const mDNSs32 nextResolverDiscoveryEvent = ResolverDiscovery_GetNextScheduledEvent();
5553 if (nextResolverDiscoveryEvent && (e - nextResolverDiscoveryEvent > 0)) e = nextResolverDiscoveryEvent;
5554 #endif
5555
5556 // NextScheduledSPRetry only valid when DelaySleep not set
5557 if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
5558 if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
5559
5560 if (m->SuppressQueries)
5561 {
5562 if (e - m->SuppressQueries > 0) e = m->SuppressQueries;
5563 }
5564 else
5565 {
5566 if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery;
5567 if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe;
5568 }
5569 if (m->SuppressResponses)
5570 {
5571 if (e - m->SuppressResponses > 0) e = m->SuppressResponses;
5572 }
5573 else
5574 {
5575 if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
5576 }
5577 if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime;
5578
5579 if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime;
5580
5581 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
5582 if (m->NextUpdateDNSSECValidatedCache && (e - m->NextUpdateDNSSECValidatedCache > 0))
5583 {
5584 e = m->NextUpdateDNSSECValidatedCache;
5585 }
5586 #endif
5587
5588 #if MDNSRESPONDER_SUPPORTS(APPLE, RUNTIME_MDNS_METRICS)
5589 if (m->NextMDNSResponseDelayReport && (e - m->NextMDNSResponseDelayReport > 0))
5590 {
5591 e = m->NextMDNSResponseDelayReport;
5592 }
5593 #endif
5594
5595 return(e);
5596 }
5597
5598 #define LogTSE TSE++,LogMsg
5599
ShowTaskSchedulingError(mDNS * const m)5600 mDNSexport void ShowTaskSchedulingError(mDNS *const m)
5601 {
5602 int TSE = 0;
5603 AuthRecord *rr;
5604 mDNS_Lock(m);
5605
5606 LogMsg("Task Scheduling Error: *** Continuously busy for more than a second");
5607
5608 // Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above
5609
5610 if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
5611 LogTSE("Task Scheduling Error: NewQuestion %##s (%s)",
5612 m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
5613
5614 if (m->NewLocalOnlyQuestions)
5615 LogTSE("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
5616 m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
5617
5618 if (m->NewLocalRecords)
5619 {
5620 rr = AnyLocalRecordReady(m);
5621 if (rr) LogTSE("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
5622 }
5623
5624 if (m->NewLocalOnlyRecords) LogTSE("Task Scheduling Error: NewLocalOnlyRecords");
5625
5626 if (m->SPSProxyListChanged) LogTSE("Task Scheduling Error: SPSProxyListChanged");
5627
5628 if (m->LocalRemoveEvents) LogTSE("Task Scheduling Error: LocalRemoveEvents");
5629
5630 #ifndef UNICAST_DISABLED
5631 if (m->timenow - m->NextuDNSEvent >= 0)
5632 LogTSE("Task Scheduling Error: m->NextuDNSEvent %d", m->timenow - m->NextuDNSEvent);
5633 if (m->timenow - m->NextScheduledNATOp >= 0)
5634 LogTSE("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp);
5635 if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0)
5636 LogTSE("Task Scheduling Error: m->NextSRVUpdate %d", m->timenow - m->NextSRVUpdate);
5637 #endif
5638
5639 if (m->timenow - m->NextCacheCheck >= 0)
5640 LogTSE("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck);
5641 if (m->timenow - m->NextScheduledSPS >= 0)
5642 LogTSE("Task Scheduling Error: m->NextScheduledSPS %d", m->timenow - m->NextScheduledSPS);
5643 if (m->timenow - m->NextScheduledKA >= 0)
5644 LogTSE("Task Scheduling Error: m->NextScheduledKA %d", m->timenow - m->NextScheduledKA);
5645 if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
5646 LogTSE("Task Scheduling Error: m->NextScheduledSPRetry %d", m->timenow - m->NextScheduledSPRetry);
5647 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
5648 LogTSE("Task Scheduling Error: m->DelaySleep %d", m->timenow - m->DelaySleep);
5649
5650 if (m->SuppressQueries && m->timenow - m->SuppressQueries >= 0)
5651 LogTSE("Task Scheduling Error: m->SuppressQueries %d", m->timenow - m->SuppressQueries);
5652 if (m->SuppressResponses && m->timenow - m->SuppressResponses >= 0)
5653 LogTSE("Task Scheduling Error: m->SuppressResponses %d", m->timenow - m->SuppressResponses);
5654 if (m->timenow - m->NextScheduledQuery >= 0)
5655 LogTSE("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery);
5656 if (m->timenow - m->NextScheduledProbe >= 0)
5657 LogTSE("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe);
5658 if (m->timenow - m->NextScheduledResponse >= 0)
5659 LogTSE("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
5660 if (m->timenow - m->NextScheduledStopTime >= 0)
5661 LogTSE("Task Scheduling Error: m->NextScheduledStopTime %d", m->timenow - m->NextScheduledStopTime);
5662
5663 if (m->timenow - m->NextScheduledEvent >= 0)
5664 LogTSE("Task Scheduling Error: m->NextScheduledEvent %d", m->timenow - m->NextScheduledEvent);
5665
5666 if (m->NetworkChanged && m->timenow - m->NetworkChanged >= 0)
5667 LogTSE("Task Scheduling Error: NetworkChanged %d", m->timenow - m->NetworkChanged);
5668
5669 if (!TSE) LogMsg("Task Scheduling Error: *** No likely causes identified");
5670 else LogMsg("Task Scheduling Error: *** %d potential cause%s identified (significant only if the same cause consistently appears)", TSE, TSE > 1 ? "s" : "");
5671
5672 mDNS_Unlock(m);
5673 }
5674
mDNS_Unlock_(mDNS * const m,const char * const functionName,const mDNSu32 lineNumber)5675 mDNSexport void mDNS_Unlock_(mDNS *const m, const char *const functionName, const mDNSu32 lineNumber)
5676 {
5677 // Decrement mDNS_busy
5678 m->mDNS_busy--;
5679
5680 // Check for locking failures
5681 mDNS_VerifyLockState("Unlock", mDNSfalse, m->mDNS_busy, m->mDNS_reentrancy, functionName, lineNumber);
5682
5683 // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
5684 if (m->mDNS_busy == 0)
5685 {
5686 m->NextScheduledEvent = GetNextScheduledEvent(m);
5687 if (m->timenow == 0)
5688 {
5689 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, PUB_S ": mDNS_Unlock: ERROR! m->timenow aready zero",
5690 functionName);
5691 }
5692 m->timenow = 0;
5693 }
5694
5695 // MUST release the platform lock LAST!
5696 mDNSPlatformUnlock(m);
5697 }
5698
5699 // ***************************************************************************
5700 // MARK: - Specialized mDNS version of vsnprintf
5701
5702 static const struct mDNSprintf_format
5703 {
5704 unsigned leftJustify : 1;
5705 unsigned forceSign : 1;
5706 unsigned zeroPad : 1;
5707 unsigned havePrecision : 1;
5708 unsigned hSize : 1;
5709 unsigned lSize : 1;
5710 char altForm;
5711 char sign; // +, - or space
5712 unsigned int fieldWidth;
5713 unsigned int precision;
5714 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
5715
5716 #define kHexDigitsLowercase "0123456789abcdef"
5717 #define kHexDigitsUppercase "0123456789ABCDEF";
5718
mDNS_vsnprintf(char * sbuffer,mDNSu32 buflen,const char * fmt,va_list arg)5719 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
5720 {
5721 mDNSu32 nwritten = 0;
5722 int c;
5723 if (buflen == 0) return(0);
5724 buflen--; // Pre-reserve one space in the buffer for the terminating null
5725 if (buflen == 0) goto exit;
5726
5727 for (c = *fmt; c != '\0'; c = (c != '\0') ? *++fmt : c)
5728 {
5729 unsigned long n;
5730 int hexdump = mDNSfalse;
5731 if (c != '%')
5732 {
5733 *sbuffer++ = (char)c;
5734 if (++nwritten >= buflen) goto exit;
5735 }
5736 else
5737 {
5738 unsigned int i=0, j;
5739 // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
5740 // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
5741 // The size needs to be enough for a 256-byte domain name plus some error text.
5742 #define mDNS_VACB_Size 300
5743 char mDNS_VACB[mDNS_VACB_Size];
5744 #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
5745 #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
5746 char *s = mDNS_VACB_Lim, *digits;
5747 struct mDNSprintf_format F = mDNSprintf_format_default;
5748
5749 while (1) // decode flags
5750 {
5751 c = *++fmt;
5752 if (c == '-') F.leftJustify = 1;
5753 else if (c == '+') F.forceSign = 1;
5754 else if (c == ' ') F.sign = ' ';
5755 else if (c == '#') F.altForm++;
5756 else if (c == '0') F.zeroPad = 1;
5757 else break;
5758 }
5759
5760 if (c == '*') // decode field width
5761 {
5762 int f = va_arg(arg, int);
5763 if (f < 0) { f = -f; F.leftJustify = 1; }
5764 F.fieldWidth = (unsigned int)f;
5765 c = *++fmt;
5766 }
5767 else
5768 {
5769 for (; c >= '0' && c <= '9'; c = *++fmt)
5770 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
5771 }
5772
5773 if (c == '.') // decode precision
5774 {
5775 if ((c = *++fmt) == '*')
5776 { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
5777 else for (; c >= '0' && c <= '9'; c = *++fmt)
5778 F.precision = (10 * F.precision) + (c - '0');
5779 F.havePrecision = 1;
5780 }
5781
5782 if (F.leftJustify) F.zeroPad = 0;
5783
5784 conv:
5785 switch (c) // perform appropriate conversion
5786 {
5787 case 'h': F.hSize = 1; c = *++fmt; goto conv;
5788 case 'l': // fall through
5789 case 'L': F.lSize = 1; c = *++fmt; goto conv;
5790 case 'd':
5791 case 'i': if (F.lSize) n = (unsigned long)va_arg(arg, long);
5792 else n = (unsigned long)va_arg(arg, int);
5793 if (F.hSize) n = (short) n;
5794 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
5795 else if (F.forceSign) F.sign = '+';
5796 goto decimal;
5797 case 'u': if (F.lSize) n = va_arg(arg, unsigned long);
5798 else n = va_arg(arg, unsigned int);
5799 if (F.hSize) n = (unsigned short) n;
5800 F.sign = 0;
5801 goto decimal;
5802 decimal: if (!F.havePrecision)
5803 {
5804 if (F.zeroPad)
5805 {
5806 F.precision = F.fieldWidth;
5807 if (F.sign) --F.precision;
5808 }
5809 if (F.precision < 1) F.precision = 1;
5810 }
5811 if (F.precision > mDNS_VACB_Size - 1)
5812 F.precision = mDNS_VACB_Size - 1;
5813 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
5814 for (; i < F.precision; i++) *--s = '0';
5815 if (F.sign) { *--s = F.sign; i++; }
5816 break;
5817
5818 case 'o': if (F.lSize) n = va_arg(arg, unsigned long);
5819 else n = va_arg(arg, unsigned int);
5820 if (F.hSize) n = (unsigned short) n;
5821 if (!F.havePrecision)
5822 {
5823 if (F.zeroPad) F.precision = F.fieldWidth;
5824 if (F.precision < 1) F.precision = 1;
5825 }
5826 if (F.precision > mDNS_VACB_Size - 1)
5827 F.precision = mDNS_VACB_Size - 1;
5828 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
5829 if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
5830 for (; i < F.precision; i++) *--s = '0';
5831 break;
5832
5833 case 'a': {
5834 unsigned char *a = va_arg(arg, unsigned char *);
5835 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
5836 else
5837 {
5838 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
5839 if (F.altForm)
5840 {
5841 const mDNSAddr *const ip = (const mDNSAddr *)a;
5842 switch (ip->type)
5843 {
5844 case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
5845 case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
5846 default:
5847 if (ip->type == mDNSAddrType_None)
5848 {
5849 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNSPECIFIED IP ADDRESS>>");
5850 }
5851 else
5852 {
5853 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
5854 "<<ERROR: %%#a used with unsupported type: %d>>", ip->type);
5855 }
5856 F.precision = 0;
5857 break;
5858 }
5859 }
5860 if (!F.altForm || (F.precision != 0))
5861 {
5862 switch (F.precision)
5863 {
5864 case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
5865 a[0], a[1], a[2], a[3]); break;
5866 case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
5867 a[0], a[1], a[2], a[3], a[4], a[5]); break;
5868 case 16: {
5869 // Print IPv6 addresses according to RFC 5952, A Recommendation for IPv6 Address Text
5870 // Representation. See <https://tools.ietf.org/html/rfc5952>.
5871
5872 int idx, runLen = 0, runStart = 0, maxRunLen = 0, maxRunStart = 0, maxRunEnd;
5873
5874 // Find the leftmost longest run of consecutive zero hextets.
5875 for (idx = 0; idx < 8; ++idx)
5876 {
5877 const unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1];
5878 if (hextet == 0)
5879 {
5880 if (runLen++ == 0) runStart = idx;
5881 if (runLen > maxRunLen)
5882 {
5883 maxRunStart = runStart;
5884 maxRunLen = runLen;
5885 }
5886 }
5887 else
5888 {
5889 // If the number of remaining hextets is less than or equal to the length of the longest
5890 // run so far, then we've found the leftmost longest run.
5891 if ((8 - (idx + 1)) <= maxRunLen) break;
5892 runLen = 0;
5893 }
5894 }
5895
5896 // Compress the leftmost longest run of two or more consecutive zero hextets as "::".
5897 // For each reminaing hextet, suppress zeros leading up to the least-significant nibble, which
5898 // is always written, even if it's zero. Because of this requirement, it's easier to write the
5899 // IPv6 address in reverse. Also, write a colon separator before each hextet except for the
5900 // first one.
5901 s = mDNS_VACB_Lim;
5902 maxRunEnd = (maxRunLen >= 2) ? (maxRunStart + maxRunLen - 1) : -1;
5903 for (idx = 7; idx >= 0; --idx)
5904 {
5905 if (idx == maxRunEnd)
5906 {
5907 if (idx == 7) *--s = ':';
5908 idx = maxRunStart;
5909 *--s = ':';
5910 }
5911 else
5912 {
5913 unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1];
5914 do {
5915 *--s = kHexDigitsLowercase[hextet % 16];
5916 hextet /= 16;
5917 } while (hextet);
5918 if (idx > 0) *--s = ':';
5919 }
5920 }
5921 i = (unsigned int)(mDNS_VACB_Lim - s);
5922 }
5923 break;
5924
5925 default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
5926 " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
5927 }
5928 }
5929 }
5930 }
5931 break;
5932
5933 case 'p': F.havePrecision = F.lSize = 1;
5934 F.precision = sizeof(void*) * 2; // 8 characters on 32-bit; 16 characters on 64-bit
5935 fallthrough();
5936 case 'X': digits = kHexDigitsUppercase;
5937 goto hexadecimal;
5938 case 'x': digits = kHexDigitsLowercase;
5939 hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long);
5940 else n = va_arg(arg, unsigned int);
5941 if (F.hSize) n = (unsigned short) n;
5942 if (!F.havePrecision)
5943 {
5944 if (F.zeroPad)
5945 {
5946 F.precision = F.fieldWidth;
5947 if (F.altForm) F.precision -= 2;
5948 }
5949 if (F.precision < 1) F.precision = 1;
5950 }
5951 if (F.precision > mDNS_VACB_Size - 1)
5952 F.precision = mDNS_VACB_Size - 1;
5953 for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
5954 for (; i < F.precision; i++) *--s = '0';
5955 #ifndef FUZZING // Pascal strings aren't supported for fuzzing
5956 if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
5957 #endif
5958 break;
5959
5960 case 'c': *--s = (char)va_arg(arg, int); i = 1; break;
5961
5962 case 's': s = va_arg(arg, char *);
5963 if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
5964 else switch (F.altForm)
5965 {
5966 case 0: i=0;
5967 if (!F.havePrecision) // C string
5968 while (s[i]) i++;
5969 else
5970 {
5971 while ((i < F.precision) && s[i]) i++;
5972 // Make sure we don't truncate in the middle of a UTF-8 character
5973 // If last character we got was any kind of UTF-8 multi-byte character,
5974 // then see if we have to back up.
5975 // This is not as easy as the similar checks below, because
5976 // here we can't assume it's safe to examine the *next* byte, so we
5977 // have to confine ourselves to working only backwards in the string.
5978 j = i; // Record where we got to
5979 // Now, back up until we find first non-continuation-char
5980 while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
5981 // Now s[i-1] is the first non-continuation-char
5982 // and (j-i) is the number of continuation-chars we found
5983 if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char
5984 {
5985 i--; // Tentatively eliminate this start-char as well
5986 // Now (j-i) is the number of characters we're considering eliminating.
5987 // To be legal UTF-8, the start-char must contain (j-i) one-bits,
5988 // followed by a zero bit. If we shift it right by (7-(j-i)) bits
5989 // (with sign extension) then the result has to be 0xFE.
5990 // If this is right, then we reinstate the tentatively eliminated bytes.
5991 if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
5992 }
5993 }
5994 break;
5995 #ifndef FUZZING // Pascal strings aren't supported for fuzzing
5996 case 1: i = (unsigned char) *s++; break; // Pascal string
5997 #endif
5998 case 2: { // DNS label-sequence name
5999 unsigned char *a = (unsigned char *)s;
6000 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
6001 if (*a == 0) *s++ = '.'; // Special case for root DNS name
6002 while (*a)
6003 {
6004 char buf[63*4+1];
6005 if (*a > 63)
6006 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
6007 if (s + *a >= &mDNS_VACB[254])
6008 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
6009 // Need to use ConvertDomainLabelToCString to do proper escaping here,
6010 // so it's clear what's a literal dot and what's a label separator
6011 ConvertDomainLabelToCString((domainlabel*)a, buf);
6012 s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf);
6013 a += 1 + *a;
6014 }
6015 i = (mDNSu32)(s - mDNS_VACB);
6016 s = mDNS_VACB; // Reset s back to the start of the buffer
6017 break;
6018 }
6019 default:
6020 break;
6021 }
6022 // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
6023 if (F.havePrecision && i > F.precision)
6024 { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
6025 break;
6026
6027 case 'H': {
6028 s = va_arg(arg, char *);
6029 hexdump = mDNStrue;
6030 }
6031 break;
6032
6033 #ifndef FUZZING
6034 case 'n':
6035 s = va_arg(arg, char *);
6036 if (F.hSize) *(short *) s = (short)nwritten;
6037 else if (F.lSize) *(long *) s = (long)nwritten;
6038 else *(int *) s = (int)nwritten;
6039 continue;
6040 #endif
6041
6042 default: s = mDNS_VACB;
6043 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", mDNSIsPrintASCII(c) ? c : ' ');
6044 break;
6045
6046 case '%': *sbuffer++ = (char)c;
6047 if (++nwritten >= buflen) goto exit;
6048 break;
6049 }
6050
6051 if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
6052 do {
6053 *sbuffer++ = ' ';
6054 if (++nwritten >= buflen) goto exit;
6055 } while (i < --F.fieldWidth);
6056
6057 if (hexdump)
6058 {
6059 #ifndef FUZZING
6060 char *dst = sbuffer;
6061 const char *const lim = &sbuffer[buflen - nwritten];
6062 if (F.havePrecision)
6063 {
6064 for (i = 0; (i < F.precision) && (dst < lim); i++)
6065 {
6066 const unsigned int b = (unsigned int) *s++;
6067 if (i > 0) *dst++ = ' ';
6068 if (dst < lim) *dst++ = kHexDigitsLowercase[(b >> 4) & 0xF];
6069 if (dst < lim) *dst++ = kHexDigitsLowercase[ b & 0xF];
6070 }
6071 }
6072 i = (unsigned int)(dst - sbuffer);
6073 sbuffer = dst;
6074 #endif
6075 }
6076 else
6077 {
6078 // Make sure we don't truncate in the middle of a UTF-8 character.
6079 // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
6080 // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
6081 // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
6082 // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
6083 if (i > buflen - nwritten)
6084 { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
6085 for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
6086 }
6087 nwritten += i;
6088 if (nwritten >= buflen) goto exit;
6089
6090 for (; i < F.fieldWidth; i++) // Pad on the right
6091 {
6092 *sbuffer++ = ' ';
6093 if (++nwritten >= buflen) goto exit;
6094 }
6095 }
6096 }
6097 exit:
6098 *sbuffer++ = 0;
6099 return(nwritten);
6100 }
6101
mDNS_snprintf(char * sbuffer,mDNSu32 buflen,const char * fmt,...)6102 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
6103 {
6104 mDNSu32 length;
6105
6106 va_list ptr;
6107 va_start(ptr,fmt);
6108 length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
6109 va_end(ptr);
6110
6111 return(length);
6112 }
6113
6114 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
mDNS_GetNextResolverGroupID(void)6115 mDNSexport mDNSu32 mDNS_GetNextResolverGroupID(void)
6116 {
6117 static mDNSu32 lastID = 0;
6118 if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero.
6119 return(lastID);
6120 }
6121 #endif
6122
6123 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
6124
GetReverseIPv6Addr(const domainname * name,mDNSu8 outIPv6[16])6125 mDNSexport mDNSBool GetReverseIPv6Addr(const domainname *name, mDNSu8 outIPv6[16])
6126 {
6127 const mDNSu8 * ptr;
6128 int i;
6129 mDNSu8 ipv6[16];
6130
6131 // If the name is of the form "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa.", where each x
6132 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
6133 // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
6134
6135 ptr = name->c;
6136 for (i = 0; i < 32; i++)
6137 {
6138 unsigned int c, nibble;
6139 const int j = 15 - (i / 2);
6140 if (*ptr++ != 1) return (mDNSfalse); // If this label's length is not 1, then fail.
6141 c = *ptr++; // Get label byte.
6142 if ( (c >= '0') && (c <= '9')) nibble = c - '0'; // If it's a hex digit, get its numeric value.
6143 else if ((c >= 'a') && (c <= 'f')) nibble = (c - 'a') + 10;
6144 else if ((c >= 'A') && (c <= 'F')) nibble = (c - 'A') + 10;
6145 else return (mDNSfalse); // Otherwise, fail.
6146 if ((i % 2) == 0)
6147 {
6148 ipv6[j] = (mDNSu8)nibble;
6149 }
6150 else
6151 {
6152 ipv6[j] |= (mDNSu8)(nibble << 4);
6153 }
6154 }
6155
6156 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
6157
6158 if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse);
6159 if (outIPv6) mDNSPlatformMemCopy(outIPv6, ipv6, 16);
6160 return (mDNStrue);
6161 }
6162 #endif // !STANDALONE
6163