]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/uDNS.c
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSCore / uDNS.c
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: uDNS.c,v $
28 Revision 1.54 2004/06/22 02:10:53 ksekar
29 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
30
31 Revision 1.53 2004/06/17 20:49:09 ksekar
32 <rdar://problem/3690436>: Tiger8A148: repeated crash of mDNSResponder while location cycling
33
34 Revision 1.52 2004/06/17 01:13:11 ksekar
35 <rdar://problem/3696616>: polling interval too short
36
37 Revision 1.51 2004/06/10 04:36:44 cheshire
38 Fix compiler warning
39
40 Revision 1.50 2004/06/10 00:55:13 ksekar
41 <rdar://problem/3686213>: crash on network reconnect
42
43 Revision 1.49 2004/06/10 00:10:50 ksekar
44 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
45
46 Revision 1.48 2004/06/09 20:03:37 ksekar
47 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
48
49 Revision 1.47 2004/06/09 03:48:28 ksekar
50 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
51
52 Revision 1.46 2004/06/09 01:44:30 ksekar
53 <rdar://problem/3681378> reworked Cache Record copy code
54
55 Revision 1.45 2004/06/08 18:54:47 ksekar
56 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
57
58 Revision 1.44 2004/06/05 00:33:51 cheshire
59 <rdar://problem/3681029>: Check for incorrect time comparisons
60
61 Revision 1.43 2004/06/05 00:14:44 cheshire
62 Fix signed/unsigned and other compiler warnings
63
64 Revision 1.42 2004/06/04 22:36:16 ksekar
65 Properly set u->nextevent in uDNS_Execute
66
67 Revision 1.41 2004/06/04 08:58:29 ksekar
68 <rdar://problem/3668624>: Keychain integration for secure dynamic update
69
70 Revision 1.40 2004/06/03 03:09:58 ksekar
71 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
72
73 Revision 1.39 2004/06/01 23:46:50 ksekar
74 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
75
76 Revision 1.38 2004/05/31 22:19:44 ksekar
77 <rdar://problem/3258021>: Feature: DNS server->client notification on
78 record changes (#7805) - revert to polling mode on setup errors
79
80 Revision 1.37 2004/05/28 23:42:37 ksekar
81 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
82
83 Revision 1.36 2004/05/18 23:51:25 cheshire
84 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
85
86 Revision 1.35 2004/05/07 23:01:04 ksekar
87 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
88 conditional assignment.
89
90 Revision 1.34 2004/05/05 18:26:12 ksekar
91 Periodically re-transmit questions if the send() fails. Include
92 internal questions in retransmission.
93
94 Revision 1.33 2004/05/05 17:40:06 ksekar
95 Removed prerequisite from deregistration update - it does not work for
96 shared records, and is unnecessary until we have more sophisticated
97 name conflict management.
98
99 Revision 1.32 2004/05/05 17:32:18 ksekar
100 Prevent registration of loopback interface caused by removal of
101 Multicast flag in interface structure.
102
103 Revision 1.31 2004/05/05 17:05:02 ksekar
104 Use LargeCacheRecord structs when pulling records off packets
105
106 Revision 1.30 2004/04/16 21:33:27 ksekar
107 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
108
109 Revision 1.29 2004/04/15 20:03:13 ksekar
110 Clarified log message when pulling bad resource records off packet.
111
112 Revision 1.28 2004/04/15 00:51:28 bradley
113 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
114 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
115
116 Revision 1.27 2004/04/14 23:09:28 ksekar
117 Support for TSIG signed dynamic updates.
118
119 Revision 1.26 2004/04/14 19:36:05 ksekar
120 Fixed memory corruption error in deriveGoodbyes.
121
122 Revision 1.25 2004/04/14 04:07:11 ksekar
123 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
124
125 Revision 1.24 2004/04/08 09:41:40 bradley
126 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
127
128 Revision 1.23 2004/03/24 00:29:45 ksekar
129 Make it safe to call StopQuery in a unicast question callback
130
131 Revision 1.22 2004/03/19 10:11:09 bradley
132 Added AuthRecord * cast from umalloc for C++ builds.
133
134 Revision 1.21 2004/03/15 02:03:45 bradley
135 Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
136 of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
137
138 Revision 1.20 2004/03/13 02:07:26 ksekar
139 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
140
141 Revision 1.19 2004/03/13 01:57:33 ksekar
142 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
143
144 Revision 1.18 2004/02/21 08:34:15 bradley
145 Added casts from void * to specific type for C++ builds. Changed void * l-value cast
146 r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
147
148 Revision 1.17 2004/02/21 02:06:24 cheshire
149 Can't use anonymous unions -- they're non-standard and don't work on all compilers
150
151 Revision 1.16 2004/02/12 01:51:45 cheshire
152 Don't try to send uDNS queries unless we have at least one uDNS server available
153
154 Revision 1.15 2004/02/10 03:02:46 cheshire
155 Fix compiler warning
156
157 Revision 1.14 2004/02/06 23:04:19 ksekar
158 Basic Dynamic Update support via mDNS_Register (dissabled via
159 UNICAST_REGISTRATION #define)
160
161 Revision 1.13 2004/02/03 22:15:01 ksekar
162 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
163
164 Revision 1.12 2004/02/03 19:47:36 ksekar
165 Added an asyncronous state machine mechanism to uDNS.c, including
166 calls to find the parent zone for a domain name. Changes include code
167 in repository previously dissabled via "#if 0 //incomplete". Codepath
168 is currently unused, and will be called to create update records, etc.
169
170 Revision 1.11 2004/01/30 02:12:30 ksekar
171 Changed uDNS_ReceiveMsg() to correctly return void.
172
173 Revision 1.10 2004/01/29 02:59:17 ksekar
174 Unicast DNS: Changed from a resource record oriented question/response
175 matching to packet based matching. New callback architecture allows
176 collections of records in a response to be processed differently
177 depending on the nature of the request, and allows the same structure
178 to be used for internal and client-driven queries with different processing needs.
179
180 Revision 1.9 2004/01/28 20:20:45 ksekar
181 Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
182 demux them. Check-in includes work-in-progress code, #ifdef'd out.
183
184 Revision 1.8 2004/01/28 02:30:07 ksekar
185 Added default Search Domains to unicast browsing, controlled via
186 Networking sharing prefs pane. Stopped sending unicast messages on
187 every interface. Fixed unicast resolving via mach-port API.
188
189 Revision 1.7 2004/01/27 20:15:22 cheshire
190 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
191
192 Revision 1.6 2004/01/24 23:47:17 cheshire
193 Use mDNSOpaque16fromIntVal() instead of shifting and masking
194
195 Revision 1.5 2004/01/24 04:59:15 cheshire
196 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
197
198 Revision 1.4 2004/01/24 04:19:26 cheshire
199 Restore overwritten checkin 1.2
200
201 Revision 1.3 2004/01/23 23:23:15 ksekar
202 Added TCP support for truncated unicast messages.
203
204 Revision 1.2 2004/01/22 03:48:41 cheshire
205 Make sure uDNS client doesn't accidentally use query ID zero
206
207 Revision 1.1 2003/12/13 03:05:27 ksekar
208 <rdar://problem/3192548>: DynDNS: Unicast query of service records
209
210 */
211
212 #include "uDNS.h"
213
214 #if(defined(_MSC_VER))
215 // Disable "assignment within conditional expression".
216 // Other compilers understand the convention that if you place the assignment expression within an extra pair
217 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
218 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
219 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
220 #pragma warning(disable:4706)
221 #endif
222
223 #ifndef NULL
224 #define NULL mDNSNULL
225 #endif // NULL
226
227
228 #define ustrcpy(d,s) mDNSPlatformStrCopy(s,d) // use strcpy(2) param ordering
229 #define ustrlen(s) mDNSPlatformStrLen(s)
230 #define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines
231 #define ufree(x) mDNSPlatformMemFree(x)
232 #define ubzero(x,y) mDNSPlatformMemZero(x,y)
233 #define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering
234
235
236 // Asyncronous operation types
237
238 typedef enum
239 {
240 zoneDataResult
241 // other async. operation names go here
242 } AsyncOpResultType;
243
244 typedef struct
245 {
246 domainname zoneName;
247 mDNSAddr primaryAddr;
248 mDNSu16 zoneClass;
249 mDNSIPPort llqPort;
250 mDNSIPPort updatePort;
251 } zoneData_t;
252
253 // other async. result struct defs go here
254
255 typedef struct
256 {
257 AsyncOpResultType type;
258 zoneData_t zoneData;
259 // other async result structs go here
260 } AsyncOpResult;
261
262 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
263
264
265 // Private Function Prototypes
266 // Note: In general, functions are ordered such that they do not require forward declarations.
267 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
268 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
269 // read top-to-bottom.)
270
271 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m);
272 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
273 AsyncOpCallback callback, void *callbackInfo);
274 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
275 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
276 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
277
278 // ***************************************************************************
279 #if COMPILER_LIKES_PRAGMA_MARK
280 #pragma mark - General Utility Functions
281 #endif
282
283 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
284 {
285 // if NextMessageID is 0 (ininitialized) or 0xffff (reserved for TCP packets) reset to 1
286 if (!u->NextMessageID || u->NextMessageID == (mDNSu16)~0) u->NextMessageID = 1;
287 return mDNSOpaque16fromIntVal(u->NextMessageID++);
288 }
289
290 // unlink an AuthRecord from a linked list
291 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
292 {
293 AuthRecord *rptr, *prev = NULL;
294
295 for (rptr = *list; rptr; rptr = rptr->next)
296 {
297 if (rptr == rr)
298 {
299 if (prev) prev->next = rptr->next;
300 else *list = rptr->next;
301 rptr->next = NULL;
302 return mStatus_NoError;
303 }
304 prev = rptr;
305 }
306 LogMsg("ERROR: unlinkAR - no such active record");
307 return mStatus_UnknownErr;
308 }
309
310 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
311 {
312 if (IsActiveUnicastQuery(q, u))
313 { LogMsg("LinkActiveQuestion - %s (%d) already in list!", q->qname.c, q->qtype); return; }
314
315 q->next = u->ActiveQueries;
316 u->ActiveQueries = q;
317 }
318
319
320 // ***************************************************************************
321 #if COMPILER_LIKES_PRAGMA_MARK
322 #pragma mark - Name Server List Management
323 #endif
324
325 mDNSexport void mDNS_RegisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr)
326 {
327 //!!!KRS do this dynamically!
328 uDNS_GlobalInfo *u = &m->uDNS_info;
329 int i;
330
331 if (!dnsAddr->NotAnInteger)
332 {
333 LogMsg("ERROR: attempt to register DNS with IP address 0");
334 return;
335 }
336
337 for (i = 0; i < 32; i++)
338 {
339 if (!u->Servers[i].ip.v4.NotAnInteger)
340 {
341 u->Servers[i].ip.v4.NotAnInteger = dnsAddr->NotAnInteger;
342 u->Servers[i].type = mDNSAddrType_IPv4;
343 return;
344 }
345 if (u->Servers[i].ip.v4.NotAnInteger == dnsAddr->NotAnInteger)
346 {
347 LogMsg("ERROR: mDNS_RegisterDNS - DNS already registered");
348 return;
349 }
350 }
351 if (i == 32) { LogMsg("ERROR: mDNS_RegisterDNS - too many registered servers"); }
352
353 }
354
355 mDNSexport void mDNS_DeregisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr)
356 {
357 uDNS_GlobalInfo *u = &m->uDNS_info;
358 int i;
359
360 if (!dnsAddr->NotAnInteger)
361 {
362 LogMsg("ERROR: attempt to deregister DNS with IP address 0");
363 return;
364 }
365
366 for (i = 0; i < 32; i++)
367 {
368
369 if (u->Servers[i].ip.v4.NotAnInteger == dnsAddr->NotAnInteger)
370 {
371 u->Servers[i].ip.v4.NotAnInteger = 0;
372 return;
373 }
374 }
375 if (i == 32) { LogMsg("ERROR: mDNS_DeregisterDNS - no such DNS registered"); }
376 }
377
378 mDNSexport void mDNS_DeregisterDNSList(mDNS *const m)
379 {
380 ubzero(m->uDNS_info.Servers, 32 * sizeof(mDNSAddr));
381 }
382
383 mDNSexport mDNSBool mDNS_DNSRegistered(mDNS *const m)
384 {
385 int i;
386
387 for (i = 0; i < 32; i++) if (m->uDNS_info.Servers[i].ip.v4.NotAnInteger) return mDNStrue;
388 return mDNSfalse;
389 }
390
391
392 // ***************************************************************************
393 #if COMPILER_LIKES_PRAGMA_MARK
394 #pragma mark - authorization management
395 #endif
396
397
398 mDNSexport mStatus mDNS_UpdateDomainRequiresAuthentication(mDNS *m, domainname *zone, domainname *key,
399 mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
400 {
401 uDNS_AuthInfo *info;
402 mDNSu8 keybuf[1024];
403 mDNSs32 keylen;
404
405 info = (uDNS_AuthInfo*)umalloc(sizeof(uDNS_AuthInfo) + ssLen);
406 if (!info) { LogMsg("ERROR: umalloc"); return mStatus_NoMemoryErr; }
407 ubzero(info, sizeof(uDNS_AuthInfo));
408 ustrcpy(info->zone.c, zone->c);
409 ustrcpy(info->keyname.c, key->c);
410
411 if (base64)
412 {
413 keylen = DNSDigest_Base64ToBin((const char*)sharedSecret, keybuf, 1024);
414 if (keylen < 0)
415 {
416 LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
417 ufree(info);
418 return mStatus_UnknownErr;
419 }
420 DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
421 }
422 else DNSDigest_ConstructHMACKey(info, sharedSecret, ssLen);
423
424 // link into list
425 // !!!KRS this should be a hashtable since we must check if updates are required on each registration
426 info->next = m->uDNS_info.AuthInfoList;
427 m->uDNS_info.AuthInfoList = info;
428 return mStatus_NoError;
429 }
430
431 mDNSexport void mDNS_ClearAuthenticationList(mDNS *m)
432 {
433 uDNS_AuthInfo *fptr, *ptr = m->uDNS_info.AuthInfoList;
434
435 while (ptr)
436 {
437 fptr = ptr;
438 ptr = ptr->next;
439 ufree(fptr);
440 }
441 m->uDNS_info.AuthInfoList = NULL;
442 }
443
444 mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const domainname *zone)
445 {
446 uDNS_AuthInfo *ptr;
447 domainname *z;
448 mDNSu32 zoneLen, ptrZoneLen;
449
450 zoneLen = ustrlen(zone->c);
451 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
452 {
453 z = &ptr->zone;
454 ptrZoneLen = ustrlen(z->c);
455 if (zoneLen < ptrZoneLen) continue;
456 // return info if zone ends in info->zone
457 if (mDNSPlatformMemSame(z->c, zone->c + (zoneLen - ptrZoneLen), ptrZoneLen)) return ptr;
458 }
459 return NULL;
460 }
461
462
463
464
465 // ***************************************************************************
466 #if COMPILER_LIKES_PRAGMA_MARK
467 #pragma mark - host name and interface management
468 #endif
469
470
471 mDNSlocal void hostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
472 {
473 // note that the rr is already unlinked if result is non-zero
474
475 if (result == mStatus_MemFree) return;
476 if (result == mStatus_NameConflict && rr->resrec.RecordType == kDNSRecordTypeUnique)
477 {
478 // if we get a name conflict, make sure our name/addr isn't already registered by re-registering
479 rr->resrec.RecordType = kDNSRecordTypeKnownUnique;
480 uDNS_RegisterRecord(m, rr);
481 return;
482 }
483
484 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
485 // we've already tried to re-register. reset RecordType before returning RR to client
486 {
487 if (result == mStatus_NoSuchRecord) // name is advertised for some other address
488 result = mStatus_NameConflict;
489 rr->resrec.RecordType = kDNSRecordTypeUnique;
490 }
491
492 if (!result) rr->resrec.RecordType = kDNSRecordTypeVerified;
493 if (result)
494 ((NetworkInterfaceInfo *)(rr->RecordContext))->uDNS_info.registered = mDNSfalse;
495 mDNS_HostNameCallback(m, rr, result);
496 }
497
498
499 mDNSlocal void deadvertiseIfCallback(mDNS *const m, AuthRecord *const rr, mStatus err)
500 {
501 (void)m; // unused
502
503 if (err == mStatus_MemFree) ufree(rr);
504 else LogMsg("deadvertiseIfCallback - error %s for record %s", err, rr->resrec.name.c);
505 }
506
507 mDNSexport void uDNS_DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
508 {
509 AuthRecord *copy;
510 AuthRecord *rr = &set->uDNS_info.RR_A;
511
512 // NOTE: for compatibility w/ mDNS architecture, we make a copy of the address record before sending a
513 // goodbye, since mDNS does not send goodbyes for address records and expects the memory to be immediately
514 // freed
515
516 if (set->uDNS_info.registered)
517 {
518 // copy resource record
519 copy = (AuthRecord*)umalloc(sizeof(AuthRecord)); // allocate storage
520 if (!copy) { LogMsg("ERROR: Malloc"); return; }
521 umemcpy(copy, rr, sizeof(AuthRecord)); // copy all fields
522 copy->resrec.rdata = &copy->rdatastorage; // set rdata pointer
523 if (rr->resrec.rdata != &rr->rdatastorage)
524 { LogMsg("ERROR: uDNS_DeadvertiseInterface - expected local rdata storage. Aborting deregistration"); return; }
525
526 // link copy into list
527 copy->next = m->uDNS_info.RecordRegistrations;
528 m->uDNS_info.RecordRegistrations = copy;
529 copy->RecordCallback = deadvertiseIfCallback;
530
531 // unlink the original
532 unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
533 rr->uDNS_info.state = regState_Unregistered;
534 set->uDNS_info.registered = mDNSfalse;
535 uDNS_DeregisterRecord(m, copy);
536 }
537 else debugf("uDNS_DeadvertiseInterface - interface not registered");
538 return;
539 }
540
541 mDNSexport void uDNS_AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
542 {
543 mDNSu8 *ip = set->ip.ip.v4.b;
544 AuthRecord *a = &set->uDNS_info.RR_A;
545 a->RecordContext = set;
546 if (set->ip.type != mDNSAddrType_IPv4 // non-v4
547 || (ip[0] == 169 && ip[1] == 254) // link-local
548 || (ip[0] == 127 && ip[1] == 0 && ip[2] == 0 && ip[3] == 1)) // loopback
549 return;
550
551 if (set->uDNS_info.registered && SameDomainName(&m->uDNS_info.hostname, &set->uDNS_info.regname))
552 return; // already registered
553
554 if (!m->uDNS_info.hostname.c[0])
555 {
556 // no hostname available
557 set->uDNS_info.registered = mDNSfalse;
558 return;
559 }
560
561 set->uDNS_info.registered = mDNStrue;
562 ustrcpy(set->uDNS_info.regname.c, m->uDNS_info.hostname.c);
563 //!!!KRS temp ttl 1
564 mDNS_SetupResourceRecord(a, mDNSNULL, 0, kDNSType_A, 1, kDNSRecordTypeShared /*Unique*/, hostnameCallback, set); //!!!KRS
565
566 ustrcpy(a->resrec.name.c, m->uDNS_info.hostname.c);
567 a->resrec.rdata->u.ip = set->ip.ip.v4;
568 LogMsg("uDNS_AdvertiseInterface: advertising %s", m->uDNS_info.hostname.c);
569
570 uDNS_RegisterRecord(m, a);
571 }
572
573
574 // ***************************************************************************
575 #if COMPILER_LIKES_PRAGMA_MARK
576 #pragma mark - Incoming Message Processing
577 #endif
578
579 mDNSlocal mDNSBool sameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
580 {
581 return (r1->namehash == r2->namehash &&
582 r1->rrtype == r2->rrtype &&
583 SameDomainName(&r1->name, &r2->name) &&
584 SameRData(r1, r2));
585 }
586
587 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
588 {
589 CacheRecord *ptr;
590
591 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
592 if (sameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
593
594 return mDNSfalse;
595 }
596
597
598 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
599 {
600 CacheRecord *ptr, *prev = NULL;
601
602 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
603 {
604 if (sameResourceRecord(&ptr->resrec, &rr->resrec))
605 {
606 if (prev) prev->next = ptr->next;
607 else question->uDNS_info.knownAnswers = ptr->next;
608 ufree(ptr);
609 return;
610 }
611 prev = ptr;
612 }
613 LogMsg("removeKnownAnswer() called for record not in KA list");
614 }
615
616
617 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
618 {
619 CacheRecord *newCR = NULL;
620 mDNSu32 size;
621
622 size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
623 newCR = (CacheRecord *)umalloc(size);
624 if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
625 umemcpy(newCR, rr, size);
626 newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
627 newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
628 newCR->next = question->uDNS_info.knownAnswers;
629 question->uDNS_info.knownAnswers = newCR;
630 }
631
632 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question)
633 {
634 const mDNSu8 *ptr;
635 int i;
636 CacheRecord *fptr, *ka, *cr, *answers = NULL, *prev = NULL;
637 LargeCacheRecord *lcr;
638
639 if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
640
641 ptr = LocateAnswers(msg, end);
642 if (!ptr) goto pkt_error;
643
644 if (!msg->h.numAnswers)
645 {
646 // delete the whole KA list
647 ka = question->uDNS_info.knownAnswers;
648 while (ka)
649 {
650 debugf("deriving goodbye for %s", ka->resrec.name.c);
651 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
652 if (question != m->uDNS_info.CurrentQuery)
653 {
654 debugf("deriveGoodbyes - question removed via callback. returning.");
655 return;
656 }
657 fptr = ka;
658 ka = ka->next;
659 ufree(fptr);
660 }
661 question->uDNS_info.knownAnswers = NULL;
662 return;
663 }
664
665 // make a list of all the new answers
666 for (i = 0; i < msg->h.numAnswers; i++)
667 {
668 lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
669 if (!lcr) goto malloc_error;
670 ubzero(lcr, sizeof(LargeCacheRecord));
671 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
672 if (!ptr) goto pkt_error;
673 cr = &lcr->r;
674 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
675 {
676 cr->next = answers;
677 answers = cr;
678 }
679 else ufree(cr);
680 }
681
682 // make sure every known answer is in the answer list
683 ka = question->uDNS_info.knownAnswers;
684 while (ka)
685 {
686 for (cr = answers; cr; cr = cr->next)
687 { if (sameResourceRecord(&ka->resrec, &cr->resrec)) break; }
688 if (!cr)
689 {
690 // record is in KA list but not answer list - remove from KA list
691 if (prev) prev->next = ka->next;
692 else question->uDNS_info.knownAnswers = ka->next;
693 debugf("deriving goodbye for %s", ka->resrec.name.c);
694 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
695 if (question != m->uDNS_info.CurrentQuery)
696 {
697 debugf("deriveGoodbyes - question removed via callback. returning.");
698 return;
699 }
700 fptr = ka;
701 ka = ka->next;
702 ufree(fptr);
703 }
704 else
705 {
706 prev = ka;
707 ka = ka->next;
708 }
709 }
710
711 // free temp answers list
712 cr = answers;
713 while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
714
715 return;
716
717 pkt_error:
718 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %s (%d)",
719 question->qname.c, question->qtype);
720 return;
721
722 malloc_error:
723 LogMsg("ERROR: Malloc");
724 }
725
726 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
727 {
728 const mDNSu8 *ptr;
729 int i;
730 LargeCacheRecord lcr;
731 CacheRecord *cr = &lcr.r;
732 mDNSBool goodbye, inKAList;
733 LLQ_Info *llqInfo = question->uDNS_info.llq;
734
735 if (question != m->uDNS_info.CurrentQuery)
736 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
737
738 ptr = LocateAnswers(msg, end);
739 if (!ptr) goto pkt_error;
740
741 for (i = 0; i < msg->h.numAnswers; i++)
742 {
743 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
744 if (!ptr) goto pkt_error;
745 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
746 {
747 goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
748 inKAList = kaListContainsAnswer(question, cr);
749
750 if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue; // list up to date
751 if (!inKAList) addKnownAnswer(question, cr);
752 if (goodbye) removeKnownAnswer(question, cr);
753 question->QuestionCallback(m, question, &cr->resrec, !goodbye);
754 if (question != m->uDNS_info.CurrentQuery)
755 {
756 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
757 return;
758 }
759 }
760 else
761 {
762 LogMsg("unexpected answer: %s", cr->resrec.name.c);
763 }
764 }
765 if (llq && (llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume))
766 { deriveGoodbyes(m, msg, end,question); llqInfo->deriveRemovesOnResume = mDNSfalse; }
767 //!!!KRS should we derive goodbyes for non-LLQs?
768
769 return;
770
771 pkt_error:
772 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %s (%d)",
773 question->qname.c, question->qtype);
774 return;
775 }
776
777 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
778 {
779 (void)context; // unused
780 pktResponseHndlr(m, msg, end, question, mDNSfalse);
781 }
782
783 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
784 {
785 (void)context; // unused
786 pktResponseHndlr(m, msg, end, question, mDNStrue);
787 }
788
789
790
791 mDNSlocal void unlinkSRS(uDNS_GlobalInfo *u, ServiceRecordSet *srs)
792 {
793 ServiceRecordSet *ptr, *prev = NULL;
794
795 for (ptr = u->ServiceRegistrations; ptr; ptr = ptr->next)
796 {
797 if (ptr == srs)
798 {
799 if (prev) prev->next = ptr->next;
800 else u->ServiceRegistrations = ptr->next;
801 ptr->next = NULL;
802 return;
803 }
804 prev = ptr;
805 }
806 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
807 }
808
809
810 mDNSlocal mStatus checkUpdateResult(domainname *name, mDNSu8 rcode, const DNSMessage *msg)
811 {
812 (void)msg; // currently unused, needed for TSIG errors
813 if (!rcode) return mStatus_NoError;
814 else if (rcode == kDNSFlag1_RC_YXDomain)
815 {
816 LogMsg("Name in use: %s", name->c);
817 return mStatus_NameConflict;
818 }
819 else if (rcode == kDNSFlag1_RC_Refused)
820 {
821 LogMsg("Update %s refused", name->c);
822 return mStatus_Refused;
823 }
824 else if (rcode == kDNSFlag1_RC_NXRRSet)
825 {
826 LogMsg("Reregister refusted (NXRRSET): %s", name->c);
827 return mStatus_NoSuchRecord;
828 }
829 else if (rcode == kDNSFlag1_RC_NotAuth)
830 {
831 LogMsg("Permission denied (NOAUTH): %s", name->c);
832 return mStatus_NoAuth;
833 }
834 else if (rcode == kDNSFlag1_RC_FmtErr)
835 {
836 LogMsg("Format Error: %s", name->c);
837 return mStatus_UnknownErr;
838 //!!!KRS need to parse message for TSIG errors
839 }
840 else
841 {
842 LogMsg("Update %s failed with rcode %d", name->c, rcode);
843 return mStatus_UnknownErr;
844 }
845 }
846
847 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err)
848 {
849 //!!!KRS make sure we're doing the right thing w/ MemFree
850
851 switch (srs->uDNS_info.state)
852 {
853 case regState_Pending:
854 case regState_Refresh:
855 if (err)
856 {
857 if (srs->uDNS_info.lease && err == mStatus_UnknownErr)
858 {
859 LogMsg("Re-trying update of service %s without lease option", srs->RR_SRV.resrec.name.c);
860 srs->uDNS_info.lease = mDNSfalse;
861 srs->uDNS_info.expire = -1;
862 SendServiceRegistration(m, srs);
863 return;
864 }
865 else
866 {
867 LogMsg("hndlServiceUpdateReply: Error %d returned for registration of %s",
868 err, srs->RR_SRV.resrec.name.c);
869 srs->uDNS_info.state = regState_Unregistered;
870 break;
871 }
872 }
873 else
874 {
875 if (srs->uDNS_info.state == regState_Refresh)
876 {
877 srs->uDNS_info.state = regState_Registered;
878 return;
879 }
880 srs->uDNS_info.state = regState_Registered;
881 break;
882 }
883 case regState_DeregPending:
884 if (err) LogMsg("hndlServiceUpdateReply: Error %d returned for dereg of %s",
885 err, srs->RR_SRV.resrec.name.c);
886 else err = mStatus_MemFree;
887 break;
888 case regState_DeregDeferred:
889 if (err) LogMsg("hndlServiceUpdateReply: Error %d received prior to deferred derigstration of %s",
890 err, srs->RR_SRV.resrec.name.c);
891 LogMsg("Performing deferred deregistration of %s", srs->RR_SRV.resrec.name.c);
892 uDNS_DeregisterService(m, srs);
893 return;
894 case regState_TargetChange:
895 if (err)
896 {
897 LogMsg("hdnlServiceUpdateReply: Error %d returned for host target update of %s",
898 err, srs->RR_SRV.resrec.name.c);
899 srs->uDNS_info.state = regState_Unregistered;
900 // !!!KRS we are leaving the ptr/txt records registered
901 }
902 else srs->uDNS_info.state = regState_Registered;
903 break;
904 default:
905 LogMsg("hndlServiceUpdateReply called for service %s in unexpected state %d with error %d. Unlinking.",
906 srs->RR_SRV.resrec.name.c, srs->uDNS_info.state, err);
907 err = mStatus_UnknownErr;
908 }
909
910 if (err)
911 {
912 unlinkSRS(&m->uDNS_info, srs); // name conflicts, force dereg, and errors
913 srs->uDNS_info.state = regState_Unregistered;
914 }
915
916 srs->ServiceCallback(m, srs, err);
917 // NOTE: do not touch structures after calling ServiceCallback
918 }
919
920 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
921 {
922 uDNS_GlobalInfo *u = &m->uDNS_info;
923
924 if (rr->uDNS_info.state == regState_DeregPending)
925 {
926 debugf("Received reply for deregister record %s type %d", rr->resrec.name.c, rr->resrec.rrtype);
927 if (err) LogMsg("ERROR: Deregistration of record %s type %s failed with error %d",
928 rr->resrec.name.c, rr->resrec.rrtype, err);
929 else err = mStatus_MemFree;
930 if (unlinkAR(&m->uDNS_info.RecordRegistrations, rr))
931 LogMsg("ERROR: Could not unlink resource record following deregistration");
932 rr->uDNS_info.state = regState_Unregistered;
933 rr->RecordCallback(m, rr, err);
934 return;
935 }
936
937 if (rr->uDNS_info.state == regState_DeregDeferred)
938 {
939 if (err)
940 {
941 LogMsg("Cancelling deferred deregistration record %s type %d due to registration error %d",
942 rr->resrec.name.c, rr->resrec.rrtype, err);
943 unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
944 rr->uDNS_info.state = regState_Unregistered;
945 return;
946 }
947 LogMsg("Calling deferred deregistration of record %s type %d",
948 rr->resrec.name.c, rr->resrec.rrtype);
949 rr->uDNS_info.state = regState_Registered;
950 uDNS_DeregisterRecord(m, rr);
951 return;
952 }
953
954 if (rr->uDNS_info.state == regState_Pending || rr->uDNS_info.state == regState_Refresh)
955 {
956 if (err)
957 {
958 if (rr->uDNS_info.lease && err == mStatus_UnknownErr)
959 {
960 LogMsg("Re-trying update of record %s without lease option", rr->resrec.name.c);
961 rr->uDNS_info.lease = mDNSfalse;
962 rr->uDNS_info.expire = -1;
963 sendRecordRegistration(m, rr);
964 return;
965 }
966
967 LogMsg("Registration of record %s type %d failed with error %d",
968 rr->resrec.name.c, rr->resrec.rrtype, err);
969 unlinkAR(&u->RecordRegistrations, rr);
970 rr->uDNS_info.state = regState_Unregistered;
971 }
972 else
973 {
974 if (rr->uDNS_info.state == regState_Refresh)
975 rr->uDNS_info.state = regState_Registered;
976 else
977 {
978 rr->uDNS_info.state = regState_Registered;
979 rr->RecordCallback(m, rr, err);
980 }
981 return;
982 }
983 }
984
985 LogMsg("Received unexpected response for record %s type %d, in state %d, with response error %d",
986 rr->resrec.name.c, rr->resrec.rrtype, rr->uDNS_info.state, err);
987 }
988
989
990 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
991 {
992 LargeCacheRecord lcr;
993 const mDNSu8 *ptr;
994 int i;
995 mDNSu32 lease = 0;
996
997 ptr = LocateAdditionals(msg, end);
998
999 if (info->lease && (ptr = LocateAdditionals(msg, end)))
1000 {
1001 for (i = 0; i < msg->h.numAdditionals; i++)
1002 {
1003 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
1004 if (!ptr) break;
1005 if (lcr.r.resrec.rrtype == kDNSType_OPT)
1006 {
1007 if (lcr.r.resrec.rdlength < LEASE_OPT_SIZE) continue;
1008 if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
1009 lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
1010 break;
1011 }
1012 }
1013 }
1014
1015 if (lease > 0)
1016 info->expire = (mDNSPlatformTimeNow() + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
1017 else info->expire = -1;
1018 }
1019
1020 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
1021 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
1022 const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
1023 {
1024 DNSQuestion *qptr;
1025 AuthRecord *rptr;
1026 ServiceRecordSet *sptr;
1027 mStatus err = mStatus_NoError;
1028 uDNS_GlobalInfo *u = &m->uDNS_info;
1029
1030 mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
1031 mDNSu8 UpdateR = kDNSFlag0_OP_Update | kDNSFlag0_QR_Response;
1032 mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
1033 mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
1034
1035 // unused
1036 (void)srcaddr;
1037 (void)srcport;
1038 (void)dstaddr;
1039 (void)dstport;
1040 (void)ttl;
1041 (void)InterfaceID;
1042
1043 if (QR_OP == StdR)
1044 {
1045 // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
1046 if (recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
1047
1048 for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
1049 {
1050 //!!!KRS we should have a hashtable, hashed on message id
1051 if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
1052 {
1053 if (msg->h.flags.b[0] & kDNSFlag0_TC)
1054 { hndlTruncatedAnswer(qptr, srcaddr, m); return; }
1055 else
1056 {
1057 u->CurrentQuery = qptr;
1058 qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
1059 u->CurrentQuery = NULL;
1060 // Note: responseCallback can invalidate qptr
1061 return;
1062 }
1063 }
1064 }
1065 }
1066 if (QR_OP == UpdateR)
1067 {
1068 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
1069 {
1070 if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
1071 {
1072 err = checkUpdateResult(&sptr->RR_SRV.resrec.name, rcode, msg);
1073 if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
1074 hndlServiceUpdateReply(m, sptr, err);
1075 return;
1076 }
1077 }
1078 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
1079 {
1080 if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
1081 {
1082 err = checkUpdateResult(&rptr->resrec.name, rcode, msg);
1083 if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
1084 hndlRecordUpdateReply(m, rptr, err);
1085 return;
1086 }
1087 }
1088 }
1089 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
1090 }
1091
1092
1093 mDNSlocal void receiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
1094 const mDNSInterfaceID InterfaceID)
1095 {
1096 mDNSAddr *sa = NULL, *da = NULL;
1097 mDNSIPPort sp, dp;
1098 mDNSu8 ttl = 0;
1099
1100 sp.NotAnInteger = 0;
1101 dp.NotAnInteger = 0;
1102 uDNS_ReceiveMsg(m, msg, end, sa, sp, da, dp, InterfaceID, ttl);
1103 }
1104
1105 //!!!KRS this should go away (don't just pick one randomly!)
1106 mDNSlocal const mDNSAddr *getInitializedDNS(uDNS_GlobalInfo *u)
1107 {
1108 int i;
1109 for (i = 0; i < 32; i++)
1110 if (u->Servers[i].ip.v4.NotAnInteger) return &u->Servers[i];
1111
1112 return NULL;
1113 }
1114
1115 // ***************************************************************************
1116 #if COMPILER_LIKES_PRAGMA_MARK
1117 #pragma mark - Query Routines
1118 #endif
1119
1120 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
1121
1122 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
1123 {
1124 mDNSOpaque16 flags = QueryFlags;
1125
1126 ubzero(msg, sizeof(msg));
1127 flags.b[0] |= kDNSFlag0_RD; // recursion desired
1128 InitializeDNSMessage(&msg->h, question->uDNS_info.id, flags);
1129 }
1130
1131 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
1132 {
1133 initializeQuery(msg, question);
1134
1135 *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
1136 if (!*endPtr)
1137 {
1138 LogMsg("ERROR: Unicast query out of space in packet");
1139 return mStatus_UnknownErr;
1140 }
1141 return mStatus_NoError;
1142 }
1143
1144 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
1145 {
1146 AuthRecord rr;
1147 ResourceRecord *opt = &rr.resrec;
1148 rdataOpt *optRD;
1149
1150 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1151 if (includeQuestion)
1152 {
1153 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
1154 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return NULL; }
1155 }
1156 // locate OptRR if it exists, set pointer to end
1157 // !!!KRS implement me
1158
1159
1160 // format opt rr (fields not specified are zero-valued)
1161 ubzero(&rr, sizeof(AuthRecord));
1162 opt->rdata = &rr.rdatastorage;
1163
1164 opt->RecordType = kDNSRecordTypeKnownUnique; // to avoid warnings in other layers
1165 opt->rrtype = kDNSType_OPT;
1166 opt->rdlength = LLQ_OPT_SIZE;
1167 opt->rdestimate = LLQ_OPT_SIZE;
1168
1169 optRD = &rr.resrec.rdata->u.opt;
1170 optRD->opt = kDNSOpt_LLQ;
1171 optRD->optlen = sizeof(LLQOptData);
1172 umemcpy(&optRD->OptData.llq, data, sizeof(LLQOptData));
1173 ptr = PutResourceRecordTTL(msg, ptr, &msg->h.numAdditionals, opt, 0);
1174 if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTL"); return NULL; }
1175
1176 return ptr;
1177 }
1178
1179
1180 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
1181 {
1182 LargeCacheRecord lcr;
1183 int i;
1184 const mDNSu8 *ptr;
1185
1186 ptr = LocateAdditionals(msg, end);
1187 if (!ptr) return mDNSfalse;
1188
1189 // find the last additional
1190 for (i = 0; i < msg->h.numAdditionals; i++)
1191 // { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
1192 //!!!KRS workaround for LH server bug, which puts OPT as first additional
1193 { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
1194 if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
1195 if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_SIZE) return mDNSfalse; // rdata too small
1196 umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(LLQOptData)), sizeof(LLQOptData));
1197 return mDNStrue;
1198 }
1199
1200 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
1201 {
1202 LLQ_Info *qInfo;
1203 LLQOptData pktData;
1204
1205 qInfo = q->uDNS_info.llq;
1206 if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
1207 if (pktData.llqOp != kLLQ_Refresh) return;
1208 if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; }
1209 if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
1210
1211 qInfo->expire = mDNSPlatformTimeNow() + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
1212 qInfo->retry = qInfo->expire + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond * 3/4);
1213
1214 qInfo->origLease = pktData.lease;
1215 qInfo->state = LLQ_Established;
1216 }
1217
1218 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
1219 {
1220 DNSMessage msg;
1221 mDNSu8 *end;
1222 LLQOptData llq;
1223 LLQ_Info *info = q->uDNS_info.llq;
1224 mStatus err;
1225
1226 if (info->state == kLLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES)
1227 {
1228 LogMsg("sendLLQRefresh - %d failed attempts for llq %s", info->ntries, q->qname.c);
1229 info->state = LLQ_Retry;
1230 info->retry = mDNSPlatformTimeNow() + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
1231 info->deriveRemovesOnResume = mDNStrue;
1232 return;
1233 //!!!KRS handle this - periodically try to re-establish
1234 }
1235
1236 llq.vers = kLLQ_Vers;
1237 llq.llqOp = kLLQ_Refresh;
1238 llq.err = LLQErr_NoError;
1239 umemcpy(llq.id, info->id, 8);
1240 llq.lease = lease;
1241
1242 initializeQuery(&msg, q);
1243 end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
1244 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
1245
1246 err = mDNSSendDNSMessage(m, &msg, end, q->InterfaceID, &info->servAddr, info->servPort);
1247 if (err) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %d", err);
1248
1249 if (info->state == LLQ_Established) info->ntries = 1;
1250 else info->ntries++;
1251 info->state = LLQ_Refresh;
1252 q->LastQTime = mDNSPlatformTimeNow();
1253 info->retry = (info->expire - q->LastQTime) / 2;
1254 }
1255
1256 mDNSlocal void recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
1257 {
1258 DNSMessage ack;
1259 mDNSu8 *ackEnd = ack.data;
1260 mStatus err;
1261
1262 // invoke response handler
1263 m->uDNS_info.CurrentQuery = q;
1264 q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
1265 if (m->uDNS_info.CurrentQuery != q) return;
1266
1267 // format and send ack
1268 InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
1269 ackEnd = putQuestion(&ack, ack.data, ack.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
1270 if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putQuestion"); return; }
1271 err = mDNSSendDNSMessage(m, &ack, ackEnd, InterfaceID, srcaddr, srcport);
1272 if (err) LogMsg("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %d", err);
1273 }
1274
1275
1276
1277 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
1278 {
1279 LLQ_Info *info = q->uDNS_info.llq;
1280
1281 if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
1282 if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
1283 info->expire = mDNSPlatformTimeNow() + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
1284 info->retry = info->expire + ((mDNSs32)llq->lease * mDNSPlatformOneSecond * 3/4);
1285
1286 info->origLease = llq->lease;
1287 info->state = LLQ_Established;
1288 q->uDNS_info.responseCallback = llqResponseHndlr;
1289 llqResponseHndlr(m, pktMsg, end, q, NULL);
1290 return;
1291
1292 error:
1293 info->state = LLQ_Error;
1294 }
1295
1296 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
1297 {
1298 LLQ_Info *info = q->uDNS_info.llq;
1299 DNSMessage response;
1300 mDNSu8 *responsePtr = response.data;
1301 mStatus err;
1302 LLQOptData llqBuf;
1303 mDNSs32 timenow = mDNSPlatformTimeNow();
1304
1305 if (info->ntries++ == kLLQ_MAX_TRIES)
1306 {
1307 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %s. Will re-try in %d minutes",
1308 kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
1309 info->state = LLQ_Retry;
1310 info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
1311 // !!!KRS give a callback error in these cases?
1312 return;
1313 }
1314
1315
1316 if (!llq)
1317 {
1318 llq = &llqBuf;
1319 llq->vers = kLLQ_Vers;
1320 llq->llqOp = kLLQ_Setup;
1321 llq->err = LLQErr_NoError;
1322 umemcpy(llq->id, info->id, 8);
1323 llq->lease = info->origLease;
1324 }
1325
1326 q->LastQTime = timenow;
1327 info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
1328
1329 if (constructQueryMsg(&response, &responsePtr, q)) goto error;
1330 responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
1331 if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
1332
1333 err = mDNSSendDNSMessage(m, &response, responsePtr, q->InterfaceID, &info->servAddr, info->servPort);
1334 if (err) LogMsg("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %d", err);
1335 // on error, we procede as normal and retry after the appropriate interval
1336
1337 return;
1338
1339 error:
1340 info->state = LLQ_Error;
1341 }
1342
1343
1344
1345 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
1346 {
1347 LLQ_Info *info = q->uDNS_info.llq;
1348 mDNSs32 timenow = mDNSPlatformTimeNow();
1349 switch(llq->err)
1350 {
1351 case LLQErr_NoError: break;
1352 case LLQErr_ServFull:
1353 LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %s. Retry in %d sec", q->qname.c, llq->lease);
1354 info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
1355 info->state = LLQ_Retry;
1356 simpleResponseHndlr(m, pktMsg, end, q, NULL); // get available answers
1357 info->deriveRemovesOnResume = mDNStrue;
1358 case LLQErr_Static:
1359 info->state = LLQ_Static;
1360 LogMsg("LLQ %s: static", q->qname.c);
1361 simpleResponseHndlr(m, pktMsg, end, q, NULL);
1362 return;
1363 case LLQErr_FormErr:
1364 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %s", q->qname.c);
1365 goto error;
1366 case LLQErr_BadVers:
1367 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
1368 goto error;
1369 case LLQErr_UnknownErr:
1370 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %s", q->qname.c);
1371 goto error;
1372 default:
1373 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %s", llq->err, q->qname.c);
1374 goto error;
1375 }
1376
1377 if (info->origLease != llq->lease)
1378 LogMsg("hndlRequestChallenge: requested lease %d, granted lease %d", info->origLease, llq->lease);
1379
1380 // cache expiration in case we go to sleep before finishing setup
1381 info->origLease = llq->lease;
1382 info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
1383
1384 // update state and timestamp
1385 info->state = LLQ_SecondaryRequest;
1386 umemcpy(info->id, llq->id, 8);
1387 info->ntries = 0; // first attempt to send response
1388
1389 sendChallengeResponse(m, q, llq);
1390 return;
1391
1392
1393 error:
1394 info->state = LLQ_Error;
1395 }
1396
1397
1398 // response handler for initial and secondary setup responses
1399 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
1400 {
1401 DNSQuestion pktQuestion;
1402 LLQOptData llq;
1403 const mDNSu8 *ptr = pktMsg->data;
1404 LLQ_Info *info = q->uDNS_info.llq;
1405 mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
1406
1407 (void)clientContext; // unused
1408
1409 if (rcode && rcode != kDNSFlag1_RC_NXDomain)
1410 {
1411 LogMsg("LLQ Setup for %s failed with rcode %d. Reverting to polling mode", q->qname.c, rcode);
1412 info->state = LLQ_Poll;
1413 q->uDNS_info.responseCallback = simpleResponseHndlr;
1414 q->LastQTime = mDNSPlatformTimeNow();
1415 q->ThisQInterval = 1;
1416 return;
1417 }
1418
1419 ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
1420 if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto error; }
1421 if (!SameDomainName(&q->qname, &pktQuestion.qname))
1422 { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %s", q->qname.c); goto error; }
1423
1424 if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { LogMsg("ERROR: recvSetupResponse - GetLLQAtIndex"); goto error; }
1425 if (llq.llqOp != kLLQ_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto error; }
1426 if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers); goto error; }
1427
1428 if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
1429 if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
1430 LogMsg("recvSetupResponse - bad state %d", info->state);
1431
1432
1433 error:
1434 info->state = LLQ_Error;
1435 }
1436
1437
1438
1439 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info)
1440 {
1441 DNSMessage msg;
1442 mDNSu8 *end;
1443 LLQOptData llqData;
1444 DNSQuestion *q = info->question;
1445 mStatus err;
1446 mDNSs32 timenow = mDNSPlatformTimeNow();
1447
1448 if (info->ntries++ == kLLQ_MAX_TRIES)
1449 {
1450 LogMsg("startLLQHandshake: %d failed attempts for LLQ %s. Will re-try in %d minutes",
1451 kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
1452 info->state = LLQ_Retry;
1453 info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
1454 // !!!KRS give a callback error in these cases?
1455 return;
1456 }
1457
1458 // set llq rdata
1459 llqData.vers = kLLQ_Vers;
1460 llqData.llqOp = kLLQ_Setup;
1461 llqData.err = LLQErr_NoError;
1462 ubzero(llqData.id, 8);
1463 llqData.lease = kLLQ_DefLease;
1464
1465 initializeQuery(&msg, q);
1466 end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
1467 if (!end)
1468 {
1469 LogMsg("ERROR: startLLQHandshake - putLLQ");
1470 info->state = LLQ_Error;
1471 return;
1472 }
1473
1474 err = mDNSSendDNSMessage(m, &msg, end, q->InterfaceID, &info->servAddr, info->servPort);
1475 if (err) LogMsg("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %d", err);
1476 // on error, we procede as normal and retry after the appropriate interval
1477
1478 // update question/info state
1479 info->state = LLQ_InitialRequest;
1480 info->origLease = kLLQ_DefLease;
1481 info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
1482 q->LastQTime = timenow;
1483 q->uDNS_info.responseCallback = recvSetupResponse;
1484 q->uDNS_info.internal = mDNStrue;
1485 }
1486
1487 // wrapper for startLLQHandshake, invoked by async op callback
1488 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
1489 {
1490 LLQ_Info *info = (LLQ_Info *)llqInfo;
1491 const zoneData_t *zoneInfo = &result->zoneData;
1492
1493 if (err)
1494 {
1495 LogMsg("ERROR: startLLQHandshakeCallback invoked with error code %d", err);
1496 info->state = LLQ_Poll;
1497 info->question->LastQTime = 0; // trigger immediate poll
1498 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1499 return;
1500 }
1501
1502 if (info->state == LLQ_Cancelled)
1503 {
1504 // StopQuery was called while we were getting the zone info
1505 LogMsg("startLLQHandshake - LLQ Cancelled.");
1506 info->question = NULL; // question may be deallocated
1507 ufree(info);
1508 return;
1509 }
1510
1511 if (info->state != LLQ_GetZoneInfo)
1512 {
1513 LogMsg("ERROR: startLLQHandshake - bad state %d", info->state);
1514 return;
1515 }
1516
1517 // cache necessary zone data
1518 info->servAddr.type = zoneInfo->primaryAddr.type;
1519 info->servAddr.ip.v4.NotAnInteger = zoneInfo->primaryAddr.ip.v4.NotAnInteger;
1520 info->servPort.NotAnInteger = zoneInfo->llqPort.NotAnInteger;
1521 info->ntries = 0;
1522 startLLQHandshake(m, info);
1523 }
1524
1525 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
1526 {
1527 LLQ_Info *info;
1528 mStatus err = mStatus_NoError;
1529
1530 // allocate / init info struct
1531 info = umalloc(sizeof(LLQ_Info));
1532 if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
1533 ubzero(info, sizeof(LLQ_Info));
1534 info->state = LLQ_GetZoneInfo;
1535
1536 // link info/question
1537 info->question = question;
1538 question->uDNS_info.llq = info;
1539
1540 question->uDNS_info.responseCallback = llqResponseHndlr;
1541
1542 err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
1543 if (err)
1544 {
1545 LogMsg("ERROR: startLLQ - startGetZoneData returned %d", err);
1546 info->question = NULL;
1547 ufree(info);
1548 question->uDNS_info.llq = NULL;
1549 return err;
1550 }
1551
1552 LinkActiveQuestion(&m->uDNS_info, question);
1553 return err;
1554 }
1555
1556 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
1557 {
1558 DNSQuestion pktQ, *q;
1559 uDNS_GlobalInfo *u = &m->uDNS_info;
1560 const mDNSu8 *ptr = msg->data;
1561 LLQ_Info *llqInfo;
1562
1563 if (!msg->h.numQuestions) return mDNSfalse;
1564
1565 ptr = getQuestion(msg, ptr, end, 0, &pktQ);
1566 if (!ptr) return mDNSfalse;
1567 pktQ.uDNS_info.id = msg->h.id;
1568
1569 // !!!KRS we should do a table lookup to quickly determine if this packet is for an LLQ
1570
1571 q = u->ActiveQueries;
1572 while (q)
1573 {
1574 llqInfo = q->uDNS_info.llq;
1575 if (q->LongLived &&
1576 llqInfo &&
1577 q->qnamehash == pktQ.qnamehash &&
1578 q->qtype == pktQ.qtype &&
1579 SameDomainName(&q->qname, &pktQ.qname))
1580 {
1581 u->CurrentQuery = q;
1582 if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
1583 { recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID); return mDNStrue; }
1584 else if (msg->h.id.NotAnInteger != q->uDNS_info.id.NotAnInteger)
1585 { q = q->next; continue; }
1586 else if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
1587 { recvRefreshReply(m, msg, end, q); return mDNStrue; }
1588 else if (llqInfo->state < LLQ_Static)
1589 { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
1590 }
1591 q = q->next;
1592 }
1593 return mDNSfalse;
1594 }
1595
1596 mDNSexport mDNSBool IsActiveUnicastQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
1597 {
1598 DNSQuestion *q;
1599
1600 for (q = u->ActiveQueries; q; q = q->next)
1601 {
1602 if (q == question)
1603 {
1604 if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID || IsLocalDomain(&question->qname))
1605 LogMsg("Warning: Question %s in Active Unicast Query list with id %d, interfaceID %x",
1606 question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
1607 return mDNStrue;
1608 }
1609 }
1610 return mDNSfalse;
1611 }
1612
1613 // stopLLQ happens IN ADDITION to stopQuery
1614 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
1615 {
1616 LLQ_Info *info = question->uDNS_info.llq;
1617 (void)m; // unused
1618
1619 if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
1620 if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
1621
1622 switch (info->state)
1623 {
1624 case LLQ_UnInit:
1625 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
1626 //!!!KRS should we unlink info<->question here?
1627 return;
1628 case LLQ_GetZoneInfo:
1629 info->question = NULL; // remove ref to question, as it may be freed when we get called back from async op
1630 info->state = LLQ_Cancelled;
1631 return;
1632 case LLQ_Established:
1633 case LLQ_Refresh:
1634 // refresh w/ lease 0
1635 sendLLQRefresh(m, question, 0);
1636 goto free_info;
1637 default:
1638 debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
1639 goto free_info;
1640 }
1641
1642 free_info:
1643 info->question = NULL;
1644 ufree(info);
1645 question->uDNS_info.llq = NULL;
1646
1647 }
1648
1649 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
1650 {
1651 uDNS_GlobalInfo *u = &m->uDNS_info;
1652 DNSQuestion *qptr, *prev = NULL;
1653 CacheRecord *ka;
1654
1655 qptr = u->ActiveQueries;
1656 while (qptr)
1657 {
1658 if (qptr == question)
1659 {
1660 if (question->LongLived && question->uDNS_info.llq)
1661 stopLLQ(m, question);
1662 if (m->uDNS_info.CurrentQuery == question)
1663 m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
1664 while (question->uDNS_info.knownAnswers)
1665 {
1666 ka = question->uDNS_info.knownAnswers;
1667 question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
1668 ufree(ka);
1669 }
1670 if (prev) prev->next = question->next;
1671 else u->ActiveQueries = question->next;
1672 return mStatus_NoError;
1673 }
1674 prev = qptr;
1675 qptr = qptr->next;
1676 }
1677 LogMsg("uDNS_StopQuery: no such active query (%s)", question->qname.c);
1678 return mStatus_UnknownErr;
1679 }
1680
1681 mDNSexport void uDNS_SuspendLLQs(mDNS *m)
1682 {
1683 DNSQuestion *q;
1684 LLQ_Info *llq;
1685 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
1686 {
1687 llq = q->uDNS_info.llq;
1688 if (q->LongLived && llq && llq->state < LLQ_Suspended)
1689 {
1690 if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
1691 sendLLQRefresh(m, q, 0);
1692 // note that we suspend LLQs in setup states too
1693 if (llq->state != LLQ_Retry) llq->state = LLQ_Suspended;
1694 }
1695 }
1696 }
1697
1698 extern void uDNS_RestartLLQs(mDNS *m)
1699 {
1700 uDNS_GlobalInfo *u = &m->uDNS_info;
1701 DNSQuestion *q;
1702 LLQ_Info *llqInfo;
1703
1704 u->CurrentQuery = u->ActiveQueries;
1705 while (u->CurrentQuery)
1706 {
1707 q = u->CurrentQuery;
1708 u->CurrentQuery = u->CurrentQuery->next;
1709 llqInfo = q->uDNS_info.llq;
1710 if (q->LongLived && llqInfo && llqInfo->state == LLQ_Suspended)
1711 { llqInfo->ntries = 0; llqInfo->deriveRemovesOnResume = mDNStrue; startLLQHandshake(m, llqInfo); }
1712 }
1713 }
1714
1715
1716 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
1717 {
1718 uDNS_GlobalInfo *u = &m->uDNS_info;
1719 DNSMessage msg;
1720 mDNSu8 *endPtr;
1721 mStatus err = mStatus_NoError;
1722 const mDNSAddr *server;
1723
1724 //!!!KRS we should check if the question is already in our acivequestion list
1725 if (!ValidateDomainName(&question->qname))
1726 {
1727 LogMsg("Attempt to start query with invalid qname %##s %s", question->qname.c, DNSTypeName(question->qtype));
1728 return mStatus_Invalid;
1729 }
1730
1731 question->next = NULL;
1732 question->qnamehash = DomainNameHashValue(&question->qname); // to do quick domain name comparisons
1733 question->uDNS_info.id = newMessageID(u);
1734
1735 // break here if its and LLQ
1736 if (question->LongLived) return startLLQ(m, question);
1737
1738 err = constructQueryMsg(&msg, &endPtr, question);
1739 if (err) return err;
1740
1741 // else send the query to our server
1742
1743 question->LastQTime = mDNSPlatformTimeNow();
1744 question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1745 // store the question/id in active question list
1746 question->uDNS_info.timestamp = question->LastQTime;
1747 question->uDNS_info.internal = internal;
1748 LinkActiveQuestion(u, question);
1749 question->uDNS_info.knownAnswers = NULL;
1750
1751 server = getInitializedDNS(u);
1752 if (!server) { LogMsg("startQuery - no initialized DNS"); err = mStatus_NotInitializedErr; }
1753 else err = mDNSSendDNSMessage(m, &msg, endPtr, question->InterfaceID, server, UnicastDNSPort);
1754 if (err) { LogMsg("ERROR: startQuery - %d (keeping question in list for retransmission", err); }
1755
1756 return err;
1757 }
1758
1759 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
1760 {
1761 ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
1762 question->uDNS_info.responseCallback = simpleResponseHndlr;
1763 question->uDNS_info.context = NULL;
1764 return startQuery(m, question, 0);
1765 }
1766
1767 // explicitly set response handler
1768 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
1769 {
1770 ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
1771 q->QuestionContext = hndlrContext;
1772 q->uDNS_info.responseCallback = callback;
1773 q->uDNS_info.context = hndlrContext;
1774 return startQuery(m, q, 1);
1775 }
1776
1777
1778
1779 // ***************************************************************************
1780 #if COMPILER_LIKES_PRAGMA_MARK
1781 #pragma mark - Domain -> Name Server Conversion
1782 #endif
1783
1784
1785 /* startGetZoneData
1786 *
1787 * asyncronously find the address of the nameserver for the enclosing zone for a given domain name,
1788 * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is
1789 * derived, it will be passed to the callback, along with a context pointer. If the zone cannot
1790 * be determined or if an error occurs, an all-zeros address will be passed and a message will be
1791 * written to the syslog.
1792 *
1793 * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
1794 * by querying for the _update._dns-sd._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set,
1795 * the port on which the server accepts long lived queries is determined by querying for _llq._dns-sd.
1796 * _udp.<zone>. record. If either of these queries fail, or flags are not specified, the llqPort and
1797 * updatePort fields in the result structure are set to zero.
1798 *
1799 * Steps for deriving the zone name are as follows:
1800 *
1801 * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority
1802 * section), we strip the leading label from the name and repeat, until we get an answer.
1803 *
1804 * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain
1805 * name of the primary NS.
1806 *
1807 * We verify that there is an NS record with this zone for a name and the mname for its rdata.
1808 * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
1809 * the NS query will get us address records in the additionals section, which we'd otherwise have to
1810 * explicitly query for.)
1811 *
1812 * We then query for the address record for this nameserver (if it is not in the addionals section of
1813 * the NS record response.)
1814 */
1815
1816
1817 // state machine types and structs
1818 //
1819
1820 // state machine states
1821 typedef enum
1822 {
1823 init,
1824 lookupSOA,
1825 foundZone,
1826 lookupNS,
1827 foundNS,
1828 lookupA,
1829 foundA,
1830 lookupPort,
1831 foundPort,
1832 complete
1833 } ntaState;
1834
1835 // state machine actions
1836 typedef enum
1837 {
1838 smContinue, // continue immediately to next state
1839 smBreak, // break until next packet/timeout
1840 smError // terminal error - cleanup and abort
1841 } smAction;
1842
1843 typedef struct
1844 {
1845 domainname origName; // name we originally try to convert
1846 domainname *curSOA; // name we have an outstanding SOA query for
1847 ntaState state; // determines what we do upon receiving a packet
1848 mDNS *m;
1849 domainname zone; // left-hand-side of SOA record
1850 mDNSu16 zoneClass;
1851 domainname ns; // mname in SOA rdata, verified in confirmNS state
1852 mDNSv4Addr addr; // address of nameserver
1853 DNSQuestion question; // storage for any active question
1854 DNSQuestion extraQuestion; // additional storage
1855 mDNSBool questionActive; // if true, StopQuery() can be called on the question field
1856 mDNSBool findUpdatePort;
1857 mDNSBool findLLQPort;
1858 mDNSIPPort updatePort;
1859 mDNSIPPort llqPort;
1860 AsyncOpCallback *callback; // caller specified function to be called upon completion
1861 void *callbackInfo;
1862 } ntaContext;
1863
1864
1865 // function prototypes (for routines that must be used as fn pointers prior to their definitions,
1866 // and allows states to be read top-to-bottom in logical order)
1867 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
1868 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
1869 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
1870 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
1871 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
1872 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
1873
1874 // initialization
1875 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
1876 AsyncOpCallback callback, void *callbackInfo)
1877 {
1878 ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
1879 if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr; }
1880 ubzero(context, sizeof(ntaContext));
1881 ustrcpy(context->origName.c, name->c);
1882 context->state = init;
1883 context->m = m;
1884 context->callback = callback;
1885 context->callbackInfo = callbackInfo;
1886 context->findUpdatePort = findUpdatePort;
1887 context->findLLQPort = findLLQPort;
1888 getZoneData(m, NULL, NULL, NULL, context);
1889 return mStatus_NoError;
1890 }
1891
1892 // state machine entry routine
1893 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
1894 {
1895 AsyncOpResult result;
1896 ntaContext *context = (ntaContext*)contextPtr;
1897 smAction action;
1898
1899 // unused
1900 (void)m;
1901 (void)question;
1902
1903 // stop any active question
1904 if (context->questionActive)
1905 {
1906 uDNS_StopQuery(context->m, &context->question);
1907 context->questionActive = mDNSfalse;
1908 }
1909
1910 if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
1911 {
1912 // rcode non-zero, non-nxdomain
1913 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
1914 goto error;
1915 }
1916
1917 switch (context->state)
1918 {
1919 case init:
1920 case lookupSOA:
1921 action = hndlLookupSOA(msg, end, context);
1922 if (action == smError) goto error;
1923 if (action == smBreak) return;
1924 case foundZone:
1925 case lookupNS:
1926 action = confirmNS(msg, end, context);
1927 if (action == smError) goto error;
1928 if (action == smBreak) return;
1929 case foundNS:
1930 case lookupA:
1931 action = lookupNSAddr(msg, end, context);
1932 if (action == smError) goto error;
1933 if (action == smBreak) return;
1934 case foundA:
1935 if (!context->findUpdatePort && !context->findLLQPort)
1936 {
1937 context->state = complete;
1938 break;
1939 }
1940 case lookupPort:
1941 action = hndlLookupPorts(msg, end, context);
1942 if (action == smError) goto error;
1943 if (action == smBreak) return;
1944 if (action == smContinue) context->state = complete;
1945 case foundPort:
1946 case complete: break;
1947 }
1948
1949 if (context->state != complete)
1950 {
1951 LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
1952 goto error;
1953 }
1954
1955 result.type = zoneDataResult;
1956 result.zoneData.primaryAddr.ip.v4.NotAnInteger = context->addr.NotAnInteger;
1957 result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
1958 ustrcpy(result.zoneData.zoneName.c, context->zone.c);
1959 result.zoneData.zoneClass = context->zoneClass;
1960 result.zoneData.llqPort = context->findLLQPort ? context->llqPort : zeroIPPort;
1961 result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
1962 context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
1963 goto cleanup;
1964
1965 error:
1966 if (context && context->callback)
1967 context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, NULL);
1968 cleanup:
1969 if (context && context->questionActive)
1970 {
1971 uDNS_StopQuery(context->m, &context->question);
1972 context->questionActive = mDNSfalse;
1973 }
1974 if (context) ufree(context);
1975 }
1976
1977 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
1978 {
1979 mStatus err;
1980 LargeCacheRecord lcr;
1981 ResourceRecord *rr = &lcr.r.resrec;
1982 DNSQuestion *query = &context->question;
1983 const mDNSu8 *ptr;
1984
1985 if (msg)
1986 {
1987 // if msg contains SOA record in answer or authority sections, update context/state and return
1988 int i;
1989 ptr = LocateAnswers(msg, end);
1990 for (i = 0; i < msg->h.numAnswers; i++)
1991 {
1992 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1993 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError; }
1994 if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, &rr->name))
1995 {
1996 processSOA(context, rr);
1997 return smContinue;
1998 }
1999 }
2000 ptr = LocateAuthorities(msg, end);
2001 // SOA not in answers, check in authority
2002 for (i = 0; i < msg->h.numAuthorities; i++)
2003 {
2004 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
2005 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError; }
2006 if (rr->rrtype == kDNSType_SOA)
2007 {
2008 processSOA(context, rr);
2009 return smContinue;
2010 }
2011 }
2012 }
2013
2014 if (context->state != init && !context->curSOA->c[0])
2015 {
2016 // we've gone down to the root and have not found an SOA
2017 LogMsg("ERROR: hndlLookupSOA - recursed to root label of %s without finding SOA",
2018 context->origName.c);
2019 return smError;
2020 }
2021
2022 ubzero(query, sizeof(DNSQuestion));
2023 // chop off leading label unless this is our first try
2024 if (context->state == init) context->curSOA = &context->origName;
2025 else context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
2026
2027 context->state = lookupSOA;
2028 ustrcpy(query->qname.c, context->curSOA->c);
2029 query->qtype = kDNSType_SOA;
2030 query->qclass = kDNSClass_IN;
2031 err = startInternalQuery(query, context->m, getZoneData, context);
2032 context->questionActive = mDNStrue;
2033 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
2034
2035 return smBreak; // break from state machine until we receive another packet
2036 }
2037
2038 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
2039 {
2040 ustrcpy(context->zone.c, rr->name.c);
2041 context->zoneClass = rr->rrclass;
2042 ustrcpy(context->ns.c, rr->rdata->u.soa.mname.c);
2043 context->state = foundZone;
2044 }
2045
2046
2047 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
2048 {
2049 DNSQuestion *query = &context->question;
2050 mStatus err;
2051 LargeCacheRecord lcr;
2052 ResourceRecord *rr = &lcr.r.resrec;
2053 const mDNSu8 *ptr;
2054 int i;
2055
2056 if (context->state == foundZone)
2057 {
2058 // we've just learned the zone. confirm that an NS record exists
2059 ustrcpy(query->qname.c, context->zone.c);
2060 query->qtype = kDNSType_NS;
2061 query->qclass = kDNSClass_IN;
2062 err = startInternalQuery(query, context->m, getZoneData, context);
2063 context->questionActive = mDNStrue;
2064 if (err) LogMsg("confirmNS: startInternalQuery returned error %d (breaking until next periodic retransmission", err);
2065 context->state = lookupNS;
2066 return smBreak; // break from SM until we receive another packet
2067 }
2068 else if (context->state == lookupNS)
2069 {
2070 ptr = LocateAnswers(msg, end);
2071 for (i = 0; i < msg->h.numAnswers; i++)
2072 {
2073 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
2074 if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError; }
2075 if (rr->rrtype == kDNSType_NS &&
2076 SameDomainName(&context->zone, &rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
2077 {
2078 context->state = foundNS;
2079 return smContinue; // next routine will examine additionals section of A record
2080 }
2081 }
2082 LogMsg("ERROR: could not confirm existance of NS record %s", context->zone.c);
2083 return smError;
2084 }
2085 else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
2086 }
2087
2088 mDNSlocal smAction queryNSAddr(ntaContext *context)
2089 {
2090 mStatus err;
2091 DNSQuestion *query = &context->question;
2092
2093 ustrcpy(query->qname.c, context->ns.c);
2094 query->qtype = kDNSType_A;
2095 query->qclass = kDNSClass_IN;
2096 err = startInternalQuery(query, context->m, getZoneData, context);
2097 context->questionActive = mDNStrue;
2098 if (err) LogMsg("confirmNS: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
2099 context->state = lookupA;
2100 return smBreak;
2101 }
2102
2103 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
2104 {
2105 const mDNSu8 *ptr;
2106 int i;
2107 LargeCacheRecord lcr;
2108 ResourceRecord *rr = &lcr.r.resrec;
2109
2110 if (context->state == foundNS)
2111 {
2112 // we just found the NS record - look for the corresponding A record in the Additionals section
2113 if (!msg->h.numAdditionals) return queryNSAddr(context);
2114 ptr = LocateAdditionals(msg, end);
2115 if (!ptr)
2116 {
2117 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
2118 return queryNSAddr(context);
2119 }
2120 else
2121 {
2122 for (i = 0; i < msg->h.numAdditionals; i++)
2123 {
2124 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
2125 if (!ptr)
2126 {
2127 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
2128 return queryNSAddr(context);
2129 }
2130 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
2131 {
2132 context->addr.NotAnInteger = rr->rdata->u.ip.NotAnInteger;
2133 context->state = foundA;
2134 return smContinue;
2135 }
2136 }
2137 }
2138 // no A record in Additionals - query the server
2139 return queryNSAddr(context);
2140 }
2141 else if (context->state == lookupA)
2142 {
2143 ptr = LocateAnswers(msg, end);
2144 if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError; }
2145 for (i = 0; i < msg->h.numAnswers; i++)
2146 {
2147 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
2148 if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
2149 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
2150 {
2151 context->addr.NotAnInteger = rr->rdata->u.ip.NotAnInteger;
2152 context->state = foundA;
2153 return smContinue;
2154 }
2155 }
2156 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
2157 return smError;
2158 }
2159 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
2160 }
2161
2162 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
2163 {
2164 int i;
2165 LargeCacheRecord lcr;
2166 const mDNSu8 *ptr;
2167 DNSQuestion *q;
2168 mStatus err;
2169
2170 if (context->state == lookupPort) // we've already issued the query
2171 {
2172 if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
2173 ptr = LocateAnswers(msg, end);
2174 for (i = 0; i < msg->h.numAnswers; i++)
2175 {
2176 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
2177 if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError; }
2178 if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
2179 {
2180 port->NotAnInteger = lcr.r.resrec.rdata->u.srv.port.NotAnInteger;
2181 context->state = foundPort;
2182 return smContinue;
2183 }
2184 }
2185 LogMsg("hndlLookupUpdatePort %s - answer not contained in reply. Guessing port %d", portName, UnicastDNSPort);
2186 *port = UnicastDNSPort;
2187 context->state = foundPort;
2188 return smContinue;
2189 }
2190
2191 // query the server for the update port for the zone
2192 context->state = lookupPort;
2193 q = &context->question;
2194 MakeDomainNameFromDNSNameString(&q->qname, portName);
2195 ustrcpy((q->qname.c + ustrlen(q->qname.c)), context->zone.c);
2196 q->qtype = kDNSType_SRV;
2197 q->qclass = kDNSClass_IN;
2198 err = startInternalQuery(q, context->m, getZoneData, context);
2199 context->questionActive = mDNStrue;
2200 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
2201 return smBreak; // break from state machine until we receive another packet
2202 }
2203
2204 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
2205 {
2206 smAction action;
2207
2208 if (context->findUpdatePort && !context->updatePort.NotAnInteger)
2209 {
2210 action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
2211 if (action != smContinue) return action;
2212 }
2213 if (context->findLLQPort && !context->llqPort.NotAnInteger)
2214 return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
2215
2216 return smContinue;
2217 }
2218
2219
2220 // ***************************************************************************
2221 #if COMPILER_LIKES_PRAGMA_MARK
2222 #pragma mark - Truncation Handling
2223 #endif
2224
2225 typedef struct
2226 {
2227 DNSQuestion *question;
2228 DNSMessage reply;
2229 mDNSu16 replylen;
2230 int nread;
2231 mDNS *m;
2232 } tcpInfo_t;
2233
2234 // issue queries over a conected socket
2235 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
2236 {
2237 mStatus err = 0;
2238 char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
2239 DNSMessage *msg;
2240 mDNSu8 *end;
2241 tcpInfo_t *info = (tcpInfo_t *)context;
2242 DNSQuestion *question = info->question;
2243 int n;
2244
2245 question->uDNS_info.id.NotAnInteger = (mDNSu16)~0;
2246
2247 if (ConnectionEstablished)
2248 {
2249 // connection is established - send the message
2250 msg = (DNSMessage *)&msgbuf;
2251 err = constructQueryMsg(msg, &end, question);
2252 if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %d", err); goto error; }
2253 err = mDNSSendDNSMessage_tcp(info->m, msg, end, sd);
2254 if (err) { LogMsg("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %d", err); goto error; }
2255 return;
2256 }
2257 else
2258 {
2259 if (!info->nread)
2260 {
2261 // read msg len
2262 n = mDNSPlatformReadTCP(sd, &info->replylen, 2);
2263 if (n != 2)
2264 {
2265 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
2266 goto error;
2267 }
2268 }
2269 n = mDNSPlatformReadTCP(sd, ((char *)&info->reply) + info->nread, info->replylen - info->nread);
2270 if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
2271 info->nread += n;
2272 if (info->nread == info->replylen)
2273 {
2274 // finished reading message
2275 receiveMsg(info->m, &info->reply, ((mDNSu8 *)&info->reply) + info->replylen, question->InterfaceID);
2276 mDNSPlatformTCPCloseConnection(sd);
2277 ufree(info);
2278 return;
2279 }
2280 else return;
2281 }
2282 return;
2283
2284 error:
2285 mDNSPlatformTCPCloseConnection(sd);
2286 ufree(info);
2287 }
2288
2289 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m)
2290 {
2291 mStatus connectionStatus;
2292 uDNS_QuestionInfo *info = &question->uDNS_info;
2293 int sd;
2294 tcpInfo_t *context;
2295
2296 context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
2297 if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
2298 ubzero(context, sizeof(tcpInfo_t));
2299 context->question = question;
2300 context->m = m;
2301
2302 info->id.NotAnInteger = (mDNSu16)~0; // all 1's indicates TCP queries
2303 info->timestamp = mDNSPlatformTimeNow(); // reset timestamp
2304
2305 connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
2306 if (connectionStatus == mStatus_ConnectionEstablished) // manually invoke callback if connection completes
2307 {
2308 conQueryCallback(sd, context, mDNStrue);
2309 return;
2310 }
2311 if (connectionStatus == mStatus_ConnectionPending) return; // callback will be automatically invoked when connection completes
2312 LogMsg("hndlTruncatedAnswer: connection failed");
2313 uDNS_StopQuery(m, question); //!!!KRS can we really call this here?
2314 }
2315
2316
2317 // ***************************************************************************
2318 #if COMPILER_LIKES_PRAGMA_MARK
2319 #pragma mark - Dynamic Updates
2320 #endif
2321
2322
2323 mDNSlocal mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
2324 {
2325 ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
2326 if (!ptr || ptr + 4 > limit) return NULL; // If we're out-of-space, return NULL
2327 ((mDNSOpaque16 *)ptr)->NotAnInteger = kDNSType_SOA;
2328 ptr += 2;
2329 ((mDNSOpaque16 *)ptr)->NotAnInteger = zoneClass.NotAnInteger;
2330 ptr += 2;
2331 msg->h.mDNS_numZones++;
2332 return ptr;
2333 }
2334
2335
2336
2337 mDNSlocal mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
2338 {
2339 AuthRecord prereq;
2340
2341 ubzero(&prereq, sizeof(AuthRecord));
2342 ustrcpy(prereq.resrec.name.c, name->c);
2343 prereq.resrec.rrtype = kDNSQType_ANY;
2344 prereq.resrec.rrclass = kDNSClass_NONE;
2345 ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
2346 return ptr;
2347 }
2348
2349 mDNSlocal mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
2350 {
2351 mDNSu16 origclass;
2352 // deletion: specify record w/ TTL 0, class NONE
2353
2354 origclass = rr->rrclass;
2355 rr->rrclass = kDNSClass_NONE;
2356 ptr = PutResourceRecordTTL(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
2357 rr->rrclass = origclass;
2358 return ptr;
2359 }
2360
2361 mDNSlocal mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end)
2362 {
2363 AuthRecord rr;
2364 ResourceRecord *opt = &rr.resrec;
2365 rdataOpt *optRD;
2366
2367 ubzero(&rr, sizeof(AuthRecord));
2368 opt->rdata = &rr.rdatastorage;
2369
2370 opt->RecordType = kDNSRecordTypeKnownUnique; // to avoid warnings in other layers
2371 opt->rrtype = kDNSType_OPT;
2372 opt->rdlength = LEASE_OPT_SIZE;
2373 opt->rdestimate = LEASE_OPT_SIZE;
2374
2375 optRD = &rr.resrec.rdata->u.opt;
2376 optRD->opt = kDNSOpt_Lease;
2377 optRD->optlen = sizeof(mDNSs32);
2378 optRD->OptData.lease = kUpdate_DefLease;
2379 end = PutResourceRecordTTL(msg, end, &msg->h.numAdditionals, opt, 0);
2380 if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return NULL; }
2381
2382 return end;
2383
2384 }
2385
2386 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
2387 {
2388 DNSMessage msg;
2389 mDNSu8 *ptr = msg.data;
2390 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
2391 uDNS_GlobalInfo *u = &m->uDNS_info;
2392 mDNSOpaque16 id;
2393 uDNS_AuthInfo *authInfo;
2394 uDNS_RegInfo *regInfo = &rr->uDNS_info;
2395 mStatus err = mStatus_UnknownErr;
2396
2397 id = newMessageID(u);
2398 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
2399 rr->uDNS_info.id.NotAnInteger = id.NotAnInteger;
2400
2401 // set zone
2402 ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
2403 if (!ptr) goto error;
2404
2405 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->uDNS_info.state == regState_Refresh)
2406 {
2407 // KnownUnique means the record must ALREADY exist, as does refresh
2408 // prereq: record must exist (put record in prereq section w/ TTL 0)
2409 ptr = PutResourceRecordTTL(&msg, ptr, &msg.h.mDNS_numPrereqs, &rr->resrec, 0);
2410 if (!ptr) goto error;
2411 }
2412 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
2413 {
2414 ptr = putPrereqNameNotInUse(&rr->resrec.name, &msg, ptr, end);
2415 if (!ptr) goto error;
2416 }
2417
2418 ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec);
2419 if (!ptr) goto error;
2420
2421 if (rr->uDNS_info.lease)
2422 ptr = putUpdateLease(&msg, ptr);
2423
2424 rr->uDNS_info.expire = -1;
2425
2426 authInfo = GetAuthInfoForZone(u, &regInfo->zone);
2427 if (authInfo)
2428 {
2429 err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &regInfo->ns, regInfo->port, authInfo);
2430 if (err) { LogMsg("ERROR: sendRecordRegistration - mDNSSendSignedDNSMessage - %d", err); goto error; }
2431 }
2432 else
2433 {
2434 err = mDNSSendDNSMessage(m, &msg, ptr, 0, &regInfo->ns, regInfo->port);
2435 if (err) { LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %d", err); goto error; }
2436 }
2437
2438 if (regInfo->state != regState_Refresh) regInfo->state = regState_Pending;
2439 return;
2440
2441 error:
2442 if (rr->uDNS_info.state != regState_Unregistered)
2443 {
2444 unlinkAR(&u->RecordRegistrations, rr);
2445 rr->uDNS_info.state = regState_Unregistered;
2446 }
2447 rr->RecordCallback(m, rr, err);
2448 // NOTE: not safe to touch any client structures here
2449 }
2450
2451 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
2452 {
2453 AuthRecord *newRR = (AuthRecord*)authPtr;
2454 const zoneData_t *zoneData = &result->zoneData;
2455 uDNS_GlobalInfo *u = &m->uDNS_info;
2456 AuthRecord *ptr;
2457
2458 for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
2459 if (ptr == newRR) break;
2460 if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
2461
2462 if (err) { LogMsg("RecordRegistrationCallback: error %d", err); goto error; }
2463 if (newRR->uDNS_info.state == regState_Cancelled)
2464 {
2465 //!!!KRS we should send a memfree callback here!
2466 LogMsg("Registration of %s type %d cancelled prior to update",
2467 newRR->resrec.name.c, newRR->resrec.rrtype);
2468 newRR->uDNS_info.state = regState_Unregistered;
2469 unlinkAR(&u->RecordRegistrations, newRR);
2470 return;
2471 }
2472
2473 if (result->type != zoneDataResult)
2474 {
2475 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
2476 goto error;
2477 }
2478
2479 if (newRR->resrec.rrclass != zoneData->zoneClass)
2480 {
2481 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
2482 newRR->resrec.rrclass, zoneData->zoneClass);
2483 goto error;
2484 }
2485
2486 // cache zone data
2487 ustrcpy(newRR->uDNS_info.zone.c, zoneData->zoneName.c);
2488 newRR->uDNS_info.ns.type = mDNSAddrType_IPv4;
2489 newRR->uDNS_info.ns.ip.v4.NotAnInteger = zoneData->primaryAddr.ip.v4.NotAnInteger;
2490 newRR->uDNS_info.port.NotAnInteger = zoneData->updatePort.NotAnInteger;
2491
2492 sendRecordRegistration(m, newRR);
2493 return;
2494
2495 error:
2496 if (newRR->uDNS_info.state != regState_Unregistered)
2497 {
2498 unlinkAR(&u->RecordRegistrations, newRR);
2499 newRR->uDNS_info.state = regState_Unregistered;
2500 }
2501 newRR->RecordCallback(m, newRR, err);
2502 // NOTE: not safe to touch any client structures here
2503 }
2504
2505
2506 mDNSlocal mDNSBool setHostTarget(AuthRecord *rr, mDNS *m)
2507 {
2508 domainname *target;
2509
2510 if (!rr->HostTarget)
2511 {
2512 debugf("Service %s - not updating host target", rr->resrec.name.c);
2513 return mDNSfalse;
2514 }
2515
2516 // set SRV target
2517 target = GetRRDomainNameTarget(&rr->resrec);
2518 if (!target)
2519 {
2520 LogMsg("ERROR: setHostTarget: Can't set target of rrtype %d", rr->resrec.rrtype);
2521 return mDNSfalse;
2522 }
2523
2524 if (SameDomainName(target, &m->uDNS_info.hostname))
2525 {
2526 debugf("Host target for %s unchanged", rr->resrec.name.c);
2527 return mDNSfalse;
2528 }
2529 AssignDomainName(*target, m->uDNS_info.hostname);
2530 SetNewRData(&rr->resrec, NULL, 0);
2531 return mDNStrue;
2532 }
2533
2534 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
2535 {
2536 DNSMessage msg;
2537 mDNSu8 *ptr = msg.data;
2538 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
2539 uDNS_GlobalInfo *u = &m->uDNS_info;
2540 mDNSOpaque16 id;
2541 uDNS_AuthInfo *authInfo;
2542 uDNS_RegInfo *rInfo = &srs->uDNS_info;
2543 mStatus err = mStatus_UnknownErr;
2544
2545 id = newMessageID(u);
2546 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
2547 rInfo->id.NotAnInteger = id.NotAnInteger;
2548
2549 // setup resource records
2550 if (setHostTarget(&srs->RR_SRV, m))
2551 SetNewRData(&srs->RR_SRV.resrec, NULL, 0); // set rdlen/estimate/hash
2552
2553 //SetNewRData(&srs->RR_ADV.resrec, NULL, 0); //!!!KRS
2554 SetNewRData(&srs->RR_PTR.resrec, NULL, 0);
2555 SetNewRData(&srs->RR_TXT.resrec, NULL, 0);
2556
2557 // construct update packet
2558 // set zone
2559 ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
2560 if (!ptr) goto error;
2561
2562 if (srs->uDNS_info.state == regState_Refresh)
2563 {
2564 // prereq: record must exist (put record in prereq section w/ TTL 0)
2565 ptr = PutResourceRecordTTL(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0);
2566 if (!ptr) goto error;
2567 }
2568 else
2569 {
2570 // use SRV for prereq
2571 ptr = putPrereqNameNotInUse(&srs->RR_SRV.resrec.name, &msg, ptr, end);
2572 if (!ptr) goto error;
2573 }
2574
2575 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
2576 //if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_ADV.resrec))) goto error;
2577 if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec))) goto error;
2578 if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_SRV.resrec))) goto error;
2579 if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec))) goto error;
2580 // !!!KRS do subtypes/extras etc.
2581
2582 if (srs->uDNS_info.lease)
2583 ptr = putUpdateLease(&msg, ptr);
2584
2585 srs->uDNS_info.expire = -1;
2586
2587 authInfo = GetAuthInfoForZone(u, &rInfo->zone);
2588 if (authInfo)
2589 {
2590 err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &rInfo->ns, rInfo->port, authInfo);
2591 if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendSignedDNSMessage - %d", err); goto error; }
2592 }
2593 else
2594 {
2595 err = mDNSSendDNSMessage(m, &msg, ptr, 0, &rInfo->ns, rInfo->port);
2596 if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err); goto error; }
2597 }
2598 if (rInfo->state != regState_Refresh)
2599 rInfo->state = regState_Pending;
2600 return;
2601
2602 error:
2603 unlinkSRS(u, srs);
2604 rInfo->state = regState_Unregistered;
2605 srs->ServiceCallback(m, srs, err);
2606 //!!!KRS will mem still be free'd on error?
2607 // NOTE: not safe to touch any client structures here
2608 }
2609
2610 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
2611 {
2612 ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
2613 const zoneData_t *zoneData = &result->zoneData;
2614 uDNS_GlobalInfo *u = &m->uDNS_info;
2615
2616 if (err) goto error;
2617 if (result->type != zoneDataResult)
2618 {
2619 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
2620 goto error;
2621 }
2622
2623 if (srs->uDNS_info.state == regState_Cancelled)
2624 {
2625 // client cancelled registration while fetching zone data
2626 srs->uDNS_info.state = regState_Unregistered;
2627 unlinkSRS(u, srs);
2628 srs->ServiceCallback(m, srs, mStatus_MemFree);
2629 return;
2630 }
2631
2632 if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
2633 {
2634 LogMsg("Service %s - class does not match zone", srs->RR_SRV.resrec.name.c);
2635 goto error;
2636 }
2637 // cache zone data
2638 ustrcpy(srs->uDNS_info.zone.c, zoneData->zoneName.c);
2639 srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
2640 srs->uDNS_info.ns.ip.v4.NotAnInteger = zoneData->primaryAddr.ip.v4.NotAnInteger;
2641 srs->uDNS_info.port.NotAnInteger = zoneData->updatePort.NotAnInteger;
2642
2643 SendServiceRegistration(m, srs);
2644 return;
2645
2646 error:
2647 unlinkSRS(u, srs);
2648 srs->uDNS_info.state = regState_Unregistered;
2649 srs->ServiceCallback(m, srs, err);
2650 //!!!KRS will mem still be free'd on error?
2651 // NOTE: not safe to touch any client structures here
2652 }
2653
2654 mDNSexport void uDNS_UpdateServiceTargets(mDNS *const m)
2655 {
2656 DNSMessage msg;
2657 mDNSu8 *ptr = msg.data;
2658 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
2659 uDNS_GlobalInfo *u = &m->uDNS_info;
2660 ServiceRecordSet *srs;
2661 AuthRecord *rr;
2662 mStatus err = mStatus_NoError;
2663
2664 if (!m->uDNS_info.hostname.c[0])
2665 {
2666 LogMsg("ERROR: uDNS_UpdateServiceTargets called before registration of hostname");
2667 return;
2668 //!!!KRS need to handle this case properly!
2669 }
2670
2671 for (srs = u->ServiceRegistrations; srs; srs = srs->next)
2672 {
2673 if (err) srs = u->ServiceRegistrations;
2674 // start again from beginning of list, since it may have changed
2675 // (setHostTarget() will skip records already updated)
2676 rr = &srs->RR_SRV;
2677 if (srs->uDNS_info.state != regState_Registered)
2678 {
2679 LogMsg("ERROR: uDNS_UpdateServiceTargets - service %s not registered", rr->resrec.name.c);
2680 continue;
2681 //!!!KRS need to handle this
2682 }
2683 InitializeDNSMessage(&msg.h, srs->uDNS_info.id, UpdateReqFlags);
2684
2685 // construct update packet
2686 ptr = putZone(&msg, ptr, end, &srs->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
2687 if (ptr) ptr = putDeletionRecord(&msg, ptr, &rr->resrec); // delete the old target
2688 // update the target
2689 if (!setHostTarget(rr, m)) continue;
2690 if (ptr) ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec); // put the new target
2691 // !!!KRS do subtypes/extras etc.
2692 if (!ptr) err = mStatus_UnknownErr;
2693 else err = mDNSSendDNSMessage(m, &msg, ptr, 0, &srs->uDNS_info.ns, srs->uDNS_info.port);
2694 if (err)
2695 {
2696 LogMsg("ERROR: uDNS_UpdateServiceTargets - %s", ptr ? "mDNSSendDNSMessage" : "message formatting error");
2697 unlinkSRS(u, srs);
2698 srs->uDNS_info.state = regState_Unregistered;
2699 srs->ServiceCallback(m, srs, err);
2700 //!!!KRS will mem still be free'd on error?
2701 // NOTE: not safe to touch any client structures here
2702 }
2703 else srs->uDNS_info.state = regState_TargetChange;
2704 }
2705 }
2706
2707
2708 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
2709 {
2710 domainname *target = GetRRDomainNameTarget(&rr->resrec);
2711
2712 if (rr->uDNS_info.state == regState_FetchingZoneData ||
2713 rr->uDNS_info.state == regState_Pending ||
2714 rr->uDNS_info.state == regState_Registered)
2715 {
2716 LogMsg("Requested double-registration of physical record %s type %s",
2717 rr->resrec.name.c, rr->resrec.rrtype);
2718 return mStatus_AlreadyRegistered;
2719 }
2720
2721 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
2722 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
2723
2724 if (!ValidateDomainName(&rr->resrec.name))
2725 {
2726 LogMsg("Attempt to register record with invalid name: %s", GetRRDisplayString(m, rr));
2727 return mStatus_Invalid;
2728 }
2729
2730 // Don't do this until *after* we've set rr->resrec.rdlength
2731 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
2732 { LogMsg("Attempt to register record with invalid rdata: %s", GetRRDisplayString(m, rr));
2733 return mStatus_Invalid;
2734 }
2735
2736 rr->resrec.namehash = DomainNameHashValue(&rr->resrec.name);
2737 rr->resrec.rdatahash = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
2738 rr->resrec.rdnamehash = target ? DomainNameHashValue(target) : 0;
2739
2740 rr->uDNS_info.state = regState_FetchingZoneData;
2741 rr->next = m->uDNS_info.RecordRegistrations;
2742 m->uDNS_info.RecordRegistrations = rr;
2743
2744 rr->uDNS_info.lease = mDNStrue;
2745 return startGetZoneData(&rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
2746 }
2747
2748
2749
2750 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
2751 {
2752 uDNS_GlobalInfo *u = &m->uDNS_info;
2753 DNSMessage msg;
2754 mDNSu8 *ptr = msg.data;
2755 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
2756 mStatus err;
2757 uDNS_AuthInfo *authInfo;
2758 switch (rr->uDNS_info.state)
2759 {
2760 case regState_FetchingZoneData:
2761 rr->uDNS_info.state = regState_Cancelled;
2762 return mStatus_NoError;
2763 case regState_Pending:
2764 rr->uDNS_info.state = regState_DeregDeferred;
2765 debugf("Deferring deregistration of record %s until registration completes", rr->resrec.name.c);
2766 return mStatus_NoError;
2767 case regState_Registered:
2768 break;
2769 case regState_DeregPending:
2770 case regState_Cancelled:
2771 LogMsg("Double deregistration of record %s type %d",
2772 rr->resrec.name.c, rr->resrec.rrtype);
2773 return mStatus_UnknownErr;
2774 case regState_Unregistered:
2775 LogMsg("Requested deregistration of unregistered record %s type %d",
2776 rr->resrec.name.c, rr->resrec.rrtype);
2777 return mStatus_UnknownErr;
2778 default:
2779 LogMsg("ERROR: uDNS_DeregisterRecord called for record %s type %d with unknown state %d",
2780 rr->resrec.name.c, rr->resrec.rrtype, rr->uDNS_info.state);
2781 return mStatus_UnknownErr;
2782 }
2783
2784 InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
2785
2786 // put zone
2787 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
2788 if (!ptr) goto error;
2789
2790 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
2791
2792 authInfo = GetAuthInfoForZone(u, &rr->uDNS_info.zone);
2793 if (authInfo)
2794 {
2795 err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &rr->uDNS_info.ns, rr->uDNS_info.port, authInfo);
2796 if (err) { LogMsg("ERROR: uDNS_DeregiserRecord - mDNSSendSignedDNSMessage - %d", err); goto error; }
2797 }
2798 else
2799 {
2800 err = mDNSSendDNSMessage(m, &msg, ptr, 0, &rr->uDNS_info.ns, rr->uDNS_info.port);
2801 if (err) { LogMsg("ERROR: uDNS_DeregisterRecord - mDNSSendDNSMessage - %d", err); goto error; }
2802 }
2803
2804 return mStatus_NoError;
2805
2806 error:
2807 if (rr->uDNS_info.state != regState_Unregistered)
2808 {
2809 unlinkAR(&u->RecordRegistrations, rr);
2810 rr->uDNS_info.state = regState_Unregistered;
2811 }
2812 return mStatus_UnknownErr;
2813 }
2814
2815
2816 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
2817 {
2818 if (!*m->uDNS_info.NameRegDomain)
2819 {
2820 LogMsg("ERROR: uDNS_RegisterService - cannot register unicast service "
2821 "without setting the NameRegDomain via mDNSResponder.conf");
2822 srs->uDNS_info.state = regState_Unregistered;
2823 return mStatus_UnknownErr;
2824 }
2825
2826 srs->RR_SRV.resrec.rroriginalttl = 3;
2827 srs->RR_TXT.resrec.rroriginalttl = 3;
2828 srs->RR_PTR.resrec.rroriginalttl = 3;
2829
2830 // set state and link into list
2831 srs->uDNS_info.state = regState_FetchingZoneData;
2832 srs->next = m->uDNS_info.ServiceRegistrations;
2833 m->uDNS_info.ServiceRegistrations = srs;
2834 srs->uDNS_info.lease = mDNStrue;
2835
2836 return startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
2837 }
2838
2839 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
2840 {
2841 uDNS_GlobalInfo *u = &m->uDNS_info;
2842 DNSMessage msg;
2843 mDNSu8 *ptr = msg.data;
2844 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
2845 mStatus err = mStatus_UnknownErr;
2846 uDNS_AuthInfo *authInfo;
2847
2848 //!!!KRS make sure we're doing the right thing w/ memfree
2849
2850 switch (srs->uDNS_info.state)
2851 {
2852 case regState_Unregistered:
2853 LogMsg("ERROR: uDNS_DeregisterService - service not registerd");
2854 return mStatus_UnknownErr;
2855 case regState_FetchingZoneData:
2856 case regState_Pending:
2857 // let the async op complete, then terminate
2858 srs->uDNS_info.state = regState_Cancelled;
2859 return mStatus_NoError; // deliver memfree upon completion of async op
2860 case regState_DeregPending:
2861 case regState_DeregDeferred:
2862 case regState_Cancelled:
2863 LogMsg("uDNS_DeregisterService - deregistration in process");
2864 return mStatus_UnknownErr;
2865 }
2866
2867 srs->uDNS_info.state = regState_DeregPending;
2868 InitializeDNSMessage(&msg.h, srs->uDNS_info.id, UpdateReqFlags);
2869
2870 // put zone
2871 ptr = putZone(&msg, ptr, end, &srs->uDNS_info.zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
2872 if (!ptr) { LogMsg("ERROR: uDNS_DeregisterService - putZone"); goto error; }
2873
2874 // prereq: record must exist (put record in prereq section w/ TTL 0)
2875 ptr = PutResourceRecordTTL(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0);
2876 if (!ptr) { LogMsg("ERROR: uDNS_DeregisterService - PutResourceRecordTTL"); goto error; }
2877
2878 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_SRV.resrec))) goto error;
2879 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error;
2880 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
2881 //if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_ADV.resrec))) goto error;
2882 //!!!KRS need to handle extras/subtypes etc
2883
2884
2885 authInfo = GetAuthInfoForZone(u, &srs->uDNS_info.zone);
2886 if (authInfo)
2887 {
2888 err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &srs->uDNS_info.ns, srs->uDNS_info.port, authInfo);
2889 if (err) { LogMsg("ERROR: uDNS_DeregiserService - mDNSSendSignedDNSMessage - %d", err); goto error; }
2890 }
2891 else
2892 {
2893 err = mDNSSendDNSMessage(m, &msg, ptr, 0, &srs->uDNS_info.ns, srs->uDNS_info.port);
2894 if (err) { LogMsg("ERROR: uDNS_DeregisterService - mDNSSendDNSMessage - %d", err); goto error; }
2895 }
2896
2897 return mStatus_NoError;
2898
2899 error:
2900 unlinkSRS(u, srs);
2901 srs->uDNS_info.state = regState_Unregistered;
2902 return err;
2903 }
2904
2905 mDNSexport void uDNS_Execute(mDNS *const m)
2906 {
2907 DNSQuestion *q;
2908 DNSMessage msg;
2909 mStatus err;
2910 mDNSu8 *end;
2911 mDNSs32 sendtime;
2912 LLQ_Info *llq;
2913 AuthRecord *rr;
2914 ServiceRecordSet *srs;
2915 uDNS_RegInfo *rInfo;
2916 uDNS_GlobalInfo *u = &m->uDNS_info;
2917 const mDNSAddr *server = getInitializedDNS(&m->uDNS_info);
2918 mDNSs32 timenow = mDNSPlatformTimeNow();
2919
2920 u->nextevent = timenow + 0x78000000;
2921 if (!server) { debugf("uDNS_Execute - no DNS server"); return; }
2922
2923 for (q = u->ActiveQueries; q; q = q->next)
2924 {
2925 llq = q->uDNS_info.llq;
2926 if (q->LongLived && llq->state != LLQ_Poll)
2927 {
2928 if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Suspended && llq->retry <= timenow)
2929 {
2930
2931 // sanity check to avoid packet flood bugs
2932 if (!llq->retry)
2933 LogMsg("ERROR: retry timer not set for LLQ %s in state %d", q->qname.c, llq->state);
2934 else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
2935 sendLLQRefresh(m, q, llq->origLease);
2936 else if (llq->state == LLQ_InitialRequest)
2937 startLLQHandshake(m, llq);
2938 else if (llq->state == LLQ_SecondaryRequest)
2939 sendChallengeResponse(m, q, NULL);
2940 else if (llq->state == LLQ_Retry)
2941 { llq->ntries = 0; startLLQHandshake(m, llq); }
2942 }
2943 }
2944 else
2945 {
2946 sendtime = q->LastQTime + q->ThisQInterval;
2947 if (sendtime <= timenow)
2948 {
2949 err = constructQueryMsg(&msg, &end, q);
2950 if (err)
2951 {
2952 LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %s",
2953 q->qname.c);
2954 continue;
2955 }
2956 err = mDNSSendDNSMessage(m, &msg, end, q->InterfaceID, server, UnicastDNSPort);
2957 if (err) { debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err); } // surpress syslog messages if we have no network
2958 q->LastQTime = timenow;
2959 if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2;
2960 }
2961 else if (u->nextevent - sendtime > 0) u->nextevent = sendtime;
2962 }
2963 }
2964
2965 //!!!KRS list should be pre-sorted by expiration
2966 for (rr = u->RecordRegistrations; rr; rr = rr->next)
2967 {
2968 rInfo = &rr->uDNS_info;
2969 if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
2970 {
2971 if (rInfo->expire < timenow)
2972 {
2973 debugf("refreshing record %s", rr->resrec.name.c);
2974 rInfo->state = regState_Refresh;
2975 sendRecordRegistration(m, rr);
2976 }
2977 else if (u->nextevent - rInfo->expire > 0) u->nextevent = rInfo->expire;
2978 }
2979 }
2980 //!!!KRS list should be pre-sorted by expiration
2981 for (srs = u->ServiceRegistrations; srs; srs = srs->next)
2982 {
2983 rInfo = &srs->uDNS_info;
2984 if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
2985 {
2986 if (rInfo->expire < timenow)
2987 {
2988 debugf("refreshing service %s", srs->RR_SRV.resrec.name.c);
2989 rInfo->state = regState_Refresh;
2990 SendServiceRegistration(m, srs);
2991 }
2992 else if (u->nextevent - rInfo->expire > 0) u->nextevent = rInfo->expire;
2993 }
2994 }
2995 }
2996
2997 mDNSexport void uDNS_Init(mDNS *const m)
2998 {
2999 mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
3000 m->uDNS_info.nextevent = mDNSPlatformTimeNow() + 0x78000000;
3001 }