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