2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
28 Revision 1.54 2004/06/22 02:10:53 ksekar
29 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
31 Revision 1.53 2004/06/17 20:49:09 ksekar
32 <rdar://problem/3690436>: Tiger8A148: repeated crash of mDNSResponder while location cycling
34 Revision 1.52 2004/06/17 01:13:11 ksekar
35 <rdar://problem/3696616>: polling interval too short
37 Revision 1.51 2004/06/10 04:36:44 cheshire
40 Revision 1.50 2004/06/10 00:55:13 ksekar
41 <rdar://problem/3686213>: crash on network reconnect
43 Revision 1.49 2004/06/10 00:10:50 ksekar
44 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
46 Revision 1.48 2004/06/09 20:03:37 ksekar
47 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
49 Revision 1.47 2004/06/09 03:48:28 ksekar
50 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
52 Revision 1.46 2004/06/09 01:44:30 ksekar
53 <rdar://problem/3681378> reworked Cache Record copy code
55 Revision 1.45 2004/06/08 18:54:47 ksekar
56 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
58 Revision 1.44 2004/06/05 00:33:51 cheshire
59 <rdar://problem/3681029>: Check for incorrect time comparisons
61 Revision 1.43 2004/06/05 00:14:44 cheshire
62 Fix signed/unsigned and other compiler warnings
64 Revision 1.42 2004/06/04 22:36:16 ksekar
65 Properly set u->nextevent in uDNS_Execute
67 Revision 1.41 2004/06/04 08:58:29 ksekar
68 <rdar://problem/3668624>: Keychain integration for secure dynamic update
70 Revision 1.40 2004/06/03 03:09:58 ksekar
71 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
73 Revision 1.39 2004/06/01 23:46:50 ksekar
74 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
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
80 Revision 1.37 2004/05/28 23:42:37 ksekar
81 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
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
86 Revision 1.35 2004/05/07 23:01:04 ksekar
87 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
88 conditional assignment.
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.
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.
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.
103 Revision 1.31 2004/05/05 17:05:02 ksekar
104 Use LargeCacheRecord structs when pulling records off packets
106 Revision 1.30 2004/04/16 21:33:27 ksekar
107 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
109 Revision 1.29 2004/04/15 20:03:13 ksekar
110 Clarified log message when pulling bad resource records off packet.
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.
116 Revision 1.27 2004/04/14 23:09:28 ksekar
117 Support for TSIG signed dynamic updates.
119 Revision 1.26 2004/04/14 19:36:05 ksekar
120 Fixed memory corruption error in deriveGoodbyes.
122 Revision 1.25 2004/04/14 04:07:11 ksekar
123 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
125 Revision 1.24 2004/04/08 09:41:40 bradley
126 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
128 Revision 1.23 2004/03/24 00:29:45 ksekar
129 Make it safe to call StopQuery in a unicast question callback
131 Revision 1.22 2004/03/19 10:11:09 bradley
132 Added AuthRecord * cast from umalloc for C++ builds.
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++.
138 Revision 1.20 2004/03/13 02:07:26 ksekar
139 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
141 Revision 1.19 2004/03/13 01:57:33 ksekar
142 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
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.
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
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
154 Revision 1.15 2004/02/10 03:02:46 cheshire
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)
161 Revision 1.13 2004/02/03 22:15:01 ksekar
162 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
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.
170 Revision 1.11 2004/01/30 02:12:30 ksekar
171 Changed uDNS_ReceiveMsg() to correctly return void.
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.
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.
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.
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
192 Revision 1.6 2004/01/24 23:47:17 cheshire
193 Use mDNSOpaque16fromIntVal() instead of shifting and masking
195 Revision 1.5 2004/01/24 04:59:15 cheshire
196 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
198 Revision 1.4 2004/01/24 04:19:26 cheshire
199 Restore overwritten checkin 1.2
201 Revision 1.3 2004/01/23 23:23:15 ksekar
202 Added TCP support for truncated unicast messages.
204 Revision 1.2 2004/01/22 03:48:41 cheshire
205 Make sure uDNS client doesn't accidentally use query ID zero
207 Revision 1.1 2003/12/13 03:05:27 ksekar
208 <rdar://problem/3192548>: DynDNS: Unicast query of service records
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)
224 #define NULL mDNSNULL
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
236 // Asyncronous operation types
241 // other async. operation names go here
247 mDNSAddr primaryAddr
;
250 mDNSIPPort updatePort
;
253 // other async. result struct defs go here
257 AsyncOpResultType type
;
259 // other async result structs go here
262 typedef void AsyncOpCallback(mStatus err
, mDNS
*const m
, void *info
, const AsyncOpResult
*result
);
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.)
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
);
278 // ***************************************************************************
279 #if COMPILER_LIKES_PRAGMA_MARK
280 #pragma mark - General Utility Functions
283 mDNSlocal mDNSOpaque16
newMessageID(uDNS_GlobalInfo
*u
)
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
++);
290 // unlink an AuthRecord from a linked list
291 mDNSlocal mStatus
unlinkAR(AuthRecord
**list
, AuthRecord
*const rr
)
293 AuthRecord
*rptr
, *prev
= NULL
;
295 for (rptr
= *list
; rptr
; rptr
= rptr
->next
)
299 if (prev
) prev
->next
= rptr
->next
;
300 else *list
= rptr
->next
;
302 return mStatus_NoError
;
306 LogMsg("ERROR: unlinkAR - no such active record");
307 return mStatus_UnknownErr
;
310 mDNSlocal
void LinkActiveQuestion(uDNS_GlobalInfo
*u
, DNSQuestion
*q
)
312 if (IsActiveUnicastQuery(q
, u
))
313 { LogMsg("LinkActiveQuestion - %s (%d) already in list!", q
->qname
.c
, q
->qtype
); return; }
315 q
->next
= u
->ActiveQueries
;
316 u
->ActiveQueries
= q
;
320 // ***************************************************************************
321 #if COMPILER_LIKES_PRAGMA_MARK
322 #pragma mark - Name Server List Management
325 mDNSexport
void mDNS_RegisterDNS(mDNS
*const m
, mDNSv4Addr
*const dnsAddr
)
327 //!!!KRS do this dynamically!
328 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
331 if (!dnsAddr
->NotAnInteger
)
333 LogMsg("ERROR: attempt to register DNS with IP address 0");
337 for (i
= 0; i
< 32; i
++)
339 if (!u
->Servers
[i
].ip
.v4
.NotAnInteger
)
341 u
->Servers
[i
].ip
.v4
.NotAnInteger
= dnsAddr
->NotAnInteger
;
342 u
->Servers
[i
].type
= mDNSAddrType_IPv4
;
345 if (u
->Servers
[i
].ip
.v4
.NotAnInteger
== dnsAddr
->NotAnInteger
)
347 LogMsg("ERROR: mDNS_RegisterDNS - DNS already registered");
351 if (i
== 32) { LogMsg("ERROR: mDNS_RegisterDNS - too many registered servers"); }
355 mDNSexport
void mDNS_DeregisterDNS(mDNS
*const m
, mDNSv4Addr
*const dnsAddr
)
357 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
360 if (!dnsAddr
->NotAnInteger
)
362 LogMsg("ERROR: attempt to deregister DNS with IP address 0");
366 for (i
= 0; i
< 32; i
++)
369 if (u
->Servers
[i
].ip
.v4
.NotAnInteger
== dnsAddr
->NotAnInteger
)
371 u
->Servers
[i
].ip
.v4
.NotAnInteger
= 0;
375 if (i
== 32) { LogMsg("ERROR: mDNS_DeregisterDNS - no such DNS registered"); }
378 mDNSexport
void mDNS_DeregisterDNSList(mDNS
*const m
)
380 ubzero(m
->uDNS_info
.Servers
, 32 * sizeof(mDNSAddr
));
383 mDNSexport mDNSBool
mDNS_DNSRegistered(mDNS
*const m
)
387 for (i
= 0; i
< 32; i
++) if (m
->uDNS_info
.Servers
[i
].ip
.v4
.NotAnInteger
) return mDNStrue
;
392 // ***************************************************************************
393 #if COMPILER_LIKES_PRAGMA_MARK
394 #pragma mark - authorization management
398 mDNSexport mStatus
mDNS_UpdateDomainRequiresAuthentication(mDNS
*m
, domainname
*zone
, domainname
*key
,
399 mDNSu8
*sharedSecret
, mDNSu32 ssLen
, mDNSBool base64
)
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
);
413 keylen
= DNSDigest_Base64ToBin((const char*)sharedSecret
, keybuf
, 1024);
416 LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
418 return mStatus_UnknownErr
;
420 DNSDigest_ConstructHMACKey(info
, keybuf
, (mDNSu32
)keylen
);
422 else DNSDigest_ConstructHMACKey(info
, sharedSecret
, ssLen
);
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
;
431 mDNSexport
void mDNS_ClearAuthenticationList(mDNS
*m
)
433 uDNS_AuthInfo
*fptr
, *ptr
= m
->uDNS_info
.AuthInfoList
;
441 m
->uDNS_info
.AuthInfoList
= NULL
;
444 mDNSlocal uDNS_AuthInfo
*GetAuthInfoForZone(const uDNS_GlobalInfo
*u
, const domainname
*zone
)
448 mDNSu32 zoneLen
, ptrZoneLen
;
450 zoneLen
= ustrlen(zone
->c
);
451 for (ptr
= u
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
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
;
465 // ***************************************************************************
466 #if COMPILER_LIKES_PRAGMA_MARK
467 #pragma mark - host name and interface management
471 mDNSlocal
void hostnameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
473 // note that the rr is already unlinked if result is non-zero
475 if (result
== mStatus_MemFree
) return;
476 if (result
== mStatus_NameConflict
&& rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
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
);
484 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
485 // we've already tried to re-register. reset RecordType before returning RR to client
487 if (result
== mStatus_NoSuchRecord
) // name is advertised for some other address
488 result
= mStatus_NameConflict
;
489 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
492 if (!result
) rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
494 ((NetworkInterfaceInfo
*)(rr
->RecordContext
))->uDNS_info
.registered
= mDNSfalse
;
495 mDNS_HostNameCallback(m
, rr
, result
);
499 mDNSlocal
void deadvertiseIfCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus err
)
503 if (err
== mStatus_MemFree
) ufree(rr
);
504 else LogMsg("deadvertiseIfCallback - error %s for record %s", err
, rr
->resrec
.name
.c
);
507 mDNSexport
void uDNS_DeadvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
510 AuthRecord
*rr
= &set
->uDNS_info
.RR_A
;
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
516 if (set
->uDNS_info
.registered
)
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
= ©
->rdatastorage
; // set rdata pointer
523 if (rr
->resrec
.rdata
!= &rr
->rdatastorage
)
524 { LogMsg("ERROR: uDNS_DeadvertiseInterface - expected local rdata storage. Aborting deregistration"); return; }
526 // link copy into list
527 copy
->next
= m
->uDNS_info
.RecordRegistrations
;
528 m
->uDNS_info
.RecordRegistrations
= copy
;
529 copy
->RecordCallback
= deadvertiseIfCallback
;
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
);
537 else debugf("uDNS_DeadvertiseInterface - interface not registered");
541 mDNSexport
void uDNS_AdvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
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
551 if (set
->uDNS_info
.registered
&& SameDomainName(&m
->uDNS_info
.hostname
, &set
->uDNS_info
.regname
))
552 return; // already registered
554 if (!m
->uDNS_info
.hostname
.c
[0])
556 // no hostname available
557 set
->uDNS_info
.registered
= mDNSfalse
;
561 set
->uDNS_info
.registered
= mDNStrue
;
562 ustrcpy(set
->uDNS_info
.regname
.c
, m
->uDNS_info
.hostname
.c
);
564 mDNS_SetupResourceRecord(a
, mDNSNULL
, 0, kDNSType_A
, 1, kDNSRecordTypeShared
/*Unique*/, hostnameCallback
, set
); //!!!KRS
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
);
570 uDNS_RegisterRecord(m
, a
);
574 // ***************************************************************************
575 #if COMPILER_LIKES_PRAGMA_MARK
576 #pragma mark - Incoming Message Processing
579 mDNSlocal mDNSBool
sameResourceRecord(ResourceRecord
*r1
, ResourceRecord
*r2
)
581 return (r1
->namehash
== r2
->namehash
&&
582 r1
->rrtype
== r2
->rrtype
&&
583 SameDomainName(&r1
->name
, &r2
->name
) &&
587 mDNSlocal mDNSBool
kaListContainsAnswer(DNSQuestion
*question
, CacheRecord
*rr
)
591 for (ptr
= question
->uDNS_info
.knownAnswers
; ptr
; ptr
= ptr
->next
)
592 if (sameResourceRecord(&ptr
->resrec
, &rr
->resrec
)) return mDNStrue
;
598 mDNSlocal
void removeKnownAnswer(DNSQuestion
*question
, CacheRecord
*rr
)
600 CacheRecord
*ptr
, *prev
= NULL
;
602 for (ptr
= question
->uDNS_info
.knownAnswers
; ptr
; ptr
= ptr
->next
)
604 if (sameResourceRecord(&ptr
->resrec
, &rr
->resrec
))
606 if (prev
) prev
->next
= ptr
->next
;
607 else question
->uDNS_info
.knownAnswers
= ptr
->next
;
613 LogMsg("removeKnownAnswer() called for record not in KA list");
617 mDNSlocal
void addKnownAnswer(DNSQuestion
*question
, const CacheRecord
*rr
)
619 CacheRecord
*newCR
= NULL
;
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
;
632 mDNSlocal
void deriveGoodbyes(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
)
636 CacheRecord
*fptr
, *ka
, *cr
, *answers
= NULL
, *prev
= NULL
;
637 LargeCacheRecord
*lcr
;
639 if (question
!= m
->uDNS_info
.CurrentQuery
) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
641 ptr
= LocateAnswers(msg
, end
);
642 if (!ptr
) goto pkt_error
;
644 if (!msg
->h
.numAnswers
)
646 // delete the whole KA list
647 ka
= question
->uDNS_info
.knownAnswers
;
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
)
654 debugf("deriveGoodbyes - question removed via callback. returning.");
661 question
->uDNS_info
.knownAnswers
= NULL
;
665 // make a list of all the new answers
666 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
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
;
674 if (ResourceRecordAnswersQuestion(&cr
->resrec
, question
))
682 // make sure every known answer is in the answer list
683 ka
= question
->uDNS_info
.knownAnswers
;
686 for (cr
= answers
; cr
; cr
= cr
->next
)
687 { if (sameResourceRecord(&ka
->resrec
, &cr
->resrec
)) break; }
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
)
697 debugf("deriveGoodbyes - question removed via callback. returning.");
711 // free temp answers list
713 while (cr
) { fptr
= cr
; cr
= cr
->next
; ufree(fptr
); }
718 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %s (%d)",
719 question
->qname
.c
, question
->qtype
);
723 LogMsg("ERROR: Malloc");
726 mDNSlocal
void pktResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, mDNSBool llq
)
730 LargeCacheRecord lcr
;
731 CacheRecord
*cr
= &lcr
.r
;
732 mDNSBool goodbye
, inKAList
;
733 LLQ_Info
*llqInfo
= question
->uDNS_info
.llq
;
735 if (question
!= m
->uDNS_info
.CurrentQuery
)
736 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
738 ptr
= LocateAnswers(msg
, end
);
739 if (!ptr
) goto pkt_error
;
741 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
743 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
744 if (!ptr
) goto pkt_error
;
745 if (ResourceRecordAnswersQuestion(&cr
->resrec
, question
))
747 goodbye
= llq
? ((mDNSs32
)cr
->resrec
.rroriginalttl
== -1) : mDNSfalse
;
748 inKAList
= kaListContainsAnswer(question
, cr
);
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
)
756 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
762 LogMsg("unexpected answer: %s", cr
->resrec
.name
.c
);
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?
772 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %s (%d)",
773 question
->qname
.c
, question
->qtype
);
777 mDNSlocal
void simpleResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
)
779 (void)context
; // unused
780 pktResponseHndlr(m
, msg
, end
, question
, mDNSfalse
);
783 mDNSlocal
void llqResponseHndlr(mDNS
* const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *context
)
785 (void)context
; // unused
786 pktResponseHndlr(m
, msg
, end
, question
, mDNStrue
);
791 mDNSlocal
void unlinkSRS(uDNS_GlobalInfo
*u
, ServiceRecordSet
*srs
)
793 ServiceRecordSet
*ptr
, *prev
= NULL
;
795 for (ptr
= u
->ServiceRegistrations
; ptr
; ptr
= ptr
->next
)
799 if (prev
) prev
->next
= ptr
->next
;
800 else u
->ServiceRegistrations
= ptr
->next
;
806 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
810 mDNSlocal mStatus
checkUpdateResult(domainname
*name
, mDNSu8 rcode
, const DNSMessage
*msg
)
812 (void)msg
; // currently unused, needed for TSIG errors
813 if (!rcode
) return mStatus_NoError
;
814 else if (rcode
== kDNSFlag1_RC_YXDomain
)
816 LogMsg("Name in use: %s", name
->c
);
817 return mStatus_NameConflict
;
819 else if (rcode
== kDNSFlag1_RC_Refused
)
821 LogMsg("Update %s refused", name
->c
);
822 return mStatus_Refused
;
824 else if (rcode
== kDNSFlag1_RC_NXRRSet
)
826 LogMsg("Reregister refusted (NXRRSET): %s", name
->c
);
827 return mStatus_NoSuchRecord
;
829 else if (rcode
== kDNSFlag1_RC_NotAuth
)
831 LogMsg("Permission denied (NOAUTH): %s", name
->c
);
832 return mStatus_NoAuth
;
834 else if (rcode
== kDNSFlag1_RC_FmtErr
)
836 LogMsg("Format Error: %s", name
->c
);
837 return mStatus_UnknownErr
;
838 //!!!KRS need to parse message for TSIG errors
842 LogMsg("Update %s failed with rcode %d", name
->c
, rcode
);
843 return mStatus_UnknownErr
;
847 mDNSlocal
void hndlServiceUpdateReply(mDNS
* const m
, ServiceRecordSet
*srs
, mStatus err
)
849 //!!!KRS make sure we're doing the right thing w/ MemFree
851 switch (srs
->uDNS_info
.state
)
853 case regState_Pending
:
854 case regState_Refresh
:
857 if (srs
->uDNS_info
.lease
&& err
== mStatus_UnknownErr
)
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
);
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
;
875 if (srs
->uDNS_info
.state
== regState_Refresh
)
877 srs
->uDNS_info
.state
= regState_Registered
;
880 srs
->uDNS_info
.state
= regState_Registered
;
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
;
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
);
894 case regState_TargetChange
:
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
902 else srs
->uDNS_info
.state
= regState_Registered
;
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
;
912 unlinkSRS(&m
->uDNS_info
, srs
); // name conflicts, force dereg, and errors
913 srs
->uDNS_info
.state
= regState_Unregistered
;
916 srs
->ServiceCallback(m
, srs
, err
);
917 // NOTE: do not touch structures after calling ServiceCallback
920 mDNSlocal
void hndlRecordUpdateReply(mDNS
*m
, AuthRecord
*rr
, mStatus err
)
922 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
924 if (rr
->uDNS_info
.state
== regState_DeregPending
)
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
);
937 if (rr
->uDNS_info
.state
== regState_DeregDeferred
)
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
;
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
);
954 if (rr
->uDNS_info
.state
== regState_Pending
|| rr
->uDNS_info
.state
== regState_Refresh
)
958 if (rr
->uDNS_info
.lease
&& err
== mStatus_UnknownErr
)
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
);
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
;
974 if (rr
->uDNS_info
.state
== regState_Refresh
)
975 rr
->uDNS_info
.state
= regState_Registered
;
978 rr
->uDNS_info
.state
= regState_Registered
;
979 rr
->RecordCallback(m
, rr
, err
);
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
);
990 mDNSlocal
void SetUpdateExpiration(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, uDNS_RegInfo
*info
)
992 LargeCacheRecord lcr
;
997 ptr
= LocateAdditionals(msg
, end
);
999 if (info
->lease
&& (ptr
= LocateAdditionals(msg
, end
)))
1001 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
1003 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
1005 if (lcr
.r
.resrec
.rrtype
== kDNSType_OPT
)
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
;
1016 info
->expire
= (mDNSPlatformTimeNow() + (((mDNSs32
)lease
* mDNSPlatformOneSecond
)) * 3/4);
1017 else info
->expire
= -1;
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
)
1026 ServiceRecordSet
*sptr
;
1027 mStatus err
= mStatus_NoError
;
1028 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
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
);
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;
1048 for (qptr
= u
->ActiveQueries
; qptr
; qptr
= qptr
->next
)
1050 //!!!KRS we should have a hashtable, hashed on message id
1051 if (qptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
1053 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
)
1054 { hndlTruncatedAnswer(qptr
, srcaddr
, m
); return; }
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
1066 if (QR_OP
== UpdateR
)
1068 for (sptr
= u
->ServiceRegistrations
; sptr
; sptr
= sptr
->next
)
1070 if (sptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
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
);
1078 for (rptr
= u
->RecordRegistrations
; rptr
; rptr
= rptr
->next
)
1080 if (rptr
->uDNS_info
.id
.NotAnInteger
== msg
->h
.id
.NotAnInteger
)
1082 err
= checkUpdateResult(&rptr
->resrec
.name
, rcode
, msg
);
1083 if (!err
) SetUpdateExpiration(m
, msg
, end
, &rptr
->uDNS_info
);
1084 hndlRecordUpdateReply(m
, rptr
, err
);
1089 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg
->h
.id
));
1093 mDNSlocal
void receiveMsg(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
1094 const mDNSInterfaceID InterfaceID
)
1096 mDNSAddr
*sa
= NULL
, *da
= NULL
;
1100 sp
.NotAnInteger
= 0;
1101 dp
.NotAnInteger
= 0;
1102 uDNS_ReceiveMsg(m
, msg
, end
, sa
, sp
, da
, dp
, InterfaceID
, ttl
);
1105 //!!!KRS this should go away (don't just pick one randomly!)
1106 mDNSlocal
const mDNSAddr
*getInitializedDNS(uDNS_GlobalInfo
*u
)
1109 for (i
= 0; i
< 32; i
++)
1110 if (u
->Servers
[i
].ip
.v4
.NotAnInteger
) return &u
->Servers
[i
];
1115 // ***************************************************************************
1116 #if COMPILER_LIKES_PRAGMA_MARK
1117 #pragma mark - Query Routines
1120 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
1122 mDNSlocal
void initializeQuery(DNSMessage
*msg
, DNSQuestion
*question
)
1124 mDNSOpaque16 flags
= QueryFlags
;
1126 ubzero(msg
, sizeof(msg
));
1127 flags
.b
[0] |= kDNSFlag0_RD
; // recursion desired
1128 InitializeDNSMessage(&msg
->h
, question
->uDNS_info
.id
, flags
);
1131 mDNSlocal mStatus
constructQueryMsg(DNSMessage
*msg
, mDNSu8
**endPtr
, DNSQuestion
*const question
)
1133 initializeQuery(msg
, question
);
1135 *endPtr
= putQuestion(msg
, msg
->data
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
1138 LogMsg("ERROR: Unicast query out of space in packet");
1139 return mStatus_UnknownErr
;
1141 return mStatus_NoError
;
1144 mDNSlocal mDNSu8
*putLLQ(DNSMessage
*const msg
, mDNSu8
*ptr
, DNSQuestion
*question
, LLQOptData
*data
, mDNSBool includeQuestion
)
1147 ResourceRecord
*opt
= &rr
.resrec
;
1150 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
1151 if (includeQuestion
)
1153 ptr
= putQuestion(msg
, ptr
, msg
->data
+ AbsoluteMaxDNSMessageData
, &question
->qname
, question
->qtype
, question
->qclass
);
1154 if (!ptr
) { LogMsg("ERROR: putLLQ - putQuestion"); return NULL
; }
1156 // locate OptRR if it exists, set pointer to end
1157 // !!!KRS implement me
1160 // format opt rr (fields not specified are zero-valued)
1161 ubzero(&rr
, sizeof(AuthRecord
));
1162 opt
->rdata
= &rr
.rdatastorage
;
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
;
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
; }
1180 mDNSlocal mDNSBool
getLLQAtIndex(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, LLQOptData
*llq
, int index
)
1182 LargeCacheRecord lcr
;
1186 ptr
= LocateAdditionals(msg
, end
);
1187 if (!ptr
) return mDNSfalse
;
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
));
1200 mDNSlocal
void recvRefreshReply(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*q
)
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; }
1211 qInfo
->expire
= mDNSPlatformTimeNow() + ((mDNSs32
)pktData
.lease
* mDNSPlatformOneSecond
);
1212 qInfo
->retry
= qInfo
->expire
+ ((mDNSs32
)pktData
.lease
* mDNSPlatformOneSecond
* 3/4);
1214 qInfo
->origLease
= pktData
.lease
;
1215 qInfo
->state
= LLQ_Established
;
1218 mDNSlocal
void sendLLQRefresh(mDNS
*m
, DNSQuestion
*q
, mDNSu32 lease
)
1223 LLQ_Info
*info
= q
->uDNS_info
.llq
;
1226 if (info
->state
== kLLQ_Refresh
&& info
->ntries
>= kLLQ_MAX_TRIES
)
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
;
1233 //!!!KRS handle this - periodically try to re-establish
1236 llq
.vers
= kLLQ_Vers
;
1237 llq
.llqOp
= kLLQ_Refresh
;
1238 llq
.err
= LLQErr_NoError
;
1239 umemcpy(llq
.id
, info
->id
, 8);
1242 initializeQuery(&msg
, q
);
1243 end
= putLLQ(&msg
, msg
.data
, q
, &llq
, mDNStrue
);
1244 if (!end
) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
1246 err
= mDNSSendDNSMessage(m
, &msg
, end
, q
->InterfaceID
, &info
->servAddr
, info
->servPort
);
1247 if (err
) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %d", err
);
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;
1256 mDNSlocal
void recvLLQEvent(mDNS
*m
, DNSQuestion
*q
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, mDNSInterfaceID InterfaceID
)
1259 mDNSu8
*ackEnd
= ack
.data
;
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;
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
);
1277 mDNSlocal
void hndlChallengeResponseAck(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, LLQOptData
*llq
, DNSQuestion
*q
)
1279 LLQ_Info
*info
= q
->uDNS_info
.llq
;
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);
1286 info
->origLease
= llq
->lease
;
1287 info
->state
= LLQ_Established
;
1288 q
->uDNS_info
.responseCallback
= llqResponseHndlr
;
1289 llqResponseHndlr(m
, pktMsg
, end
, q
, NULL
);
1293 info
->state
= LLQ_Error
;
1296 mDNSlocal
void sendChallengeResponse(mDNS
*m
, DNSQuestion
*q
, LLQOptData
*llq
)
1298 LLQ_Info
*info
= q
->uDNS_info
.llq
;
1299 DNSMessage response
;
1300 mDNSu8
*responsePtr
= response
.data
;
1303 mDNSs32 timenow
= mDNSPlatformTimeNow();
1305 if (info
->ntries
++ == kLLQ_MAX_TRIES
)
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?
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
;
1326 q
->LastQTime
= timenow
;
1327 info
->retry
= timenow
+ (kLLQ_INIT_RESEND
* info
->ntries
* mDNSPlatformOneSecond
);
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
; }
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
1340 info
->state
= LLQ_Error
;
1345 mDNSlocal
void hndlRequestChallenge(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, LLQOptData
*llq
, DNSQuestion
*q
)
1347 LLQ_Info
*info
= q
->uDNS_info
.llq
;
1348 mDNSs32 timenow
= mDNSPlatformTimeNow();
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
;
1359 info
->state
= LLQ_Static
;
1360 LogMsg("LLQ %s: static", q
->qname
.c
);
1361 simpleResponseHndlr(m
, pktMsg
, end
, q
, NULL
);
1363 case LLQErr_FormErr
:
1364 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %s", q
->qname
.c
);
1366 case LLQErr_BadVers
:
1367 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
1369 case LLQErr_UnknownErr
:
1370 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %s", q
->qname
.c
);
1373 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %s", llq
->err
, q
->qname
.c
);
1377 if (info
->origLease
!= llq
->lease
)
1378 LogMsg("hndlRequestChallenge: requested lease %d, granted lease %d", info
->origLease
, llq
->lease
);
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
);
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
1389 sendChallengeResponse(m
, q
, llq
);
1394 info
->state
= LLQ_Error
;
1398 // response handler for initial and secondary setup responses
1399 mDNSlocal
void recvSetupResponse(mDNS
*m
, DNSMessage
*pktMsg
, const mDNSu8
*end
, DNSQuestion
*q
, void *clientContext
)
1401 DNSQuestion pktQuestion
;
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
);
1407 (void)clientContext
; // unused
1409 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
)
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;
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
; }
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
; }
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
);
1434 info
->state
= LLQ_Error
;
1439 mDNSlocal
void startLLQHandshake(mDNS
*m
, LLQ_Info
*info
)
1444 DNSQuestion
*q
= info
->question
;
1446 mDNSs32 timenow
= mDNSPlatformTimeNow();
1448 if (info
->ntries
++ == kLLQ_MAX_TRIES
)
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?
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
;
1465 initializeQuery(&msg
, q
);
1466 end
= putLLQ(&msg
, msg
.data
, q
, &llqData
, mDNStrue
);
1469 LogMsg("ERROR: startLLQHandshake - putLLQ");
1470 info
->state
= LLQ_Error
;
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
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
;
1487 // wrapper for startLLQHandshake, invoked by async op callback
1488 mDNSlocal
void startLLQHandshakeCallback(mStatus err
, mDNS
*const m
, void *llqInfo
, const AsyncOpResult
*result
)
1490 LLQ_Info
*info
= (LLQ_Info
*)llqInfo
;
1491 const zoneData_t
*zoneInfo
= &result
->zoneData
;
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
;
1502 if (info
->state
== LLQ_Cancelled
)
1504 // StopQuery was called while we were getting the zone info
1505 LogMsg("startLLQHandshake - LLQ Cancelled.");
1506 info
->question
= NULL
; // question may be deallocated
1511 if (info
->state
!= LLQ_GetZoneInfo
)
1513 LogMsg("ERROR: startLLQHandshake - bad state %d", info
->state
);
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
;
1522 startLLQHandshake(m
, info
);
1525 mDNSlocal mStatus
startLLQ(mDNS
*m
, DNSQuestion
*question
)
1528 mStatus err
= mStatus_NoError
;
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
;
1536 // link info/question
1537 info
->question
= question
;
1538 question
->uDNS_info
.llq
= info
;
1540 question
->uDNS_info
.responseCallback
= llqResponseHndlr
;
1542 err
= startGetZoneData(&question
->qname
, m
, mDNSfalse
, mDNStrue
, startLLQHandshakeCallback
, info
);
1545 LogMsg("ERROR: startLLQ - startGetZoneData returned %d", err
);
1546 info
->question
= NULL
;
1548 question
->uDNS_info
.llq
= NULL
;
1552 LinkActiveQuestion(&m
->uDNS_info
, question
);
1556 mDNSlocal mDNSBool
recvLLQResponse(mDNS
*m
, DNSMessage
*msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSInterfaceID InterfaceID
)
1558 DNSQuestion pktQ
, *q
;
1559 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1560 const mDNSu8
*ptr
= msg
->data
;
1563 if (!msg
->h
.numQuestions
) return mDNSfalse
;
1565 ptr
= getQuestion(msg
, ptr
, end
, 0, &pktQ
);
1566 if (!ptr
) return mDNSfalse
;
1567 pktQ
.uDNS_info
.id
= msg
->h
.id
;
1569 // !!!KRS we should do a table lookup to quickly determine if this packet is for an LLQ
1571 q
= u
->ActiveQueries
;
1574 llqInfo
= q
->uDNS_info
.llq
;
1577 q
->qnamehash
== pktQ
.qnamehash
&&
1578 q
->qtype
== pktQ
.qtype
&&
1579 SameDomainName(&q
->qname
, &pktQ
.qname
))
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
; }
1596 mDNSexport mDNSBool
IsActiveUnicastQuery(DNSQuestion
*const question
, uDNS_GlobalInfo
*u
)
1600 for (q
= u
->ActiveQueries
; q
; q
= q
->next
)
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
);
1613 // stopLLQ happens IN ADDITION to stopQuery
1614 mDNSlocal
void stopLLQ(mDNS
*m
, DNSQuestion
*question
)
1616 LLQ_Info
*info
= question
->uDNS_info
.llq
;
1619 if (!question
->LongLived
) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
1620 if (!info
) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
1622 switch (info
->state
)
1625 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
1626 //!!!KRS should we unlink info<->question here?
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
;
1632 case LLQ_Established
:
1634 // refresh w/ lease 0
1635 sendLLQRefresh(m
, question
, 0);
1638 debugf("stopLLQ - silently discarding LLQ in state %d", info
->state
);
1643 info
->question
= NULL
;
1645 question
->uDNS_info
.llq
= NULL
;
1649 mDNSexport mStatus
uDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
1651 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1652 DNSQuestion
*qptr
, *prev
= NULL
;
1655 qptr
= u
->ActiveQueries
;
1658 if (qptr
== question
)
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
)
1666 ka
= question
->uDNS_info
.knownAnswers
;
1667 question
->uDNS_info
.knownAnswers
= question
->uDNS_info
.knownAnswers
->next
;
1670 if (prev
) prev
->next
= question
->next
;
1671 else u
->ActiveQueries
= question
->next
;
1672 return mStatus_NoError
;
1677 LogMsg("uDNS_StopQuery: no such active query (%s)", question
->qname
.c
);
1678 return mStatus_UnknownErr
;
1681 mDNSexport
void uDNS_SuspendLLQs(mDNS
*m
)
1685 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
= q
->next
)
1687 llq
= q
->uDNS_info
.llq
;
1688 if (q
->LongLived
&& llq
&& llq
->state
< LLQ_Suspended
)
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
;
1698 extern void uDNS_RestartLLQs(mDNS
*m
)
1700 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1704 u
->CurrentQuery
= u
->ActiveQueries
;
1705 while (u
->CurrentQuery
)
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
); }
1716 mDNSlocal mStatus
startQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool internal
)
1718 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
1721 mStatus err
= mStatus_NoError
;
1722 const mDNSAddr
*server
;
1724 //!!!KRS we should check if the question is already in our acivequestion list
1725 if (!ValidateDomainName(&question
->qname
))
1727 LogMsg("Attempt to start query with invalid qname %##s %s", question
->qname
.c
, DNSTypeName(question
->qtype
));
1728 return mStatus_Invalid
;
1731 question
->next
= NULL
;
1732 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // to do quick domain name comparisons
1733 question
->uDNS_info
.id
= newMessageID(u
);
1735 // break here if its and LLQ
1736 if (question
->LongLived
) return startLLQ(m
, question
);
1738 err
= constructQueryMsg(&msg
, &endPtr
, question
);
1739 if (err
) return err
;
1741 // else send the query to our server
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
;
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
); }
1759 mDNSexport mStatus
uDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
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);
1767 // explicitly set response handler
1768 mDNSlocal mStatus
startInternalQuery(DNSQuestion
*q
, mDNS
*m
, InternalResponseHndlr callback
, void *hndlrContext
)
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);
1779 // ***************************************************************************
1780 #if COMPILER_LIKES_PRAGMA_MARK
1781 #pragma mark - Domain -> Name Server Conversion
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.
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.
1799 * Steps for deriving the zone name are as follows:
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.
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.
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.)
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.)
1817 // state machine types and structs
1820 // state machine states
1835 // state machine actions
1838 smContinue
, // continue immediately to next state
1839 smBreak
, // break until next packet/timeout
1840 smError
// terminal error - cleanup and abort
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
1849 domainname zone
; // left-hand-side of SOA record
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
;
1860 AsyncOpCallback
*callback
; // caller specified function to be called upon completion
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
);
1875 mDNSlocal mStatus
startGetZoneData(domainname
*name
, mDNS
*m
, mDNSBool findUpdatePort
, mDNSBool findLLQPort
,
1876 AsyncOpCallback callback
, void *callbackInfo
)
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
;
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
;
1892 // state machine entry routine
1893 mDNSlocal
void getZoneData(mDNS
*const m
, DNSMessage
*msg
, const mDNSu8
*end
, DNSQuestion
*question
, void *contextPtr
)
1895 AsyncOpResult result
;
1896 ntaContext
*context
= (ntaContext
*)contextPtr
;
1903 // stop any active question
1904 if (context
->questionActive
)
1906 uDNS_StopQuery(context
->m
, &context
->question
);
1907 context
->questionActive
= mDNSfalse
;
1910 if (msg
&& msg
->h
.flags
.b
[2] >> 4 && msg
->h
.flags
.b
[2] >> 4 != kDNSFlag1_RC_NXDomain
)
1912 // rcode non-zero, non-nxdomain
1913 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg
->h
.flags
.b
[2] >> 4);
1917 switch (context
->state
)
1921 action
= hndlLookupSOA(msg
, end
, context
);
1922 if (action
== smError
) goto error
;
1923 if (action
== smBreak
) return;
1926 action
= confirmNS(msg
, end
, context
);
1927 if (action
== smError
) goto error
;
1928 if (action
== smBreak
) return;
1931 action
= lookupNSAddr(msg
, end
, context
);
1932 if (action
== smError
) goto error
;
1933 if (action
== smBreak
) return;
1935 if (!context
->findUpdatePort
&& !context
->findLLQPort
)
1937 context
->state
= complete
;
1941 action
= hndlLookupPorts(msg
, end
, context
);
1942 if (action
== smError
) goto error
;
1943 if (action
== smBreak
) return;
1944 if (action
== smContinue
) context
->state
= complete
;
1946 case complete
: break;
1949 if (context
->state
!= complete
)
1951 LogMsg("ERROR: getZoneData - exited state machine with state %d", context
->state
);
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
);
1966 if (context
&& context
->callback
)
1967 context
->callback(mStatus_UnknownErr
, context
->m
, context
->callbackInfo
, NULL
);
1969 if (context
&& context
->questionActive
)
1971 uDNS_StopQuery(context
->m
, &context
->question
);
1972 context
->questionActive
= mDNSfalse
;
1974 if (context
) ufree(context
);
1977 mDNSlocal smAction
hndlLookupSOA(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
1980 LargeCacheRecord lcr
;
1981 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1982 DNSQuestion
*query
= &context
->question
;
1987 // if msg contains SOA record in answer or authority sections, update context/state and return
1989 ptr
= LocateAnswers(msg
, end
);
1990 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
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
))
1996 processSOA(context
, rr
);
2000 ptr
= LocateAuthorities(msg
, end
);
2001 // SOA not in answers, check in authority
2002 for (i
= 0; i
< msg
->h
.numAuthorities
; i
++)
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
)
2008 processSOA(context
, rr
);
2014 if (context
->state
!= init
&& !context
->curSOA
->c
[0])
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
);
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);
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
);
2035 return smBreak
; // break from state machine until we receive another packet
2038 mDNSlocal
void processSOA(ntaContext
*context
, ResourceRecord
*rr
)
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
;
2047 mDNSlocal smAction
confirmNS(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
2049 DNSQuestion
*query
= &context
->question
;
2051 LargeCacheRecord lcr
;
2052 ResourceRecord
*rr
= &lcr
.r
.resrec
;
2056 if (context
->state
== foundZone
)
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
2068 else if (context
->state
== lookupNS
)
2070 ptr
= LocateAnswers(msg
, end
);
2071 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
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
))
2078 context
->state
= foundNS
;
2079 return smContinue
; // next routine will examine additionals section of A record
2082 LogMsg("ERROR: could not confirm existance of NS record %s", context
->zone
.c
);
2085 else { LogMsg("ERROR: confirmNS - bad state %d", context
->state
); return smError
; }
2088 mDNSlocal smAction
queryNSAddr(ntaContext
*context
)
2091 DNSQuestion
*query
= &context
->question
;
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
;
2103 mDNSlocal smAction
lookupNSAddr(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
2107 LargeCacheRecord lcr
;
2108 ResourceRecord
*rr
= &lcr
.r
.resrec
;
2110 if (context
->state
== foundNS
)
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
);
2117 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg
->h
.numAdditionals
);
2118 return queryNSAddr(context
);
2122 for (i
= 0; i
< msg
->h
.numAdditionals
; i
++)
2124 ptr
= GetLargeResourceRecord(context
->m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
2127 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
2128 return queryNSAddr(context
);
2130 if (rr
->rrtype
== kDNSType_A
&& SameDomainName(&context
->ns
, &rr
->name
))
2132 context
->addr
.NotAnInteger
= rr
->rdata
->u
.ip
.NotAnInteger
;
2133 context
->state
= foundA
;
2138 // no A record in Additionals - query the server
2139 return queryNSAddr(context
);
2141 else if (context
->state
== lookupA
)
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
++)
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
))
2151 context
->addr
.NotAnInteger
= rr
->rdata
->u
.ip
.NotAnInteger
;
2152 context
->state
= foundA
;
2156 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
2159 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context
->state
); return smError
; }
2162 mDNSlocal smAction
lookupDNSPort(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
, char *portName
, mDNSIPPort
*port
)
2165 LargeCacheRecord lcr
;
2170 if (context
->state
== lookupPort
) // we've already issued the query
2172 if (!msg
) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError
; }
2173 ptr
= LocateAnswers(msg
, end
);
2174 for (i
= 0; i
< msg
->h
.numAnswers
; i
++)
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
))
2180 port
->NotAnInteger
= lcr
.r
.resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
2181 context
->state
= foundPort
;
2185 LogMsg("hndlLookupUpdatePort %s - answer not contained in reply. Guessing port %d", portName
, UnicastDNSPort
);
2186 *port
= UnicastDNSPort
;
2187 context
->state
= foundPort
;
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
2204 mDNSlocal smAction
hndlLookupPorts(DNSMessage
*msg
, const mDNSu8
*end
, ntaContext
*context
)
2208 if (context
->findUpdatePort
&& !context
->updatePort
.NotAnInteger
)
2210 action
= lookupDNSPort(msg
, end
, context
, UPDATE_PORT_NAME
, &context
->updatePort
);
2211 if (action
!= smContinue
) return action
;
2213 if (context
->findLLQPort
&& !context
->llqPort
.NotAnInteger
)
2214 return lookupDNSPort(msg
, end
, context
, LLQ_PORT_NAME
, &context
->llqPort
);
2220 // ***************************************************************************
2221 #if COMPILER_LIKES_PRAGMA_MARK
2222 #pragma mark - Truncation Handling
2227 DNSQuestion
*question
;
2234 // issue queries over a conected socket
2235 mDNSlocal
void conQueryCallback(int sd
, void *context
, mDNSBool ConnectionEstablished
)
2238 char msgbuf
[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
2241 tcpInfo_t
*info
= (tcpInfo_t
*)context
;
2242 DNSQuestion
*question
= info
->question
;
2245 question
->uDNS_info
.id
.NotAnInteger
= (mDNSu16
)~0;
2247 if (ConnectionEstablished
)
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
; }
2262 n
= mDNSPlatformReadTCP(sd
, &info
->replylen
, 2);
2265 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n
);
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
; }
2272 if (info
->nread
== info
->replylen
)
2274 // finished reading message
2275 receiveMsg(info
->m
, &info
->reply
, ((mDNSu8
*)&info
->reply
) + info
->replylen
, question
->InterfaceID
);
2276 mDNSPlatformTCPCloseConnection(sd
);
2285 mDNSPlatformTCPCloseConnection(sd
);
2289 mDNSlocal
void hndlTruncatedAnswer(DNSQuestion
*question
, const mDNSAddr
*src
, mDNS
*m
)
2291 mStatus connectionStatus
;
2292 uDNS_QuestionInfo
*info
= &question
->uDNS_info
;
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
;
2302 info
->id
.NotAnInteger
= (mDNSu16
)~0; // all 1's indicates TCP queries
2303 info
->timestamp
= mDNSPlatformTimeNow(); // reset timestamp
2305 connectionStatus
= mDNSPlatformTCPConnect(src
, UnicastDNSPort
, question
->InterfaceID
, conQueryCallback
, context
, &sd
);
2306 if (connectionStatus
== mStatus_ConnectionEstablished
) // manually invoke callback if connection completes
2308 conQueryCallback(sd
, context
, mDNStrue
);
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?
2317 // ***************************************************************************
2318 #if COMPILER_LIKES_PRAGMA_MARK
2319 #pragma mark - Dynamic Updates
2323 mDNSlocal mDNSu8
*putZone(DNSMessage
*const msg
, mDNSu8
*ptr
, mDNSu8
*limit
, const domainname
*zone
, mDNSOpaque16 zoneClass
)
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
;
2329 ((mDNSOpaque16
*)ptr
)->NotAnInteger
= zoneClass
.NotAnInteger
;
2331 msg
->h
.mDNS_numZones
++;
2337 mDNSlocal mDNSu8
*putPrereqNameNotInUse(domainname
*name
, DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*end
)
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
);
2349 mDNSlocal mDNSu8
*putDeletionRecord(DNSMessage
*msg
, mDNSu8
*ptr
, ResourceRecord
*rr
)
2352 // deletion: specify record w/ TTL 0, class NONE
2354 origclass
= rr
->rrclass
;
2355 rr
->rrclass
= kDNSClass_NONE
;
2356 ptr
= PutResourceRecordTTL(msg
, ptr
, &msg
->h
.mDNS_numUpdates
, rr
, 0);
2357 rr
->rrclass
= origclass
;
2361 mDNSlocal mDNSu8
*putUpdateLease(DNSMessage
*msg
, mDNSu8
*end
)
2364 ResourceRecord
*opt
= &rr
.resrec
;
2367 ubzero(&rr
, sizeof(AuthRecord
));
2368 opt
->rdata
= &rr
.rdatastorage
;
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
;
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
; }
2386 mDNSlocal
void sendRecordRegistration(mDNS
*const m
, AuthRecord
*rr
)
2389 mDNSu8
*ptr
= msg
.data
;
2390 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
2391 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2393 uDNS_AuthInfo
*authInfo
;
2394 uDNS_RegInfo
*regInfo
= &rr
->uDNS_info
;
2395 mStatus err
= mStatus_UnknownErr
;
2397 id
= newMessageID(u
);
2398 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
2399 rr
->uDNS_info
.id
.NotAnInteger
= id
.NotAnInteger
;
2402 ptr
= putZone(&msg
, ptr
, end
, ®Info
->zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
2403 if (!ptr
) goto error
;
2405 if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
|| rr
->uDNS_info
.state
== regState_Refresh
)
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
;
2412 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeShared
)
2414 ptr
= putPrereqNameNotInUse(&rr
->resrec
.name
, &msg
, ptr
, end
);
2415 if (!ptr
) goto error
;
2418 ptr
= PutResourceRecord(&msg
, ptr
, &msg
.h
.mDNS_numUpdates
, &rr
->resrec
);
2419 if (!ptr
) goto error
;
2421 if (rr
->uDNS_info
.lease
)
2422 ptr
= putUpdateLease(&msg
, ptr
);
2424 rr
->uDNS_info
.expire
= -1;
2426 authInfo
= GetAuthInfoForZone(u
, ®Info
->zone
);
2429 err
= mDNSSendSignedDNSMessage(m
, &msg
, ptr
, 0, ®Info
->ns
, regInfo
->port
, authInfo
);
2430 if (err
) { LogMsg("ERROR: sendRecordRegistration - mDNSSendSignedDNSMessage - %d", err
); goto error
; }
2434 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, 0, ®Info
->ns
, regInfo
->port
);
2435 if (err
) { LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %d", err
); goto error
; }
2438 if (regInfo
->state
!= regState_Refresh
) regInfo
->state
= regState_Pending
;
2442 if (rr
->uDNS_info
.state
!= regState_Unregistered
)
2444 unlinkAR(&u
->RecordRegistrations
, rr
);
2445 rr
->uDNS_info
.state
= regState_Unregistered
;
2447 rr
->RecordCallback(m
, rr
, err
);
2448 // NOTE: not safe to touch any client structures here
2451 mDNSlocal
void RecordRegistrationCallback(mStatus err
, mDNS
*const m
, void *authPtr
, const AsyncOpResult
*result
)
2453 AuthRecord
*newRR
= (AuthRecord
*)authPtr
;
2454 const zoneData_t
*zoneData
= &result
->zoneData
;
2455 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
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; }
2462 if (err
) { LogMsg("RecordRegistrationCallback: error %d", err
); goto error
; }
2463 if (newRR
->uDNS_info
.state
== regState_Cancelled
)
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
);
2473 if (result
->type
!= zoneDataResult
)
2475 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result
->type
);
2479 if (newRR
->resrec
.rrclass
!= zoneData
->zoneClass
)
2481 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
2482 newRR
->resrec
.rrclass
, zoneData
->zoneClass
);
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
;
2492 sendRecordRegistration(m
, newRR
);
2496 if (newRR
->uDNS_info
.state
!= regState_Unregistered
)
2498 unlinkAR(&u
->RecordRegistrations
, newRR
);
2499 newRR
->uDNS_info
.state
= regState_Unregistered
;
2501 newRR
->RecordCallback(m
, newRR
, err
);
2502 // NOTE: not safe to touch any client structures here
2506 mDNSlocal mDNSBool
setHostTarget(AuthRecord
*rr
, mDNS
*m
)
2510 if (!rr
->HostTarget
)
2512 debugf("Service %s - not updating host target", rr
->resrec
.name
.c
);
2517 target
= GetRRDomainNameTarget(&rr
->resrec
);
2520 LogMsg("ERROR: setHostTarget: Can't set target of rrtype %d", rr
->resrec
.rrtype
);
2524 if (SameDomainName(target
, &m
->uDNS_info
.hostname
))
2526 debugf("Host target for %s unchanged", rr
->resrec
.name
.c
);
2529 AssignDomainName(*target
, m
->uDNS_info
.hostname
);
2530 SetNewRData(&rr
->resrec
, NULL
, 0);
2534 mDNSlocal
void SendServiceRegistration(mDNS
*m
, ServiceRecordSet
*srs
)
2537 mDNSu8
*ptr
= msg
.data
;
2538 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
2539 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2541 uDNS_AuthInfo
*authInfo
;
2542 uDNS_RegInfo
*rInfo
= &srs
->uDNS_info
;
2543 mStatus err
= mStatus_UnknownErr
;
2545 id
= newMessageID(u
);
2546 InitializeDNSMessage(&msg
.h
, id
, UpdateReqFlags
);
2547 rInfo
->id
.NotAnInteger
= id
.NotAnInteger
;
2549 // setup resource records
2550 if (setHostTarget(&srs
->RR_SRV
, m
))
2551 SetNewRData(&srs
->RR_SRV
.resrec
, NULL
, 0); // set rdlen/estimate/hash
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);
2557 // construct update packet
2559 ptr
= putZone(&msg
, ptr
, end
, &rInfo
->zone
, mDNSOpaque16fromIntVal(srs
->RR_SRV
.resrec
.rrclass
));
2560 if (!ptr
) goto error
;
2562 if (srs
->uDNS_info
.state
== regState_Refresh
)
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
;
2570 // use SRV for prereq
2571 ptr
= putPrereqNameNotInUse(&srs
->RR_SRV
.resrec
.name
, &msg
, ptr
, end
);
2572 if (!ptr
) goto error
;
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.
2582 if (srs
->uDNS_info
.lease
)
2583 ptr
= putUpdateLease(&msg
, ptr
);
2585 srs
->uDNS_info
.expire
= -1;
2587 authInfo
= GetAuthInfoForZone(u
, &rInfo
->zone
);
2590 err
= mDNSSendSignedDNSMessage(m
, &msg
, ptr
, 0, &rInfo
->ns
, rInfo
->port
, authInfo
);
2591 if (err
) { LogMsg("ERROR: SendServiceRegistration - mDNSSendSignedDNSMessage - %d", err
); goto error
; }
2595 err
= mDNSSendDNSMessage(m
, &msg
, ptr
, 0, &rInfo
->ns
, rInfo
->port
);
2596 if (err
) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err
); goto error
; }
2598 if (rInfo
->state
!= regState_Refresh
)
2599 rInfo
->state
= regState_Pending
;
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
2610 mDNSlocal
void serviceRegistrationCallback(mStatus err
, mDNS
*const m
, void *srsPtr
, const AsyncOpResult
*result
)
2612 ServiceRecordSet
*srs
= (ServiceRecordSet
*)srsPtr
;
2613 const zoneData_t
*zoneData
= &result
->zoneData
;
2614 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2616 if (err
) goto error
;
2617 if (result
->type
!= zoneDataResult
)
2619 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result
->type
);
2623 if (srs
->uDNS_info
.state
== regState_Cancelled
)
2625 // client cancelled registration while fetching zone data
2626 srs
->uDNS_info
.state
= regState_Unregistered
;
2628 srs
->ServiceCallback(m
, srs
, mStatus_MemFree
);
2632 if (srs
->RR_SRV
.resrec
.rrclass
!= zoneData
->zoneClass
)
2634 LogMsg("Service %s - class does not match zone", srs
->RR_SRV
.resrec
.name
.c
);
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
;
2643 SendServiceRegistration(m
, 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
2654 mDNSexport
void uDNS_UpdateServiceTargets(mDNS
*const m
)
2657 mDNSu8
*ptr
= msg
.data
;
2658 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
2659 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2660 ServiceRecordSet
*srs
;
2662 mStatus err
= mStatus_NoError
;
2664 if (!m
->uDNS_info
.hostname
.c
[0])
2666 LogMsg("ERROR: uDNS_UpdateServiceTargets called before registration of hostname");
2668 //!!!KRS need to handle this case properly!
2671 for (srs
= u
->ServiceRegistrations
; srs
; srs
= srs
->next
)
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)
2677 if (srs
->uDNS_info
.state
!= regState_Registered
)
2679 LogMsg("ERROR: uDNS_UpdateServiceTargets - service %s not registered", rr
->resrec
.name
.c
);
2681 //!!!KRS need to handle this
2683 InitializeDNSMessage(&msg
.h
, srs
->uDNS_info
.id
, UpdateReqFlags
);
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
);
2696 LogMsg("ERROR: uDNS_UpdateServiceTargets - %s", ptr
? "mDNSSendDNSMessage" : "message formatting error");
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
2703 else srs
->uDNS_info
.state
= regState_TargetChange
;
2708 mDNSexport mStatus
uDNS_RegisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
2710 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
2712 if (rr
->uDNS_info
.state
== regState_FetchingZoneData
||
2713 rr
->uDNS_info
.state
== regState_Pending
||
2714 rr
->uDNS_info
.state
== regState_Registered
)
2716 LogMsg("Requested double-registration of physical record %s type %s",
2717 rr
->resrec
.name
.c
, rr
->resrec
.rrtype
);
2718 return mStatus_AlreadyRegistered
;
2721 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
2722 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
2724 if (!ValidateDomainName(&rr
->resrec
.name
))
2726 LogMsg("Attempt to register record with invalid name: %s", GetRRDisplayString(m
, rr
));
2727 return mStatus_Invalid
;
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
;
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;
2740 rr
->uDNS_info
.state
= regState_FetchingZoneData
;
2741 rr
->next
= m
->uDNS_info
.RecordRegistrations
;
2742 m
->uDNS_info
.RecordRegistrations
= rr
;
2744 rr
->uDNS_info
.lease
= mDNStrue
;
2745 return startGetZoneData(&rr
->resrec
.name
, m
, mDNStrue
, mDNSfalse
, RecordRegistrationCallback
, rr
);
2750 mDNSexport mStatus
uDNS_DeregisterRecord(mDNS
*const m
, AuthRecord
*const rr
)
2752 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2754 mDNSu8
*ptr
= msg
.data
;
2755 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
2757 uDNS_AuthInfo
*authInfo
;
2758 switch (rr
->uDNS_info
.state
)
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
:
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
;
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
;
2784 InitializeDNSMessage(&msg
.h
, rr
->uDNS_info
.id
, UpdateReqFlags
);
2787 ptr
= putZone(&msg
, ptr
, end
, &rr
->uDNS_info
.zone
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
2788 if (!ptr
) goto error
;
2790 if (!(ptr
= putDeletionRecord(&msg
, ptr
, &rr
->resrec
))) goto error
;
2792 authInfo
= GetAuthInfoForZone(u
, &rr
->uDNS_info
.zone
);
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
; }
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
; }
2804 return mStatus_NoError
;
2807 if (rr
->uDNS_info
.state
!= regState_Unregistered
)
2809 unlinkAR(&u
->RecordRegistrations
, rr
);
2810 rr
->uDNS_info
.state
= regState_Unregistered
;
2812 return mStatus_UnknownErr
;
2816 mDNSexport mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
2818 if (!*m
->uDNS_info
.NameRegDomain
)
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
;
2826 srs
->RR_SRV
.resrec
.rroriginalttl
= 3;
2827 srs
->RR_TXT
.resrec
.rroriginalttl
= 3;
2828 srs
->RR_PTR
.resrec
.rroriginalttl
= 3;
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
;
2836 return startGetZoneData(&srs
->RR_SRV
.resrec
.name
, m
, mDNStrue
, mDNSfalse
, serviceRegistrationCallback
, srs
);
2839 mDNSexport mStatus
uDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
2841 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2843 mDNSu8
*ptr
= msg
.data
;
2844 mDNSu8
*end
= (mDNSu8
*)&msg
+ sizeof(DNSMessage
);
2845 mStatus err
= mStatus_UnknownErr
;
2846 uDNS_AuthInfo
*authInfo
;
2848 //!!!KRS make sure we're doing the right thing w/ memfree
2850 switch (srs
->uDNS_info
.state
)
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
;
2867 srs
->uDNS_info
.state
= regState_DeregPending
;
2868 InitializeDNSMessage(&msg
.h
, srs
->uDNS_info
.id
, UpdateReqFlags
);
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
; }
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
; }
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
2885 authInfo
= GetAuthInfoForZone(u
, &srs
->uDNS_info
.zone
);
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
; }
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
; }
2897 return mStatus_NoError
;
2901 srs
->uDNS_info
.state
= regState_Unregistered
;
2905 mDNSexport
void uDNS_Execute(mDNS
*const m
)
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();
2920 u
->nextevent
= timenow
+ 0x78000000;
2921 if (!server
) { debugf("uDNS_Execute - no DNS server"); return; }
2923 for (q
= u
->ActiveQueries
; q
; q
= q
->next
)
2925 llq
= q
->uDNS_info
.llq
;
2926 if (q
->LongLived
&& llq
->state
!= LLQ_Poll
)
2928 if (llq
->state
>= LLQ_InitialRequest
&& llq
->state
<= LLQ_Suspended
&& llq
->retry
<= timenow
)
2931 // sanity check to avoid packet flood bugs
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
); }
2946 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
2947 if (sendtime
<= timenow
)
2949 err
= constructQueryMsg(&msg
, &end
, q
);
2952 LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %s",
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;
2961 else if (u
->nextevent
- sendtime
> 0) u
->nextevent
= sendtime
;
2965 //!!!KRS list should be pre-sorted by expiration
2966 for (rr
= u
->RecordRegistrations
; rr
; rr
= rr
->next
)
2968 rInfo
= &rr
->uDNS_info
;
2969 if (rInfo
->lease
&& rInfo
->state
== regState_Registered
&& rInfo
->expire
> 0)
2971 if (rInfo
->expire
< timenow
)
2973 debugf("refreshing record %s", rr
->resrec
.name
.c
);
2974 rInfo
->state
= regState_Refresh
;
2975 sendRecordRegistration(m
, rr
);
2977 else if (u
->nextevent
- rInfo
->expire
> 0) u
->nextevent
= rInfo
->expire
;
2980 //!!!KRS list should be pre-sorted by expiration
2981 for (srs
= u
->ServiceRegistrations
; srs
; srs
= srs
->next
)
2983 rInfo
= &srs
->uDNS_info
;
2984 if (rInfo
->lease
&& rInfo
->state
== regState_Registered
&& rInfo
->expire
> 0)
2986 if (rInfo
->expire
< timenow
)
2988 debugf("refreshing service %s", srs
->RR_SRV
.resrec
.name
.c
);
2989 rInfo
->state
= regState_Refresh
;
2990 SendServiceRegistration(m
, srs
);
2992 else if (u
->nextevent
- rInfo
->expire
> 0) u
->nextevent
= rInfo
->expire
;
2997 mDNSexport
void uDNS_Init(mDNS
*const m
)
2999 mDNSPlatformMemZero(&m
->uDNS_info
, sizeof(uDNS_GlobalInfo
));
3000 m
->uDNS_info
.nextevent
= mDNSPlatformTimeNow() + 0x78000000;